Make tsleep/wakeup() MP SAFE for kernel threads and get us closer to
authorMatthew Dillon <dillon@dragonflybsd.org>
Mon, 14 Nov 2005 18:50:18 +0000 (18:50 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Mon, 14 Nov 2005 18:50:18 +0000 (18:50 +0000)
making it MP SAFE for user processes.  Currently the code is operating
under the rule that access to a thread structure requires cpu locality of
reference, and access to a proc structure requires the Big Giant Lock.  The
two are not mutually exclusive so, for example, tsleep/wakeup on a proc
needs both cpu locality of reference *AND* the BGL.  This was true with the
old tsleep/wakeup and has now been documented.

The new tsleep/wakeup algorithm is quite simple in concept.  Each cpu has its
own ident based hash table and each hash slot has a cpu mask which tells
wakeup() which cpu's might have the ident.  A wakeup iterates through all
candidate cpus simply by chaining the IPI message through them until either
all candidate cpus have been serviced, or (with wakeup_one()) the requested
number of threads have been woken up.

Other changes made in this patch set:

* The sense of P_INMEM has been reversed.  It is now P_SWAPPEDOUT.  Also,
  P_SWAPPING, P_SWAPINREQ are not longer relevant and have been removed.

* The swapping code has been cleaned up and seriously revamped.  The new
  swapin code staggers swapins to give the VM system a chance to respond
  to new conditions.  Also some lwp-related fixes were made (more
  p_rtprio vs lwp_rtprio confusion).

* As mentioned above, tsleep/wakeup have been rewritten.  The process
  p_stat no longer does crazy transitions from SSLEEP to SSTOP.  There is
  now only SSLEEP and SSTOP is synthesized from P_SWAPPEDOUT for userland
  consumpion.  Additionally, tsleep() with PCATCH will NO LONGER STOP THE
  PROCESS IN THE TSLEEP CALL.  Instead, the actual stop is deferred until
  the process tries to return to userland.  This removes all remaining cases
  where a stopped process can hold a locked kernel resource.

* A P_BREAKTSLEEP flag has been added.  This flag indicates when an event
  occurs that is allowed to break a tsleep with PCATCH.  All the weird
  undocumented setrunnable() rules have been removed and replaced with a
  very simple algorithm based on this flag.

* Since the UAREA is no longer swapped, we no longer faultin() on PHOLD().
  This also incidently fixes the 'ps' command's tendancy to try to swap
  all processes back into memory.

* speedup_syncer() no longer does hackish checks on proc0's tsleep channel
  (td_wchan).

* Userland scheduler acquisition and release has now been tightened up and
  KKASSERT's have been added (one of the bugs Stefan found was related
  to an improper lwkt_schedule() that was found by one of the new assertions).
  We also have added other assertions related to expected conditions.

* A serious race in pmap_release_free_page() has been corrected.  We
  no longer couple the object generation check with a failed
  pmap_release_free_page() call.  Instead the two conditions are checked
  independantly.  We no longer loop when pmap_release_free_page() succeeds
  (it is unclear how that could ever have worked properly).

Major testing by: Stefan Krueger <skrueger@meinberlikomm.de>

46 files changed:
bin/ps/print.c
bin/ps/ps.1
bin/ps/ps.c
sys/dev/raid/vinum/vinumdaemon.c
sys/emulation/linux/i386/linux_ptrace.c
sys/emulation/posix4/ksched.c
sys/emulation/svr4/svr4_misc.c
sys/i386/i386/db_trace.c
sys/i386/i386/pmap.c
sys/i386/i386/procfs_machdep.c
sys/i386/i386/trap.c
sys/kern/init_main.c
sys/kern/kern_exit.c
sys/kern/kern_fork.c
sys/kern/kern_proc.c
sys/kern/kern_resource.c
sys/kern/kern_sched.c
sys/kern/kern_sig.c
sys/kern/kern_synch.c
sys/kern/lwkt_thread.c
sys/kern/sys_generic.c
sys/kern/sys_process.c
sys/kern/tty.c
sys/kern/usched_bsd4.c
sys/kern/vfs_sync.c
sys/netproto/smb/smb_subr.c
sys/platform/pc32/i386/db_trace.c
sys/platform/pc32/i386/pmap.c
sys/platform/pc32/i386/procfs_machdep.c
sys/platform/pc32/i386/trap.c
sys/sys/kernel.h
sys/sys/proc.h
sys/sys/systm.h
sys/sys/thread.h
sys/vfs/procfs/procfs_ctl.c
sys/vfs/procfs/procfs_dbregs.c
sys/vfs/procfs/procfs_fpregs.c
sys/vfs/procfs/procfs_regs.c
sys/vfs/procfs/procfs_status.c
sys/vm/pmap.h
sys/vm/vm_fault.c
sys/vm/vm_glue.c
sys/vm/vm_meter.c
sys/vm/vm_pageout.c
usr.bin/systat/pigs.c
usr.bin/top/machine.c

index a93999d..80738cf 100644 (file)
@@ -32,7 +32,7 @@
  *
  * @(#)print.c 8.6 (Berkeley) 4/16/94
  * $FreeBSD: src/bin/ps/print.c,v 1.36.2.4 2002/11/30 13:00:14 tjr Exp $
- * $DragonFly: src/bin/ps/print.c,v 1.23 2005/10/08 19:46:50 corecode Exp $
+ * $DragonFly: src/bin/ps/print.c,v 1.24 2005/11/14 18:49:48 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -209,7 +209,7 @@ state(const KINFO *k, const struct varent *vent)
                *cp = '?';
        }
        cp++;
-       if (!(flag & P_INMEM))
+       if (flag & P_SWAPPEDOUT)
                *cp++ = 'W';
        if (p->p_nice < NZERO)
                *cp++ = '<';
@@ -479,7 +479,7 @@ getpcpu(const KINFO *k)
 #define        fxtofl(fixpt)   ((double)(fixpt) / fscale)
 
        /* XXX - I don't like this */
-       if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0)
+       if (p->p_swtime == 0 || (p->p_flag & P_SWAPPEDOUT))
                return (0.0);
        if (rawcpu)
                return (100.0 * fxtofl(p->p_pctcpu));
@@ -532,7 +532,7 @@ getpmem(const KINFO *k)
 
        p = KI_PROC(k);
        e = KI_EPROC(k);
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (0.0);
        /* XXX want pmap ptpages, segtab, etc. (per architecture) */
        szptudot = UPAGES;
index 39e2677..70c9564 100644 (file)
@@ -31,7 +31,7 @@
 .\"
 .\"     @(#)ps.1       8.3 (Berkeley) 4/18/94
 .\" $FreeBSD: src/bin/ps/ps.1,v 1.24.2.7 2002/06/20 22:43:33 charnier Exp $
-.\" $DragonFly: src/bin/ps/ps.1,v 1.6 2004/12/26 12:37:07 swildner Exp $
+.\" $DragonFly: src/bin/ps/ps.1,v 1.7 2005/11/14 18:49:48 dillon Exp $
 .\"
 .Dd April 18, 1994
 .Dt PS 1
@@ -205,7 +205,7 @@ the include file
 .Bl -column P_NOCLDSTOP P_NOCLDSTOP
 .It Dv "P_ADVLOCK" Ta No "0x00001      Process may hold a POSIX advisory lock"
 .It Dv "P_CONTROLT" Ta No "0x00002     Has a controlling terminal"
-.It Dv "P_INMEM" Ta No "0x00004                Loaded into memory"
+.It Dv "P_SWAPPEDOUT" Ta No "0x00004   Swapped out of memory"
 .It Dv "P_NOCLDSTOP" Ta No "0x00008    No SIGCHLD when children stop"
 .It Dv "P_PPWAIT" Ta No "0x00010       Parent is waiting for child to exec/exit"
 .It Dv "P_PROFIL" Ta No "0x00020       Has started profiling"
