bug-hurd
[Top][All Lists]
Advanced

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

[PATCH 04/15] Hurd signals: refactor check_pending_signals


From: Jeremie Koenig
Subject: [PATCH 04/15] Hurd signals: refactor check_pending_signals
Date: Wed, 29 Jun 2011 18:30:16 +0200

* hurd/hurdsig.c (check_pending_signals): Split into pending_signals,
post_pending and post_all_pending_signals.
(_hurd_internal_post_signal): Handle the distinction between poll
requests and real signals there.
---
 hurd/hurdsig.c |  134 +++++++++++++++++++++++++++++---------------------------
 1 files changed, 70 insertions(+), 64 deletions(-)

diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index e93bbfa..2715d37 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -949,74 +949,42 @@ post_signal (struct hurd_sigstate *ss,
   return 1;
 }
 
-/* Try to find a non-blocked pending signal and deliver it, testing the
-   sigstate SS first.  Called with SS locked. If a pending signal is delivered,
-   return the corresponding sigstate, locked.  Otherwise, return NULL.  */
-static struct hurd_sigstate *
-check_pending_signal (struct hurd_sigstate *ss, void (*reply) (void), int poll)
+/* 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;
-    sigset_t pending;
-
-    /* Return nonzero if SS has any signals pending we should worry about.
-       We don't worry about any pending signals if we are stopped, nor if
-       SS is in a critical section.  We are guaranteed to get a sig_post
-       message before any of them become deliverable: either the SIGCONT
-       signal, or a sig_post with SIGNO==0 as an explicit poll when the
-       thread finishes its critical section.  */
-    inline int signals_pending (void)
-      {
-       if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
-         return 0;
-       return pending = ss->pending & ~ss->blocked;
-      }
 
-    if (signals_pending ())
-      {
        for (signo = 1; signo < NSIG; ++signo)
          if (__sigismember (&pending, signo))
            {
-           deliver_pending:
              __sigdelset (&ss->pending, signo);
              detail = ss->pending_data[signo];
              __spin_unlock (&ss->lock);
 
-             if (post_signal (ss, signo, &detail, 0, reply))
-               return ss;
-             else
-               return NULL;
+             /* Will reacquire the lock, except if the signal is traced.  */
+             if (! post_signal (ss, signo, &detail, 0, reply))
+               return 0;
            }
-      }
 
-    /* No pending signals left undelivered for this thread.
-       If we were sent signal 0, we need to check for pending
-       signals for all threads.  */
-    if (poll)
-      {
-       __spin_unlock (&ss->lock);
-       __mutex_lock (&_hurd_siglock);
-       for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
-         {
-           __spin_lock (&ss->lock);
-           for (signo = 1; signo < NSIG; ++signo)
-             if (__sigismember (&ss->pending, signo)
-                 && (!__sigismember (&ss->blocked, signo)
-                     /* We "deliver" immediately pending blocked signals whose
-                        action might be to ignore, so that if ignored they are
-                        dropped right away.  */
-                     || ss->actions[signo].sa_handler == SIG_IGN
-                     || ss->actions[signo].sa_handler == SIG_DFL))
-               {
-                 mutex_unlock (&_hurd_siglock);
-                 goto deliver_pending;
-               }
-           __spin_unlock (&ss->lock);
-         }
-       __mutex_unlock (&_hurd_siglock);
-      }
-    else
-      {
        /* No more signals pending; SS->lock is still locked.
           Wake up any sigsuspend call that is blocking SS->thread.  */
        if (ss->suspended != MACH_PORT_NULL)
@@ -1036,9 +1004,39 @@ check_pending_signal (struct hurd_sigstate *ss, void 
(*reply) (void), int poll)
            assert_perror (err);
          }
        __spin_unlock (&ss->lock);
-      }
 
-    return NULL;
+    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)
+       return 1;
+      if (! post_pending (ss, pending, reply))
+       return 0;
+    }
 }
 
 /* Deliver a signal.  SS is not locked.  */
@@ -1066,20 +1064,28 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
   if (! post_signal (ss, signo, detail, untraced, reply))
     return;
 
+  /* The signal was neither fatal nor traced.  We still hold SS->lock.  */
   if (signo != 0)
     {
       /* The signal has either been ignored or is now being handled.  We can
         consider it delivered and reply to the killer.  */
       reply ();
-    }
 
-  /* We get here unless the signal was fatal.  We still hold SS->lock.
-     Check for pending signals, and loop to post them.  */
-  while (ss = check_pending_signal (ss, reply, signo == 0));
+      /* Post any pending signals for this thread.  */
+      if (! post_pending (ss, pending_signals (ss), reply))
+       return;
+    }
+  else
+    {
+      /* We need to check for pending signals for all threads.  */
+      __spin_unlock (&ss->lock);
+      if (! post_all_pending_signals (reply))
+       return;
 
-  /* All pending signals delivered to all threads.
-     Now we can send the reply message even for signal 0.  */
-  reply ();
+      /* All pending signals delivered to all threads.
+        Now we can send the reply message even for signal 0.  */
+      reply ();
+    }
 }
 
 /* Decide whether REFPORT enables the sender to send us a SIGNO signal.
-- 
1.7.5.3




reply via email to

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