svn commit: r355644 - head/sys/kern
Mark Johnston
markj at FreeBSD.org
Thu Dec 12 02:43:25 UTC 2019
Author: markj
Date: Thu Dec 12 02:43:24 2019
New Revision: 355644
URL: https://svnweb.freebsd.org/changeset/base/355644
Log:
Rename tdq_ipipending and clear it in sched_switch().
This fixes a regression after r355311. Specifically, sched_preempt()
may trigger a context switch by calling thread_lock(), since
thread_lock() calls critical_exit() in its slow path and the interrupted
thread may have already been marked for preemption. This would happen
before tdq_ipipending is cleared, blocking further preemption IPIs. The
CPU can be left in this state indefinitely if the interrupted thread
migrates.
Rename tdq_ipipending to tdq_owepreempt. Any switch satisfies a remote
preemption request, so clear tdq_owepreempt in sched_switch() instead of
sched_preempt() to avoid subtle problems of the sort described above.
Reviewed by: jeff, kib
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D22758
Modified:
head/sys/kern/sched_ule.c
Modified: head/sys/kern/sched_ule.c
==============================================================================
--- head/sys/kern/sched_ule.c Thu Dec 12 02:42:27 2019 (r355643)
+++ head/sys/kern/sched_ule.c Thu Dec 12 02:43:24 2019 (r355644)
@@ -244,7 +244,7 @@ struct tdq {
volatile short tdq_switchcnt; /* Switches this tick. */
volatile short tdq_oldswitchcnt; /* Switches last tick. */
u_char tdq_lowpri; /* Lowest priority thread. */
- u_char tdq_ipipending; /* IPI pending. */
+ u_char tdq_owepreempt; /* Remote preemption pending. */
u_char tdq_idx; /* Current insert index. */
u_char tdq_ridx; /* Current removal index. */
int tdq_id; /* cpuid. */
@@ -1073,7 +1073,7 @@ tdq_notify(struct tdq *tdq, struct thread *td)
int pri;
int cpu;
- if (tdq->tdq_ipipending)
+ if (tdq->tdq_owepreempt)
return;
cpu = td_get_sched(td)->ts_cpu;
pri = td->td_priority;
@@ -1096,7 +1096,12 @@ tdq_notify(struct tdq *tdq, struct thread *td)
if (!tdq->tdq_cpu_idle || cpu_idle_wakeup(cpu))
return;
}
- tdq->tdq_ipipending = 1;
+
+ /*
+ * The run queues have been updated, so any switch on the remote CPU
+ * will satisfy the preemption request.
+ */
+ tdq->tdq_owepreempt = 1;
ipi_cpu(cpu, IPI_PREEMPT);
}
@@ -2079,8 +2084,10 @@ sched_switch(struct thread *td, struct thread *newtd,
(flags & SW_PREEMPT) != 0;
td->td_flags &= ~(TDF_NEEDRESCHED | TDF_SLICEEND);
td->td_owepreempt = 0;
+ tdq->tdq_owepreempt = 0;
if (!TD_IS_IDLETHREAD(td))
tdq->tdq_switchcnt++;
+
/*
* The lock pointer in an idle thread should never change. Reset it
* to CAN_RUN as well.
@@ -2386,7 +2393,6 @@ sched_preempt(struct thread *td)
thread_lock(td);
tdq = TDQ_SELF();
TDQ_LOCK_ASSERT(tdq, MA_OWNED);
- tdq->tdq_ipipending = 0;
if (td->td_priority > tdq->tdq_lowpri) {
int flags;
@@ -2397,6 +2403,8 @@ sched_preempt(struct thread *td)
mi_switch(flags | SWT_REMOTEWAKEIDLE, NULL);
else
mi_switch(flags | SWT_REMOTEPREEMPT, NULL);
+ } else {
+ tdq->tdq_owepreempt = 0;
}
thread_unlock(td);
}
More information about the svn-src-all
mailing list