Blame hurd/hurdsig.c

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