Rework stopping of procs.
authorSimon Schubert <corecode@dragonflybsd.org>
Mon, 12 Mar 2007 21:08:15 +0000 (21:08 +0000)
committerSimon Schubert <corecode@dragonflybsd.org>
Mon, 12 Mar 2007 21:08:15 +0000 (21:08 +0000)
Before, proc_stop() would sleep until all running lwps stopped.  This
break when a stop signal is actually coming from the console and is
executed in the context of the idle thread.

Now we count all sleeping threads as stopped and also set LWP_WSTOP to
indicate so.  These threads will stop before return to userland.
Running threads (including the current one) will eventually stop when
returning to userland and will increase p_nstopped.  The last thread
stopping will then send a signal to the parent process.

Discussed-with:  Thomas E. Spanjaard <tgen@netphreax.net>

sys/kern/kern_sig.c
sys/kern/kern_synch.c
sys/sys/proc.h
sys/vfs/procfs/procfs_ctl.c

index 71b24ad..fb5c52d 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_sig.c  8.7 (Berkeley) 4/18/94
  * $FreeBSD: src/sys/kern/kern_sig.c,v 1.72.2.17 2003/05/16 16:34:34 obrien Exp $
- * $DragonFly: src/sys/kern/kern_sig.c,v 1.75 2007/03/12 21:07:42 corecode Exp $
+ * $DragonFly: src/sys/kern/kern_sig.c,v 1.76 2007/03/12 21:08:15 corecode Exp $
  */
 
 #include "opt_ktrace.h"
@@ -1124,7 +1124,7 @@ active_process:
                 * stop it.  Lwps will stop as soon as they safely can.
                 */
                p->p_xstat = sig;
-               proc_stop(p, 1);
+               proc_stop(p);
                goto out;
        }
 
@@ -1239,19 +1239,17 @@ signotify_remote(void *arg)
 #endif
 
 void
-proc_stop(struct proc *p, int notify)
+proc_stop(struct proc *p)
 {
-       struct lwp *lp, *preempted;
-       int stopped;
+       struct lwp *lp;
 
        /* If somebody raced us, be happy with it */
        if (p->p_stat == SSTOP)
                return;
 
+       crit_enter();
        p->p_stat = SSTOP;
 
-       preempted = lwkt_preempted_proc();
-       stopped = 0;
        FOREACH_LWP_IN_PROC(lp, p) {
                switch (lp->lwp_stat) {
                case LSSTOP:
@@ -1265,33 +1263,33 @@ proc_stop(struct proc *p, int notify)
                        /*
                         * We're sleeping, but we will stop before
                         * returning to userspace, so count us
-                        * as stopped as well.  Don't increment
-                        * p_nstopped, that will happen in tstop().
+                        * as stopped as well.  We set LWP_WSTOP
+                        * to signal the lwp that it should not
+                        * increase p_nstopped when reaching tstop().
                         */
-                       ++stopped;
+                       if ((lp->lwp_flag & LWP_WSTOP) == 0) {
+                               lp->lwp_flag |= LWP_WSTOP;
+                               ++p->p_nstopped;
+                       }
                        break;
 
                case LSRUN:
-                       lwp_signotify(lp);
                        /*
-                        * No need to wait for the preempted/current
-                        * lwp.  It will stop on return to userland
-                        * later, so consider it as stopped.
+                        * We might notify ourself, but that's not
+                        * a problem.
                         */
-                       if (lp == preempted)
-                               ++stopped;
+                       lwp_signotify(lp);
                        break;
                }
        }
 
-       while (p->p_nstopped + stopped < p->p_nthreads)
-               tsleep(&p->p_nstopped, 0, "pstop", hz);
-
-       p->p_flag &= ~P_WAITED;
-       wakeup(p->p_pptr);
-       if (notify > 1 ||
-           (notify && (p->p_pptr->p_sigacts->ps_flag & PS_NOCLDSTOP) == 0))
-               ksignal(p->p_pptr, SIGCHLD);
+       if (p->p_nstopped == p->p_nthreads) {
+               p->p_flag &= ~P_WAITED;
+               wakeup(p->p_pptr);
+               if ((p->p_pptr->p_sigacts->ps_flag & PS_NOCLDSTOP) == 0)
+                       ksignal(p->p_pptr, SIGCHLD);
+       }
+       crit_exit();
 }
 
 void
@@ -1301,6 +1299,8 @@ proc_unstop(struct proc *p)
 
        if (p->p_stat != SSTOP)
                return;
+
+       crit_enter();
        p->p_stat = SACTIVE;
 
        FOREACH_LWP_IN_PROC(lp, p) {
@@ -1314,17 +1314,33 @@ proc_unstop(struct proc *p)
                                        p->p_pid, lp->lwp_tid);
                        break;
 
-               case LSSTOP:
-                       setrunnable(lp);
-                       break;
-
                case LSSLEEP:
                        /*
                         * Still sleeping.  Don't bother waking it up.
+                        * However, if this thread was counted as
+                        * stopped, undo this.
+                        *
+                        * Nevertheless we call setrunnable() so that it
+                        * will wake up in case a signal or timeout arrived
+                        * in the meantime.
                         */
