mirror of
https://github.com/RGBCube/serenity
synced 2025-05-16 18:25:06 +00:00
Thread: Cleanup m_blocker handling
The only two places we set m_blocker now are Thread::set_state(), and Thread::block(). set_state is mostly just an issue of clarity: we don't want to end up with state() != Blocked with an m_blocker, because that's weird. It's also possible: if we yield, someone else may set_state() us. We also now set_state() and set m_blocker under lock in block(), rather than unlocking which might allow someone else to mess with our internals while we're in the process of trying to block. This seems to fix sending STOP & CONT causing a panic. My guess as to what was happening is this: thread A blocks in select(): Blocking & m_blocker != nullptr thread B sends SIGSTOP: Stopped & m_blocker != nullptr thread B sends SIGCONT: we continue execution. Runnable & m_blocker != nullptr thread A tries to block in select() again: * sets m_blocker * unlocks (in block_helper) * someone else tries to unblock us? maybe from the old m_blocker? unclear -- clears m_blocker * sets Blocked (while unlocked!) So, thread A is left with state Blocked & m_blocker == nullptr, leading to the scheduler assert (m_blocker != nullptr) failing. Long story short, let's do all our data management with the lock _held_.
This commit is contained in:
parent
046f00f77e
commit
d48c73b10a
3 changed files with 21 additions and 10 deletions
|
@ -222,10 +222,8 @@ void Thread::consider_unblock(time_t now_sec, long now_usec)
|
|||
return;
|
||||
case Thread::Blocked:
|
||||
ASSERT(m_blocker);
|
||||
if (m_blocker->should_unblock(*this, now_sec, now_usec)) {
|
||||
if (m_blocker->should_unblock(*this, now_sec, now_usec))
|
||||
unblock();
|
||||
m_blocker = nullptr;
|
||||
}
|
||||
return;
|
||||
case Thread::Skip1SchedulerPass:
|
||||
set_state(Thread::Skip0SchedulerPasses);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue