/* * Common routine to implement atexit-like functionality. */ #include #include #include #include #include "atexit.h" /* Make this a weak reference to avoid pulling in malloc. */ void * malloc(size_t) _ATTRIBUTE((__weak__)); __LOCK_INIT(, __atexit_lock); /* * Register a function to be performed at exit or on shared library unload. */ int _DEFUN (__register_exitproc, (type, fn, arg, d), int type _AND void (*fn) (void) _AND void *arg _AND void *d) { struct _on_exit_args * args; register struct _atexit *p; #ifndef __SINGLE_THREAD__ __lock_acquire(__atexit_lock); #endif p = _GLOBAL_REENT->_atexit; if (p == NULL) _GLOBAL_REENT->_atexit = p = &_GLOBAL_REENT->_atexit0; if (p->_ind >= _ATEXIT_SIZE) { #ifndef _ATEXIT_DYNAMIC_ALLOC return -1; #else /* Don't dynamically allocate the atexit array if malloc is not available. */ if (!malloc) return -1; p = (struct _atexit *) malloc (sizeof *p); if (p == NULL) { #ifndef __SINGLE_THREAD__ __lock_release(__atexit_lock); #endif return -1; } p->_ind = 0; p->_next = _GLOBAL_REENT->_atexit; _GLOBAL_REENT->_atexit = p; #ifndef _REENT_SMALL p->_on_exit_args._fntypes = 0; p->_on_exit_args._is_cxa = 0; #endif #endif } if (type != __et_atexit) { #ifdef _REENT_SMALL args = p->_on_exit_args_ptr; if (args == NULL) { if (malloc) args = malloc (sizeof * p->_on_exit_args_ptr); if (args == NULL) { #ifndef __SINGLE_THREAD__ __lock_release(lock); #endif return -1; } args->_fntypes = 0; args->_is_cxa = 0; p->_on_exit_args_ptr = args; } #else args = &p->_on_exit_args; #endif args->_fnargs[p->_ind] = arg; args->_fntypes |= (1 << p->_ind); args->_dso_handle[p->_ind] = d; if (type == __et_cxa) args->_is_cxa |= (1 << p->_ind); } p->_fns[p->_ind++] = fn; #ifndef __SINGLE_THREAD__ __lock_release(__atexit_lock); #endif return 0; }