bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 6/8] Hurd signals: make sigsuspend POSIX-conformant.


From: Jeremie Koenig
Subject: [PATCH 6/8] Hurd signals: make sigsuspend POSIX-conformant.
Date: Wed, 25 May 2011 17:59:32 +0200

* hurd/hurdsig.c (wake_sigsuspend): New function.
(post_signal): wake up sigsuspend calls in the "handle" case.
(post_signals): no longer wake up sigsuspend calls indiscriminately.
---
 hurd/hurdsig.c |   46 ++++++++++++++++++++++++++++------------------
 1 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 234da1e..b6fbb14 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -416,60 +416,84 @@ abort_all_rpcs (int signo, struct 
machine_thread_all_state *state, int live)
            if (state_changed)
              /* Aborting the RPC needed to change this thread's state,
                 and it might ever run again.  So write back its state.  */
              __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
                                  (natural_t *) &state->basic,
                                  MACHINE_THREAD_STATE_COUNT);
          }
       }
 
   /* Wait for replies from all the successfully interrupted RPCs.  */
   while (nthreads-- > 0)
     if (reply_ports[nthreads] != MACH_PORT_NULL)
       {
        error_t err;
        mach_msg_header_t head;
        err = __mach_msg (&head, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof head,
                          reply_ports[nthreads],
                          _hurd_interrupted_rpc_timeout, MACH_PORT_NULL);
        switch (err)
          {
          case MACH_RCV_TIMED_OUT:
          case MACH_RCV_TOO_LARGE:
            break;
 
          default:
            assert_perror (err);
          }
       }
 }
 
