Module: xenomai-head Branch: master Commit: def92aae66fe3335664c92e4b212cc52fd501365 URL: http://git.xenomai.org/?p=xenomai-head.git;a=commit;h=def92aae66fe3335664c92e4b212cc52fd501365
Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org> Date: Sun Aug 22 14:11:16 2010 +0200 common: fix private heap unmapping upon fork. In order to fix private heap unmapping/remapping behaviour with dlopen, an atfork handler was installed which unmaps and remaps the private heap by commit e70ce487ac7ab62cd8de28af8ddccf7309f1259d Unfortunately, the atfork handler for semaphore heaps used a system call to get private heap data which turned out returning data for the shared heap after fork, leading to: - a simple segfault if the private heap and shared heap have different sizes; - silent corruption of the shared heap when using private objects in the child otherwise. So, we fix this by only unmapping the private heap upon fork, and waiting for any skin to be bound in the child process for remapping the private heap. --- src/skins/common/sem_heap.c | 86 +++++++++++++++++++++++++------------------ 1 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/skins/common/sem_heap.c b/src/skins/common/sem_heap.c index 2adbdbc..c2f62cd 100644 --- a/src/skins/common/sem_heap.c +++ b/src/skins/common/sem_heap.c @@ -16,10 +16,16 @@ #include <asm-generic/bits/current.h> #include "sem_heap.h" -unsigned long xeno_sem_heap[2] = { 0, 0 }; +#define PRIVATE 0 +#define SHARED 1 struct xnvdso *nkvdso; +unsigned long xeno_sem_heap[2] = { 0, 0 }; + +static pthread_once_t init_private_heap = PTHREAD_ONCE_INIT; +static struct xnheap_desc private_hdesc; + void *xeno_map_heap(struct xnheap_desc *hd) { int fd, ret; @@ -47,43 +53,42 @@ void *xeno_map_heap(struct xnheap_desc *hd) static void *map_sem_heap(unsigned int shared) { - struct xnheap_desc hdesc; + struct xnheap_desc global_hdesc, *hdesc; int ret; - ret = XENOMAI_SYSCALL2(__xn_sys_sem_heap, &hdesc, shared); + hdesc = shared ? &global_hdesc : &private_hdesc; + ret = XENOMAI_SYSCALL2(__xn_sys_sem_heap, hdesc, shared); if (ret < 0) { errno = -ret; perror("Xenomai: sys_sem_heap"); return MAP_FAILED; } - return xeno_map_heap(&hdesc); + return xeno_map_heap(hdesc); } -static void unmap_sem_heap(unsigned long addr, unsigned int shared) +static void unmap_on_fork(void) { - struct xnheap_desc hdesc; - int ret; - - ret = XENOMAI_SYSCALL2(__xn_sys_sem_heap, &hdesc, shared); - if (ret < 0) { - errno = -ret; - perror("Xenomai: unmap sem_heap"); - return; - } - - munmap((void *)addr, hdesc.size); -} - -static void remap_on_fork(void) -{ - unmap_sem_heap(xeno_sem_heap[0], 0); - - xeno_sem_heap[0] = (unsigned long)map_sem_heap(0); - if (xeno_sem_heap[0] == (unsigned long)MAP_FAILED) { - perror("Xenomai: mmap local sem heap"); - exit(EXIT_FAILURE); - } + /* + Remapping the private heap must be done after the process has been + bound again, in order for it to have a new private heap, + Otherwise the global heap would be used instead, which + leads to unwanted effects. + + We set xeno_sem_heap[PRIVATE] to NULL on machines with an + MMU, so that any reference to the private heap prior to + re-binding will cause a segmentation fault. + + On machines without an MMU, we keep the address unchanged, + it will cause unwanted mutual exclusion with the father, + but at least, we will not get any memory corruption. + */ + + munmap((void *)xeno_sem_heap[PRIVATE], private_hdesc.size); +#ifdef CONFIG_MMU + xeno_sem_heap[PRIVATE] = NULL; +#endif + init_private_heap = PTHREAD_ONCE_INIT; } static void xeno_init_vdso(void) @@ -98,22 +103,29 @@ static void xeno_init_vdso(void) exit(EXIT_FAILURE); } - nkvdso = (struct xnvdso *)(xeno_sem_heap[1] + sysinfo.vdso); + nkvdso = (struct xnvdso *)(xeno_sem_heap[SHARED] + sysinfo.vdso); if (!xnvdso_test_feature(XNVDSO_FEAT_DROP_U_MODE)) xeno_current_warn_old(); } -static void xeno_init_sem_heaps_inner(void) +/* Will be called once at library loading time, and when re-binding + after a fork */ +static void xeno_init_private_heap(void) { - xeno_sem_heap[0] = (unsigned long)map_sem_heap(0); - if (xeno_sem_heap[0] == (unsigned long)MAP_FAILED) { + xeno_sem_heap[PRIVATE] = (unsigned long)map_sem_heap(PRIVATE); + if (xeno_sem_heap[PRIVATE] == (unsigned long)MAP_FAILED) { perror("Xenomai: mmap local sem heap"); exit(EXIT_FAILURE); } - pthread_atfork(NULL, NULL, remap_on_fork); +} - xeno_sem_heap[1] = (unsigned long)map_sem_heap(1); - if (xeno_sem_heap[1] == (unsigned long)MAP_FAILED) { +/* Will be called only once, at library loading time. */ +static void xeno_init_rest_once(void) +{ + pthread_atfork(NULL, NULL, unmap_on_fork); + + xeno_sem_heap[SHARED] = (unsigned long)map_sem_heap(SHARED); + if (xeno_sem_heap[SHARED] == (unsigned long)MAP_FAILED) { perror("Xenomai: mmap global sem heap"); exit(EXIT_FAILURE); } @@ -123,6 +135,8 @@ static void xeno_init_sem_heaps_inner(void) void xeno_init_sem_heaps(void) { - static pthread_once_t init_sem_heaps_once = PTHREAD_ONCE_INIT; - pthread_once(&init_sem_heaps_once, &xeno_init_sem_heaps_inner); + static pthread_once_t init_rest_once = PTHREAD_ONCE_INIT; + + pthread_once(&init_private_heap, &xeno_init_private_heap); + pthread_once(&init_rest_once, &xeno_init_rest_once); } _______________________________________________ Xenomai-git mailing list Xenomai-git@gna.org https://mail.gna.org/listinfo/xenomai-git