Update the userland scheduler. Fix scheduler interactions which were
authorMatthew Dillon <dillon@dragonflybsd.org>
Sat, 24 Jul 2004 20:21:35 +0000 (20:21 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sat, 24 Jul 2004 20:21:35 +0000 (20:21 +0000)
previously resulting in the wrong process sometimes getting a full 1/10
second slice, which under heavy load resulted in serious glitching.
Introduce a new dynamic 'p_interactive' heuristic and allow it to effect
priority +/- by a few nice levels.

With this patch batch operations such as buildworlds, setiathome should not
interfere with X / interactive operations as much as they did before.

Note that we are talking about the the userland scheduler here, not the
LWKT scheduler.  Also note that the userland scheduler needs a complete
rewrite.

20 files changed:
sys/i386/i386/machdep.c
sys/i386/i386/trap.c
sys/i386/isa/intr_machdep.c
sys/kern/imgact_aout.c
sys/kern/imgact_elf.c
sys/kern/init_main.c
sys/kern/kern_fork.c
sys/kern/kern_proc.c
sys/kern/kern_switch.c
sys/kern/kern_synch.c
sys/kern/lwkt_msgport.c
sys/kern/lwkt_thread.c
sys/platform/pc32/i386/machdep.c
sys/platform/pc32/i386/trap.c
sys/platform/pc32/isa/intr_machdep.c
sys/sys/param.h
sys/sys/proc.h
sys/sys/sysent.h
sys/sys/thread.h
sys/vm/vm_glue.c

index ea7b454..f2ba475 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)machdep.c     7.4 (Berkeley) 6/3/91
  * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $
- * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.61 2004/07/05 00:07:35 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/machdep.c,v 1.62 2004/07/24 20:21:33 dillon Exp $
  */
 
 #include "use_apm.h"
@@ -1870,7 +1870,6 @@ init386(int first)
        lwkt_set_comm(&thread0, "thread0");
        proc0.p_addr = (void *)thread0.td_kstack;
        proc0.p_thread = &thread0;
-       proc0.p_flag |= P_CP_RELEASED;  /* early set.  See also init_main.c */
        varsymset_init(&proc0.p_varsymset, NULL);
        thread0.td_flags |= TDF_RUNNING;
        thread0.td_proc = &proc0;
index 4440cbd..c22ac3a 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)trap.c        7.4 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $
- * $DragonFly: src/sys/i386/i386/Attic/trap.c,v 1.53 2004/07/06 01:52:24 hmp Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/trap.c,v 1.54 2004/07/24 20:21:33 dillon Exp $
  */
 
 /*
@@ -172,14 +172,10 @@ SYSCTL_INT(_machdep, OID_AUTO, slow_release, CTLFLAG_RW,
 MALLOC_DEFINE(M_SYSMSG, "sysmsg", "sysmsg structure");
 
 /*
- * USER->KERNEL transition.  Do not transition us out of userland from the
- * point of view of the userland scheduler unless we actually have to
- * switch.  Switching typically occurs when a process blocks in the kernel.
- *
- * passive_release is called from within a critical section and the BGL will
- * still be held.  This function is NOT called for preemptions, only for
- * switchouts.  Note that other elements of the system (uio_yield()) assume
- * that the user cruft will be released when lwkt_switch() is called.
+ * Passive USER->KERNEL transition.  This only occurs if we block in the
+ * kernel while still holding our userland priority.  We have to fixup our
+ * priority in order to avoid potential deadlocks before we allow the system
+ * to switch us to another thread.
  */
 static void
 passive_release(struct thread *td)
@@ -187,6 +183,7 @@ passive_release(struct thread *td)
        struct proc *p = td->td_proc;
 
        td->td_release = NULL;
+       lwkt_setpri_self(TDPRI_KERN_USER);
        release_curproc(p);
 }
 
@@ -203,30 +200,12 @@ userenter(struct thread *curtd)
 }
 
 /*
- * Reacquire our current process designation.  This will not return until
- * we have it.  Our LWKT priority will be adjusted for our return to
- * userland.  acquire_curproc() also handles cleaning up P_CP_RELEASED.
+ * Handle signals, upcalls, profiling, and other AST's and/or tasks that
+ * must be completed before we can return to or try to return to userland.
  *
- * This is always the last step before returning to user mode.
- */
-static __inline void
-userexit(struct proc *p)
-{
-       struct thread *td = p->p_thread;
-
-       td->td_release = NULL;
-       if (p->p_flag & P_CP_RELEASED)
-               ++slow_release;
-       else
-               ++fast_release;
-       acquire_curproc(p);
-}
-
-/*
- * userret() handles signals, upcalls, and deals with system profiling
- * charges.  Note that td_sticks is a 64 bit quantity, but there's no
- * point doing 64 arithmatic on the delta calculation so the absolute
- * tick values are truncated to an integer.
+ * Note that td_sticks is a 64 bit quantity, but there's no point doing 64
+ * arithmatic on the delta calculation so the absolute tick values are
+ * truncated to an integer.
  */
 static void
 userret(struct proc *p, struct trapframe *frame, int sticks)
@@ -248,17 +227,6 @@ userret(struct proc *p, struct trapframe *frame, int sticks)
                postsig(sig);
        }
 
-       /*
-        * If a reschedule has been requested then we release the current
-        * process in order to shift the current process designation to
-        * another user process and/or to switch to a higher priority
-        * kernel thread at userexit() time. 
-        */
-       if (any_resched_wanted()) {
-               p->p_thread->td_release = NULL;
-               release_curproc(p);
-       }
-
        /*
         * Charge system time if profiling.  Note: times are in microseconds.
         */
@@ -274,6 +242,88 @@ userret(struct proc *p, struct trapframe *frame, int sticks)
                postsig(sig);
 }
 
+/*
+ * Cleanup from userenter and any passive release that might have occured.
+ * We must reclaim the current-process designation before we can return
+ * to usermode.  We also handle both LWKT and USER reschedule requests.
+ */
+static __inline void
+userexit(struct proc *p)
+{
+       struct thread *td = p->p_thread;
+       globaldata_t gd = td->td_gd;
+
+#if 0
+       /*
+        * If a user reschedule is requested force a new process to be
+        * chosen by releasing the current process.  Our process will only
+        * be chosen again if it has a considerably better priority.
+        */
+       if (user_resched_wanted())
+               release_curproc(p);
+#endif
+
+again:
+       /*
+        * Handle a LWKT reschedule request first.  Since our passive release
+        * is still in place we do not have to do anything special.
+        */
+       if (lwkt_resched_wanted())
+               lwkt_switch();
+
+       /*
+        * Acquire the current process designation if we do not own it.
+        * Note that acquire_curproc() does not reset the user reschedule
+        * bit on purpose, because we may need to accumulate over several
+        * threads waking up at the same time.
+        *
+        * NOTE: userland scheduler cruft: because processes are removed
+        * from the userland scheduler's queue we run through loops to try
+        * to figure out which is the best of [ existing, waking-up ]
+        * threads.
+        */
+       if (p != gd->gd_uschedcp) {
+               ++slow_release;
+               acquire_curproc(p);
+               /* We may have switched cpus on acquisition */
+               gd = td->td_gd;
+       } else {
+               ++fast_release;
+       }
+
+       /*
+        * Reduce our priority in preparation for a return to userland.  If
+        * our passive release function was still in place, our priority was
+        * never raised and does not need to be reduced.
+        */
+       if (td->td_release == NULL)
+               lwkt_setpri_self(TDPRI_USER_NORM);
+       td->td_release = NULL;
+
+       /*
+        * After reducing our priority there might be other kernel-level
+        * LWKTs that now have a greater priority.  Run them as necessary.
+        * We don't have to worry about losing cpu to userland because
+        * we still control the current-process designation and we no longer
+        * have a passive release function installed.
+        */
+       if (lwkt_checkpri_self())
+               lwkt_switch();
+
+       /*
+        * If a userland reschedule is [still] pending we may not be the best
+        * selected process.  Select a better one.  If another LWKT resched
+        * is pending the trap will be re-entered.
+        */
+       if (user_resched_wanted()) {
+               select_curproc(gd);
+               if (p != gd->gd_uschedcp) {
+                       lwkt_setpri_self(TDPRI_KERN_USER);
+                       goto again;
+               }
+       }
+}
+
 #ifdef DEVICE_POLLING
 extern u_int32_t poll_in_trap;
 extern int ether_poll (int count);
@@ -1185,7 +1235,6 @@ syscall2(struct trapframe frame)
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
        caddr_t params;
