kernel - Fix issue revealed by new yield code master
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 14 Sep 2013 09:08:18 +0000 (02:08 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 14 Sep 2013 09:08:18 +0000 (02:08 -0700)
* Make sure the current lwp is released from the scheduler in all cases.
  There were a few race cases where it would not be released.

* Reorder the yield code a little.

sys/kern/kern_exit.c
sys/kern/usched_dfly.c

index bd9d7c6..cd1b48b 100644 (file)
@@ -556,12 +556,6 @@ exit1(int rv)
         */
        plimit_free(p);
 
-       /*
-        * Release the current user process designation on the process so
-        * the userland scheduler can work in someone else.
-        */
-       p->p_usched->release_curproc(lp);
-
        /*
         * Finally, call machine-dependent code to release as many of the
         * lwp's resources as we can and halt execution of this thread.
@@ -582,6 +576,12 @@ lwp_exit(int masterexit)
        struct proc *p = lp->lwp_proc;
        int dowake = 0;
 
+       /*
+        * Release the current user process designation on the process so
+        * the userland scheduler can work in someone else.
+        */
+       p->p_usched->release_curproc(lp);
+
        /*
         * lwp_exit() may be called without setting LWP_MP_WEXIT, so
         * make sure it is set here.
index e917fcf..d091052 100644 (file)
@@ -384,9 +384,6 @@ dfly_acquire_curproc(struct lwp *lp)
                if (lp->lwp_thread->td_mpflags & TDF_MP_DIDYIELD) {
                        u_int32_t tsqbits;
 
-                       atomic_clear_int(&lp->lwp_thread->td_mpflags,
-                                        TDF_MP_DIDYIELD);
-
                        switch(lp->lwp_rqtype) {
                        case RTP_PRIO_NORMAL:
                                tsqbits = dd->queuebits;
@@ -402,6 +399,8 @@ dfly_acquire_curproc(struct lwp *lp)
                        }
                        lwkt_deschedule(lp->lwp_thread);
                        dfly_setrunqueue_dd(dd, lp);
+                       atomic_clear_int(&lp->lwp_thread->td_mpflags,
+                                        TDF_MP_DIDYIELD);
                        lwkt_switch();
                        gd = mycpu;
                        dd = &dfly_pcpu[gd->gd_cpuid];
@@ -721,15 +720,14 @@ dfly_setrunqueue_dd(dfly_pcpu_t rdd, struct lwp *lp)
        } else if (rgd == mycpu) {
                /*
                 * We should interrupt the currently running thread, which
-                * is on the current cpu.
+                * is on the current cpu.  However, if DIDYIELD is set we
+                * round-robin unconditionally and do not interrupt it.
                 */
                spin_unlock(&rdd->spin);
-               if (rdd->uschedcp == NULL) {
+               if (rdd->uschedcp == NULL)
                        wakeup_mycpu(&rdd->helper_thread); /* XXX */
+               if ((lp->lwp_thread->td_mpflags & TDF_MP_DIDYIELD) == 0)
                        need_user_resched();
-               } else {
-                       need_user_resched();
-               }
        } else {
                /*
                 * We should interrupt the currently running thread, which