Call exit handlers before notfying the parent

Fixes #941.
This commit is contained in:
Christian Prochaska 2013-10-30 14:46:46 +01:00 committed by Norman Feske
parent 59cb7d9263
commit 1a22664fee

View File

@ -60,33 +60,42 @@ struct atexit_fn
void *fn_dso; /* shared module handle */ void *fn_dso; /* shared module handle */
}; };
/* all members are initialized with 0 */
static struct atexit static struct atexit
{ {
bool enabled;
int index; int index;
struct atexit_fn fns[ATEXIT_SIZE]; struct atexit_fn fns[ATEXIT_SIZE];
} _atexit; } _atexit;
static Lock *atexit_lock() static Lock &atexit_lock()
{ {
static Lock _atexit_lock; static Lock _atexit_lock;
return &_atexit_lock; return _atexit_lock;
}
static void atexit_enable()
{
_atexit.enabled = true;
} }
static int atexit_register(struct atexit_fn *fn) static int atexit_register(struct atexit_fn *fn)
{ {
atexit_lock()->lock(); Lock::Guard atexit_lock_guard(atexit_lock());
if (!_atexit.enabled)
return 0;
if (_atexit.index >= ATEXIT_SIZE) { if (_atexit.index >= ATEXIT_SIZE) {
PERR("Cannot register exit handler - ATEXIT_SIZE reached"); PERR("Cannot register exit handler - ATEXIT_SIZE reached");
atexit_lock()->unlock();
return -1; return -1;
} }
_atexit.fns[_atexit.index++] = *fn; _atexit.fns[_atexit.index++] = *fn;
atexit_lock()->unlock();
return 0; return 0;
} }
@ -142,8 +151,7 @@ void genode___cxa_finalize(void *dso)
struct atexit_fn fn; struct atexit_fn fn;
int n = 0; int n = 0;
atexit_lock()->lock(); atexit_lock().lock();
for (n = _atexit.index; --n >= 0;) { for (n = _atexit.index; --n >= 0;) {
if (_atexit.fns[n].fn_type == ATEXIT_FN_EMPTY) if (_atexit.fns[n].fn_type == ATEXIT_FN_EMPTY)
continue; /* already been called */ continue; /* already been called */
@ -156,17 +164,17 @@ void genode___cxa_finalize(void *dso)
* has already been called. * has already been called.
*/ */
_atexit.fns[n].fn_type = ATEXIT_FN_EMPTY; _atexit.fns[n].fn_type = ATEXIT_FN_EMPTY;
atexit_lock()->unlock(); atexit_lock().unlock();
/* call the function of correct type */ /* call the function of correct type */
if (fn.fn_type == ATEXIT_FN_CXA) if (fn.fn_type == ATEXIT_FN_CXA)
fn.fn_ptr.cxa_func(fn.fn_arg); fn.fn_ptr.cxa_func(fn.fn_arg);
else if (fn.fn_type == ATEXIT_FN_STD) else if (fn.fn_type == ATEXIT_FN_STD)
fn.fn_ptr.std_func(); fn.fn_ptr.std_func();
atexit_lock()->lock();
}
atexit_lock()->unlock(); atexit_lock().lock();
}
atexit_lock().unlock();
} }
@ -177,29 +185,17 @@ extern "C" void __cxa_finalize(void *dso);
*/ */
void genode_exit(int status) void genode_exit(int status)
{ {
/* inform parent about the exit status */ /* call handlers registered with 'atexit()' or '__cxa_atexit()' */
env()->parent()->exit(status); __cxa_finalize(0);
/* /* call destructors for global static objects. */
* Call destructors for static objects.
*
* It happened that a function from the dtors list (namely
* __clean_env_destructor() from the libc) called another function, which
* depended on the Genode environment. Since the Genode environment gets
* destroyed by genode___cxa_finalize(), the functions from the dtors list
* are called before genode___cxa_finalize().
*
*/
void (**func)(); void (**func)();
for (func = &_dtors_start; func != &_dtors_end; (*func++)()); for (func = &_dtors_start; func != &_dtors_end; (*func++)());
/* call all handlers registered with atexit() or __cxa_atexit() */ /* inform parent about the exit status */
__cxa_finalize(0); env()->parent()->exit(status);
/* /* wait for destruction by the parent */
* Wait for destruction by the parent who was supposed to be notified by
* the destructor of the static Genode::Env instance.
*/
sleep_forever(); sleep_forever();
} }
@ -238,6 +234,16 @@ extern "C" int _main()
/* call env() explicitly to setup the environment */ /* call env() explicitly to setup the environment */
(void*)env(); (void*)env();
/*
* Allow exit handlers to be registered.
*
* This is done after the creation of the environment to prevent its
* destruction. The environment is still needed to notify the parent
* after all exit handlers (including static object destructors) have
* been called.
*/
atexit_enable();
/* initialize exception handling */ /* initialize exception handling */
init_exception_handling(); init_exception_handling();