aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-05-28 17:10:47 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-06-07 16:32:42 +0000
commitb25cbead39ca3e23de6f2a61f089da972b9f3157 (patch)
treef02194b6e838b4268374995b95fc3d3f55f3a627
parent664aff03fae2594e7db640c06c9edac5cb57bc7f (diff)
downloadsrc-b25cbead39ca3e23de6f2a61f089da972b9f3157.tar.gz
src-b25cbead39ca3e23de6f2a61f089da972b9f3157.zip
quisce_cpus(): add special handling for PDROP
(cherry picked from commit 3a68546d2377d6e9776060043372d66f07022543)
-rw-r--r--sys/kern/subr_smp.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c
index d4f8aac9e751..935fb6ee977c 100644
--- a/sys/kern/subr_smp.c
+++ b/sys/kern/subr_smp.c
@@ -943,25 +943,31 @@ smp_rendezvous_cpus_done(struct smp_rendezvous_cpus_retry_arg *arg)
}
/*
+ * If (prio & PDROP) == 0:
* Wait for specified idle threads to switch once. This ensures that even
* preempted threads have cycled through the switch function once,
* exiting their codepaths. This allows us to change global pointers
* with no other synchronization.
+ * If (prio & PDROP) != 0:
+ * Force the specified CPUs to switch context at least once.
*/
int
quiesce_cpus(cpuset_t map, const char *wmesg, int prio)
{
struct pcpu *pcpu;
- u_int gen[MAXCPU];
+ u_int *gen;
int error;
int cpu;
error = 0;
- for (cpu = 0; cpu <= mp_maxid; cpu++) {
- if (!CPU_ISSET(cpu, &map) || CPU_ABSENT(cpu))
- continue;
- pcpu = pcpu_find(cpu);
- gen[cpu] = pcpu->pc_idlethread->td_generation;
+ if ((prio & PDROP) == 0) {
+ gen = malloc(sizeof(u_int) * MAXCPU, M_TEMP, M_WAITOK);
+ for (cpu = 0; cpu <= mp_maxid; cpu++) {
+ if (!CPU_ISSET(cpu, &map) || CPU_ABSENT(cpu))
+ continue;
+ pcpu = pcpu_find(cpu);
+ gen[cpu] = pcpu->pc_idlethread->td_generation;
+ }
}
for (cpu = 0; cpu <= mp_maxid; cpu++) {
if (!CPU_ISSET(cpu, &map) || CPU_ABSENT(cpu))
@@ -970,8 +976,10 @@ quiesce_cpus(cpuset_t map, const char *wmesg, int prio)
thread_lock(curthread);
sched_bind(curthread, cpu);
thread_unlock(curthread);
+ if ((prio & PDROP) != 0)
+ continue;
while (gen[cpu] == pcpu->pc_idlethread->td_generation) {
- error = tsleep(quiesce_cpus, prio, wmesg, 1);
+ error = tsleep(quiesce_cpus, prio & ~PDROP, wmesg, 1);
if (error != EWOULDBLOCK)
goto out;
error = 0;
@@ -981,6 +989,8 @@ out:
thread_lock(curthread);
sched_unbind(curthread);
thread_unlock(curthread);
+ if ((prio & PDROP) == 0)
+ free(gen, M_TEMP);
return (error);
}