kernel/thread: Fix data race on to_do field

The inner execution loop in run_loop() reads and writes to_do
without holding the mutex, while exit_delete() and suspend()
modify it from other threads. This is a data race.

Restructure the inner loop so that every access to to_do is
under the mutex. The lock is acquired briefly to snapshot or
modify to_do, then released before guest execution. The lock
is held when the loop breaks out, matching the original post-loop
lock state.
This commit is contained in:
Sergi (セルジ)
2026-04-11 20:57:13 +09:00
parent 9410c9d9cd
commit a93e009add
+13 -7
View File
@@ -258,21 +258,27 @@ bool ThreadState::run_loop() {
}
// Run the cpu
do {
if (to_do == ThreadToDo::step) {
res = step(*cpu);
while (true) {
lock.lock();
if (to_do != ThreadToDo::run && to_do != ThreadToDo::step)
break;
if (res != 0 || call_level != run_level || hit_breakpoint(*cpu))
break;
const bool do_step = (to_do == ThreadToDo::step);
if (do_step)
to_do = ThreadToDo::suspend;
lock.unlock();
} else
if (do_step)
res = step(*cpu);
else
res = run(*cpu);
// handle svc call if this was what stopped the cpu
if (cpu->svc_called) {
cpu->protocol->call_svc(*cpu, cpu->svc, read_pc(*cpu), *this);
}
} while (to_do == ThreadToDo::run && res == 0 && call_level == run_level && !hit_breakpoint(*cpu));
lock.lock();
}
// Handle errors
if (to_do == ThreadToDo::remove)