Index: kern/sched_ule.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sched_ule.c,v retrieving revision 1.243 diff -u -r1.243 sched_ule.c --- kern/sched_ule.c 17 Apr 2008 09:56:01 -0000 1.243 +++ kern/sched_ule.c 22 Apr 2008 12:21:17 -0000 @@ -2201,29 +2201,58 @@ return (PCPU_GET(idlethread)); } +int oldresched = 0; + /* * Set owepreempt if necessary. Preemption never happens directly in ULE, - * we always request it once we exit a critical section. + * we always request it once we exit a critical section. If preemption is + * not set we may conditionally set NEEDRESCHED if the woken thread should + * be running. */ static inline void sched_setpreempt(struct thread *td) { struct thread *ctd; + struct tdq *tdq; int cpri; int pri; + u_char cdelta; + u_char delta; THREAD_LOCK_ASSERT(curthread, MA_OWNED); ctd = curthread; pri = td->td_priority; cpri = ctd->td_priority; - if (pri < cpri) + if (oldresched && pri < cpri) ctd->td_flags |= TDF_NEEDRESCHED; if (panicstr != NULL || pri >= cpri || cold || TD_IS_INHIBITED(ctd)) return; - if (!sched_shouldpreempt(pri, cpri, 0)) + if (sched_shouldpreempt(pri, cpri, 0)) { + ctd->td_owepreempt = 1; + return; + } + if (oldresched) + return; + /* + * Timeshare threads require special checks to see if the newly + * woken thread should be run straight away or if the existing + * thread may continue. + */ + tdq = TDQ_SELF(); + if (ctd->td_sched->ts_runq != &tdq->tdq_timeshare || + td->td_sched->ts_runq != &tdq->tdq_timeshare) { + ctd->td_flags |= TDF_NEEDRESCHED; return; - ctd->td_owepreempt = 1; + } + /* + * Compute the distance from the head of the queue. If the new + * thread is closer than curthread force a reschedule. + */ + cdelta = (ctd->td_rqindex - tdq->tdq_ridx) % RQ_NQS; + delta = (td->td_rqindex - tdq->tdq_ridx) % RQ_NQS; + if (delta < cdelta) + ctd->td_flags |= TDF_NEEDRESCHED; } /* @@ -2588,6 +2617,8 @@ 0,"Number of times idle will spin waiting for new work."); SYSCTL_INT(_kern_sched, OID_AUTO, idlespinthresh, CTLFLAG_RW, &sched_idlespinthresh, 0,"Threshold before we will permit idle spinning."); +SYSCTL_INT(_kern_sched, OID_AUTO, oldresched, CTLFLAG_RW, &oldresched, + 0,"Threshold before we will permit idle spinning."); #ifdef SMP SYSCTL_INT(_kern_sched, OID_AUTO, affinity, CTLFLAG_RW, &affinity, 0, "Number of hz ticks to keep thread affinity for");