-       int i;
        struct sysent *callp;
        register_t orig_tf_eflags;
        int sticks;
@@ -1241,9 +1290,7 @@ syscall2(struct trapframe frame)
                }
        }
 
-       if (p->p_sysent->sv_mask)
-               code &= p->p_sysent->sv_mask;
-
+       code &= p->p_sysent->sv_mask;
        if (code >= p->p_sysent->sv_size)
                callp = &p->p_sysent->sv_table[0];
        else
@@ -1254,13 +1301,17 @@ syscall2(struct trapframe frame)
        /*
         * copyin is MP aware, but the tracing code is not
         */
-       if (params && (i = narg * sizeof(register_t)) &&
-           (error = copyin(params, (caddr_t)(&args.nosys.usrmsg + 1), (u_int)i))) {
+       if (narg && params) {
+               error = copyin(params, (caddr_t)(&args.nosys.usrmsg + 1),
+                               narg * sizeof(register_t));
+               if (error) {
 #ifdef KTRACE
-               if (KTRPOINT(td, KTR_SYSCALL))
-                       ktrsyscall(p->p_tracep, code, narg, (void *)(&args.nosys.usrmsg + 1));
+                       if (KTRPOINT(td, KTR_SYSCALL))
+                               ktrsyscall(p->p_tracep, code, narg,
+                                       (void *)(&args.nosys.usrmsg + 1));
 #endif
-               goto bad;
+                       goto bad;
+               }
        }
 
 #if 0
index b22b929..bb14b71 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)isa.c 7.2 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
- * $DragonFly: src/sys/i386/isa/Attic/intr_machdep.c,v 1.22 2004/04/10 20:55:22 dillon Exp $
+ * $DragonFly: src/sys/i386/isa/Attic/intr_machdep.c,v 1.23 2004/07/24 20:21:34 dillon Exp $
  */
 /*
  * This file contains an aggregated module marked:
@@ -792,7 +792,7 @@ cpu_intr_preempt(struct thread *td, int critpri)
        if ((curthread->td_cpl & (1 << info->irq)) == 0)
                lwkt_preempt(td, critpri);
        else
-               need_lwkt_resched();
+               need_lwkt_resched(); /* XXX may not be required */
 }
 
 static int
