diff options
Diffstat (limited to 'libpthread/linuxthreads.old/ptfork.c')
-rw-r--r-- | libpthread/linuxthreads.old/ptfork.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/libpthread/linuxthreads.old/ptfork.c b/libpthread/linuxthreads.old/ptfork.c new file mode 100644 index 000000000..6f1e2d3c9 --- /dev/null +++ b/libpthread/linuxthreads.old/ptfork.c @@ -0,0 +1,167 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* 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" + +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) +{ + if (handler == NULL) return; + if (at_end) { + while(*list != NULL) list = &((*list)->next); + } + newlist->handler = handler; + newlist->next = *list; + *list = newlist; +} + +struct handler_list_block { + struct handler_list prepare, parent, child; +}; + +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)*/ + +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; + + __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(); + pthread_call_handlers(child); + } else { +#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(); + pthread_call_handlers(parent); + } + return pid; +} +strong_alias(__fork,fork) +strong_alias(__fork,vfork) + +#else + +/* 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)) +{ + /* ENOMEM is probably pushing it a little bit. + Take it as `no *virtual* memory' :-) */ + errno = ENOMEM; + return -1; +} + +#endif |