assert (_hurdsig_fault_sigcode >= (long int) ss->context && _hurdsig_fault_sigcode < (long int) (ss->context + 1));
_hurd_internal_post_signal (struct hurd_sigstate *ss,			    int signo, long int sigcode, int sigerror,			    mach_port_t reply_port,			    mach_msg_type_name_t reply_port_type,			    int untraced){  error_t err;  struct machine_thread_all_state thread_state;  enum { stop, ignore, core, term, handle } act;  struct hurd_signal_preempter *pe;  sighandler_t handler;  sigset_t pending;  int ss_suspended;  /* Reply to this sig_post message.  */  __typeof (__msg_sig_post_reply) *reply_rpc    = (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply);  void reply (void)    {      error_t err;      if (reply_port == MACH_PORT_NULL)	return;      err = (*reply_rpc) (reply_port, reply_port_type, 0);      reply_port = MACH_PORT_NULL;      if (err != MACH_SEND_INVALID_DEST) /* Ignore dead reply port.  */	assert_perror (err);    }  /* Mark the signal as pending.  */  void mark_pending (void)    {      __sigaddset (&ss->pending, signo);      /* Save the code to be given to the handler when SIGNO is	 unblocked.  */      ss->pending_data[signo].code = sigcode;      ss->pending_data[signo].error = sigerror;    }  /* Suspend the process with SIGNO.  */  void suspend (void)    {      /* Stop all other threads and mark ourselves stopped.  */      __USEPORT (PROC,		 ({		   /* Hold the siglock while stopping other threads to be		      sure it is not held by another thread afterwards.  */		   __mutex_lock (&_hurd_siglock);		   __proc_dostop (port, _hurd_msgport_thread);		   __mutex_unlock (&_hurd_siglock);		   abort_all_rpcs (signo, &thread_state, 1);		   reply ();		   __proc_mark_stop (port, signo);		 }));      _hurd_stopped = 1;    }  /* Resume the process after a suspension.  */  void resume (void)    {      /* Resume the process from being stopped.  */      thread_t *threads;      mach_msg_type_number_t nthreads, i;      error_t err;      if (! _hurd_stopped)	return;      /* Tell the proc server we are continuing.  */      __USEPORT (PROC, __proc_mark_cont (port));      /* Fetch ports to all our threads and resume them.  */      err = __task_threads (__mach_task_self (), &threads, &nthreads);      assert_perror (err);      for (i = 0; i < nthreads; ++i)	{	  if (threads[i] != _hurd_msgport_thread &&	      (act != handle || threads[i] != ss->thread))	    {	      err = __thread_resume (threads[i]);	      assert_perror (err);	    }	  err = __mach_port_deallocate (__mach_task_self (),					threads[i]);	  assert_perror (err);	}      __vm_deallocate (__mach_task_self (),		       (vm_address_t) threads,		       nthreads * sizeof *threads);      _hurd_stopped = 0;      /* The thread that will run the handler is already suspended.  */      ss_suspended = 1;    }  if (signo == 0)    {      if (untraced)	/* This is PTRACE_CONTINUE.  */	resume ();      /* This call is just to check for pending signals.  */      __spin_lock (&ss->lock);      goto check_pending_signals;    } post_signal:  thread_state.set = 0;		/* We know nothing.  */  __spin_lock (&ss->lock);  /* Check for a preempted signal.  Preempted signals can arrive during     critical sections.  */  handler = SIG_ERR;  for (pe = ss->preempters; pe && handler == SIG_ERR; pe = pe->next)    if (HURD_PREEMPT_SIGNAL_P (pe, signo, sigcode))      handler = (*pe->preempter) (pe, ss, &signo, &sigcode, &sigerror);  if (handler == SIG_ERR && (__sigmask (signo) & _hurdsig_preempted_set))    {      __mutex_lock (&_hurd_siglock);      for (pe = _hurdsig_preempters; pe && handler == SIG_ERR; pe = pe->next)	if (HURD_PREEMPT_SIGNAL_P (pe, signo, sigcode))	  handler = (*pe->preempter) (pe, ss, &signo, &sigcode, &sigerror);      __mutex_unlock (&_hurd_siglock);    }  ss_suspended = 0;  if (handler == SIG_IGN)    /* Ignore the signal altogether.  */    act = ignore;  if (handler != SIG_ERR)    /* Run the preemption-provided handler.  */    act = handle;  else    {      /* No preemption.  Do normal handling.  */      if (!untraced && (_hurd_exec_flags & EXEC_TRACED))	{	  /* We are being traced.  Stop to tell the debugger of the signal.  */	  if (_hurd_stopped)	    /* Already stopped.  Mark the signal as pending;	       when resumed, we will notice it and stop again.  */	    mark_pending ();	  else	    suspend ();	  __spin_unlock (&ss->lock);	  reply ();	  return;	}      handler = ss->actions[signo].sa_handler;      if (handler == SIG_DFL)	/* Figure out the default action for this signal.  */	switch (signo)	  {	  case 0:	    /* A sig_post msg with SIGNO==0 is sent to	       tell us to check for pending signals.  */	    act = ignore;	    break;	  case SIGTTIN:	  case SIGTTOU:	  case SIGSTOP:	  case SIGTSTP:	    act = stop;	    break;	  case SIGCONT:	  case SIGIO:	  case SIGURG:	  case SIGCHLD:	  case SIGWINCH:	    act = ignore;	    break;	  case SIGQUIT:	  case SIGILL:	  case SIGTRAP:	  case SIGIOT:	  case SIGEMT:	  case SIGFPE:	  case SIGBUS:	  case SIGSEGV:	  case SIGSYS:	    act = core;	    break;	  case SIGINFO:	    if (_hurd_pgrp == _hurd_pid)	      {		/* We are the process group leader.  Since there is no		   user-specified handler for SIGINFO, we use a default one		   which prints something interesting.  We use the normal		   handler mechanism instead of just doing it here to avoid		   the signal thread faulting or blocking in this		   potentially hairy operation.  */		act = handle;		handler = _hurd_siginfo_handler;	      }	    else	      act = ignore;	    break;	  default:	    act = term;	    break;	  }      else if (handler == SIG_IGN)	act = ignore;      else	act = handle;      if (__sigmask (signo) & STOPSIGS)	/* Stop signals clear a pending SIGCONT even if they	   are handled or ignored (but not if preempted).  */	ss->pending &= ~sigmask (SIGCONT);      else	{	  if (signo == SIGCONT)	    /* Even if handled or ignored (but not preempted), SIGCONT clears	       stop signals and resumes the process.  */	    ss->pending &= ~STOPSIGS;	  if (_hurd_stopped && act != stop && (untraced || signo == SIGCONT))	    resume ();	}    }  if (_hurd_orphaned && act == stop &&      (__sigmask (signo) & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) |			    __sigmask (SIGTSTP))))    {      /* If we would ordinarily stop for a job control signal, but we are	 orphaned so noone would ever notice and continue us again, we just	 quietly die, alone and in the dark.  */      sigcode = signo;      signo = SIGKILL;      act = term;    }  /* Handle receipt of a blocked signal, or any signal while stopped.  */  if (__sigismember (&ss->blocked, signo) ||      (signo != SIGKILL && _hurd_stopped))    {      mark_pending ();      act = ignore;    }  /* Perform the chosen action for the signal.  */  switch (act)    {    case stop:      if (_hurd_stopped)	{	  /* We are already stopped, but receiving an untraced stop	     signal.  Instead of resuming and suspending again, just	     notify the proc server of the new stop signal.  */	  error_t err = __USEPORT (PROC, __proc_mark_stop (port, signo));	  assert_perror (err);	}      else	/* Suspend the process.  */	suspend ();      break;    case ignore:      /* Nobody cares about this signal.  */      break;    sigbomb:      /* We got a fault setting up the stack frame for the handler.	 Nothing to do but die; BSD gets SIGILL in this case.  */      sigcode = signo;	/* XXX ? */      signo = SIGILL;      act = core;      /* FALLTHROUGH */    case term:			/* Time to die.  */    case core:			/* And leave a rotting corpse.  */      /* Have the proc server stop all other threads in our task.  */      err = __USEPORT (PROC, __proc_dostop (port, _hurd_msgport_thread));      assert_perror (err);      /* No more user instructions will be executed.	 The signal can now be considered delivered.  */      reply ();      /* Abort all server operations now in progress.  */      abort_all_rpcs (signo, &thread_state, 0);      {	int status = W_EXITCODE (0, signo);	/* Do a core dump if desired.  Only set the wait status bit saying we	   in fact dumped core if the operation was actually successful.  */	if (act == core && write_corefile (signo, sigcode, sigerror))	  status |= WCOREFLAG;	/* Tell proc how we died and then stick the saber in the gut.  */	_hurd_exit (status);	/* NOTREACHED */      }    case handle:      /* Call a handler for this signal.  */      {	struct sigcontext *scp, ocontext;	int wait_for_reply, state_changed;	/* Stop the thread and abort its pending RPC operations.  */	if (! ss_suspended)	  {	    err = __thread_suspend (ss->thread);	    assert_perror (err);	  }	/* Abort the thread's kernel context, so any pending message send	   or receive completes immediately or aborts.  If an interruptible	   RPC is in progress, abort_rpcs will do this.  But we must always	   do it before fetching the thread's state, because	   thread_get_state is never kosher before thread_abort.  */	abort_thread (ss, &thread_state, NULL);	if (ss->context)	  {	    /* We have a previous sigcontext that sigreturn was about	       to restore when another signal arrived.  */	    mach_port_t *loc;	    if (_hurdsig_catch_fault (SIGSEGV))	      {		assert (_hurdsig_fault_sigcode >= (long int) ss->context &&			_hurdsig_fault_sigcode < (long int) (ss->context + 1));		/* We faulted reading the thread's stack.  Forget that		   context and pretend it wasn't there.  It almost		   certainly crash if this handler returns, but that's it's		   problem.  */		ss->context = NULL;	      }	    else	      {		/* Copy the context from the thread's stack before		   we start diddling the stack to set up the handler.  */		ocontext = *ss->context;		ss->context = &ocontext;	      }	    _hurdsig_end_catch_fault ();	    if (! machine_get_basic_state (ss->thread, &thread_state))	      goto sigbomb;	    loc = interrupted_reply_port_location (&thread_state, 1);	    if (loc && *loc != MACH_PORT_NULL)	      /* This is the reply port for the context which called		 sigreturn.  Since we are abandoning that context entirely		 and restoring SS->context instead, destroy this port.  */	      __mach_port_destroy (__mach_task_self (), *loc);	    /* The thread was in sigreturn, not in any interruptible RPC.  */	    wait_for_reply = 0;	    assert (! ss->critical_section);	  }	else	  {	    wait_for_reply	      = (_hurdsig_abort_rpcs (ss, signo, 1,				      &thread_state, &state_changed,				      &reply)		 != MACH_PORT_NULL);	    if (ss->critical_section)	      {		/* The thread is in a critical section.  Mark the signal as		   pending.  When it finishes the critical section, it will		   check for pending signals.  */		mark_pending ();		assert (! state_changed);		__thread_resume (ss->thread);		break;	      }	  }	/* Call the machine-dependent function to set the thread up	   to run the signal handler, and preserve its old context.  */	scp = _hurd_setup_sighandler (ss, handler,				      signo, sigcode,				      wait_for_reply, &thread_state);	if (scp == NULL)	  goto sigbomb;	/* Set the machine-independent parts of the signal context.  */	{	  /* Fetch the thread variable for the MiG reply port,	     and set it to MACH_PORT_NULL.  */	  mach_port_t *loc = interrupted_reply_port_location (&thread_state,							      1);	  if (loc)	    {	      scp->sc_reply_port = *loc;	      *loc = MACH_PORT_NULL;	    }	  else	    scp->sc_reply_port = MACH_PORT_NULL;	  /* Save the intr_port in use by the interrupted code,	     and clear the cell before running the trampoline.  */	  scp->sc_intr_port = ss->intr_port;	  ss->intr_port = MACH_PORT_NULL;	  if (ss->context)	    {	      /* After the handler runs we will restore to the state in		 SS->context, not the state of the thread now.  So restore		 that context's reply port and intr port.  */	      scp->sc_reply_port = ss->context->sc_reply_port;	      scp->sc_intr_port = ss->context->sc_intr_port;	      ss->context = NULL;	    }	}	/* Backdoor extra argument to signal handler.  */	scp->sc_error = sigerror;	/* Block SIGNO and requested signals while running the handler.  */	scp->sc_mask = ss->blocked;	ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;	/* Start the thread running the handler (or possibly waiting for an	   RPC reply before running the handler).  */	err = __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,				  (natural_t *) &thread_state.basic,				  MACHINE_THREAD_STATE_COUNT);	assert_perror (err);	err = __thread_resume (ss->thread);	assert_perror (err);	thread_state.set = 0;	/* Everything we know is now wrong.  */	break;      }    }  /* The signal has either been ignored or is now being handled.  We can     consider it delivered and reply to the killer.  */  reply ();  /* We get here unless the signal was fatal.  We still hold SS->lock.     Check for pending signals, and loop to post them.  */  {    /* Return nonzero if SS has any signals pending we should worry about.       We don't worry about any pending signals if we are stopped, nor if       SS is in a critical section.  We are guaranteed to get a sig_post       message before any of them become deliverable: either the SIGCONT       signal, or a sig_post with SIGNO==0 as an explicit poll when the       thread finishes its critical section.  */    inline int signals_pending (void)      {	if (_hurd_stopped || ss->critical_section)	  return 0;	return pending = ss->pending & ~ss->blocked;      }  check_pending_signals:    untraced = 0;    if (signals_pending ())      {      pending:	for (signo = 1; signo < NSIG; ++signo)	  if (__sigismember (&pending, signo))	    {	      __sigdelset (&ss->pending, signo);	      sigcode = ss->pending_data[signo].code;	      sigerror = ss->pending_data[signo].error;	      __spin_unlock (&ss->lock);	      goto post_signal;	    }      }    /* No pending signals left undelivered for this thread.       If we were sent signal 0, we need to check for pending       signals for all threads.  */    if (signo == 0)      {	__spin_unlock (&ss->lock);	__mutex_lock (&_hurd_siglock);	for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)	  {	    __spin_lock (&ss->lock);	    if (signals_pending ())	      goto pending;	    __spin_unlock (&ss->lock);	  }	__mutex_unlock (&_hurd_siglock);      }    else      {	/* No more signals pending; SS->lock is still locked.	   Wake up any sigsuspend call that is blocking SS->thread.  */	if (ss->suspended != MACH_PORT_NULL)	  {	    /* There is a sigsuspend waiting.  Tell it to wake up.  */	    error_t err;	    mach_msg_header_t msg;	    err = __mach_port_insert_right (__mach_task_self (),					    ss->suspended, ss->suspended,					    MACH_MSG_TYPE_MAKE_SEND);	    assert_perror (err);	    msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MOVE_SEND, 0);	    msg.msgh_remote_port = ss->suspended;	    msg.msgh_local_port = MACH_PORT_NULL;	    /* These values do not matter.  */	    msg.msgh_id = 8675309; /* Jenny, Jenny.  */	    msg.msgh_seqno = 17; /* Random.  */	    ss->suspended = MACH_PORT_NULL;	    err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,			      MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,			      MACH_PORT_NULL);	    assert_perror (err);	  }	__spin_unlock (&ss->lock);      }  }  /* All pending signals delivered to all threads.     Now we can send the reply message even for signal 0.  */  reply ();}