summary refs log tree commit diff
path: root/hurd
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1996-07-05 23:47:08 +0000
committerRoland McGrath <roland@gnu.org>1996-07-05 23:47:08 +0000
commite33b438a8456aecf60a661ee75ac5977a7b49815 (patch)
tree4cb110b68bb4ddf7611aba3a5382561535c16d65 /hurd
parent39d690795a63d66c893ceecf74b910977cdfc8f1 (diff)
downloadglibc-e33b438a8456aecf60a661ee75ac5977a7b49815.tar.gz
glibc-e33b438a8456aecf60a661ee75ac5977a7b49815.tar.xz
glibc-e33b438a8456aecf60a661ee75ac5977a7b49815.zip
Fri Jul 5 12:22:51 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
	* hurd/hurdsig.c (_hurd_internal_post_signal): In case of handled
	signal during critical section doing interruptible RPC, if
	_hurdsig_abort_rpcs wants to change thread state, do thread_set_state
	before thread_resume.  If in critical section, pass 0 for SIGNO to
	_hurdsig_abort_rpcs so rpc is interrupted regardless of SA_RESTART.
Diffstat (limited to 'hurd')
-rw-r--r--hurd/hurdsig.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index a3ec24e9e6..1da3fa580d 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -802,19 +802,41 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 	  }
 	else
 	  {
+	    int crit = __spin_lock_locked (&ss->critical_section_lock);
+
 	    wait_for_reply
-	      = (_hurdsig_abort_rpcs (ss, signo, 1,
+	      = (_hurdsig_abort_rpcs (ss,
+				      /* In a critical section, any RPC
+					 should be cancelled instead of
+					 restarted, regardless of
+					 SA_RESTART, so the the entire
+					 "atomic" operation can be aborted
+					 as a unit.  */
+				      crit ? 0 : signo, 1,
 				      &thread_state, &state_changed,
 				      &reply)
 		 != MACH_PORT_NULL);
 
-	    if (__spin_lock_locked (&ss->critical_section_lock))
+	    if (crit)
 	      {
 		/* The thread is in a critical section.  Mark the signal as
 		   pending.  When it finishes the critical section, it will
 		   check for pending signals.  */
 		mark_pending ();
-		assert (! state_changed);
+		if (state_changed)
+		  /* Some cases of interrupting an RPC must change the
+		     thread state to back out the call.  Normally this
+		     change is rolled into the warping to the handler and
+		     sigreturn, but we are not running the handler now
+		     because the thread is in a critical section.  Instead,
+		     mutate the thread right away for the RPC interruption
+		     and resume it; the RPC will return early so the
+		     critical section can end soon.  */
+		  __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
+				      (natural_t *) &thread_state.basic,
+				      MACHINE_THREAD_STATE_COUNT);
+		/* */
+		ss->intr_port = MACH_PORT_NULL;
 		__thread_resume (ss->thread);
 		break;
 	      }