(_hurd_interrupted_rpc_timeout): New variable.
authorroland <roland>
Mon, 14 Aug 1995 22:04:20 +0000 (22:04 +0000)
committerroland <roland>
Mon, 14 Aug 1995 22:04:20 +0000 (22:04 +0000)
(interrupted_reply_port_location): Take new flag arg; only catch faults if
it's set.
(abort_rpcs): Rename to _hurdsig_abort_rpcs; take same new flag arg.
No longer use _hurdsig_rcv_interrupted_p; instead compare PC to
&_hurd_intr_rpc_msg_in_trap.  If before it, mutate state to simulate
MACH_SEND_INTERRUPTED return; on it, interrupt the operation.
All callers changed.

hurd/hurdsig.c

index 9414c05..7dd2b8c 100644 (file)
@@ -41,6 +41,9 @@ thread_t _hurd_sigthread;
 
 /* Linked-list of per-thread signal state.  */
 struct hurd_sigstate *_hurd_sigstates;
+
+/* Timeout for RPC's after interrupt_operation. */
+mach_msg_timeout_t _hurd_interrupted_rpc_timeout = 3000;
 \f
 static void
 default_sigaction (struct sigaction actions[NSIG])
@@ -76,9 +79,6 @@ _hurd_thread_sigstate (thread_t thread)
       __sigemptyset (&ss->pending);
       memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
       ss->suspended = 0;
-#ifdef noteven
-      __condition_init (&ss->arrived);
-#endif
       ss->intr_port = MACH_PORT_NULL;
       ss->context = NULL;
 
@@ -225,16 +225,17 @@ abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
 }
 
 /* Find the location of the MiG reply port cell in use by the thread whose
-   state is described by THREAD_STATE.  Make sure that this location can be
-   set without faulting, or else return NULL.  */
+   state is described by THREAD_STATE.  If SIGTHREAD is nonzero, make sure
+   that this location can be set without faulting, or else return NULL.  */
 
 static mach_port_t *
-interrupted_reply_port_location (struct machine_thread_all_state *thread_state)
+interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
+                                int sigthread)
 {
   mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp
     (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP);
 
-  if (_hurdsig_catch_fault (SIGSEGV))
+  if (sigthread && _hurdsig_catch_fault (SIGSEGV))
     {
       assert (_hurdsig_fault_sigcode == (long int) portloc);
       /* Faulted trying to read the stack.  */
@@ -244,7 +245,8 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state)
   /* Fault now if this pointer is bogus.  */
   *(volatile mach_port_t *) portloc = *portloc;
 
-  _hurdsig_end_catch_fault ();
+  if (sigthread)
+    _hurdsig_end_catch_fault ();
 
   return portloc;
 }
@@ -266,12 +268,14 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state)
    be applied back to the thread if it might ever run again, else zero.  */
 
 static mach_port_t
-abort_rpcs (struct hurd_sigstate *ss, int signo,
-           struct machine_thread_all_state *state, int *state_change,
-           mach_port_t *reply_port, mach_msg_type_name_t reply_port_type,
-           int untraced)
+_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,
+                    int untraced)
 {
-  mach_port_t msging_port;
+  extern const void _hurd_intr_rpc_msg_do_trap, _hurd_intr_rpc_msg_in_trap;
+  mach_port_t rcv_port = MACH_PORT_NULL;
   mach_port_t intr_port;
 
   *state_change = 0;
@@ -285,71 +289,69 @@ abort_rpcs (struct hurd_sigstate *ss, int signo,
      receive completes immediately or aborts.  */
   abort_thread (ss, state, reply_port, reply_port_type, untraced);
 
-  if (_hurdsig_rcv_interrupted_p (state, &msging_port))
+  if (state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap)
     {
-      error_t err;
-
-      /* The RPC request message was sent and the thread was waiting for
-        the reply message; now the message receive has been aborted, so
-        the mach_msg_call will return MACH_RCV_INTERRUPTED.  We must tell
-        the server to interrupt the pending operation.  The thread must
-        wait for the reply message before running the signal handler (to
-        guarantee that the operation has finished being interrupted), so
-        our nonzero return tells the trampoline code to finish the message
-        receive operation before running the handler.  */
-
-      err = __interrupt_operation (intr_port);
-
-      if (err)
-       {
-         mach_port_t *reply;
-
-         /* The interrupt didn't work.
-            Destroy the receive right the thread is blocked on.  */
-         __mach_port_destroy (__mach_task_self (), msging_port);
-
-         /* The system call return value register now contains
-            MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the
-            call.  Since we have just destroyed the receive right, the
-            retry will fail with MACH_RCV_INVALID_NAME.  Instead, just
-            change the return value here to EINTR so mach_msg will not
-            retry and the EINTR error code will propagate up.  */
-         state->basic.SYSRETURN = EINTR;
-         *state_change = 1;
-
-         /* If that was the thread's MiG reply port (which I think should
-            always be the case), clear the reply port cell so it won't be
-            reused.  */
-         reply = interrupted_reply_port_location (state);
-         if (reply != NULL && *reply == msging_port)
-           *reply = MACH_PORT_NULL;
-       }
-
-      /* All threads whose RPCs were interrupted by the interrupt_operation
-        call above will retry their RPCs unless we clear SS->intr_port.
-        So we clear it for the thread taking a signal when SA_RESTART is
-        clear, so that its call returns EINTR.  */
-      if (!(ss->actions[signo].sa_flags & SA_RESTART))
-       ss->intr_port = MACH_PORT_NULL;
-
-      return err ? MACH_PORT_NULL : msging_port;
+      /* The thread is about to do the RPC, but hasn't yet entered
+        mach_msg.  Mutate the thread's state so it knows not to try
+        the RPC.  */
+      MACHINE_THREAD_STATE_SET_PC (&state->basic,
+                                  &_hurd_intr_rpc_msg_in_trap);
+      state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;
+      *state_change = 1;
     }
+  else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap &&
+          /* The thread was blocked in the system call.  After thread_abort,
+             the return value register indicates what state the RPC was in
+             when interrupted.  */
+          state->basic.SYSRETURN == MACH_RCV_INTERRUPTED)
+      {
+       /* The RPC request message was sent and the thread was waiting for
+          the reply message; now the message receive has been aborted, so
+          the mach_msg call will return MACH_RCV_INTERRUPTED.  We must tell
+          the server to interrupt the pending operation.  The thread must
+          wait for the reply message before running the signal handler (to
+          guarantee that the operation has finished being interrupted), so
+          our nonzero return tells the trampoline code to finish the message
+          receive operation before running the handler.  */
+
+       mach_port_t *reply = interrupted_reply_port_location (state,
+                                                             sigthread);
+       error_t err = __interrupt_operation (intr_port);
+
+       if (err)
+         {
+           if (reply)
+             {
+               /* The interrupt didn't work.
+                  Destroy the receive right the thread is blocked on.  */
+               __mach_port_destroy (__mach_task_self (), *reply);
+               *reply = MACH_PORT_NULL;
+             }
 
-  /* One of the following is true:
-
-     1. The RPC has not yet been sent.  The thread will start its operation
-     after the signal has been handled.
-
-     2. The RPC has finished, but not yet cleared SS->intr_port.
-     The thread will clear SS->intr_port after running the handler.
-
-     3. The RPC request message was being sent was aborted.  The mach_msg
-     system call will return MACH_SEND_INTERRUPTED, and HURD_EINTR_RPC will
-     notice the interruption (either retrying the RPC or returning EINTR).  */
+           /* The system call return value register now contains
+              MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the
+              call.  Since we have just destroyed the receive right, the
+              retry will fail with MACH_RCV_INVALID_NAME.  Instead, just
+              change the return value here to EINTR so mach_msg will not
+              retry and the EINTR error code will propagate up.  */
+           state->basic.SYSRETURN = EINTR;
+           *state_change = 1;
+         }
+       else if (reply)
+         rcv_port = *reply;
+
+       /* All threads whose RPCs were interrupted by the interrupt_operation
+          call above will retry their RPCs unless we clear SS->intr_port.
+          So we clear it for the thread taking a signal when SA_RESTART is
+          clear, so that its call returns EINTR.  */
+       if (! signo || !(ss->actions[signo].sa_flags & SA_RESTART))
+         ss->intr_port = MACH_PORT_NULL;
+      }
 
-  return MACH_PORT_NULL;
+  return rcv_port;
 }
 
