diff options
Diffstat (limited to 'libpthread/linuxthreads/ptfork.c')
-rw-r--r-- | libpthread/linuxthreads/ptfork.c | 173 |
1 files changed, 124 insertions, 49 deletions
diff --git a/libpthread/linuxthreads/ptfork.c b/libpthread/linuxthreads/ptfork.c index 71404acf1..6f1e2d3c9 100644 --- a/libpthread/linuxthreads/ptfork.c +++ b/libpthread/linuxthreads/ptfork.c @@ -12,81 +12,156 @@ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU Library General Public License for more details. */ +/* mods for uClibc: removed strong alias and defined funcs properly */ + /* The "atfork" stuff */ #include <errno.h> + +#ifdef __ARCH_USE_MMU__ + +#include <bits/uClibc_mutex.h> #include <stddef.h> #include <stdlib.h> #include <unistd.h> #include "pthread.h" #include "internals.h" -#include <bits/libc-lock.h> -#include "fork.h" -pid_t __pthread_fork (struct fork_block *b) +struct handler_list { + void (*handler)(void); + struct handler_list * next; +}; + +static pthread_mutex_t pthread_atfork_lock = PTHREAD_MUTEX_INITIALIZER; +static struct handler_list * pthread_atfork_prepare = NULL; +static struct handler_list * pthread_atfork_parent = NULL; +static struct handler_list * pthread_atfork_child = NULL; + +#ifdef __MALLOC__ +__UCLIBC_MUTEX_EXTERN(__malloc_heap_lock); +__UCLIBC_MUTEX_EXTERN(__malloc_sbrk_lock); +#ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ +__UCLIBC_MUTEX_EXTERN(__malloc_mmb_heap_lock); +#endif +#elif defined(__MALLOC_STANDARD__) || defined(__MALLOC_SIMPLE__) +__UCLIBC_MUTEX_EXTERN(__malloc_lock); +#endif + +static void pthread_insert_list(struct handler_list ** list, + void (*handler)(void), + struct handler_list * newlist, + int at_end) { - pid_t pid; - list_t *runp; + if (handler == NULL) return; + if (at_end) { + while(*list != NULL) list = &((*list)->next); + } + newlist->handler = handler; + newlist->next = *list; + *list = newlist; +} - __libc_lock_lock (b->lock); +struct handler_list_block { + struct handler_list prepare, parent, child; +}; - /* Run all the registered preparation handlers. In reverse order. */ - list_for_each_prev (runp, &b->prepare_list) - { - struct fork_handler *curp; - curp = list_entry (runp, struct fork_handler, list); - curp->handler (); - } +int pthread_atfork(void (*prepare)(void), + void (*parent)(void), + void (*child)(void)) +{ + struct handler_list_block * block = + (struct handler_list_block *) malloc(sizeof(struct handler_list_block)); + if (block == NULL) return ENOMEM; + __pthread_mutex_lock(&pthread_atfork_lock); + /* "prepare" handlers are called in LIFO */ + pthread_insert_list(&pthread_atfork_prepare, prepare, &block->prepare, 0); + /* "parent" handlers are called in FIFO */ + pthread_insert_list(&pthread_atfork_parent, parent, &block->parent, 1); + /* "child" handlers are called in FIFO */ + pthread_insert_list(&pthread_atfork_child, child, &block->child, 1); + __pthread_mutex_unlock(&pthread_atfork_lock); + return 0; +} +/*strong_alias (__pthread_atfork, pthread_atfork)*/ - __pthread_once_fork_prepare(); - __flockfilelist(); +static __inline__ void pthread_call_handlers(struct handler_list * list) +{ + for (/*nothing*/; list != NULL; list = list->next) (list->handler)(); +} + +void __pthread_once_fork_prepare(void); +void __pthread_once_fork_child(void); +void __pthread_once_fork_parent(void); + +static pid_t __fork(void) +{ + pid_t pid; + struct handler_list * prepare, * child, * parent; - pid = ARCH_FORK (); + __pthread_mutex_lock(&pthread_atfork_lock); + prepare = pthread_atfork_prepare; + child = pthread_atfork_child; + parent = pthread_atfork_parent; + pthread_call_handlers(prepare); + __pthread_once_fork_prepare(); +#ifdef __MALLOC__ + __pthread_mutex_lock(&__malloc_sbrk_lock); + __pthread_mutex_lock(&__malloc_heap_lock); +#ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ + __pthread_mutex_lock(&__malloc_mmb_heap_lock); +#endif +#elif defined(__MALLOC_STANDARD__) || defined(__MALLOC_SIMPLE__) + __pthread_mutex_lock(&__malloc_lock); +#endif + + pid = __libc_fork(); if (pid == 0) { +#if defined(__MALLOC_STANDARD__) || defined(__MALLOC_SIMPLE__) + __libc_lock_init_recursive(__malloc_lock); +#elif defined(__MALLOC__) +#ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ + __libc_lock_init_adaptive(__malloc_mmb_heap_lock); +#endif + __libc_lock_init_adaptive(__malloc_heap_lock); + __libc_lock_init(__malloc_sbrk_lock); +#endif + __libc_lock_init_adaptive(pthread_atfork_lock); __pthread_reset_main_thread(); - __fresetlockfiles(); __pthread_once_fork_child(); - - /* Run the handlers registered for the child. */ - list_for_each (runp, &b->child_list) - { - struct fork_handler *curp; - curp = list_entry (runp, struct fork_handler, list); - curp->handler (); - } - - __libc_lock_init (b->lock); + pthread_call_handlers(child); } else { - __funlockfilelist(); +#if defined(__MALLOC_STANDARD__) || defined(__MALLOC_SIMPLE__) + __pthread_mutex_unlock(&__malloc_lock); +#elif defined(__MALLOC__) +#ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ + __pthread_mutex_unlock(&__malloc_mmb_heap_lock); +#endif + __pthread_mutex_unlock(&__malloc_heap_lock); + __pthread_mutex_unlock(&__malloc_sbrk_lock); +#endif + __pthread_mutex_unlock(&pthread_atfork_lock); __pthread_once_fork_parent(); - - /* Run the handlers registered for the parent. */ - list_for_each (runp, &b->parent_list) - { - struct fork_handler *curp; - curp = list_entry (runp, struct fork_handler, list); - curp->handler (); - } - - __libc_lock_unlock (b->lock); + pthread_call_handlers(parent); } - return pid; } +strong_alias(__fork,fork) +strong_alias(__fork,vfork) -/* psm: have no idea why these are here, sjhill? */ -#if 0 /*def SHARED*/ -pid_t __fork (void) -{ - return __libc_fork (); -} -weak_alias (__fork, fork) +#else -pid_t __vfork(void) +/* We can't support pthread_atfork without MMU, since we don't have + fork(), and we can't offer the correct semantics for vfork(). */ +int pthread_atfork(void (*prepare)(void), + void (*parent)(void), + void (*child)(void)) { - return __libc_fork (); + /* ENOMEM is probably pushing it a little bit. + Take it as `no *virtual* memory' :-) */ + errno = ENOMEM; + return -1; } -weak_alias (__vfork, vfork) + #endif |