123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- /* 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);
- extern __typeof(fork) __libc_fork;
- pid_t __fork(void) attribute_hidden;
- 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)
- pid_t vfork(void)
- {
- return __fork();
- }
- #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
|