kernel - Fix cumulative nprocs bug
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 26 Oct 2011 18:13:56 +0000 (11:13 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 26 Oct 2011 18:13:56 +0000 (11:13 -0700)
* nprocs requires atomic ops now that the related code is MPSAFE.

* Fixes issue reported w/pkgbox64 of the machine running out of processes
  unexpectedly.

* Also move a wakeup() to outside p->p_token to improve concurrency and
  other minor adjustments.

sys/kern/kern_exit.c
sys/kern/kern_fork.c

index 26174ab..f391658 100644 (file)
@@ -588,6 +588,7 @@ lwp_exit(int masterexit)
        struct thread *td = curthread;
        struct lwp *lp = td->td_lwp;
        struct proc *p = lp->lwp_proc;
+       int dowake = 0;
 
        /*
         * lwp_exit() may be called without setting LWP_WEXIT, so
@@ -652,7 +653,7 @@ lwp_exit(int masterexit)
                lwp_rb_tree_RB_REMOVE(&p->p_lwp_tree, lp);
                --p->p_nthreads;
                if (p->p_nthreads <= 1)
-                       wakeup(&p->p_nthreads);
+                       dowake = 1;
                lwkt_gettoken(&deadlwp_token);
                LIST_INSERT_HEAD(&deadlwp_list[mycpuid], lp, u.lwp_reap_entry);
                taskqueue_enqueue(taskqueue_thread[mycpuid],
@@ -661,14 +662,17 @@ lwp_exit(int masterexit)
        } else {
                --p->p_nthreads;
                if (p->p_nthreads <= 1)
-                       wakeup(&p->p_nthreads);
+                       dowake = 1;
        }
 
        /*
-        * Release p_token.  The mp_token may also be held and we depend on
-        * the lwkt_switch() code to clean it up.
+        * Release p_token.  Issue the wakeup() on p_nthreads if necessary,
+        * as late as possible to give us a chance to actually deschedule and
+        * switch away before another cpu core hits reaplwp().
         */
        lwkt_reltoken(&p->p_token);
+       if (dowake)
+               wakeup(&p->p_nthreads);
        cpu_lwp_exit();
 }
 
@@ -951,7 +955,7 @@ loop:
                        while (p->p_lock)
                                tsleep(p, 0, "reap4", hz);
                        kfree(p, M_PROC);
-                       nprocs--;
+                       atomic_add_int(&nprocs, -1);
                        error = 0;
                        goto done;
                }
@@ -1104,8 +1108,11 @@ reaplwps(void *context, int dummy)
 static void
 reaplwp(struct lwp *lp)
 {
-       while (lwp_wait(lp) == 0)
-               tsleep(lp, 0, "lwpreap", 1);
+       if (lwp_wait(lp) == 0) {
+               tsleep_interlock(lp, 0);
+               while (lwp_wait(lp) == 0)
+                       tsleep(lp, PINTERLOCKED, "lwpreap", 1);
+       }
        lwp_dispose(lp);
 }
 
index d563a53..4a8a16c 100644 (file)
@@ -332,11 +332,12 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
                error = EAGAIN;
                goto done;
        }
+
        /*
         * Increment the nprocs resource before blocking can occur.  There
         * are hard-limits as to the number of processes that can run.
         */
-       nprocs++;
+       atomic_add_int(&nprocs, 1);
 
        /*
         * Increment the count of procs running with this uid. Don't allow
@@ -348,7 +349,7 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
                /*
                 * Back out the process count
                 */
-               nprocs--;
+               atomic_add_int(&nprocs, -1);
                if (ppsratecheck(&lastfail, &curfail, 1))
                        kprintf("maxproc limit exceeded by uid %d, please "
                               "see tuning(7) and login.conf(5).\n", uid);
@@ -373,7 +374,7 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
 
        RB_INIT(&p2->p_lwp_tree);
        spin_init(&p2->p_spin);
-       lwkt_token_init(&p2->p_token, "iproc");
+       lwkt_token_init(&p2->p_token, "proc");
        p2->p_lasttid = -1;     /* first tid will be 0 */
 
        /*
@@ -522,7 +523,7 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
        lwkt_reltoken(&pptr->p_token);
 
        varsymset_init(&p2->p_varsymset, &p1->p_varsymset);
-       callout_init(&p2->p_ithandle);
+       callout_init_mp(&p2->p_ithandle);
 
 #ifdef KTRACE
        /*