summaryrefslogtreecommitdiff
path: root/src/lib/libc/stdlib/atexit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/stdlib/atexit.c')
-rw-r--r--src/lib/libc/stdlib/atexit.c93
1 files changed, 84 insertions, 9 deletions
diff --git a/src/lib/libc/stdlib/atexit.c b/src/lib/libc/stdlib/atexit.c
index 50f8ec9372..ebf5f8775c 100644
--- a/src/lib/libc/stdlib/atexit.c
+++ b/src/lib/libc/stdlib/atexit.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: atexit.c,v 1.12 2006/02/22 07:16:32 otto Exp $ */ 1/* $OpenBSD: atexit.c,v 1.13 2007/09/03 14:40:16 millert Exp $ */
2/* 2/*
3 * Copyright (c) 2002 Daniel Hartmeier 3 * Copyright (c) 2002 Daniel Hartmeier
4 * All rights reserved. 4 * All rights reserved.
@@ -45,17 +45,22 @@ struct atexit *__atexit;
45 * function pointer in the first allocated page (the last one in 45 * function pointer in the first allocated page (the last one in
46 * the linked list) is reserved for the cleanup function. 46 * the linked list) is reserved for the cleanup function.
47 * 47 *
48 * Outside the following two functions, all pages are mprotect()'ed 48 * Outside the following functions, all pages are mprotect()'ed
49 * to prevent unintentional/malicious corruption. 49 * to prevent unintentional/malicious corruption.
50 */ 50 */
51 51
52/* 52/*
53 * Register a function to be performed at exit. 53 * Register a function to be performed at exit or when a shared object
54 * with the given dso handle is unloaded dynamically. Also used as
55 * the backend for atexit(). For more info on this API, see:
56 *
57 * http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor
54 */ 58 */
55int 59int
56atexit(void (*fn)(void)) 60__cxa_atexit(void (*func)(void *), void *arg, void *dso)
57{ 61{
58 struct atexit *p; 62 struct atexit *p = __atexit;
63 struct atexit_fn *fnp;
59 int pgsize = getpagesize(); 64 int pgsize = getpagesize();
60 int ret = -1; 65 int ret = -1;
61 66
@@ -75,7 +80,7 @@ atexit(void (*fn)(void))
75 if (p == MAP_FAILED) 80 if (p == MAP_FAILED)
76 goto unlock; 81 goto unlock;
77 if (__atexit == NULL) { 82 if (__atexit == NULL) {
78 p->fns[0] = NULL; 83 memset(&p->fns[0], 0, sizeof(p->fns[0]));
79 p->ind = 1; 84 p->ind = 1;
80 } else 85 } else
81 p->ind = 0; 86 p->ind = 0;
@@ -86,7 +91,10 @@ atexit(void (*fn)(void))
86 if (__atexit_invalid) 91 if (__atexit_invalid)
87 __atexit_invalid = 0; 92 __atexit_invalid = 0;
88 } 93 }
89 p->fns[p->ind++] = fn; 94 fnp = &p->fns[p->ind++];
95 fnp->fn_ptr.cxa_func = func;
96 fnp->fn_arg = arg;
97 fnp->fn_dso = dso;
90 if (mprotect(p, pgsize, PROT_READ)) 98 if (mprotect(p, pgsize, PROT_READ))
91 goto unlock; 99 goto unlock;
92 ret = 0; 100 ret = 0;
@@ -96,10 +104,75 @@ unlock:
96} 104}
97 105
98/* 106/*
107 * Register a function to be performed at exit.
108 */
109int
110atexit(void (*func)(void))
111{
112 return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
113}
114
115/*
116 * Call all handlers registered with __cxa_atexit() for the shared
117 * object owning 'dso'.
118 * Note: if 'dso' is NULL, then all remaining handlers are called.
119 */
120void
121__cxa_finalize(void *dso)
122{
123 struct atexit *p, *q;
124 struct atexit_fn fn;
125 int n, pgsize = getpagesize();
126 static int call_depth;
127
128 if (__atexit_invalid)
129 return;
130
131 call_depth++;
132
133 for (p = __atexit; p != NULL; p = p->next) {
134 for (n = p->ind; --n >= 0;) {
135 if (p->fns[n].fn_ptr.cxa_func == NULL)
136 continue; /* already called */
137 if (dso != NULL && dso != p->fns[n].fn_dso)
138 continue; /* wrong DSO */
139
140 /*
141 * Mark handler as having been already called to avoid
142 * dupes and loops, then call the appropriate function.
143 */
144 fn = p->fns[n];
145 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE) == 0) {
146 p->fns[n].fn_ptr.cxa_func = NULL;
147 mprotect(p, pgsize, PROT_READ);
148 }
149 if (dso != NULL)
150 (*fn.fn_ptr.cxa_func)(fn.fn_arg);
151 else
152 (*fn.fn_ptr.std_func)();
153 }
154 }
155
156 /*
157 * If called via exit(), unmap the pages since we have now run
158 * all the handlers. We defer this until calldepth == 0 so that
159 * we don't unmap things prematurely if called recursively.
160 */
161 if (dso == NULL && --call_depth == 0) {
162 for (p = __atexit; p != NULL; ) {
163 q = p;
164 p = p->next;
165 munmap(q, pgsize);
166 }
167 __atexit = NULL;
168 }
169}
170
171/*
99 * Register the cleanup function 172 * Register the cleanup function
100 */ 173 */
101void 174void
102__atexit_register_cleanup(void (*fn)(void)) 175__atexit_register_cleanup(void (*func)(void))
103{ 176{
104 struct atexit *p; 177 struct atexit *p;
105 int pgsize = getpagesize(); 178 int pgsize = getpagesize();
@@ -126,7 +199,9 @@ __atexit_register_cleanup(void (*fn)(void))
126 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE)) 199 if (mprotect(p, pgsize, PROT_READ | PROT_WRITE))
127 goto unlock; 200 goto unlock;
128 } 201 }
129 p->fns[0] = fn; 202 p->fns[0].fn_ptr.std_func = func;
203 p->fns[0].fn_arg = NULL;
204 p->fns[0].fn_dso = NULL;
130 mprotect(p, pgsize, PROT_READ); 205 mprotect(p, pgsize, PROT_READ);
131unlock: 206unlock:
132 _ATEXIT_UNLOCK(); 207 _ATEXIT_UNLOCK();