1 /* $NetBSD: atexit.c,v 1.17 2005/06/12 05:21:28 lukem 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.17 2005/06/12 05:21:28 lukem 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 = MUTEX_INITIALIZER; 85 #endif /* _REENTRANT */ 86 87 /* 88 * Allocate an atexit handler descriptor. If "dso" is NULL, it indicates 89 * a normal atexit handler, which must be allocated from the static pool, 90 * if possible. cxa_atexit handlers are never allocated from the static 91 * pool. 92 * 93 * atexit_mutex must be held. 94 */ 95 static struct atexit_handler * 96 atexit_handler_alloc(void *dso) 97 { 98 struct atexit_handler *ah; 99 int i; 100 101 if (dso == NULL) { 102 for (i = 0; i < NSTATIC_HANDLERS; i++) { 103 ah = &atexit_handler0[i]; 104 if (ah->ah_atexit == NULL) { 105 /* Slot is free. */ 106 return (ah); 107 } 108 } 109 } 110 111 /* 112 * Either no static slot was free, or this is a cxa_atexit 113 * handler. Allocate a new one. We keep the atexit_mutex 114 * held to prevent handlers from being run while we (potentially) 115 * block in malloc(). 116 */ 117 ah = malloc(sizeof(*ah)); 118 return (ah); 119 } 120 121 /* 122 * Register an atexit routine. This is suitable either for a cxa_atexit 123 * or normal atexit type handler. The __cxa_atexit() name and arguments 124 * are specified by the C++ ABI. See: 125 * 126 * http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor 127 */ 128 int 129 __cxa_atexit(void (*func)(void *), void *arg, void *dso) 130 { 131 struct atexit_handler *ah; 132 133 _DIAGASSERT(func != NULL); 134 135 mutex_lock(&atexit_mutex); 136 137 ah = atexit_handler_alloc(dso); 138 if (ah == NULL) { 139 mutex_unlock(&atexit_mutex); 140 return (-1); 141 } 142 143 ah->ah_cxa_atexit = func; 144 ah->ah_arg = arg; 145 ah->ah_dso = dso; 146 147 ah->ah_next = atexit_handler_stack; 148 atexit_handler_stack = ah; 149 150 mutex_unlock(&atexit_mutex); 151 return (0); 152 } 153 154 /* 155 * Run the list of atexit handlers. If dso is NULL, run all of them, 156 * otherwise run only those matching the specified dso. 157 * 158 * Note that we can be recursively invoked; rtld cleanup is via an 159 * atexit handler, and rtld cleanup invokes _fini() for DSOs, which 160 * in turn invokes __cxa_finalize() for the DSO. 161 */ 162 void 163 __cxa_finalize(void *dso) 164 { 165 static thr_t owner; 166 static u_int call_depth; 167 struct atexit_handler *ah, *dead_handlers = NULL, **prevp; 168 void (*cxa_func)(void *); 169 void (*atexit_func)(void); 170 171 /* 172 * We implement our own recursive mutex here because we need 173 * to keep track of the call depth anyway, and it saves us 174 * having to dynamically initialize the mutex. 175 */ 176 if (mutex_trylock(&atexit_mutex) == 0) 177 owner = thr_self(); 178 else if (owner != thr_self()) { 179 mutex_lock(&atexit_mutex); 180 owner = thr_self(); 181 } 182 183 call_depth++; 184 185 /* 186 * If we are at call depth 1 (which is usually the "do everything" 187 * call from exit(3)), we go ahead and remove elements from the 188 * list as we call them. This will prevent any nested calls from 189 * having to traverse elements we've already processed. If we are 190 * at call depth > 1, we simply mark elements we process as unused. 191 * When the depth 1 caller sees those, it will simply unlink them 192 * for us. 193 */ 194 for (prevp = &atexit_handler_stack; (ah = (*prevp)) != NULL;) { 195 if (dso == NULL || dso == ah->ah_dso || ah->ah_atexit == NULL) { 196 if (ah->ah_atexit != NULL) { 197 if (ah->ah_dso != NULL) { 198 cxa_func = ah->ah_cxa_atexit; 199 ah->ah_cxa_atexit = NULL; 200 (*cxa_func)(ah->ah_arg); 201 } else { 202 atexit_func = ah->ah_atexit; 203 ah->ah_atexit = NULL; 204 (*atexit_func)(); 205 } 206 } 207 208 if (call_depth == 1) { 209 *prevp = ah->ah_next; 210 if (! STATIC_HANDLER_P(ah)) { 211 ah->ah_next = dead_handlers; 212 dead_handlers = ah; 213 } 214 } else 215 prevp = &ah->ah_next; 216 } else 217 prevp = &ah->ah_next; 218 } 219 220 call_depth--; 221 222 if (call_depth > 0) 223 return; 224 225 mutex_unlock(&atexit_mutex); 226 227 /* 228 * Now free any dead handlers. Do this even if we're about to 229 * exit, in case a leak-detecting malloc is being used. 230 */ 231 while ((ah = dead_handlers) != NULL) { 232 dead_handlers = ah->ah_next; 233 free(ah); 234 } 235 } 236 237 /* 238 * Register a function to be performed at exit. 239 */ 240 int 241 atexit(void (*func)(void)) 242 { 243 244 return (__cxa_atexit((void (*)(void *))func, NULL, NULL)); 245 } 246