bug-hurd
[Top][All Lists]
Advanced

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

[PATCH 1/8] _hurd_internal_post_signal: Split into more functions


From: Jeremie Koenig
Subject: [PATCH 1/8] _hurd_internal_post_signal: Split into more functions
Date: Wed, 25 May 2011 17:59:27 +0200

* hurd/hurdsig.c (_hurd_internal_post_signal): Use inner functions
instead of gotos for the overall flow control.

This patch should change nothing besides replacing gotos with function
calls and return statements.

Note that the "signo == 0" test at the beginning of post_signal, is now
done on every call.  However, only the first call ever has a zero signo,
so this does not change the overall behavior.
---
 hurd/hurdsig.c |   47 +++++++++++++++++++++++++++++++++++------------
 1 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 4cb5e3c..c139805 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -455,60 +455,66 @@ weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
 
 /* Deliver a signal.  SS is not locked.  */
 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)
 {
   error_t err;
   struct machine_thread_all_state thread_state;
   enum { stop, ignore, core, term, handle } act;
   sighandler_t handler;
   sigset_t pending;
   int ss_suspended;
 
   /* Reply to this sig_post message.  */
   __typeof (__msg_sig_post_reply) *reply_rpc
     = (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply);
   void reply (void)
     {
       error_t err;
       if (reply_port == MACH_PORT_NULL)
        return;
       err = (*reply_rpc) (reply_port, reply_port_type, 0);
       reply_port = MACH_PORT_NULL;
       if (err != MACH_SEND_INVALID_DEST) /* Ignore dead reply port.  */
        assert_perror (err);
     }
 
+/* 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.   */
+int post_signal (void)
+{
+
   /* 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;
     }
 
   /* Suspend the process with SIGNO.  */
   void suspend (void)
     {
       /* Stop all other threads and mark ourselves stopped.  */
       __USEPORT (PROC,
                 ({
                   /* Hold the siglock while stopping other threads to be
                      sure it is not held by another thread afterwards.  */
                   __mutex_lock (&_hurd_siglock);
                   __proc_dostop (port, _hurd_msgport_thread);
                   __mutex_unlock (&_hurd_siglock);
                   abort_all_rpcs (signo, &thread_state, 1);
                   reply ();
                   __proc_mark_stop (port, signo, detail->code);
                 }));
       _hurd_stopped = 1;
     }
   /* Resume the process after a suspension.  */
   void resume (void)
     {
       /* Resume the process from being stopped.  */
@@ -526,65 +532,63 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       assert_perror (err);
       for (i = 0; i < nthreads; ++i)
        {
          if (threads[i] != _hurd_msgport_thread &&
              (act != handle || threads[i] != ss->thread))
            {
              err = __thread_resume (threads[i]);
              assert_perror (err);
            }
          err = __mach_port_deallocate (__mach_task_self (),
                                        threads[i]);
          assert_perror (err);
        }
       __vm_deallocate (__mach_task_self (),
                       (vm_address_t) threads,
                       nthreads * sizeof *threads);
       _hurd_stopped = 0;
       if (act == handle)
        /* The thread that will run the handler is already suspended.  */
        ss_suspended = 1;
     }
 
   if (signo == 0)
     {
       if (untraced)
        /* This is PTRACE_CONTINUE.  */
        resume ();
 
       /* This call is just to check for pending signals.  */
       __spin_lock (&ss->lock);
-      goto check_pending_signals;
+      return 1;
     }
 
- post_signal:
-
   thread_state.set = 0;                /* We know nothing.  */
 
   __spin_lock (&ss->lock);
 
   /* Check for a preempted signal.  Preempted signals can arrive during
      critical sections.  */
   {
     inline sighandler_t try_preemptor (struct hurd_signal_preemptor *pe)
       {                                /* PE cannot be null.  */
        do
          {
            if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
              {
                if (pe->preemptor)
                  {
                    sighandler_t handler = (*pe->preemptor) (pe, ss,
                                                             &signo, detail);
                    if (handler != SIG_ERR)
                      return handler;
                  }
                else
                  return pe->handler;
              }
            pe = pe->next;
          } while (pe != 0);
        return SIG_ERR;
       }
 
     handler = ss->preemptors ? try_preemptor (ss->preemptors) : SIG_ERR;
 
@@ -593,61 +597,61 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       {
        __mutex_lock (&_hurd_siglock);
        handler = try_preemptor (_hurdsig_preemptors);
        __mutex_unlock (&_hurd_siglock);
       }
   }
 
   ss_suspended = 0;
 
   if (handler == SIG_IGN)
     /* Ignore the signal altogether.  */
     act = ignore;
   else if (handler != SIG_ERR)
     /* Run the preemption-provided handler.  */
     act = handle;
   else
     {
       /* No preemption.  Do normal handling.  */
 
       if (!untraced && __sigismember (&_hurdsig_traced, signo))
        {
          /* We are being traced.  Stop to tell the debugger of the signal.  */
          if (_hurd_stopped)
            /* Already stopped.  Mark the signal as pending;
               when resumed, we will notice it and stop again.  */
            mark_pending ();
          else
            suspend ();
          __spin_unlock (&ss->lock);
          reply ();
-         return;
+         return 0;
        }
 
       handler = ss->actions[signo].sa_handler;
 
       if (handler == SIG_DFL)
        /* Figure out the default action for this signal.  */
        switch (signo)
          {
          case 0:
            /* A sig_post msg with SIGNO==0 is sent to
               tell us to check for pending signals.  */
            act = ignore;
            break;
 
          case SIGTTIN:
          case SIGTTOU:
          case SIGSTOP:
          case SIGTSTP:
            act = stop;
            break;
 
          case SIGCONT:
          case SIGIO:
          case SIGURG:
          case SIGCHLD:
          case SIGWINCH:
            act = ignore;
            break;
 
          case SIGQUIT:
@@ -935,146 +939,165 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
        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;
 
        /* 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;
       }
     }
 
-  /* The signal has either been ignored or is now being handled.  We can
-     consider it delivered and reply to the killer.  */
-  reply ();
+  return 1;
+}
 
-  /* We get here unless the signal was fatal.  We still hold SS->lock.
-     Check for pending signals, and loop to post them.  */
-  {
+/* Try to find a non-blocked pending signal and deliver it.  Called with
+   SS locked.  If a signal is delivered, return 1 and leave SS locked.
+   If the signal is traced, or if none can be found, return 0 with
+   SS unlocked.  */
+int check_pending_signal (void)
+{
     /* 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;
       }
 
-  check_pending_signals:
     untraced = 0;
 
     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);
-             goto post_signal;
+
+             return post_signal ();
            }
       }
 
     /* 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 (signo == 0)
       {
        __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)
          {
            /* 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);
          }
        __spin_unlock (&ss->lock);
       }
+
+    return 0;
   }
 
+
+  if (! post_signal ())
+    return;
+
+  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 (check_pending_signal ());
+
   /* 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.
    Returns zero if so, otherwise the error code to return to the sender.  */
 
 static error_t
 signal_allowed (int signo, mach_port_t refport)
 {
   if (signo < 0 || signo >= NSIG)
     return EINVAL;
 
   if (refport == __mach_task_self ())
     /* Can send any signal.  */
     goto win;
 
   /* Avoid needing to check for this below.  */
   if (refport == MACH_PORT_NULL)
     return EPERM;
 
   switch (signo)
     {
     case SIGINT:
     case SIGQUIT:
     case SIGTSTP:
     case SIGHUP:
     case SIGINFO:
     case SIGTTIN:
-- 
1.7.1




reply via email to

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