Clearing the flag when preempting will let the preempted thread run

too much time. This can finish in a scheduler deadlock with ping-pong
between two threads.

One sample of this is:
- device lapic (to have a preemption point on critical_exit())
- options DEVICE_POLLING with HZ>1499 (to have lapic freq = hardclock freq)
- running a cpu intensive task (that does not enter the kernel)
- only one CPU on SMP or no SMP.

As requested by jhb@ 4BSD have received the same type of fix instead of
propagating the flag to the new thread.

Reviewed by:	jhb, jeff
MFC after:	1 month
This commit is contained in:
Fabien Thomas 2011-03-31 13:59:47 +00:00
parent a90dd577e7
commit 586cb6ec77
2 changed files with 4 additions and 7 deletions

View File

@ -940,13 +940,9 @@ sched_switch(struct thread *td, struct thread *newtd, int flags)
if ((td->td_flags & TDF_NOLOAD) == 0)
sched_load_rem();
if (newtd) {
MPASS(newtd->td_lock == &sched_lock);
newtd->td_flags |= (td->td_flags & TDF_NEEDRESCHED);
}
td->td_lastcpu = td->td_oncpu;
td->td_flags &= ~TDF_NEEDRESCHED;
if (!(flags & SW_PREEMPT))
td->td_flags &= ~TDF_NEEDRESCHED;
td->td_owepreempt = 0;
td->td_oncpu = NOCPU;

View File

@ -1783,7 +1783,8 @@ sched_switch(struct thread *td, struct thread *newtd, int flags)
ts->ts_rltick = ticks;
td->td_lastcpu = td->td_oncpu;
td->td_oncpu = NOCPU;
td->td_flags &= ~TDF_NEEDRESCHED;
if (!(flags & SW_PREEMPT))
td->td_flags &= ~TDF_NEEDRESCHED;
td->td_owepreempt = 0;
tdq->tdq_switchcnt++;
/*