xref: /minix/lib/libc/stdlib/atexit.c (revision 0a6a1f1d)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: atexit.c,v 1.29 2015/04/19 18:15:26 joerg Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras  * Copyright (c) 2003 The NetBSD Foundation, Inc.
52fe8fb19SBen Gras  * All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * This code is derived from software contributed to The NetBSD Foundation
82fe8fb19SBen Gras  * by Jason R. Thorpe.
92fe8fb19SBen Gras  *
102fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
112fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
122fe8fb19SBen Gras  * are met:
132fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
172fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
182fe8fb19SBen Gras  *
192fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
202fe8fb19SBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
212fe8fb19SBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
222fe8fb19SBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
232fe8fb19SBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
242fe8fb19SBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
252fe8fb19SBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
262fe8fb19SBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
272fe8fb19SBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
282fe8fb19SBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
292fe8fb19SBen Gras  * POSSIBILITY OF SUCH DAMAGE.
302fe8fb19SBen Gras  */
312fe8fb19SBen Gras 
322fe8fb19SBen Gras #include <sys/cdefs.h>
332fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
34*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: atexit.c,v 1.29 2015/04/19 18:15:26 joerg Exp $");
352fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
362fe8fb19SBen Gras 
372fe8fb19SBen Gras #include "reentrant.h"
382fe8fb19SBen Gras 
392fe8fb19SBen Gras #include <assert.h>
402fe8fb19SBen Gras #include <stdlib.h>
412fe8fb19SBen Gras 
422fe8fb19SBen Gras #include "atexit.h"
432fe8fb19SBen Gras 
442fe8fb19SBen Gras struct atexit_handler {
452fe8fb19SBen Gras 	struct atexit_handler *ah_next;
462fe8fb19SBen Gras 	union {
472fe8fb19SBen Gras 		void (*fun_atexit)(void);
482fe8fb19SBen Gras 		void (*fun_cxa_atexit)(void *);
492fe8fb19SBen Gras 	} ah_fun;
502fe8fb19SBen Gras #define	ah_atexit	ah_fun.fun_atexit
512fe8fb19SBen Gras #define	ah_cxa_atexit	ah_fun.fun_cxa_atexit
522fe8fb19SBen Gras 
532fe8fb19SBen Gras 	void *ah_arg;	/* argument for cxa_atexit handlers */
542fe8fb19SBen Gras 	void *ah_dso;	/* home DSO for cxa_atexit handlers */
552fe8fb19SBen Gras };
562fe8fb19SBen Gras 
572fe8fb19SBen Gras /*
582fe8fb19SBen Gras  * There must be at least 32 to guarantee ANSI conformance, plus
592fe8fb19SBen Gras  * 3 additional ones for the benefit of the startup code, which
602fe8fb19SBen Gras  * may use them to register the dynamic loader's cleanup routine,
612fe8fb19SBen Gras  * the profiling cleanup routine, and the global destructor routine.
622fe8fb19SBen Gras  */
632fe8fb19SBen Gras #define	NSTATIC_HANDLERS	(32 + 3)
642fe8fb19SBen Gras static struct atexit_handler atexit_handler0[NSTATIC_HANDLERS];
652fe8fb19SBen Gras 
662fe8fb19SBen Gras #define	STATIC_HANDLER_P(ah)						\
672fe8fb19SBen Gras 	(ah >= &atexit_handler0[0] && ah < &atexit_handler0[NSTATIC_HANDLERS])
682fe8fb19SBen Gras 
692fe8fb19SBen Gras /*
702fe8fb19SBen Gras  * Stack of atexit handlers.  Handlers must be called in the opposite
712fe8fb19SBen Gras  * order they were registered.
722fe8fb19SBen Gras  */
732fe8fb19SBen Gras static struct atexit_handler *atexit_handler_stack;
742fe8fb19SBen Gras 
752fe8fb19SBen Gras #ifdef _REENTRANT
762fe8fb19SBen Gras /* ..and a mutex to protect it all. */
7784d9c625SLionel Sambuc mutex_t __atexit_mutex;
782fe8fb19SBen Gras #endif /* _REENTRANT */
792fe8fb19SBen Gras 
802fe8fb19SBen Gras void	__libc_atexit_init(void) __attribute__ ((visibility("hidden")));
812fe8fb19SBen Gras 
822fe8fb19SBen Gras /*
832fe8fb19SBen Gras  * Allocate an atexit handler descriptor.  If "dso" is NULL, it indicates
842fe8fb19SBen Gras  * a normal atexit handler, which must be allocated from the static pool,
852fe8fb19SBen Gras  * if possible. cxa_atexit handlers are never allocated from the static
862fe8fb19SBen Gras  * pool.
872fe8fb19SBen Gras  *
8884d9c625SLionel Sambuc  * __atexit_mutex must be held.
892fe8fb19SBen Gras  */
902fe8fb19SBen Gras static struct atexit_handler *
atexit_handler_alloc(void * dso)912fe8fb19SBen Gras atexit_handler_alloc(void *dso)
922fe8fb19SBen Gras {
932fe8fb19SBen Gras 	struct atexit_handler *ah;
942fe8fb19SBen Gras 	int i;
952fe8fb19SBen Gras 
962fe8fb19SBen Gras 	if (dso == NULL) {
972fe8fb19SBen Gras 		for (i = 0; i < NSTATIC_HANDLERS; i++) {
982fe8fb19SBen Gras 			ah = &atexit_handler0[i];
992fe8fb19SBen Gras 			if (ah->ah_atexit == NULL && ah->ah_next == NULL) {
1002fe8fb19SBen Gras 				/* Slot is free. */
1012fe8fb19SBen Gras 				return (ah);
1022fe8fb19SBen Gras 			}
1032fe8fb19SBen Gras 		}
1042fe8fb19SBen Gras 	}
1052fe8fb19SBen Gras 
1062fe8fb19SBen Gras 	/*
1072fe8fb19SBen Gras 	 * Either no static slot was free, or this is a cxa_atexit
10884d9c625SLionel Sambuc 	 * handler.  Allocate a new one.  We keep the __atexit_mutex
1092fe8fb19SBen Gras 	 * held to prevent handlers from being run while we (potentially)
1102fe8fb19SBen Gras 	 * block in malloc().
1112fe8fb19SBen Gras 	 */
1122fe8fb19SBen Gras 	ah = malloc(sizeof(*ah));
1132fe8fb19SBen Gras 	return (ah);
1142fe8fb19SBen Gras }
1152fe8fb19SBen Gras 
1162fe8fb19SBen Gras /*
11784d9c625SLionel Sambuc  * Initialize __atexit_mutex with the PTHREAD_MUTEX_RECURSIVE attribute.
1182fe8fb19SBen Gras  * Note that __cxa_finalize may generate calls to __cxa_atexit.
1192fe8fb19SBen Gras  */
12084d9c625SLionel Sambuc void __section(".text.startup")
__libc_atexit_init(void)1212fe8fb19SBen Gras __libc_atexit_init(void)
1222fe8fb19SBen Gras {
123*0a6a1f1dSLionel Sambuc #ifdef _REENTRANT
1242fe8fb19SBen Gras 	mutexattr_t atexit_mutex_attr;
1252fe8fb19SBen Gras 	mutexattr_init(&atexit_mutex_attr);
1262fe8fb19SBen Gras 	mutexattr_settype(&atexit_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
12784d9c625SLionel Sambuc 	mutex_init(&__atexit_mutex, &atexit_mutex_attr);
128*0a6a1f1dSLionel Sambuc #endif
1292fe8fb19SBen Gras }
1302fe8fb19SBen Gras 
1312fe8fb19SBen Gras /*
1322fe8fb19SBen Gras  * Register an atexit routine.  This is suitable either for a cxa_atexit
1332fe8fb19SBen Gras  * or normal atexit type handler.  The __cxa_atexit() name and arguments
1342fe8fb19SBen Gras  * are specified by the C++ ABI.  See:
1352fe8fb19SBen Gras  *
1362fe8fb19SBen Gras  *	http://www.codesourcery.com/cxx-abi/abi.html#dso-dtor
1372fe8fb19SBen Gras  */
138*0a6a1f1dSLionel Sambuc #if defined(__ARM_EABI__) && !defined(lint)
139*0a6a1f1dSLionel Sambuc int
140*0a6a1f1dSLionel Sambuc __aeabi_atexit(void *arg, void (*func)(void *), void *dso);
141*0a6a1f1dSLionel Sambuc 
142*0a6a1f1dSLionel Sambuc int
__aeabi_atexit(void * arg,void (* func)(void *),void * dso)143*0a6a1f1dSLionel Sambuc __aeabi_atexit(void *arg, void (*func)(void *), void *dso)
144*0a6a1f1dSLionel Sambuc {
145*0a6a1f1dSLionel Sambuc 	return __cxa_atexit(func, arg, dso);
146*0a6a1f1dSLionel Sambuc }
147*0a6a1f1dSLionel Sambuc #endif
148*0a6a1f1dSLionel Sambuc 
1492fe8fb19SBen Gras int
__cxa_atexit(void (* func)(void *),void * arg,void * dso)1502fe8fb19SBen Gras __cxa_atexit(void (*func)(void *), void *arg, void *dso)
1512fe8fb19SBen Gras {
1522fe8fb19SBen Gras 	struct atexit_handler *ah;
1532fe8fb19SBen Gras 
1542fe8fb19SBen Gras 	_DIAGASSERT(func != NULL);
1552fe8fb19SBen Gras 
15684d9c625SLionel Sambuc 	mutex_lock(&__atexit_mutex);
1572fe8fb19SBen Gras 
1582fe8fb19SBen Gras 	ah = atexit_handler_alloc(dso);
1592fe8fb19SBen Gras 	if (ah == NULL) {
16084d9c625SLionel Sambuc 		mutex_unlock(&__atexit_mutex);
1612fe8fb19SBen Gras 		return (-1);
1622fe8fb19SBen Gras 	}
1632fe8fb19SBen Gras 
1642fe8fb19SBen Gras 	ah->ah_cxa_atexit = func;
1652fe8fb19SBen Gras 	ah->ah_arg = arg;
1662fe8fb19SBen Gras 	ah->ah_dso = dso;
1672fe8fb19SBen Gras 
1682fe8fb19SBen Gras 	ah->ah_next = atexit_handler_stack;
1692fe8fb19SBen Gras 	atexit_handler_stack = ah;
1702fe8fb19SBen Gras 
17184d9c625SLionel Sambuc 	mutex_unlock(&__atexit_mutex);
1722fe8fb19SBen Gras 	return (0);
1732fe8fb19SBen Gras }
1742fe8fb19SBen Gras 
1752fe8fb19SBen Gras /*
1762fe8fb19SBen Gras  * Run the list of atexit handlers.  If dso is NULL, run all of them,
1772fe8fb19SBen Gras  * otherwise run only those matching the specified dso.
1782fe8fb19SBen Gras  *
1792fe8fb19SBen Gras  * Note that we can be recursively invoked; rtld cleanup is via an
1802fe8fb19SBen Gras  * atexit handler, and rtld cleanup invokes _fini() for DSOs, which
1812fe8fb19SBen Gras  * in turn invokes __cxa_finalize() for the DSO.
1822fe8fb19SBen Gras  */
1832fe8fb19SBen Gras void
__cxa_finalize(void * dso)1842fe8fb19SBen Gras __cxa_finalize(void *dso)
1852fe8fb19SBen Gras {
1862fe8fb19SBen Gras 	static u_int call_depth;
1872fe8fb19SBen Gras 	struct atexit_handler *ah, *dead_handlers = NULL, **prevp;
1882fe8fb19SBen Gras 	void (*cxa_func)(void *);
1892fe8fb19SBen Gras 	void (*atexit_func)(void);
1902fe8fb19SBen Gras 
19184d9c625SLionel Sambuc 	mutex_lock(&__atexit_mutex);
1922fe8fb19SBen Gras 	call_depth++;
1932fe8fb19SBen Gras 
1942fe8fb19SBen Gras 	/*
1952fe8fb19SBen Gras 	 * If we are at call depth 1 (which is usually the "do everything"
1962fe8fb19SBen Gras 	 * call from exit(3)), we go ahead and remove elements from the
1972fe8fb19SBen Gras 	 * list as we call them.  This will prevent any nested calls from
1982fe8fb19SBen Gras 	 * having to traverse elements we've already processed.  If we are
1992fe8fb19SBen Gras 	 * at call depth > 1, we simply mark elements we process as unused.
2002fe8fb19SBen Gras 	 * When the depth 1 caller sees those, it will simply unlink them
2012fe8fb19SBen Gras 	 * for us.
2022fe8fb19SBen Gras 	 */
2032fe8fb19SBen Gras again:
2042fe8fb19SBen Gras 	for (prevp = &atexit_handler_stack; (ah = (*prevp)) != NULL;) {
2052fe8fb19SBen Gras 		if (dso == NULL || dso == ah->ah_dso || ah->ah_atexit == NULL) {
2062fe8fb19SBen Gras 			if (ah->ah_atexit != NULL) {
2072fe8fb19SBen Gras 				void *p = atexit_handler_stack;
2082fe8fb19SBen Gras 				if (ah->ah_dso != NULL) {
2092fe8fb19SBen Gras 					cxa_func = ah->ah_cxa_atexit;
2102fe8fb19SBen Gras 					ah->ah_cxa_atexit = NULL;
2112fe8fb19SBen Gras 					(*cxa_func)(ah->ah_arg);
2122fe8fb19SBen Gras 				} else {
2132fe8fb19SBen Gras 					atexit_func = ah->ah_atexit;
2142fe8fb19SBen Gras 					ah->ah_atexit = NULL;
2152fe8fb19SBen Gras 					(*atexit_func)();
2162fe8fb19SBen Gras 				}
2172fe8fb19SBen Gras 				/* Restart if new atexit handler was added. */
2182fe8fb19SBen Gras 				if (p != atexit_handler_stack)
2192fe8fb19SBen Gras 					goto again;
2202fe8fb19SBen Gras 			}
2212fe8fb19SBen Gras 
2222fe8fb19SBen Gras 			if (call_depth == 1) {
2232fe8fb19SBen Gras 				*prevp = ah->ah_next;
2242fe8fb19SBen Gras 				if (STATIC_HANDLER_P(ah))
2252fe8fb19SBen Gras 					ah->ah_next = NULL;
2262fe8fb19SBen Gras 				else {
2272fe8fb19SBen Gras 					ah->ah_next = dead_handlers;
2282fe8fb19SBen Gras 					dead_handlers = ah;
2292fe8fb19SBen Gras 				}
2302fe8fb19SBen Gras 			} else
2312fe8fb19SBen Gras 				prevp = &ah->ah_next;
2322fe8fb19SBen Gras 		} else
2332fe8fb19SBen Gras 			prevp = &ah->ah_next;
2342fe8fb19SBen Gras 	}
2352fe8fb19SBen Gras 	call_depth--;
23684d9c625SLionel Sambuc 	mutex_unlock(&__atexit_mutex);
2372fe8fb19SBen Gras 
2382fe8fb19SBen Gras 	if (call_depth > 0)
2392fe8fb19SBen Gras 		return;
2402fe8fb19SBen Gras 
2412fe8fb19SBen Gras 	/*
2422fe8fb19SBen Gras 	 * Now free any dead handlers.  Do this even if we're about to
2432fe8fb19SBen Gras 	 * exit, in case a leak-detecting malloc is being used.
2442fe8fb19SBen Gras 	 */
2452fe8fb19SBen Gras 	while ((ah = dead_handlers) != NULL) {
2462fe8fb19SBen Gras 		dead_handlers = ah->ah_next;
2472fe8fb19SBen Gras 		free(ah);
2482fe8fb19SBen Gras 	}
2492fe8fb19SBen Gras }
2502fe8fb19SBen Gras 
2512fe8fb19SBen Gras /*
2522fe8fb19SBen Gras  * Register a function to be performed at exit.
2532fe8fb19SBen Gras  */
2542fe8fb19SBen Gras int
atexit(void (* func)(void))2552fe8fb19SBen Gras atexit(void (*func)(void))
2562fe8fb19SBen Gras {
2572fe8fb19SBen Gras 
2582fe8fb19SBen Gras 	return (__cxa_atexit((void (*)(void *))func, NULL, NULL));
2592fe8fb19SBen Gras }
260