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

Kernel: Unwind kernel stacks before dying

While executing in the kernel, a thread can acquire various resources
that need cleanup, such as locks and references to RefCounted objects.
This cleanup normally happens on the exit path, such as in destructors
for various RAII guards. But we weren't calling those exit paths when
killing threads that have been executing in the kernel, such as threads
blocked on reading or sleeping, thus causing leaks.

This commit changes how killing threads works. Now, instead of killing
a thread directly, one is supposed to call thread->set_should_die(),
which will unblock it and make it unwind the stack if it is blocked
in the kernel. Then, just before returning to the userspace, the thread
will automatically die.
This commit is contained in:
Sergey Bugaev 2019-11-14 18:46:01 +03:00 committed by Andreas Kling
parent 00e56cda0c
commit 1e1ddce9d8
4 changed files with 58 additions and 7 deletions

View file

@ -131,6 +131,46 @@ void Thread::unblock()
set_state(Thread::Runnable);
}
void Thread::set_should_die()
{
if (m_should_die)
return;
InterruptDisabler disabler;
// Remember that we should die instead of returning to
// the userspace.
m_should_die = true;
if (is_blocked()) {
ASSERT(in_kernel());
ASSERT(m_blocker != nullptr);
// We're blocked in the kernel. Pretend to have
// been interrupted by a signal (perhaps that is
// what has actually killed us).
m_blocker->set_interrupted_by_signal();
unblock();
} else if (!in_kernel()) {
// We're executing in userspace (and we're clearly
// not the current thread). No need to unwind, so
// set the state to dying right away. This also
// makes sure we won't be scheduled anymore.
set_state(Thread::State::Dying);
}
}
void Thread::die_if_needed()
{
ASSERT(current == this);
if (!m_should_die)
return;
InterruptDisabler disabler;
set_state(Thread::State::Dying);
if (!Scheduler::is_active())
Scheduler::pick_next_and_switch_now();
}
void Thread::block_helper()
{
// This function mostly exists to avoid circular header dependencies. If