Back to index

glibc  2.9
Classes | Defines | Functions | Variables
signal.h File Reference
#include <features.h>
#include <stddef.h>
#include <mach/mach_types.h>
#include <mach/port.h>
#include <mach/message.h>
#include <hurd/hurd_types.h>
#include <signal.h>
#include <errno.h>
#include <hurd/msg.h>
#include <cthreads.h>
#include <setjmp.h>
#include <spin-lock.h>
#include <hurd/threadvar.h>

Go to the source code of this file.

Classes

struct  hurd_signal_detail
struct  hurd_sigstate

Defines

#define __need_size_t
#define __need_NULL
#define _HURD_SIGNAL_H_EXTERN_INLINE   __extern_inline
#define HURD_CRITICAL_BEGIN   { void *__hurd_critical__ = _hurd_critical_section_lock ()
#define HURD_CRITICAL_END   _hurd_critical_section_unlock (__hurd_critical__); } while (0)
#define _SIG_CANT_MASK   (__sigmask (SIGSTOP) | __sigmask (SIGKILL))
#define HURD_MSGPORT_RPC(fetch_msgport_expr,fetch_refport_expr, dealloc_refport,rpc_expr)

Functions

struct hurd_sigstate_hurd_thread_sigstate (thread_t)
struct hurd_sigstate_hurd_self_sigstate (void) __attribute__((__const__))
_HURD_SIGNAL_H_EXTERN_INLINE void * _hurd_critical_section_lock (void)
_HURD_SIGNAL_H_EXTERN_INLINE void _hurd_critical_section_unlock (void *our_lock)
void _hurdsig_init (const int *intarray, size_t intarraysize)
void _hurdsig_fault_init (void)
void _hurd_raise_signal (struct hurd_sigstate *ss, int signo, const struct hurd_signal_detail *detail)
void _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
void _hurd_internal_post_signal (struct hurd_sigstate *ss, int signo, struct hurd_signal_detail *detail, mach_port_t reply_port, mach_msg_type_name_t reply_port_type, int untraced)
struct sigcontext_hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler, int signo, struct hurd_signal_detail *detail, int rpc_wait, struct machine_thread_all_state *state)
void _hurd_msgport_receive (void)
void _hurd_initialize_fault_recovery_state (void *state)
void _hurd_longjmp_thread_state (void *state, jmp_buf env, int value)
void _hurd_siginfo_handler (int)
error_t _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg, mach_msg_option_t option, mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_t rcv_name, mach_msg_timeout_t timeout, mach_port_t notify)

Variables

struct hurd_sigstate_hurd_sigstates
thread_t _hurd_msgport_thread
mach_port_t _hurd_msgport
thread_t _hurd_sigthread
int _hurd_core_limit
mach_msg_timeout_t _hurd_interrupted_rpc_timeout

Class Documentation

struct hurd_signal_detail

Definition at line 50 of file signal.h.

Class Members
integer_t code
error_t error
integer_t exc
integer_t exc_code
integer_t exc_subcode

Define Documentation

#define __need_NULL

Definition at line 31 of file signal.h.

#define __need_size_t

Definition at line 30 of file signal.h.

Definition at line 131 of file signal.h.

#define _SIG_CANT_MASK   (__sigmask (SIGSTOP) | __sigmask (SIGKILL))

Definition at line 312 of file signal.h.

#define HURD_CRITICAL_BEGIN   { void *__hurd_critical__ = _hurd_critical_section_lock ()

Definition at line 221 of file signal.h.

#define HURD_CRITICAL_END   _hurd_critical_section_unlock (__hurd_critical__); } while (0)

Definition at line 223 of file signal.h.

#define HURD_MSGPORT_RPC (   fetch_msgport_expr,
  fetch_refport_expr,
  dealloc_refport,
  rpc_expr 
)
Value:
({                                                                   \
    error_t __err;                                                   \
    mach_port_t msgport, refport = MACH_PORT_NULL;                          \
    do                                                               \
      {                                                                     \
       /* Get the message port.  */                                         \
       __err = (fetch_msgport_expr);                                        \
       if (__err)                                                    \
         break;                                                      \
       /* Get the reference port.  */                                       \
       __err = (fetch_refport_expr);                                        \
       if (__err)                                                    \
         {                                                           \
           /* Couldn't get it; deallocate MSGPORT and fail.  */             \
           __mach_port_deallocate (__mach_task_self (), msgport);           \
           break;                                                    \
         }                                                           \
       __err = (rpc_expr);                                           \
       __mach_port_deallocate (__mach_task_self (), msgport);               \
       if ((dealloc_refport) && refport != MACH_PORT_NULL)                  \
         __mach_port_deallocate (__mach_task_self (), refport);             \
      } while (__err == MACH_SEND_INVALID_DEST ||                           \
              __err == MIG_SERVER_DIED);                             \
    __err;                                                           \
})

Definition at line 337 of file signal.h.


Function Documentation

Definition at line 170 of file signal.h.