+
 /* Abort the RPCs being run by all threads but this one;
    all other threads should be suspended.  If LIVE is nonzero, those
    threads may run again, so they should be adjusted as necessary to be
@@ -387,8 +389,9 @@ abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
        /* Abort any operation in progress with interrupt_operation.
           Record the reply port the thread is waiting on.
           We will wait for all the replies below.  */
-       reply_ports[nthreads++] = abort_rpcs (ss, signo, state, &state_changed,
-                                             NULL, 0, 0);
+       reply_ports[nthreads++] = _hurdsig_abort_rpcs (ss, signo, 1,
+                                                      state, &state_changed,
+                                                      NULL, 0, 0);
        if (state_changed && live)
          /* Aborting the RPC needed to change this thread's state,
             and it might ever run again.  So write back its state.  */
@@ -403,11 +406,18 @@ abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
       {
        error_t err;
        mach_msg_header_t head;
-       err = __mach_msg (&head, MACH_RCV_MSG, 0, sizeof head,
+       err = __mach_msg (&head, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof head,
                          reply_ports[nthreads],
-                         MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-       if (err != MACH_RCV_TOO_LARGE)
-         assert_perror (err);
+                         _hurd_interrupted_rpc_timeout, MACH_PORT_NULL);
+       switch (err)
+         {
+         case MACH_RCV_TIMED_OUT:
+         case MACH_RCV_TOO_LARGE:
+           break;
+
+         default:
+           assert_perror (err);
+         }
       }
 }
 
@@ -745,7 +755,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
            
            if (! machine_get_basic_state (ss->thread, &thread_state))
              goto sigbomb;
-           loc = interrupted_reply_port_location (&thread_state);
+           loc = interrupted_reply_port_location (&thread_state, 1);
            if (loc && *loc != MACH_PORT_NULL)
              /* This is the reply port for the context which called
                 sigreturn.  Since we are abandoning that context entirely
@@ -759,11 +769,11 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
          }
        else
          {
-           wait_for_reply = (abort_rpcs (ss, signo,
-                                         &thread_state, &state_changed,
-                                         &reply_port, reply_port_type,
-                                         untraced)
-                             != MACH_PORT_NULL);
+           wait_for_reply
+             = (_hurdsig_abort_rpcs (ss, signo, 1, 
+                                     &thread_state, &state_changed,
+                                     &reply_port, reply_port_type, untraced)
+                != MACH_PORT_NULL);
 
            if (ss->critical_section)
              {
@@ -790,7 +800,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
        {
          /* Fetch the thread variable for the MiG reply port,
             and set it to MACH_PORT_NULL.  */
-         mach_port_t *loc = interrupted_reply_port_location (&thread_state);
+         mach_port_t *loc = interrupted_reply_port_location (&thread_state,
+                                                             1);
          if (loc)
            {
              scp->sc_reply_port = *loc;