(root)/
glibc-2.38/
sysdeps/
mach/
hurd/
_Fork.c
       1  /* Copyright (C) 1994-2023 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, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <unistd.h>
      20  #include <hurd.h>
      21  #include <hurd/signal.h>
      22  #include <hurd/threadvar.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  #include <tls.h>
      30  #include <malloc/malloc-internal.h>
      31  #include <nss/nss_database.h>
      32  #include <unwind-link.h>
      33  #include <register-atfork.h>
      34  
      35  #undef __fork
      36  
      37  
      38  /* Things that want to be locked while forking.  */
      39  symbol_set_declare (_hurd_fork_locks)
      40  
      41  /* Things that want to be called before we fork, to prepare the parent for
      42     task_create, when the new child task will inherit our address space.  */
      43  DEFINE_HOOK (_hurd_fork_prepare_hook, (void));
      44  
      45  /* Things that want to be called when we are forking, with the above all
      46     locked.  They are passed the task port of the child.  The child process
      47     is all set up except for doing proc_child, and has no threads yet.  */
      48  DEFINE_HOOK (_hurd_fork_setup_hook, (void));
      49  
      50  /* Things to be run in the child fork.  */
      51  DEFINE_HOOK (_hurd_fork_child_hook, (void));
      52  
      53  /* Things to be run in the parent fork.  */
      54  DEFINE_HOOK (_hurd_fork_parent_hook, (void));
      55  
      56  
      57  /* Clone the calling process, creating an exact copy.
      58     Return -1 for errors, 0 to the new process,
      59     and the process ID of the new process to the old process.  */
      60  pid_t
      61  _Fork (void)
      62  {
      63    jmp_buf env;
      64    pid_t pid;
      65    size_t i;
      66    error_t err;
      67    struct hurd_sigstate *volatile ss;
      68  
      69    ss = _hurd_self_sigstate ();
      70  retry:
      71    __spin_lock (&ss->critical_section_lock);
      72  
      73  #undef	LOSE
      74  #define LOSE do { assert_perror (err); goto lose; } while (0) /* XXX */
      75  
      76    if (! setjmp (env))
      77      {
      78        process_t newproc;
      79        task_t newtask;
      80        thread_t thread, sigthread;
      81        mach_port_urefs_t thread_refs, sigthread_refs;
      82        struct machine_thread_state state;
      83        mach_msg_type_number_t statecount;
      84        mach_port_t *portnames = NULL;
      85        mach_msg_type_number_t nportnames = 0;
      86        mach_port_type_t *porttypes = NULL;
      87        mach_msg_type_number_t nporttypes = 0;
      88        thread_t *threads = NULL;
      89        mach_msg_type_number_t nthreads = 0;
      90        int ports_locked = 0, stopped = 0;
      91  
      92        void resume_threads (void)
      93  	{
      94  	  if (! stopped)
      95  	    return;
      96  
      97  	  assert (threads);
      98  
      99  	  for (i = 0; i < nthreads; ++i)
     100  	    if (threads[i] != ss->thread)
     101  	      __thread_resume (threads[i]);
     102  	  stopped = 0;
     103  	}
     104  
     105        /* Run things that prepare for forking before we create the task.  */
     106        RUN_HOOK (_hurd_fork_prepare_hook, ());
     107  
     108        /* Lock things that want to be locked before we fork.  */
     109        {
     110  	void *const *p;
     111  	for (p = symbol_set_first_element (_hurd_fork_locks);
     112  	     ! symbol_set_end_p (_hurd_fork_locks, p);
     113  	     ++p)
     114  	  __mutex_lock (*p);
     115        }
     116        __mutex_lock (&_hurd_siglock);
     117  
     118        /* Acquire malloc locks.  This needs to come last because fork
     119  	 handlers may use malloc, and the libio list lock has an
     120  	 indirect malloc dependency as well (via the getdelim
     121  	 function).  */
     122        _hurd_malloc_fork_prepare ();
     123  
     124        newtask = MACH_PORT_NULL;
     125        thread = sigthread = MACH_PORT_NULL;
     126        newproc = MACH_PORT_NULL;
     127  
     128        /* Lock all the port cells for the standard ports while we copy the
     129  	 address space.  We want to insert all the send rights into the
     130  	 child with the same names.  */
     131        for (i = 0; i < _hurd_nports; ++i)
     132  	__spin_lock (&_hurd_ports[i].lock);
     133        ports_locked = 1;
     134  
     135  
     136        /* Keep our SS locked while stopping other threads, so they don't get a
     137           chance to have it locked in the copied space.  */
     138        __spin_lock (&ss->lock);
     139        /* Stop all other threads while copying the address space,
     140  	 so nothing changes.  */
     141        err = __proc_dostop (_hurd_ports[INIT_PORT_PROC].port, ss->thread);
     142        __spin_unlock (&ss->lock);
     143        if (!err)
     144  	{
     145  	  stopped = 1;
     146  
     147  #define XXX_KERNEL_PAGE_FAULT_BUG /* XXX work around page fault bug in mk */
     148  
     149  #ifdef XXX_KERNEL_PAGE_FAULT_BUG
     150  	  /* Gag me with a pitchfork.
     151  	     The bug scenario is this:
     152  
     153  	     - The page containing __mach_task_self_ is paged out.
     154  	     - The signal thread was faulting on that page when we
     155  	       suspended it via proc_dostop.  It holds some lock, or set
     156  	       some busy bit, or somesuch.
     157  	     - Now this thread faults on that same page.
     158  	     - GRATUIOUS DEADLOCK
     159  
     160  	     We can break the deadlock by aborting the thread that faulted
     161  	     first, which if the bug happened was the signal thread because
     162  	     it is the only other thread and we just suspended it.
     163  	     */
     164  	  __thread_abort (_hurd_msgport_thread);
     165  #endif
     166  	  /* Create the child task.  It will inherit a copy of our memory.  */
     167  	  err = __task_create (__mach_task_self (),
     168  #ifdef KERN_INVALID_LEDGER
     169  			       NULL, 0,	/* OSF Mach */
     170  #endif
     171  			       1, &newtask);
     172  	}
     173  
     174        /* Unlock the global signal state lock, so we do not
     175  	 block the signal thread any longer than necessary.  */
     176        __mutex_unlock (&_hurd_siglock);
     177  
     178        if (err)
     179  	LOSE;
     180  
     181        /* Fetch the names of all ports used in this task.  */
     182        if (err = __mach_port_names (__mach_task_self (),
     183  				   &portnames, &nportnames,
     184  				   &porttypes, &nporttypes))
     185  	LOSE;
     186        if (nportnames != nporttypes)
     187  	{
     188  	  err = EGRATUITOUS;
     189  	  LOSE;
     190  	}
     191  
     192        /* Get send rights for all the threads in this task.
     193  	 We want to avoid giving these rights to the child.  */
     194        if (err = __task_threads (__mach_task_self (), &threads, &nthreads))
     195  	LOSE;
     196  
     197        /* Get the child process's proc server port.  We will insert it into
     198  	 the child with the same name as we use for our own proc server
     199  	 port; and we will need it to set the child's message port.  */
     200        if (err = __proc_task2proc (_hurd_ports[INIT_PORT_PROC].port,
     201  				  newtask, &newproc))
     202  	LOSE;
     203  
     204        /* Insert all our port rights into the child task.  */
     205        thread_refs = sigthread_refs = 0;
     206        for (i = 0; i < nportnames; ++i)
     207  	{
     208  	  if (porttypes[i] & MACH_PORT_TYPE_RECEIVE)
     209  	    {
     210  	      /* This is a receive right.  We want to give the child task
     211  		 its own new receive right under the same name.  */
     212  	      if (err = __mach_port_allocate_name (newtask,
     213  						   MACH_PORT_RIGHT_RECEIVE,
     214  						   portnames[i]))
     215  		LOSE;
     216  	      if (porttypes[i] & MACH_PORT_TYPE_SEND)
     217  		{
     218  		  /* Give the child as many send rights for its receive
     219  		     right as we have for ours.  */
     220  		  mach_port_urefs_t refs;
     221  		  mach_port_t port;
     222  		  mach_msg_type_name_t poly;
     223  		  if (err = __mach_port_get_refs (__mach_task_self (),
     224  						  portnames[i],
     225  						  MACH_PORT_RIGHT_SEND,
     226  						  &refs))
     227  		    LOSE;
     228  		  if (err = __mach_port_extract_right (newtask,
     229  						       portnames[i],
     230  						       MACH_MSG_TYPE_MAKE_SEND,
     231  						       &port, &poly))
     232  		    LOSE;
     233  		  if (portnames[i] == _hurd_msgport)
     234  		    {
     235  		      /* We just created a receive right for the child's
     236  			 message port and are about to insert send rights
     237  			 for it.  Now, while we happen to have a send right
     238  			 for it, give it to the proc server.  */
     239  		      mach_port_t old;
     240  		      if (err = __proc_setmsgport (newproc, port, &old))
     241  			LOSE;
     242  		      if (old != MACH_PORT_NULL)
     243  			/* XXX what to do here? */
     244  			__mach_port_deallocate (__mach_task_self (), old);
     245  		      /* The new task will receive its own exceptions
     246  			 on its message port.  */
     247  		      if (err =
     248  #ifdef TASK_EXCEPTION_PORT
     249  			  __task_set_special_port (newtask,
     250  						   TASK_EXCEPTION_PORT,
     251  						   port)
     252  #elif defined (EXC_MASK_ALL)
     253  			  __task_set_exception_ports
     254  			  (newtask, EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
     255  						     | EXC_MASK_MACH_SYSCALL
     256  						     | EXC_MASK_RPC_ALERT),
     257  			   port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)
     258  #else
     259  # error task_set_exception_port?
     260  #endif
     261  			  )
     262  			LOSE;
     263  		    }
     264  		  if (err = __mach_port_insert_right (newtask,
     265  						      portnames[i],
     266  						      port,
     267  						      MACH_MSG_TYPE_MOVE_SEND))
     268  		    LOSE;
     269  		  if (refs > 1
     270  		      && (err = __mach_port_mod_refs (newtask,
     271  						      portnames[i],
     272  						      MACH_PORT_RIGHT_SEND,
     273  						      refs - 1)))
     274  		    LOSE;
     275  		}
     276  	      if (porttypes[i] & MACH_PORT_TYPE_SEND_ONCE)
     277  		{
     278  		  /* Give the child a send-once right for its receive right,
     279  		     since we have one for ours.  */
     280  		  mach_port_t port;
     281  		  mach_msg_type_name_t poly;
     282  		  if (err = __mach_port_extract_right
     283  		      (newtask,
     284  		       portnames[i],
     285  		       MACH_MSG_TYPE_MAKE_SEND_ONCE,
     286  		       &port, &poly))
     287  		    LOSE;
     288  		  if (err = __mach_port_insert_right
     289  		      (newtask,
     290  		       portnames[i], port,
     291  		       MACH_MSG_TYPE_MOVE_SEND_ONCE))
     292  		    LOSE;
     293  		}
     294  	    }
     295  	  else if (porttypes[i]
     296  		   & (MACH_PORT_TYPE_SEND|MACH_PORT_TYPE_DEAD_NAME))
     297  	    {
     298  	      /* This is a send right or a dead name.
     299  		 Give the child as many references for it as we have.  */
     300  	      mach_port_urefs_t refs = 0, *record_refs = NULL;
     301  	      mach_port_t insert;
     302  	      mach_msg_type_name_t insert_type = MACH_MSG_TYPE_COPY_SEND;
     303  	      if (portnames[i] == newtask || portnames[i] == newproc)
     304  		/* Skip the name we use for the child's task or proc ports.  */
     305  		continue;
     306  	      if (portnames[i] == __mach_task_self ())
     307  		/* For the name we use for our own task port,
     308  		   insert the child's task port instead.  */
     309  		insert = newtask;
     310  	      else if (portnames[i] == _hurd_ports[INIT_PORT_PROC].port)
     311  		{
     312  		  /* Use the proc server port for the new task.  */
     313  		  insert = newproc;
     314  		  insert_type = MACH_MSG_TYPE_COPY_SEND;
     315  		}
     316  	      else if (portnames[i] == ss->thread)
     317  		{
     318  		  /* For the name we use for our own thread port, we will
     319  		     insert the thread port for the child main user thread
     320  		     after we create it.  */
     321  		  insert = MACH_PORT_NULL;
     322  		  record_refs = &thread_refs;
     323  		  /* Allocate a dead name right for this name as a
     324  		     placeholder, so the kernel will not chose this name
     325  		     for any other new port (it might use it for one of the
     326  		     rights created when a thread is created).  */
     327  		  if (err = __mach_port_allocate_name
     328  		      (newtask, MACH_PORT_RIGHT_DEAD_NAME, portnames[i]))
     329  		    LOSE;
     330  		}
     331  	      else if (portnames[i] == _hurd_msgport_thread)
     332  		/* For the name we use for our signal thread's thread port,
     333  		   we will insert the thread port for the child's signal
     334  		   thread after we create it.  */
     335  		{
     336  		  insert = MACH_PORT_NULL;
     337  		  record_refs = &sigthread_refs;
     338  		  /* Allocate a dead name right as a placeholder.  */
     339  		  if (err = __mach_port_allocate_name
     340  		      (newtask, MACH_PORT_RIGHT_DEAD_NAME, portnames[i]))
     341  		    LOSE;
     342  		}
     343  	      else
     344  		{
     345  		  /* Skip the name we use for any of our own thread ports.  */
     346  		  mach_msg_type_number_t j;
     347  		  for (j = 0; j < nthreads; ++j)
     348  		    if (portnames[i] == threads[j])
     349  		      break;
     350  		  if (j < nthreads)
     351  		    continue;
     352  
     353  		  /* Copy our own send right.  */
     354  		  insert = portnames[i];
     355  		}
     356  	      /* Find out how many user references we have for
     357  		 the send right with this name.  */
     358  	      if (err = __mach_port_get_refs (__mach_task_self (),
     359  					      portnames[i],
     360  					      MACH_PORT_RIGHT_SEND,
     361  					      record_refs ?: &refs))
     362  		LOSE;
     363  	      if (insert == MACH_PORT_NULL)
     364  		continue;
     365  	      if (insert == portnames[i]
     366  		  && (porttypes[i] & MACH_PORT_TYPE_DEAD_NAME))
     367  		/* This is a dead name; allocate another dead name
     368  		   with the same name in the child.  */
     369  	      allocate_dead_name:
     370  		err = __mach_port_allocate_name (newtask,
     371  						 MACH_PORT_RIGHT_DEAD_NAME,
     372  						 portnames[i]);
     373  	      else
     374  		/* Insert the chosen send right into the child.  */
     375  		err = __mach_port_insert_right (newtask,
     376  						portnames[i],
     377  						insert, insert_type);
     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,
     441  					      MACH_MSG_TYPE_COPY_SEND)))
     442  	LOSE;
     443        /* XXX consumed? (_hurd_sigthread is no more) */
     444        if (thread_refs > 1
     445  	  && (err = __mach_port_mod_refs (newtask, ss->thread,
     446  					  MACH_PORT_RIGHT_SEND,
     447  					  thread_refs - 1)))
     448  	LOSE;
     449        if ((_hurd_msgport_thread != MACH_PORT_NULL) /* Let user have none.  */
     450  	  && ((err = __mach_port_deallocate (newtask, _hurd_msgport_thread))
     451  	      || (err = __mach_port_insert_right (newtask,
     452  						  _hurd_msgport_thread,
     453  						  sigthread,
     454  						  MACH_MSG_TYPE_COPY_SEND))))
     455  	LOSE;
     456        if (sigthread_refs > 1
     457  	  && (err = __mach_port_mod_refs (newtask, _hurd_msgport_thread,
     458  					  MACH_PORT_RIGHT_SEND,
     459  					  sigthread_refs - 1)))
     460  	LOSE;
     461  
     462        /* This seems like a convenient juncture to copy the proc server's
     463  	 idea of what addresses our argv and envp are found at from the
     464  	 parent into the child.  Since we happen to know that the child
     465  	 shares our memory image, it is we who should do this copying.  */
     466        {
     467  	vm_address_t argv, envp;
     468  	err = (__USEPORT (PROC, __proc_get_arg_locations (port, &argv, &envp))
     469  	       ?: __proc_set_arg_locations (newproc, argv, envp));
     470  	if (err)
     471  	  LOSE;
     472        }
     473  
     474        /* Set the child signal thread up to run the msgport server function
     475  	 using the same signal thread stack copied from our address space.
     476  	 We fetch the state before longjmp'ing it so that miscellaneous
     477  	 registers not affected by longjmp (such as i386 segment registers)
     478  	 are in their normal default state.  */
     479        statecount = MACHINE_THREAD_STATE_COUNT;
     480        if (err = __thread_get_state (_hurd_msgport_thread,
     481  				    MACHINE_THREAD_STATE_FLAVOR,
     482  				    (natural_t *) &state, &statecount))
     483  	LOSE;
     484  
     485        MACHINE_THREAD_STATE_SETUP_CALL(&state,
     486  	  __hurd_sigthread_stack_base,
     487  	  __hurd_sigthread_stack_end - __hurd_sigthread_stack_base,
     488  	  (uintptr_t) _hurd_msgport_receive);
     489  
     490        /* Do special signal thread setup for TLS if needed.  */
     491        if (err = _hurd_tls_fork (sigthread, _hurd_msgport_thread, &state))
     492  	LOSE;
     493  
     494        if (err = __thread_set_state (sigthread, MACHINE_THREAD_STATE_FLAVOR,
     495  				    (natural_t *) &state, statecount))
     496  	LOSE;
     497        /* We do not thread_resume SIGTHREAD here because the child
     498  	 fork needs to do more setup before it can take signals.  */
     499  
     500        /* Set the child user thread up to return 1 from the setjmp above.  */
     501        _hurd_longjmp_thread_state (&state, env, 1);
     502  
     503        /* Do special thread setup for TLS if needed.  */
     504        if (err = _hurd_tls_fork (thread, ss->thread, &state))
     505  	LOSE;
     506  
     507        if (err = __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR,
     508  				    (natural_t *) &state, statecount))
     509  	LOSE;
     510  
     511        /* Get the PID of the child from the proc server.  We must do this
     512  	 before calling proc_child below, because at that point any
     513  	 authorized POSIX.1 process may kill the child task with SIGKILL.  */
     514        if (err = __USEPORT (PROC, __proc_task2pid (port, newtask, &pid)))
     515  	LOSE;
     516  
     517        /* Register the child with the proc server.  It is important that
     518  	 this be that last thing we do before starting the child thread
     519  	 running.  Once proc_child has been done for the task, it appears
     520  	 as a POSIX.1 process.  Any errors we get must be detected before
     521  	 this point, and the child must have a message port so it responds
     522  	 to POSIX.1 signals.  */
     523        if (err = __USEPORT (PROC, __proc_child (port, newtask)))
     524  	LOSE;
     525  
     526        /* This must be the absolutely last thing we do; we can't assume that
     527  	 the child will remain alive for even a moment once we do this.  We
     528  	 ignore errors because we have committed to the fork and are not
     529  	 allowed to return them after the process becomes visible to
     530  	 POSIX.1 (which happened right above when we called proc_child).  */
     531        (void) __thread_resume (thread);
     532  
     533      lose:
     534        if (ports_locked)
     535  	for (i = 0; i < _hurd_nports; ++i)
     536  	  __spin_unlock (&_hurd_ports[i].lock);
     537  
     538        resume_threads ();
     539  
     540        if (newtask != MACH_PORT_NULL)
     541  	{
     542  	  if (err)
     543  	    __task_terminate (newtask);
     544  	  __mach_port_deallocate (__mach_task_self (), newtask);
     545  	}
     546        if (thread != MACH_PORT_NULL)
     547  	__mach_port_deallocate (__mach_task_self (), thread);
     548        if (sigthread != MACH_PORT_NULL)
     549  	__mach_port_deallocate (__mach_task_self (), sigthread);
     550        if (newproc != MACH_PORT_NULL)
     551  	__mach_port_deallocate (__mach_task_self (), newproc);
     552  
     553        if (portnames)
     554  	__vm_deallocate (__mach_task_self (),
     555  			 (vm_address_t) portnames,
     556  			 nportnames * sizeof (*portnames));
     557        if (porttypes)
     558  	__vm_deallocate (__mach_task_self (),
     559  			 (vm_address_t) porttypes,
     560  			 nporttypes * sizeof (*porttypes));
     561        if (threads)
     562  	{
     563  	  for (i = 0; i < nthreads; ++i)
     564  	    __mach_port_deallocate (__mach_task_self (), threads[i]);
     565  	  __vm_deallocate (__mach_task_self (),
     566  			   (vm_address_t) threads,
     567  			   nthreads * sizeof (*threads));
     568  	}
     569  
     570        /* Release malloc locks.  */
     571        _hurd_malloc_fork_parent ();
     572  
     573        /* Run things that want to run in the parent to restore it to
     574  	 normality.  Usually prepare hooks and parent hooks are
     575  	 symmetrical: the prepare hook arrests state in some way for the
     576  	 fork, and the parent hook restores the state for the parent to
     577  	 continue executing normally.  */
     578        RUN_HOOK (_hurd_fork_parent_hook, ());
     579      }
     580    else
     581      {
     582        struct hurd_sigstate *oldstates;
     583  
     584        /* We are the child task.  Unlock the standard port cells, which were
     585  	 locked in the parent when we copied its memory.  The parent has
     586  	 inserted send rights with the names that were in the cells then.  */
     587        for (i = 0; i < _hurd_nports; ++i)
     588  	__spin_unlock (&_hurd_ports[i].lock);
     589  
     590        /* Claim our sigstate structure and unchain the rest: the
     591  	 threads existed in the parent task but don't exist in this
     592  	 task (the child process).  Delay freeing them until later
     593  	 because some of the further setup and unlocking might be
     594  	 required for free to work.  Before we finish cleaning up,
     595  	 we will reclaim the signal thread's sigstate structure (if
     596  	 it had one).  */
     597        oldstates = _hurd_sigstates;
     598        if (oldstates == ss)
     599  	oldstates = ss->next;
     600        else
     601  	{
     602  	  while (_hurd_sigstates->next != ss)
     603  	    _hurd_sigstates = _hurd_sigstates->next;
     604  	  _hurd_sigstates->next = ss->next;
     605  	}
     606        ss->next = NULL;
     607        _hurd_sigstates = ss;
     608        __mutex_unlock (&_hurd_siglock);
     609        /* Earlier on, the global sigstate may have been tainted and now needs to
     610           be reinitialized.  Nobody is interested in its present state anymore:
     611           we're not, the signal thread will be restarted, and there are no other
     612           threads.
     613  
     614           We can't simply allocate a fresh global sigstate here, as
     615           _hurd_thread_sigstate will call malloc and that will deadlock trying
     616           to determine the current thread's sigstate.  */
     617  #if 0
     618        _hurd_thread_sigstate_init (_hurd_global_sigstate, MACH_PORT_NULL);
     619  #else
     620        /* Only reinitialize the lock -- otherwise we might have to do additional
     621           setup as done in hurdsig.c:_hurdsig_init.  */
     622        __spin_lock_init (&_hurd_global_sigstate->lock);
     623  #endif
     624  
     625        /* We are one of the (exactly) two threads in this new task, we
     626  	 will take the task-global signals.  */
     627        _hurd_sigstate_set_global_rcv (ss);
     628  
     629        /* Fetch our new process IDs from the proc server.  No need to
     630  	 refetch our pgrp; it is always inherited from the parent (so
     631  	 _hurd_pgrp is already correct), and the proc server will send us a
     632  	 proc_newids notification when it changes.  */
     633        err = __USEPORT (PROC, __proc_getpids (port, &_hurd_pid, &_hurd_ppid,
     634  					     &_hurd_orphaned));
     635  
     636        /* Forking clears the trace flag and pending masks.  */
     637        __sigemptyset (&_hurdsig_traced);
     638        __sigemptyset (&_hurd_global_sigstate->pending);
     639        __sigemptyset (&ss->pending);
     640  
     641        __libc_unwind_link_after_fork ();
     642  
     643        /* Release malloc locks.  */
     644        _hurd_malloc_fork_child ();
     645        call_function_static_weak (__malloc_fork_unlock_child);
     646  
     647        /* Run things that want to run in the child task to set up.  */
     648        RUN_HOOK (_hurd_fork_child_hook, ());
     649  
     650        /* Set up proc server-assisted fault recovery for the signal thread.  */
     651        _hurdsig_fault_init ();
     652  
     653        /* Start the signal thread listening on the message port.  */
     654        if (!err)
     655  	err = __thread_resume (_hurd_msgport_thread);
     656  
     657        /* Reclaim the signal thread's sigstate structure and free the
     658  	 other old sigstate structures.  */
     659        while (oldstates != NULL)
     660  	{
     661  	  struct hurd_sigstate *next = oldstates->next;
     662  
     663  	  if (oldstates->thread == _hurd_msgport_thread)
     664  	    {
     665  	      /* If we have a second signal state structure then we
     666  		 must have been through here before--not good.  */
     667  	      assert (_hurd_sigstates->next == 0);
     668  	      _hurd_sigstates->next = oldstates;
     669  	      oldstates->next = 0;
     670  	    }
     671  	  else
     672  	    free (oldstates);
     673  
     674  	  oldstates = next;
     675  	}
     676  
     677        /* XXX what to do if we have any errors here? */
     678  
     679        pid = 0;
     680      }
     681  
     682    /* Unlock things we locked before creating the child task.
     683       They are locked in both the parent and child tasks.  */
     684    {
     685      void *const *p;
     686      for (p = symbol_set_first_element (_hurd_fork_locks);
     687  	 ! symbol_set_end_p (_hurd_fork_locks, p);
     688  	 ++p)
     689        __mutex_unlock (*p);
     690    }
     691  
     692    _hurd_critical_section_unlock (ss);
     693    if (err == EINTR)
     694      /* Got a signal while inside an RPC of the critical section, retry again */
     695      goto retry;
     696  
     697    return err ? __hurd_fail (err) : pid;
     698  }
     699  libc_hidden_def (_Fork)