{
  struct hurd_sigstate **location =
    (void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE);
  struct hurd_sigstate *ss = *location;
  if (ss == NULL)
    {
      /* The thread variable is unset; this must be the first time we've
        asked for it.  In this case, the critical section flag cannot
        possible already be set.  Look up our sigstate structure the slow
        way; this locks the sigstate lock.  */
      ss = *location = _hurd_thread_sigstate (__mach_thread_self ());
      __spin_unlock (&ss->lock);
    }

  if (! __spin_try_lock (&ss->critical_section_lock))
    /* We are already in a critical section, so do nothing.  */
    return NULL;

  /* With the critical section lock held no signal handler will run.
     Return our sigstate pointer; this will be passed to
     _hurd_critical_section_unlock to unlock it.  */
  return ss;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 196 of file signal.h.

{
  if (our_lock == NULL)
    /* The critical section lock was held when we began.  Do nothing.  */
    return;
  else
    {
      /* It was us who acquired the critical section lock.  Unlock it.  */
      struct hurd_sigstate *ss = our_lock;
      sigset_t pending;
      __spin_lock (&ss->lock);
      __spin_unlock (&ss->critical_section_lock);
      pending = ss->pending & ~ss->blocked;
      __spin_unlock (&ss->lock);
      if (! __sigisemptyset (&pending))
       /* There are unblocked signals pending, which weren't
          delivered because we were in the critical section.
          Tell the signal thread to deliver them now.  */
       __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _hurd_exception2signal ( struct hurd_signal_detail detail,
int signo 
)

Definition at line 28 of file exc2signal.c.

{
  detail->error = 0;

  switch (detail->exc)
    {
    default:
      *signo = SIGIOT;
      detail->code = detail->exc;
      break;
      
    case EXC_BAD_ACCESS:
      if (detail->exc_code == KERN_PROTECTION_FAILURE)
       *signo = SIGSEGV;
      else
       *signo = SIGBUS;
      detail->code = detail->exc_subcode;
      detail->error = detail->exc_code;
      break;

    case EXC_BAD_INSTRUCTION:
      *signo = SIGILL;
      if (detail->exc_code == EXC_MIPS_II)
       detail->code = detail->exc_subcode;
      else
       detail->code = 0;
      break;
      
    case EXC_ARITHMETIC:
      switch (detail->exc_code)
       {
       case EXC_MIPS_OV:    /* integer overflow */
         *signo = SIGFPE;
         detail->code = detail->exc_subcode;
         break;

       default:
         *signo = SIGFPE;
         detail->code = 0;
         break;

       case EXC_MIPS_INT:
         /* Subcode is the fp_status word saved by the hardware.
            Give an error code corresponding to the first bit set.  */
         if (detail->exc_subcode == EXC_MIPS_FLT_UNIMP)
           *signo = SIGILL;
         else
           *signo = SIGFPE;
         detail->code = detail->exc_subcode;
         break;
       }
      break;

    case EXC_EMULATION:            
      /* 3.0 doesn't give this one, why, I don't know.  */
      *signo = SIGEMT;
      detail->code = 0;
      break;

    case EXC_SOFTWARE:
      *signo = SIGEMT;
      detail->code = 0;
      break;
      
    case EXC_BREAKPOINT:
      *signo = SIGTRAP;
      detail->code = 0;
      break;
    }
}
void _hurd_initialize_fault_recovery_state ( void *  state)

Definition at line 35 of file init-fault.c.

{
  struct mips_thread_state *ts = state;
  memset (ts, 0, sizeof (*ts));
  ts->r29 = (int) &fault_stack[sizeof (fault_stack)];
  ts->pc = (int) &faulted;
}

Here is the call graph for this function:

void _hurd_internal_post_signal ( struct hurd_sigstate ss,
int  signo,
struct hurd_signal_detail detail,
mach_port_t  reply_port,
mach_msg_type_name_t  reply_port_type,
int  untraced 
)

Here is the caller graph for this function:

error_t _hurd_intr_rpc_mach_msg ( mach_msg_header_t *  msg,
mach_msg_option_t  option,
mach_msg_size_t  send_size,
mach_msg_size_t  rcv_size,
mach_port_t  rcv_name,
mach_msg_timeout_t  timeout,
mach_port_t  notify 
)

Definition at line 34 of file intr-msg.c.

{
  error_t err;
  struct hurd_sigstate *ss;
  const mach_msg_option_t user_option = option;
  const mach_msg_timeout_t user_timeout = timeout;

  struct clobber
  {
#ifdef NDR_CHAR_ASCII
    NDR_record_t ndr;
#else
    mach_msg_type_t type;
#endif
    error_t err;
  };
  union msg
  {
    mach_msg_header_t header;
    mig_reply_header_t reply;
    struct
    {
      mach_msg_header_t header;
#ifdef NDR_CHAR_ASCII
      NDR_record_t ndr;
#else
      int type;
#endif
      int code;
    } check;
    struct
    {
      mach_msg_header_t header;
      struct clobber data;
    } request;
  };
  union msg *const m = (void *) msg;
  mach_msg_bits_t msgh_bits;
  mach_port_t remote_port;
  mach_msg_id_t msgid;
  struct clobber save_data;

  if ((option & (MACH_SEND_MSG|MACH_RCV_MSG)) != (MACH_SEND_MSG|MACH_RCV_MSG)
      || _hurd_msgport_thread == MACH_PORT_NULL)
    {
      /* Either this is not an RPC (i.e., only a send or only a receive),
        so it can't be interruptible; or, the signal thread is not set up
        yet, so we cannot do the normal signal magic.  Do a normal,
        uninterruptible mach_msg call instead.  */
      return __mach_msg (&m->header, option, send_size, rcv_size, rcv_name,
                      timeout, notify);
    }

  ss = _hurd_self_sigstate ();

  /* Save state that gets clobbered by an EINTR reply message.
     We will need to restore it if we want to retry the RPC.  */
  msgh_bits = m->header.msgh_bits;
  remote_port = m->header.msgh_remote_port;
  msgid = m->header.msgh_id;
  assert (rcv_size >= sizeof m->request);
  save_data = m->request.data;

  /* Tell the signal thread that we are doing an interruptible RPC on
     this port.  If we get a signal and should return EINTR, the signal
     thread will set this variable to MACH_PORT_NULL.  The RPC might
     return EINTR when some other thread gets a signal, in which case we
     want to restart our call.  */
  ss->intr_port = m->header.msgh_remote_port;

  /* A signal may arrive here, after intr_port is set, but before the
     mach_msg system call.  The signal handler might do an interruptible
     RPC, and clobber intr_port; then it would not be set properly when we
     actually did send the RPC, and a later signal wouldn't interrupt that
     RPC.  So, _hurd_setup_sighandler saves intr_port in the sigcontext,
     and sigreturn restores it.  */

 message:

  /* XXX
     At all points here (once SS->intr_port is set), the signal thread
     thinks we are "about to enter the syscall", and might mutate our
     return-value register.  This is bogus.
   */

  if (ss->cancel)
    {
      /* We have been cancelled.  Don't do an RPC at all.  */
      ss->intr_port = MACH_PORT_NULL;
      ss->cancel = 0;
      return EINTR;
    }

  /* Note that the signal trampoline code might modify our OPTION!  */
  err = INTR_MSG_TRAP (msg, option, send_size,
                     rcv_size, rcv_name, timeout, notify);

  switch (err)
    {
    case MACH_RCV_TIMED_OUT:
      if (user_option & MACH_RCV_TIMEOUT)
       /* The real user RPC timed out.  */
       break;
      else
       /* The operation was supposedly interrupted, but still has
          not returned.  Declare it interrupted.  */
       goto interrupted;

    case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */
      if (!(option & MACH_SEND_MSG))
       {
         /* Oh yes, it did!  Since we were not doing a message send,
            this return code cannot have come from the kernel!
            Instead, it was the signal thread mutating our state to tell
            us not to enter this RPC.  However, we are already in the receive!
            Since the signal thread thought we weren't in the RPC yet,
            it didn't do an interrupt_operation.
            XXX */
         goto retry_receive;
       }
      /* FALLTHROUGH */

      /* These are the other codes that mean a pseudo-receive modified
        the message buffer and we might need to clean up the port rights.  */
    case MACH_SEND_TIMED_OUT:
    case MACH_SEND_INVALID_NOTIFY:
#ifdef MACH_SEND_NO_NOTIFY
    case MACH_SEND_NO_NOTIFY:
#endif
#ifdef MACH_SEND_NOTIFY_IN_PROGRESS
    case MACH_SEND_NOTIFY_IN_PROGRESS:
#endif
      if (MACH_MSGH_BITS_REMOTE (msg->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND)
       {
         __mach_port_deallocate (__mach_task_self (), msg->msgh_remote_port);
         msg->msgh_bits
           = (MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
                            MACH_MSGH_BITS_LOCAL (msg->msgh_bits))
              | MACH_MSGH_BITS_OTHER (msg->msgh_bits));
       }
      if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX)
       {
#ifndef MACH_MSG_PORT_DESCRIPTOR
         /* Check for MOVE_SEND rights in the message.  These hold refs
            that we need to release in case the message is in fact never
            re-sent later.  Since it might in fact be re-sent, we turn
            these into COPY_SEND's after deallocating the extra user ref;
            the caller is responsible for still holding a ref to go with
            the original COPY_SEND right, so the resend copies it again.  */

         mach_msg_type_long_t *ty = (void *) (msg + 1);
         while ((void *) ty < (void *) msg + msg->msgh_size)
           {
             mach_msg_type_name_t name;
             mach_msg_type_size_t size;
             mach_msg_type_number_t number;

             inline void clean_ports (mach_port_t *ports, int dealloc)
              {
                mach_msg_type_number_t i;
                switch (name)
                  {
                  case MACH_MSG_TYPE_MOVE_SEND:
                    for (i = 0; i < number; i++)
                     __mach_port_deallocate (__mach_task_self (), *ports++);
                    if (ty->msgtl_header.msgt_longform)
                     ty->msgtl_name = MACH_MSG_TYPE_COPY_SEND;
                    else
                     ty->msgtl_header.msgt_name = MACH_MSG_TYPE_COPY_SEND;
                    break;
                  case MACH_MSG_TYPE_COPY_SEND:
                  case MACH_MSG_TYPE_MOVE_RECEIVE:
                    break;
                  default:
                    if (MACH_MSG_TYPE_PORT_ANY (name))
                     assert (! "unexpected port type in interruptible RPC");
                  }
                if (dealloc)
                  __vm_deallocate (__mach_task_self (),
                                 (vm_address_t) ports,
                                 number * sizeof (mach_port_t));
              }

             if (ty->msgtl_header.msgt_longform)
              {
                name = ty->msgtl_name;
                size = ty->msgtl_size;
                number = ty->msgtl_number;
                ty = (void *) ty + sizeof (mach_msg_type_long_t);
              }
             else
              {
                name = ty->msgtl_header.msgt_name;
                size = ty->msgtl_header.msgt_size;
                number = ty->msgtl_header.msgt_number;
                ty = (void *) ty + sizeof (mach_msg_type_t);
              }

             if (ty->msgtl_header.msgt_inline)
              {
                clean_ports ((void *) ty, 0);
                /* calculate length of data in bytes, rounding up */
                ty = (void *) ty + (((((number * size) + 7) >> 3)
                                   + sizeof (mach_msg_type_t) - 1)
                                  &~ (sizeof (mach_msg_type_t) - 1));
              }
             else
              {
                clean_ports (*(void **) ty,
                            ty->msgtl_header.msgt_deallocate);
                ty = (void *) ty + sizeof (void *);
              }
           }
#else  /* Untyped Mach IPC flavor. */
         mach_msg_body_t *body = (void *) (msg + 1);
         mach_msg_descriptor_t *desc = (void *) (body + 1);
         mach_msg_descriptor_t *desc_end = desc + body->msgh_descriptor_count;
         for (; desc < desc_end; ++desc)
           switch (desc->type.type)
             {
             case MACH_MSG_PORT_DESCRIPTOR:
              switch (desc->port.disposition)
                {
                case MACH_MSG_TYPE_MOVE_SEND:
                  __mach_port_deallocate (mach_task_self (),
                                       desc->port.name);
                  desc->port.disposition = MACH_MSG_TYPE_COPY_SEND;
                  break;
                case MACH_MSG_TYPE_COPY_SEND:
                case MACH_MSG_TYPE_MOVE_RECEIVE:
                  break;
                default:
                  assert (! "unexpected port type in interruptible RPC");
                }
              break;
             case MACH_MSG_OOL_DESCRIPTOR:
              if (desc->out_of_line.deallocate)
                __vm_deallocate (__mach_task_self (),
                               (vm_address_t) desc->out_of_line.address,
                               desc->out_of_line.size);
              break;
             case MACH_MSG_OOL_PORTS_DESCRIPTOR:
              switch (desc->ool_ports.disposition)
                {
                case MACH_MSG_TYPE_MOVE_SEND:
                  {
                    mach_msg_size_t i;
                    const mach_port_t *ports = desc->ool_ports.address;
                    for (i = 0; i < desc->ool_ports.count; ++i)
                     __mach_port_deallocate (__mach_task_self (), ports[i]);
                    desc->ool_ports.disposition = MACH_MSG_TYPE_COPY_SEND;
                    break;
                  }
                case MACH_MSG_TYPE_COPY_SEND:
                case MACH_MSG_TYPE_MOVE_RECEIVE:
                  break;
                default:
                  assert (! "unexpected port type in interruptible RPC");
                }
              if (desc->ool_ports.deallocate)
                __vm_deallocate (__mach_task_self (),
                               (vm_address_t) desc->ool_ports.address,
                               desc->ool_ports.count
                               * sizeof (mach_port_t));
              break;
             default:
              assert (! "unexpected descriptor type in interruptible RPC");
             }
#endif
       }
      break;

    case EINTR:
      /* Either the process was stopped and continued,
        or the server doesn't support interrupt_operation.  */
      if (ss->intr_port != MACH_PORT_NULL)
       /* If this signal was for us and it should interrupt calls, the
          signal thread will have cleared SS->intr_port.
          Since it's not cleared, the signal was for another thread,
          or SA_RESTART is set.  Restart the interrupted call.  */
       {
         /* Make sure we have a valid reply port.  The one we were using
            may have been destroyed by interruption.  */
         m->header.msgh_local_port = rcv_name = __mig_get_reply_port ();
         m->header.msgh_bits = msgh_bits;
         option = user_option;
         timeout = user_timeout;
         goto message;
       }
      /* FALLTHROUGH */

    case MACH_RCV_PORT_DIED:
      /* Server didn't respond to interrupt_operation,
        so the signal thread destroyed the reply port.  */
      /* FALLTHROUGH */

    interrupted:
      err = EINTR;

      /* The EINTR return indicates cancellation, so clear the flag.  */
      ss->cancel = 0;
      break;

    case MACH_RCV_INTERRUPTED:     /* RPC sent; no reply.  */
      option &= ~MACH_SEND_MSG;    /* Don't send again.  */
    retry_receive:
      if (ss->intr_port == MACH_PORT_NULL)
       {
         /* This signal or cancellation was for us.  We need to wait for
             the reply, but not hang forever.  */
         option |= MACH_RCV_TIMEOUT;
         /* Never decrease the user's timeout.  */
         if (!(user_option & MACH_RCV_TIMEOUT)
             || timeout > _hurd_interrupted_rpc_timeout)
           timeout = _hurd_interrupted_rpc_timeout;
       }
      else
       {
         option = user_option;
         timeout = user_timeout;
       }
      goto message;         /* Retry the receive.  */

    case MACH_MSG_SUCCESS:
      {
       /* We got a reply.  Was it EINTR?  */
#ifdef MACH_MSG_TYPE_BIT
       const union
       {
         mach_msg_type_t t;
         int i;
       } check =
         { t: { MACH_MSG_TYPE_INTEGER_T, sizeof (integer_t) * 8,
               1, TRUE, FALSE, FALSE, 0 } };
#endif

        if (m->reply.RetCode == EINTR &&
           m->header.msgh_size == sizeof m->reply &&
#ifdef MACH_MSG_TYPE_BIT
           m->check.type == check.i &&
#endif
           !(m->header.msgh_bits & MACH_MSGH_BITS_COMPLEX))
         {
           /* It is indeed EINTR.  Is the interrupt for us?  */
           if (ss->intr_port != MACH_PORT_NULL)
             {
              /* Nope; repeat the RPC.
                 XXX Resources moved? */

              assert (m->header.msgh_id == msgid + 100);

              /* We know we have a valid reply port, because we just
                 received the EINTR reply on it.  Restore it and the
                 other fields in the message header needed for send,
                 since the header now reflects receipt of the reply.  */
              m->header.msgh_local_port = rcv_name;
              m->header.msgh_remote_port = remote_port;
              m->header.msgh_id = msgid;
              m->header.msgh_bits = msgh_bits;
              /* Restore the two words clobbered by the reply data.  */
              m->request.data = save_data;

              /* Restore the original mach_msg options.
                 OPTION may have had MACH_RCV_TIMEOUT added,
                 and/or MACH_SEND_MSG removed.  */
              option = user_option;
              timeout = user_timeout;

              /* Now we are ready to repeat the original message send.  */
              goto message;
             }
           else
             /* The EINTR return indicates cancellation,
               so clear the flag.  */
             ss->cancel = 0;
         }
      }
      break;

    default:                /* Quiet -Wswitch-enum.  */
      break;
    }

  ss->intr_port = MACH_PORT_NULL;

  return err;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _hurd_longjmp_thread_state ( void *  state,
jmp_buf  env,
int  value 
)

Definition at line 26 of file longjmp-ts.c.

{
  /* Set all the registers in *STATE to the values described by ENV and
     RETVAL.  After this, setting that thread's state to STATE should be
     just like calling `longjmp (ENV, RETVAL)'.  */
  #error "Need to write sysdeps/mach/hurd/MACHINE/longjmp-ctx.c"
}

Here is the caller graph for this function:

void _hurd_msgport_receive ( void  )

Definition at line 56 of file msgportdemux.c.

{
  /* Get our own sigstate cached so we never again have to take a lock to
     fetch it.  There is much code in hurdsig.c that operates with some
     sigstate lock held, which will deadlock with _hurd_thread_sigstate.

     Furthermore, in the cthreads case this is the convenient spot
     to initialize _hurd_msgport_thread (see hurdsig.c:_hurdsig_init).  */

  _hurd_msgport_thread = _hurd_self_sigstate ()->thread;

  while (1)
    (void) __mach_msg_server (msgport_server, __vm_page_size, _hurd_msgport);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _hurd_raise_signal ( struct hurd_sigstate ss,
int  signo,
const struct hurd_signal_detail detail 
)

Definition at line 29 of file hurd-raise.c.

{
  if (ss == NULL)
    {
      ss = _hurd_self_sigstate ();
      __spin_lock (&ss->lock);
    }

  /* Mark SIGNO as pending to be delivered.  */
  __sigaddset (&ss->pending, signo);
  ss->pending_data[signo] = *detail;

  __spin_unlock (&ss->lock);

  /* Send a message to the signal thread so it will wake up and check for
     pending signals.  This is a generic "poll request" message (SIGNO==0)
     rather than delivering this signal and its detail, because we have
     already marked the signal as pending for the particular thread we
     want.  Generating the signal with an RPC might deliver it to some
     other thread.  */
  __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 135 of file signal.h.

{
  struct hurd_sigstate **location =
    (void *) __hurd_threadvar_location (_HURD_THREADVAR_SIGSTATE);
  if (*location == NULL)
    *location = _hurd_thread_sigstate (__mach_thread_self ());
  return *location;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct sigcontext* _hurd_setup_sighandler ( struct hurd_sigstate ss,
__sighandler_t  handler,
int  signo,
struct hurd_signal_detail detail,
int  rpc_wait,
struct machine_thread_all_state state 
) [read]

Definition at line 30 of file trampoline.c.

{
  __label__ trampoline, rpc_wait_trampoline, firewall;
  void *volatile sigsp;
  struct sigcontext *scp;
  struct
    {
      int signo;
      long int sigcode;
      struct sigcontext *scp;      /* Points to ctx, below.  */
      void *sigreturn_addr;
      void *sigreturn_returns_here;
      struct sigcontext *return_scp; /* Same; arg to sigreturn.  */
      struct sigcontext ctx;
      struct hurd_userlink link;
    } *stackframe;

  if (ss->context)
    {
      /* We have a previous sigcontext that sigreturn was about
        to restore when another signal arrived.  We will just base
        our setup on that.  */
      if (! _hurdsig_catch_memory_fault (ss->context))
       {
         memcpy (&state->basic, &ss->context->sc_mips_thread_state,
                sizeof (state->basic));
         memcpy (&state->exc, &ss->context->sc_mips_exc_state,
                sizeof (state->exc));
         state->set = (1 << MIPS_THREAD_STATE) | (1 << MIPS_EXC_STATE);
         if (state->exc.coproc_state & SC_COPROC_USE_FPU)
           {
             memcpy (&state->fpu, &ss->context->sc_mips_float_state,
                    sizeof (state->fpu));
             state->set |= (1 << MIPS_FLOAT_STATE);
           }
       }
    }

  if (! machine_get_basic_state (ss->thread, state))
    return NULL;

  /* Save the original SP in the gratuitous s0 ($16) slot.
     We may need to reset the SP (the `r29' slot) to avoid clobbering an
     interrupted RPC frame.  */
  state->basic.r16 = state->basic.r29;

  if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
      !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
    {
      sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
      ss->sigaltstack.ss_flags |= SS_ONSTACK;
      /* XXX need to set up base of new stack for
        per-thread variables, cthreads.  */
    }
  else
    sigsp = (char *) state->basic.r29;

  /* Push the arguments to call `trampoline' on the stack.  */
  sigsp -= sizeof (*stackframe);
  stackframe = sigsp;

  if (_hurdsig_catch_memory_fault (stackframe))
    {
      /* We got a fault trying to write the stack frame.
        We cannot set up the signal handler.
        Returning NULL tells our caller, who will nuke us with a SIGILL.  */
      return NULL;
    }
  else
    {
      int ok;

      extern void _hurdsig_longjmp_from_handler (void *, jmp_buf, int);

      /* Add a link to the thread's active-resources list.  We mark this as
        the only user of the "resource", so the cleanup function will be
        called by any longjmp which is unwinding past the signal frame.
        The cleanup function (in sigunwind.c) will make sure that all the
        appropriate cleanups done by sigreturn are taken care of.  */
      stackframe->link.cleanup = &_hurdsig_longjmp_from_handler;
      stackframe->link.cleanup_data = &stackframe->ctx;
      stackframe->link.resource.next = NULL;
      stackframe->link.resource.prevp = NULL;
      stackframe->link.thread.next = ss->active_resources;
      stackframe->link.thread.prevp = &ss->active_resources;
      if (stackframe->link.thread.next)
       stackframe->link.thread.next->thread.prevp
         = &stackframe->link.thread.next;
      ss->active_resources = &stackframe->link;

      /* Set up the arguments for the signal handler.  */
      stackframe->signo = signo;
      stackframe->sigcode = detail->code;
      stackframe->scp = stackframe->return_scp = scp = &stackframe->ctx;
      stackframe->sigreturn_addr = &__sigreturn;
      stackframe->sigreturn_returns_here = &&firewall; /* Crash on return.  */

      /* Set up the sigcontext from the current state of the thread.  */

      scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;

      /* struct sigcontext is laid out so that starting at sc_gpr
        mimics a struct mips_thread_state.  */
      memcpy (&scp->sc_mips_thread_state,
             &state->basic, sizeof (state->basic));

      /* struct sigcontext is laid out so that starting at sc_cause
        mimics a struct mips_exc_state.  */
      ok = machine_get_state (ss->thread, state, MIPS_EXC_STATE,
                           &state->exc, &scp->sc_cause,
                           sizeof (state->exc));

      if (ok && (scp->sc_coproc_used & SC_COPROC_USE_FPU))
       /* struct sigcontext is laid out so that starting at sc_fpr
          mimics a struct mips_float_state.  This state
          is only meaningful if the coprocessor was used.  */
         ok = machine_get_state (ss->thread, state, MIPS_FLOAT_STATE,
                              &state->fpu, &scp->sc_mips_float_state,
                              sizeof (state->fpu));

      _hurdsig_end_catch_fault ();

      if (! ok)
       return NULL;
    }

  /* Modify the thread state to call the trampoline code on the new stack.  */
  if (rpc_wait)
    {
      /* The signalee thread was blocked in a mach_msg_trap system call,
        still waiting for a reply.  We will have it run the special
        trampoline code which retries the message receive before running
        the signal handler.

        To do this we change the OPTION argument in its registers to
        enable only message reception, since the request message has
        already been sent.  */

      /* The system call arguments are stored in consecutive registers
        starting with a0 ($4).  */
      struct mach_msg_trap_args *args = (void *) &state->basic.r4;

      if (_hurdsig_catch_memory_fault (args))
       {
         /* Faulted accessing ARGS.  Bomb.  */
         return NULL;
       }

      assert (args->option & MACH_RCV_MSG);
      /* Disable the message-send, since it has already completed.  The
        calls we retry need only wait to receive the reply message.  */
      args->option &= ~MACH_SEND_MSG;

      /* Limit the time to receive the reply message, in case the server
        claimed that `interrupt_operation' succeeded but in fact the RPC
        is hung.  */
      args->option |= MACH_RCV_TIMEOUT;
      args->timeout = _hurd_interrupted_rpc_timeout;

      _hurdsig_end_catch_fault ();

      state->basic.pc = (int) &&rpc_wait_trampoline;
      /* The reply-receiving trampoline code runs initially on the original
        user stack.  We pass it the signal stack pointer in s4 ($20).  */
      state->basic.r29 = state->basic.r16; /* Restore mach_msg syscall SP.  */
      state->basic.r20 = (int) sigsp;
      /* After doing the message receive, the trampoline code will need to
        update the v0 ($2) value to be restored by sigreturn.  To simplify
        the assembly code, we pass the address of its slot in SCP to the
        trampoline code in s5 ($21).  */
      state->basic.r21 = (int) &scp->sc_gpr[1];
      /* We must preserve the mach_msg_trap args in a0..t2 ($4..$10).
        Pass the handler args to the trampoline code in s1..s3 ($17..$19).  */
      state->basic.r17 = signo;
      state->basic.r18 = detail->code;
      state->basic.r19 = (int) scp;
    }
  else
    {
      state->basic.pc = (int) &&trampoline;
      state->basic.r29 = (int) sigsp;
      state->basic.r4 = signo;
      state->basic.r5 = detail->code;
      state->basic.r6 = (int) scp;
    }

  /* We pass the handler function to the trampoline code in s6 ($22).  */
  state->basic.r22 = (int) handler;
  /* In the callee-saved register s0 ($16), we save the SCP value to pass
     to __sigreturn after the handler returns.  */
  state->basic.r16 = (int) scp;

  return scp;

  /* The trampoline code follows.  This is not actually executed as part of
     this function, it is just convenient to write it that way.  */

 rpc_wait_trampoline:
  /* This is the entry point when we have an RPC reply message to receive
     before running the handler.  The MACH_MSG_SEND bit has already been
     cleared in the OPTION argument in our registers.  For our convenience,
     $3 points to the sc_gpr[1] member of the sigcontext (saved v0 ($2)).  */
  asm volatile
    (".set noat; .set noreorder; .set nomacro\n"
     /* Retry the interrupted mach_msg system call.  */
#ifdef __mips64
     "dli $2, -25\n"        /* mach_msg_trap */
#else
     "li $2, -25\n"         /* mach_msg_trap */
#endif
     "syscall\n"
     /* When the sigcontext was saved, v0 was MACH_RCV_INTERRUPTED.  But
       now the message receive has completed and the original caller of
       the RPC (i.e. the code running when the signal arrived) needs to
       see the final return value of the message receive in v0.  So
       store the new v0 value into the sc_gpr[1] member of the sigcontext
       (whose address is in s5 to make this code simpler).  */
#ifdef __mips64
     "sd $2, ($21)\n"
#else
     "sw $2, ($21)\n"
#endif
     /* Since the argument registers needed to have the mach_msg_trap
       arguments, we've stored the arguments to the handler function
       in registers s1..s3 ($17..$19).  */
     "move $4, $17\n"
     "move $5, $18\n"
     "move $6, $19\n"
     /* Switch to the signal stack.  */
     "move $29, $20\n");

 trampoline:
  /* Entry point for running the handler normally.  The arguments to the
     handler function are already in the standard registers:

       a0     SIGNO
       a1     SIGCODE
       a2     SCP
     */
  asm volatile
    ("move $25, $22\n"             /* Copy s6 to t9 for MIPS ABI.  */
     "jal $25; nop\n"              /* Call the handler function.  */
     /* Call __sigreturn (SCP); this cannot return.  */
#ifdef __mips64
     "dla $1,%0\n"
#else
     "la $1,%0\n"
#endif
     "j $1\n"
     "move $4, $16"         /* Set up arg from saved SCP in delay slot.  */
     : : "i" (&__sigreturn));

  /* NOTREACHED */
  asm volatile (".set reorder; .set at; .set macro");

 firewall:
  asm volatile ("hlt: j hlt");

  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 23 of file siginfo.c.

{
  /* XXX */
  puts ("got a SIGINFO");
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 75 of file hurdsig.c.

{
  struct hurd_sigstate *ss;
  __mutex_lock (&_hurd_siglock);
  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
    if (ss->thread == thread)
       break;
  if (ss == NULL)
    {
      ss = malloc (sizeof (*ss));
      if (ss == NULL)
       __libc_fatal ("hurd: Can't allocate thread sigstate\n");
      ss->thread = thread;
      __spin_lock_init (&ss->lock);

      /* Initialize default state.  */
      __sigemptyset (&ss->blocked);
      __sigemptyset (&ss->pending);
      memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
      ss->preemptors = NULL;
      ss->suspended = MACH_PORT_NULL;
      ss->intr_port = MACH_PORT_NULL;
      ss->context = NULL;

      /* Initialize the sigaction vector from the default signal receiving
        thread's state, and its from the system defaults.  */
      if (thread == _hurd_sigthread)
       default_sigaction (ss->actions);
      else
       {
         struct hurd_sigstate *s;
         for (s = _hurd_sigstates; s != NULL; s = s->next)
           if (s->thread == _hurd_sigthread)
             break;
         if (s)
           {
             __spin_lock (&s->lock);
             memcpy (ss->actions, s->actions, sizeof (s->actions));
             __spin_unlock (&s->lock);
           }
         else
           default_sigaction (ss->actions);
       }

      ss->next = _hurd_sigstates;
      _hurd_sigstates = ss;
    }
  __mutex_unlock (&_hurd_siglock);
  return ss;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _hurdsig_fault_init ( void  )

Definition at line 168 of file hurdfault.c.

{
  error_t err;
  struct machine_thread_state state;
  mach_port_t sigexc;

  /* Allocate a port to receive signal thread exceptions.
     We will move this receive right to the proc server.  */
  err = __mach_port_allocate (__mach_task_self (),
                           MACH_PORT_RIGHT_RECEIVE, &sigexc);
  assert_perror (err);
  err = __mach_port_allocate (__mach_task_self (),
                           MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
  assert_perror (err);

  /* Allocate a port to receive the exception msgs forwarded
     from the proc server.  */
  err = __mach_port_insert_right (__mach_task_self (), sigexc,
                              sigexc, MACH_MSG_TYPE_MAKE_SEND);
  assert_perror (err);

  /* Set the queue limit for this port to just one.  The proc server will
     notice if we ever get a second exception while one remains queued and
     unreceived, and decide we are hopelessly buggy.  */
#ifdef MACH_PORT_RECEIVE_STATUS_COUNT
  {
    const mach_port_limits_t lim = { mpl_qlimit: 1 };
    assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
    err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
                                  MACH_PORT_RECEIVE_STATUS,
                                  (mach_port_info_t) &lim,
                                  MACH_PORT_RECEIVE_STATUS_COUNT);
  }
#else
  err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
#endif
  assert_perror (err);

  /* This state will be restored when we fault.
     It runs the function above.  */
  memset (&state, 0, sizeof state);
  MACHINE_THREAD_STATE_SET_PC (&state, faulted);
  MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);

  err = __USEPORT
    (PROC,
     __proc_handle_exceptions (port,
                            sigexc,
                            forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
                            MACHINE_THREAD_STATE_FLAVOR,
                            (natural_t *) &state,
                            MACHINE_THREAD_STATE_COUNT));
  assert_perror (err);

  /* Direct signal thread exceptions to the proc server.  */
#ifdef THREAD_EXCEPTION_PORT
  err = __thread_set_special_port (_hurd_msgport_thread,
                               THREAD_EXCEPTION_PORT, sigexc);
#elif defined (EXC_MASK_ALL)
  __thread_set_exception_ports (_hurd_msgport_thread,
                            EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
                                           | EXC_MASK_MACH_SYSCALL
                                           | EXC_MASK_RPC_ALERT),
                            sigexc,
                            EXCEPTION_STATE_IDENTITY,
                            MACHINE_THREAD_STATE);
#else
# error thread_set_exception_ports?
#endif
  __mach_port_deallocate (__mach_task_self (), sigexc);
  assert_perror (err);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _hurdsig_init ( const int intarray,
size_t  intarraysize 
)

Definition at line 1216 of file hurdsig.c.

{
  error_t err;
  vm_size_t stacksize;
  struct hurd_sigstate *ss;

  __mutex_init (&_hurd_siglock);

  err = __mach_port_allocate (__mach_task_self (),
                           MACH_PORT_RIGHT_RECEIVE,
                           &_hurd_msgport);
  assert_perror (err);

  /* Make a send right to the signal port.  */
  err = __mach_port_insert_right (__mach_task_self (),
                              _hurd_msgport,
                              _hurd_msgport,
                              MACH_MSG_TYPE_MAKE_SEND);
  assert_perror (err);

  /* Initialize the main thread's signal state.  */
  ss = _hurd_self_sigstate ();

  /* Copy inherited values from our parent (or pre-exec process state)
     into the signal settings of the main thread.  */
  if (intarraysize > INIT_SIGMASK)
    ss->blocked = intarray[INIT_SIGMASK];
  if (intarraysize > INIT_SIGPENDING)
    ss->pending = intarray[INIT_SIGPENDING];
  if (intarraysize > INIT_SIGIGN && intarray[INIT_SIGIGN] != 0)
    {
      int signo;
      for (signo = 1; signo < NSIG; ++signo)
       if (intarray[INIT_SIGIGN] & __sigmask(signo))
         ss->actions[signo].sa_handler = SIG_IGN;
    }

  /* Set the default thread to receive task-global signals
     to this one, the main (first) user thread.  */
  _hurd_sigthread = ss->thread;

  /* Start the signal thread listening on the message port.  */

  if (__hurd_threadvar_stack_mask == 0)
    {
      err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
      assert_perror (err);

      stacksize = __vm_page_size * 8; /* Small stack for signal thread.  */
      err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
                             _hurd_msgport_receive,
                             (vm_address_t *) &__hurd_sigthread_stack_base,
                             &stacksize);
      assert_perror (err);

      __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
      __hurd_sigthread_variables =
       malloc (__hurd_threadvar_max * sizeof (unsigned long int));
      if (__hurd_sigthread_variables == NULL)
       __libc_fatal ("hurd: Can't allocate threadvars for signal thread\n");
      memset (__hurd_sigthread_variables, 0,
             __hurd_threadvar_max * sizeof (unsigned long int));
      __hurd_sigthread_variables[_HURD_THREADVAR_LOCALE]
       = (unsigned long int) &_nl_global_locale;

      /* Reinitialize the MiG support routines so they will use a per-thread
        variable for the cached reply port.  */
      __mig_init ((void *) __hurd_sigthread_stack_base);

      err = __thread_resume (_hurd_msgport_thread);
      assert_perror (err);
    }
  else
    {
      /* When cthreads is being used, we need to make the signal thread a
         proper cthread.  Otherwise it cannot use mutex_lock et al, which
         will be the cthreads versions.  Various of the message port RPC
         handlers need to take locks, so we need to be able to call into
         cthreads code and meet its assumptions about how our thread and
         its stack are arranged.  Since cthreads puts it there anyway,
         we'll let the signal thread's per-thread variables be found as for
         any normal cthread, and just leave the magic __hurd_sigthread_*
         values all zero so they'll be ignored.  */
#pragma weak cthread_fork
#pragma weak cthread_detach
      cthread_detach (cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0));

      /* XXX We need the thread port for the signal thread further on
         in this thread (see hurdfault.c:_hurdsigfault_init).
         Therefore we block until _hurd_msgport_thread is initialized
         by the newly created thread.  This really shouldn't be
         necessary; we should be able to fetch the thread port for a
         cthread from here.  */
      while (_hurd_msgport_thread == 0)
       __swtch_pri (0);
    }

  /* Receive exceptions on the signal port.  */
#ifdef TASK_EXCEPTION_PORT
  __task_set_special_port (__mach_task_self (),
                        TASK_EXCEPTION_PORT, _hurd_msgport);
#elif defined (EXC_MASK_ALL)
  __task_set_exception_ports (__mach_task_self (),
                           EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
                                          | EXC_MASK_MACH_SYSCALL
                                          | EXC_MASK_RPC_ALERT),
                           _hurd_msgport,
                           EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
#else
# error task_set_exception_port?
#endif

  /* Sanity check.  Any pending, unblocked signals should have been
     taken by our predecessor incarnation (i.e. parent or pre-exec state)
     before packing up our init ints.  This assert is last (not above)
     so that signal handling is all set up to handle the abort.  */
  assert ((ss->pending &~ ss->blocked) == 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

mach_msg_timeout_t _hurd_interrupted_rpc_timeout

Definition at line 59 of file hurdsig.c.

mach_port_t _hurd_msgport

Definition at line 42 of file hurdsig.c.

Definition at line 45 of file hurdsig.c.

Definition at line 56 of file hurdsig.c.

Definition at line 48 of file hurdsig.c.