1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 10:38:11 +00:00

Scheduler: Allow reentry into block()

With the presence of signal handlers, it is possible that a thread might
be blocked multiple times. Picture for instance a signal handler using
read(), or wait() while the thread is already blocked elsewhere before
the handler is invoked.

To fix this, we turn m_blocker into a chain of handlers. Each block()
call now prepends to the list, and unblocking will only consider the
most recent (first) blocker in the chain.

Fixes #309
This commit is contained in:
Robin Burchell 2019-07-21 12:14:58 +02:00 committed by Andreas Kling
parent a9db382f0e
commit dea7f937bf
3 changed files with 37 additions and 17 deletions

View file

@ -221,8 +221,8 @@ void Thread::consider_unblock(time_t now_sec, long now_usec)
/* don't know, don't care */
return;
case Thread::Blocked:
ASSERT(m_blocker);
if (m_blocker->should_unblock(*this, now_sec, now_usec))
ASSERT(!m_blockers.is_empty());
if (m_blockers.first()->should_unblock(*this, now_sec, now_usec))
unblock();
return;
case Thread::Skip1SchedulerPass:
@ -307,8 +307,8 @@ bool Scheduler::pick_next()
return IterationDecision::Continue;
if (was_blocked) {
dbgprintf("Unblock %s(%u) due to signal\n", thread.process().name().characters(), thread.pid());
ASSERT(thread.m_blocker);
thread.m_blocker->set_interrupted_by_signal();
ASSERT(!thread.m_blockers.is_empty());
thread.m_blockers.first()->set_interrupted_by_signal();
thread.unblock();
}
return IterationDecision::Continue;