index 790aa9e..e05917d 100644 (file)
@@ -33,7 +33,7 @@
  * @(#) Copyright (c) 1990, 1993, 1994 The Regents of the University of California.  All rights reserved.
  * @(#)ps.c    8.4 (Berkeley) 4/2/94
  * $FreeBSD: src/bin/ps/ps.c,v 1.30.2.6 2002/07/04 08:30:37 sobomax Exp $
- * $DragonFly: src/bin/ps/ps.c,v 1.17 2005/10/08 19:46:50 corecode Exp $
+ * $DragonFly: src/bin/ps/ps.c,v 1.18 2005/11/14 18:49:48 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -536,7 +536,8 @@ getfmt(char **(*fn) (kvm_t *, const struct kinfo_proc *, int), KINFO *ki, char
        return (s);
 }
 
-#define UREADOK(ki)    (forceuread || (KI_PROC(ki)->p_flag & P_INMEM))
+#define UREADOK(ki)    \
+       (forceuread || (KI_PROC(ki)->p_flag & P_SWAPPEDOUT) == 0)
 
 static void
 saveuser(KINFO *ki)
@@ -545,7 +546,7 @@ saveuser(KINFO *ki)
 
        usp = &ki->ki_u;
 
-       if (KI_PROC(ki)->p_flag & P_INMEM) {
+       if ((KI_PROC(ki)->p_flag & P_SWAPPEDOUT) == 0) {
                /*
                 * The u-area might be swapped out, and we can't get
                 * at it because we have a crashdump and no swap.
index c6ad6f8..90a8398 100644 (file)
@@ -36,7 +36,7 @@
  *
  * $Id: vinumdaemon.c,v 1.8 2000/01/03 05:22:03 grog Exp grog $
  * $FreeBSD: src/sys/dev/vinum/vinumdaemon.c,v 1.16 2000/01/05 06:03:56 grog Exp $
- * $DragonFly: src/sys/dev/raid/vinum/vinumdaemon.c,v 1.5 2005/06/11 00:05:46 dillon Exp $
+ * $DragonFly: src/sys/dev/raid/vinum/vinumdaemon.c,v 1.6 2005/11/14 18:49:54 dillon Exp $
  */
 
 #include "vinumhdr.h"
@@ -69,7 +69,7 @@ vinum_daemon(void)
 {
     struct daemonq *request;
 
-    curproc->p_flag |= P_INMEM | P_SYSTEM;                 /* we're a system process */
+    curproc->p_flag |= P_SYSTEM;                   /* we're a system process */
     daemon_save_config();                                  /* start by saving the configuration */
     daemonpid = curproc->p_pid;                                    /* mark our territory */
     while (1) {
index 971b3a1..bb68b33 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/linux/linux_ptrace.c,v 1.7.4.3 2003/01/03 17:13:23 kan Exp $
- * $DragonFly: src/sys/emulation/linux/i386/linux_ptrace.c,v 1.8 2003/08/07 21:17:18 dillon Exp $
+ * $DragonFly: src/sys/emulation/linux/i386/linux_ptrace.c,v 1.9 2005/11/14 18:49:57 dillon Exp $
  */
 
 #include "opt_cpu.h"
@@ -222,7 +222,7 @@ linux_proc_read_fpxregs(struct proc *p, struct linux_pt_fpxreg *fpxregs)
        int error;
 
        error = 0;
-       if (cpu_fxsr == 0 || (p->p_flag & P_INMEM) == 0)
+       if (cpu_fxsr == 0 || (p->p_flag & P_SWAPPEDOUT))
                error = EIO;
        else
                bcopy(&p->p_thread->td_pcb->pcb_save.sv_xmm,
@@ -236,7 +236,7 @@ linux_proc_write_fpxregs(struct proc *p, struct linux_pt_fpxreg *fpxregs)
        int error;
 
        error = 0;
-       if (cpu_fxsr == 0 || (p->p_flag & P_INMEM) == 0)
+       if (cpu_fxsr == 0 || (p->p_flag & P_SWAPPEDOUT))
                error = EIO;
        else
                bcopy(fpxregs, &p->p_thread->td_pcb->pcb_save.sv_xmm,
index aef99e7..0199873 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/posix4/ksched.c,v 1.7.2.1 2000/05/16 06:58:13 dillon Exp $
- * $DragonFly: src/sys/emulation/posix4/Attic/ksched.c,v 1.5 2005/06/27 18:38:02 dillon Exp $
+ * $DragonFly: src/sys/emulation/posix4/Attic/ksched.c,v 1.6 2005/11/14 18:50:00 dillon Exp $
  */
 
 /* ksched: Soft real time scheduling based on "rtprio".
@@ -100,7 +100,7 @@ getscheduler(register_t *ret, struct ksched *ksched, struct proc *p)
 {
        int e = 0;
 
-       switch (p->p_rtprio.type)
+       switch (p->p_lwp.lwp_rtprio.type)
        {
                case RTP_PRIO_FIFO:
                *ret = SCHED_FIFO;
@@ -140,7 +140,7 @@ int ksched_setparam(register_t *ret, struct ksched *ksched,
 int ksched_getparam(register_t *ret, struct ksched *ksched,
        struct proc *p, struct sched_param *param)
 {
-       if (RTP_PRIO_IS_REALTIME(p->p_rtprio.type))
+       if (RTP_PRIO_IS_REALTIME(p->p_lwp.lwp_rtprio.type))
                param->sched_priority = rtpprio_to_p4prio(p->p_rtprio.prio);
 
        return 0;
@@ -171,7 +171,7 @@ int ksched_setscheduler(register_t *ret, struct ksched *ksched,
                        rtp.type = (policy == SCHED_FIFO)
                                ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
 
-                       p->p_rtprio = rtp;
+                       p->p_lwp.lwp_rtprio = rtp;
                        need_user_resched();
                }
                else
@@ -184,7 +184,7 @@ int ksched_setscheduler(register_t *ret, struct ksched *ksched,
                {
                        rtp.type = RTP_PRIO_NORMAL;
                        rtp.prio = p4prio_to_rtpprio(param->sched_priority);
-                       p->p_rtprio = rtp;
+                       p->p_lwp.lwp_rtprio = rtp;
 
                        /* XXX Simply revert to whatever we had for last
                         *     normal scheduler priorities.
index 147f78f..4de38e1 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * 
  * $FreeBSD: src/sys/svr4/svr4_misc.c,v 1.13.2.7 2003/01/14 21:33:58 dillon Exp $
- * $DragonFly: src/sys/emulation/svr4/Attic/svr4_misc.c,v 1.29 2005/08/27 20:23:05 joerg Exp $
+ * $DragonFly: src/sys/emulation/svr4/Attic/svr4_misc.c,v 1.30 2005/11/14 18:50:01 dillon Exp $
  */
 
 /*
@@ -1314,7 +1314,7 @@ loop:
                        nprocs--;
                        return 0;
                }
-               if (q->p_stat == SSTOP && (q->p_flag & P_WAITED) == 0 &&
+               if ((q->p_flag & P_STOPPED) && (q->p_flag & P_WAITED) == 0 &&
                    (q->p_flag & P_TRACED ||
                     (SCARG(uap, options) & (SVR4_WSTOPPED|SVR4_WCONTINUED)))) {
                        DPRINTF(("jobcontrol %d\n", q->p_pid));
index 20df584..651d455 100644 (file)
@@ -24,7 +24,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/i386/i386/db_trace.c,v 1.35.2.3 2002/02/21 22:31:25 silby Exp $
- * $DragonFly: src/sys/i386/i386/Attic/db_trace.c,v 1.10 2005/04/25 20:22:27 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/db_trace.c,v 1.11 2005/11/14 18:50:03 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -304,7 +304,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
                                db_printf("pid %d not found\n", pid);
                                return;
                        }
-                       if ((p->p_flag & P_INMEM) == 0) {
+                       if ((p->p_flag & P_SWAPPEDOUT)) {
                                db_printf("pid %d swapped out\n", pid);
                                return;
                        }
index f0cb599..1968e52 100644 (file)
@@ -40,7 +40,7 @@
  *
  *     from:   @(#)pmap.c      7.7 (Berkeley)  5/12/91
  * $FreeBSD: src/sys/i386/i386/pmap.c,v 1.250.2.18 2002/03/06 22:48:53 silby Exp $
- * $DragonFly: src/sys/i386/i386/Attic/pmap.c,v 1.52 2005/11/07 20:05:51 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/pmap.c,v 1.53 2005/11/14 18:50:03 dillon Exp $
  */
 
 /*
@@ -944,70 +944,6 @@ pmap_dispose_proc(struct proc *p)
        return(td);
 }
 
-/*
- * Allow the UPAGES for a process to be prejudicially paged out.
- */
-void
-pmap_swapout_proc(struct proc *p)
-{
-#if 0
-       int i;
-       int s;
-       vm_object_t upobj;
-       vm_page_t m;
-
-       upobj = p->p_upages_obj;
-
-       /*
-        * Unwiring the pages allow them to be paged to their backing store
-        * (swap).
-        */
-       crit_enter();
-       for (i = 0; i < UPAGES; i++) {
-               if ((m = vm_page_lookup(upobj, i)) == NULL)
-                       panic("pmap_swapout_proc: upage already missing???");
-               vm_page_dirty(m);
-               vm_page_unwire(m, 0);
-               pmap_kremove((vm_offset_t)p->p_addr + (PAGE_SIZE * i));
-       }
-       crit_exit();
-#endif
-}
-
-/*
- * Bring the UPAGES for a specified process back in.
- */
-void
-pmap_swapin_proc(struct proc *p)
-{
-#if 0
-       int i,rv;
-       vm_object_t upobj;
-       vm_page_t m;
-
-       crit_enter();
-       upobj = p->p_upages_obj;
-       for (i = 0; i < UPAGES; i++) {
-               m = vm_page_grab(upobj, i, VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
-
-               pmap_kenter((vm_offset_t)p->p_addr + (i * PAGE_SIZE),
-                       VM_PAGE_TO_PHYS(m));
-
-               if (m->valid != VM_PAGE_BITS_ALL) {
-                       rv = vm_pager_get_pages(upobj, &m, 1, 0);
-                       if (rv != VM_PAGER_OK)
-                               panic("pmap_swapin_proc: cannot get upages for proc: %d\n", p->p_pid);
-                       m = vm_page_lookup(upobj, i);
-                       m->valid = VM_PAGE_BITS_ALL;
-               }
-               vm_page_wire(m);
-               vm_page_wakeup(m);
-               vm_page_flag_set(m, PG_MAPPED | PG_WRITEABLE);
-       }
-       crit_exit();
-#endif
-}
-
 /***************************************************
  * Page table page management routines.....
  ***************************************************/
@@ -1166,6 +1102,10 @@ pmap_pinit2(struct pmap *pmap)
        bcopy(PTD + KPTDI, pmap->pm_pdir + KPTDI, nkpt * PTESIZE);
 }
 
+/*
+ * Attempt to release and free and vm_page in a pmap.  Returns 1 on success,
+ * 0 on failure (if the procedure had to sleep).
+ */
 static int
 pmap_release_free_page(struct pmap *pmap, vm_page_t p)
 {
@@ -1361,18 +1301,20 @@ retry:
                        ptdpg = p;
                        continue;
                }
-               while (1) {
-                       if (!pmap_release_free_page(pmap, p) &&
-                           (object->generation != curgeneration)) {
-                               crit_exit();
-                               goto retry;
-                       }
+               if (!pmap_release_free_page(pmap, p)) {
+                       crit_exit();
+                       goto retry;
+               }
+               if (object->generation != curgeneration) {
+                       crit_exit();
+                       goto retry;
                }
        }
-       crit_exit();
-
-       if (ptdpg && !pmap_release_free_page(pmap, ptdpg))
+       if (ptdpg && !pmap_release_free_page(pmap, ptdpg)) {
+               crit_exit();
                goto retry;
+       }
+       crit_exit();
 }
 \f
 static int
index a01b037..1d66c44 100644 (file)
@@ -38,7 +38,7 @@
  *
  * From:
  * $FreeBSD: src/sys/i386/i386/procfs_machdep.c,v 1.14 1999/10/11 14:50:03 peter Exp $
- * $DragonFly: src/sys/i386/i386/Attic/procfs_machdep.c,v 1.4 2005/10/27 03:15:47 sephe Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/procfs_machdep.c,v 1.5 2005/11/14 18:50:03 dillon Exp $
  */
 
 /*
@@ -86,7 +86,7 @@ procfs_read_regs(p, regs)
        struct proc *p;
        struct reg *regs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (fill_regs(&p->p_lwp, regs));
 }
@@ -96,7 +96,7 @@ procfs_write_regs(p, regs)
        struct proc *p;
        struct reg *regs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (set_regs(&p->p_lwp, regs));
 }
@@ -106,7 +106,7 @@ procfs_read_dbregs(p, dbregs)
        struct proc *p;
        struct dbreg *dbregs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (fill_dbregs(&p->p_lwp, dbregs));
 }
@@ -116,7 +116,7 @@ procfs_write_dbregs(p, dbregs)
        struct proc *p;
        struct dbreg *dbregs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (set_dbregs(&p->p_lwp, dbregs));
 }
@@ -131,7 +131,7 @@ procfs_read_fpregs(p, fpregs)
        struct proc *p;
        struct fpreg *fpregs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (fill_fpregs(&p->p_lwp, fpregs));
 }
@@ -141,7 +141,7 @@ procfs_write_fpregs(p, fpregs)
        struct proc *p;
        struct fpreg *fpregs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (set_fpregs(&p->p_lwp, fpregs));
 }
@@ -150,7 +150,7 @@ int
 procfs_sstep(p)
        struct proc *p;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (ptrace_single_step(&p->p_lwp));
 }
index 997a82e..e471d1c 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)trap.c        7.4 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $
- * $DragonFly: src/sys/i386/i386/Attic/trap.c,v 1.65 2005/11/04 08:57:27 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/trap.c,v 1.66 2005/11/14 18:50:03 dillon Exp $
  */
 
 /*
@@ -213,34 +213,55 @@ userret(struct lwp *lp, struct trapframe *frame, int sticks)
        struct proc *p = lp->lwp_proc;
        int sig;
 
+       /*
+        * Charge system time if profiling.  Note: times are in microseconds.
+        * This may do a copyout and block, so do it first even though it
+        * means some system time will be charged as user time.
+        */
+       if (p->p_flag & P_PROFIL) {
+               addupc_task(p, frame->tf_eip, 
+                       (u_int)((int)p->p_thread->td_sticks - sticks));
+       }
+
+recheck:
+       /*
+        * Block here if we are in a stopped state.
+        */
+       if (p->p_flag & P_STOPPED) {
+               tstop(p);
+               goto recheck;
+       }
+
        /*
         * Post any pending upcalls
         */
        if (p->p_flag & P_UPCALLPEND) {
                p->p_flag &= ~P_UPCALLPEND;
                postupcall(lp);
+               goto recheck;
        }
 
        /*
         * Post any pending signals
         */
-       while ((sig = CURSIG(p)) != 0) {
+       if ((sig = CURSIG(p)) != 0) {
                postsig(sig);
+               goto recheck;
        }
 
        /*
-        * Charge system time if profiling.  Note: times are in microseconds.
+        * block here if we are swapped out, but still process signals
+        * (such as SIGKILL).  proc0 (the swapin scheduler) is already
+        * aware of our situation, we do not have to wake it up.
         */
-       if (p->p_flag & P_PROFIL) {
-               addupc_task(p, frame->tf_eip, 
-                       (u_int)((int)p->p_thread->td_sticks - sticks));
+       if (p->p_flag & P_SWAPPEDOUT) {
+               p->p_flag |= P_SWAPWAIT;
+               swapin_request();
+               if (p->p_flag & P_SWAPWAIT)
+                       tsleep(p, PCATCH, "SWOUT", 0);
+               p->p_flag &= ~P_SWAPWAIT;
+               goto recheck;
        }
-
-       /*
-        * Post any pending signals XXX
-        */
-       while ((sig = CURSIG(p)) != 0)
-               postsig(sig);
 }
 
 /*
index 325b089..90da0c2 100644 (file)
@@ -40,7 +40,7 @@
  *
  *     @(#)init_main.c 8.9 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/init_main.c,v 1.134.2.8 2003/06/06 20:21:32 tegge Exp $
- * $DragonFly: src/sys/kern/init_main.c,v 1.50 2005/11/08 20:46:59 dillon Exp $
+ * $DragonFly: src/sys/kern/init_main.c,v 1.51 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include "opt_init_path.h"
@@ -306,7 +306,7 @@ proc0_init(void *dummy __unused)
        p->p_sysent = &aout_sysvec;
        TAILQ_INIT(&lp->lwp_sysmsgq);
 
-       p->p_flag = P_INMEM | P_SYSTEM;
+       p->p_flag = P_SYSTEM;
        p->p_stat = SRUN;
        p->p_nice = NZERO;
        p->p_rtprio.type = RTP_PRIO_NORMAL;
@@ -598,7 +598,7 @@ create_init(const void *udata __unused)
        error = fork1(&proc0.p_lwp, RFFDG | RFPROC, &initproc);
        if (error)
                panic("cannot fork init: %d", error);
-       initproc->p_flag |= P_INMEM | P_SYSTEM;
+       initproc->p_flag |= P_SYSTEM;
        cpu_set_fork_handler(initproc, start_init, NULL);
        crit_exit();
 }
index 9c1b528..06d65cf 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_exit.c 8.7 (Berkeley) 2/12/94
  * $FreeBSD: src/sys/kern/kern_exit.c,v 1.92.2.11 2003/01/13 22:51:16 dillon Exp $
- * $DragonFly: src/sys/kern/kern_exit.c,v 1.47 2005/10/11 09:59:56 corecode Exp $
+ * $DragonFly: src/sys/kern/kern_exit.c,v 1.48 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -551,7 +551,7 @@ loop:
                        nprocs--;
                        return (0);
                }
-               if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 &&
+               if ((p->p_flag & P_STOPPED) && (p->p_flag & P_WAITED) == 0 &&
                    (p->p_flag & P_TRACED || options & WUNTRACED)) {
                        p->p_flag |= P_WAITED;
 
index fc30504..7a5b1f9 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_fork.c 8.6 (Berkeley) 4/8/94
  * $FreeBSD: src/sys/kern/kern_fork.c,v 1.72.2.14 2003/06/26 04:15:10 silby Exp $
- * $DragonFly: src/sys/kern/kern_fork.c,v 1.43 2005/10/11 09:59:56 corecode Exp $
+ * $DragonFly: src/sys/kern/kern_fork.c,v 1.44 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -385,7 +385,7 @@ again:
         * Increase reference counts on shared objects.
         * The p_stats and p_sigacts substructs are set in vm_fork.
         */
-       p2->p_flag = P_INMEM;
+       p2->p_flag = 0;
        if (p1->p_flag & P_PROFIL)
                startprofclock(p2);
        p2->p_ucred = crhold(p1->p_ucred);
index 87ee1b8..1a300fe 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)kern_proc.c 8.7 (Berkeley) 2/14/95
  * $FreeBSD: src/sys/kern/kern_proc.c,v 1.63.2.9 2003/05/08 07:47:16 kbyanc Exp $
- * $DragonFly: src/sys/kern/kern_proc.c,v 1.20 2005/04/22 17:41:15 joerg Exp $
+ * $DragonFly: src/sys/kern/kern_proc.c,v 1.21 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -331,7 +331,7 @@ orphanpg(struct pgrp *pg)
        struct proc *p;
 
        LIST_FOREACH(p, &pg->pg_members, p_pglist) {
-               if (p->p_stat == SSTOP) {
+               if (p->p_flag & P_STOPPED) {
                        LIST_FOREACH(p, &pg->pg_members, p_pglist) {
                                psignal(p, SIGHUP);
                                psignal(p, SIGCONT);
@@ -426,7 +426,7 @@ fill_eproc(struct proc *p, struct eproc *ep)
                ep->e_vm = *vm;
                ep->e_vm.vm_rssize = vmspace_resident_count(vm); /*XXX*/
        }
-       if ((p->p_flag & P_INMEM) && p->p_stats)
+       if ((p->p_flag & P_SWAPPEDOUT) == 0 && p->p_stats)
                ep->e_stats = *p->p_stats;
        if (p->p_pptr)
                ep->e_ppid = p->p_pptr->p_pid;
@@ -481,16 +481,18 @@ sysctl_out_proc(struct proc *p, struct thread *td, struct sysctl_req *req, int d
                xproc = *p;
 
                /*
-                * Fixup p_stat from SRUN to SSLEEP if the LWKT thread is
-                * in a thread-blocked state.
-                *
-                * XXX temporary fix which might become permanent (I'd rather
-                * not pollute the thread scheduler with knowlege about 
-                * processes).
+                * p_stat fixup.  If we are in a thread sleep mark p_stat
+                * as sleeping if the thread is blocked.
                 */
                if (p->p_stat == SRUN && td && (td->td_flags & TDF_BLOCKED)) {
                        xproc.p_stat = SSLEEP;
                }
+               /*
+                * If the process is being stopped but is in a normal tsleep,
+                * mark it as being SSTOP.
+                */
+               if (p->p_stat == SSLEEP && (p->p_flag & P_STOPPED))
+                       xproc.p_stat = SSTOP;
        } else if (td) {
                fill_eproc_td(td, &eproc, &xproc);
        }
index f7f11e6..6676300 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_resource.c     8.5 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/kern_resource.c,v 1.55.2.5 2001/11/03 01:41:08 ps Exp $
- * $DragonFly: src/sys/kern/kern_resource.c,v 1.23 2005/10/11 09:59:56 corecode Exp $
+ * $DragonFly: src/sys/kern/kern_resource.c,v 1.24 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include "opt_compat.h"
@@ -235,7 +235,7 @@ rtprio(struct rtprio_args *uap)
 
        switch (uap->function) {
        case RTP_LOOKUP:
-               return (copyout(&p->p_rtprio, uap->rtp, sizeof(struct rtprio)));
+               return (copyout(&p->p_lwp.lwp_rtprio, uap->rtp, sizeof(struct rtprio)));
        case RTP_SET:
                if (cr->cr_uid && cr->cr_ruid &&
                    cr->cr_uid != p->p_ucred->cr_uid &&
@@ -266,7 +266,7 @@ rtprio(struct rtprio_args *uap)
                case RTP_PRIO_IDLE:
                        if (rtp.prio > RTP_PRIO_MAX)
                                return (EINVAL);
-                       p->p_rtprio = rtp;
+                       p->p_lwp.lwp_rtprio = rtp;
                        return (0);
                default:
                        return (EINVAL);
index 399ac08..8f8aed9 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/posix4/ksched.c,v 1.7.2.1 2000/05/16 06:58:13 dillon Exp $
- * $DragonFly: src/sys/kern/kern_sched.c,v 1.5 2005/06/27 18:38:02 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_sched.c,v 1.6 2005/11/14 18:50:00 dillon Exp $
  */
 
 /* ksched: Soft real time scheduling based on "rtprio".
@@ -100,7 +100,7 @@ getscheduler(register_t *ret, struct ksched *ksched, struct proc *p)
 {
        int e = 0;
 
-       switch (p->p_rtprio.type)
+       switch (p->p_lwp.lwp_rtprio.type)
        {
                case RTP_PRIO_FIFO:
                *ret = SCHED_FIFO;
@@ -140,7 +140,7 @@ int ksched_setparam(register_t *ret, struct ksched *ksched,
 int ksched_getparam(register_t *ret, struct ksched *ksched,
        struct proc *p, struct sched_param *param)
 {
-       if (RTP_PRIO_IS_REALTIME(p->p_rtprio.type))
+       if (RTP_PRIO_IS_REALTIME(p->p_lwp.lwp_rtprio.type))
                param->sched_priority = rtpprio_to_p4prio(p->p_rtprio.prio);
 
        return 0;
@@ -171,7 +171,7 @@ int ksched_setscheduler(register_t *ret, struct ksched *ksched,
                        rtp.type = (policy == SCHED_FIFO)
                                ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
 
-                       p->p_rtprio = rtp;
+                       p->p_lwp.lwp_rtprio = rtp;
                        need_user_resched();
                }
                else
@@ -184,7 +184,7 @@ int ksched_setscheduler(register_t *ret, struct ksched *ksched,
                {
                        rtp.type = RTP_PRIO_NORMAL;
                        rtp.prio = p4prio_to_rtpprio(param->sched_priority);
-                       p->p_rtprio = rtp;
+                       p->p_lwp.lwp_rtprio = rtp;
 
                        /* XXX Simply revert to whatever we had for last
                         *     normal scheduler priorities.
index e947d93..b520329 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.38 2005/10/11 09:59:56 corecode Exp $
+ * $DragonFly: src/sys/kern/kern_sig.c,v 1.39 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -77,7 +77,6 @@ static char   *expand_name(const char *, uid_t, pid_t);
 static int     killpg(int sig, int pgid, int all);
 static int     sig_ffs(sigset_t *set);
 static int     sigprop(int sig);
-static void    stop(struct proc *);
 #ifdef SMP
 static void    signotify_remote(void *arg);
 #endif
@@ -760,12 +759,6 @@ trapsignal(struct proc *p, int sig, u_long code)
  *
  * Other ignored signals are discarded immediately.
  */
-
-/*
- * temporary hack to allow checkpoint code to continue to
- * be in a module for the moment
- */
-
 void
 psignal(struct proc *p, int sig)
 {
@@ -814,10 +807,12 @@ psignal(struct proc *p, int sig)
                p->p_nice = NZERO;
        }
 
+       /*
+        * If continuing, clear any pending STOP signals.
+        */
        if (prop & SA_CONT)
                SIG_STOPSIGMASK(p->p_siglist);
        
-
        if (prop & SA_STOP) {
                /*
                 * If sending a tty stop signal to a member of an orphaned
@@ -837,76 +832,110 @@ psignal(struct proc *p, int sig)
         * Defer further processing for signals which are held,
         * except that stopped processes must be continued by SIGCONT.
         */
-       if (action == SIG_HOLD && (!(prop & SA_CONT) || p->p_stat != SSTOP))
-               return;
+       if (action == SIG_HOLD) {
+               if ((prop & SA_CONT) == 0 || (p->p_flag & P_STOPPED) == 0)
+                       return;
+       }
 
        crit_enter();
 
-       switch (p->p_stat) {
-       case SSLEEP:
+       /*
+        * Process is in tsleep and not stopped
+        */
+       if (p->p_stat == SSLEEP && (p->p_flag & P_STOPPED) == 0) {
                /*
-                * If process is sleeping uninterruptibly
+                * If the process is sleeping uninterruptibly
                 * we can't interrupt the sleep... the signal will
                 * be noticed when the process returns through
                 * trap() or syscall().
                 */
                if ((p->p_flag & P_SINTR) == 0)
                        goto out;
+
                /*
-                * Process is sleeping and traced... make it runnable
+                * If the process is sleeping and traced, make it runnable
                 * so it can discover the signal in issignal() and stop
                 * for the parent.
+                *
+                * If the process is stopped and traced, no further action
+                * is necessary.
                 */
                if (p->p_flag & P_TRACED)
                        goto run;
+
                /*
-                * If SIGCONT is default (or ignored) and process is
-                * asleep, we are finished; the process should not
-                * be awakened.
+                * If the process is sleeping and SA_CONT, and the signal
+                * mode is SIG_DFL, then make the process runnable.
+                *
+                * However, do *NOT* set P_BREAKTSLEEP.  We do not want 
+                * a SIGCONT to terminate an interruptable tsleep early
+                * and generate a spurious EINTR.
                 */
                if ((prop & SA_CONT) && action == SIG_DFL) {
                        SIGDELSET(p->p_siglist, sig);
-                       goto out;
+                       goto run_no_break;
                }
+
                /*
-                * When a sleeping process receives a stop
-                * signal, process immediately if possible.
-                * All other (caught or default) signals
-                * cause the process to run.
+                * If the process is sleeping and receives a STOP signal,
+                * process immediately if possible.  All other (caught or
+                * default) signals cause the process to run.
                 */
                if (prop & SA_STOP) {
                        if (action != SIG_DFL)
                                goto run;
+
                        /*
-                        * If a child holding parent blocked,
-                        * stopping could cause deadlock.
+                        * If a child holding parent blocked, stopping 
+                        * could cause deadlock.  Take no action at this
+                        * time.
                         */
                        if (p->p_flag & P_PPWAIT)
                                goto out;
+
+                       /*
+                        * Do not actually try to manipulate the process
+                        * while it is sleeping, simply set P_STOPPED to
+                        * indicate that it should stop as soon as it safely
+                        * can.
+                        */
                        SIGDELSET(p->p_siglist, sig);
+                       p->p_flag |= P_STOPPED;
+                       p->p_flag &= ~P_WAITED;
                        p->p_xstat = sig;
                        if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0)
                                psignal(p->p_pptr, SIGCHLD);
-                       stop(p);
                        goto out;
-               } else {
-                       goto run;
                }
-               /*NOTREACHED*/
-       case SSTOP:
+
+               /*
+                * Otherwise the signal can interrupt the sleep.
+                */
+               goto run;
+       }
+
+       /*
+        * Process is in tsleep and is stopped
+        */
+       if (p->p_stat == SSLEEP && (p->p_flag & P_STOPPED)) {
                /*
-                * If traced process is already stopped,
-                * then no further action is necessary.
+                * If the process is stopped and is being traced, then no
+                * further action is necessary.
                 */
                if (p->p_flag & P_TRACED)
                        goto out;
 
                /*
-                * Kill signal always sets processes running.
+                * If the process is stopped and receives a KILL signal,
+                * make the process runnable.
                 */
                if (sig == SIGKILL)
                        goto run;
 
+               /*
+                * If the process is stopped and receives a CONT signal,
+                * then try to make the process runnable again.
+                */
                if (prop & SA_CONT) {
                        /*
                         * If SIGCONT is default (or ignored), we continue the
@@ -914,88 +943,83 @@ psignal(struct proc *p, int sig)
                         * it has no further action.  If SIGCONT is held, we
                         * continue the process and leave the signal in
                         * p_siglist.  If the process catches SIGCONT, let it
-                        * handle the signal itself.  If it isn't waiting on
-                        * an event, then it goes back to run state.
-                        * Otherwise, process goes back to sleep state.
+                        * handle the signal itself.
                         */
                        if (action == SIG_DFL)
                                SIGDELSET(p->p_siglist, sig);
                        if (action == SIG_CATCH)
                                goto run;
-                       if (p->p_wchan == 0)
-                               goto run;
-                       clrrunnable(p, SSLEEP);
-                       goto out;
-               }
 
-               if (prop & SA_STOP) {
                        /*
-                        * Already stopped, don't need to stop again.
-                        * (If we did the shell could get confused.)
+                        * Make runnable but do not break a tsleep unless
+                        * some other signal was pending.
                         */
+                       goto run_no_break;
+               }
+
+               /*
+                * If the process is stopped and receives another STOP
+                * signal, we do not need to stop it again.  If we did
+                * the shell could get confused.
+                */
+               if (prop & SA_STOP) {
                        SIGDELSET(p->p_siglist, sig);
                        goto out;
                }
 
                /*
-                * If process is sleeping interruptibly, then simulate a
-                * wakeup so that when it is continued, it will be made
-                * runnable and can look at the signal.  But don't make
-                * the process runnable, leave it stopped.
+                * Otherwise the process is sleeping interruptably but
+                * is stopped, just set the P_BREAKTSLEEP flag and take
+                * no further action.  The next runnable action will wake
+                * the process up.
                 */
-               if (p->p_wchan && (p->p_flag & P_SINTR))
-                       unsleep(p->p_thread);
+               p->p_flag |= P_BREAKTSLEEP;
                goto out;
-       default:
-               /*
-                * SRUN, SIDL, SZOMB do nothing with the signal,
-                * other than kicking ourselves if we are running.
-                * It will either never be noticed, or noticed very soon.
-                *
-                * Note that p_thread may be NULL or may not be completely
-                * initialized if the process is in the SIDL or SZOMB state.
-                *
-                * For SMP we may have to forward the request to another cpu.
-                * YYY the MP lock prevents the target process from moving
-                * to another cpu, see kern/kern_switch.c
-                *
-                * If the target thread is waiting on its message port,
-                * wakeup the target thread so it can check (or ignore)
-                * the new signal.  YYY needs cleanup.
-                */
+       }
+
+       /*
+        * Otherwise the process is running
+        *
+        * SRUN, SIDL, SZOMB do nothing with the signal,
+        * other than kicking ourselves if we are running.
+        * It will either never be noticed, or noticed very soon.
+        *
+        * Note that p_thread may be NULL or may not be completely
+        * initialized if the process is in the SIDL or SZOMB state.
+        *
+        * For SMP we may have to forward the request to another cpu.
+        * YYY the MP lock prevents the target process from moving
+        * to another cpu, see kern/kern_switch.c
+        *
+        * If the target thread is waiting on its message port,
+        * wakeup the target thread so it can check (or ignore)
+        * the new signal.  YYY needs cleanup.
+        */
+       if (lp == lwkt_preempted_proc()) {
+               signotify();
+       } else if (p->p_stat == SRUN) {
+               struct thread *td = p->p_thread;
+
+               KASSERT(td != NULL, 
+                   ("pid %d NULL p_thread stat %d flags %08x",
+                   p->p_pid, p->p_stat, p->p_flag));
+
 #ifdef SMP
-               if (lp == lwkt_preempted_proc()) {
-                       signotify();
-               } else if (p->p_stat == SRUN) {
-                       struct thread *td = p->p_thread;
-
-                       KASSERT(td != NULL, 
-                           ("pid %d NULL p_thread stat %d flags %08x",
-                           p->p_pid, p->p_stat, p->p_flag));
-
-                       if (td->td_gd != mycpu)
-                               lwkt_send_ipiq(td->td_gd, signotify_remote, lp);
-                       else if (td->td_msgport.mp_flags & MSGPORTF_WAITING)
-                               lwkt_schedule(td);
-               }
-#else
-               if (lp == lwkt_preempted_proc()) {
-                       signotify();
-               } else if (p->p_stat == SRUN) {
-                       struct thread *td = p->p_thread;
-
-                       KASSERT(td != NULL, 
-                           ("pid %d NULL p_thread stat %d flags %08x",
-                           p->p_pid, p->p_stat, p->p_flag));
-
-                       if (td->td_msgport.mp_flags & MSGPORTF_WAITING)
-                               lwkt_schedule(td);
-               }
+               if (td->td_gd != mycpu)
+                       lwkt_send_ipiq(td->td_gd, signotify_remote, lp);
+               else
 #endif
-               goto out;
+               if (td->td_msgport.mp_flags & MSGPORTF_WAITING)
+                       lwkt_schedule(td);
        }
+       goto out;
        /*NOTREACHED*/
 run:
+       /*
+        * Make runnable and break out of any tsleep as well.
+        */
+       p->p_flag |= P_BREAKTSLEEP;
+run_no_break:
        setrunnable(p);
 out:
        crit_exit();
@@ -1235,17 +1259,24 @@ issignal(struct proc *p)
                        SIGDELSET(p->p_siglist, sig);
                        continue;
                }
-               if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) {
+               if ((p->p_flag & P_TRACED) && (p->p_flag & P_PPWAIT) == 0) {
                        /*
-                        * If traced, always stop, and stay
-                        * stopped until released by the parent.
+                        * If traced, always stop, and stay stopped until
+                        * released by the parent.
+                        *
+                        * NOTE: P_STOPPED may get cleared during the loop,
+                        * but we do not re-notify the parent if we have 
+                        * to loop several times waiting for the parent
+                        * to let us continue.
                         */
                        p->p_xstat = sig;
+                       p->p_flag |= P_STOPPED;
+                       p->p_flag &= ~P_WAITED;
                        psignal(p->p_pptr, SIGCHLD);
                        do {
-                               stop(p);
-                               mi_switch(p);
-                       } while (!trace_req(p) && p->p_flag & P_TRACED);
+                               tstop(p);
+                       } while (!trace_req(p) && (p->p_flag & P_TRACED));
+                       p->p_flag &= ~P_STOPPED;
 
                        /*
                         * If parent wants us to take the signal,
@@ -1282,7 +1313,6 @@ issignal(struct proc *p)
                 * to clear it from the pending mask.
                 */
                switch ((int)(intptr_t)p->p_sigacts->ps_sigact[_SIG_IDX(sig)]) {
-
                case (int)SIG_DFL:
                        /*
                         * Don't take default actions on system processes.
@@ -1320,10 +1350,14 @@ issignal(struct proc *p)
                                    prop & SA_TTYSTOP))
                                        break;  /* == ignore */
                                p->p_xstat = sig;
-                               stop(p);
+                               p->p_flag |= P_STOPPED;
+                               p->p_flag &= ~P_WAITED;
+
                                if ((p->p_pptr->p_procsig->ps_flag & PS_NOCLDSTOP) == 0)
                                        psignal(p->p_pptr, SIGCHLD);
-                               mi_switch(p);
+                               while (p->p_flag & P_STOPPED) {
+                                       tstop(p);
+                               }
                                break;
                        } else if (prop & SA_IGNORE) {
                                /*
@@ -1360,19 +1394,6 @@ issignal(struct proc *p)
        /* NOTREACHED */
 }
 
-/*
- * Put the argument process into the stopped state and notify the parent
- * via wakeup.  Signals are handled elsewhere.  The process must not be
- * on the run queue.
- */
-void
-stop(struct proc *p)
-{
-       p->p_stat = SSTOP;
-       p->p_flag &= ~P_WAITED;
-       wakeup((caddr_t)p->p_pptr);
-}
-
 /*
  * Take the action for the specified signal
  * from the current set of pending signals.
index 1b542bb..acc3391 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.52 2005/11/09 03:39:15 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_synch.c,v 1.53 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -51,6 +51,7 @@
 #include <sys/vmmeter.h>
 #include <sys/sysctl.h>
 #include <sys/thread2.h>
+#include <sys/lock.h>
 #ifdef KTRACE
 #include <sys/uio.h>
 #include <sys/ktrace.h>
@@ -68,6 +69,7 @@ SYSINIT(sched_setup, SI_SUB_KICK_SCHEDULER, SI_ORDER_FIRST, sched_setup, NULL)
 
 int    hogticks;
 int    lbolt;
+int    lbolt_syncer;
 int    sched_quantum;          /* Roundrobin scheduling quantum in ticks. */
 int    ncpus;
 int    ncpus2, ncpus2_shift, ncpus2_mask;
@@ -90,6 +92,7 @@ static fixpt_t cexp[3] = {
 };
 
 static void    endtsleep (void *);
+static void    unsleep_and_wakeup_thread(struct thread *td);
 static void    loadav (void *arg);
 static void    schedcpu (void *arg);
 
@@ -157,17 +160,17 @@ SYSCTL_INT(_kern, OID_AUTO, fscale, CTLFLAG_RD, 0, FSCALE, "");
 static void
 schedcpu(void *arg)
 {
+       struct rlimit *rlim;
        struct proc *p;
+       u_int64_t ttime;
 
+       /*
+        * General process statistics once a second
+        */
        FOREACH_PROC_IN_SYSTEM(p) {
-               /*
-                * Increment time in/out of memory and sleep time
-                * (if sleeping).  We ignore overflow; with 16-bit int's
-                * (remember them?) overflow takes 45 days.
-                */
                crit_enter();
                p->p_swtime++;
-               if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
+               if (p->p_stat == SSLEEP)
                        p->p_slptime++;
 
                /*
@@ -181,7 +184,43 @@ schedcpu(void *arg)
                }
                crit_exit();
        }
+
+       /*
+        * Resource checks.  XXX break out since psignal/killproc can block,
+        * limiting us to one process killed per second.  There is probably
+        * a better way.
+        */
+       FOREACH_PROC_IN_SYSTEM(p) {
+               crit_enter();
+               if (p->p_stat == SZOMB || 
+                   p->p_limit == NULL || 
+                   p->p_thread == NULL
+               ) {
+                       crit_exit();
+                       continue;
+               }
+               ttime = p->p_thread->td_sticks + p->p_thread->td_uticks;
+               if (p->p_limit->p_cpulimit != RLIM_INFINITY &&
+                   ttime > p->p_limit->p_cpulimit
+               ) {
+                       rlim = &p->p_rlimit[RLIMIT_CPU];
+                       if (ttime / (rlim_t)1000000 >= rlim->rlim_max) {
+                               killproc(p, "exceeded maximum CPU limit");
+                       } else {
+                               psignal(p, SIGXCPU);
+                               if (rlim->rlim_cur < rlim->rlim_max) {
+                                       /* XXX: we should make a private copy */
+                                       rlim->rlim_cur += 5;
+                               }
+                       }
+                       crit_exit();
+                       break;
+               }
+               crit_exit();
+       }
+
        wakeup((caddr_t)&lbolt);
+       wakeup((caddr_t)&lbolt_syncer);
        callout_reset(&schedcpu_callout, hz, schedcpu, NULL);
 }
 
@@ -234,11 +273,8 @@ sleep_gdinit(globaldata_t gd)
 
                gd->gd_tsleep_hash = slpque_cpu0;
        } else {
-#if 0
                gd->gd_tsleep_hash = malloc(sizeof(slpque_cpu0), 
                                            M_TSLEEP, M_WAITOK | M_ZERO);
-#endif
-               gd->gd_tsleep_hash = slpque_cpu0;
        }
        for (i = 0; i < TABLESIZE; ++i)
                TAILQ_INIT(&gd->gd_tsleep_hash[i]);
@@ -267,8 +303,10 @@ tsleep(void *ident, int flags, const char *wmesg, int timo)
        struct thread *td = curthread;
        struct proc *p = td->td_proc;           /* may be NULL */
        globaldata_t gd;
-       int sig = 0, catch = flags & PCATCH;
-       int id = LOOKUP(ident);
+       int sig;
+       int catch;
+       int id;
+       int error;
        int oldpri;
        struct callout thandle;
 
@@ -292,15 +330,53 @@ tsleep(void *ident, int flags, const char *wmesg, int timo)
        }
        gd = td->td_gd;
        KKASSERT(td != &gd->gd_idlethread);     /* you must be kidding! */
+
+       /*
+        * NOTE: all of this occurs on the current cpu, including any
+        * callout-based wakeups, so a critical section is a sufficient
+        * interlock.
+        *
+        * The entire sequence through to where we actually sleep must
+        * run without breaking the critical section.
+        */
+       id = LOOKUP(ident);
+       catch = flags & PCATCH;
+       error = 0;
+       sig = 0;
+
        crit_enter_quick(td);
+
        KASSERT(ident != NULL, ("tsleep: no ident"));
        KASSERT(p == NULL || p->p_stat == SRUN, ("tsleep %p %s %d",
                ident, wmesg, p->p_stat));
 
-       td->td_wchan = ident;
-       td->td_wmesg = wmesg;
-       td->td_wdomain = flags & PDOMAIN_MASK;
+       /*
+        * Setup for the current process (if this is a process). 
+        */
        if (p) {
+               if (catch) {
+                       /*
+                        * Early termination if PCATCH was set and a
+                        * signal is pending, interlocked with the
+                        * critical section.
+                        *
+                        * Early termination only occurs when tsleep() is
+                        * entered while in a normal SRUN state.
+                        */
+                       if ((sig = CURSIG(p)) != 0)
+                               goto resume;
+
+                       /*
+                        * Causes psignal to wake us up when.
+                        */
+                       p->p_flag |= P_SINTR;
+               }
+
+               /*
+                * Make sure the current process has been untangled from
+                * the userland scheduler and initialize slptime to start
+                * counting.
+                */
                if (flags & PNORESCHED)
                        td->td_flags |= TDF_NORESCHED;
                p->p_usched->release_curproc(&p->p_lwp);
@@ -308,102 +384,98 @@ tsleep(void *ident, int flags, const char *wmesg, int timo)
        }
 
        /*
-        * note: all of this occurs on the current cpu, including any
-        * callout-based wakeups, so a critical section is a sufficient
-        * interlock.
+        * Move our thread to the correct queue and setup our wchan, etc.
         */
        lwkt_deschedule_self(td);
+       td->td_flags |= TDF_TSLEEPQ;
        TAILQ_INSERT_TAIL(&gd->gd_tsleep_hash[id], td, td_threadq);
        atomic_set_int(&slpque_cpumasks[id], gd->gd_cpumask);
+
+       td->td_wchan = ident;
+       td->td_wmesg = wmesg;
+       td->td_wdomain = flags & PDOMAIN_MASK;
+
+       /*
+        * Setup the timeout, if any
+        */
        if (timo) {
                callout_init(&thandle);
                callout_reset(&thandle, timo, endtsleep, td);
        }
+
        /*
-        * We put ourselves on the sleep queue and start our timeout
-        * before calling CURSIG, as we could stop there, and a wakeup
-        * or a SIGCONT (or both) could occur while we were stopped.
-        * A SIGCONT would cause us to be marked as SSLEEP
-        * without resuming us, thus we must be ready for sleep
-        * when CURSIG is called.  If the wakeup happens while we're
-        * stopped, td->td_wchan will be 0 upon return from CURSIG.
+        * Beddy bye bye.
         */
        if (p) {
-               if (catch) {
-                       p->p_flag |= P_SINTR;
-                       if ((sig = CURSIG(p))) {
-                               if (td->td_wchan) {
-                                       unsleep(td);
-                                       lwkt_schedule_self(td);
-                               }
-                               p->p_stat = SRUN;
-                               goto resume;
-                       }
-                       if (td->td_wchan == NULL) {
-                               catch = 0;
-                               goto resume;
-                       }
-               } else {
-                       sig = 0;
-               }
-
                /*
-                * If we are not the current process we have to remove ourself
-                * from the run queue.
+                * Ok, we are sleeping.  Remove us from the userland runq
+                * and place us in the SSLEEP state.
                 */
-               KASSERT(p->p_stat == SRUN, ("PSTAT NOT SRUN %d %d", p->p_pid, p->p_stat));
-               /*
-                * If this is the current 'user' process schedule another one.
-                */
-               clrrunnable(p, SSLEEP);
+               if (p->p_flag & P_ONRUNQ)
+                       p->p_usched->remrunqueue(&p->p_lwp);
+               p->p_stat = SSLEEP;
                p->p_stats->p_ru.ru_nvcsw++;
-               mi_switch(p);
-               KASSERT(p->p_stat == SRUN, ("tsleep: stat not srun"));
+               lwkt_switch();
+               p->p_stat = SRUN;
        } else {
                lwkt_switch();
        }
+
        /* 
         * Make sure we haven't switched cpus while we were asleep.  It's
-        * not supposed to happen.
+        * not supposed to happen.  Cleanup our temporary flags.
         */
        KKASSERT(gd == td->td_gd);
-resume:
-       if (p)
-               p->p_flag &= ~P_SINTR;
-       crit_exit_quick(td);
        td->td_flags &= ~TDF_NORESCHED;
-       if (td->td_flags & TDF_TIMEOUT) {
-               td->td_flags &= ~TDF_TIMEOUT;
-               if (sig == 0)
-                       return (EWOULDBLOCK);
-       } else if (timo) {
-               callout_stop(&thandle);
-       } else if (td->td_wmesg) {
-               /*
-                * This can happen if a thread is woken up directly.  Clear
-                * wmesg to avoid debugging confusion.
-                */
-               td->td_wmesg = NULL;
+
+       /*
+        * Cleanup the timeout.
+        */
+       if (timo) {
+               if (td->td_flags & TDF_TIMEOUT) {
+                       td->td_flags &= ~TDF_TIMEOUT;
+                       if (sig == 0)
+                               error = EWOULDBLOCK;
+               } else {
+                       callout_stop(&thandle);
+               }
        }
-       /* inline of iscaught() */
+
+       /*
+        * Since td_threadq is used both for our run queue AND for the
+        * tsleep hash queue, we can't still be on it at this point because
+        * we've gotten cpu back.
+        */
+       KKASSERT((td->td_flags & TDF_TSLEEPQ) == 0);
+       td->td_wchan = NULL;
+       td->td_wmesg = NULL;
+       td->td_wdomain = 0;
+
+       /*
+        * Figure out the correct error return
+        */
+resume:
        if (p) {
-               if (catch && (sig != 0 || (sig = CURSIG(p)))) {
+               p->p_flag &= ~(P_BREAKTSLEEP | P_SINTR);
+               if (catch && error == 0 && (sig != 0 || (sig = CURSIG(p)))) {
                        if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig))
-                               return (EINTR);
-                       return (ERESTART);
+                               error = EINTR;
+                       else
+                               error = ERESTART;
                }
        }
-       return (0);
+       crit_exit_quick(td);
+       return (error);
 }
 
 /*
- * Implement the timeout for tsleep.  We interlock against
- * wchan when setting TDF_TIMEOUT.  For processes we remove
- * the sleep if the process is stopped rather then sleeping,
- * so it remains stopped.
+ * Implement the timeout for tsleep.
  *
- * This type of callout timeout had better be scheduled on the same
- * cpu the process is sleeping on.
+ * We set P_BREAKTSLEEP to indicate that an event has occured, but
+ * we only call setrunnable if the process is not stopped.
+ *
+ * This type of callout timeout is scheduled on the same cpu the process
+ * is sleeping on.  Also, at the moment, the MP lock is held.
  */
 static void
 endtsleep(void *arg)
@@ -411,40 +483,54 @@ endtsleep(void *arg)
        thread_t td = arg;
        struct proc *p;
 
+       ASSERT_MP_LOCK_HELD(curthread);
        crit_enter();
-       if (td->td_wchan) {
+
+       /*
+        * cpu interlock.  Thread flags are only manipulated on
+        * the cpu owning the thread.  proc flags are only manipulated
+        * by the older of the MP lock.  We have both.
+        */
+       if (td->td_flags & TDF_TSLEEPQ) {
                td->td_flags |= TDF_TIMEOUT;
+
                if ((p = td->td_proc) != NULL) {
-                       if (p->p_stat == SSLEEP)
+                       p->p_flag |= P_BREAKTSLEEP;
+                       if ((p->p_flag & P_STOPPED) == 0)
                                setrunnable(p);
-                       else
-                               unsleep(td);
                } else {
-                       unsleep(td);
-                       lwkt_schedule(td);
+                       unsleep_and_wakeup_thread(td);
                }
        }
        crit_exit();
 }
 
 /*
- * Remove a process from its wait queue
- *
- * XXX not MP safe until called only on the cpu holding the sleeping
- * process.
+ * Unsleep and wakeup a thread.  This function runs without the MP lock
+ * which means that it can only manipulate thread state on the owning cpu,
+ * and cannot touch the process state at all.
  */
+static
 void
-unsleep(struct thread *td)
+unsleep_and_wakeup_thread(struct thread *td)
 {
+       globaldata_t gd = mycpu;
        int id;
 
+#ifdef SMP
+       if (td->td_gd != gd) {
+               lwkt_send_ipiq(td->td_gd, (ipifunc1_t)unsleep_and_wakeup_thread, td);
+               return;
+       }
+#endif
        crit_enter();
-       id = LOOKUP(td->td_wchan);
-       if (td->td_wchan) {
-               TAILQ_REMOVE(&td->td_gd->gd_tsleep_hash[id], td, td_threadq);
-               if (TAILQ_FIRST(&td->td_gd->gd_tsleep_hash[id]) == NULL)
-                       atomic_clear_int(&slpque_cpumasks[id], td->td_gd->gd_cpumask);
-               td->td_wchan = NULL;
+       if (td->td_flags & TDF_TSLEEPQ) {
+               td->td_flags &= ~TDF_TSLEEPQ;
+               id = LOOKUP(td->td_wchan);
+               TAILQ_REMOVE(&gd->gd_tsleep_hash[id], td, td_threadq);
+               if (TAILQ_FIRST(&gd->gd_tsleep_hash[id]) == NULL)
+                       atomic_clear_int(&slpque_cpumasks[id], gd->gd_cpumask);
+               lwkt_schedule(td);
        }
        crit_exit();
 }
@@ -455,6 +541,10 @@ unsleep(struct thread *td)
  *
  * The domain encodes the sleep/wakeup domain AND the first cpu to check
  * (which is always the current cpu).  As we iterate across cpus
+ *
+ * This call may run without the MP lock held.  We can only manipulate thread
+ * state on the cpu owning the thread.  We CANNOT manipulate process state
+ * at all.
  */
 static void
 _wakeup(void *ident, int domain)
@@ -463,14 +553,11 @@ _wakeup(void *ident, int domain)
        struct thread *td;
        struct thread *ntd;
        globaldata_t gd;
-       struct proc *p;
-#if 0
 #ifdef SMP
        cpumask_t mask;
        cpumask_t tmask;
        int startcpu;
        int nextcpu;
-#endif
 #endif
        int id;
 
@@ -484,37 +571,20 @@ restart:
                if (td->td_wchan == ident && 
                    td->td_wdomain == (domain & PDOMAIN_MASK)
                ) {
+                       KKASSERT(td->td_flags & TDF_TSLEEPQ);
+                       td->td_flags &= ~TDF_TSLEEPQ;
                        TAILQ_REMOVE(qp, td, td_threadq);
                        if (TAILQ_FIRST(qp) == NULL) {
                                atomic_clear_int(&slpque_cpumasks[id],
                                                 gd->gd_cpumask);
                        }
-                       td->td_wchan = NULL;
-                       if ((p = td->td_proc) != NULL && p->p_stat == SSLEEP) {
-                               p->p_stat = SRUN;
-                               if (p->p_flag & P_INMEM) {
-                                       /*
-                                        * LWKT scheduled now, there is no
-                                        * userland runq interaction until
-                                        * the thread tries to return to user
-                                        * mode.  We do NOT call setrunqueue().
-                                        */
-                                       lwkt_schedule(td);
-                               } else {
-                                       p->p_flag |= P_SWAPINREQ;
-                                       wakeup((caddr_t)&proc0);
-                               }
-                               /* END INLINE EXPANSION */
-                       } else if (p == NULL) {
-                               lwkt_schedule(td);
-                       }
+                       lwkt_schedule(td);
                        if (domain & PWAKEUP_ONE)
                                goto done;
                        goto restart;
                }
        }
 
-#if 0
 #ifdef SMP
        /*
         * We finished checking the current cpu but there still may be
@@ -594,7 +664,6 @@ restart:
                }
        }
 #endif
-#endif
 done:
        crit_exit();
 }
@@ -626,96 +695,47 @@ wakeup_domain_one(void *ident, int domain)
 }
 
 /*
- * The machine independent parts of mi_switch().
+ * setrunnable()
+ *
+ * Make a process runnable.  The MP lock must be held on call.  This only
+ * has an effect if we are in SSLEEP.  We only break out of the
+ * tsleep if P_BREAKTSLEEP is set, otherwise we just fix-up the state.
  *
- * 'p' must be the current process.
+ * NOTE: With the MP lock held we can only safely manipulate the process
+ * structure.  We cannot safely manipulate the thread structure.
  */
 void
-mi_switch(struct proc *p)
+setrunnable(struct proc *p)
 {
-       thread_t td = p->p_thread;
-       struct rlimit *rlim;
-       u_int64_t ttime;
-
-       KKASSERT(td == mycpu->gd_curthread);
-
-       crit_enter_quick(td);
-
-       /*
-        * Check if the process exceeds its cpu resource allocation.
-        * If over max, kill it.  Time spent in interrupts is not 
-        * included.  YYY 64 bit match is expensive.  Ick.
-        *
-        * XXX move to the once-a-second process scan
-        */
-       ttime = td->td_sticks + td->td_uticks;
-       if (p->p_stat != SZOMB && p->p_limit->p_cpulimit != RLIM_INFINITY &&
-           ttime > p->p_limit->p_cpulimit) {
-               rlim = &p->p_rlimit[RLIMIT_CPU];
-               if (ttime / (rlim_t)1000000 >= rlim->rlim_max) {
-                       killproc(p, "exceeded maximum CPU limit");
-               } else {
-                       psignal(p, SIGXCPU);
-                       if (rlim->rlim_cur < rlim->rlim_max) {
-                               /* XXX: we should make a private copy */
-                               rlim->rlim_cur += 5;
-                       }
-               }
+       crit_enter();
+       ASSERT_MP_LOCK_HELD(curthread);
+       p->p_flag &= ~P_STOPPED;
+       if (p->p_stat == SSLEEP && (p->p_flag & P_BREAKTSLEEP)) {
+               unsleep_and_wakeup_thread(p->p_thread);
        }
-
-       /*
-        * If we are in a SSTOPped state we deschedule ourselves.  
-        * YYY this needs to be cleaned up, remember that LWKTs stay on
-        * their run queue which works differently then the user scheduler
-        * which removes the process from the runq when it runs it.
-        */
-       mycpu->gd_cnt.v_swtch++;
-       if (p->p_stat == SSTOP)
-               lwkt_deschedule_self(td);
-       lwkt_switch();
-       crit_exit_quick(td);
+       crit_exit();
 }
 
 /*
- * Change process state to be runnable, placing it on the run queue if it
- * is in memory, and awakening the swapper if it isn't in memory.
+ * The process is stopped due to some condition, usually because P_STOPPED
+ * is set but also possibly due to being traced.  
  *
- * This operation MUST OCCUR on the cpu that the thread is sleeping on.
+ * NOTE!  If the caller sets P_STOPPED, the caller must also clear P_WAITED
+ * because the parent may check the child's status before the child actually
+ * gets to this routine.
+ *
+ * This routine is called with the current process only, typically just
+ * before returning to userland.
+ *
+ * Setting P_BREAKTSLEEP before entering the tsleep will cause a passive
+ * SIGCONT to break out of the tsleep.
  */
 void
-setrunnable(struct proc *p)
+tstop(struct proc *p)
 {
-       crit_enter();
-
-       switch (p->p_stat) {
-       case 0:
-       case SRUN:
-       case SZOMB:
-       default:
-               panic("setrunnable");
-       case SSTOP:
-       case SSLEEP:
-               unsleep(p->p_thread);   /* e.g. when sending signals */
-               break;
-
-       case SIDL:
-               break;
-       }
-       p->p_stat = SRUN;
-
-       /*
-        * The process is controlled by LWKT at this point, we do not mess
-        * around with the userland scheduler until the thread tries to 
-        * return to user mode.  We do not clear p_slptime or call
-        * setrunqueue().
-        */
-       if (p->p_flag & P_INMEM) {
-               lwkt_schedule(p->p_thread);
-       } else {
-               p->p_flag |= P_SWAPINREQ;
-               wakeup((caddr_t)&proc0);
-       }
-       crit_exit();
+       wakeup((caddr_t)p->p_pptr);
+       p->p_flag |= P_BREAKTSLEEP;
+       tsleep(p, 0, "stop", 0);
 }
 
 /*
@@ -751,20 +771,6 @@ uio_yield(void)
        }
 }
 
-/*
- * Change the process state to NOT be runnable, removing it from the run
- * queue.
- */
-void
-clrrunnable(struct proc *p, int stat)
-{
-       crit_enter_quick(p->p_thread);
-       if (p->p_stat == SRUN && (p->p_flag & P_ONRUNQ))
-               p->p_usched->remrunqueue(&p->p_lwp);
-       p->p_stat = stat;
-       crit_exit_quick(p->p_thread);
-}
-
 /*
  * Compute a tenex style load average of a quantity on
  * 1, 5 and 15 minute intervals.
index 028e5d6..62026b8 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.85 2005/11/08 22:38:43 dillon Exp $
+ * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.86 2005/11/14 18:50:05 dillon Exp $
  */
 
 /*
@@ -146,7 +146,7 @@ static __inline
 void
 _lwkt_enqueue(thread_t td)
 {
-    if ((td->td_flags & (TDF_RUNQ|TDF_MIGRATING)) == 0) {
+    if ((td->td_flags & (TDF_RUNQ|TDF_MIGRATING|TDF_TSLEEPQ|TDF_BLOCKQ)) == 0) {
        int nq = td->td_pri & TDPRI_MASK;
        struct globaldata *gd = td->td_gd;
 
@@ -169,11 +169,8 @@ lwkt_schedule_self(thread_t td)
     crit_enter_quick(td);
     KASSERT(td->td_wait == NULL, ("lwkt_schedule_self(): td_wait not NULL!"));
     KASSERT(td != &td->td_gd->gd_idlethread, ("lwkt_schedule_self(): scheduling gd_idlethread is illegal!"));
+    KKASSERT(td->td_proc == NULL || (td->td_proc->p_flag & P_ONRUNQ) == 0);
     _lwkt_enqueue(td);
-#ifdef _KERNEL
-    if (td->td_proc && td->td_proc->p_stat == SSLEEP)
-       panic("SCHED SELF PANIC");
-#endif
     crit_exit_quick(td);
 }
 
@@ -665,10 +662,12 @@ again:
                    ntd->td_flags |= TDF_IDLE_NOHLT;
                    goto using_idle_thread;
                } else {
+                   ++gd->gd_cnt.v_swtch;
                    TAILQ_REMOVE(&gd->gd_tdrunq[nq], ntd, td_threadq);
                    TAILQ_INSERT_TAIL(&gd->gd_tdrunq[nq], ntd, td_threadq);
                }
            } else {
+               ++gd->gd_cnt.v_swtch;
                TAILQ_REMOVE(&gd->gd_tdrunq[nq], ntd, td_threadq);
                TAILQ_INSERT_TAIL(&gd->gd_tdrunq[nq], ntd, td_threadq);
            }
@@ -677,6 +676,7 @@ again:
             * THREAD SELECTION FOR A UP MACHINE BUILD.  We don't have to
             * worry about tokens or the BGL.
             */
+           ++gd->gd_cnt.v_swtch;
            TAILQ_REMOVE(&gd->gd_tdrunq[nq], ntd, td_threadq);
            TAILQ_INSERT_TAIL(&gd->gd_tdrunq[nq], ntd, td_threadq);
 #endif
@@ -973,23 +973,9 @@ lwkt_schedule(thread_t td)
 {
     globaldata_t mygd = mycpu;
 
-#ifdef INVARIANTS
     KASSERT(td != &td->td_gd->gd_idlethread, ("lwkt_schedule(): scheduling gd_idlethread is illegal!"));
-    if ((td->td_flags & TDF_PREEMPT_LOCK) == 0 && td->td_proc 
-       && td->td_proc->p_stat == SSLEEP
-    ) {
-       printf("PANIC schedule curtd = %p (%d %d) target %p (%d %d)\n",
-           curthread,
-           curthread->td_proc ? curthread->td_proc->p_pid : -1,
-           curthread->td_proc ? curthread->td_proc->p_stat : -1,
-           td,
-           td->td_proc ? td->td_proc->p_pid : -1,
-           td->td_proc ? td->td_proc->p_stat : -1
-       );
-       panic("SCHED PANIC");
-    }
-#endif
     crit_enter_gd(mygd);
+    KKASSERT(td->td_proc == NULL || (td->td_proc->p_flag & P_ONRUNQ) == 0);
     if (td == mygd->gd_curthread) {
        _lwkt_enqueue(td);
     } else {
@@ -1248,6 +1234,7 @@ lwkt_setcpu_remote(void *arg)
     td->td_gd = gd;
     cpu_sfence();
     td->td_flags &= ~TDF_MIGRATING;
+    KKASSERT(td->td_proc == NULL || (td->td_proc->p_flag & P_ONRUNQ) == 0);
     _lwkt_enqueue(td);
 }
 #endif
@@ -1277,16 +1264,14 @@ lwkt_block(lwkt_wait_t w, const char *wmesg, int *gen)
     crit_enter();
     if (w->wa_gen == *gen) {
        _lwkt_dequeue(td);
+       td->td_flags |= TDF_BLOCKQ;
        TAILQ_INSERT_TAIL(&w->wa_waitq, td, td_threadq);
        ++w->wa_count;
        td->td_wait = w;
        td->td_wmesg = wmesg;
-    again:
        lwkt_switch();
-       if (td->td_wmesg != NULL) {
-           _lwkt_dequeue(td);
-           goto again;
-       }
+       KKASSERT((td->td_flags & TDF_BLOCKQ) == 0);
+       td->td_wmesg = NULL;
     }
     crit_exit();
     *gen = w->wa_gen;
@@ -1315,9 +1300,11 @@ lwkt_signal(lwkt_wait_t w, int count)
     while ((td = TAILQ_FIRST(&w->wa_waitq)) != NULL && count) {
        --count;
        --w->wa_count;
+       KKASSERT(td->td_flags & TDF_BLOCKQ);
        TAILQ_REMOVE(&w->wa_waitq, td, td_threadq);
+       td->td_flags &= ~TDF_BLOCKQ;
        td->td_wait = NULL;
-       td->td_wmesg = NULL;
+       KKASSERT(td->td_proc == NULL || (td->td_proc->p_flag & P_ONRUNQ) == 0);
 #ifdef SMP
        if (td->td_gd == mycpu) {
            _lwkt_enqueue(td);
index 596b643..e3c877e 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)sys_generic.c       8.5 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/sys_generic.c,v 1.55.2.10 2001/03/17 10:39:32 peter Exp $
- * $DragonFly: src/sys/kern/sys_generic.c,v 1.22 2005/06/22 01:33:21 dillon Exp $
+ * $DragonFly: src/sys/kern/sys_generic.c,v 1.23 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -977,12 +977,17 @@ selwakeup(struct selinfo *sip)
        if (p != NULL) {
                crit_enter();
                if (p->p_wchan == (caddr_t)&selwait) {
-                       if (p->p_stat == SSLEEP)
+                       /*
+                        * Flag the process to break the tsleep when 
+                        * setrunnable is called, but only call setrunnable
+                        * here if the process is not in a stopped state.
+                        */
+                       p->p_flag |= P_BREAKTSLEEP;
+                       if ((p->p_flag & P_STOPPED) == 0)
                                setrunnable(p);
-                       else
-                               unsleep(p->p_thread);
-               } else if (p->p_flag & P_SELECT)
+               } else if (p->p_flag & P_SELECT) {
                        p->p_flag &= ~P_SELECT;
+               }
                crit_exit();
        }
 }
index 001862b..2dc1cf2 100644 (file)
@@ -29,7 +29,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/sys_process.c,v 1.51.2.6 2003/01/08 03:06:45 kan Exp $
- * $DragonFly: src/sys/kern/sys_process.c,v 1.17 2005/10/27 03:15:47 sephe Exp $
+ * $DragonFly: src/sys/kern/sys_process.c,v 1.18 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -358,8 +358,10 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, int data, int *re
                        return EBUSY;
 
                /* not currently stopped */
-               if (p->p_stat != SSTOP || (p->p_flag & P_WAITED) == 0)
+               if ((p->p_flag & P_STOPPED) == 0 ||
+                   (p->p_flag & P_WAITED) == 0) {
                        return EBUSY;
+               }
 
                /* OK */
                break;
@@ -438,10 +440,14 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr, int data, int *re
                }
 
        sendsig:
-               /* deliver or queue signal */
+               /*
+                * Deliver or queue signal.  If the process is stopped
+                * force it to SRUN again.
+                */
                crit_enter();
-               if (p->p_stat == SSTOP) {
+               if (p->p_flag & P_STOPPED) {
                        p->p_xstat = data;
+                       p->p_flag |= P_BREAKTSLEEP;
                        setrunnable(p);
                } else if (data) {
                        psignal(p, data);
index cc94e17..acec586 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)tty.c       8.8 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/tty.c,v 1.129.2.5 2002/03/11 01:32:31 dd Exp $
- * $DragonFly: src/sys/kern/tty.c,v 1.18 2005/06/27 18:37:57 dillon Exp $
+ * $DragonFly: src/sys/kern/tty.c,v 1.19 2005/11/14 18:50:05 dillon Exp $
  */
 
 /*-
@@ -2412,7 +2412,7 @@ ttyinfo(tp)
                 * 'pick' becomes invalid the moment we exit the critical
                 * section.
                 */
-               if (pick->p_thread && (pick->p_flag & P_INMEM)) {
+               if (pick->p_thread && (pick->p_flag & P_SWAPPEDOUT) == 0) {
                        calcru(pick, &utime, &stime, NULL);
                        isinmem = 1;
                } else {
index 8f987b5..83fb7d9 100644 (file)
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/kern/usched_bsd4.c,v 1.3 2005/10/11 09:59:56 corecode Exp $
+ * $DragonFly: src/sys/kern/usched_bsd4.c,v 1.4 2005/11/14 18:50:05 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -706,9 +706,15 @@ bsd4_select_curproc(globaldata_t gd)
  * This function is called at kernel-user priority (not userland priority)
  * when curlwp does not match gd_uschedcp.
  *
+ * This function is only called just prior to returning to user mode.
+ *
  * Basically we recalculate our estcpu to hopefully give us a more
  * favorable disposition, setrunqueue, then wait for the curlwp
  * designation to be handed to us (if the setrunqueue didn't do it).
+ *
+ * WARNING! THIS FUNCTION MAY CAUSE THE CURRENT THREAD TO MIGRATE TO
+ * ANOTHER CPU!  Because most of the kernel assumes that no migration will
+ * occur, this function is called only under very controlled circumstances.
  */
 static void
 bsd4_acquire_curproc(struct lwp *lp)
@@ -716,31 +722,36 @@ bsd4_acquire_curproc(struct lwp *lp)
        globaldata_t gd = mycpu;
 
        crit_enter();
-       ++lp->lwp_stats->p_ru.ru_nivcsw;
 
        /*
-        * Loop until we become the current process.  
+        * Recalculate our priority and put us back on the userland
+        * scheduler's runq.
+        *
+        * Only increment the involuntary context switch count if the
+        * setrunqueue call did not immediately schedule us.
         */
-       do {
-               KKASSERT(lp == gd->gd_curthread->td_lwp);
-               bsd4_recalculate_estcpu(lp);
-               lwkt_deschedule_self(gd->gd_curthread);
-               bsd4_setrunqueue(lp);
-               lwkt_switch();
-
-               /*
-                * WE MAY HAVE BEEN MIGRATED TO ANOTHER CPU, RELOAD GD.
-                */
-               gd = mycpu;
-       } while (gd->gd_uschedcp != lp);
+       KKASSERT(lp == gd->gd_curthread->td_lwp);
+       bsd4_recalculate_estcpu(lp);
+       lwkt_deschedule_self(gd->gd_curthread);
+       bsd4_setrunqueue(lp);
+       if ((gd->gd_curthread->td_flags & TDF_RUNQ) == 0)
+               ++lp->lwp_stats->p_ru.ru_nivcsw;
+       lwkt_switch();
 
-       crit_exit();
+       /*
+        * Because we put ourselves back on the userland scheduler's run
+        * queue, WE MAY HAVE BEEN MIGRATED TO ANOTHER CPU
+        */
+       gd = mycpu;
 
        /*
-        * That's it.  Cleanup, we are done.  The caller can return to
-        * user mode now.
+        * We better be the current process when we wake up, and we had
+        * better not be on the run queue.
         */
+       KKASSERT(gd->gd_uschedcp == lp);
        KKASSERT((lp->lwp_proc->p_flag & P_ONRUNQ) == 0);
+
+       crit_exit();
 }
 
 /*
index 05bb7ca..a255184 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_subr.c  8.31 (Berkeley) 5/26/95
  * $FreeBSD: src/sys/kern/vfs_subr.c,v 1.249.2.30 2003/04/04 20:35:57 tegge Exp $
- * $DragonFly: src/sys/kern/vfs_sync.c,v 1.7 2005/09/17 07:43:00 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_sync.c,v 1.8 2005/11/14 18:50:05 dillon Exp $
  */
 
 /*
@@ -266,7 +266,7 @@ sched_sync(void)
                 * filesystem activity.
                 */
                if (time_second == starttime)
-                       tsleep(&lbolt, 0, "syncer", 0);
+                       tsleep(&lbolt_syncer, 0, "syncer", 0);
        }
 }
 
@@ -280,12 +280,11 @@ sched_sync(void)
 int
 speedup_syncer(void)
 {
-       crit_enter();
-       if (updatethread->td_wchan == &lbolt) { /* YYY */
-               unsleep(updatethread);
-               lwkt_schedule(updatethread);
-       }
-       crit_exit();
+       /*
+        * Don't bother protecting the test.  unsleep_and_wakeup_thread()
+        * will only do something real if the thread is in the right state.
+        */
+       wakeup(&lbolt_syncer);
        if (rushjob < syncdelay / 2) {
                rushjob += 1;
                stat_rush_requests += 1;
index 60271ab..a2aad45 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/netsmb/smb_subr.c,v 1.1.2.2 2001/09/03 08:55:11 bp Exp $
- * $DragonFly: src/sys/netproto/smb/smb_subr.c,v 1.15 2005/10/11 09:59:56 corecode Exp $
+ * $DragonFly: src/sys/netproto/smb/smb_subr.c,v 1.16 2005/11/14 18:50:10 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -386,7 +386,7 @@ kthread_create2(void (*func)(void *), void *arg,
                *newpp = p2;
 
        /* this is a non-swapped system process */
-       p2->p_flag |= P_INMEM | P_SYSTEM;
+       p2->p_flag |= P_SYSTEM;
        p2->p_procsig->ps_flag |= PS_NOCLDWAIT;
 
        /* set up arg0 for 'ps', et al */
index 434e6d0..b7dc338 100644 (file)
@@ -24,7 +24,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/i386/i386/db_trace.c,v 1.35.2.3 2002/02/21 22:31:25 silby Exp $
- * $DragonFly: src/sys/platform/pc32/i386/db_trace.c,v 1.10 2005/04/25 20:22:27 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/db_trace.c,v 1.11 2005/11/14 18:50:03 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -304,7 +304,7 @@ db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
                                db_printf("pid %d not found\n", pid);
                                return;
                        }
-                       if ((p->p_flag & P_INMEM) == 0) {
+                       if ((p->p_flag & P_SWAPPEDOUT)) {
                                db_printf("pid %d swapped out\n", pid);
                                return;
                        }
index 285647a..6946025 100644 (file)
@@ -40,7 +40,7 @@
  *
  *     from:   @(#)pmap.c      7.7 (Berkeley)  5/12/91
  * $FreeBSD: src/sys/i386/i386/pmap.c,v 1.250.2.18 2002/03/06 22:48:53 silby Exp $
- * $DragonFly: src/sys/platform/pc32/i386/pmap.c,v 1.52 2005/11/07 20:05:51 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/pmap.c,v 1.53 2005/11/14 18:50:03 dillon Exp $
  */
 
 /*
@@ -944,70 +944,6 @@ pmap_dispose_proc(struct proc *p)
        return(td);
 }
 
-/*
- * Allow the UPAGES for a process to be prejudicially paged out.
- */
-void
-pmap_swapout_proc(struct proc *p)
-{
-#if 0
-       int i;
-       int s;
-       vm_object_t upobj;
-       vm_page_t m;
-
-       upobj = p->p_upages_obj;
-
-       /*
-        * Unwiring the pages allow them to be paged to their backing store
-        * (swap).
-        */
-       crit_enter();
-       for (i = 0; i < UPAGES; i++) {
-               if ((m = vm_page_lookup(upobj, i)) == NULL)
-                       panic("pmap_swapout_proc: upage already missing???");
-               vm_page_dirty(m);
-               vm_page_unwire(m, 0);
-               pmap_kremove((vm_offset_t)p->p_addr + (PAGE_SIZE * i));
-       }
-       crit_exit();
-#endif
-}
-
-/*
- * Bring the UPAGES for a specified process back in.
- */
-void
-pmap_swapin_proc(struct proc *p)
-{
-#if 0
-       int i,rv;
-       vm_object_t upobj;
-       vm_page_t m;
-
-       crit_enter();
-       upobj = p->p_upages_obj;
-       for (i = 0; i < UPAGES; i++) {
-               m = vm_page_grab(upobj, i, VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
-
-               pmap_kenter((vm_offset_t)p->p_addr + (i * PAGE_SIZE),
-                       VM_PAGE_TO_PHYS(m));
-
-               if (m->valid != VM_PAGE_BITS_ALL) {
-                       rv = vm_pager_get_pages(upobj, &m, 1, 0);
-                       if (rv != VM_PAGER_OK)
-                               panic("pmap_swapin_proc: cannot get upages for proc: %d\n", p->p_pid);
-                       m = vm_page_lookup(upobj, i);
-                       m->valid = VM_PAGE_BITS_ALL;
-               }
-               vm_page_wire(m);
-               vm_page_wakeup(m);
-               vm_page_flag_set(m, PG_MAPPED | PG_WRITEABLE);
-       }
-       crit_exit();
-#endif
-}
-
 /***************************************************
  * Page table page management routines.....
  ***************************************************/
@@ -1166,6 +1102,10 @@ pmap_pinit2(struct pmap *pmap)
        bcopy(PTD + KPTDI, pmap->pm_pdir + KPTDI, nkpt * PTESIZE);
 }
 
+/*
+ * Attempt to release and free and vm_page in a pmap.  Returns 1 on success,
+ * 0 on failure (if the procedure had to sleep).
+ */
 static int
 pmap_release_free_page(struct pmap *pmap, vm_page_t p)
 {
@@ -1361,18 +1301,20 @@ retry:
                        ptdpg = p;
                        continue;
                }
-               while (1) {
-                       if (!pmap_release_free_page(pmap, p) &&
-                           (object->generation != curgeneration)) {
-                               crit_exit();
-                               goto retry;
-                       }
+               if (!pmap_release_free_page(pmap, p)) {
+                       crit_exit();
+                       goto retry;
+               }
+               if (object->generation != curgeneration) {
+                       crit_exit();
+                       goto retry;
                }
        }
-       crit_exit();
-
-       if (ptdpg && !pmap_release_free_page(pmap, ptdpg))
+       if (ptdpg && !pmap_release_free_page(pmap, ptdpg)) {
+               crit_exit();
                goto retry;
+       }
+       crit_exit();
 }
 \f
 static int
index 8c514a6..0937dec 100644 (file)
@@ -38,7 +38,7 @@
  *
  * From:
  * $FreeBSD: src/sys/i386/i386/procfs_machdep.c,v 1.14 1999/10/11 14:50:03 peter Exp $
- * $DragonFly: src/sys/platform/pc32/i386/procfs_machdep.c,v 1.4 2005/10/27 03:15:47 sephe Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/procfs_machdep.c,v 1.5 2005/11/14 18:50:03 dillon Exp $
  */
 
 /*
@@ -86,7 +86,7 @@ procfs_read_regs(p, regs)
        struct proc *p;
        struct reg *regs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (fill_regs(&p->p_lwp, regs));
 }
@@ -96,7 +96,7 @@ procfs_write_regs(p, regs)
        struct proc *p;
        struct reg *regs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (set_regs(&p->p_lwp, regs));
 }
@@ -106,7 +106,7 @@ procfs_read_dbregs(p, dbregs)
        struct proc *p;
        struct dbreg *dbregs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (fill_dbregs(&p->p_lwp, dbregs));
 }
@@ -116,7 +116,7 @@ procfs_write_dbregs(p, dbregs)
        struct proc *p;
        struct dbreg *dbregs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (set_dbregs(&p->p_lwp, dbregs));
 }
@@ -131,7 +131,7 @@ procfs_read_fpregs(p, fpregs)
        struct proc *p;
        struct fpreg *fpregs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (fill_fpregs(&p->p_lwp, fpregs));
 }
@@ -141,7 +141,7 @@ procfs_write_fpregs(p, fpregs)
        struct proc *p;
        struct fpreg *fpregs;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (set_fpregs(&p->p_lwp, fpregs));
 }
@@ -150,7 +150,7 @@ int
 procfs_sstep(p)
        struct proc *p;
 {
-       if ((p->p_flag & P_INMEM) == 0)
+       if (p->p_flag & P_SWAPPEDOUT)
                return (EIO);
        return (ptrace_single_step(&p->p_lwp));
 }
index 8619cf2..9b0c0c6 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)trap.c        7.4 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $
- * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.65 2005/11/04 08:57:27 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.66 2005/11/14 18:50:03 dillon Exp $
  */
 
 /*
@@ -213,34 +213,55 @@ userret(struct lwp *lp, struct trapframe *frame, int sticks)
        struct proc *p = lp->lwp_proc;
        int sig;
 
+       /*
+        * Charge system time if profiling.  Note: times are in microseconds.
+        * This may do a copyout and block, so do it first even though it
+        * means some system time will be charged as user time.
+        */
+       if (p->p_flag & P_PROFIL) {
+               addupc_task(p, frame->tf_eip, 
+                       (u_int)((int)p->p_thread->td_sticks - sticks));
+       }
+
+recheck:
+       /*
+        * Block here if we are in a stopped state.
+        */
+       if (p->p_flag & P_STOPPED) {
+               tstop(p);
+               goto recheck;
+       }
+
        /*
         * Post any pending upcalls
         */
        if (p->p_flag & P_UPCALLPEND) {
                p->p_flag &= ~P_UPCALLPEND;
                postupcall(lp);
+               goto recheck;
        }
 
        /*
         * Post any pending signals
         */
-       while ((sig = CURSIG(p)) != 0) {
+       if ((sig = CURSIG(p)) != 0) {
                postsig(sig);
+               goto recheck;
        }
 
        /*
-        * Charge system time if profiling.  Note: times are in microseconds.
+        * block here if we are swapped out, but still process signals
+        * (such as SIGKILL).  proc0 (the swapin scheduler) is already
+        * aware of our situation, we do not have to wake it up.
         */
-       if (p->p_flag & P_PROFIL) {
-               addupc_task(p, frame->tf_eip, 
-                       (u_int)((int)p->p_thread->td_sticks - sticks));
+       if (p->p_flag & P_SWAPPEDOUT) {
+               p->p_flag |= P_SWAPWAIT;
+               swapin_request();
+               if (p->p_flag & P_SWAPWAIT)
+                       tsleep(p, PCATCH, "SWOUT", 0);
+               p->p_flag &= ~P_SWAPWAIT;
+               goto recheck;
        }
-
-       /*
-        * Post any pending signals XXX
-        */
-       while ((sig = CURSIG(p)) != 0)
-               postsig(sig);
 }
 
 /*
index fbe9b02..2526705 100644 (file)
@@ -40,7 +40,7 @@
  *
  *     @(#)kernel.h    8.3 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/sys/kernel.h,v 1.63.2.9 2002/07/02 23:00:30 archie Exp $
- * $DragonFly: src/sys/sys/kernel.h,v 1.17 2005/06/10 23:59:33 dillon Exp $
+ * $DragonFly: src/sys/sys/kernel.h,v 1.18 2005/11/14 18:50:11 dillon Exp $
  */
 
 #ifndef _SYS_KERNEL_H_
@@ -76,6 +76,7 @@ extern int stathz;                    /* statistics clock's frequency */
 extern int profhz;                     /* profiling clock's frequency */
 extern int ticks;
 extern int lbolt;                      /* once a second sleep address */
+extern int lbolt_syncer;               /* approx 1 hz but may be sped up */
 
 #endif /* _KERNEL */
 
index 5e13cb7..1182ce4 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.71 2005/11/08 20:47:02 dillon Exp $
+ * $DragonFly: src/sys/sys/proc.h,v 1.72 2005/11/14 18:50:11 dillon Exp $
  */
 
 #ifndef _SYS_PROC_H_
@@ -303,27 +303,31 @@ struct    proc {
 #define        p_pgid          p_pgrp->pg_id
 #endif
 
-/* Status values. */
+/*
+ * Status values.   Please note that p_stat doesn't actually take on
+ * synthesized states.
+ */
 #define        SIDL    1               /* Process being created by fork. */
 #define        SRUN    2               /* Currently runnable. */
 #define        SSLEEP  3               /* Sleeping on an address. */
-#define        SSTOP   4               /* Process debugging or suspension. */
+#define        SSTOP   4               /* Synthesized from SSLEEP + P_STOPPED */
 #define        SZOMB   5               /* Awaiting collection by parent. */
 #define STHREAD        6               /* Synthesized for eproc only */
 
 /* These flags are kept in p_flags. */
 #define        P_ADVLOCK       0x00001 /* Process may hold a POSIX advisory lock. */
 #define        P_CONTROLT      0x00002 /* Has a controlling terminal. */
-#define        P_INMEM         0x00004 /* Loaded into memory. */
+#define        P_SWAPPEDOUT    0x00004 /* Swapped out of memory */
+#define P_BREAKTSLEEP  0x00008 /* Event pending, break tsleep on sigcont */
 #define        P_PPWAIT        0x00010 /* Parent is waiting for child to exec/exit. */
 #define        P_PROFIL        0x00020 /* Has started profiling. */
 #define P_SELECT       0x00040 /* Selecting; wakeup/waiting danger. */
 #define        P_SINTR         0x00080 /* Sleep is interruptible. */
 #define        P_SUGID         0x00100 /* Had set id privileges since last exec. */
 #define        P_SYSTEM        0x00200 /* System proc: no sigs, stats or swapping. */
-#define        P_UNUSED00400   0x00400
+#define        P_STOPPED       0x00400 /* SIGSTOP status */
 #define        P_TRACED        0x00800 /* Debugged process being traced. */
-#define        P_WAITED        0x01000 /* Debugging process has waited for child. */
+#define        P_WAITED        0x01000 /* SIGSTOP status was returned by wait3/4 */
 #define        P_WEXIT         0x02000 /* Working on exiting. */
 #define        P_EXEC          0x04000 /* Process called exec. */
 
@@ -333,13 +337,13 @@ struct    proc {
 
 #define        P_UPCALLPEND    0x20000 /* an upcall is pending */
 
-#define        P_SWAPPING      0x40000 /* Process is being swapped. */
-#define        P_SWAPINREQ     0x80000 /* Swapin request due to wakeup */
+#define        P_SWAPWAIT      0x40000 /* Waiting for a swapin */
+#define        P_UNUSED80000   0x80000
 
 /* Marked a kernel thread */
 #define        P_ONRUNQ        0x100000 /* on a user scheduling run queue */
 #define        P_KTHREADP      0x200000 /* Process is really a kernel thread */
-#define P_UNUSED400000 0x400000
+#define P_IDLESWAP     0x400000 /* Swapout was due to idleswap, not load */
 #define        P_DEADLKTREAT   0x800000 /* lock aquisition - deadlock treatment */
 
 #define        P_JAILED        0x1000000 /* Process is in jail */
@@ -393,10 +397,7 @@ extern void stopevent(struct proc*, unsigned int, unsigned int);
        } while (0)
 
 /* hold process U-area in memory, normally for ptrace/procfs work */
-#define PHOLD(p) {                                                     \
-       if ((p)->p_lock++ == 0 && ((p)->p_flag & P_INMEM) == 0) \
-               faultin(p);                                             \
-}
+#define PHOLD(p)       (++(p)->p_lock)
 #define PRELE(p)       (--(p)->p_lock)
 
 #define        PIDHASH(pid)    (&pidhashtbl[(pid) & pidhash])
@@ -457,14 +458,13 @@ void      procinit (void);
 void   relscurproc(struct proc *curp);
 int    p_trespass (struct ucred *cr1, struct ucred *cr2);
 void   setrunnable (struct proc *);
-void   clrrunnable (struct proc *, int stat);
+void   clrrunnable (struct proc *);
 void   sleep_gdinit (struct globaldata *);
 int    suser (struct thread *td);
 int    suser_proc (struct proc *p);
 int    suser_cred (struct ucred *cred, int flag);
 void   cpu_heavy_switch (struct thread *);
 void   cpu_lwkt_switch (struct thread *);
-void   unsleep (struct thread *);
 
 void   cpu_proc_exit (void) __dead2;
 void   cpu_thread_exit (void) __dead2;
@@ -480,6 +480,7 @@ void        cpu_thread_wait (struct thread *);
 int    cpu_coredump (struct thread *, struct vnode *, struct ucred *);
 void   setsugid (void);
 void   faultin (struct proc *p);
+void   swapin_request (void);
 
 u_int32_t      procrunnable (void);
 
index 0f4fe26..6bcb29c 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)systm.h     8.7 (Berkeley) 3/29/95
  * $FreeBSD: src/sys/sys/systm.h,v 1.111.2.18 2002/12/17 18:04:02 sam Exp $
- * $DragonFly: src/sys/sys/systm.h,v 1.32 2005/10/24 21:57:54 eirikn Exp $
+ * $DragonFly: src/sys/sys/systm.h,v 1.33 2005/11/14 18:50:11 dillon Exp $
  */
 
 #ifndef _SYS_SYSTM_H_
@@ -297,6 +297,7 @@ extern watchdog_tickle_fn   wdog_tickler;
  * less often.
  */
 int    tsleep (void *chan, int slpflags, const char *wmesg, int timo);
+void   tstop (struct proc *);
 void   wakeup (void *chan);
 void   wakeup_one (void *chan);
 void   wakeup_domain (void *chan, int domain);
index ec1a2ed..3fda7d6 100644 (file)
@@ -7,7 +7,7 @@
  * Types which must already be defined when this header is included by
  * userland:   struct md_thread
  * 
- * $DragonFly: src/sys/sys/thread.h,v 1.72 2005/11/08 22:40:00 dillon Exp $
+ * $DragonFly: src/sys/sys/thread.h,v 1.73 2005/11/14 18:50:11 dillon Exp $
  */
 
 #ifndef _SYS_THREAD_H_
@@ -279,6 +279,11 @@ struct thread {
  * LWKT threads stay on their (per-cpu) run queue while running, not to
  * be confused with user processes which are removed from the user scheduling
  * run queue while actually running.
+ *
+ * td_threadq can represent the thread on one of three queues... the LWKT
+ * run queue, a tsleep queue, or an lwkt blocking queue.  The LWKT subsystem
+ * does not allow a thread to be scheduled if it already resides on some
+ * queue.
  */
 #define TDF_RUNNING            0x0001  /* thread still active */
 #define TDF_RUNQ               0x0002  /* on an LWKT run queue */
@@ -287,6 +292,7 @@ struct thread {
 #define TDF_IDLE_NOHLT         0x0010  /* we need to spin */
 #define TDF_MIGRATING          0x0020  /* thread is being migrated */
 #define TDF_SINTR              0x0040  /* interruptability hint for 'ps' */
+#define TDF_TSLEEPQ            0x0080  /* on a tsleep wait queue */
 
 #define TDF_SYSTHREAD          0x0100  /* system thread */
 #define TDF_ALLOCATED_THREAD   0x0200  /* zalloc allocated thread */
@@ -300,6 +306,7 @@ struct thread {
 #define TDF_NORESCHED          0x00020000      /* Do not reschedule on wake */
 #define TDF_BLOCKED            0x00040000      /* Thread is blocked */
 #define TDF_PANICWARN          0x00080000      /* panic warning in switch */
+#define TDF_BLOCKQ             0x00100000      /* on block queue */
 
 /*
  * Thread priorities.  Typically only one thread from any given
index 943d35b..bb4a9dd 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.7 2004/05/02 03:05:11 cpressey Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_ctl.c,v 1.8 2005/11/14 18:50:13 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -60,7 +60,7 @@
  * relative to process (curp)
  */
 #define TRACE_WAIT_P(curp, p) \
-       ((p)->p_stat == SSTOP && \
+       (((p)->p_flag & P_STOPPED) && \
         (p)->p_pptr == (curp) && \
         ((p)->p_flag & P_TRACED))
 
@@ -246,7 +246,7 @@ procfs_control(struct proc *curp, struct proc *p, int op)
                error = 0;
                if (p->p_flag & P_TRACED) {
                        while (error == 0 &&
-                                       (p->p_stat != SSTOP) &&
+                                       (p->p_flag & P_STOPPED) == 0 &&
                                        (p->p_flag & P_TRACED) &&
                                        (p->p_pptr == curp)) {
                                error = tsleep((caddr_t) p,
@@ -255,7 +255,7 @@ procfs_control(struct proc *curp, struct proc *p, int op)
                        if (error == 0 && !TRACE_WAIT_P(curp, p))
                                error = EBUSY;
                } else {
-                       while (error == 0 && p->p_stat != SSTOP) {
+                       while (error == 0 && (p->p_flag & P_STOPPED) == 0) {
                                error = tsleep((caddr_t) p,
                                                PCATCH, "procfs", 0);
                        }
@@ -266,7 +266,12 @@ procfs_control(struct proc *curp, struct proc *p, int op)
                panic("procfs_control");
        }
 
-       if (p->p_stat == SSTOP)
+       /*
+        * If the process is in a stopped state, make it runnable again.
+        * Do not set P_BREAKTSLEEP - that is, do not break a tsleep that
+        * might be in progress.
+        */
+       if (p->p_flag & P_STOPPED)
                setrunnable(p);
        return (0);
 }
@@ -310,6 +315,10 @@ procfs_doctl(struct proc *curp, struct proc *p, struct pfsnode *pfs,
 #ifdef FIX_SSTEP
                                FIX_SSTEP(p);
 #endif
+                               /*
+                                * Make the process runnable but do not
+                                * break its tsleep.
+                                */
                                setrunnable(p);
                        } else {
                                psignal(p, nm->nm_val);
index 538eb11..c255d49 100644 (file)
@@ -41,7 +41,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/miscfs/procfs/procfs_dbregs.c,v 1.4.2.3 2002/01/22 17:22:59 nectar Exp $
- * $DragonFly: src/sys/vfs/procfs/procfs_dbregs.c,v 1.6 2004/05/02 03:05:11 cpressey Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_dbregs.c,v 1.7 2005/11/14 18:50:13 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -78,7 +78,7 @@ procfs_dodbregs(struct proc *curp, struct proc *p, struct pfsnode *pfs,
        if (error == 0)
                error = uiomove_frombuf(&r, sizeof(r), uio);
        if (error == 0 && uio->uio_rw == UIO_WRITE) {
-               if (p->p_stat != SSTOP)
+               if ((p->p_flag & P_STOPPED) == 0)
                        error = EBUSY;
                else
                        error = procfs_write_dbregs(p, &r);
index 7c8514f..c5619dd 100644 (file)
@@ -38,7 +38,7 @@
  *
  * From:
  * $FreeBSD: src/sys/miscfs/procfs/procfs_fpregs.c,v 1.11.2.3 2002/01/22 17:22:59 nectar Exp $
- * $DragonFly: src/sys/vfs/procfs/procfs_fpregs.c,v 1.6 2004/05/02 03:05:11 cpressey Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_fpregs.c,v 1.7 2005/11/14 18:50:13 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -75,7 +75,7 @@ procfs_dofpregs(struct proc *curp, struct proc *p, struct pfsnode *pfs,
        if (error == 0)
                error = uiomove_frombuf(&r, sizeof(r), uio);
        if (error == 0 && uio->uio_rw == UIO_WRITE) {
-               if (p->p_stat != SSTOP)
+               if ((p->p_flag & P_STOPPED) == 0)
                        error = EBUSY;
                else
                        error = procfs_write_fpregs(p, &r);
index 719378e..1f5a78b 100644 (file)
@@ -38,7 +38,7 @@
  *
  * From:
  * $FreeBSD: src/sys/miscfs/procfs/procfs_regs.c,v 1.10.2.3 2002/01/22 17:22:59 nectar Exp $
- * $DragonFly: src/sys/vfs/procfs/procfs_regs.c,v 1.7 2004/05/02 03:05:11 cpressey Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_regs.c,v 1.8 2005/11/14 18:50:13 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -77,7 +77,7 @@ procfs_doregs(struct proc *curp, struct proc *p, struct pfsnode *pfs,
        if (error == 0)
                error = uiomove_frombuf(&r, sizeof(r), uio);
        if (error == 0 && uio->uio_rw == UIO_WRITE) {
-               if (p->p_stat != SSTOP)
+               if ((p->p_flag & P_STOPPED) == 0)
                        error = EBUSY;
                else
                        error = procfs_write_regs(p, &r);
index 163819d..ca17d19 100644 (file)
@@ -38,7 +38,7 @@
  *
  * From:
  * $FreeBSD: src/sys/miscfs/procfs/procfs_status.c,v 1.20.2.4 2002/01/22 17:22:59 nectar Exp $
- * $DragonFly: src/sys/vfs/procfs/procfs_status.c,v 1.10 2005/10/08 19:46:51 corecode Exp $
+ * $DragonFly: src/sys/vfs/procfs/procfs_status.c,v 1.11 2005/11/14 18:50:13 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -119,7 +119,10 @@ procfs_dostatus(struct proc *curp, struct proc *p, struct pfsnode *pfs,
                DOCHECK();
        }
 
-       if (p->p_flag & P_INMEM) {
+       if (p->p_flag & P_SWAPPEDOUT) {
+               ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
+                   " -1,-1 -1,-1 -1,-1");
+       } else {
                struct timeval ut, st;
 
                calcru(p, &ut, &st, (struct timeval *) NULL);
@@ -129,9 +132,7 @@ procfs_dostatus(struct proc *curp, struct proc *p, struct pfsnode *pfs,
                    p->p_start.tv_usec,
                    ut.tv_sec, ut.tv_usec,
                    st.tv_sec, st.tv_usec);
-       } else
-               ps += snprintf(ps, psbuf + sizeof(psbuf) - ps,
-                   " -1,-1 -1,-1 -1,-1");
+       }
        DOCHECK();
 
        ps += snprintf(ps, psbuf + sizeof(psbuf) - ps, " %s",
index 7e08ada..b0922c6 100644 (file)
@@ -62,7 +62,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/pmap.h,v 1.33.2.4 2002/03/06 22:44:24 silby Exp $
- * $DragonFly: src/sys/vm/pmap.h,v 1.15 2005/05/05 22:57:45 swildner Exp $
+ * $DragonFly: src/sys/vm/pmap.h,v 1.16 2005/11/14 18:50:15 dillon Exp $
  */
 
 /*
@@ -142,8 +142,6 @@ int          pmap_mincore (pmap_t pmap, vm_offset_t addr);
 void            pmap_init_proc (struct proc *p, struct thread *td);
 void            pmap_init_thread (struct thread *td);
 struct thread  *pmap_dispose_proc (struct proc *p);
-void            pmap_swapout_proc (struct proc *p);
-void            pmap_swapin_proc (struct proc *p);
 void            pmap_activate (struct proc *p);
 vm_offset_t     pmap_addr_hint (vm_object_t obj, vm_offset_t addr, vm_size_t size);
 void           *pmap_kenter_temporary (vm_paddr_t pa, int i);
index f87bf95..840ae41 100644 (file)
@@ -67,7 +67,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/vm_fault.c,v 1.108.2.8 2002/02/26 05:49:27 silby Exp $
- * $DragonFly: src/sys/vm/vm_fault.c,v 1.19 2005/10/24 20:02:09 dillon Exp $
+ * $DragonFly: src/sys/vm/vm_fault.c,v 1.20 2005/11/14 18:50:15 dillon Exp $
  */
 
 /*
@@ -901,7 +901,8 @@ readrest:
                vm_page_activate(fs.m);
        }
 
-       if (curproc && (curproc->p_flag & P_INMEM) && curproc->p_stats) {
+       if (curproc && (curproc->p_flag & P_SWAPPEDOUT) == 0 &&
+           curproc->p_stats) {
                if (hardfault) {
                        curproc->p_stats->p_ru.ru_majflt++;
                } else {
index 43311b2..665c5a7 100644 (file)
@@ -60,7 +60,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/vm_glue.c,v 1.94.2.4 2003/01/13 22:51:17 dillon Exp $
- * $DragonFly: src/sys/vm/vm_glue.c,v 1.35 2005/10/11 09:59:56 corecode Exp $
+ * $DragonFly: src/sys/vm/vm_glue.c,v 1.36 2005/11/14 18:50:15 dillon Exp $
  */
 
 #include "opt_vm.h"
@@ -110,6 +110,15 @@ SYSINIT(vm_limits, SI_SUB_VM_CONF, SI_ORDER_FIRST, vm_init_limits, &proc0)
 static void scheduler (void *);
 SYSINIT(scheduler, SI_SUB_RUN_SCHEDULER, SI_ORDER_FIRST, scheduler, NULL)
 
+#ifdef INVARIANTS
+
+static int swap_debug = 0;
+SYSCTL_INT(_vm, OID_AUTO, swap_debug,
+       CTLFLAG_RW, &swap_debug, 0, "");
+
+#endif
+
+static int scheduler_notify;
 
 static void swapout (struct proc *);
 
@@ -307,30 +316,31 @@ vm_init_limits(void *udata)
        p->p_rlimit[RLIMIT_RSS].rlim_max = RLIM_INFINITY;
 }
 
+/*
+ * Faultin the specified process.  Note that the process can be in any
+ * state.  Just clear P_SWAPPEDOUT and call wakeup in case the process is
+ * sleeping.
+ */
 void
 faultin(struct proc *p)
 {
-       if ((p->p_flag & P_INMEM) == 0) {
-
-               ++p->p_lock;
-
-               pmap_swapin_proc(p);
-
-               crit_enter();
-
+       if (p->p_flag & P_SWAPPEDOUT) {
+               PHOLD(p);
                /*
-                * The process is in the kernel and controlled by LWKT,
-                * so we just schedule it rather then call setrunqueue().
+                * The process is waiting in the kernel to return to user
+                * mode but cannot until P_SWAPPEDOUT gets cleared.
                 */
-               if (p->p_stat == SRUN)
-                       lwkt_schedule(p->p_thread);
-
-               p->p_flag |= P_INMEM;
+               crit_enter();
+               p->p_flag &= ~(P_SWAPPEDOUT | P_SWAPWAIT);
+#ifdef INVARIANTS
+               if (swap_debug)
+                       printf("swapping in %d (%s)\n", p->p_pid, p->p_comm);
+#endif
+               wakeup(p);
 
                /* undo the effect of setting SLOCK above */
-               --p->p_lock;
+               PRELE(p);
                crit_exit();
-
        }
 }
 
@@ -342,31 +352,48 @@ faultin(struct proc *p)
  * is enough space for them.  Of course, if a process waits for a long
  * time, it will be swapped in anyway.
  */
+
 /* ARGSUSED*/
 static void
 scheduler(void *dummy)
 {
        struct proc *p;
-       int pri;
        struct proc *pp;
+       int pri;
        int ppri;
+       segsz_t pgs;
 
        KKASSERT(!IN_CRITICAL_SECT(curthread));
 loop:
+       scheduler_notify = 0;
+       /*
+        * Don't try to swap anything in if we are low on memory.
+        */
        if (vm_page_count_min()) {
                vm_wait();
                goto loop;
        }
 
+       /*
+        * Look for a good candidate to wake up
+        */
        pp = NULL;
        ppri = INT_MIN;
        for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
-               if (p->p_stat == SRUN &&
-                       (p->p_flag & (P_INMEM | P_SWAPPING)) == 0) {
+               if (p->p_flag & P_SWAPWAIT) {
+                       pri = p->p_swtime + p->p_slptime - p->p_nice * 8;
 
-                       pri = p->p_swtime + p->p_slptime;
-                       if ((p->p_flag & P_SWAPINREQ) == 0) {
-                               pri -= p->p_nice * 8;
+                       /*
+                        * The more pages paged out while we were swapped,
+                        * the more work we have to do to get up and running
+                        * again and the lower our wakeup priority.
+                        *
+                        * Each second of sleep time is worth ~1MB
+                        */
+                       pgs = vmspace_resident_count(p->p_vmspace);
+                       if (pgs < p->p_vmspace->vm_swrss) {
+                               pri -= (p->p_vmspace->vm_swrss - pgs) /
+                                       (1024 * 1024 / PAGE_SIZE);
                        }
 
                        /*
@@ -382,27 +409,45 @@ loop:
        }
 
        /*
-        * Nothing to do, back to sleep.
+        * Nothing to do, back to sleep for at least 1/10 of a second.  If
+        * we are woken up, immediately process the next request.  If
+        * multiple requests have built up the first is processed 
+        * immediately and the rest are staggered.
         */
        if ((p = pp) == NULL) {
-               tsleep(&proc0, 0, "sched", 0);
+               tsleep(&proc0, 0, "nowork", hz / 10);
+               if (scheduler_notify == 0)
+                       tsleep(&scheduler_notify, 0, "nowork", 0);
                goto loop;
        }
-       p->p_flag &= ~P_SWAPINREQ;
 
        /*
-        * We would like to bring someone in. (only if there is space).
+        * Fault the selected process in, then wait for a short period of
+        * time and loop up.
+        *
+        * XXX we need a heuristic to get a measure of system stress and
+        * then adjust our stagger wakeup delay accordingly.
         */
        faultin(p);
        p->p_swtime = 0;
+       tsleep(&proc0, 0, "swapin", hz / 10);
        goto loop;
 }
 
+void
+swapin_request(void)
+{
+       if (scheduler_notify == 0) {
+               scheduler_notify = 1;
+               wakeup(&scheduler_notify);
+       }
+}
+
 #ifndef NO_SWAPPING
 
 #define        swappable(p) \
        (((p)->p_lock == 0) && \
-               ((p)->p_flag & (P_TRACED|P_SYSTEM|P_INMEM|P_WEXIT|P_SWAPPING)) == P_INMEM)
+       ((p)->p_flag & (P_TRACED|P_SYSTEM|P_SWAPPEDOUT|P_WEXIT)) == 0)
 
 
 /*
@@ -414,16 +459,19 @@ SYSCTL_INT(_vm, OID_AUTO, swap_idle_threshold1,
 
 /*
  * Swap_idle_threshold2 is the time that a process can be idle before
- * it will be swapped out, if idle swapping is enabled.
+ * it will be swapped out, if idle swapping is enabled.  Default is
+ * one minute.
  */
-static int swap_idle_threshold2 = 10;
+static int swap_idle_threshold2 = 60;
 SYSCTL_INT(_vm, OID_AUTO, swap_idle_threshold2,
        CTLFLAG_RW, &swap_idle_threshold2, 0, "");
 
 /*
  * Swapout is driven by the pageout daemon.  Very simple, we find eligible
- * procs and unwire their u-areas.  We try to always "swap" at least one
- * process in case we need the room for a swapin.
+ * procs and mark them as being swapped out.  This will cause the kernel
+ * to prefer to pageout those proc's pages first and the procs in question 
+ * will not return to user mode until the swapper tells them they can.
+ *
  * If any procs have been sleeping/stopped for at least maxslp seconds,
  * they are swapped.  Else, we swap the longest-sleeping or stopped process,
  * if any, otherwise the longest-resident process.
@@ -434,7 +482,6 @@ swapout_procs(int action)
        struct proc *p;
        struct proc *outp, *outp2;
        int outpri, outpri2;
-       int didswap = 0;
 
        outp = outp2 = NULL;
        outpri = outpri2 = INT_MIN;
@@ -446,22 +493,14 @@ retry:
 
                vm = p->p_vmspace;
 
-               switch (p->p_stat) {
-               default:
-                       continue;
-
-               case SSLEEP:
-               case SSTOP:
+               if (p->p_stat == SSLEEP || p->p_stat == SRUN) {
                        /*
-                        * do not swapout a realtime process
+                        * do not swap out a realtime process
                         */
-                       if (RTP_PRIO_IS_REALTIME(p->p_rtprio.type))
+                       if (RTP_PRIO_IS_REALTIME(p->p_lwp.lwp_rtprio.type))
                                continue;
 
                        /*
-                        * YYY do not swapout a proc waiting on a critical
-                        * event.
-                        *
                         * Guarentee swap_idle_threshold time in memory
                         */
                        if (p->p_slptime < swap_idle_threshold1)
@@ -473,32 +512,22 @@ retry:
                         * then swap the process out.
                         */
                        if (((action & VM_SWAP_NORMAL) == 0) &&
-                               (((action & VM_SWAP_IDLE) == 0) ||
-                                 (p->p_slptime < swap_idle_threshold2)))
+                           (((action & VM_SWAP_IDLE) == 0) ||
+                            (p->p_slptime < swap_idle_threshold2))) {
                                continue;
+                       }
 
                        ++vm->vm_refcnt;
+
                        /*
-                        * do not swapout a process that is waiting for VM
-                        * data structures there is a possible deadlock.
-                        */
-                       if (lockmgr(&vm->vm_map.lock,
-                                       LK_EXCLUSIVE | LK_NOWAIT,
-                                       NULL, curthread)) {
-                               vmspace_free(vm);
-                               continue;
-                       }
-                       vm_map_unlock(&vm->vm_map);
-                       /*
-                        * If the process has been asleep for awhile and had
-                        * most of its pages taken away already, swap it out.
+                        * If the process has been asleep for awhile, swap
+                        * it out.
                         */
                        if ((action & VM_SWAP_NORMAL) ||
-                               ((action & VM_SWAP_IDLE) &&
-                                (p->p_slptime > swap_idle_threshold2))) {
+                           ((action & VM_SWAP_IDLE) &&
+                            (p->p_slptime > swap_idle_threshold2))) {
                                swapout(p);
                                vmspace_free(vm);
-                               didswap++;
                                goto retry;
                        }
 
@@ -508,37 +537,23 @@ retry:
                        vmspace_free(vm);
                }
        }
-       /*
-        * If we swapped something out, and another process needed memory,
-        * then wakeup the sched process.
-        */
-       if (didswap)
-               wakeup(&proc0);
 }
 
 static void
 swapout(struct proc *p)
 {
-
-#if defined(SWAP_DEBUG)
-       printf("swapping out %d\n", p->p_pid);
+#ifdef INVARIANTS
+       if (swap_debug)
+               printf("swapping out %d (%s)\n", p->p_pid, p->p_comm);
 #endif
        ++p->p_stats->p_ru.ru_nswap;
        /*
         * remember the process resident count
         */
        p->p_vmspace->vm_swrss = vmspace_resident_count(p->p_vmspace);
-
-       crit_enter();
-       p->p_flag &= ~P_INMEM;
-       p->p_flag |= P_SWAPPING;
-       if (p->p_flag & P_ONRUNQ)
-               p->p_usched->remrunqueue(&p->p_lwp);
-       crit_exit();
-
-       pmap_swapout_proc(p);
-
-       p->p_flag &= ~P_SWAPPING;
+       p->p_flag |= P_SWAPPEDOUT;
        p->p_swtime = 0;
 }
+
 #endif /* !NO_SWAPPING */
+
index 05516e3..07ce932 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)vm_meter.c  8.4 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/vm/vm_meter.c,v 1.34.2.7 2002/10/10 19:28:22 dillon Exp $
- * $DragonFly: src/sys/vm/vm_meter.c,v 1.7 2003/07/19 21:14:53 dillon Exp $
+ * $DragonFly: src/sys/vm/vm_meter.c,v 1.8 2005/11/14 18:50:15 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -106,24 +106,24 @@ do_vmtotal(SYSCTL_HANDLER_ARGS)
                        continue;
 
                case SSLEEP:
-               case SSTOP:
-                       if (p->p_flag & P_INMEM) {
+                       if ((p->p_flag & P_SWAPPEDOUT) == 0) {
                                if ((p->p_flag & P_SINTR) == 0)
                                        totalp->t_dw++;
                                else if (p->p_slptime < maxslp)
                                        totalp->t_sl++;
-                       } else if (p->p_slptime < maxslp)
+                       } else if (p->p_slptime < maxslp) {
                                totalp->t_sw++;
+                       }
                        if (p->p_slptime >= maxslp)
                                continue;
                        break;
 
                case SRUN:
                case SIDL:
-                       if (p->p_flag & P_INMEM)
-                               totalp->t_rq++;
-                       else
+                       if (p->p_flag & P_SWAPPEDOUT)
                                totalp->t_sw++;
+                       else
+                               totalp->t_rq++;
                        if (p->p_stat == SIDL)
                                continue;
                        break;
index 1d776d1..99c2587 100644 (file)
@@ -66,7 +66,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/vm_pageout.c,v 1.151.2.15 2002/12/29 18:21:04 dillon Exp $
- * $DragonFly: src/sys/vm/vm_pageout.c,v 1.15 2005/10/11 09:59:56 corecode Exp $
+ * $DragonFly: src/sys/vm/vm_pageout.c,v 1.16 2005/11/14 18:50:15 dillon Exp $
  */
 
 /*
@@ -1472,11 +1472,11 @@ vm_daemon(void)
 
                        /*
                         * let processes that are swapped out really be
-                        * swapped out set the limit to nothing (will force a
-                        * swap-out.)
+                        * swapped out.  Set the limit to nothing to get as
+                        * many pages out to swap as possible.
                         */
-                       if ((p->p_flag & P_INMEM) == 0)
-                               limit = 0;      /* XXX */
+                       if (p->p_flag & P_SWAPPEDOUT)
+                               limit = 0;
 
                        size = vmspace_resident_count(p->p_vmspace);
                        if (limit >= 0 && size >= limit) {
index 12af191..24bce44 100644 (file)
@@ -32,7 +32,7 @@
  *
  * @(#)pigs.c  8.2 (Berkeley) 9/23/93
  *
- * $DragonFly: src/usr.bin/systat/pigs.c,v 1.10 2005/05/07 22:50:05 corecode Exp $
+ * $DragonFly: src/usr.bin/systat/pigs.c,v 1.11 2005/11/14 18:50:17 dillon Exp $
  */
 
 /*
@@ -211,7 +211,7 @@ fetchpigs(void)
                pp = &kpp[i].kp_proc;
                pctp = &pt[i].pt_pctcpu;
                time = pp->p_swtime;
-               if (time == 0 || (pp->p_flag & P_INMEM) == 0)
+               if (time == 0 || (pp->p_flag & P_SWAPPEDOUT))
                        *pctp = 0;
                else
                        *pctp = ((double) pp->p_pctcpu /
index 4f84add..fefa0f4 100644 (file)
@@ -21,7 +21,7 @@
  *          Hiten Pandya <hmp@backplane.com>
  *
  * $FreeBSD: src/usr.bin/top/machine.c,v 1.29.2.2 2001/07/31 20:27:05 tmm Exp $
- * $DragonFly: src/usr.bin/top/machine.c,v 1.17 2005/08/31 17:20:18 liamfoy Exp $
+ * $DragonFly: src/usr.bin/top/machine.c,v 1.18 2005/11/14 18:50:18 dillon Exp $
  */
 
 
@@ -522,7 +522,7 @@ char *format_next_process(caddr_t handle, char *(*get_userid)())
     hp->remaining--;
     
     /* set the wrapper for the process/thread name */
-    if ((PP(pp, p_flag) & P_INMEM) == 0)
+    if ((PP(pp, p_flag) & P_SWAPPEDOUT))
         wrapper = "[]"; /* swapped process [pname] */
     else if (((PP(pp, p_flag) & P_SYSTEM) != 0) && (TP(pp, td_proc) != NULL))
         wrapper = "()"; /* system process (pname) */