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 */ |
---|