Skip to content
Snippets Groups Projects
Commit ac7a8447 authored by Avi Kivity's avatar Avi Kivity
Browse files

rcu: fix hang due to race while awaiting a quiescent state

Waiting for a quiescent state happens in two stages: first, we request all
cpus to schedule at least once.  Then, we wait until they do so.

If, between the two stages, a cpu is brought online, then we will request
N cpus to schedule but wait for N+1 to respond.  This of course never happens,
and the system hangs.

Fix by copying the vector which holds the cpus which we signal and wait for;
forcing them to be consistent.  This is safe since newly-added cpus cannot
be accessing any rcu-protected variables before we started signalling.

Fixes random hangs with rcu, mostly seen with 'perf callstack'
parent 748b168d
No related branches found
No related tags found
No related merge requests found
...@@ -68,9 +68,10 @@ void cpu_quiescent_state_thread::work() ...@@ -68,9 +68,10 @@ void cpu_quiescent_state_thread::work()
} }
} }
bool all_at_generation(uint64_t generation) bool all_at_generation(decltype(cpu_quiescent_state_threads)& cqsts,
uint64_t generation)
{ {
for (auto cqst : cpu_quiescent_state_threads) { for (auto cqst : cqsts) {
if (!cqst->check(generation)) { if (!cqst->check(generation)) {
return false; return false;
} }
...@@ -82,10 +83,15 @@ void await_grace_period() ...@@ -82,10 +83,15 @@ void await_grace_period()
{ {
static uint64_t generation = 0; static uint64_t generation = 0;
++generation; ++generation;
for (auto cqst : cpu_quiescent_state_threads) { // copy cpu_quiescent_state_threads to prevent a hotplugged cpu
// from changing the number of cpus we request a new generation on,
// and the number of cpus we wait on
// FIXME: better locking
auto cqsts = cpu_quiescent_state_threads;
for (auto cqst : cqsts) {
cqst->request(generation); cqst->request(generation);
} }
sched::thread::wait_until([] { return all_at_generation(generation); }); sched::thread::wait_until([&cqsts] { return all_at_generation(cqsts, generation); });
} }
void collect_garbage() void collect_garbage()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment