Blame hurd/hurdsig.c

Packit 6c4009
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
#include <cthreads.h>		/* For `struct mutex'.  */
Packit 6c4009
#include <pthreadP.h>
Packit 6c4009
#include <mach.h>
Packit 6c4009
#include <mach/thread_switch.h>
Packit 6c4009
#include <mach/mig_support.h>
Packit 6c4009
Packit 6c4009
#include <hurd.h>
Packit 6c4009
#include <hurd/id.h>
Packit 6c4009
#include <hurd/signal.h>
Packit 6c4009
Packit 6c4009
#include "hurdfault.h"
Packit 6c4009
#include "hurdmalloc.h"		/* XXX */
Packit 6c4009
#include "../locale/localeinfo.h"
Packit 6c4009
Packit 6c4009
#include <libc-diag.h>
Packit 6c4009
Packit 6c4009
const char *_hurdsig_getenv (const char *);
Packit 6c4009
Packit 6c4009
struct mutex _hurd_siglock;
Packit 6c4009
int _hurd_stopped;
Packit 6c4009
Packit 6c4009
/* Port that receives signals and other miscellaneous messages.  */
Packit 6c4009
mach_port_t _hurd_msgport;
Packit 6c4009
Packit 6c4009
/* Thread listening on it.  */
Packit 6c4009
thread_t _hurd_msgport_thread;
Packit 6c4009
Packit 6c4009
/* Thread which receives task-global signals.  */
Packit 6c4009
thread_t _hurd_sigthread;
Packit 6c4009
Packit 6c4009
/* These are set up by _hurdsig_init.  */
Packit 6c4009
unsigned long int __hurd_sigthread_stack_base;
Packit 6c4009
unsigned long int __hurd_sigthread_stack_end;
Packit 6c4009
Packit 6c4009
/* Linked-list of per-thread signal state.  */
Packit 6c4009
struct hurd_sigstate *_hurd_sigstates;
Packit 6c4009
Packit 6c4009
/* Timeout for RPC's after interrupt_operation. */
Packit 6c4009
mach_msg_timeout_t _hurd_interrupted_rpc_timeout = 3000;
Packit 6c4009

