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