[444] | 1 | /* Linuxthreads - a simple clone()-based implementation of Posix */ |
---|
| 2 | /* threads for Linux. */ |
---|
| 3 | /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ |
---|
| 4 | /* */ |
---|
| 5 | /* This program is free software; you can redistribute it and/or */ |
---|
| 6 | /* modify it under the terms of the GNU Library General Public License */ |
---|
| 7 | /* as published by the Free Software Foundation; either version 2 */ |
---|
| 8 | /* of the License, or (at your option) any later version. */ |
---|
| 9 | /* */ |
---|
| 10 | /* This program is distributed in the hope that it will be useful, */ |
---|
| 11 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ |
---|
| 12 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ |
---|
| 13 | /* GNU Library General Public License for more details. */ |
---|
| 14 | |
---|
| 15 | /* The "atfork" stuff */ |
---|
| 16 | |
---|
| 17 | #include <errno.h> |
---|
| 18 | #include <stddef.h> |
---|
| 19 | #include <stdlib.h> |
---|
| 20 | #include <unistd.h> |
---|
| 21 | #include "pthread.h" |
---|
| 22 | #include "internals.h" |
---|
| 23 | #include <bits/libc-lock.h> |
---|
| 24 | |
---|
| 25 | struct handler_list { |
---|
| 26 | void (*handler)(void); |
---|
| 27 | struct handler_list * next; |
---|
| 28 | }; |
---|
| 29 | |
---|
| 30 | static pthread_mutex_t pthread_atfork_lock = PTHREAD_MUTEX_INITIALIZER; |
---|
| 31 | static struct handler_list * pthread_atfork_prepare = NULL; |
---|
| 32 | static struct handler_list * pthread_atfork_parent = NULL; |
---|
| 33 | static struct handler_list * pthread_atfork_child = NULL; |
---|
| 34 | |
---|
| 35 | static void pthread_insert_list(struct handler_list ** list, |
---|
| 36 | void (*handler)(void), |
---|
| 37 | struct handler_list * newlist, |
---|
| 38 | int at_end) |
---|
| 39 | { |
---|
| 40 | if (handler == NULL) return; |
---|
| 41 | if (at_end) { |
---|
| 42 | while(*list != NULL) list = &((*list)->next); |
---|
| 43 | } |
---|
| 44 | newlist->handler = handler; |
---|
| 45 | newlist->next = *list; |
---|
| 46 | *list = newlist; |
---|
| 47 | } |
---|
| 48 | |
---|
| 49 | struct handler_list_block { |
---|
| 50 | struct handler_list prepare, parent, child; |
---|
| 51 | }; |
---|
| 52 | |
---|
| 53 | int __pthread_atfork(void (*prepare)(void), |
---|
| 54 | void (*parent)(void), |
---|
| 55 | void (*child)(void)) |
---|
| 56 | { |
---|
| 57 | struct handler_list_block * block = |
---|
| 58 | (struct handler_list_block *) malloc(sizeof(struct handler_list_block)); |
---|
| 59 | if (block == NULL) return ENOMEM; |
---|
| 60 | pthread_mutex_lock(&pthread_atfork_lock); |
---|
| 61 | /* "prepare" handlers are called in LIFO */ |
---|
| 62 | pthread_insert_list(&pthread_atfork_prepare, prepare, &block->prepare, 0); |
---|
| 63 | /* "parent" handlers are called in FIFO */ |
---|
| 64 | pthread_insert_list(&pthread_atfork_parent, parent, &block->parent, 1); |
---|
| 65 | /* "child" handlers are called in FIFO */ |
---|
| 66 | pthread_insert_list(&pthread_atfork_child, child, &block->child, 1); |
---|
| 67 | pthread_mutex_unlock(&pthread_atfork_lock); |
---|
| 68 | return 0; |
---|
| 69 | } |
---|
| 70 | strong_alias (__pthread_atfork, pthread_atfork) |
---|
| 71 | |
---|
| 72 | static inline void pthread_call_handlers(struct handler_list * list) |
---|
| 73 | { |
---|
| 74 | for (/*nothing*/; list != NULL; list = list->next) (list->handler)(); |
---|
| 75 | } |
---|
| 76 | |
---|
| 77 | extern int __libc_fork(void); |
---|
| 78 | |
---|
| 79 | pid_t __fork(void) |
---|
| 80 | { |
---|
| 81 | pid_t pid; |
---|
| 82 | |
---|
| 83 | pthread_mutex_lock(&pthread_atfork_lock); |
---|
| 84 | |
---|
| 85 | pthread_call_handlers(pthread_atfork_prepare); |
---|
| 86 | __pthread_once_fork_prepare(); |
---|
| 87 | __flockfilelist(); |
---|
| 88 | |
---|
| 89 | pid = __libc_fork(); |
---|
| 90 | |
---|
| 91 | if (pid == 0) { |
---|
| 92 | __pthread_reset_main_thread(); |
---|
| 93 | |
---|
| 94 | __fresetlockfiles(); |
---|
| 95 | __pthread_once_fork_child(); |
---|
| 96 | pthread_call_handlers(pthread_atfork_child); |
---|
| 97 | |
---|
| 98 | pthread_mutex_init(&pthread_atfork_lock, NULL); |
---|
| 99 | } else { |
---|
| 100 | __funlockfilelist(); |
---|
| 101 | __pthread_once_fork_parent(); |
---|
| 102 | pthread_call_handlers(pthread_atfork_parent); |
---|
| 103 | |
---|
| 104 | pthread_mutex_unlock(&pthread_atfork_lock); |
---|
| 105 | } |
---|
| 106 | |
---|
| 107 | return pid; |
---|
| 108 | } |
---|
| 109 | |
---|
| 110 | weak_alias (__fork, fork); |
---|
| 111 | |
---|
| 112 | #if !defined(_ELIX_LEVEL) || _ELIX_LEVEL >= 4 |
---|
| 113 | |
---|
| 114 | pid_t __vfork(void) |
---|
| 115 | { |
---|
| 116 | return __fork(); |
---|
| 117 | } |
---|
| 118 | weak_alias (__vfork, vfork); |
---|
| 119 | |
---|
| 120 | #endif /* !_ELIX_LEVEL || _ELIX_LEVEL >= 4 */ |
---|