Packit 6c4009
static void
Packit 6c4009
default_sigaction (struct sigaction actions[NSIG])
Packit 6c4009
{
Packit 6c4009
  int signo;
Packit 6c4009
Packit 6c4009
  __sigemptyset (&actions[0].sa_mask);
Packit 6c4009
  actions[0].sa_flags = SA_RESTART;
Packit 6c4009
  actions[0].sa_handler = SIG_DFL;
Packit 6c4009
Packit 6c4009
  for (signo = 1; signo < NSIG; ++signo)
Packit 6c4009
    actions[signo] = actions[0];
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
struct hurd_sigstate *
Packit 6c4009
_hurd_thread_sigstate (thread_t thread)
Packit 6c4009
{
Packit 6c4009
  struct hurd_sigstate *ss;
Packit 6c4009
  __mutex_lock (&_hurd_siglock);
Packit 6c4009
  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
Packit 6c4009
    if (ss->thread == thread)
Packit 6c4009
       break;
Packit 6c4009
  if (ss == NULL)
Packit 6c4009
    {
Packit 6c4009
      ss = malloc (sizeof (*ss));
Packit 6c4009
      if (ss == NULL)
Packit 6c4009
	__libc_fatal ("hurd: Can't allocate thread sigstate\n");
Packit 6c4009
      ss->thread = thread;
Packit 6c4009
      __spin_lock_init (&ss->lock);
Packit 6c4009
Packit 6c4009
      /* Initialize default state.  */
Packit 6c4009
      __sigemptyset (&ss->blocked);
Packit 6c4009
      __sigemptyset (&ss->pending);
Packit 6c4009
      memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
Packit 6c4009
      ss->preemptors = NULL;
Packit 6c4009
      ss->suspended = MACH_PORT_NULL;
Packit 6c4009
      ss->intr_port = MACH_PORT_NULL;
Packit 6c4009
      ss->context = NULL;
Packit 6c4009
Packit 6c4009
      /* Initialize the sigaction vector from the default signal receiving
Packit 6c4009
	 thread's state, and its from the system defaults.  */
Packit 6c4009
      if (thread == _hurd_sigthread)
Packit 6c4009
	default_sigaction (ss->actions);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  struct hurd_sigstate *s;
Packit 6c4009
	  for (s = _hurd_sigstates; s != NULL; s = s->next)
Packit 6c4009
	    if (s->thread == _hurd_sigthread)
Packit 6c4009
	      break;
Packit 6c4009
	  if (s)
Packit 6c4009
	    {
Packit 6c4009
	      __spin_lock (&s->lock);
Packit 6c4009
	      memcpy (ss->actions, s->actions, sizeof (s->actions));
Packit 6c4009
	      __spin_unlock (&s->lock);
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    default_sigaction (ss->actions);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      ss->next = _hurd_sigstates;
Packit 6c4009
      _hurd_sigstates = ss;
Packit 6c4009
    }
Packit 6c4009
  __mutex_unlock (&_hurd_siglock);
Packit 6c4009
  return ss;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (_hurd_thread_sigstate)
Packit 6c4009

Packit 6c4009
/* Signal delivery itself is on this page.  */
Packit 6c4009
Packit 6c4009
#include <hurd/fd.h>
Packit 6c4009
#include <hurd/crash.h>
Packit 6c4009
#include <hurd/resource.h>
Packit 6c4009
#include <hurd/paths.h>
Packit 6c4009
#include <setjmp.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <sys/wait.h>
Packit 6c4009
#include <thread_state.h>
Packit 6c4009
#include <hurd/msg_server.h>
Packit 6c4009
#include <hurd/msg_reply.h>	/* For __msg_sig_post_reply.  */
Packit 6c4009
#include <hurd/interrupt.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Call the crash dump server to mummify us before we die.
Packit 6c4009
   Returns nonzero if a core file was written.  */
Packit 6c4009
static int
Packit 6c4009
write_corefile (int signo, const struct hurd_signal_detail *detail)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
  mach_port_t coreserver;
Packit 6c4009
  file_t file, coredir;
Packit 6c4009
  const char *name;
Packit 6c4009
Packit 6c4009
  /* Don't bother locking since we just read the one word.  */
Packit 6c4009
  rlim_t corelimit = _hurd_rlimits[RLIMIT_CORE].rlim_cur;
Packit 6c4009
Packit 6c4009
  if (corelimit == 0)
Packit 6c4009
    /* No core dumping, thank you very much.  Note that this makes
Packit 6c4009
       `ulimit -c 0' prevent crash-suspension too, which is probably
Packit 6c4009
       what the user wanted.  */
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  /* XXX RLIMIT_CORE:
Packit 6c4009
     When we have a protocol to make the server return an error
Packit 6c4009
     for RLIMIT_FSIZE, then tell the corefile fs server the RLIMIT_CORE
Packit 6c4009
     value in place of the RLIMIT_FSIZE value.  */
Packit 6c4009
Packit 6c4009
  /* First get a port to the core dumping server.  */
Packit 6c4009
  coreserver = MACH_PORT_NULL;
Packit 6c4009
  name = _hurdsig_getenv ("CRASHSERVER");
Packit 6c4009
  if (name != NULL)
Packit 6c4009
    coreserver = __file_name_lookup (name, 0, 0);
Packit 6c4009
  if (coreserver == MACH_PORT_NULL)
Packit 6c4009
    coreserver = __file_name_lookup (_SERVERS_CRASH, 0, 0);
Packit 6c4009
  if (coreserver == MACH_PORT_NULL)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  /* Get a port to the directory where the new core file will reside.  */
Packit 6c4009
  file = MACH_PORT_NULL;
Packit 6c4009
  name = _hurdsig_getenv ("COREFILE");
Packit 6c4009
  if (name == NULL)
Packit 6c4009
    name = "core";
Packit 6c4009
  coredir = __file_name_split (name, (char **) &name);
Packit 6c4009
  if (coredir != MACH_PORT_NULL)
Packit 6c4009
    /* Create the new file, but don't link it into the directory yet.  */
Packit 6c4009
    __dir_mkfile (coredir, O_WRONLY|O_CREAT,
Packit 6c4009
		  0600 & ~_hurd_umask, /* XXX ? */
Packit 6c4009
		  &file;;
Packit 6c4009
Packit 6c4009
  /* Call the core dumping server to write the core file.  */
Packit 6c4009
  err = __crash_dump_task (coreserver,
Packit 6c4009
			   __mach_task_self (),
Packit 6c4009
			   file,
Packit 6c4009
			   signo, detail->code, detail->error,
Packit 6c4009
			   detail->exc, detail->exc_code, detail->exc_subcode,
Packit 6c4009
			   _hurd_ports[INIT_PORT_CTTYID].port,
Packit 6c4009
			   MACH_MSG_TYPE_COPY_SEND);
Packit 6c4009
  __mach_port_deallocate (__mach_task_self (), coreserver);
Packit 6c4009
Packit 6c4009
  if (! err && file != MACH_PORT_NULL)
Packit 6c4009
    /* The core dump into FILE succeeded, so now link it into the
Packit 6c4009
       directory.  */
Packit 6c4009
    err = __dir_link (coredir, file, name, 1);
Packit 6c4009
  __mach_port_deallocate (__mach_task_self (), file);
Packit 6c4009
  __mach_port_deallocate (__mach_task_self (), coredir);
Packit 6c4009
  return !err && file != MACH_PORT_NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The lowest-numbered thread state flavor value is 1,
Packit 6c4009
   so we use bit 0 in machine_thread_all_state.set to
Packit 6c4009
   record whether we have done thread_abort.  */
Packit 6c4009
#define THREAD_ABORTED 1
Packit 6c4009
Packit 6c4009
/* SS->thread is suspended.  Abort the thread and get its basic state.  */
Packit 6c4009
static void
Packit 6c4009
abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
Packit 6c4009
	      void (*reply) (void))
Packit 6c4009
{
Packit 6c4009
  if (!(state->set & THREAD_ABORTED))
Packit 6c4009
    {
Packit 6c4009
      error_t err = __thread_abort (ss->thread);
Packit 6c4009
      assert_perror (err);
Packit 6c4009
      /* Clear all thread state flavor set bits, because thread_abort may
Packit 6c4009
	 have changed the state.  */
Packit 6c4009
      state->set = THREAD_ABORTED;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (reply)
Packit 6c4009
    (*reply) ();
Packit 6c4009
Packit 6c4009
  machine_get_basic_state (ss->thread, state);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Find the location of the MiG reply port cell in use by the thread whose
Packit 6c4009
   state is described by THREAD_STATE.  If SIGTHREAD is nonzero, make sure
Packit 6c4009
   that this location can be set without faulting, or else return NULL.  */
Packit 6c4009
Packit 6c4009
static mach_port_t *
Packit 6c4009
interrupted_reply_port_location (thread_t thread,
Packit 6c4009
				 struct machine_thread_all_state *thread_state,
Packit 6c4009
				 int sigthread)
Packit 6c4009
{
Packit 6c4009
  mach_port_t *portloc = &THREAD_TCB(thread, thread_state)->reply_port;
Packit 6c4009
Packit 6c4009
  if (sigthread && _hurdsig_catch_memory_fault (portloc))
Packit 6c4009
    /* Faulted trying to read the TCB.  */
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
  /* GCC 6 and before seem to be confused by the setjmp call inside
Packit 6c4009
     _hurdsig_catch_memory_fault and think that we may be returning a second
Packit 6c4009
     time to here with portloc uninitialized (but we never do). */
Packit 6c4009
  DIAG_IGNORE_NEEDS_COMMENT (6, "-Wmaybe-uninitialized");
Packit 6c4009
  /* Fault now if this pointer is bogus.  */
Packit 6c4009
  *(volatile mach_port_t *) portloc = *portloc;
Packit 6c4009
  DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
Packit 6c4009
  if (sigthread)
Packit 6c4009
    _hurdsig_end_catch_fault ();
Packit 6c4009
Packit 6c4009
  return portloc;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
#include <hurd/sigpreempt.h>
Packit 6c4009
#include <intr-msg.h>
Packit 6c4009
Packit 6c4009
/* Timeout on interrupt_operation calls.  */
Packit 6c4009
mach_msg_timeout_t _hurdsig_interrupt_timeout = 1000;
Packit 6c4009
Packit 6c4009
/* SS->thread is suspended.
Packit 6c4009
Packit 6c4009
   Abort any interruptible RPC operation the thread is doing.
Packit 6c4009
Packit 6c4009
   This uses only the constant member SS->thread and the unlocked, atomically
Packit 6c4009
   set member SS->intr_port, so no locking is needed.
Packit 6c4009
Packit 6c4009
   If successfully sent an interrupt_operation and therefore the thread should
Packit 6c4009
   wait for its pending RPC to return (possibly EINTR) before taking the
Packit 6c4009
   incoming signal, returns the reply port to be received on.  Otherwise
Packit 6c4009
   returns MACH_PORT_NULL.
Packit 6c4009
Packit 6c4009
   SIGNO is used to find the applicable SA_RESTART bit.  If SIGNO is zero,
Packit 6c4009
   the RPC fails with EINTR instead of restarting (thread_cancel).
Packit 6c4009
Packit 6c4009
   *STATE_CHANGE is set nonzero if STATE->basic was modified and should
Packit 6c4009
   be applied back to the thread if it might ever run again, else zero.  */
Packit 6c4009
Packit 6c4009
mach_port_t
Packit 6c4009
_hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
Packit 6c4009
		     struct machine_thread_all_state *state, int *state_change,
Packit 6c4009
		     void (*reply) (void))
Packit 6c4009
{
Packit 6c4009
  extern const void _hurd_intr_rpc_msg_in_trap;
Packit 6c4009
  mach_port_t rcv_port = MACH_PORT_NULL;
Packit 6c4009
  mach_port_t intr_port;
Packit 6c4009
Packit 6c4009
  *state_change = 0;
Packit 6c4009
Packit 6c4009
  intr_port = ss->intr_port;
Packit 6c4009
  if (intr_port == MACH_PORT_NULL)
Packit 6c4009
    /* No interruption needs done.  */
Packit 6c4009
    return MACH_PORT_NULL;
Packit 6c4009
Packit 6c4009
  /* Abort the thread's kernel context, so any pending message send or
Packit 6c4009
     receive completes immediately or aborts.  */
Packit 6c4009
  abort_thread (ss, state, reply);
Packit 6c4009
Packit 6c4009
  if (state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap)
Packit 6c4009
    {
Packit 6c4009
      /* The thread is about to do the RPC, but hasn't yet entered
Packit 6c4009
	 mach_msg.  Mutate the thread's state so it knows not to try
Packit 6c4009
	 the RPC.  */
Packit 6c4009
      INTR_MSG_BACK_OUT (&state->basic);
Packit 6c4009
      MACHINE_THREAD_STATE_SET_PC (&state->basic,
Packit 6c4009
				   &_hurd_intr_rpc_msg_in_trap);
Packit 6c4009
      state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;
Packit 6c4009
      *state_change = 1;
Packit 6c4009
    }
Packit 6c4009
  else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap &&
Packit 6c4009
	   /* The thread was blocked in the system call.  After thread_abort,
Packit 6c4009
	      the return value register indicates what state the RPC was in
Packit 6c4009
	      when interrupted.  */
Packit 6c4009
	   state->basic.SYSRETURN == MACH_RCV_INTERRUPTED)
Packit 6c4009
      {
Packit 6c4009
	/* The RPC request message was sent and the thread was waiting for
Packit 6c4009
	   the reply message; now the message receive has been aborted, so
Packit 6c4009
	   the mach_msg call will return MACH_RCV_INTERRUPTED.  We must tell
Packit 6c4009
	   the server to interrupt the pending operation.  The thread must
Packit 6c4009
	   wait for the reply message before running the signal handler (to
Packit 6c4009
	   guarantee that the operation has finished being interrupted), so
Packit 6c4009
	   our nonzero return tells the trampoline code to finish the message
Packit 6c4009
	   receive operation before running the handler.  */
Packit 6c4009
Packit 6c4009
	mach_port_t *reply = interrupted_reply_port_location (ss->thread,
Packit 6c4009
							      state,
Packit 6c4009
							      sigthread);
Packit 6c4009
	error_t err = __interrupt_operation (intr_port, _hurdsig_interrupt_timeout);
Packit 6c4009
Packit 6c4009
	if (err)
Packit 6c4009
	  {
Packit 6c4009
	    if (reply)
Packit 6c4009
	      {
Packit 6c4009
		/* The interrupt didn't work.
Packit 6c4009
		   Destroy the receive right the thread is blocked on.  */
Packit 6c4009
		__mach_port_destroy (__mach_task_self (), *reply);
Packit 6c4009
		*reply = MACH_PORT_NULL;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    /* The system call return value register now contains
Packit 6c4009
	       MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the
Packit 6c4009
	       call.  Since we have just destroyed the receive right, the
Packit 6c4009
	       retry will fail with MACH_RCV_INVALID_NAME.  Instead, just
Packit 6c4009
	       change the return value here to EINTR so mach_msg will not
Packit 6c4009
	       retry and the EINTR error code will propagate up.  */
Packit 6c4009
	    state->basic.SYSRETURN = EINTR;
Packit 6c4009
	    *state_change = 1;
Packit 6c4009
	  }
Packit 6c4009
	else if (reply)
Packit 6c4009
	  rcv_port = *reply;
Packit 6c4009
Packit 6c4009
	/* All threads whose RPCs were interrupted by the interrupt_operation
Packit 6c4009
	   call above will retry their RPCs unless we clear SS->intr_port.
Packit 6c4009
	   So we clear it for the thread taking a signal when SA_RESTART is
Packit 6c4009
	   clear, so that its call returns EINTR.  */
Packit 6c4009
	if (! signo || !(ss->actions[signo].sa_flags & SA_RESTART))
Packit 6c4009
	  ss->intr_port = MACH_PORT_NULL;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  return rcv_port;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Abort the RPCs being run by all threads but this one;
Packit 6c4009
   all other threads should be suspended.  If LIVE is nonzero, those
Packit 6c4009
   threads may run again, so they should be adjusted as necessary to be
Packit 6c4009
   happy when resumed.  STATE is clobbered as a scratch area; its initial
Packit 6c4009
   contents are ignored, and its contents on return are not useful.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
Packit 6c4009
{
Packit 6c4009
  /* We can just loop over the sigstates.  Any thread doing something
Packit 6c4009
     interruptible must have one.  We needn't bother locking because all
Packit 6c4009
     other threads are stopped.  */
Packit 6c4009
Packit 6c4009
  struct hurd_sigstate *ss;
Packit 6c4009
  size_t nthreads;
Packit 6c4009
  mach_port_t *reply_ports;
Packit 6c4009
Packit 6c4009
  /* First loop over the sigstates to count them.
Packit 6c4009
     We need to know how big a vector we will need for REPLY_PORTS.  */
Packit 6c4009
  nthreads = 0;
Packit 6c4009
  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
Packit 6c4009
    ++nthreads;
Packit 6c4009
Packit 6c4009
  reply_ports = alloca (nthreads * sizeof *reply_ports);
Packit 6c4009
Packit 6c4009
  nthreads = 0;
Packit 6c4009
  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next, ++nthreads)
Packit 6c4009
    if (ss->thread == _hurd_msgport_thread)
Packit 6c4009
      reply_ports[nthreads] = MACH_PORT_NULL;
Packit 6c4009
    else
Packit 6c4009
      {
Packit 6c4009
	int state_changed;
Packit 6c4009
	state->set = 0;		/* Reset scratch area.  */
Packit 6c4009
Packit 6c4009
	/* Abort any operation in progress with interrupt_operation.
Packit 6c4009
	   Record the reply port the thread is waiting on.
Packit 6c4009
	   We will wait for all the replies below.  */
Packit 6c4009
	reply_ports[nthreads] = _hurdsig_abort_rpcs (ss, signo, 1,
Packit 6c4009
						     state, &state_changed,
Packit 6c4009
						     NULL);
Packit 6c4009
	if (live)
Packit 6c4009
	  {
Packit 6c4009
	    if (reply_ports[nthreads] != MACH_PORT_NULL)
Packit 6c4009
	      {
Packit 6c4009
		/* We will wait for the reply to this RPC below, so the
Packit 6c4009
		   thread must issue a new RPC rather than waiting for the
Packit 6c4009
		   reply to the one it sent.  */
Packit 6c4009
		state->basic.SYSRETURN = EINTR;
Packit 6c4009
		state_changed = 1;
Packit 6c4009
	      }
Packit 6c4009
	    if (state_changed)
Packit 6c4009
	      /* Aborting the RPC needed to change this thread's state,
Packit 6c4009
		 and it might ever run again.  So write back its state.  */
Packit 6c4009
	      __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
Packit 6c4009
				  (natural_t *) &state->basic,
Packit 6c4009
				  MACHINE_THREAD_STATE_COUNT);
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  /* Wait for replies from all the successfully interrupted RPCs.  */
Packit 6c4009
  while (nthreads-- > 0)
Packit 6c4009
    if (reply_ports[nthreads] != MACH_PORT_NULL)
Packit 6c4009
      {
Packit 6c4009
	error_t err;
Packit 6c4009
	mach_msg_header_t head;
Packit 6c4009
	err = __mach_msg (&head, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof head,
Packit 6c4009
			  reply_ports[nthreads],
Packit 6c4009
			  _hurd_interrupted_rpc_timeout, MACH_PORT_NULL);
Packit 6c4009
	switch (err)
Packit 6c4009
	  {
Packit 6c4009
	  case MACH_RCV_TIMED_OUT:
Packit 6c4009
	  case MACH_RCV_TOO_LARGE:
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  default:
Packit 6c4009
	    assert_perror (err);
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
struct hurd_signal_preemptor *_hurdsig_preemptors = 0;
Packit 6c4009
sigset_t _hurdsig_preempted_set;
Packit 6c4009
Packit 6c4009
/* XXX temporary to deal with spelling fix */
Packit 6c4009
weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
Packit 6c4009
Packit 6c4009
/* Mask of stop signals.  */
Packit 6c4009
#define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \
Packit 6c4009
		  sigmask (SIGSTOP) | sigmask (SIGTSTP))
Packit 6c4009
Packit 6c4009
/* Deliver a signal.  SS is not locked.  */
Packit 6c4009
void
Packit 6c4009
_hurd_internal_post_signal (struct hurd_sigstate *ss,
Packit 6c4009
			    int signo, struct hurd_signal_detail *detail,
Packit 6c4009
			    mach_port_t reply_port,
Packit 6c4009
			    mach_msg_type_name_t reply_port_type,
Packit 6c4009
			    int untraced)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
  struct machine_thread_all_state thread_state;
Packit 6c4009
  enum { stop, ignore, core, term, handle } act;
Packit 6c4009
  sighandler_t handler;
Packit 6c4009
  sigset_t pending;
Packit 6c4009
  int ss_suspended;
Packit 6c4009
Packit 6c4009
  /* Reply to this sig_post message.  */
Packit 6c4009
  __typeof (__msg_sig_post_reply) *reply_rpc
Packit 6c4009
    = (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply);
Packit 6c4009
  void reply (void)
Packit 6c4009
    {
Packit 6c4009
      error_t err;
Packit 6c4009
      if (reply_port == MACH_PORT_NULL)
Packit 6c4009
	return;
Packit 6c4009
      err = (*reply_rpc) (reply_port, reply_port_type, 0);
Packit 6c4009
      reply_port = MACH_PORT_NULL;
Packit 6c4009
      if (err != MACH_SEND_INVALID_DEST) /* Ignore dead reply port.  */
Packit 6c4009
	assert_perror (err);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Mark the signal as pending.  */
Packit 6c4009
  void mark_pending (void)
Packit 6c4009
    {
Packit 6c4009
      __sigaddset (&ss->pending, signo);
Packit 6c4009
      /* Save the details to be given to the handler when SIGNO is
Packit 6c4009
	 unblocked.  */
Packit 6c4009
      ss->pending_data[signo] = *detail;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Suspend the process with SIGNO.  */
Packit 6c4009
  void suspend (void)
Packit 6c4009
    {
Packit 6c4009
      /* Stop all other threads and mark ourselves stopped.  */
Packit 6c4009
      __USEPORT (PROC,
Packit 6c4009
		 ({
Packit 6c4009
		   /* Hold the siglock while stopping other threads to be
Packit 6c4009
		      sure it is not held by another thread afterwards.  */
Packit 6c4009
		   __mutex_lock (&_hurd_siglock);
Packit 6c4009
		   __proc_dostop (port, _hurd_msgport_thread);
Packit 6c4009
		   __mutex_unlock (&_hurd_siglock);
Packit 6c4009
		   abort_all_rpcs (signo, &thread_state, 1);
Packit 6c4009
		   reply ();
Packit 6c4009
		   __proc_mark_stop (port, signo, detail->code);
Packit 6c4009
		 }));
Packit 6c4009
      _hurd_stopped = 1;
Packit 6c4009
    }
Packit 6c4009
  /* Resume the process after a suspension.  */
Packit 6c4009
  void resume (void)
Packit 6c4009
    {
Packit 6c4009
      /* Resume the process from being stopped.  */
Packit 6c4009
      thread_t *threads;
Packit 6c4009
      mach_msg_type_number_t nthreads, i;
Packit 6c4009
      error_t err;
Packit 6c4009
Packit 6c4009
      if (! _hurd_stopped)
Packit 6c4009
	return;
Packit 6c4009
Packit 6c4009
      /* Tell the proc server we are continuing.  */
Packit 6c4009
      __USEPORT (PROC, __proc_mark_cont (port));
Packit 6c4009
      /* Fetch ports to all our threads and resume them.  */
Packit 6c4009
      err = __task_threads (__mach_task_self (), &threads, &nthreads);
Packit 6c4009
      assert_perror (err);
Packit 6c4009
      for (i = 0; i < nthreads; ++i)
Packit 6c4009
	{
Packit 6c4009
	  if (threads[i] != _hurd_msgport_thread &&
Packit 6c4009
	      (act != handle || threads[i] != ss->thread))
Packit 6c4009
	    {
Packit 6c4009
	      err = __thread_resume (threads[i]);
Packit 6c4009
	      assert_perror (err);
Packit 6c4009
	    }
Packit 6c4009
	  err = __mach_port_deallocate (__mach_task_self (),
Packit 6c4009
					threads[i]);
Packit 6c4009
	  assert_perror (err);
Packit 6c4009
	}
Packit 6c4009
      __vm_deallocate (__mach_task_self (),
Packit 6c4009
		       (vm_address_t) threads,
Packit 6c4009
		       nthreads * sizeof *threads);
Packit 6c4009
      _hurd_stopped = 0;
Packit 6c4009
      if (act == handle)
Packit 6c4009
	/* The thread that will run the handler is already suspended.  */
Packit 6c4009
	ss_suspended = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (signo == 0)
Packit 6c4009
    {
Packit 6c4009
      if (untraced)
Packit 6c4009
	/* This is PTRACE_CONTINUE.  */
Packit 6c4009
	resume ();
Packit 6c4009
Packit 6c4009
      /* This call is just to check for pending signals.  */
Packit 6c4009
      __spin_lock (&ss->lock);
Packit 6c4009
      goto check_pending_signals;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
 post_signal:
Packit 6c4009
Packit 6c4009
  thread_state.set = 0;		/* We know nothing.  */
Packit 6c4009
Packit 6c4009
  __spin_lock (&ss->lock);
Packit 6c4009
Packit 6c4009
  /* Check for a preempted signal.  Preempted signals can arrive during
Packit 6c4009
     critical sections.  */
Packit 6c4009
  {
Packit 6c4009
    inline sighandler_t try_preemptor (struct hurd_signal_preemptor *pe)
Packit 6c4009
      {				/* PE cannot be null.  */
Packit 6c4009
	do
Packit 6c4009
	  {
Packit 6c4009
	    if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
Packit 6c4009
	      {
Packit 6c4009
		if (pe->preemptor)
Packit 6c4009
		  {
Packit 6c4009
		    sighandler_t handler = (*pe->preemptor) (pe, ss,
Packit 6c4009
							     &signo, detail);
Packit 6c4009
		    if (handler != SIG_ERR)
Packit 6c4009
		      return handler;
Packit 6c4009
		  }
Packit 6c4009
		else
Packit 6c4009
		  return pe->handler;
Packit 6c4009
	      }
Packit 6c4009
	    pe = pe->next;
Packit 6c4009
	  } while (pe != 0);
Packit 6c4009
	return SIG_ERR;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    handler = ss->preemptors ? try_preemptor (ss->preemptors) : SIG_ERR;
Packit 6c4009
Packit 6c4009
    /* If no thread-specific preemptor, check for a global one.  */
Packit 6c4009
    if (handler == SIG_ERR && __sigismember (&_hurdsig_preempted_set, signo))
Packit 6c4009
      {
Packit 6c4009
	__mutex_lock (&_hurd_siglock);
Packit 6c4009
	handler = try_preemptor (_hurdsig_preemptors);
Packit 6c4009
	__mutex_unlock (&_hurd_siglock);
Packit 6c4009
      }
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  ss_suspended = 0;
Packit 6c4009
Packit 6c4009
  if (handler == SIG_IGN)
Packit 6c4009
    /* Ignore the signal altogether.  */
Packit 6c4009
    act = ignore;
Packit 6c4009
  else if (handler != SIG_ERR)
Packit 6c4009
    /* Run the preemption-provided handler.  */
Packit 6c4009
    act = handle;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* No preemption.  Do normal handling.  */
Packit 6c4009
Packit 6c4009
      if (!untraced && __sigismember (&_hurdsig_traced, signo))
Packit 6c4009
	{
Packit 6c4009
	  /* We are being traced.  Stop to tell the debugger of the signal.  */
Packit 6c4009
	  if (_hurd_stopped)
Packit 6c4009
	    /* Already stopped.  Mark the signal as pending;
Packit 6c4009
	       when resumed, we will notice it and stop again.  */
Packit 6c4009
	    mark_pending ();
Packit 6c4009
	  else
Packit 6c4009
	    suspend ();
Packit 6c4009
	  __spin_unlock (&ss->lock);
Packit 6c4009
	  reply ();
Packit 6c4009
	  return;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      handler = ss->actions[signo].sa_handler;
Packit 6c4009
Packit 6c4009
      if (handler == SIG_DFL)
Packit 6c4009
	/* Figure out the default action for this signal.  */
Packit 6c4009
	switch (signo)
Packit 6c4009
	  {
Packit 6c4009
	  case 0:
Packit 6c4009
	    /* A sig_post msg with SIGNO==0 is sent to
Packit 6c4009
	       tell us to check for pending signals.  */
Packit 6c4009
	    act = ignore;
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  case SIGTTIN:
Packit 6c4009
	  case SIGTTOU:
Packit 6c4009
	  case SIGSTOP:
Packit 6c4009
	  case SIGTSTP:
Packit 6c4009
	    act = stop;
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  case SIGCONT:
Packit 6c4009
	  case SIGIO:
Packit 6c4009
	  case SIGURG:
Packit 6c4009
	  case SIGCHLD:
Packit 6c4009
	  case SIGWINCH:
Packit 6c4009
	    act = ignore;
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  case SIGQUIT:
Packit 6c4009
	  case SIGILL:
Packit 6c4009
	  case SIGTRAP:
Packit 6c4009
	  case SIGIOT:
Packit 6c4009
	  case SIGEMT:
Packit 6c4009
	  case SIGFPE:
Packit 6c4009
	  case SIGBUS:
Packit 6c4009
	  case SIGSEGV:
Packit 6c4009
	  case SIGSYS:
Packit 6c4009
	    act = core;
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  case SIGINFO:
Packit 6c4009
	    if (_hurd_pgrp == _hurd_pid)
Packit 6c4009
	      {
Packit 6c4009
		/* We are the process group leader.  Since there is no
Packit 6c4009
		   user-specified handler for SIGINFO, we use a default one
Packit 6c4009
		   which prints something interesting.  We use the normal
Packit 6c4009
		   handler mechanism instead of just doing it here to avoid
Packit 6c4009
		   the signal thread faulting or blocking in this
Packit 6c4009
		   potentially hairy operation.  */
Packit 6c4009
		act = handle;
Packit 6c4009
		handler = _hurd_siginfo_handler;
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
	      act = ignore;
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  default:
Packit 6c4009
	    act = term;
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
      else if (handler == SIG_IGN)
Packit 6c4009
	act = ignore;
Packit 6c4009
      else
Packit 6c4009
	act = handle;
Packit 6c4009
Packit 6c4009
      if (__sigmask (signo) & STOPSIGS)
Packit 6c4009
	/* Stop signals clear a pending SIGCONT even if they
Packit 6c4009
	   are handled or ignored (but not if preempted).  */
Packit 6c4009
	__sigdelset (&ss->pending, SIGCONT);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  if (signo == SIGCONT)
Packit 6c4009
	    /* Even if handled or ignored (but not preempted), SIGCONT clears
Packit 6c4009
	       stop signals and resumes the process.  */
Packit 6c4009
	    ss->pending &= ~STOPSIGS;
Packit 6c4009
Packit 6c4009
	  if (_hurd_stopped && act != stop && (untraced || signo == SIGCONT))
Packit 6c4009
	    resume ();
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (_hurd_orphaned && act == stop &&
Packit 6c4009
      (__sigmask (signo) & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) |
Packit 6c4009
			    __sigmask (SIGTSTP))))
Packit 6c4009
    {
Packit 6c4009
      /* If we would ordinarily stop for a job control signal, but we are
Packit 6c4009
	 orphaned so noone would ever notice and continue us again, we just
Packit 6c4009
	 quietly die, alone and in the dark.  */
Packit 6c4009
      detail->code = signo;
Packit 6c4009
      signo = SIGKILL;
Packit 6c4009
      act = term;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Handle receipt of a blocked signal, or any signal while stopped.  */
Packit 6c4009
  if (act != ignore &&		/* Signals ignored now are forgotten now.  */
Packit 6c4009
      __sigismember (&ss->blocked, signo) ||
Packit 6c4009
      (signo != SIGKILL && _hurd_stopped))
Packit 6c4009
    {
Packit 6c4009
      mark_pending ();
Packit 6c4009
      act = ignore;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Perform the chosen action for the signal.  */
Packit 6c4009
  switch (act)
Packit 6c4009
    {
Packit 6c4009
    case stop:
Packit 6c4009
      if (_hurd_stopped)
Packit 6c4009
	{
Packit 6c4009
	  /* We are already stopped, but receiving an untraced stop
Packit 6c4009
	     signal.  Instead of resuming and suspending again, just
Packit 6c4009
	     notify the proc server of the new stop signal.  */
Packit 6c4009
	  error_t err = __USEPORT (PROC, __proc_mark_stop
Packit 6c4009
				   (port, signo, detail->code));
Packit 6c4009
	  assert_perror (err);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	/* Suspend the process.  */
Packit 6c4009
	suspend ();
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case ignore:
Packit 6c4009
      if (detail->exc)
Packit 6c4009
	/* Blocking or ignoring a machine exception is fatal.
Packit 6c4009
	   Otherwise we could just spin on the faulting instruction.  */
Packit 6c4009
	goto fatal;
Packit 6c4009
Packit 6c4009
      /* Nobody cares about this signal.  If there was a call to resume
Packit 6c4009
	 above in SIGCONT processing and we've left a thread suspended,
Packit 6c4009
	 now's the time to set it going. */
Packit 6c4009
      if (ss_suspended)
Packit 6c4009
	{
Packit 6c4009
	  err = __thread_resume (ss->thread);
Packit 6c4009
	  assert_perror (err);
Packit 6c4009
	  ss_suspended = 0;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    sigbomb:
Packit 6c4009
      /* We got a fault setting up the stack frame for the handler.
Packit 6c4009
	 Nothing to do but die; BSD gets SIGILL in this case.  */
Packit 6c4009
      detail->code = signo;	/* XXX ? */
Packit 6c4009
      signo = SIGILL;
Packit 6c4009
Packit 6c4009
    fatal:
Packit 6c4009
      act = core;
Packit 6c4009
      /* FALLTHROUGH */
Packit 6c4009
Packit 6c4009
    case term:			/* Time to die.  */
Packit 6c4009
    case core:			/* And leave a rotting corpse.  */
Packit 6c4009
      /* Have the proc server stop all other threads in our task.  */
Packit 6c4009
      err = __USEPORT (PROC, __proc_dostop (port, _hurd_msgport_thread));
Packit 6c4009
      assert_perror (err);
Packit 6c4009
      /* No more user instructions will be executed.
Packit 6c4009
	 The signal can now be considered delivered.  */
Packit 6c4009
      reply ();
Packit 6c4009
      /* Abort all server operations now in progress.  */
Packit 6c4009
      abort_all_rpcs (signo, &thread_state, 0);
Packit 6c4009
Packit 6c4009
      {
Packit 6c4009
	int status = W_EXITCODE (0, signo);
Packit 6c4009
	/* Do a core dump if desired.  Only set the wait status bit saying we
Packit 6c4009
	   in fact dumped core if the operation was actually successful.  */
Packit 6c4009
	if (act == core && write_corefile (signo, detail))
Packit 6c4009
	  status |= WCOREFLAG;
Packit 6c4009
	/* Tell proc how we died and then stick the saber in the gut.  */
Packit 6c4009
	_hurd_exit (status);
Packit 6c4009
	/* NOTREACHED */
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    case handle:
Packit 6c4009
      /* Call a handler for this signal.  */
Packit 6c4009
      {
Packit 6c4009
	struct sigcontext *scp, ocontext;
Packit 6c4009
	int wait_for_reply, state_changed;
Packit 6c4009
Packit 6c4009
	/* Stop the thread and abort its pending RPC operations.  */
Packit 6c4009
	if (! ss_suspended)
Packit 6c4009
	  {
Packit 6c4009
	    err = __thread_suspend (ss->thread);
Packit 6c4009
	    assert_perror (err);
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	/* Abort the thread's kernel context, so any pending message send
Packit 6c4009
	   or receive completes immediately or aborts.  If an interruptible
Packit 6c4009
	   RPC is in progress, abort_rpcs will do this.  But we must always
Packit 6c4009
	   do it before fetching the thread's state, because
Packit 6c4009
	   thread_get_state is never kosher before thread_abort.  */
Packit 6c4009
	abort_thread (ss, &thread_state, NULL);
Packit 6c4009
Packit 6c4009
	if (ss->context)
Packit 6c4009
	  {
Packit 6c4009
	    /* We have a previous sigcontext that sigreturn was about
Packit 6c4009
	       to restore when another signal arrived.  */
Packit 6c4009
Packit 6c4009
	    mach_port_t *loc;
Packit 6c4009
Packit 6c4009
	    if (_hurdsig_catch_memory_fault (ss->context))
Packit 6c4009
	      {
Packit 6c4009
		/* We faulted reading the thread's stack.  Forget that
Packit 6c4009
		   context and pretend it wasn't there.  It almost
Packit 6c4009
		   certainly crash if this handler returns, but that's it's
Packit 6c4009
		   problem.  */
Packit 6c4009
		ss->context = NULL;
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
	      {
Packit 6c4009
		/* Copy the context from the thread's stack before
Packit 6c4009
		   we start diddling the stack to set up the handler.  */
Packit 6c4009
		ocontext = *ss->context;
Packit 6c4009
		ss->context = &ocontext;
Packit 6c4009
	      }
Packit 6c4009
	    _hurdsig_end_catch_fault ();
Packit 6c4009
Packit 6c4009
	    if (! machine_get_basic_state (ss->thread, &thread_state))
Packit 6c4009
	      goto sigbomb;
Packit 6c4009
	    loc = interrupted_reply_port_location (ss->thread,
Packit 6c4009
						   &thread_state, 1);
Packit 6c4009
	    if (loc && *loc != MACH_PORT_NULL)
Packit 6c4009
	      /* This is the reply port for the context which called
Packit 6c4009
		 sigreturn.  Since we are abandoning that context entirely
Packit 6c4009
		 and restoring SS->context instead, destroy this port.  */
Packit 6c4009
	      __mach_port_destroy (__mach_task_self (), *loc);
Packit 6c4009
Packit 6c4009
	    /* The thread was in sigreturn, not in any interruptible RPC.  */
Packit 6c4009
	    wait_for_reply = 0;
Packit 6c4009
Packit 6c4009
	    assert (! __spin_lock_locked (&ss->critical_section_lock));
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
	  {
Packit 6c4009
	    int crit = __spin_lock_locked (&ss->critical_section_lock);
Packit 6c4009
Packit 6c4009
	    wait_for_reply
Packit 6c4009
	      = (_hurdsig_abort_rpcs (ss,
Packit 6c4009
				      /* In a critical section, any RPC
Packit 6c4009
					 should be cancelled instead of
Packit 6c4009
					 restarted, regardless of
Packit 6c4009
					 SA_RESTART, so the entire
Packit 6c4009
					 "atomic" operation can be aborted
Packit 6c4009
					 as a unit.  */
Packit 6c4009
				      crit ? 0 : signo, 1,
Packit 6c4009
				      &thread_state, &state_changed,
Packit 6c4009
				      &reply)
Packit 6c4009
		 != MACH_PORT_NULL);
Packit 6c4009
Packit 6c4009
	    if (crit)
Packit 6c4009
	      {
Packit 6c4009
		/* The thread is in a critical section.  Mark the signal as
Packit 6c4009
		   pending.  When it finishes the critical section, it will
Packit 6c4009
		   check for pending signals.  */
Packit 6c4009
		mark_pending ();
Packit 6c4009
		if (state_changed)
Packit 6c4009
		  /* Some cases of interrupting an RPC must change the
Packit 6c4009
		     thread state to back out the call.  Normally this
Packit 6c4009
		     change is rolled into the warping to the handler and
Packit 6c4009
		     sigreturn, but we are not running the handler now
Packit 6c4009
		     because the thread is in a critical section.  Instead,
Packit 6c4009
		     mutate the thread right away for the RPC interruption
Packit 6c4009
		     and resume it; the RPC will return early so the
Packit 6c4009
		     critical section can end soon.  */
Packit 6c4009
		  __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
Packit 6c4009
				      (natural_t *) &thread_state.basic,
Packit 6c4009
				      MACHINE_THREAD_STATE_COUNT);
Packit 6c4009
		/* */
Packit 6c4009
		ss->intr_port = MACH_PORT_NULL;
Packit 6c4009
		__thread_resume (ss->thread);
Packit 6c4009
		break;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	/* Call the machine-dependent function to set the thread up
Packit 6c4009
	   to run the signal handler, and preserve its old context.  */
Packit 6c4009
	scp = _hurd_setup_sighandler (ss, handler, signo, detail,
Packit 6c4009
				      wait_for_reply, &thread_state);
Packit 6c4009
	if (scp == NULL)
Packit 6c4009
	  goto sigbomb;
Packit 6c4009
Packit 6c4009
	/* Set the machine-independent parts of the signal context.  */
Packit 6c4009
Packit 6c4009
	{
Packit 6c4009
	  /* Fetch the thread variable for the MiG reply port,
Packit 6c4009
	     and set it to MACH_PORT_NULL.  */
Packit 6c4009
	  mach_port_t *loc = interrupted_reply_port_location (ss->thread,
Packit 6c4009
							      &thread_state,
Packit 6c4009
							      1);
Packit 6c4009
	  if (loc)
Packit 6c4009
	    {
Packit 6c4009
	      scp->sc_reply_port = *loc;
Packit 6c4009
	      *loc = MACH_PORT_NULL;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    scp->sc_reply_port = MACH_PORT_NULL;
Packit 6c4009
Packit 6c4009
	  /* Save the intr_port in use by the interrupted code,
Packit 6c4009
	     and clear the cell before running the trampoline.  */
Packit 6c4009
	  scp->sc_intr_port = ss->intr_port;
Packit 6c4009
	  ss->intr_port = MACH_PORT_NULL;
Packit 6c4009
Packit 6c4009
	  if (ss->context)
Packit 6c4009
	    {
Packit 6c4009
	      /* After the handler runs we will restore to the state in
Packit 6c4009
		 SS->context, not the state of the thread now.  So restore
Packit 6c4009
		 that context's reply port and intr port.  */
Packit 6c4009
Packit 6c4009
	      scp->sc_reply_port = ss->context->sc_reply_port;
Packit 6c4009
	      scp->sc_intr_port = ss->context->sc_intr_port;
Packit 6c4009
Packit 6c4009
	      ss->context = NULL;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	/* Backdoor extra argument to signal handler.  */
Packit 6c4009
	scp->sc_error = detail->error;
Packit 6c4009
Packit 6c4009
	/* Block requested signals while running the handler.  */
Packit 6c4009
	scp->sc_mask = ss->blocked;
Packit 6c4009
	__sigorset (&ss->blocked, &ss->blocked, &ss->actions[signo].sa_mask);
Packit 6c4009
Packit 6c4009
	/* Also block SIGNO unless we're asked not to.  */
Packit 6c4009
	if (! (ss->actions[signo].sa_flags & (SA_RESETHAND | SA_NODEFER)))
Packit 6c4009
	  __sigaddset (&ss->blocked, signo);
Packit 6c4009
Packit 6c4009
	/* Reset to SIG_DFL if requested.  SIGILL and SIGTRAP cannot
Packit 6c4009
           be automatically reset when delivered; the system silently
Packit 6c4009
           enforces this restriction.  */
Packit 6c4009
	if (ss->actions[signo].sa_flags & SA_RESETHAND
Packit 6c4009
	    && signo != SIGILL && signo != SIGTRAP)
Packit 6c4009
	  ss->actions[signo].sa_handler = SIG_DFL;
Packit 6c4009
Packit 6c4009
	/* Start the thread running the handler (or possibly waiting for an
Packit 6c4009
	   RPC reply before running the handler).  */
Packit 6c4009
	err = __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
Packit 6c4009
				  (natural_t *) &thread_state.basic,
Packit 6c4009
				  MACHINE_THREAD_STATE_COUNT);
Packit 6c4009
	assert_perror (err);
Packit 6c4009
	err = __thread_resume (ss->thread);
Packit 6c4009
	assert_perror (err);
Packit 6c4009
	thread_state.set = 0;	/* Everything we know is now wrong.  */
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* The signal has either been ignored or is now being handled.  We can
Packit 6c4009
     consider it delivered and reply to the killer.  */
Packit 6c4009
  reply ();
Packit 6c4009
Packit 6c4009
  /* We get here unless the signal was fatal.  We still hold SS->lock.
Packit 6c4009
     Check for pending signals, and loop to post them.  */
Packit 6c4009
  {
Packit 6c4009
    /* Return nonzero if SS has any signals pending we should worry about.
Packit 6c4009
       We don't worry about any pending signals if we are stopped, nor if
Packit 6c4009
       SS is in a critical section.  We are guaranteed to get a sig_post
Packit 6c4009
       message before any of them become deliverable: either the SIGCONT
Packit 6c4009
       signal, or a sig_post with SIGNO==0 as an explicit poll when the
Packit 6c4009
       thread finishes its critical section.  */
Packit 6c4009
    inline int signals_pending (void)
Packit 6c4009
      {
Packit 6c4009
	if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
Packit 6c4009
	  return 0;
Packit 6c4009
	return pending = ss->pending & ~ss->blocked;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  check_pending_signals:
Packit 6c4009
    untraced = 0;
Packit 6c4009
Packit 6c4009
    if (signals_pending ())
Packit 6c4009
      {
Packit 6c4009
	for (signo = 1; signo < NSIG; ++signo)
Packit 6c4009
	  if (__sigismember (&pending, signo))
Packit 6c4009
	    {
Packit 6c4009
	    deliver_pending:
Packit 6c4009
	      __sigdelset (&ss->pending, signo);
Packit 6c4009
	      *detail = ss->pending_data[signo];
Packit 6c4009
	      __spin_unlock (&ss->lock);
Packit 6c4009
	      goto post_signal;
Packit 6c4009
	    }
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    /* No pending signals left undelivered for this thread.
Packit 6c4009
       If we were sent signal 0, we need to check for pending
Packit 6c4009
       signals for all threads.  */
Packit 6c4009
    if (signo == 0)
Packit 6c4009
      {
Packit 6c4009
	__spin_unlock (&ss->lock);
Packit 6c4009
	__mutex_lock (&_hurd_siglock);
Packit 6c4009
	for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
Packit 6c4009
	  {
Packit 6c4009
	    __spin_lock (&ss->lock);
Packit 6c4009
	    for (signo = 1; signo < NSIG; ++signo)
Packit 6c4009
	      if (__sigismember (&ss->pending, signo)
Packit 6c4009
		  && (!__sigismember (&ss->blocked, signo)
Packit 6c4009
		      /* We "deliver" immediately pending blocked signals whose
Packit 6c4009
			 action might be to ignore, so that if ignored they are
Packit 6c4009
			 dropped right away.  */
Packit 6c4009
		      || ss->actions[signo].sa_handler == SIG_IGN
Packit 6c4009
		      || ss->actions[signo].sa_handler == SIG_DFL))
Packit 6c4009
		{
Packit 6c4009
		  __mutex_unlock (&_hurd_siglock);
Packit 6c4009
		  goto deliver_pending;
Packit 6c4009
		}
Packit 6c4009
	    __spin_unlock (&ss->lock);
Packit 6c4009
	  }
Packit 6c4009
	__mutex_unlock (&_hurd_siglock);
Packit 6c4009
      }
Packit 6c4009
    else
Packit 6c4009
      {
Packit 6c4009
	/* No more signals pending; SS->lock is still locked.
Packit 6c4009
	   Wake up any sigsuspend call that is blocking SS->thread.  */
Packit 6c4009
	if (ss->suspended != MACH_PORT_NULL)
Packit 6c4009
	  {
Packit 6c4009
	    /* There is a sigsuspend waiting.  Tell it to wake up.  */
Packit 6c4009
	    error_t err;
Packit 6c4009
	    mach_msg_header_t msg;
Packit 6c4009
	    msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
Packit 6c4009
	    msg.msgh_remote_port = ss->suspended;
Packit 6c4009
	    msg.msgh_local_port = MACH_PORT_NULL;
Packit 6c4009
	    /* These values do not matter.  */
Packit 6c4009
	    msg.msgh_id = 8675309; /* Jenny, Jenny.  */
Packit 6c4009
	    ss->suspended = MACH_PORT_NULL;
Packit 6c4009
	    err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
Packit 6c4009
			      MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
Packit 6c4009
			      MACH_PORT_NULL);
Packit 6c4009
	    assert_perror (err);
Packit 6c4009
	  }
Packit 6c4009
	__spin_unlock (&ss->lock);
Packit 6c4009
      }
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  /* All pending signals delivered to all threads.
Packit 6c4009
     Now we can send the reply message even for signal 0.  */
Packit 6c4009
  reply ();
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Decide whether REFPORT enables the sender to send us a SIGNO signal.
Packit 6c4009
   Returns zero if so, otherwise the error code to return to the sender.  */
Packit 6c4009
Packit 6c4009
static error_t
Packit 6c4009
signal_allowed (int signo, mach_port_t refport)
Packit 6c4009
{
Packit 6c4009
  if (signo < 0 || signo >= NSIG)
Packit 6c4009
    return EINVAL;
Packit 6c4009
Packit 6c4009
  if (refport == __mach_task_self ())
Packit 6c4009
    /* Can send any signal.  */
Packit 6c4009
    goto win;
Packit 6c4009
Packit 6c4009
  /* Avoid needing to check for this below.  */
Packit 6c4009
  if (refport == MACH_PORT_NULL)
Packit 6c4009
    return EPERM;
Packit 6c4009
Packit 6c4009
  switch (signo)
Packit 6c4009
    {
Packit 6c4009
    case SIGINT:
Packit 6c4009
    case SIGQUIT:
Packit 6c4009
    case SIGTSTP:
Packit 6c4009
    case SIGHUP:
Packit 6c4009
    case SIGINFO:
Packit 6c4009
    case SIGTTIN:
Packit 6c4009
    case SIGTTOU:
Packit 6c4009
    case SIGWINCH:
Packit 6c4009
      /* Job control signals can be sent by the controlling terminal.  */
Packit 6c4009
      if (__USEPORT (CTTYID, port == refport))
Packit 6c4009
	goto win;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case SIGCONT:
Packit 6c4009
      {
Packit 6c4009
	/* A continue signal can be sent by anyone in the session.  */
Packit 6c4009
	mach_port_t sessport;
Packit 6c4009
	if (! __USEPORT (PROC, __proc_getsidport (port, &sessport)))
Packit 6c4009
	  {
Packit 6c4009
	    __mach_port_deallocate (__mach_task_self (), sessport);
Packit 6c4009
	    if (refport == sessport)
Packit 6c4009
	      goto win;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case SIGIO:
Packit 6c4009
    case SIGURG:
Packit 6c4009
      {
Packit 6c4009
	/* Any io object a file descriptor refers to might send us
Packit 6c4009
	   one of these signals using its async ID port for REFPORT.
Packit 6c4009
Packit 6c4009
	   This is pretty wide open; it is not unlikely that some random
Packit 6c4009
	   process can at least open for reading something we have open,
Packit 6c4009
	   get its async ID port, and send us a spurious SIGIO or SIGURG
Packit 6c4009
	   signal.  But BSD is actually wider open than that!--you can set
Packit 6c4009
	   the owner of an io object to any process or process group
Packit 6c4009
	   whatsoever and send them gratuitous signals.
Packit 6c4009
Packit 6c4009
	   Someday we could implement some reasonable scheme for
Packit 6c4009
	   authorizing SIGIO and SIGURG signals properly.  */
Packit 6c4009
Packit 6c4009
	int d;
Packit 6c4009
	int lucky = 0;		/* True if we find a match for REFPORT.  */
Packit 6c4009
	__mutex_lock (&_hurd_dtable_lock);
Packit 6c4009
	for (d = 0; !lucky && (unsigned) d < (unsigned) _hurd_dtablesize; ++d)
Packit 6c4009
	  {
Packit 6c4009
	    struct hurd_userlink ulink;
Packit 6c4009
	    io_t port;
Packit 6c4009
	    mach_port_t asyncid;
Packit 6c4009
	    if (_hurd_dtable[d] == NULL)
Packit 6c4009
	      continue;
Packit 6c4009
	    port = _hurd_port_get (&_hurd_dtable[d]->port, &ulink);
Packit 6c4009
	    if (! __io_get_icky_async_id (port, &asyncid))
Packit 6c4009
	      {
Packit 6c4009
		if (refport == asyncid)
Packit 6c4009
		  /* Break out of the loop on the next iteration.  */
Packit 6c4009
		  lucky = 1;
Packit 6c4009
		__mach_port_deallocate (__mach_task_self (), asyncid);
Packit 6c4009
	      }
Packit 6c4009
	    _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port);
Packit 6c4009
	  }
Packit 6c4009
	__mutex_unlock (&_hurd_dtable_lock);
Packit 6c4009
	/* If we found a lucky winner, we've set D to -1 in the loop.  */
Packit 6c4009
	if (lucky)
Packit 6c4009
	  goto win;
Packit 6c4009
      }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* If this signal is legit, we have done `goto win' by now.
Packit 6c4009
     When we return the error, mig deallocates REFPORT.  */
Packit 6c4009
  return EPERM;
Packit 6c4009
Packit 6c4009
 win:
Packit 6c4009
  /* Deallocate the REFPORT send right; we are done with it.  */
Packit 6c4009
  __mach_port_deallocate (__mach_task_self (), refport);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Implement the sig_post RPC from <hurd/msg.defs>;
Packit 6c4009
   sent when someone wants us to get a signal.  */
Packit 6c4009
kern_return_t
Packit 6c4009
_S_msg_sig_post (mach_port_t me,
Packit 6c4009
		 mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
Packit 6c4009
		 int signo, natural_t sigcode,
Packit 6c4009
		 mach_port_t refport)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
  struct hurd_signal_detail d;
Packit 6c4009
Packit 6c4009
  if (err = signal_allowed (signo, refport))
Packit 6c4009
    return err;
Packit 6c4009
Packit 6c4009
  d.code = sigcode;
Packit 6c4009
  d.exc = 0;
Packit 6c4009
Packit 6c4009
  /* Post the signal to the designated signal-receiving thread.  This will
Packit 6c4009
     reply when the signal can be considered delivered.  */
Packit 6c4009
  _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread),
Packit 6c4009
			      signo, &d, reply_port, reply_port_type,
Packit 6c4009
			      0); /* Stop if traced.  */
Packit 6c4009
Packit 6c4009
  return MIG_NO_REPLY;		/* Already replied.  */
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Implement the sig_post_untraced RPC from <hurd/msg.defs>;
Packit 6c4009
   sent when the debugger wants us to really get a signal
Packit 6c4009
   even if we are traced.  */
Packit 6c4009
kern_return_t
Packit 6c4009
_S_msg_sig_post_untraced (mach_port_t me,
Packit 6c4009
			  mach_port_t reply_port,
Packit 6c4009
			  mach_msg_type_name_t reply_port_type,
Packit 6c4009
			  int signo, natural_t sigcode,
Packit 6c4009
			  mach_port_t refport)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
  struct hurd_signal_detail d;
Packit 6c4009
Packit 6c4009
  if (err = signal_allowed (signo, refport))
Packit 6c4009
    return err;
Packit 6c4009
Packit 6c4009
  d.code = sigcode;
Packit 6c4009
  d.exc = 0;
Packit 6c4009
Packit 6c4009
  /* Post the signal to the designated signal-receiving thread.  This will
Packit 6c4009
     reply when the signal can be considered delivered.  */
Packit 6c4009
  _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread),
Packit 6c4009
			      signo, &d, reply_port, reply_port_type,
Packit 6c4009
			      1); /* Untraced flag. */
Packit 6c4009
Packit 6c4009
  return MIG_NO_REPLY;		/* Already replied.  */
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
extern void __mig_init (void *);
Packit 6c4009
Packit 6c4009
#include <mach/task_special_ports.h>
Packit 6c4009
Packit 6c4009
/* Initialize the message port and _hurd_sigthread and start the signal
Packit 6c4009
   thread.  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_hurdsig_init (const int *intarray, size_t intarraysize)
Packit 6c4009
{
Packit 6c4009
  error_t err;
Packit 6c4009
  vm_size_t stacksize;
Packit 6c4009
  struct hurd_sigstate *ss;
Packit 6c4009
Packit 6c4009
  __mutex_init (&_hurd_siglock);
Packit 6c4009
Packit 6c4009
  err = __mach_port_allocate (__mach_task_self (),
Packit 6c4009
			      MACH_PORT_RIGHT_RECEIVE,
Packit 6c4009
			      &_hurd_msgport);
Packit 6c4009
  assert_perror (err);
Packit 6c4009
Packit 6c4009
  /* Make a send right to the signal port.  */
Packit 6c4009
  err = __mach_port_insert_right (__mach_task_self (),
Packit 6c4009
				  _hurd_msgport,
Packit 6c4009
				  _hurd_msgport,
Packit 6c4009
				  MACH_MSG_TYPE_MAKE_SEND);
Packit 6c4009
  assert_perror (err);
Packit 6c4009
Packit 6c4009
  /* Initialize the main thread's signal state.  */
Packit 6c4009
  ss = _hurd_self_sigstate ();
Packit 6c4009
Packit 6c4009
  /* Copy inherited values from our parent (or pre-exec process state)
Packit 6c4009
     into the signal settings of the main thread.  */
Packit 6c4009
  if (intarraysize > INIT_SIGMASK)
Packit 6c4009
    ss->blocked = intarray[INIT_SIGMASK];
Packit 6c4009
  if (intarraysize > INIT_SIGPENDING)
Packit 6c4009
    ss->pending = intarray[INIT_SIGPENDING];
Packit 6c4009
  if (intarraysize > INIT_SIGIGN && intarray[INIT_SIGIGN] != 0)
Packit 6c4009
    {
Packit 6c4009
      int signo;
Packit 6c4009
      for (signo = 1; signo < NSIG; ++signo)
Packit 6c4009
	if (intarray[INIT_SIGIGN] & __sigmask(signo))
Packit 6c4009
	  ss->actions[signo].sa_handler = SIG_IGN;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Set the default thread to receive task-global signals
Packit 6c4009
     to this one, the main (first) user thread.  */
Packit 6c4009
  _hurd_sigthread = ss->thread;
Packit 6c4009
Packit 6c4009
  /* Start the signal thread listening on the message port.  */
Packit 6c4009
Packit 6c4009
#pragma weak __cthread_fork
Packit 6c4009
  if (!__cthread_fork)
Packit 6c4009
    {
Packit 6c4009
      err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
Packit 6c4009
      assert_perror (err);
Packit 6c4009
Packit 6c4009
      stacksize = __vm_page_size * 8; /* Small stack for signal thread.  */
Packit 6c4009
      err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
Packit 6c4009
				 _hurd_msgport_receive,
Packit 6c4009
				 (vm_address_t *) &__hurd_sigthread_stack_base,
Packit 6c4009
				 &stacksize);
Packit 6c4009
      assert_perror (err);
Packit 6c4009
      err = __mach_setup_tls (_hurd_msgport_thread);
Packit 6c4009
      assert_perror (err);
Packit 6c4009
Packit 6c4009
      __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
Packit 6c4009
Packit 6c4009
      /* Reinitialize the MiG support routines so they will use a per-thread
Packit 6c4009
	 variable for the cached reply port.  */
Packit 6c4009
      __mig_init ((void *) __hurd_sigthread_stack_base);
Packit 6c4009
Packit 6c4009
      err = __thread_resume (_hurd_msgport_thread);
Packit 6c4009
      assert_perror (err);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* When cthreads is being used, we need to make the signal thread a
Packit 6c4009
         proper cthread.  Otherwise it cannot use mutex_lock et al, which
Packit 6c4009
         will be the cthreads versions.  Various of the message port RPC
Packit 6c4009
         handlers need to take locks, so we need to be able to call into
Packit 6c4009
         cthreads code and meet its assumptions about how our thread and
Packit 6c4009
         its stack are arranged.  Since cthreads puts it there anyway,
Packit 6c4009
         we'll let the signal thread's per-thread variables be found as for
Packit 6c4009
         any normal cthread, and just leave the magic __hurd_sigthread_*
Packit 6c4009
         values all zero so they'll be ignored.  */
Packit 6c4009
#pragma weak __cthread_detach
Packit 6c4009
#pragma weak __pthread_getattr_np
Packit 6c4009
#pragma weak __pthread_attr_getstack
Packit 6c4009
      __cthread_t thread = __cthread_fork (
Packit 6c4009
			     (cthread_fn_t) &_hurd_msgport_receive, 0);
Packit 6c4009
      __cthread_detach (thread);
Packit 6c4009
Packit 6c4009
      if (__pthread_getattr_np)
Packit 6c4009
	{
Packit 6c4009
	  /* Record signal thread stack layout for fork() */
Packit 6c4009
	  pthread_attr_t attr;
Packit 6c4009
	  void *addr;
Packit 6c4009
	  size_t size;
Packit 6c4009
Packit 6c4009
	  __pthread_getattr_np ((pthread_t) thread, &attr);
Packit 6c4009
	  __pthread_attr_getstack (&attr, &addr, &size);
Packit 6c4009
	  __hurd_sigthread_stack_base = (uintptr_t) addr;
Packit 6c4009
	  __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + size;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* XXX We need the thread port for the signal thread further on
Packit 6c4009
         in this thread (see hurdfault.c:_hurdsigfault_init).
Packit 6c4009
         Therefore we block until _hurd_msgport_thread is initialized
Packit 6c4009
         by the newly created thread.  This really shouldn't be
Packit 6c4009
         necessary; we should be able to fetch the thread port for a
Packit 6c4009
         cthread from here.  */
Packit 6c4009
      while (_hurd_msgport_thread == 0)
Packit 6c4009
	__swtch_pri (0);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Receive exceptions on the signal port.  */
Packit 6c4009
#ifdef TASK_EXCEPTION_PORT
Packit 6c4009
  __task_set_special_port (__mach_task_self (),
Packit 6c4009
			   TASK_EXCEPTION_PORT, _hurd_msgport);
Packit 6c4009
#elif defined (EXC_MASK_ALL)
Packit 6c4009
  __task_set_exception_ports (__mach_task_self (),
Packit 6c4009
			      EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
Packit 6c4009
					       | EXC_MASK_MACH_SYSCALL
Packit 6c4009
					       | EXC_MASK_RPC_ALERT),
Packit 6c4009
			      _hurd_msgport,
Packit 6c4009
			      EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
Packit 6c4009
#else
Packit 6c4009
# error task_set_exception_port?
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Sanity check.  Any pending, unblocked signals should have been
Packit 6c4009
     taken by our predecessor incarnation (i.e. parent or pre-exec state)
Packit 6c4009
     before packing up our init ints.  This assert is last (not above)
Packit 6c4009
     so that signal handling is all set up to handle the abort.  */
Packit 6c4009
  assert ((ss->pending &~ ss->blocked) == 0);
Packit 6c4009
}
Packit 6c4009
				/* XXXX */
Packit 6c4009
/* Reauthenticate with the proc server.  */
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
reauth_proc (mach_port_t new)
Packit 6c4009
{
Packit 6c4009
  mach_port_t ref, ignore;
Packit 6c4009
Packit 6c4009
  ref = __mach_reply_port ();
Packit 6c4009
  if (! HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
Packit 6c4009
		       __proc_reauthenticate (port, ref,
Packit 6c4009
					      MACH_MSG_TYPE_MAKE_SEND) ||
Packit 6c4009
		       __auth_user_authenticate (new, ref,
Packit 6c4009
						 MACH_MSG_TYPE_MAKE_SEND,
Packit 6c4009
						 &ignore))
Packit 6c4009
      && ignore != MACH_PORT_NULL)
Packit 6c4009
    __mach_port_deallocate (__mach_task_self (), ignore);
Packit 6c4009
  __mach_port_destroy (__mach_task_self (), ref);
Packit 6c4009
Packit 6c4009
  /* Set the owner of the process here too. */
Packit 6c4009
  __mutex_lock (&_hurd_id.lock);
Packit 6c4009
  if (!_hurd_check_ids ())
Packit 6c4009
    HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
Packit 6c4009
		   __proc_setowner (port,
Packit 6c4009
				    (_hurd_id.gen.nuids
Packit 6c4009
				     ? _hurd_id.gen.uids[0] : 0),
Packit 6c4009
				    !_hurd_id.gen.nuids));
Packit 6c4009
  __mutex_unlock (&_hurd_id.lock);
Packit 6c4009
Packit 6c4009
  (void) &reauth_proc;		/* Silence compiler warning.  */
Packit 6c4009
}
Packit 6c4009
text_set_element (_hurd_reauth_hook, reauth_proc);
Packit 6c4009

Packit 6c4009
/* Like `getenv', but safe for the signal thread to run.
Packit 6c4009
   If the environment is trashed, this will just return NULL.  */
Packit 6c4009
Packit 6c4009
const char *
Packit 6c4009
_hurdsig_getenv (const char *variable)
Packit 6c4009
{
Packit 6c4009
  if (__libc_enable_secure)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  if (_hurdsig_catch_memory_fault (__environ))
Packit 6c4009
    /* We bombed in getenv.  */
Packit 6c4009
    return NULL;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      const size_t len = strlen (variable);
Packit 6c4009
      char *value = NULL;
Packit 6c4009
      char *volatile *ep = __environ;
Packit 6c4009
      while (*ep)
Packit 6c4009
	{
Packit 6c4009
	  const char *p = *ep;
Packit 6c4009
	  _hurdsig_fault_preemptor.first = (long int) p;
Packit 6c4009
	  _hurdsig_fault_preemptor.last = VM_MAX_ADDRESS;
Packit 6c4009
	  if (! strncmp (p, variable, len) && p[len] == '=')
Packit 6c4009
	    {
Packit 6c4009
	      size_t valuelen;
Packit 6c4009
	      p += len + 1;
Packit 6c4009
	      valuelen = strlen (p);
Packit 6c4009
	      _hurdsig_fault_preemptor.last = (long int) (p + valuelen);
Packit 6c4009
	      value = malloc (++valuelen);
Packit 6c4009
	      if (value)
Packit 6c4009
		memcpy (value, p, valuelen);
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  _hurdsig_fault_preemptor.first = (long int) ++ep;
Packit 6c4009
	  _hurdsig_fault_preemptor.last = (long int) (ep + 1);
Packit 6c4009
	}
Packit 6c4009
      _hurdsig_end_catch_fault ();
Packit 6c4009
      return value;
Packit 6c4009
    }
Packit 6c4009
}