+/* Wake up any sigsuspend call that is blocking SS->thread.  SS must be
+   locked.  */
+static void
+wake_sigsuspend (struct hurd_sigstate *ss)
+{
+  error_t err;
+  mach_msg_header_t msg;
+
+  if (ss->suspended == MACH_PORT_NULL)
+    return;
+
+  /* There is a sigsuspend waiting.  Tell it to wake up.  */
+  msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
+  msg.msgh_remote_port = ss->suspended;
+  msg.msgh_local_port = MACH_PORT_NULL;
+  /* These values do not matter.  */
+  msg.msgh_id = 8675309; /* Jenny, Jenny.  */
+  ss->suspended = MACH_PORT_NULL;
+  err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
+      MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+      MACH_PORT_NULL);
+  assert_perror (err);
+}
+
 struct hurd_signal_preemptor *_hurdsig_preemptors = 0;
 sigset_t _hurdsig_preempted_set;
 
 /* XXX temporary to deal with spelling fix */
 weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
 
 /* Mask of stop signals.  */
 #define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \
                  sigmask (SIGSTOP) | sigmask (SIGTSTP))
 
 /* Actual delivery of a single signal.  Called with SS unlocked.  When
    the signal is delivered, return 1 with SS locked.  If the signal is
    being traced, return 0 with SS unlocked.   */
 static int
 post_signal (struct hurd_sigstate *ss,
             int signo, struct hurd_signal_detail *detail,
             int untraced, void (*reply) (void))
 {
   struct machine_thread_all_state thread_state;
   enum { stop, ignore, core, term, handle } act;
   int ss_suspended;
 
   /* Mark the signal as pending.  */
   void mark_pending (void)
     {
       __sigaddset (&ss->pending, signo);
       /* Save the details to be given to the handler when SIGNO is
         unblocked.  */
       ss->pending_data[signo] = *detail;
     }
@@ -906,130 +930,116 @@ post_signal (struct hurd_sigstate *ss,
            {
              /* After the handler runs we will restore to the state in
                 SS->context, not the state of the thread now.  So restore
                 that context's reply port and intr port.  */
 
              scp->sc_reply_port = ss->context->sc_reply_port;
              scp->sc_intr_port = ss->context->sc_intr_port;
 
              ss->context = NULL;
            }
        }
 
        /* Backdoor extra argument to signal handler.  */
        scp->sc_error = detail->error;
 
        /* Block requested signals while running the handler.  */
        scp->sc_mask = ss->blocked;
        __sigorset (&ss->blocked, &ss->blocked, &ss->actions[signo].sa_mask);
 
        /* Also block SIGNO unless we're asked not to.  */
        if (! (ss->actions[signo].sa_flags & (SA_RESETHAND | SA_NODEFER)))
          __sigaddset (&ss->blocked, signo);
 
        /* Reset to SIG_DFL if requested.  SIGILL and SIGTRAP cannot
            be automatically reset when delivered; the system silently
            enforces this restriction.  */
        if (ss->actions[signo].sa_flags & SA_RESETHAND
            && signo != SIGILL && signo != SIGTRAP)
          ss->actions[signo].sa_handler = SIG_DFL;
 
+       /* Any sigsuspend call must return after the handler does.  */
+       wake_sigsuspend (ss);
+
        /* Start the thread running the handler (or possibly waiting for an
           RPC reply before running the handler).  */
        err = __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
                                  (natural_t *) &thread_state.basic,
                                  MACHINE_THREAD_STATE_COUNT);
        assert_perror (err);
        err = __thread_resume (ss->thread);
        assert_perror (err);
        thread_state.set = 0;   /* Everything we know is now wrong.  */
        break;
       }
     }
 
   return 1;
 }
 
 /* Return the set of pending signals in SS which should be delivered. */
 static sigset_t
 pending_signals (struct hurd_sigstate *ss)
 {
   /* We don't worry about any pending signals if we are stopped, nor if
      SS is in a critical section.  We are guaranteed to get a sig_post
      message before any of them become deliverable: either the SIGCONT
      signal, or a sig_post with SIGNO==0 as an explicit poll when the
      thread finishes its critical section.  */
   if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
     return 0;
 
   return ss->pending & ~ss->blocked;
 }
 
 /* Post the specified pending signals in SS and return 1.  If one of
    them is traced, abort immediately and return 0.  SS must be locked on
    entry and will be unlocked in all cases.  */
 static int
 post_pending (struct hurd_sigstate *ss, sigset_t pending, void (*reply) (void))
 {
   int signo;
   struct hurd_signal_detail detail;
 
   for (signo = 1; signo < NSIG; ++signo)
     if (__sigismember (&pending, signo))
       {
        __sigdelset (&ss->pending, signo);
        detail = ss->pending_data[signo];
        __spin_unlock (&ss->lock);
 
        /* Will reacquire the lock, except if the signal is traced.  */
        if (! post_signal (ss, signo, &detail, 0, reply))
          return 0;
       }
 
-  /* No more signals pending; SS->lock is still locked.
-     Wake up any sigsuspend call that is blocking SS->thread.  */
-  if (ss->suspended != MACH_PORT_NULL)
-    {
-      /* There is a sigsuspend waiting.  Tell it to wake up.  */
-      error_t err;
-      mach_msg_header_t msg;
-      msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
-      msg.msgh_remote_port = ss->suspended;
-      msg.msgh_local_port = MACH_PORT_NULL;
-      /* These values do not matter.  */
-      msg.msgh_id = 8675309; /* Jenny, Jenny.  */
-      ss->suspended = MACH_PORT_NULL;
-      err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
-                       MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
-                       MACH_PORT_NULL);
-      assert_perror (err);
-    }
+  /* No more signals pending; SS->lock is still locked.  */
   __spin_unlock (&ss->lock);
 
   return 1;
 }
 
 /* Post all the pending signals of all threads and return 1.  If a traced
    signal is encountered, abort immediately and return 0.  */
 static int
 post_all_pending_signals (void (*reply) (void))
 {
   struct hurd_sigstate *ss;
   sigset_t pending;
 
   for (;;)
     {
       __mutex_lock (&_hurd_siglock);
       for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
         {
          __spin_lock (&ss->lock);
 
          pending = pending_signals (ss);
          if (pending)
            /* post_pending() below will unlock SS. */
            break;
 
          __spin_unlock (&ss->lock);
        }
       __mutex_unlock (&_hurd_siglock);
 
       if (! pending)
-- 
1.7.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]