* ctype/ctype.h (__ctype_b, __ctype_toupper, __ctype_tolower):
[platform/upstream/glibc.git] / linuxthreads / ptfork.c
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 pid_t __vfork(void)
113 {
114   return __fork();
115 }
116 weak_alias (__vfork, vfork);