mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 23:47:45 +00:00
Kernel: Dispatch pending signals when returning from a syscall
It was quite easy to put the system into a heavy churn state by doing e.g "cat /dev/zero". It was then basically impossible to kill the "cat" process, even with "kill -9", since signals are only delivered in two conditions: a) The target thread is blocked in the kernel b) The target thread is running in userspace However, since "cat /dev/zero" command spends most of its time actively running in the kernel, not blocked, the signal dispatch code just kept postponing actually handling the signal indefinitely. To fix this, we now check before returning from a syscall if there are any pending unmasked signals, and if so, we take a dramatic pause by blocking the current thread, knowing it will immediately be unblocked by signal dispatch anyway. :^)
This commit is contained in:
parent
62a191b59a
commit
8b54ba0d61
2 changed files with 6 additions and 5 deletions
|
@ -322,11 +322,9 @@ bool Scheduler::pick_next()
|
||||||
if (&thread == current)
|
if (&thread == current)
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
// We know how to interrupt blocked processes, but if they are just executing
|
// We know how to interrupt blocked processes, but if they are just executing
|
||||||
// at some random point in the kernel, let them continue. They'll be in userspace
|
// at some random point in the kernel, let them continue.
|
||||||
// sooner or later and we can deliver the signal then.
|
// Before returning to userspace from a syscall, we will block a thread if it has any
|
||||||
// FIXME: Maybe we could check when returning from a syscall if there's a pending
|
// pending unmasked signals, allowing it to be dispatched then.
|
||||||
// signal and dispatch it then and there? Would that be doable without the
|
|
||||||
// syscall effectively being "interrupted" despite having completed?
|
|
||||||
if (thread.in_kernel() && !thread.is_blocked() && !thread.is_stopped())
|
if (thread.in_kernel() && !thread.is_blocked() && !thread.is_stopped())
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
// NOTE: dispatch_one_pending_signal() may unblock the process.
|
// NOTE: dispatch_one_pending_signal() may unblock the process.
|
||||||
|
|
|
@ -135,4 +135,7 @@ void syscall_handler(RegisterDump regs)
|
||||||
|
|
||||||
// Check if we're supposed to return to userspace or just die.
|
// Check if we're supposed to return to userspace or just die.
|
||||||
current->die_if_needed();
|
current->die_if_needed();
|
||||||
|
|
||||||
|
if (current->has_unmasked_pending_signals())
|
||||||
|
(void)current->block<Thread::SemiPermanentBlocker>(Thread::SemiPermanentBlocker::Reason::Signal);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue