Update to LGPL v2.1.
[jlayton/glibc.git] / sysdeps / mach / hurd / fork.c
1 /* Copyright (C) 1994,95,96,97,99,2001 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <errno.h>
20 #include <unistd.h>
21 #include <hurd.h>
22 #include <hurd/signal.h>
23 #include <setjmp.h>
24 #include "thread_state.h"
25 #include <sysdep.h>             /* For stack growth direction.  */
26 #include "set-hooks.h"
27 #include <assert.h>
28 #include "hurdmalloc.h"         /* XXX */
29
30
31 /* Things that want to be locked while forking.  */
32 symbol_set_declare (_hurd_fork_locks)
33
34
35 /* Things that want to be called before we fork, to prepare the parent for
36    task_create, when the new child task will inherit our address space.  */
37 DEFINE_HOOK (_hurd_fork_prepare_hook, (void));
38
39 /* Things that want to be called when we are forking, with the above all
40    locked.  They are passed the task port of the child.  The child process
41    is all set up except for doing proc_child, and has no threads yet.  */
42 DEFINE_HOOK (_hurd_fork_setup_hook, (void));
43
44 /* Things to be run in the child fork.  */
45 DEFINE_HOOK (_hurd_fork_child_hook, (void));
46
47 /* Things to be run in the parent fork.  */
48 DEFINE_HOOK (_hurd_fork_parent_hook, (void));
49
50
51 /* Clone the calling process, creating an exact copy.
52    Return -1 for errors, 0 to the new process,
53    and the process ID of the new process to the old process.  */
54 pid_t
55 __fork (void)
56 {
57   jmp_buf env;
58   pid_t pid;
59   size_t i;
60   error_t err;
61   struct hurd_sigstate *volatile ss;
62
63   ss = _hurd_self_sigstate ();
64   __spin_lock (&ss->critical_section_lock);
65
66 #undef  LOSE
67 #define LOSE do { assert_perror (err); goto lose; } while (0) /* XXX */
68
69   if (! setjmp (env))
70     {
71       process_t newproc;
72       task_t newtask;
73       thread_t thread, sigthread;
74       mach_port_urefs_t thread_refs, sigthread_refs;
75       struct machine_thread_state state;
76       mach_msg_type_number_t statecount;
77       mach_port_t *portnames = NULL;
78       mach_msg_type_number_t nportnames = 0;
79       mach_port_type_t *porttypes = NULL;
80       mach_msg_type_number_t nporttypes = 0;
81       thread_t *threads = NULL;
82       mach_msg_type_number_t nthreads = 0;
83       int ports_locked = 0, stopped = 0;
84
85       void resume_threads (void)
86         {
87           if (! stopped)
88             return;
89
90           assert (threads);
91
92           for (i = 0; i < nthreads; ++i)
93             if (threads[i] != ss->thread)
94               __thread_resume (threads[i]);
95           stopped = 0;
96         }
97
98       /* Run things that prepare for forking before we create the task.  */
99       RUN_HOOK (_hurd_fork_prepare_hook, ());
100
101       /* Lock things that want to be locked before we fork.  */
102       {
103         void *const *p;
104         for (p = symbol_set_first_element (_hurd_fork_locks);
105              ! symbol_set_end_p (_hurd_fork_locks, p);
106              ++p)
107           __mutex_lock (*p);
108       }
109       __mutex_lock (&_hurd_siglock);
110
111       newtask = MACH_PORT_NULL;
112       thread = sigthread = MACH_PORT_NULL;
113       newproc = MACH_PORT_NULL;
114
115       /* Lock all the port cells for the standard ports while we copy the
116          address space.  We want to insert all the send rights into the
117          child with the same names.  */
118       for (i = 0; i < _hurd_nports; ++i)
119         __spin_lock (&_hurd_ports[i].lock);
120       ports_locked = 1;
121
122
123       /* Stop all other threads while copying the address space,
124          so nothing changes.  */
125       err = __proc_dostop (_hurd_ports[INIT_PORT_PROC].port, ss->thread);
126       if (!err)
127         {
128           stopped = 1;
129
130 #define XXX_KERNEL_PAGE_FAULT_BUG /* XXX work around page fault bug in mk */
131
132 #ifdef XXX_KERNEL_PAGE_FAULT_BUG
133           /* Gag me with a pitchfork.
134              The bug scenario is this:
135
136              - The page containing __mach_task_self_ is paged out.
137              - The signal thread was faulting on that page when we
138                suspended it via proc_dostop.  It holds some lock, or set
139                some busy bit, or somesuch.
140              - Now this thread faults on that same page.
141              - GRATUIOUS DEADLOCK
142
143              We can break the deadlock by aborting the thread that faulted
144              first, which if the bug happened was the signal thread because
145              it is the only other thread and we just suspended it.
146              */
147           __thread_abort (_hurd_msgport_thread);
148 #endif
149           /* Create the child task.  It will inherit a copy of our memory.  */
150           err = __task_create (__mach_task_self (), 1, &newtask);
151         }
152
153       /* Unlock the global signal state lock, so we do not
154          block the signal thread any longer than necessary.  */
155       __mutex_unlock (&_hurd_siglock);
156
157       if (err)
158         LOSE;
159
160       /* Fetch the names of all ports used in this task.  */
161       if (err = __mach_port_names (__mach_task_self (),
162                                    &portnames, &nportnames,
163                                    &porttypes, &nporttypes))
164         LOSE;
165       if (nportnames != nporttypes)
166         {
167           err = EGRATUITOUS;
168           LOSE;
169         }
170
171       /* Get send rights for all the threads in this task.
172          We want to avoid giving these rights to the child.  */
173       if (err = __task_threads (__mach_task_self (), &threads, &nthreads))
174         LOSE;
175
176       /* Get the child process's proc server port.  We will insert it into
177          the child with the same name as we use for our own proc server
178          port; and we will need it to set the child's message port.  */
179       if (err = __proc_task2proc (_hurd_ports[INIT_PORT_PROC].port,
180                                   newtask, &newproc))
181         LOSE;
182
183       /* Insert all our port rights into the child task.  */
184       thread_refs = sigthread_refs = 0;
185       for (i = 0; i < nportnames; ++i)
186         {
187           if (porttypes[i] & MACH_PORT_TYPE_RECEIVE)
188             {
189               /* This is a receive right.  We want to give the child task
190                  its own new receive right under the same name.  */
191               err = __mach_port_allocate_name (newtask,
192                                                MACH_PORT_RIGHT_RECEIVE,
193                                                portnames[i]);
194               if (err == KERN_NAME_EXISTS)
195                 {
196                   /* It already has a right under this name (?!).  Well,
197                      there is this bizarre old Mach IPC feature (in #ifdef
198                      MACH_IPC_COMPAT in the ukernel) which results in new
199                      tasks getting a new receive right for task special
200                      port number 2.  What else might be going on I'm not
201                      sure.  So let's check.  */
202 #if !MACH_IPC_COMPAT
203 #define TASK_NOTIFY_PORT 2
204 #endif
205                   assert (({ mach_port_t thisport, notify_port;
206                              mach_msg_type_name_t poly;
207                              (__task_get_special_port (newtask,
208                                                        TASK_NOTIFY_PORT,
209                                                        &notify_port) == 0 &&
210                               __mach_port_extract_right
211                               (newtask,
212                                portnames[i],
213                                MACH_MSG_TYPE_MAKE_SEND,
214                                &thisport, &poly) == 0 &&
215                               (thisport == notify_port) &&
216                               __mach_port_deallocate (__mach_task_self (),
217                                                       thisport) == 0 &&
218                               __mach_port_deallocate (__mach_task_self (),
219                                                       notify_port) == 0);
220                            }));
221                 }
222               else if (err)
223                 LOSE;
224               if (porttypes[i] & MACH_PORT_TYPE_SEND)
225                 {
226                   /* Give the child as many send rights for its receive
227                      right as we have for ours.  */
228                   mach_port_urefs_t refs;
229                   mach_port_t port;
230                   mach_msg_type_name_t poly;
231                   if (err = __mach_port_get_refs (__mach_task_self (),
232                                                   portnames[i],
233                                                   MACH_PORT_RIGHT_SEND,
234                                                   &refs))
235                     LOSE;
236                   if (err = __mach_port_extract_right (newtask,
237                                                        portnames[i],
238                                                        MACH_MSG_TYPE_MAKE_SEND,
239                                                        &port, &poly))
240                     LOSE;
241                   if (portnames[i] == _hurd_msgport)
242                     {
243                       /* We just created a receive right for the child's
244                          message port and are about to insert send rights
245                          for it.  Now, while we happen to have a send right
246                          for it, give it to the proc server.  */
247                       mach_port_t old;
248                       if (err = __proc_setmsgport (newproc, port, &old))
249                         LOSE;
250                       if (old != MACH_PORT_NULL)
251                         /* XXX what to do here? */
252                         __mach_port_deallocate (__mach_task_self (), old);
253                       /* The new task will receive its own exceptions
254                          on its message port.  */
255                       if (err = __task_set_special_port (newtask,
256                                                          TASK_EXCEPTION_PORT,
257                                                          port))
258                         LOSE;
259                     }
260                   if (err = __mach_port_insert_right (newtask,
261                                                       portnames[i],
262                                                       port,
263                                                       MACH_MSG_TYPE_MOVE_SEND))
264                     LOSE;
265                   if (refs > 1 &&
266                       (err = __mach_port_mod_refs (newtask,
267                                                    portnames[i],
268                                                    MACH_PORT_RIGHT_SEND,
269                                                    refs - 1)))
270                     LOSE;
271                 }
272               if (porttypes[i] & MACH_PORT_TYPE_SEND_ONCE)
273                 {
274                   /* Give the child a send-once right for its receive right,
275                      since we have one for ours.  */
276                   mach_port_t port;
277                   mach_msg_type_name_t poly;
278                   if (err = __mach_port_extract_right
279                       (newtask,
280                        portnames[i],
281                        MACH_MSG_TYPE_MAKE_SEND_ONCE,
282                        &port, &poly))
283                     LOSE;
284                   if (err = __mach_port_insert_right
285                       (newtask,
286                        portnames[i], port,
287                        MACH_MSG_TYPE_MOVE_SEND_ONCE))
288                     LOSE;
289                 }
290             }
291           else if (porttypes[i] &
292                    (MACH_PORT_TYPE_SEND|MACH_PORT_TYPE_DEAD_NAME))
293             {
294               /* This is a send right or a dead name.
295                  Give the child as many references for it as we have.  */
296               mach_port_urefs_t refs, *record_refs = NULL;
297               mach_port_t insert;
298               mach_msg_type_name_t insert_type = MACH_MSG_TYPE_COPY_SEND;
299               if (portnames[i] == newtask || portnames[i] == newproc)
300                 /* Skip the name we use for the child's task or proc ports.  */
301                 continue;
302               if (portnames[i] == __mach_task_self ())
303                 /* For the name we use for our own task port,
304                    insert the child's task port instead.  */
305                 insert = newtask;
306               else if (portnames[i] == _hurd_ports[INIT_PORT_PROC].port)
307                 {
308                   /* Use the proc server port for the new task.  */
309                   insert = newproc;
310                   insert_type = MACH_MSG_TYPE_COPY_SEND;
311                 }
312               else if (portnames[i] == ss->thread)
313                 {
314                   /* For the name we use for our own thread port, we will
315                      insert the thread port for the child main user thread
316                      after we create it.  */
317                   insert = MACH_PORT_NULL;
318                   record_refs = &thread_refs;
319                   /* Allocate a dead name right for this name as a
320                      placeholder, so the kernel will not chose this name
321                      for any other new port (it might use it for one of the
322                      rights created when a thread is created).  */
323                   if (err = __mach_port_allocate_name
324                       (newtask, MACH_PORT_RIGHT_DEAD_NAME, portnames[i]))
325                     LOSE;
326                 }
327               else if (portnames[i] == _hurd_msgport_thread)
328                 /* For the name we use for our signal thread's thread port,
329                    we will insert the thread port for the child's signal
330                    thread after we create it.  */
331                 {
332                   insert = MACH_PORT_NULL;
333                   record_refs = &sigthread_refs;
334                   /* Allocate a dead name right as a placeholder.  */
335                   if (err = __mach_port_allocate_name
336                       (newtask, MACH_PORT_RIGHT_DEAD_NAME, portnames[i]))
337                     LOSE;
338                 }
339               else
340                 {
341                   /* Skip the name we use for any of our own thread ports.  */
342                   mach_msg_type_number_t j;
343                   for (j = 0; j < nthreads; ++j)
344                     if (portnames[i] == threads[j])
345                       break;
346                   if (j < nthreads)
347                     continue;
348
349                   /* Copy our own send right.  */
350                   insert = portnames[i];
351                 }
352               /* Find out how many user references we have for
353                  the send right with this name.  */
354               if (err = __mach_port_get_refs (__mach_task_self (),
355                                               portnames[i],
356                                               MACH_PORT_RIGHT_SEND,
357                                               record_refs ?: &refs))
358                 LOSE;
359               if (insert == MACH_PORT_NULL)
360                 continue;
361               if (insert == portnames[i] &&
362                   (porttypes[i] & MACH_PORT_TYPE_DEAD_NAME))
363                 /* This is a dead name; allocate another dead name
364                    with the same name in the child.  */
365               allocate_dead_name:
366                 err = __mach_port_allocate_name (newtask,
367                                                  MACH_PORT_RIGHT_DEAD_NAME,
368                                                  portnames[i]);
369               else
370                 /* Insert the chosen send right into the child.  */
371                 err = __mach_port_insert_right (newtask,
372                                                 portnames[i],
373                                                 insert, insert_type);
374               switch (err)
375                 {
376                 case KERN_NAME_EXISTS:
377                   {
378                     /* It already has a send right under this name (?!).
379                        Well, it starts out with a send right for its task
380                        port, and inherits the bootstrap and exception ports
381                        from us.  */
382                     mach_port_t childport;
383                     mach_msg_type_name_t poly;
384                     assert (__mach_port_extract_right (newtask, portnames[i],
385                                                        MACH_MSG_TYPE_COPY_SEND,
386                                                        &childport,
387                                                        &poly) == 0 &&
388                             childport == insert &&
389                             __mach_port_deallocate (__mach_task_self (),
390                                                     childport) == 0);
391                     break;
392                   }
393
394                 case KERN_INVALID_CAPABILITY:
395                   /* The port just died.  It was a send right,
396                      and now it's a dead name.  */
397                   goto allocate_dead_name;
398
399                 default:
400                   LOSE;
401                   break;
402
403                 case KERN_SUCCESS:
404                   /* Give the child as many user references as we have.  */
405                   if (refs > 1 &&
406                       (err = __mach_port_mod_refs (newtask,
407                                                    portnames[i],
408                                                    MACH_PORT_RIGHT_SEND,
409                                                    refs - 1)))
410                     LOSE;
411                 }
412             }
413         }
414
415       /* Unlock the standard port cells.  The child must unlock its own
416          copies too.  */
417       for (i = 0; i < _hurd_nports; ++i)
418         __spin_unlock (&_hurd_ports[i].lock);
419       ports_locked = 0;
420
421       /* All state has now been copied from the parent.  It is safe to
422          resume other parent threads.  */
423       resume_threads ();
424
425       /* Create the child main user thread and signal thread.  */
426       if ((err = __thread_create (newtask, &thread)) ||
427           (err = __thread_create (newtask, &sigthread)))
428         LOSE;
429
430       /* Insert send rights for those threads.  We previously allocated
431          dead name rights with the names we want to give the thread ports
432          in the child as placeholders.  Now deallocate them so we can use
433          the names.  */
434       if ((err = __mach_port_deallocate (newtask, ss->thread)) ||
435           (err = __mach_port_insert_right (newtask, ss->thread,
436                                            thread, MACH_MSG_TYPE_COPY_SEND)))
437         LOSE;
438       /* We have one extra user reference created at the beginning of this
439          function, accounted for by mach_port_names (and which will thus be
440          accounted for in the child below).  This extra right gets consumed
441          in the child by the store into _hurd_sigthread in the child fork.  */
442       if (thread_refs > 1 &&
443           (err = __mach_port_mod_refs (newtask, ss->thread,
444                                        MACH_PORT_RIGHT_SEND,
445                                        thread_refs)))
446         LOSE;
447       if ((_hurd_msgport_thread != MACH_PORT_NULL) /* Let user have none.  */
448           && ((err = __mach_port_deallocate (newtask, _hurd_msgport_thread)) ||
449               (err = __mach_port_insert_right (newtask, _hurd_msgport_thread,
450                                                sigthread,
451                                                MACH_MSG_TYPE_COPY_SEND))))
452         LOSE;
453       if (sigthread_refs > 1 &&
454           (err = __mach_port_mod_refs (newtask, _hurd_msgport_thread,
455                                        MACH_PORT_RIGHT_SEND,
456                                        sigthread_refs - 1)))
457         LOSE;
458
459       /* This seems like a convenient juncture to copy the proc server's
460          idea of what addresses our argv and envp are found at from the
461          parent into the child.  Since we happen to know that the child
462          shares our memory image, it is we who should do this copying.  */
463       {
464         vm_address_t argv, envp;
465         err = (__USEPORT (PROC, __proc_get_arg_locations (port, &argv, &envp))
466                ?: __proc_set_arg_locations (newproc, argv, envp));
467         if (err)
468           LOSE;
469       }
470
471       /* Set the child signal thread up to run the msgport server function
472          using the same signal thread stack copied from our address space.
473          We fetch the state before longjmp'ing it so that miscellaneous
474          registers not affected by longjmp (such as i386 segment registers)
475          are in their normal default state.  */
476       statecount = MACHINE_THREAD_STATE_COUNT;
477       if (err = __thread_get_state (_hurd_msgport_thread,
478                                     MACHINE_THREAD_STATE_FLAVOR,
479                                     (natural_t *) &state, &statecount))
480         LOSE;
481 #if STACK_GROWTH_UP
482 #define THREADVAR_SPACE (__hurd_threadvar_max \
483                          * sizeof *__hurd_sightread_variables)
484       if (__hurd_sigthread_stack_base == 0)
485         {
486           state.SP &= __hurd_threadvar_stack_mask;
487           state.SP += __hurd_threadvar_stack_offset + THREADVAR_SPACE;
488         }
489       else
490         state.SP = __hurd_sigthread_stack_base;
491 #else
492       if (__hurd_sigthread_stack_end == 0)
493         {
494           /* The signal thread has a normal stack assigned by cthreads.
495              The threadvar_stack variables conveniently tell us how
496              to get to the highest address in the stack, just below
497              the per-thread variables.  */
498           state.SP &= __hurd_threadvar_stack_mask;
499           state.SP += __hurd_threadvar_stack_offset;
500         }
501       else
502         state.SP = __hurd_sigthread_stack_end;
503 #endif
504       MACHINE_THREAD_STATE_SET_PC (&state,
505                                    (unsigned long int) _hurd_msgport_receive);
506       if (err = __thread_set_state (sigthread, MACHINE_THREAD_STATE_FLAVOR,
507                                     (natural_t *) &state, statecount))
508         LOSE;
509       /* We do not thread_resume SIGTHREAD here because the child
510          fork needs to do more setup before it can take signals.  */
511
512       /* Set the child user thread up to return 1 from the setjmp above.  */
513       _hurd_longjmp_thread_state (&state, env, 1);
514       if (err = __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR,
515                                     (natural_t *) &state, statecount))
516         LOSE;
517
518       /* Get the PID of the child from the proc server.  We must do this
519          before calling proc_child below, because at that point any
520          authorized POSIX.1 process may kill the child task with SIGKILL.  */
521       if (err = __USEPORT (PROC, __proc_task2pid (port, newtask, &pid)))
522         LOSE;
523
524       /* Register the child with the proc server.  It is important that
525          this be that last thing we do before starting the child thread
526          running.  Once proc_child has been done for the task, it appears
527          as a POSIX.1 process.  Any errors we get must be detected before
528          this point, and the child must have a message port so it responds
529          to POSIX.1 signals.  */
530       if (err = __USEPORT (PROC, __proc_child (port, newtask)))
531         LOSE;
532
533       /* This must be the absolutely last thing we do; we can't assume that
534          the child will remain alive for even a moment once we do this.  We
535          ignore errors because we have committed to the fork and are not
536          allowed to return them after the process becomes visible to
537          POSIX.1 (which happened right above when we called proc_child).  */
538       (void) __thread_resume (thread);
539
540     lose:
541       if (ports_locked)
542         for (i = 0; i < _hurd_nports; ++i)
543           __spin_unlock (&_hurd_ports[i].lock);
544
545       resume_threads ();
546
547       if (newtask != MACH_PORT_NULL)
548         {
549           if (err)
550             __task_terminate (newtask);
551           __mach_port_deallocate (__mach_task_self (), newtask);
552         }
553       if (thread != MACH_PORT_NULL)
554         __mach_port_deallocate (__mach_task_self (), thread);
555       if (sigthread != MACH_PORT_NULL)
556         __mach_port_deallocate (__mach_task_self (), sigthread);
557       if (newproc != MACH_PORT_NULL)
558         __mach_port_deallocate (__mach_task_self (), newproc);
559
560       if (portnames)
561         __vm_deallocate (__mach_task_self (),
562                          (vm_address_t) portnames,
563                          nportnames * sizeof (*portnames));
564       if (porttypes)
565         __vm_deallocate (__mach_task_self (),
566                          (vm_address_t) porttypes,
567                          nporttypes * sizeof (*porttypes));
568       if (threads)
569         {
570           for (i = 0; i < nthreads; ++i)
571             __mach_port_deallocate (__mach_task_self (), threads[i]);
572           __vm_deallocate (__mach_task_self (),
573                            (vm_address_t) threads,
574                            nthreads * sizeof (*threads));
575         }
576
577       /* Run things that want to run in the parent to restore it to
578          normality.  Usually prepare hooks and parent hooks are
579          symmetrical: the prepare hook arrests state in some way for the
580          fork, and the parent hook restores the state for the parent to
581          continue executing normally.  */
582       RUN_HOOK (_hurd_fork_parent_hook, ());
583     }
584   else
585     {
586       struct hurd_sigstate *oldstates;
587
588       /* We are the child task.  Unlock the standard port cells, which were
589          locked in the parent when we copied its memory.  The parent has
590          inserted send rights with the names that were in the cells then.  */
591       for (i = 0; i < _hurd_nports; ++i)
592         __spin_unlock (&_hurd_ports[i].lock);
593
594       /* We are the only thread in this new task, so we will
595          take the task-global signals.  */
596       _hurd_sigthread = ss->thread;
597
598       /* Unchain the sigstate structures for threads that existed in the
599          parent task but don't exist in this task (the child process).
600          Delay freeing them until later because some of the further setup
601          and unlocking might be required for free to work.  */
602       oldstates = _hurd_sigstates;
603       if (oldstates == ss)
604         oldstates = ss->next;
605       else
606         {
607           while (_hurd_sigstates->next != ss)
608             _hurd_sigstates = _hurd_sigstates->next;
609           _hurd_sigstates->next = ss->next;
610         }
611       ss->next = NULL;
612       _hurd_sigstates = ss;
613       __mutex_unlock (&_hurd_siglock);
614
615       /* Fetch our new process IDs from the proc server.  No need to
616          refetch our pgrp; it is always inherited from the parent (so
617          _hurd_pgrp is already correct), and the proc server will send us a
618          proc_newids notification when it changes.  */
619       err = __USEPORT (PROC, __proc_getpids (port, &_hurd_pid, &_hurd_ppid,
620                                              &_hurd_orphaned));
621
622       /* Forking clears the trace flag.  */
623       __sigemptyset (&_hurdsig_traced);
624
625       /* Run things that want to run in the child task to set up.  */
626       RUN_HOOK (_hurd_fork_child_hook, ());
627
628       /* Set up proc server-assisted fault recovery for the signal thread.  */
629       _hurdsig_fault_init ();
630
631       /* Start the signal thread listening on the message port.  */
632       if (!err)
633         err = __thread_resume (_hurd_msgport_thread);
634
635       /* Free the old sigstate structures.  */
636       while (oldstates != NULL)
637         {
638           struct hurd_sigstate *next = oldstates->next;
639           free (oldstates);
640           oldstates = next;
641         }
642       /* XXX what to do if we have any errors here? */
643
644       pid = 0;
645     }
646
647   /* Unlock things we locked before creating the child task.
648      They are locked in both the parent and child tasks.  */
649   {
650     void *const *p;
651     for (p = symbol_set_first_element (_hurd_fork_locks);
652          ! symbol_set_end_p (_hurd_fork_locks, p);
653          ++p)
654       __mutex_unlock (*p);
655   }
656
657   _hurd_critical_section_unlock (ss);
658
659   return err ? __hurd_fail (err) : pid;
660 }
661
662 weak_alias (__fork, fork)