OSDN Git Service

Merge commit 'origin/master' into nptl
[uclinux-h8/uClibc.git] / libpthread / nptl / sysdeps / unix / sysv / linux / fork.c
1 /* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library 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 GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sysdep.h>
26 #include <tls.h>
27 #include "fork.h"
28 #include <hp-timing.h>
29 #include <ldsodefs.h>
30 #include <atomic.h>
31 #include <errno.h>
32
33 unsigned long int *__fork_generation_pointer;
34
35
36
37 /* The single linked list of all currently registered for handlers.  */
38 struct fork_handler *__fork_handlers;
39
40
41 static void
42 fresetlockfiles (void)
43 {
44   FILE *fp;
45 #ifdef __USE_STDIO_FUTEXES__
46   for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen)
47     STDIO_INIT_MUTEX(fp->__lock);
48 #else
49   pthread_mutexattr_t attr;
50
51   pthread_mutexattr_init(&attr);
52   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
53
54   for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen)
55     pthread_mutex_init(&fp->__lock, &attr);
56
57   pthread_mutexattr_destroy(&attr);
58 #endif
59 }
60
61 extern __typeof(fork) __libc_fork;
62 pid_t __libc_fork (void)
63 {
64   pid_t pid;
65   struct used_handler
66   {
67     struct fork_handler *handler;
68     struct used_handler *next;
69   } *allp = NULL;
70
71   /* Run all the registered preparation handlers.  In reverse order.
72      While doing this we build up a list of all the entries.  */
73   struct fork_handler *runp;
74   while ((runp = __fork_handlers) != NULL)
75     {
76       unsigned int oldval = runp->refcntr;
77
78       if (oldval == 0)
79         /* This means some other thread removed the list just after
80            the pointer has been loaded.  Try again.  Either the list
81            is empty or we can retry it.  */
82         continue;
83
84       /* Bump the reference counter.  */
85       if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr,
86                                                 oldval + 1, oldval))
87         /* The value changed, try again.  */
88         continue;
89
90       /* We bumped the reference counter for the first entry in the
91          list.  That means that none of the following entries will
92          just go away.  The unloading code works in the order of the
93          list.
94
95          While executing the registered handlers we are building a
96          list of all the entries so that we can go backward later on.  */
97       while (1)
98         {
99           /* Execute the handler if there is one.  */
100           if (runp->prepare_handler != NULL)
101             runp->prepare_handler ();
102
103           /* Create a new element for the list.  */
104           struct used_handler *newp
105             = (struct used_handler *) alloca (sizeof (*newp));
106           newp->handler = runp;
107           newp->next = allp;
108           allp = newp;
109
110           /* Advance to the next handler.  */
111           runp = runp->next;
112           if (runp == NULL)
113             break;
114
115           /* Bump the reference counter for the next entry.  */
116           atomic_increment (&runp->refcntr);
117         }
118
119       /* We are done.  */
120       break;
121     }
122
123   __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock);
124
125 #ifndef NDEBUG
126   pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid);
127 #endif
128
129   /* We need to prevent the getpid() code to update the PID field so
130      that, if a signal arrives in the child very early and the signal
131      handler uses getpid(), the value returned is correct.  */
132   pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid);
133   THREAD_SETMEM (THREAD_SELF, pid, -parentpid);
134
135 #ifdef ARCH_FORK
136   pid = ARCH_FORK ();
137 #else
138 # error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used"
139   pid = INLINE_SYSCALL (fork, 0);
140 #endif
141
142
143   if (pid == 0)
144     {
145       struct pthread *self = THREAD_SELF;
146
147       assert (THREAD_GETMEM (self, tid) != ppid);
148
149       if (__fork_generation_pointer != NULL)
150         *__fork_generation_pointer += 4;
151
152       /* Adjust the PID field for the new process.  */
153       THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid));
154
155 #if HP_TIMING_AVAIL
156       /* The CPU clock of the thread and process have to be set to zero.  */
157       hp_timing_t now;
158       HP_TIMING_NOW (now);
159       THREAD_SETMEM (self, cpuclock_offset, now);
160       GL(dl_cpuclock_offset) = now;
161 #endif
162
163       /* Reset the file list.  These are recursive mutexes.  */
164       fresetlockfiles ();
165
166       /* Reset locks in the I/O code.  */
167       STDIO_INIT_MUTEX(_stdio_openlist_add_lock);
168
169       /* Run the handlers registered for the child.  */
170       while (allp != NULL)
171         {
172           if (allp->handler->child_handler != NULL)
173             allp->handler->child_handler ();
174
175           /* Note that we do not have to wake any possible waiter.
176              This is the only thread in the new process.  */
177           --allp->handler->refcntr;
178
179           /* XXX We could at this point look through the object pool
180              and mark all objects not on the __fork_handlers list as
181              unused.  This is necessary in case the fork() happened
182              while another thread called dlclose() and that call had
183              to create a new list.  */
184
185           allp = allp->next;
186         }
187
188       /* Initialize the fork lock.  */
189       __fork_lock = (lll_lock_t) LLL_LOCK_INITIALIZER;
190     }
191   else
192     {
193       assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid);
194
195       /* Restore the PID value.  */
196       THREAD_SETMEM (THREAD_SELF, pid, parentpid);
197
198       /* We execute this even if the 'fork' call failed.  */
199       __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock);
200
201       /* Run the handlers registered for the parent.  */
202       while (allp != NULL)
203         {
204           if (allp->handler->parent_handler != NULL)
205             allp->handler->parent_handler ();
206
207           if (atomic_decrement_and_test (&allp->handler->refcntr)
208               && allp->handler->need_signal)
209             lll_futex_wake (allp->handler->refcntr, 1);
210
211           allp = allp->next;
212         }
213     }
214
215   return pid;
216 }
217 weak_alias(__libc_fork,__fork)
218 libc_hidden_proto(fork)
219 weak_alias(__libc_fork,fork)
220 libc_hidden_weak(fork)