1 /* $NetBSD: atexit.c,v 1.22 2008/02/25 14:35:54 xtraeme Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if defined(LIBC_SCCS) && !defined(lint) 41 __RCSID("$NetBSD: atexit.c,v 1.22 2008/02/25 14:35:54 xtraeme Exp $"); 42 #endif /* LIBC_SCCS and not lint */ 43 44 #include "reentrant.h" 45 46 #include <assert.h> 47 #include <stdlib.h> 48 49 #include "atexit.h" 50 51 struct atexit_handler { 52 struct atexit_handler *ah_next; 53 union { 54 void (*fun_atexit)(void); 55 void (*fun_cxa_atexit)(void *); 56 } ah_fun; 57 #define ah_atexit ah_fun.fun_atexit 58 #define ah_cxa_atexit ah_fun.fun_cxa_atexit 59 60 void *ah_arg; /* argument for cxa_atexit handlers */ 61 void *ah_dso; /* home DSO for cxa_atexit handlers */ 62 }; 63 64 /* 65 * There must be at least 32 to guarantee ANSI conformance, plus 66 * 3 additional ones for the benefit of the startup code, which 67 * may use them to register the dynamic loader's cleanup routine, 68 * the profiling cleanup routine, and the global destructor routine. 69 */ 70 #define NSTATIC_HANDLERS (32 + 3) 71 static struct atexit_handler atexit_handler0[NSTATIC_HANDLERS]; 72 73 #define STATIC_HANDLER_P(ah) \ 74 (ah >= &atexit_handler0[0] && ah < &atexit_handler0[NSTATIC_HANDLERS]) 75 76 /* 77 * Stack of atexit handlers. Handlers must be called in the opposite 78 * order they were registered. 79 */ 80 static struct atexit_handler *atexit_handler_stack; 81 82 #ifdef _REENTRANT 83 /* ..and a mutex to protect it all. */ 84 static mutex_t atexit_mutex; 85 #endif /* _REENTRANT */ 86 87 void __libc_atexit_init(void) __attribute__ ((visibility("hidden"))); 88 89 /* 90 * Allocate an atexit handler descriptor. If "dso" is NULL, it indicates 91 * a normal atexit handler, which must be allocated from the static pool, 92 * if possible. cxa_atexit handlers are never allocated from the static 93 * pool. 94 * 95 * atexit_mutex must be held. 96 */ 97 static struct atexit_handler * 98 atexit_handler_alloc(void *dso) 99 { 100 struct atexit_handler *ah; 101 int i; 102 103 if (dso == NULL) { 104 for (i = 0; i < NSTATIC_HANDLERS; i++) { 105 ah = &atexit_handler0[i]; 106 if (ah->ah_atexit == NULL && ah->ah_next == NULL) { 107 /* Slot is free. */ 108 return (ah); 109 } 110 } 111 } 112 113 /* 114 * Either no static slot was free, or this is a cxa_atexit 115 * handler. Allocate a new one. We keep the atexit_mutex 116 * held to prevent handlers from being run while we (potentially) 117 * block in malloc(). 118 */ 119 ah = malloc(sizeof(*ah)); 120 return (ah); 121 } 122 123 /* 124 * Initialize atexit_mutex with the PTHREAD_MUTEX_RECURSIVE attribute. 125 * Note that __cxa_finalize may generate calls to __cxa_atexit. 126 */ 127 void 128 __libc_atexit_init(void) 129 { 130 mutexattr_t atexit_mutex_attr; 131 mutexattr_init(&atexit_mutex_attr); 132 mutexattr_settype(&atexit_mutex_attr, PTHREAD_MUTEX_RECURSIVE); 133 mutex_init(&atexit_mutex, &atexit_mutex_attr); 134 } 135 136 /* 137 * Register an atexit routine. This is suitable either for a cxa_atexit 138 * or normal atexit type handler. The __cxa_atexit() name and arguments 139 * are specified by the C++ ABI. See: 140 * 141 * http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor 142 */ 143 int 144 __cxa_atexit(void (*func)(void *), void *arg, void *dso) 145 { 146 struct atexit_handler *ah; 147 148 _DIAGASSERT(func != NULL); 149 150 mutex_lock(&atexit_mutex); 151 152 ah = atexit_handler_alloc(dso); 153 if (ah == NULL) { 154 mutex_unlock(&atexit_mutex); 155 return (-1); 156 } 157 158 ah->ah_cxa_atexit = func; 159 ah->ah_arg = arg; 160 ah->ah_dso = dso; 161 162 ah->ah_next = atexit_handler_stack; 163 atexit_handler_stack = ah; 164 165 mutex_unlock(&atexit_mutex); 166 return (0); 167 } 168 169 /* 170 * Run the list of atexit handlers. If dso is NULL, run all of them, 171 * otherwise run only those matching the specified dso. 172 * 173 * Note that we can be recursively invoked; rtld cleanup is via an 174 * atexit handler, and rtld cleanup invokes _fini() for DSOs, which 175 * in turn invokes __cxa_finalize() for the DSO. 176 */ 177 void 178 __cxa_finalize(void *dso) 179 { 180 static u_int call_depth; 181 struct atexit_handler *ah, *dead_handlers = NULL, **prevp; 182 void (*cxa_func)(void *); 183 void (*atexit_func)(void); 184 185 mutex_lock(&atexit_mutex); 186 call_depth++; 187 188 /* 189 * If we are at call depth 1 (which is usually the "do everything" 190 * call from exit(3)), we go ahead and remove elements from the 191 * list as we call them. This will prevent any nested calls from 192 * having to traverse elements we've already processed. If we are 193 * at call depth > 1, we simply mark elements we process as unused. 194 * When the depth 1 caller sees those, it will simply unlink them 195 * for us. 196 */ 197 again: 198 for (prevp = &atexit_handler_stack; (ah = (*prevp)) != NULL;) { 199 if (dso == NULL || dso == ah->ah_dso || ah->ah_atexit == NULL) { 200 if (ah->ah_atexit != NULL) { 201 void *p = atexit_handler_stack; 202 if (ah->ah_dso != NULL) { 203 cxa_func = ah->ah_cxa_atexit; 204 ah->ah_cxa_atexit = NULL; 205 (*cxa_func)(ah->ah_arg); 206 } else { 207 atexit_func = ah->ah_atexit; 208 ah->ah_atexit = NULL; 209 (*atexit_func)(); 210 } 211 /* Restart if new atexit handler was added. */ 212 if (p != atexit_handler_stack) 213 goto again; 214 } 215 216 if (call_depth == 1) { 217 *prevp = ah->ah_next; 218 if (STATIC_HANDLER_P(ah)) 219 ah->ah_next = NULL; 220 else { 221 ah->ah_next = dead_handlers; 222 dead_handlers = ah; 223 } 224 } else 225 prevp = &ah->ah_next; 226 } else 227 prevp = &ah->ah_next; 228 } 229 230 call_depth--; 231 232 if (call_depth > 0) 233 return; 234 235 mutex_unlock(&atexit_mutex); 236 237 /* 238 * Now free any dead handlers. Do this even if we're about to 239 * exit, in case a leak-detecting malloc is being used. 240 */ 241 while ((ah = dead_handlers) != NULL) { 242 dead_handlers = ah->ah_next; 243 free(ah); 244 } 245 } 246 247 /* 248 * Register a function to be performed at exit. 249 */ 250 int 251 atexit(void (*func)(void)) 252 { 253 254 return (__cxa_atexit((void (*)(void *))func, NULL, NULL)); 255 } 256