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