about summary refs log tree commit diff
path: root/src/exit/atexit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exit/atexit.c')
-rw-r--r--src/exit/atexit.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/exit/atexit.c b/src/exit/atexit.c
new file mode 100644
index 00000000..49c060e6
--- /dev/null
+++ b/src/exit/atexit.c
@@ -0,0 +1,57 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "libc.h"
+
+/* Ensure that at least 32 atexit handlers can be registered without malloc */
+#define COUNT 32
+
+static struct fl
+{
+	struct fl *next;
+	void (*f[COUNT])(void);
+} builtin, *head;
+
+static int run_atexit_functions(void)
+{
+	int i;
+	for (; head; head=head->next) {
+		for (i=COUNT-1; i>=0 && !head->f[i]; i--);
+		for (; i>=0; i--) head->f[i]();
+	}
+	return 0;
+}
+
+int (*const __funcs_on_exit)(void) = run_atexit_functions;
+
+int atexit(void (*func)(void))
+{
+	static int lock;
+	int i;
+
+	/* Hook for atexit extensions */
+	if (libc.atexit) return libc.atexit(func);
+
+	LOCK(&lock);
+
+	/* Defer initialization of head so it can be in BSS */
+	if (!head) head = &builtin;
+
+	/* If the current function list is full, add a new one */
+	if (head->f[COUNT-1]) {
+		struct fl *new_fl = calloc(sizeof(struct fl), 1);
+		if (!new_fl) {
+			UNLOCK(&lock);
+			return -1;
+		}
+		new_fl->next = head;
+		head = new_fl;
+	}
+
+	/* Append function to the list. */
+	for (i=0; i<COUNT && head->f[i]; i++);
+	head->f[i] = func;
+
+	UNLOCK(&lock);
+	return 0;
+}