index 1610094..76b0e6d 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/imgact_aout.c,v 1.59.2.5 2001/11/03 01:41:08 ps Exp $
- * $DragonFly: src/sys/kern/imgact_aout.c,v 1.8 2004/01/20 18:41:51 dillon Exp $
+ * $DragonFly: src/sys/kern/imgact_aout.c,v 1.9 2004/07/24 20:21:35 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -59,7 +59,7 @@ static int    exec_aout_imgact (struct image_params *imgp);
 struct sysentvec aout_sysvec = {
        SYS_MAXSYSCALL,
        sysent,
-       0,
+       -1,
        0,
        0,
        0,
index 776b944..206a9eb 100644 (file)
@@ -27,7 +27,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/imgact_elf.c,v 1.73.2.13 2002/12/28 19:49:41 dillon Exp $
- * $DragonFly: src/sys/kern/imgact_elf.c,v 1.20 2004/06/08 10:14:45 hsu Exp $
+ * $DragonFly: src/sys/kern/imgact_elf.c,v 1.21 2004/07/24 20:21:35 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -90,7 +90,7 @@ SYSCTL_INT(_debug, OID_AUTO, elf_legacy_coredump, CTLFLAG_RW,
 static struct sysentvec elf_freebsd_sysvec = {
         SYS_MAXSYSCALL,
         sysent,
-        0,
+        -1,
         0,
         0,
         0,
index 070a4ad..f2c0fb1 100644 (file)
@@ -40,7 +40,7 @@
  *
  *     @(#)init_main.c 8.9 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/init_main.c,v 1.134.2.8 2003/06/06 20:21:32 tegge Exp $
- * $DragonFly: src/sys/kern/init_main.c,v 1.34 2004/06/20 22:29:10 hmp Exp $
+ * $DragonFly: src/sys/kern/init_main.c,v 1.35 2004/07/24 20:21:35 dillon Exp $
  */
 
 #include "opt_init_path.h"
@@ -310,7 +310,7 @@ proc0_init(void *dummy __unused)
        p->p_sysent = &aout_sysvec;
        TAILQ_INIT(&p->p_sysmsgq);
 
-       p->p_flag = P_INMEM | P_SYSTEM | P_CP_RELEASED;
+       p->p_flag = P_INMEM | P_SYSTEM;
        p->p_stat = SRUN;
        p->p_nice = NZERO;
        p->p_rtprio.type = RTP_PRIO_NORMAL;
@@ -558,7 +558,8 @@ start_init(void *dummy)
                 * release it.
                 */
                if ((error = execve(&args)) == 0) {
-                       acquire_curproc(p);
+                       if (p->p_thread->td_gd->gd_uschedcp != p)
+                               acquire_curproc(p);
                        rel_mplock();
                        return;
                }
index 596ccf9..72826b0 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_fork.c 8.6 (Berkeley) 4/8/94
  * $FreeBSD: src/sys/kern/kern_fork.c,v 1.72.2.14 2003/06/26 04:15:10 silby Exp $
- * $DragonFly: src/sys/kern/kern_fork.c,v 1.27 2004/06/20 22:29:10 hmp Exp $
+ * $DragonFly: src/sys/kern/kern_fork.c,v 1.28 2004/07/24 20:21:35 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -367,13 +367,8 @@ again:
         * Duplicate sub-structures as needed.
         * Increase reference counts on shared objects.
         * The p_stats and p_sigacts substructs are set in vm_fork.
-        *
-        * P_CP_RELEASED indicates that the process is starting out in
-        * the kernel (in the fork trampoline).  The flag will be cleared
-        * when the new process calls userret() and acquires its current
-        * process designation for the return to userland.
         */
-       p2->p_flag = P_INMEM | P_CP_RELEASED;
+       p2->p_flag = P_INMEM;
        if (p1->p_flag & P_PROFIL)
                startprofclock(p2);
        p2->p_ucred = crhold(p1->p_ucred);
@@ -515,9 +510,12 @@ again:
         * interactive programs when they are first started.  If the child
         * is not a batch program it's priority will be corrected by the
         * scheduler.
+        *
+        * The interactivity model always starts at 0 (par value).
         */
        p2->p_estcpu_fork = p2->p_estcpu = 
                ESTCPULIM(p1->p_estcpu + ESTCPURAMP);
+       p2->p_interactive = 0;
 
        /*
         * This begins the section where we must prevent the parent
@@ -630,6 +628,10 @@ start_forked_proc(struct proc *p1, struct proc *p2)
         * Move from SIDL to RUN queue, and activate the process's thread.
         * Activation of the thread effectively makes the process "a"
         * current process, so we do not setrunqueue().
+        *
+        * YYY setrunqueue works here but we should clean up the trampoline
+        * code so we just schedule the LWKT thread and let the trampoline
+        * deal with the userland scheduler on return to userland.
         */
        KASSERT(p2 && p2->p_stat == SIDL,
            ("cannot start forked process, bad status: %p", p2));
index 1df9ad2..e47be18 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)kern_proc.c 8.7 (Berkeley) 2/14/95
  * $FreeBSD: src/sys/kern/kern_proc.c,v 1.63.2.9 2003/05/08 07:47:16 kbyanc Exp $
- * $DragonFly: src/sys/kern/kern_proc.c,v 1.15 2004/06/10 22:11:35 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_proc.c,v 1.16 2004/07/24 20:21:35 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -462,17 +462,14 @@ 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 process scheduler
-                * does not own the process and the thread scheduler says it
-                * isn't running or runnable.
+                * 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).
                 */
-               if ((p->p_flag & P_CP_RELEASED) && p->p_stat == SRUN &&
-                   td && (td->td_flags & (TDF_RUNNING|TDF_RUNQ)) == 0
-               ) {
+               if (p->p_stat == SRUN && td && (td->td_flags & TDF_BLOCKED)) {
                        xproc.p_stat = SSLEEP;
                }
        } else if (td) {
index 3daa272..6f18b4f 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_switch.c,v 1.3.2.1 2000/05/16 06:58:12 dillon Exp $
- * $DragonFly: src/sys/kern/Attic/kern_switch.c,v 1.21 2004/04/10 20:55:23 dillon Exp $
+ * $DragonFly: src/sys/kern/Attic/kern_switch.c,v 1.22 2004/07/24 20:21:35 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -75,15 +75,16 @@ static int   scancpu;
 
 SYSCTL_INT(_debug, OID_AUTO, runqcount, CTLFLAG_RD, &runqcount, 0, "");
 #ifdef INVARIANTS
-static int usched_stalls;
-SYSCTL_INT(_debug, OID_AUTO, usched_stalls, CTLFLAG_RW,
-        &usched_stalls, 0, "acquire_curproc() had to stall");
-static int usched_stolen;
-SYSCTL_INT(_debug, OID_AUTO, usched_stolen, CTLFLAG_RW,
-        &usched_stolen, 0, "acquire_curproc() stole the des");
+static int usched_nonoptimal;
+SYSCTL_INT(_debug, OID_AUTO, usched_nonoptimal, CTLFLAG_RW,
+        &usched_nonoptimal, 0, "acquire_curproc() was not optimal");
 static int usched_optimal;
 SYSCTL_INT(_debug, OID_AUTO, usched_optimal, CTLFLAG_RW,
         &usched_optimal, 0, "acquire_curproc() was optimal");
+static int usched_debug;
+static int usched_count;
+SYSCTL_INT(_debug, OID_AUTO, scdebug, CTLFLAG_RW, &usched_debug, 0, "");
+SYSCTL_INT(_debug, OID_AUTO, sccount, CTLFLAG_RW, &usched_count, 0, "");
 #endif
 #ifdef SMP
 static int remote_resched = 1;
@@ -117,25 +118,14 @@ rqinit(void *dummy)
 }
 SYSINIT(runqueue, SI_SUB_RUN_QUEUE, SI_ORDER_FIRST, rqinit, NULL)
 
-/*
- * Returns 1 if curp is equal to or better then newp.  Note that
- * lower p_priority values == higher process priorities.  Assume curp
- * is in-context and cut it some slack to avoid ping ponging.
- */
-static __inline
-int
-test_resched(struct proc *curp, struct proc *newp)
-{
-       if (curp->p_priority - newp->p_priority < PPQ)
-               return(1);
-       return(0);
-}
-
 /*
  * chooseproc() is called when a cpu needs a user process to LWKT schedule,
  * it selects a user process and returns it.  If chkp is non-NULL and chkp
- * has the same or higher priority then the process that would otherwise be
+ * has a better or equal then the process that would otherwise be
  * chosen, NULL is returned.
+ *
+ * Until we fix the RUNQ code the chkp test has to be strict or we may
+ * bounce between processes trying to acquire the current process designation.
  */
 static
 struct proc *
@@ -165,11 +155,16 @@ chooseproc(struct proc *chkp)
        KASSERT(p, ("chooseproc: no proc on busy queue"));
 
        /*
-        * If the passed process is better then the selected process,
-        * return NULL. 
+        * If the passed process <chkp> is reasonably close to the selected
+        * processed <p>, return NULL (indicating that <chkp> should be kept).
+        * 
+        * Note that we must error on the side of <chkp> to avoid bouncing
+        * between threads in the acquire code.
         */
-       if (chkp && test_resched(chkp, p))
-               return(NULL);
+       if (chkp) {
+               if (chkp->p_priority < p->p_priority + PPQ)
+                       return(NULL);
+       }
 
 #ifdef SMP
        /*
@@ -211,16 +206,9 @@ need_user_resched_remote(void *dummy)
 #endif
 
 /*
- * setrunqueue() 'wakes up' a 'user' process, which can mean several things.
- *
- * If P_CP_RELEASED is set the user process is under the control of the
- * LWKT subsystem and we simply wake the thread up.  This is ALWAYS the
- * case when setrunqueue() is called from wakeup() and, in fact wakeup()
- * asserts that P_CP_RELEASED is set.
- *
- * If P_CP_RELEASED is not set we place the process on the run queue and we
- * signal other cpus in the system that may need to be woken up to service
- * the new 'user' process.
+ * setrunqueue() 'wakes up' a 'user' process.  GIANT must be held.  The
+ * user process may represent any user process, including the current
+ * process.
  *
  * If P_PASSIVE_ACQ is set setrunqueue() will not wakeup potential target
  * cpus in an attempt to keep the process on the current cpu at least for
@@ -263,40 +251,31 @@ setrunqueue(struct proc *p)
        KKASSERT((p->p_thread->td_flags & TDF_RUNQ) == 0);
 
        /*
-        * If we have been released from the userland scheduler we
-        * directly schedule its thread.   If the priority is sufficiently
-        * high request a user reschedule.   Note that the lwkt_resched
-        * is not typically set for wakeups of userland threads that happen
-        * to be sitting in the kernel because their LWKT priorities will
-        * generally be the same.
+        * Note: gd is the gd of the TARGET thread's cpu, not our cpu.
         */
-       if (p->p_flag & P_CP_RELEASED) {
-               lwkt_schedule(p->p_thread);
-#if 0
-               if (gd->gd_uschedcp && test_resched(p, gd->gd_uschedcp))
-                       need_user_resched();
-#endif
-               crit_exit();
-               return;
-       }
+       gd = p->p_thread->td_gd;
 
        /*
         * We have not been released, make sure that we are not the currently
         * designated process.
         */
-       gd = p->p_thread->td_gd;
        KKASSERT(gd->gd_uschedcp != p);
 
        /*
         * Check cpu affinity.  The associated thread is stable at the
         * moment.  Note that we may be checking another cpu here so we
         * have to be careful.  We are currently protected by the BGL.
+        *
+        * This allows us to avoid actually queueing the process.  
+        * acquire_curproc() will handle any threads we mistakenly schedule.
         */
        cpuid = gd->gd_cpuid;
 
        if ((curprocmask & (1 << cpuid)) == 0) {
                curprocmask |= 1 << cpuid;
                gd->gd_uschedcp = p;
+               if (usched_debug) 
+                       printf("F%-7d", gd->gd_uschedcp->p_pid);
                gd->gd_upri = p->p_priority;
                lwkt_schedule(p->p_thread);
                /* CANNOT TOUCH PROC OR TD AFTER SCHEDULE CALL TO REMOTE CPU */
@@ -353,12 +332,13 @@ setrunqueue(struct proc *p)
         */
        if (gd == mycpu) {
                if ((p->p_thread->td_flags & TDF_NORESCHED) == 0 &&
-                   p->p_priority - gd->gd_upri <= -PPQ) {
+                   p->p_priority < gd->gd_upri - PPQ) {
+                       gd->gd_upri = p->p_priority;
                        need_user_resched();
                        --count;
                }
        } else if (remote_resched) {
-               if (p->p_priority - gd->gd_upri <= -PPQ) {
+               if (p->p_priority < gd->gd_upri - PPQ) {
                        gd->gd_upri = p->p_priority;
                        lwkt_send_ipiq(gd, need_user_resched_remote, NULL);
                        --count;
@@ -412,7 +392,7 @@ setrunqueue(struct proc *p)
                if (rdyprocmask & (1 << cpuid)) {
                        gd = globaldata_find(cpuid);
 
-                       if (p->p_priority - gd->gd_upri <= -PPQ) {
+                       if (p->p_priority < gd->gd_upri - PPQ) {
                                gd->gd_upri = p->p_priority;
                                lwkt_send_ipiq(gd, need_user_resched_remote, NULL);
                                ++remote_resched_nonaffinity;
@@ -421,8 +401,8 @@ setrunqueue(struct proc *p)
        }
 #else
        if ((p->p_thread->td_flags & TDF_NORESCHED) == 0 &&
-           p->p_priority - gd->gd_upri <= -PPQ) {
-               /* do not set gd_upri */
+           p->p_priority < gd->gd_upri - PPQ) {
+               gd->gd_upri = p->p_priority;
                need_user_resched();
        }
 #endif
@@ -479,12 +459,11 @@ remrunqueue(struct proc *p)
  * Release the current process designation on p.  P MUST BE CURPROC.
  * Attempt to assign a new current process from the run queue.
  *
- * If passive is non-zero, gd_uschedcp may be left set to p, the
- * fact that P_CP_RELEASED is set will allow it to be overridden at any
- * time.
+ * This function is called from exit1(), tsleep(), and the passive
+ * release code setup in <arch>/<arch>/trap.c
  *
  * If we do not have or cannot get the MP lock we just wakeup the userland
- * helper scheduler thread for this cpu.
+ * helper scheduler thread for this cpu to do the work for us.
  *
  * WARNING!  The MP lock may be in an unsynchronized state due to the
  * way get_mplock() works and the fact that this function may be called
@@ -496,7 +475,6 @@ void
 release_curproc(struct proc *p)
 {
        int cpuid;
-       struct proc *np;
        globaldata_t gd = mycpu;
 
 #ifdef ONLY_ONE_USER_CPU
@@ -505,11 +483,13 @@ release_curproc(struct proc *p)
        KKASSERT(p->p_thread->td_gd == gd);
 #endif
        crit_enter();
-       cpuid = gd->gd_cpuid;
-       if ((p->p_flag & P_CP_RELEASED) == 0) {
-               p->p_flag |= P_CP_RELEASED;
-               lwkt_setpri_self(TDPRI_KERN_USER);
+       if (usched_debug) {
+           printf("c%-7d", p->p_pid);
+           if (usched_count && --usched_count == 0)
+               panic("x");
        }
+       cpuid = gd->gd_cpuid;
+
        if (gd->gd_uschedcp == p) {
                if (try_mplock()) {
                        /* 
@@ -517,33 +497,14 @@ release_curproc(struct proc *p)
                         * will have to check that gd_uschedcp is still == p
                         * after acquisition of the MP lock
                         */
-                       /*
-                        * Choose the next designated current user process.
-                        * Note that we cannot schedule gd_schedthread
-                        * if runqcount is 0 without creating a scheduling
-                        * loop. 
-                        *
-                        * We do not clear the user resched request here,
-                        * we need to test it later when we re-acquire.
-                        */
-                       if ((np = chooseproc(NULL)) != NULL) {
-                               curprocmask |= 1 << cpuid;
-                               gd->gd_upri = np->p_priority;
-                               gd->gd_uschedcp = np;
-                               lwkt_acquire(np->p_thread);
-                               lwkt_schedule(np->p_thread);
-                       } else if (runqcount && (rdyprocmask & (1 << cpuid))) {
-                               gd->gd_uschedcp = NULL;
-                               curprocmask &= ~(1 << cpuid);
-                               rdyprocmask &= ~(1 << cpuid);
-                               lwkt_schedule(&gd->gd_schedthread);
-                       } else {
-                               gd->gd_uschedcp = NULL;
-                               curprocmask &= ~(1 << cpuid);
-                       }
+                       gd->gd_uschedcp = NULL;
+                       gd->gd_upri = PRIBASE_NULL;
+                       select_curproc(gd);
                        rel_mplock();
                } else {
                        KKASSERT(0);    /* MP LOCK ALWAYS HELD AT THE MOMENT */
+                       gd->gd_uschedcp = NULL;
+                       gd->gd_upri = PRIBASE_NULL;
                        /* YYY uschedcp and curprocmask */
                        if (runqcount && (rdyprocmask & (1 << cpuid))) {
                                rdyprocmask &= ~(1 << cpuid);
@@ -555,191 +516,102 @@ release_curproc(struct proc *p)
 }
 
 /*
- * Acquire the current process designation on the CURRENT process only.  
- * This function is called prior to returning to userland.  If the system
- * call or trap did not block and if no reschedule was requested it is
- * highly likely that p is still designated.
+ * Select a new current process, potentially retaining gd_uschedcp.  However,
+ * be sure to round-robin.  This routine is generally only called if a
+ * reschedule is requested and that typically only occurs if a new process
+ * has a better priority or when we are round-robining.
  *
- * If any reschedule (lwkt or user) was requested, release_curproc() has
- * already been called and gd_uschedcp will be NULL.  We must be sure not
- * to return without clearing both the lwkt and user ASTs.
+ * NOTE: Must be called with giant held and the current cpu's gd. 
+ * NOTE: The caller must handle the situation where it loses a
+ *     uschedcp designation that it previously held, typically by
+ *     calling acquire_curproc() again. 
+ * NOTE: May not block
  */
 void
-acquire_curproc(struct proc *p)
+select_curproc(globaldata_t gd)
 {
-       int cpuid;
-#ifdef INVARIANTS
-       enum { ACQ_OPTIMAL, ACQ_STOLEN, ACQ_STALLED } state;
-#endif
        struct proc *np;
-       globaldata_t gd = mycpu;
+       int cpuid = gd->gd_cpuid;
+       void *old;
 
-#ifdef ONLY_ONE_USER_CPU
-       KKASSERT(gd->gd_cpuid == 0);
-#endif
-       /*
-        * Shortcut the common case where the system call / other kernel entry
-        * did not block or otherwise release our current process designation.
-        * If a reschedule was requested the process would have been released
-        * from <arch>/<arch>/trap.c and gd_uschedcp will be NULL.
-        */
-       if (gd->gd_uschedcp == p && (p->p_flag & P_CP_RELEASED) == 0) {
-#ifdef INVARIANTS
-               ++usched_optimal;
-#endif
-               return;
-       }
-       KKASSERT(p == gd->gd_curthread->td_proc);
        clear_user_resched();
 
        /*
-        * We drop our priority now. 
+        * Choose the next designated current user process.
+        * Note that we cannot schedule gd_schedthread
+        * if runqcount is 0 without creating a scheduling
+        * loop. 
         *
-        * We must leave P_CP_RELEASED set.  This allows other kernel threads
-        * exiting to userland to steal our gd_uschedcp.
+        * We do not clear the user resched request here,
+        * we need to test it later when we re-acquire.
         *
-        * NOTE: If P_CP_RELEASED is not set here, our priority was never
-        * raised and we therefore do not have to lower it.
+        * NOTE: chooseproc returns NULL if the chosen proc
+        * is gd_uschedcp. XXX needs cleanup.
         */
-       if (p->p_flag & P_CP_RELEASED)
-               lwkt_setpri_self(TDPRI_USER_NORM);
-       else
-               p->p_flag |= P_CP_RELEASED;
+       old = gd->gd_uschedcp;
+       if ((np = chooseproc(gd->gd_uschedcp)) != NULL) {
+               curprocmask |= 1 << cpuid;
+               gd->gd_upri = np->p_priority;
+               gd->gd_uschedcp = np;
+               if (usched_debug) {
+                   printf("A%-7d[%p,%p]", gd->gd_uschedcp->p_pid, old, np);
+               }
+               lwkt_acquire(np->p_thread);
+               lwkt_schedule(np->p_thread);
+       } else if (gd->gd_uschedcp) {
+               gd->gd_upri = gd->gd_uschedcp->p_priority;
+               KKASSERT(curprocmask & (1 << cpuid));
+       } else if (runqcount && (rdyprocmask & (1 << cpuid))) {
+               /*gd->gd_uschedcp = NULL;*/
+               curprocmask &= ~(1 << cpuid);
+               rdyprocmask &= ~(1 << cpuid);
+               lwkt_schedule(&gd->gd_schedthread);
+       } else {
+               /*gd->gd_uschedcp = NULL;*/
+               curprocmask &= ~(1 << cpuid);
+       }
+}
 
-#ifdef INVARIANTS
-       state = ACQ_OPTIMAL;
+/*
+ * Acquire the current process designation on the CURRENT process only.
+ * This function is called at kernel-user priority (not userland priority)
+ * when curproc does not match gd_uschedcp.
+ */
+void
+acquire_curproc(struct proc *p)
+{
+       globaldata_t gd = mycpu;
+
+#ifdef ONLY_ONE_USER_CPU
+       KKASSERT(gd->gd_cpuid == 0);
 #endif
-       crit_enter();
 
        /*
-        * Obtain ownership of gd_uschedcp (the current process designation).
-        *
-        * Note: the while never loops be use the construct for the initial
-        * condition test and break statements.
+        * Loop until we become the current process.  
         */
-       while (gd->gd_uschedcp != p) {
-               /*
-                * Choose the next process to become the current process.
-                *
-                * With P_CP_RELEASED set, we can compete for the designation.
-                * if any_resched_wanted() is set 
-                */
-               cpuid = gd->gd_cpuid;
-               np = gd->gd_uschedcp;
-               if (np == NULL) {
-                       KKASSERT((curprocmask & (1 << cpuid)) == 0);
-                       curprocmask |= 1 << cpuid;
-                       if ((np = chooseproc(p)) == NULL) {
-                               gd->gd_uschedcp = p;
-                               gd->gd_upri = p->p_priority;
-                               break;
-                       }
-                       KKASSERT((np->p_flag & P_CP_RELEASED) == 0);
-                       gd->gd_upri = np->p_priority;
-                       gd->gd_uschedcp = np;
-                       lwkt_acquire(np->p_thread);
-                       lwkt_schedule(np->p_thread);
-                       /* fall through */
-               } else if ((np->p_flag&P_CP_RELEASED) && !test_resched(np, p)) {
-                       /*
-                        * When gd_uschedcp's P_CP_RELEASED flag is set it
-                        * must have just called lwkt_switch() in the post
-                        * acquisition code below.  We can safely dequeue and
-                        * setrunqueue() it.
-                        *
-                        * Note that we reverse the arguments to test_resched()
-                        * and use NOT.  This reverses the hysteresis so we do
-                        * not chain a sequence of steadily worse priorities
-                        * and end up with a very low priority (high p_priority
-                        * value) as our current process.
-                        */
-                       KKASSERT(curprocmask & (1 << cpuid));
-                       gd->gd_uschedcp = p;
-                       gd->gd_upri = p->p_priority;
-
-                       lwkt_deschedule(np->p_thread);  /* local to cpu */
-                       np->p_flag &= ~P_CP_RELEASED;
-                       setrunqueue(np);
-#ifdef INVARIANTS
-                       if (state == ACQ_OPTIMAL)
-                               state = ACQ_STOLEN;
-#endif
-                       break;
-               }
+       crit_enter();
+       ++p->p_stats->p_ru.ru_nivcsw;
+       do {
+               KKASSERT(p == gd->gd_curthread->td_proc);
 
-               /*
-                * We couldn't acquire the designation, put us on
-                * the userland run queue for selection and block.
-                * setrunqueue() will call need_user_resched() if
-                * necessary if the existing current process has a lower
-                * priority.
-                */
-               clear_lwkt_resched();
-               lwkt_deschedule_self(curthread);
-               p->p_flag &= ~P_CP_RELEASED;
+               lwkt_deschedule_self(gd->gd_curthread);
                setrunqueue(p);
                lwkt_switch();
+               if (usched_debug)
+                   printf("a");
+
                /*
-                * WE MAY HAVE BEEN MIGRATED TO ANOTHER CPU
+                * WE MAY HAVE BEEN MIGRATED TO ANOTHER CPU, RELOAD GD.
                 */
                gd = mycpu;
-               KKASSERT((p->p_flag & (P_ONRUNQ|P_CP_RELEASED)) == 0);
-               break;
-       }
-
-       /*
-        * We have acquired gd_uschedcp and our priority is correct.
-        *
-        * If P_CP_RELEASED is set we have to check lwkt_resched_wanted()
-        * and lwkt_switch() if it returns TRUE in order to run any pending
-        * threads before returning to user mode.  
-        *
-        * If P_CP_RELEASED is clear we have *ALREADY* done a switch (and
-        * we were possibly dequeued and setrunqueue()'d, and then woken up
-        * again via chooseproc()), and since our priority was lowered we
-        * are guarenteed that no other kernel threads are pending and that
-        * we are in fact the gd_uschedcp.
-        */
-       if (p->p_flag & P_CP_RELEASED) {
-               if (lwkt_resched_wanted()) {
-                       clear_lwkt_resched();
-                       lwkt_switch();
-                       gd = mycpu;     /* We may have moved */
-                       if ((p->p_flag & P_CP_RELEASED) == 0) {
-                               ++p->p_stats->p_ru.ru_nivcsw;
-#ifdef INVARIANTS
-                               state = ACQ_STALLED;
-                               ++usched_stalls;
-#endif
-                       }
-               }
-               p->p_flag &= ~P_CP_RELEASED;
-       } else {
-               ++p->p_stats->p_ru.ru_nivcsw;
-#ifdef INVARIANTS
-               state = ACQ_STALLED;
-               ++usched_stalls;
-#endif
-       }
+       } while (gd->gd_uschedcp != p);
+       crit_exit();
 
        /*
         * That's it.  Cleanup, we are done.  The caller can return to
         * user mode now.
         */
-       KKASSERT((p->p_flag & P_ONRUNQ) == 0 && gd->gd_uschedcp == p);
-       crit_exit();
-#ifdef INVARIANTS
-       switch(state) {
-       case ACQ_OPTIMAL:
-               ++usched_optimal;
-               break;
-       case ACQ_STOLEN:
-               ++usched_stolen;
-               break;
-       default:
-               break;
-       }
-#endif
+       KKASSERT((p->p_flag & P_ONRUNQ) == 0);
 }
 
 /*
@@ -807,6 +679,8 @@ sched_thread(void *dummy)
            curprocmask |= cpumask;
            gd->gd_upri = np->p_priority;
            gd->gd_uschedcp = np;
+           if (usched_debug)
+               printf("E%-7d", gd->gd_uschedcp->p_pid);
            lwkt_acquire(np->p_thread);
            lwkt_schedule(np->p_thread);
        }
index a235d75..b06add7 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)kern_synch.c        8.9 (Berkeley) 5/19/95
  * $FreeBSD: src/sys/kern/kern_synch.c,v 1.87.2.6 2002/10/13 07:29:53 kbyanc Exp $
- * $DragonFly: src/sys/kern/kern_synch.c,v 1.33 2004/06/10 22:11:35 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_synch.c,v 1.34 2004/07/24 20:21:35 dillon Exp $
  */
 
 #include "opt_ktrace.h"
@@ -223,13 +223,33 @@ schedcpu(void *arg)
                if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
                        p->p_slptime++;
                p->p_pctcpu = (p->p_pctcpu * ccpu) >> FSHIFT;
+
                /*
                 * If the process has slept the entire second,
                 * stop recalculating its priority until it wakes up.
+                *
+                * Note that interactive calculations do not occur for
+                * long sleeps (because that isn't necessarily indicative
+                * of an interactive process).
                 */
                if (p->p_slptime > 1)
                        continue;
-               s = splhigh();  /* prevent state changes and protect run queue */
+               /* prevent state changes and protect run queue */
+               s = splhigh();
+               /*
+                * p_cpticks runs at ESTCPUFREQ but must be divided by the
+                * load average for par-100% use.  Higher p_interactive
+                * values mean less interactive, lower values mean more 
+                * interactive.
+                */
+               if ((((fixpt_t)p->p_cpticks * cload(loadfac)) >> FSHIFT)  >
+                   ESTCPUFREQ / 4) {
+                       if (p->p_interactive < 127)
+                               ++p->p_interactive;
+               } else {
+                       if (p->p_interactive > -127)
+                               --p->p_interactive;
+               }
                /*
                 * p_pctcpu is only for ps.
                 */
@@ -504,7 +524,7 @@ xwakeup(struct xwait *w)
                        p->p_slptime = 0;
                        p->p_stat = SRUN;
                        if (p->p_flag & P_INMEM) {
-                               setrunqueue(p);
+                               lwkt_schedule(td);
                        } else {
                                p->p_flag |= P_SWAPINREQ;
                                wakeup((caddr_t)&proc0);
@@ -542,7 +562,15 @@ restart:
                                p->p_slptime = 0;
                                p->p_stat = SRUN;
                                if (p->p_flag & P_INMEM) {
-                                       setrunqueue(p);
+                                       /*
+                                        * LWKT scheduled now, there is no
+                                        * userland runq interaction until
+                                        * the thread tries to return to user
+                                        * mode.
+                                        *
+                                        * setrunqueue(p); 
+                                        */
+                                       lwkt_schedule(td);
                                } else {
                                        p->p_flag |= P_SWAPINREQ;
                                        wakeup((caddr_t)&proc0);
@@ -608,11 +636,10 @@ mi_switch(struct proc *p)
        }
 
        /*
-        * Pick a new current process and record its start time.  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.
+        * 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)
@@ -647,8 +674,18 @@ setrunnable(struct proc *p)
                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.
+        */
+#if 0
        if (p->p_flag & P_INMEM)
                setrunqueue(p);
+#endif
+       if (p->p_flag & P_INMEM)
+               lwkt_schedule(p->p_thread);
        splx(s);
        if (p->p_slptime > 1)
                updatepri(p);
@@ -681,7 +718,8 @@ clrrunnable(struct proc *p, int stat)
 void
 resetpriority(struct proc *p)
 {
-       unsigned int newpriority;
+       int newpriority;
+       int interactive;
        int opq;
        int npq;
 
@@ -704,11 +742,22 @@ resetpriority(struct proc *p)
 
        /*
         * NORMAL priorities fall through.  These are based on niceness
-        * and cpu use.
+        * and cpu use.  Lower numbers == higher priorities.
+        */
+       newpriority = (int)(NICE_ADJUST(p->p_nice - PRIO_MIN) +
+                       p->p_estcpu / ESTCPURAMP);
+
+       /*
+        * p_interactive is -128 to +127 and represents very long term
+        * interactivity or batch (whereas estcpu is a much faster variable).
+        * Interactivity can modify the priority by up to 8 units either way.
+        * (8 units == approximately 4 nice levels).
         */
-       newpriority = NICE_ADJUST(p->p_nice - PRIO_MIN) +
-                       p->p_estcpu / ESTCPURAMP;
+       interactive = p->p_interactive / 10;
+       newpriority += interactive;
+
        newpriority = min(newpriority, MAXPRI);
+       newpriority = max(newpriority, 0);
        npq = newpriority / PPQ;
        crit_enter();
        opq = (p->p_priority & PRIMASK) / PPQ;
@@ -740,25 +789,23 @@ loadav(void *arg)
        int i, nrun;
        struct loadavg *avg;
        struct proc *p;
+       thread_t td;
 
        avg = &averunnable;
        nrun = 0;
        FOREACH_PROC_IN_SYSTEM(p) {
-               thread_t td;
-               if (p->p_flag & P_CP_RELEASED) {
-                   if ((td = p->p_thread) != NULL) {
-                       if (td->td_flags & (TDF_RUNQ|TDF_RUNNING))
-                           nrun++;
-                   }
-               } else {
-                   switch (p->p_stat) {
-                   case SRUN:
-                   case SIDL:
-                           nrun++;
-                           break;
-                   default:
-                           break;
-                   }
+               switch (p->p_stat) {
+               case SRUN:
+                       if ((td = p->p_thread) == NULL)
+                               break;
+                       if (td->td_flags & TDF_BLOCKED)
+                               break;
+                       /* fall through */
+               case SIDL:
+                       nrun++;
+                       break;
+               default:
+                       break;
                }
        }
        for (i = 0; i < 3; i++)
index b95f719..fc02f39 100644 (file)
@@ -34,7 +34,7 @@
  * NOTE! This file may be compiled for userland libraries as well as for
  * the kernel.
  *
- * $DragonFly: src/sys/kern/lwkt_msgport.c,v 1.28 2004/07/16 05:51:10 dillon Exp $
+ * $DragonFly: src/sys/kern/lwkt_msgport.c,v 1.29 2004/07/24 20:21:35 dillon Exp $
  */
 
 #ifdef _KERNEL
@@ -587,10 +587,12 @@ lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg)
     if (msg == NULL) {
        if ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL) {
            port->mp_flags |= MSGPORTF_WAITING;
+           td->td_flags |= TDF_BLOCKED;
            do {
                lwkt_deschedule_self(td);
                lwkt_switch();
            } while ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL);
+           td->td_flags &= ~TDF_BLOCKED;
            port->mp_flags &= ~MSGPORTF_WAITING;
        }
        _lwkt_pullmsg(port, msg);
@@ -631,10 +633,10 @@ lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg)
                     * an interruptable wait and a disk wait.  YYY eventually
                     * move P_SINTR to TDF_SINTR to reduce duplication.
                     */
-                   td->td_flags |= TDF_SINTR;
+                   td->td_flags |= TDF_SINTR | TDF_BLOCKED;
                    lwkt_deschedule_self(td);
                    lwkt_switch();
-                   td->td_flags &= ~TDF_SINTR;
+                   td->td_flags &= ~(TDF_SINTR | TDF_BLOCKED);
                } while ((msg->ms_flags & MSGF_DONE) == 0);
                port->mp_flags &= ~MSGPORTF_WAITING; /* saved by the BGL */
            }
index 15cdde7..cb656b5 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.65 2004/07/16 05:51:10 dillon Exp $
+ * $DragonFly: src/sys/kern/lwkt_thread.c,v 1.66 2004/07/24 20:21:35 dillon Exp $
  */
 
 /*
@@ -503,6 +503,14 @@ lwkt_switch(void)
        }
 #endif
        ntd->td_flags |= TDF_PREEMPT_DONE;
+
+       /*
+        * XXX.  The interrupt may have woken a thread up, we need to properly
+        * set the reschedule flag if the originally interrupted thread is at
+        * a lower priority.
+        */
+       if (gd->gd_runqmask > (2 << (ntd->td_pri & TDPRI_MASK)) - 1)
+           need_lwkt_resched();
        /* YYY release mp lock on switchback if original doesn't need it */
     } else {
        /*
@@ -531,6 +539,11 @@ lwkt_switch(void)
                lwkt_drain_token_requests();
 #endif
 
+       /*
+        * If an LWKT reschedule was requested, well that is what we are
+        * doing now so clear it.
+        */
+       clear_lwkt_resched();
 again:
        if (gd->gd_runqmask) {
            int nq = bsrl(gd->gd_runqmask);
@@ -669,18 +682,19 @@ lwkt_preempt(thread_t ntd, int critpri)
     KASSERT(ntd->td_pri >= TDPRI_CRIT, ("BADCRIT0 %d", ntd->td_pri));
 
     td = gd->gd_curthread;
-    need_lwkt_resched();
     if ((ntd->td_pri & TDPRI_MASK) <= (td->td_pri & TDPRI_MASK)) {
        ++preempt_miss;
        return;
     }
     if ((td->td_pri & ~TDPRI_MASK) > critpri) {
        ++preempt_miss;
+       need_lwkt_resched();
        return;
     }
 #ifdef SMP
     if (ntd->td_gd != gd) {
        ++preempt_miss;
+       need_lwkt_resched();
        return;
     }
 #endif
@@ -693,14 +707,17 @@ lwkt_preempt(thread_t ntd, int critpri)
      */
     if (ntd->td_toks != NULL) {
        ++preempt_miss;
+       need_lwkt_resched();
        return;
     }
     if (td == ntd || ((td->td_flags | ntd->td_flags) & TDF_PREEMPT_LOCK)) {
        ++preempt_weird;
+       need_lwkt_resched();
        return;
     }
     if (ntd->td_preempted) {
        ++preempt_hit;
+       need_lwkt_resched();
        return;
     }
 #ifdef SMP
@@ -718,10 +735,15 @@ lwkt_preempt(thread_t ntd, int critpri)
     if (mpheld == 0 && ntd->td_mpcount && !cpu_try_mplock()) {
        ntd->td_mpcount -= td->td_mpcount;
        ++preempt_miss;
+       need_lwkt_resched();
        return;
     }
 #endif
 
+    /*
+     * Since we are able to preempt the current thread, there is no need to
+     * call need_lwkt_resched().
+     */
     ++preempt_hit;
     ntd->td_preempted = td;
     td->td_flags |= TDF_PREEMPT_LOCK;
@@ -827,15 +849,14 @@ lwkt_yield(void)
  */
 static __inline
 void
-_lwkt_schedule_post(thread_t ntd, int cpri)
+_lwkt_schedule_post(globaldata_t gd, thread_t ntd, int cpri)
 {
     if (ntd->td_preemptable) {
        ntd->td_preemptable(ntd, cpri); /* YYY +token */
-    } else {
-       if ((ntd->td_flags & TDF_NORESCHED) == 0) {
-           if ((ntd->td_pri & TDPRI_MASK) >= TDPRI_KERN_USER)
-               need_lwkt_resched();
-       }
+    } else if ((ntd->td_flags & TDF_NORESCHED) == 0 &&
+       (ntd->td_pri & TDPRI_MASK) > (gd->gd_curthread->td_pri & TDPRI_MASK)
+    ) {
+       need_lwkt_resched();
     }
 }
 
@@ -888,15 +909,15 @@ lwkt_schedule(thread_t td)
                --w->wa_count;
                td->td_wait = NULL;
 #ifdef SMP
-               if (td->td_gd == mycpu) {
+               if (td->td_gd == mygd) {
                    _lwkt_enqueue(td);
-                   _lwkt_schedule_post(td, TDPRI_CRIT);
+                   _lwkt_schedule_post(mygd, td, TDPRI_CRIT);
                } else {
                    lwkt_send_ipiq(td->td_gd, (ipifunc_t)lwkt_schedule, td);
                }
 #else
                _lwkt_enqueue(td);
-               _lwkt_schedule_post(td, TDPRI_CRIT);
+               _lwkt_schedule_post(mygd, td, TDPRI_CRIT);
 #endif
                lwkt_reltoken(&wref);
            } else {
@@ -912,13 +933,13 @@ lwkt_schedule(thread_t td)
 #ifdef SMP
            if (td->td_gd == mygd) {
                _lwkt_enqueue(td);
-               _lwkt_schedule_post(td, TDPRI_CRIT);
+               _lwkt_schedule_post(mygd, td, TDPRI_CRIT);
            } else {
                lwkt_send_ipiq(td->td_gd, (ipifunc_t)lwkt_schedule, td);
            }
 #else
            _lwkt_enqueue(td);
-           _lwkt_schedule_post(td, TDPRI_CRIT);
+           _lwkt_schedule_post(mygd, td, TDPRI_CRIT);
 #endif
        }
     }
@@ -1022,6 +1043,32 @@ lwkt_setpri_self(int pri)
     crit_exit();
 }
 
+/*
+ * Determine if there is a runnable thread at a higher priority then
+ * the current thread.  lwkt_setpri() does not check this automatically.
+ * Return 1 if there is, 0 if there isn't.
+ *
+ * Example: if bit 31 of runqmask is set and the current thread is priority
+ * 30, then we wind up checking the mask: 0x80000000 against 0x7fffffff.  
+ *
+ * If nq reaches 31 the shift operation will overflow to 0 and we will wind
+ * up comparing against 0xffffffff, a comparison that will always be false.
+ */
+int
+lwkt_checkpri_self(void)
+{
+    globaldata_t gd = mycpu;
+    thread_t td = gd->gd_curthread;
+    int nq = td->td_pri & TDPRI_MASK;
+
+    while (gd->gd_runqmask > (__uint32_t)(2 << nq) - 1) {
+       if (TAILQ_FIRST(&gd->gd_tdrunq[nq + 1]))
+           return(1);
+       ++nq;
+    }
+    return(0);
+}
+
 /*
  * Migrate the current thread to the specified cpu.  The BGL must be held
  * (for the gd_tdallq manipulation XXX).  This is accomplished by 
index 79afca1..8fcd0b2 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)machdep.c     7.4 (Berkeley) 6/3/91
  * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $
- * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.61 2004/07/05 00:07:35 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/machdep.c,v 1.62 2004/07/24 20:21:33 dillon Exp $
  */
 
 #include "use_apm.h"
@@ -1870,7 +1870,6 @@ init386(int first)
        lwkt_set_comm(&thread0, "thread0");
        proc0.p_addr = (void *)thread0.td_kstack;
        proc0.p_thread = &thread0;
-       proc0.p_flag |= P_CP_RELEASED;  /* early set.  See also init_main.c */
        varsymset_init(&proc0.p_varsymset, NULL);
        thread0.td_flags |= TDF_RUNNING;
        thread0.td_proc = &proc0;
index a2babd7..30cc801 100644 (file)
@@ -36,7 +36,7 @@
  *
  *     from: @(#)trap.c        7.4 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $
- * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.53 2004/07/06 01:52:24 hmp Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/trap.c,v 1.54 2004/07/24 20:21:33 dillon Exp $
  */
 
 /*
@@ -172,14 +172,10 @@ SYSCTL_INT(_machdep, OID_AUTO, slow_release, CTLFLAG_RW,
 MALLOC_DEFINE(M_SYSMSG, "sysmsg", "sysmsg structure");
 
 /*
- * USER->KERNEL transition.  Do not transition us out of userland from the
- * point of view of the userland scheduler unless we actually have to
- * switch.  Switching typically occurs when a process blocks in the kernel.
- *
- * passive_release is called from within a critical section and the BGL will
- * still be held.  This function is NOT called for preemptions, only for
- * switchouts.  Note that other elements of the system (uio_yield()) assume
- * that the user cruft will be released when lwkt_switch() is called.
+ * Passive USER->KERNEL transition.  This only occurs if we block in the
+ * kernel while still holding our userland priority.  We have to fixup our
+ * priority in order to avoid potential deadlocks before we allow the system
+ * to switch us to another thread.
  */
 static void
 passive_release(struct thread *td)
@@ -187,6 +183,7 @@ passive_release(struct thread *td)
        struct proc *p = td->td_proc;
 
        td->td_release = NULL;
+       lwkt_setpri_self(TDPRI_KERN_USER);
        release_curproc(p);
 }
 
@@ -203,30 +200,12 @@ userenter(struct thread *curtd)
 }
 
 /*
- * Reacquire our current process designation.  This will not return until
- * we have it.  Our LWKT priority will be adjusted for our return to
- * userland.  acquire_curproc() also handles cleaning up P_CP_RELEASED.
+ * Handle signals, upcalls, profiling, and other AST's and/or tasks that
+ * must be completed before we can return to or try to return to userland.
  *
- * This is always the last step before returning to user mode.
- */
-static __inline void
-userexit(struct proc *p)
-{
-       struct thread *td = p->p_thread;
-
-       td->td_release = NULL;
-       if (p->p_flag & P_CP_RELEASED)
-               ++slow_release;
-       else
-               ++fast_release;
-       acquire_curproc(p);
-}
-
-/*
- * userret() handles signals, upcalls, and deals with system profiling
- * charges.  Note that td_sticks is a 64 bit quantity, but there's no
- * point doing 64 arithmatic on the delta calculation so the absolute
- * tick values are truncated to an integer.
+ * Note that td_sticks is a 64 bit quantity, but there's no point doing 64
+ * arithmatic on the delta calculation so the absolute tick values are
+ * truncated to an integer.
  */
 static void
 userret(struct proc *p, struct trapframe *frame, int sticks)
@@ -248,17 +227,6 @@ userret(struct proc *p, struct trapframe *frame, int sticks)
                postsig(sig);
        }
 
-       /*
-        * If a reschedule has been requested then we release the current
-        * process in order to shift the current process designation to
-        * another user process and/or to switch to a higher priority
-        * kernel thread at userexit() time. 
-        */
-       if (any_resched_wanted()) {
-               p->p_thread->td_release = NULL;
-               release_curproc(p);
-       }
-
        /*
         * Charge system time if profiling.  Note: times are in microseconds.
         */
@@ -274,6 +242,88 @@ userret(struct proc *p, struct trapframe *frame, int sticks)
                postsig(sig);
 }
 
+/*
+ * Cleanup from userenter and any passive release that might have occured.
+ * We must reclaim the current-process designation before we can return
+ * to usermode.  We also handle both LWKT and USER reschedule requests.
+ */
+static __inline void
+userexit(struct proc *p)
+{
+       struct thread *td = p->p_thread;
+       globaldata_t gd = td->td_gd;
+
+#if 0
+       /*
+        * If a user reschedule is requested force a new process to be
+        * chosen by releasing the current process.  Our process will only
+        * be chosen again if it has a considerably better priority.
+        */
+       if (user_resched_wanted())
+               release_curproc(p);
+#endif
+
+again:
+       /*
+        * Handle a LWKT reschedule request first.  Since our passive release
+        * is still in place we do not have to do anything special.
+        */
+       if (lwkt_resched_wanted())
+               lwkt_switch();
+
+       /*
+        * Acquire the current process designation if we do not own it.
+        * Note that acquire_curproc() does not reset the user reschedule
+        * bit on purpose, because we may need to accumulate over several
+        * threads waking up at the same time.
+        *
+        * NOTE: userland scheduler cruft: because processes are removed
+        * from the userland scheduler's queue we run through loops to try
+        * to figure out which is the best of [ existing, waking-up ]
+        * threads.
+        */
+       if (p != gd->gd_uschedcp) {
+               ++slow_release;
+               acquire_curproc(p);
+               /* We may have switched cpus on acquisition */
+               gd = td->td_gd;
+       } else {
+               ++fast_release;
+       }
+
+       /*
+        * Reduce our priority in preparation for a return to userland.  If
+        * our passive release function was still in place, our priority was
+        * never raised and does not need to be reduced.
+        */
+       if (td->td_release == NULL)
+               lwkt_setpri_self(TDPRI_USER_NORM);
+       td->td_release = NULL;
+
+       /*
+        * After reducing our priority there might be other kernel-level
+        * LWKTs that now have a greater priority.  Run them as necessary.
+        * We don't have to worry about losing cpu to userland because
+        * we still control the current-process designation and we no longer
+        * have a passive release function installed.
+        */
+       if (lwkt_checkpri_self())
+               lwkt_switch();
+
+       /*
+        * If a userland reschedule is [still] pending we may not be the best
+        * selected process.  Select a better one.  If another LWKT resched
+        * is pending the trap will be re-entered.
+        */
+       if (user_resched_wanted()) {
+               select_curproc(gd);
+               if (p != gd->gd_uschedcp) {
+                       lwkt_setpri_self(TDPRI_KERN_USER);
+                       goto again;
+               }
+       }
+}
+
 #ifdef DEVICE_POLLING
 extern u_int32_t poll_in_trap;
 extern int ether_poll (int count);
@@ -1185,7 +1235,6 @@ syscall2(struct trapframe frame)
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
        caddr_t params;
-       int i;
        struct sysent *callp;
        register_t orig_tf_eflags;
        int sticks;
@@ -1241,9 +1290,7 @@ syscall2(struct trapframe frame)
                }
        }
 
-       if (p->p_sysent->sv_mask)
-               code &= p->p_sysent->sv_mask;
-
+       code &= p->p_sysent->sv_mask;
        if (code >= p->p_sysent->sv_size)
                callp = &p->p_sysent->sv_table[0];
        else
@@ -1254,13 +1301,17 @@ syscall2(struct trapframe frame)
        /*
         * copyin is MP aware, but the tracing code is not
         */
-       if (params && (i = narg * sizeof(register_t)) &&
-           (error = copyin(params, (caddr_t)(&args.nosys.usrmsg + 1), (u_int)i))) {
+       if (narg && params) {
+               error = copyin(params, (caddr_t)(&args.nosys.usrmsg + 1),
+                               narg * sizeof(register_t));
+               if (error) {
 #ifdef KTRACE
-               if (KTRPOINT(td, KTR_SYSCALL))
-                       ktrsyscall(p->p_tracep, code, narg, (void *)(&args.nosys.usrmsg + 1));
+                       if (KTRPOINT(td, KTR_SYSCALL))
+                               ktrsyscall(p->p_tracep, code, narg,
+                                       (void *)(&args.nosys.usrmsg + 1));
 #endif
-               goto bad;
+                       goto bad;
+               }
        }
 
 #if 0
index b399c5f..218a735 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)isa.c 7.2 (Berkeley) 5/13/91
  * $FreeBSD: src/sys/i386/isa/intr_machdep.c,v 1.29.2.5 2001/10/14 06:54:27 luigi Exp $
- * $DragonFly: src/sys/platform/pc32/isa/intr_machdep.c,v 1.22 2004/04/10 20:55:22 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/isa/intr_machdep.c,v 1.23 2004/07/24 20:21:34 dillon Exp $
  */
 /*
  * This file contains an aggregated module marked:
@@ -792,7 +792,7 @@ cpu_intr_preempt(struct thread *td, int critpri)
        if ((curthread->td_cpl & (1 << info->irq)) == 0)
                lwkt_preempt(td, critpri);
        else
-               need_lwkt_resched();
+               need_lwkt_resched(); /* XXX may not be required */
 }
 
 static int
index 6161569..2e58478 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)param.h     8.3 (Berkeley) 4/4/95
  * $FreeBSD: src/sys/sys/param.h,v 1.61.2.38 2003/05/22 17:12:01 fjoe Exp $
- * $DragonFly: src/sys/sys/param.h,v 1.14 2004/07/24 09:51:18 asmodai Exp $
+ * $DragonFly: src/sys/sys/param.h,v 1.15 2004/07/24 20:21:35 dillon Exp $
  */
 
 #ifndef _SYS_PARAM_H_
 #define PRIBASE_NORMAL         128
 #define PRIBASE_IDLE           256
 #define PRIBASE_THREAD         384     /* huh? */
+#define PRIBASE_NULL           512
 
 #define PCATCH         0x0100  /* OR'd with pri for tsleep to check signals */
 #define PUSRFLAG1      0x0200  /* Subsystem specific flag */
index cf4bd5c..cc97a24 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)proc.h      8.15 (Berkeley) 5/19/95
  * $FreeBSD: src/sys/sys/proc.h,v 1.99.2.9 2003/06/06 20:21:32 tegge Exp $
- * $DragonFly: src/sys/sys/proc.h,v 1.52 2004/07/23 13:19:42 hmp Exp $
+ * $DragonFly: src/sys/sys/proc.h,v 1.53 2004/07/24 20:21:35 dillon Exp $
  */
 
 #ifndef _SYS_PROC_H_
@@ -189,7 +189,7 @@ struct      proc {
        struct  vnode *p_textvp;        /* Vnode of executable. */
 
        char    p_lock;                 /* Process lock (prevent swap) count. */
-       short   p_priority;             /* overall process priority */
+       short   p_priority;             /* overall priority (lower==better) */
        char    p_rqindex;              /* Run queue index */
 
        unsigned int    p_stops;        /* procfs event bitmask */
@@ -212,7 +212,7 @@ struct      proc {
 
        sigset_t p_sigmask;     /* Current signal mask. */
        stack_t p_sigstk;       /* sp & on stack state variable */
-       u_char  p_unused00;     /* (used to be p_priority) */
+       char    p_interactive;  /* long term interactivity par-0 */
        char    p_nice;         /* Process "nice" value. */
 
        struct  pgrp *p_pgrp;   /* Pointer to process group. */
@@ -287,8 +287,7 @@ struct      proc {
 /* 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_CP_RELEASED  0x400000 /* directly schedule LWKT, ignore user schd */
-
+#define P_UNUSED400000 0x400000
 #define        P_DEADLKTREAT   0x800000 /* lock aquisition - deadlock treatment */
 
 #define        P_JAILED        0x1000000 /* Process is in jail */
@@ -448,6 +447,7 @@ int suser_cred (struct ucred *cred, int flag);
 void   remrunqueue (struct proc *);
 void   release_curproc (struct proc *curp);
 void   acquire_curproc (struct proc *curp);
+void   select_curproc(struct globaldata *);
 void   cpu_heavy_switch (struct thread *);
 void   cpu_lwkt_switch (struct thread *);
 void   unsleep (struct thread *);
index dfe0561..0bd0817 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/sys/sysent.h,v 1.27.2.5 2002/03/17 11:08:38 alfred Exp $
- * $DragonFly: src/sys/sys/sysent.h,v 1.7 2004/06/04 20:35:39 dillon Exp $
+ * $DragonFly: src/sys/sys/sysent.h,v 1.8 2004/07/24 20:21:35 dillon Exp $
  */
 
 #ifndef _SYS_SYSENT_H_
@@ -61,7 +61,7 @@ struct vnode;
 struct sysentvec {
        int             sv_size;        /* number of entries */
        struct sysent   *sv_table;      /* pointer to sysent */
-       u_int           sv_mask;        /* optional mask to index */
+       u_int           sv_mask;        /* optional mask to index, else -1 */
        int             sv_sigsize;     /* size of signal translation table */
        int             *sv_sigtbl;     /* signal translation table */
        int             sv_errsize;     /* size of errno translation table */
index 63776cf..1a01070 100644 (file)
@@ -7,7 +7,7 @@
  * Types which must already be defined when this header is included by
  * userland:   struct md_thread
  * 
- * $DragonFly: src/sys/sys/thread.h,v 1.55 2004/06/20 22:29:10 hmp Exp $
+ * $DragonFly: src/sys/sys/thread.h,v 1.56 2004/07/24 20:21:35 dillon Exp $
  */
 
 #ifndef _SYS_THREAD_H_
@@ -273,6 +273,7 @@ struct thread {
 #define TDF_TIMEOUT            0x8000  /* tsleep timeout */
 #define TDF_INTTHREAD          0x00010000      /* interrupt thread */
 #define TDF_NORESCHED          0x00020000      /* Do not reschedule on wake */
+#define TDF_BLOCKED            0x00040000      /* Thread is blocked */
 
 /*
  * Thread priorities.  Typically only one thread from any given
@@ -364,6 +365,7 @@ extern void lwkt_shunlock(lwkt_rwlock_t lock);
 
 extern void lwkt_setpri(thread_t td, int pri);
 extern void lwkt_setpri_self(int pri);
+extern int  lwkt_checkpri_self(void);
 extern void lwkt_setcpu_self(struct globaldata *rgd);
 extern int  lwkt_send_ipiq(struct globaldata *targ, ipifunc_t func, void *arg);
 extern int  lwkt_send_ipiq_passive(struct globaldata *targ, ipifunc_t func, void *arg);
index 9458dda..258656d 100644 (file)
@@ -60,7 +60,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/vm_glue.c,v 1.94.2.4 2003/01/13 22:51:17 dillon Exp $
- * $DragonFly: src/sys/vm/vm_glue.c,v 1.24 2004/06/20 22:29:10 hmp Exp $
+ * $DragonFly: src/sys/vm/vm_glue.c,v 1.25 2004/07/24 20:21:35 dillon Exp $
  */
 
 #include "opt_vm.h"
@@ -321,8 +321,12 @@ faultin(struct proc *p)
 
                s = splhigh();
 
+               /*
+                * The process is in the kernel and controlled by LWKT,
+                * so we just schedule it rather then call setrunqueue().
+                */
                if (p->p_stat == SRUN)
-                       setrunqueue(p);
+                       lwkt_schedule(p->p_thread);
 
                p->p_flag |= P_INMEM;