diff options
Diffstat (limited to 'src/exit')
-rw-r--r-- | src/exit/_Exit.c | 9 | ||||
-rw-r--r-- | src/exit/abort.c | 8 | ||||
-rw-r--r-- | src/exit/assert.c | 9 | ||||
-rw-r--r-- | src/exit/atexit.c | 57 | ||||
-rw-r--r-- | src/exit/exit.c | 28 |
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(;;); +} |