1 /* $NetBSD: atexit.c,v 1.16 2003/03/19 22:26:47 nathanw 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 "reentrant.h" 40 41 #include <assert.h> 42 #include <stdlib.h> 43 44 #include "atexit.h" 45 46 struct atexit_handler { 47 struct atexit_handler *ah_next; 48 union { 49 void (*fun_atexit)(void); 50 void (*fun_cxa_atexit)(void *); 51 } ah_fun; 52 #define ah_atexit ah_fun.fun_atexit 53 #define ah_cxa_atexit ah_fun.fun_cxa_atexit 54 55 void *ah_arg; /* argument for cxa_atexit handlers */ 56 void *ah_dso; /* home DSO for cxa_atexit handlers */ 57 }; 58 59 /* 60 * There must be at least 32 to guarantee ANSI conformance, plus 61 * 3 additional ones for the benefit of the startup code, which 62 * may use them to register the dynamic loader's cleanup routine, 63 * the profiling cleanup routine, and the global destructor routine. 64 */ 65 #define NSTATIC_HANDLERS (32 + 3) 66 static struct atexit_handler atexit_handler0[NSTATIC_HANDLERS]; 67 68 #define STATIC_HANDLER_P(ah) \ 69 (ah >= &atexit_handler0[0] && ah < &atexit_handler0[NSTATIC_HANDLERS]) 70 71 /* 72 * Stack of atexit handlers. Handlers must be called in the opposite 73 * order they were registered. 74 */ 75 static struct atexit_handler *atexit_handler_stack; 76 77 #ifdef _REENTRANT 78 /* ..and a mutex to protect it all. */ 79 static mutex_t atexit_mutex = MUTEX_INITIALIZER; 80 #endif /* _REENTRANT */ 81 82 /* 83 * Allocate an atexit handler descriptor. If "dso" is NULL, it indicates 84 * a normal atexit handler, which must be allocated from the static pool, 85 * if possible. cxa_atexit handlers are never allocated from the static 86 * pool. 87 * 88 * atexit_mutex must be held. 89 */ 90 static struct atexit_handler * 91 atexit_handler_alloc(void *dso) 92 { 93 struct atexit_handler *ah; 94 int i; 95 96 if (dso == NULL) { 97 for (i = 0; i < NSTATIC_HANDLERS; i++) { 98 ah = &atexit_handler0[i]; 99 if (ah->ah_atexit == NULL) { 100 /* Slot is free. */ 101 return (ah); 102 } 103 } 104 } 105 106 /* 107 * Either no static slot was free, or this is a cxa_atexit 108 * handler. Allocate a new one. We keep the atexit_mutex 109 * held to prevent handlers from being run while we (potentially) 110 * block in malloc(). 111 */ 112 ah = malloc(sizeof(*ah)); 113 return (ah); 114 } 115 116 /* 117 * Register an atexit routine. This is suitable either for a cxa_atexit 118 * or normal atexit type handler. The __cxa_atexit() name and arguments 119 * are specified by the C++ ABI. See: 120 * 121 * http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor 122 */ 123 int 124 __cxa_atexit(void (*func)(void *), void *arg, void *dso) 125 { 126 struct atexit_handler *ah; 127 128 _DIAGASSERT(func != NULL); 129 130 mutex_lock(&atexit_mutex); 131 132 ah = atexit_handler_alloc(dso); 133 if (ah == NULL) { 134 mutex_unlock(&atexit_mutex); 135 return (-1); 136 } 137 138 ah->ah_cxa_atexit = func; 139 ah->ah_arg = arg; 140 ah->ah_dso = dso; 141 142 ah->ah_next = atexit_handler_stack; 143 atexit_handler_stack = ah; 144 145 mutex_unlock(&atexit_mutex); 146 return (0); 147 } 148 149 /* 150 * Run the list of atexit handlers. If dso is NULL, run all of them, 151 * otherwise run only those matching the specified dso. 152 * 153 * Note that we can be recursively invoked; rtld cleanup is via an 154 * atexit handler, and rtld cleanup invokes _fini() for DSOs, which 155 * in turn invokes __cxa_finalize() for the DSO. 156 */ 157 void 158 __cxa_finalize(void *dso) 159 { 160 static thr_t owner; 161 static u_int call_depth; 162 struct atexit_handler *ah, *dead_handlers = NULL, **prevp; 163 void (*cxa_func)(void *); 164 void (*atexit_func)(void); 165 166 /* 167 * We implement our own recursive mutex here because we need 168 * to keep track of the call depth anyway, and it saves us 169 * having to dynamically initialize the mutex. 170 */ 171 if (mutex_trylock(&atexit_mutex) == 0) 172 owner = thr_self(); 173 else if (owner != thr_self()) { 174 mutex_lock(&atexit_mutex); 175 owner = thr_self(); 176 } 177 178 call_depth++; 179 180 /* 181 * If we are at call depth 1 (which is usually the "do everything" 182 * call from exit(3)), we go ahead and remove elements from the 183 * list as we call them. This will prevent any nested calls from 184 * having to traverse elements we've already processed. If we are 185 * at call depth > 1, we simply mark elements we process as unused. 186 * When the depth 1 caller sees those, it will simply unlink them 187 * for us. 188 */ 189 for (prevp = &atexit_handler_stack; (ah = (*prevp)) != NULL;) { 190 if (dso == NULL || dso == ah->ah_dso || ah->ah_atexit == NULL) { 191 if (ah->ah_atexit != NULL) { 192 if (ah->ah_dso != NULL) { 193 cxa_func = ah->ah_cxa_atexit; 194 ah->ah_cxa_atexit = NULL; 195 (*cxa_func)(ah->ah_arg); 196 } else { 197 atexit_func = ah->ah_atexit; 198 ah->ah_atexit = NULL; 199 (*atexit_func)(); 200 } 201 } 202 203 if (call_depth == 1) { 204 *prevp = ah->ah_next; 205 if (! STATIC_HANDLER_P(ah)) { 206 ah->ah_next = dead_handlers; 207 dead_handlers = ah; 208 } 209 } else 210 prevp = &ah->ah_next; 211 } else 212 prevp = &ah->ah_next; 213 } 214 215 call_depth--; 216 217 if (call_depth > 0) 218 return; 219 220 mutex_unlock(&atexit_mutex); 221 222 /* 223 * Now free any dead handlers. Do this even if we're about to 224 * exit, in case a leak-detecting malloc is being used. 225 */ 226 while ((ah = dead_handlers) != NULL) { 227 dead_handlers = ah->ah_next; 228 free(ah); 229 } 230 } 231 232 /* 233 * Register a function to be performed at exit. 234 */ 235 int 236 atexit(void (*func)(void)) 237 { 238 239 return (__cxa_atexit((void (*)(void *))func, NULL, NULL)); 240 } 241