mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-20 11:11:24 +00:00
Prevent preemption in slot_fill.
Implement preemption between threads in the same ksegp in out of slot situations to prevent priority inversion. Tested by: pho Reviewed by: jhb, julian Approved by: sam (mentor) MFC: ASAP
This commit is contained in:
parent
b9a80acadb
commit
84f9d4b137
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=136438
@ -214,7 +214,7 @@ slot_fill(struct ksegrp *kg)
|
|||||||
*/
|
*/
|
||||||
if (td) {
|
if (td) {
|
||||||
kg->kg_last_assigned = td;
|
kg->kg_last_assigned = td;
|
||||||
sched_add(td, SRQ_BORING);
|
sched_add(td, SRQ_YIELDING);
|
||||||
CTR2(KTR_RUNQ, "slot_fill: td%p -> kg%p", td, kg);
|
CTR2(KTR_RUNQ, "slot_fill: td%p -> kg%p", td, kg);
|
||||||
} else {
|
} else {
|
||||||
/* no threads to use up the slots. quit now */
|
/* no threads to use up the slots. quit now */
|
||||||
@ -315,6 +315,113 @@ adjustrunqueue( struct thread *td, int newpri)
|
|||||||
td->td_priority = newpri;
|
td->td_priority = newpri;
|
||||||
setrunqueue(td, SRQ_BORING);
|
setrunqueue(td, SRQ_BORING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is called when a thread is about to be put on a
|
||||||
|
* ksegrp run queue because it has been made runnable or its
|
||||||
|
* priority has been adjusted and the ksegrp does not have a
|
||||||
|
* free kse slot. It determines if a thread from the same ksegrp
|
||||||
|
* should be preempted. If so, it tries to switch threads
|
||||||
|
* if the thread is on the same cpu or notifies another cpu that
|
||||||
|
* it should switch threads.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
maybe_preempt_in_ksegrp(struct thread *td)
|
||||||
|
{
|
||||||
|
#if defined(SMP)
|
||||||
|
int worst_pri;
|
||||||
|
struct ksegrp *kg;
|
||||||
|
cpumask_t cpumask,dontuse;
|
||||||
|
struct pcpu *pc;
|
||||||
|
struct pcpu *best_pcpu;
|
||||||
|
struct thread *running_thread;
|
||||||
|
struct thread *cputhread;
|
||||||
|
|
||||||
|
#ifndef FULL_PREEMPTION
|
||||||
|
int pri;
|
||||||
|
pri = td->td_priority;
|
||||||
|
if (!(pri >= PRI_MIN_ITHD && pri <= PRI_MAX_ITHD))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mtx_assert(&sched_lock, MA_OWNED);
|
||||||
|
|
||||||
|
running_thread = curthread;
|
||||||
|
|
||||||
|
#if !defined(KSEG_PEEMPT_BEST_CPU)
|
||||||
|
if (running_thread->td_ksegrp != td->td_ksegrp) {
|
||||||
|
#endif
|
||||||
|
kg = td->td_ksegrp;
|
||||||
|
|
||||||
|
/* if someone is ahead of this thread, wait our turn */
|
||||||
|
if (td != TAILQ_FIRST(&kg->kg_runq))
|
||||||
|
return;
|
||||||
|
|
||||||
|
worst_pri = td->td_priority;
|
||||||
|
best_pcpu = NULL;
|
||||||
|
dontuse = stopped_cpus | idle_cpus_mask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find a cpu with the worst priority that runs at thread from
|
||||||
|
* the same ksegrp - if multiple exist give first the last run
|
||||||
|
* cpu and then the current cpu priority
|
||||||
|
*/
|
||||||
|
|
||||||
|
SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
|
||||||
|
cpumask = pc->pc_cpumask;
|
||||||
|
cputhread = pc->pc_curthread;
|
||||||
|
|
||||||
|
if ((cpumask & dontuse) ||
|
||||||
|
cputhread->td_ksegrp != kg)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cputhread->td_priority > worst_pri) {
|
||||||
|
worst_pri = cputhread->td_priority;
|
||||||
|
best_pcpu = pc;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cputhread->td_priority == worst_pri &&
|
||||||
|
best_pcpu != NULL &&
|
||||||
|
(td->td_lastcpu == pc->pc_cpuid ||
|
||||||
|
(PCPU_GET(cpumask) == cpumask &&
|
||||||
|
td->td_lastcpu != best_pcpu->pc_cpuid)))
|
||||||
|
best_pcpu = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we need to preempt someone */
|
||||||
|
if (best_pcpu == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PCPU_GET(cpuid) != best_pcpu->pc_cpuid) {
|
||||||
|
best_pcpu->pc_curthread->td_flags |= TDF_NEEDRESCHED;
|
||||||
|
ipi_selected(best_pcpu->pc_cpumask, IPI_AST);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if !defined(KSEG_PEEMPT_BEST_CPU)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
KASSERT(running_thread->td_ksegrp == td->td_ksegrp,
|
||||||
|
("maybe_preempt_in_ksegrp: No chance to run thread"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (td->td_priority > running_thread->td_priority)
|
||||||
|
return;
|
||||||
|
#ifdef PREEMPTION
|
||||||
|
if (running_thread->td_critnest > 1)
|
||||||
|
running_thread->td_pflags |= TDP_OWEPREEMPT;
|
||||||
|
else
|
||||||
|
mi_switch(SW_INVOL, NULL);
|
||||||
|
|
||||||
|
#else
|
||||||
|
running_thread->td_flags |= TDF_NEEDRESCHED;
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int limitcount;
|
int limitcount;
|
||||||
void
|
void
|
||||||
setrunqueue(struct thread *td, int flags)
|
setrunqueue(struct thread *td, int flags)
|
||||||
@ -421,6 +528,8 @@ setrunqueue(struct thread *td, int flags)
|
|||||||
} else {
|
} else {
|
||||||
CTR3(KTR_RUNQ, "setrunqueue: held: td%p kg%p pid%d",
|
CTR3(KTR_RUNQ, "setrunqueue: held: td%p kg%p pid%d",
|
||||||
td, td->td_ksegrp, td->td_proc->p_pid);
|
td, td->td_ksegrp, td->td_proc->p_pid);
|
||||||
|
if ((flags & SRQ_YIELDING) == 0)
|
||||||
|
maybe_preempt_in_ksegrp(td);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user