+                       if (lp->lwp_flag & LWP_WSTOP) {
+                               --p->p_nstopped;
+                       } else {
+                               if (bootverbose)
+                                       kprintf("proc_unstop: lwp %d/%d sleeping, not stopped\n",
+                                               p->p_pid, lp->lwp_tid);
+                       }
+                       /* FALLTHROUGH */
+
+               case LSSTOP:
+                       setrunnable(lp);
                        break;
+
                }
+               lp->lwp_flag &= ~LWP_WSTOP;
        }
+       crit_exit();
 }
 
 static int
@@ -1579,7 +1595,7 @@ issignal(struct lwp *lp)
                         * XXX not sure if this is still true
                         */
                        p->p_xstat = sig;
-                       proc_stop(p, 2);
+                       proc_stop(p);
                        do {
                                tstop();
                        } while (!trace_req(p) && (p->p_flag & P_TRACED));
@@ -1658,7 +1674,7 @@ issignal(struct lwp *lp)
                                    prop & SA_TTYSTOP))
                                        break;  /* == ignore */
                                p->p_xstat = sig;
-                               proc_stop(p, 1);
+                               proc_stop(p);
                                while (p->p_stat == SSTOP) {
                                        tstop();
                                }
index b2bf177..4ac931c 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_synch.c        8.9 (Berkeley) 5/19/95
  * $FreeBSD: src/sys/kern/kern_synch.c,v 1.87.2.6 2002/10/13 07:29:53 kbyanc Exp $
- * $DragonFly: src/sys/kern/kern_synch.c,v 1.81 2007/02/25 23:17:12 corecode Exp $
+ * $DragonFly: src/sys/kern/kern_synch.c,v 1.82 2007/03/12 21:08:15 corecode Exp $
  */
 
 #include "opt_ktrace.h"
@@ -948,8 +948,25 @@ tstop(void)
        lp->lwp_flag |= LWP_BREAKTSLEEP;
        lp->lwp_stat = LSSTOP;
        crit_enter();
-       p->p_nstopped++;
-       wakeup(&p->p_nstopped);         /* For the waiter in proc_stop() */
+       /*
+        * If LWP_WSTOP is set, we were sleeping
+        * while our process was stopped.  At this point
+        * we were already counted as stopped.
+        */
+       if ((lp->lwp_flag & LWP_WSTOP) == 0) {
+               /*
+                * If we're the last thread to stop, signal
+                * our parent.
+                */
+               p->p_nstopped++;
+               lp->lwp_flag |= LWP_WSTOP;
+               if (p->p_nstopped == p->p_nthreads) {
+                       p->p_flag &= ~P_WAITED;
+                       wakeup(p->p_pptr);
+                       if ((p->p_pptr->p_sigacts->ps_flag & PS_NOCLDSTOP) == 0)
+                               ksignal(p->p_pptr, SIGCHLD);
+               }
+       }
        tsleep(lp->lwp_proc, 0, "stop", 0);
        p->p_nstopped--;
        crit_exit();
index 08cda67..ec4ceef 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)proc.h      8.15 (Berkeley) 5/19/95
  * $FreeBSD: src/sys/sys/proc.h,v 1.99.2.9 2003/06/06 20:21:32 tegge Exp $
- * $DragonFly: src/sys/sys/proc.h,v 1.104 2007/03/01 01:46:53 corecode Exp $
+ * $DragonFly: src/sys/sys/proc.h,v 1.105 2007/03/12 21:08:15 corecode Exp $
  */
 
 #ifndef _SYS_PROC_H_
@@ -358,6 +358,7 @@ struct      proc {
 #define LWP_SELECT     0x0000010 /* Selecting; wakeup/waiting danger. */
 #define        LWP_ONRUNQ      0x0000020 /* on a user scheduling run queue */
 #define        LWP_WEXIT       0x0000040 /* working on exiting */
+#define        LWP_WSTOP       0x0000080 /* working on stopping */
 
 #define        FIRST_LWP_IN_PROC(p)            LIST_FIRST(&(p)->p_lwps)
 #define        FOREACH_LWP_IN_PROC(lp, p)      \
@@ -479,7 +480,7 @@ void        procinit (void);
 void   relscurproc(struct proc *curp);
 int    p_trespass (struct ucred *cr1, struct ucred *cr2);
 void   setrunnable (struct lwp *);
-void   proc_stop (struct proc *, int);
+void   proc_stop (struct proc *);
 void   proc_unstop (struct proc *);
 void   sleep_gdinit (struct globaldata *);
 int    suser (struct thread *td);
index 589c0b6..f5b260e 100644 (file)
@@ -38,7 +38,7 @@
  *
  * From:
  * $FreeBSD: src/sys/miscfs/procfs/procfs_ctl.c,v 1.20.2.2 2002/01/22 17:22:59 nectar Exp $
- * $DragonFly: src/sys/vfs/procfs/procfs_ctl.c,v 1.15 2007/02/25 23:17:13 corecode Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_ctl.c,v 1.16 2007/03/12 21:08:15 corecode Exp $
  */
 
 #include <sys/param.h>
@@ -155,7 +155,7 @@ procfs_control(struct proc *curp, struct lwp *lp, int op)
                        p->p_oppid = p->p_pptr->p_pid;
                        proc_reparent(p, curp);
                }
-               proc_stop(p, 1);
+               proc_stop(p);
                return (0);
        }