Module: xenomai-jki Branch: for-forge Commit: d373c3a3ee1dd1cce7c6fe7d3b4205af0bfce5aa URL: http://git.xenomai.org/?p=xenomai-jki.git;a=commit;h=d373c3a3ee1dd1cce7c6fe7d3b4205af0bfce5aa
Author: Jan Kiszka <jan.kis...@siemens.com> Date: Mon Jan 5 15:48:14 2015 +0100 lib/cobalt: Fix ordering of fork handler Currently, fork handlers run in more or less random order after successive forks because pthread_atfork is re-executed for some handlers. This can cause the heap being unmapped after __init_cobalt was executed, leaving cobalt_current_window in an invalid state. One result of this is a crashing sysregd when run as unprivileged user, thus when it forked fusermount from the forked daemon. Fix the issue by performing the after-fork work centrally, in a well-defined order. Signed-off-by: Jan Kiszka <jan.kis...@siemens.com> --- lib/cobalt/current.c | 8 ++------ lib/cobalt/current.h | 2 ++ lib/cobalt/init.c | 29 +++++++++++++++++++---------- lib/cobalt/internal.h | 2 ++ lib/cobalt/printf.c | 3 +-- lib/cobalt/umm.c | 4 +--- lib/cobalt/umm.h | 2 ++ 7 files changed, 29 insertions(+), 21 deletions(-) diff --git a/lib/cobalt/current.c b/lib/cobalt/current.c index b7d5b6e..a8bc330 100644 --- a/lib/cobalt/current.c +++ b/lib/cobalt/current.c @@ -26,8 +26,6 @@ static DEFINE_PRIVATE_LIST(tsd_hooks); -static void child_fork_handler(void); - #ifdef HAVE_TLS __thread __attribute__ ((tls_model (CONFIG_XENO_TLS_MODEL))) @@ -53,7 +51,7 @@ static inline void __cobalt_clear_tsd(void) static void init_current_keys(void) { - pthread_atfork(NULL, NULL, &child_fork_handler); + cobalt_current = XN_NO_HANDLE; } #else /* !HAVE_TLS */ @@ -85,8 +83,6 @@ static void init_current_keys(void) if (err) goto error_exit; - pthread_atfork(NULL, NULL, &child_fork_handler); - err = pthread_key_create(&cobalt_current_window_key, NULL); if (err) { error_exit: @@ -97,7 +93,7 @@ static void init_current_keys(void) #endif /* !HAVE_TLS */ -static void child_fork_handler(void) +void cobalt_clear_tsd(void) { struct cobalt_tsd_hook *th; diff --git a/lib/cobalt/current.h b/lib/cobalt/current.h index 3e28b83..069ee1c 100644 --- a/lib/cobalt/current.h +++ b/lib/cobalt/current.h @@ -93,4 +93,6 @@ void cobalt_init_current_keys(void); void cobalt_set_tsd(__u32 u_winoff); +void cobalt_clear_tsd(void); + #endif /* _LIB_COBALT_CURRENT_H */ diff --git a/lib/cobalt/init.c b/lib/cobalt/init.c index dfe1150..b7c8f76 100644 --- a/lib/cobalt/init.c +++ b/lib/cobalt/init.c @@ -107,6 +107,24 @@ static void low_init(void) static void __init_cobalt(void); +static void cobalt_fork_handler(void) +{ + cobalt_unmap_umm(); + cobalt_clear_tsd(); + cobalt_print_init_atfork(); +#ifdef HAVE_PTHREAD_ATFORK + /* + * Upon fork, in case the parent required init deferral, this + * is the forkee's responsibility to call __libcobalt_init() + * for bootstrapping the services the same way. On systems + * with no fork() support, clients are not supposed to, well, + * fork in the first place, so we don't take any provision for + * this event. + */ + __init_cobalt(); +#endif +} + void __libcobalt_init(void) { struct sigaction sa; @@ -118,21 +136,12 @@ void __libcobalt_init(void) sa.sa_flags = SA_SIGINFO; sigaction(SIGDEBUG, &sa, &__cobalt_orig_sigdebug); -#ifdef HAVE_PTHREAD_ATFORK /* - * Upon fork, in case the parent required init deferral, this - * is the forkee's responsibility to call __libcobalt_init() - * for bootstrapping the services the same way. On systems - * with no fork() support, clients are not supposed to, well, - * fork in the first place, so we don't take any provision for - * this event. - * * NOTE: a placeholder for pthread_atfork() may return an * error status with uClibc, so we don't check the return * value on purpose. */ - pthread_atfork(NULL, NULL, __init_cobalt); -#endif + pthread_atfork(NULL, NULL, cobalt_fork_handler); if (sizeof(struct cobalt_mutex_shadow) > sizeof(pthread_mutex_t)) { report_error("sizeof(pthread_mutex_t): %d <" diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h index c7350be..e126480 100644 --- a/lib/cobalt/internal.h +++ b/lib/cobalt/internal.h @@ -45,6 +45,8 @@ void cobalt_thread_init(void); void cobalt_print_init(void); +void cobalt_print_init_atfork(void); + void cobalt_print_exit(void); void cobalt_ticks_init(unsigned long long freq); diff --git a/lib/cobalt/printf.c b/lib/cobalt/printf.c index e391f96..f19f4ea 100644 --- a/lib/cobalt/printf.c +++ b/lib/cobalt/printf.c @@ -670,7 +670,7 @@ static void spawn_printer_thread(void) pthread_create(&printer_thread, &thattr, printer_loop, NULL); } -static void forked_child_init(void) +void cobalt_print_init_atfork(void) { struct print_buffer *my_buffer = pthread_getspecific(buffer_key); struct print_buffer **pbuffer = &first_buffer; @@ -791,7 +791,6 @@ void cobalt_print_init(void) pthread_cond_init(&printer_wakeup, NULL); spawn_printer_thread(); - pthread_atfork(NULL, NULL, forked_child_init); rt_print_auto_init(1); atexit(rt_print_flush_buffers); diff --git a/lib/cobalt/umm.c b/lib/cobalt/umm.c index a09b2d6..4a881a3 100644 --- a/lib/cobalt/umm.c +++ b/lib/cobalt/umm.c @@ -75,7 +75,7 @@ static void *__map_umm(const char *name, uint32_t *size_r) #define map_umm(__name, __size_r) __map_umm("/dev/rtdm/" __name, __size_r) -static void unmap_on_fork(void) +void cobalt_unmap_umm(void) { void *addr; @@ -121,8 +121,6 @@ static void init_loadup(__u32 vdso_offset) { uint32_t size; - pthread_atfork(NULL, NULL, unmap_on_fork); - cobalt_umm_shared = map_umm(COBALT_MEMDEV_SHARED, &size); if (cobalt_umm_shared == MAP_FAILED) { report_error("cannot map shared umm area: %s", diff --git a/lib/cobalt/umm.h b/lib/cobalt/umm.h index 5647758..b592968 100644 --- a/lib/cobalt/umm.h +++ b/lib/cobalt/umm.h @@ -22,6 +22,8 @@ void cobalt_init_umm(__u32 vdso_offset); +void cobalt_unmap_umm(void); + struct xnvdso; extern struct xnvdso *cobalt_vdso; _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git