kernel - Fix MP race in signotify_remote()
authorMatthew Dillon <dillon@apollo.backplane.com>
Sun, 28 Nov 2010 06:27:10 +0000 (22:27 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sun, 28 Nov 2010 17:32:38 +0000 (09:32 -0800)
* In rare cases it is possible for a process to hop multiple cpus while
  a signal is trying to chase the process.  Adjust signotify_remote() to
  deal with the case.

sys/kern/kern_sig.c

index 30d4cd0..617e4cf 100644 (file)
@@ -1319,18 +1319,34 @@ lwp_signotify(struct lwp *lp)
 
 /*
  * This function is called via an IPI.  We will be in a critical section but
- * the MP lock will NOT be held.  Also note that by the time the ipi message
- * gets to us the process 'p' (arg) may no longer be scheduled or even valid.
+ * the MP lock will NOT be held.  The passed lp will be held.
+ *
+ * We must essentially repeat the code at the end of lwp_signotify(),
+ * in particular rechecking all races.  If we are still not on the
+ * correct cpu we leave the lwp ref intact and continue the chase.
+ *
+ * XXX this may still not be entirely correct, since we are checking
+ *     lwp_stat asynchronously.
  */
 static void
 signotify_remote(void *arg)
 {
        struct lwp *lp = arg;
+       thread_t td;
 
        if (lp == lwkt_preempted_proc()) {
                signotify();
-       } else {
-               struct thread *td = lp->lwp_thread;
+       } else if (lp->lwp_stat == LSRUN) {
+               /*
+                * To prevent a MP race with TDF_SINTR we must
+                * schedule the thread on the correct cpu.
+                */
+               td = lp->lwp_thread;
+               if (td->td_gd != mycpu) {
+                       lwkt_send_ipiq(td->td_gd, signotify_remote, lp);
+                       return;
+                       /* NOT REACHED */
+               }
                if (td->td_flags & TDF_SINTR)
                        lwkt_schedule(td);
        }