support __cxa_atexit, and registering atexit functions from atexit handlers
[musl] / src / exit / atexit.c
1 #include <stddef.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <limits.h>
5 #include "libc.h"
6
7 /* Ensure that at least 32 atexit handlers can be registered without malloc */
8 #define COUNT 32
9
10 static struct fl
11 {
12         struct fl *next;
13         void (*f[COUNT])(void *);
14         void *a[COUNT];
15 } builtin, *head;
16
17 static int lock;
18
19 void __funcs_on_exit()
20 {
21         int i;
22         void (*func)(void *), *arg;
23         LOCK(&lock);
24         for (; head; head=head->next) {
25                 for (i=COUNT-1; i>=0 && !head->f[i]; i--);
26                 if (i<0) continue;
27                 func = head->f[i];
28                 arg = head->a[i];
29                 head->f[i] = 0;
30                 UNLOCK(&lock);
31                 func(arg);
32                 LOCK(&lock);
33         }
34 }
35
36 int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
37 {
38         int i;
39
40         LOCK(&lock);
41
42         /* Defer initialization of head so it can be in BSS */
43         if (!head) head = &builtin;
44
45         /* If the current function list is full, add a new one */
46         if (head->f[COUNT-1]) {
47                 struct fl *new_fl = calloc(sizeof(struct fl), 1);
48                 if (!new_fl) {
49                         UNLOCK(&lock);
50                         return -1;
51                 }
52                 new_fl->next = head;
53                 head = new_fl;
54         }
55
56         /* Append function to the list. */
57         for (i=0; i<COUNT && head->f[i]; i++);
58         head->f[i] = func;
59         head->a[i] = arg;
60
61         UNLOCK(&lock);
62         return 0;
63 }
64
65 static void call(void *p)
66 {
67         ((void (*)(void))(uintptr_t)p)();
68 }
69
70 int atexit(void (*func)(void))
71 {
72         return __cxa_atexit(call, (void *)(uintptr_t)func, 0);
73 }