kernel - Fix alarm() timer race against exit
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 8 Dec 2011 02:44:15 +0000 (18:44 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 8 Dec 2011 02:44:15 +0000 (18:44 -0800)
* Stop the callout synchronously to ensure that any pending alarm timeout
  is completely removed before we allow a process to exit.

* Add a required PHOLD() to the relaitexpire() function.

sys/kern/kern_exit.c
sys/kern/kern_time.c
sys/kern/kern_timeout.c

index df1114c..f3ffb2b 100644 (file)
@@ -351,7 +351,7 @@ exit1(int rv)
        SIGEMPTYSET(p->p_siglist);
        SIGEMPTYSET(lp->lwp_siglist);
        if (timevalisset(&p->p_realtimer.it_value))
-               callout_stop(&p->p_ithandle);
+               callout_stop_sync(&p->p_ithandle);
 
        /*
         * Reset any sigio structures pointing to us as a result of
index 3058bf0..271abcc 100644 (file)
@@ -759,7 +759,7 @@ sys_setitimer(struct setitimer_args *uap)
        lwkt_gettoken(&p->p_token);
        if (uap->which == ITIMER_REAL) {
                if (timevalisset(&p->p_realtimer.it_value))
-                       callout_stop(&p->p_ithandle);
+                       callout_stop_sync(&p->p_ithandle);
                if (timevalisset(&aitv.it_value)) 
                        callout_reset(&p->p_ithandle,
                            tvtohz_high(&aitv.it_value), realitexpire, p);
@@ -800,12 +800,12 @@ realitexpire(void *arg)
        struct timeval ctv, ntv;
 
        p = (struct proc *)arg;
+       PHOLD(p);
        lwkt_gettoken(&p->p_token);
        ksignal(p, SIGALRM);
        if (!timevalisset(&p->p_realtimer.it_interval)) {
                timevalclear(&p->p_realtimer.it_value);
-               lwkt_reltoken(&p->p_token);
-               return;
+               goto done;
        }
        for (;;) {
                timevaladd(&p->p_realtimer.it_value,
@@ -816,11 +816,12 @@ realitexpire(void *arg)
                        timevalsub(&ntv, &ctv);
                        callout_reset(&p->p_ithandle, tvtohz_low(&ntv),
                                      realitexpire, p);
-                       lwkt_reltoken(&p->p_token);
-                       return;
+                       goto done;
                }
        }
+done:
        lwkt_reltoken(&p->p_token);
+       PRELE(p);
 }
 
 /*
index 728b9a9..8daf221 100644 (file)
@@ -502,14 +502,20 @@ callout_stop_sync(struct callout *c)
        if (c->c_flags & CALLOUT_DID_INIT) {
                callout_stop(c);
 #ifdef SMP
-               sc = &softclock_pcpu_ary[c->c_gd->gd_cpuid];
+               if (c->c_gd) {
+                       sc = &softclock_pcpu_ary[c->c_gd->gd_cpuid];
+                       if (sc->running == c) {
+                               while (sc->running == c)
+                                       tsleep(&sc->running, 0, "crace", 1);
+                       }
+               }
 #else
                sc = &softclock_pcpu_ary[0];
-#endif
                if (sc->running == c) {
                        while (sc->running == c)
                                tsleep(&sc->running, 0, "crace", 1);
                }
+#endif
                KKASSERT((c->c_flags & (CALLOUT_PENDING|CALLOUT_ACTIVE)) == 0);
        }
 }