This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


* 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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]