about summary refs log tree commit diff
path: root/src/exit
diff options
context:
space:
mode:
Diffstat (limited to 'src/exit')
-rw-r--r--src/exit/_Exit.c9
-rw-r--r--src/exit/abort.c8
-rw-r--r--src/exit/assert.c9
-rw-r--r--src/exit/atexit.c57
-rw-r--r--src/exit/exit.c28
5 files changed, 111 insertions, 0 deletions
diff --git a/src/exit/_Exit.c b/src/exit/_Exit.c
new file mode 100644
index 00000000..8ef85a8f
--- /dev/null
+++ b/src/exit/_Exit.c
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#define SYSCALL_NORETURN
+#include "syscall.h"
+
+void _Exit(int ec)
+{
+	syscall1(__NR_exit_group, ec);
+	syscall1(__NR_exit, ec);
+}
diff --git a/src/exit/abort.c b/src/exit/abort.c
new file mode 100644
index 00000000..9a1c3d40
--- /dev/null
+++ b/src/exit/abort.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include <signal.h>
+
+void abort(void)
+{
+	raise(SIGABRT);
+	for (;;);
+}
diff --git a/src/exit/assert.c b/src/exit/assert.c
new file mode 100644
index 00000000..e87442a7
--- /dev/null
+++ b/src/exit/assert.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void __assert_fail(const char *expr, const char *file, int line, const char *func)
+{
+	fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line);
+	fflush(NULL);
+	abort();
+}
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;
+}
diff --git a/src/exit/exit.c b/src/exit/exit.c
new file mode 100644
index 00000000..d0c1bfc1
--- /dev/null
+++ b/src/exit/exit.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "libc.h"
+
+/* __overflow.c and atexit.c override these */
+static int (*const dummy)() = 0;
+weak_alias(dummy, __funcs_on_exit);
+weak_alias(dummy, __fflush_on_exit);
+
+void exit(int code)
+{
+	static int lock;
+
+	/* If more than one thread calls exit, hang until _Exit ends it all */
+	LOCK(&lock);
+
+	/* Only do atexit & stdio flush if they were actually used */
+	if (__funcs_on_exit) __funcs_on_exit();
+	if (__fflush_on_exit) __fflush_on_exit(0);
+
+	/* Destructor s**t is kept separate from atexit to avoid bloat */
+	if (libc.fini) libc.fini();
+	if (libc.ldso_fini) libc.ldso_fini();
+
+	_Exit(code);
+	for(;;);
+}