atexit.c revision 123673
11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1990, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * This code is derived from software contributed to Berkeley by 61573Srgrimes * Chris Torek. 71573Srgrimes * 81573Srgrimes * Redistribution and use in source and binary forms, with or without 91573Srgrimes * modification, are permitted provided that the following conditions 101573Srgrimes * are met: 111573Srgrimes * 1. Redistributions of source code must retain the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer. 131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer in the 151573Srgrimes * documentation and/or other materials provided with the distribution. 161573Srgrimes * 3. All advertising materials mentioning features or use of this software 171573Srgrimes * must display the following acknowledgement: 181573Srgrimes * This product includes software developed by the University of 191573Srgrimes * California, Berkeley and its contributors. 201573Srgrimes * 4. Neither the name of the University nor the names of its contributors 211573Srgrimes * may be used to endorse or promote products derived from this software 221573Srgrimes * without specific prior written permission. 231573Srgrimes * 241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341573Srgrimes * SUCH DAMAGE. 351573Srgrimes */ 361573Srgrimes 371573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 3823662Speterstatic char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94"; 391573Srgrimes#endif /* LIBC_SCCS and not lint */ 4092986Sobrien#include <sys/cdefs.h> 4192986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdlib/atexit.c 123673 2003-12-19 17:11:20Z kan $"); 421573Srgrimes 4391697Stegge#include "namespace.h" 441573Srgrimes#include <stddef.h> 451573Srgrimes#include <stdlib.h> 4618516Sphk#include <unistd.h> 4791697Stegge#include <pthread.h> 481573Srgrimes#include "atexit.h" 4991697Stegge#include "un-namespace.h" 501573Srgrimes 5191697Stegge#include "libc_private.h" 5291697Stegge 53123673Skan#define ATEXIT_FN_EMPTY 0 54123673Skan#define ATEXIT_FN_STD 1 55123673Skan#define ATEXIT_FN_CXA 2 56123673Skan 5791697Steggestatic pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER; 5891697Stegge 5991697Stegge#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) 6091697Stegge#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) 6191697Stegge 62123673Skanstruct atexit { 63123673Skan struct atexit *next; /* next in list */ 64123673Skan int ind; /* next index in this table */ 65123673Skan struct atexit_fn { 66123673Skan int fn_type; /* ATEXIT_? from above */ 67123673Skan union { 68123673Skan void (*std_func)(void); 69123673Skan void (*cxa_func)(void *); 70123673Skan } fn_ptr; /* function pointer */ 71123673Skan void *fn_arg; /* argument for CXA callback */ 72123673Skan void *fn_dso; /* shared module handle */ 73123673Skan } fns[ATEXIT_SIZE]; /* the table itself */ 74123673Skan}; 7523662Speter 76123673Skanstatic struct atexit *__atexit; /* points to head of LIFO stack */ 77123673Skan 781573Srgrimes/* 79123673Skan * Register the function described by 'fptr' to be called at application 80123673Skan * exit or owning shared object unload time. This is a helper function 81123673Skan * for atexit and __cxa_atexit. 821573Srgrimes */ 83123673Skanstatic int 84123673Skanatexit_register(struct atexit_fn *fptr) 851573Srgrimes{ 861573Srgrimes static struct atexit __atexit0; /* one guaranteed table */ 8792889Sobrien struct atexit *p; 881573Srgrimes 8991697Stegge _MUTEX_LOCK(&atexit_mutex); 901573Srgrimes if ((p = __atexit) == NULL) 911573Srgrimes __atexit = p = &__atexit0; 9291697Stegge else while (p->ind >= ATEXIT_SIZE) { 9391697Stegge struct atexit *old__atexit; 9491697Stegge old__atexit = __atexit; 9591697Stegge _MUTEX_UNLOCK(&atexit_mutex); 9691697Stegge if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL) 971573Srgrimes return (-1); 9891697Stegge _MUTEX_LOCK(&atexit_mutex); 9991697Stegge if (old__atexit != __atexit) { 10091697Stegge /* Lost race, retry operation */ 10191697Stegge _MUTEX_UNLOCK(&atexit_mutex); 10291697Stegge free(p); 10391697Stegge _MUTEX_LOCK(&atexit_mutex); 10491697Stegge p = __atexit; 10591697Stegge continue; 10691697Stegge } 1071573Srgrimes p->ind = 0; 1081573Srgrimes p->next = __atexit; 1091573Srgrimes __atexit = p; 1101573Srgrimes } 111123673Skan p->fns[p->ind++] = *fptr; 11291697Stegge _MUTEX_UNLOCK(&atexit_mutex); 113123673Skan return 0; 1141573Srgrimes} 115123673Skan 116123673Skan/* 117123673Skan * Register a function to be performed at exit. 118123673Skan */ 119123673Skanint 120123673Skanatexit(void (*func)(void)) 121123673Skan{ 122123673Skan struct atexit_fn fn; 123123673Skan int error; 124123673Skan 125123673Skan fn.fn_type = ATEXIT_FN_STD; 126123673Skan fn.fn_ptr.std_func = func;; 127123673Skan fn.fn_arg = NULL; 128123673Skan fn.fn_dso = NULL; 129123673Skan 130123673Skan error = atexit_register(&fn); 131123673Skan return (error); 132123673Skan} 133123673Skan 134123673Skan/* 135123673Skan * Register a function to be performed at exit or when an shared object 136123673Skan * with given dso handle is unloaded dynamically. 137123673Skan */ 138123673Skanint 139123673Skan__cxa_atexit(void (*func)(void *), void *arg, void *dso) 140123673Skan{ 141123673Skan struct atexit_fn fn; 142123673Skan int error; 143123673Skan 144123673Skan fn.fn_type = ATEXIT_FN_CXA; 145123673Skan fn.fn_ptr.cxa_func = func;; 146123673Skan fn.fn_arg = arg; 147123673Skan fn.fn_dso = dso; 148123673Skan 149123673Skan error = atexit_register(&fn); 150123673Skan return (error); 151123673Skan} 152123673Skan 153123673Skan/* 154123673Skan * Call all handlers registered with __cxa_atexit for the shared 155123673Skan * object owning 'dso'. Note: if 'dso' is NULL, then all remaining 156123673Skan * handlers are called. 157123673Skan */ 158123673Skanvoid 159123673Skan__cxa_finalize(void *dso) 160123673Skan{ 161123673Skan struct atexit *p; 162123673Skan struct atexit_fn fn; 163123673Skan int n; 164123673Skan 165123673Skan _MUTEX_LOCK(&atexit_mutex); 166123673Skan for (p = __atexit; p; p = p->next) { 167123673Skan for (n = p->ind; --n >= 0;) { 168123673Skan if (p->fns[n].fn_type == ATEXIT_FN_EMPTY) 169123673Skan continue; /* already been called */ 170123673Skan if (dso != NULL && dso != p->fns[n].fn_dso) 171123673Skan continue; /* wrong DSO */ 172123673Skan fn = p->fns[n]; 173123673Skan /* 174123673Skan Mark entry to indicate that this particular handler 175123673Skan has already been called. 176123673Skan */ 177123673Skan p->fns[n].fn_type = ATEXIT_FN_EMPTY; 178123673Skan _MUTEX_UNLOCK(&atexit_mutex); 179123673Skan 180123673Skan /* Call the function of correct type. */ 181123673Skan if (fn.fn_type == ATEXIT_FN_CXA) 182123673Skan fn.fn_ptr.cxa_func(fn.fn_arg); 183123673Skan else if (fn.fn_type == ATEXIT_FN_STD) 184123673Skan fn.fn_ptr.std_func(); 185123673Skan _MUTEX_LOCK(&atexit_mutex); 186123673Skan } 187123673Skan } 188123673Skan _MUTEX_UNLOCK(&atexit_mutex); 189123673Skan} 190