From: Matthew Dillon Date: Mon, 14 Nov 2005 18:50:18 +0000 (+0000) Subject: Make tsleep/wakeup() MP SAFE for kernel threads and get us closer to X-Git-Tag: v2.0.1~5651 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/344ad853388ea34261cc85d903fa9e4cb0ef2198 Make tsleep/wakeup() MP SAFE for kernel threads and get us closer to 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 --- diff --git a/bin/ps/print.c b/bin/ps/print.c index a93999dcad..80738cf9ac 100644 --- a/bin/ps/print.c +++ b/bin/ps/print.c @@ -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 @@ -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; diff --git a/bin/ps/ps.1 b/bin/ps/ps.1 index 39e267715a..70c9564779 100644 --- a/bin/ps/ps.1 +++ b/bin/ps/ps.1 @@ -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" diff --git a/bin/ps/ps.c b/bin/ps/ps.c index 790aa9ebbf..e05917d001 100644 --- a/bin/ps/ps.c +++ b/bin/ps/ps.c @@ -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 @@ -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. diff --git a/sys/dev/raid/vinum/vinumdaemon.c b/sys/dev/raid/vinum/vinumdaemon.c index c6ad6f8ccf..90a8398090 100644 --- a/sys/dev/raid/vinum/vinumdaemon.c +++ b/sys/dev/raid/vinum/vinumdaemon.c @@ -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) { diff --git a/sys/emulation/linux/i386/linux_ptrace.c b/sys/emulation/linux/i386/linux_ptrace.c index 971b3a1781..bb68b33f72 100644 --- a/sys/emulation/linux/i386/linux_ptrace.c +++ b/sys/emulation/linux/i386/linux_ptrace.c @@ -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, diff --git a/sys/emulation/posix4/ksched.c b/sys/emulation/posix4/ksched.c index aef99e7ee8..019987392c 100644 --- a/sys/emulation/posix4/ksched.c +++ b/sys/emulation/posix4/ksched.c @@ -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. diff --git a/sys/emulation/svr4/svr4_misc.c b/sys/emulation/svr4/svr4_misc.c index 147f78fba3..4de38e1567 100644 --- a/sys/emulation/svr4/svr4_misc.c +++ b/sys/emulation/svr4/svr4_misc.c @@ -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)); diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c index 20df584fb1..651d4550c9 100644 --- a/sys/i386/i386/db_trace.c +++ b/sys/i386/i386/db_trace.c @@ -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 @@ -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; } diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index f0cb59903d..1968e52b72 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -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(); } static int diff --git a/sys/i386/i386/procfs_machdep.c b/sys/i386/i386/procfs_machdep.c index a01b03714a..1d66c44609 100644 --- a/sys/i386/i386/procfs_machdep.c +++ b/sys/i386/i386/procfs_machdep.c @@ -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)); } diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 997a82eff3..e471d1cce7 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -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); } /* diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 325b089624..90da0c21a1 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -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(); } diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 9c1b52832f..06d65cf36f 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -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; diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index fc305048d7..7a5b1f9a01 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -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); diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 87ee1b867a..1a300fe4d2 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -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 @@ -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); } diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index f7f11e6f12..6676300874 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -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); diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c index 399ac08397..8f8aed9f77 100644 --- a/sys/kern/kern_sched.c +++ b/sys/kern/kern_sched.c @@ -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. diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index e947d931fd..b520329a9b 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -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. diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 1b542bb24a..acc339119b 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -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 #include #include +#include #ifdef KTRACE #include #include @@ -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. diff --git a/sys/kern/lwkt_thread.c b/sys/kern/lwkt_thread.c index 028e5d607d..62026b80b3 100644 --- a/sys/kern/lwkt_thread.c +++ b/sys/kern/lwkt_thread.c @@ -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); diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 596b643e71..e3c877e0c0 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -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(); } } diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 001862b2d6..2dc1cf26ca 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -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 @@ -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); diff --git a/sys/kern/tty.c b/sys/kern/tty.c index cc94e17818..acec586b65 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -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 { diff --git a/sys/kern/usched_bsd4.c b/sys/kern/usched_bsd4.c index 8f987b5485..83fb7d9c24 100644 --- a/sys/kern/usched_bsd4.c +++ b/sys/kern/usched_bsd4.c @@ -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 @@ -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(); } /* diff --git a/sys/kern/vfs_sync.c b/sys/kern/vfs_sync.c index 05bb7cab76..a255184833 100644 --- a/sys/kern/vfs_sync.c +++ b/sys/kern/vfs_sync.c @@ -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; diff --git a/sys/netproto/smb/smb_subr.c b/sys/netproto/smb/smb_subr.c index 60271ab196..a2aad45b4d 100644 --- a/sys/netproto/smb/smb_subr.c +++ b/sys/netproto/smb/smb_subr.c @@ -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 #include @@ -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 */ diff --git a/sys/platform/pc32/i386/db_trace.c b/sys/platform/pc32/i386/db_trace.c index 434e6d0472..b7dc338418 100644 --- a/sys/platform/pc32/i386/db_trace.c +++ b/sys/platform/pc32/i386/db_trace.c @@ -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 @@ -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; } diff --git a/sys/platform/pc32/i386/pmap.c b/sys/platform/pc32/i386/pmap.c index 285647a389..694602501f 100644 --- a/sys/platform/pc32/i386/pmap.c +++ b/sys/platform/pc32/i386/pmap.c @@ -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(); } static int diff --git a/sys/platform/pc32/i386/procfs_machdep.c b/sys/platform/pc32/i386/procfs_machdep.c index 8c514a63ee..0937dec184 100644 --- a/sys/platform/pc32/i386/procfs_machdep.c +++ b/sys/platform/pc32/i386/procfs_machdep.c @@ -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)); } diff --git a/sys/platform/pc32/i386/trap.c b/sys/platform/pc32/i386/trap.c index 8619cf2767..9b0c0c6c2d 100644 --- a/sys/platform/pc32/i386/trap.c +++ b/sys/platform/pc32/i386/trap.c @@ -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); } /* diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h index fbe9b02cfa..2526705c67 100644 --- a/sys/sys/kernel.h +++ b/sys/sys/kernel.h @@ -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 */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 5e13cb7153..1182ce4f6f 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -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); diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 0f4fe26005..6bcb29c51f 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -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); diff --git a/sys/sys/thread.h b/sys/sys/thread.h index ec1a2ed478..3fda7d670b 100644 --- a/sys/sys/thread.h +++ b/sys/sys/thread.h @@ -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 diff --git a/sys/vfs/procfs/procfs_ctl.c b/sys/vfs/procfs/procfs_ctl.c index 943d35bb88..bb4a9dd802 100644 --- a/sys/vfs/procfs/procfs_ctl.c +++ b/sys/vfs/procfs/procfs_ctl.c @@ -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 @@ -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); diff --git a/sys/vfs/procfs/procfs_dbregs.c b/sys/vfs/procfs/procfs_dbregs.c index 538eb11453..c255d498d0 100644 --- a/sys/vfs/procfs/procfs_dbregs.c +++ b/sys/vfs/procfs/procfs_dbregs.c @@ -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 @@ -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); diff --git a/sys/vfs/procfs/procfs_fpregs.c b/sys/vfs/procfs/procfs_fpregs.c index 7c8514fe6a..c5619ddec9 100644 --- a/sys/vfs/procfs/procfs_fpregs.c +++ b/sys/vfs/procfs/procfs_fpregs.c @@ -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 @@ -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); diff --git a/sys/vfs/procfs/procfs_regs.c b/sys/vfs/procfs/procfs_regs.c index 719378e550..1f5a78b57b 100644 --- a/sys/vfs/procfs/procfs_regs.c +++ b/sys/vfs/procfs/procfs_regs.c @@ -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 @@ -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); diff --git a/sys/vfs/procfs/procfs_status.c b/sys/vfs/procfs/procfs_status.c index 163819dce6..ca17d1910c 100644 --- a/sys/vfs/procfs/procfs_status.c +++ b/sys/vfs/procfs/procfs_status.c @@ -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 @@ -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", diff --git a/sys/vm/pmap.h b/sys/vm/pmap.h index 7e08ada197..b0922c685a 100644 --- a/sys/vm/pmap.h +++ b/sys/vm/pmap.h @@ -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); diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index f87bf955af..840ae41c0c 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -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 { diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index 43311b2875..665c5a77f4 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -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 */ + diff --git a/sys/vm/vm_meter.c b/sys/vm/vm_meter.c index 05516e3d1c..07ce932c9c 100644 --- a/sys/vm/vm_meter.c +++ b/sys/vm/vm_meter.c @@ -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 @@ -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; diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index 1d776d1df3..99c258748e 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -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) { diff --git a/usr.bin/systat/pigs.c b/usr.bin/systat/pigs.c index 12af191254..24bce44e81 100644 --- a/usr.bin/systat/pigs.c +++ b/usr.bin/systat/pigs.c @@ -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 / diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c index 4f84addd13..fefa0f4c70 100644 --- a/usr.bin/top/machine.c +++ b/usr.bin/top/machine.c @@ -21,7 +21,7 @@ * Hiten Pandya * * $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) */