summary refs log tree commit diff
path: root/hurd/hurdsig.c
diff options
context:
space:
mode:
Diffstat (limited to 'hurd/hurdsig.c')
-rw-r--r--hurd/hurdsig.c112
1 files changed, 65 insertions, 47 deletions
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 7affb906d5..68be2e9bd0 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -265,11 +265,14 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
    incoming signal, returns the reply port to be received on.  Otherwise
    returns MACH_PORT_NULL.
 
+   SIGNO is used to find the applicable SA_RESTART bit.  If SIGNO is zero,
+   the RPC fails with EINTR instead of restarting (thread_cancel).
+
    *STATE_CHANGE is set nonzero if STATE->basic was modified and should
    be applied back to the thread if it might ever run again, else zero.  */
 
 mach_port_t
-_hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread, 
+_hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
 		     struct machine_thread_all_state *state, int *state_change,
 		     mach_port_t *reply_port,
 		     mach_msg_type_name_t reply_port_type,
@@ -480,6 +483,52 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 		 }));
       _hurd_stopped = 1;
     }
+  /* Resume the process after a suspension.  */
+  void resume (void)
+    {
+      /* Resume the process from being stopped.  */
+      thread_t *threads;
+      mach_msg_type_number_t nthreads, i;
+      error_t err;
+
+      if (! _hurd_stopped)
+	return;
+
+      /* Tell the proc server we are continuing.  */
+      __USEPORT (PROC, __proc_mark_cont (port));
+      /* Fetch ports to all our threads and resume them.  */
+      err = __task_threads (__mach_task_self (), &threads, &nthreads);
+      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;
+      /* 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;
+    }
 
  post_signal:
 
@@ -514,8 +563,6 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 
       __spin_lock (&ss->lock);
 
-      handler = ss->actions[signo].sa_handler;
-
       if (!untraced && (_hurd_exec_flags & EXEC_TRACED))
 	{
 	  /* We are being traced.  Stop to tell the debugger of the signal.  */
@@ -530,6 +577,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 	  return;
 	}
 
+      handler = ss->actions[signo].sa_handler;
+
       if (handler == SIG_DFL)
 	/* Figure out the default action for this signal.  */
 	switch (signo)
@@ -604,35 +653,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 	    ss->pending &= ~STOPSIGS;
 
 	  if (_hurd_stopped && act != stop && (untraced || signo == SIGCONT))
-	    {
-	      /* Resume the process from being stopped.  */
-	      thread_t *threads;
-	      mach_msg_type_number_t nthreads, i;
-	      error_t err;
-	      /* Tell the proc server we are continuing.  */
-	      __USEPORT (PROC, __proc_mark_cont (port));
-	      /* Fetch ports to all our threads and resume them.  */
-	      err = __task_threads (__mach_task_self (), &threads, &nthreads);
-	      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;
-	      /* The thread that will run the handler is already suspended.  */
-	      ss_suspended = 1;
-	    }
+	    resume ();
 	}
     }
 
@@ -648,10 +669,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       act = term;
     }
 
-  /* Handle receipt of a blocked signal, or any signal while stopped.
-     It matters that we test ACT first here, because we must never pass
-     SIGNO==0 to __sigismember.  */
-  if ((act != ignore && __sigismember (&ss->blocked, signo)) ||
+  /* Handle receipt of a blocked signal, or any signal while stopped.  */
+  if (__sigismember (&ss->blocked, signo) ||
       (signo != SIGKILL && _hurd_stopped))
     {
       mark_pending ();
@@ -754,7 +773,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 		ss->context = &ocontext;
 	      }
 	    _hurdsig_end_catch_fault ();
-	    
+
 	    if (! machine_get_basic_state (ss->thread, &thread_state))
 	      goto sigbomb;
 	    loc = interrupted_reply_port_location (&thread_state, 1);
@@ -772,7 +791,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 	else
 	  {
 	    wait_for_reply
-	      = (_hurdsig_abort_rpcs (ss, signo, 1, 
+	      = (_hurdsig_abort_rpcs (ss, signo, 1,
 				      &thread_state, &state_changed,
 				      &reply_port, reply_port_type, untraced)
 		 != MACH_PORT_NULL);
@@ -851,12 +870,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
     }
 
   /* The signal has either been ignored or is now being handled.  We can
-     consider it delivered and reply to the killer.  The exception is
-     signal 0, which can be sent by a user thread to make us check for
-     pending signals.  In that case we want to deliver the pending signals
-     before replying.  */
-  if (signo != 0)
-    reply ();
+     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.  */
@@ -874,6 +889,9 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 	return pending = ss->pending & ~ss->blocked;
       }
 
+  check_pending_signals:
+    untraced = 0;
+
     if (signals_pending ())
       {
       pending:
@@ -974,7 +992,7 @@ signal_allowed (int signo, mach_port_t refport)
 	/* A continue signal can be sent by anyone in the session.  */
 	mach_port_t sessport;
 	if (! __USEPORT (PROC, __proc_getsidport (port, &sessport)))
-	  { 
+	  {
 	    __mach_port_deallocate (__mach_task_self (), sessport);
 	    if (refport == sessport)
 	      goto win;
@@ -1099,7 +1117,7 @@ _hurdsig_init (void)
 				  MACH_PORT_RIGHT_RECEIVE,
 				  &_hurd_msgport))
     __libc_fatal ("hurd: Can't create message port receive right\n");
-  
+
   /* Make a send right to the signal port.  */
   if (err = __mach_port_insert_right (__mach_task_self (),
 				      _hurd_msgport,
@@ -1135,7 +1153,7 @@ _hurdsig_init (void)
 
   if (err = __thread_resume (_hurd_msgport_thread))
     __libc_fatal ("hurd: Can't resume signal thread\n");
-    
+
 #if 0				/* Don't confuse poor gdb.  */
   /* Receive exceptions on the signal port.  */
   __task_set_special_port (__mach_task_self (),