1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:37:46 +00:00

Waiters should be notified when a waitee is killed.

Ran into a horrendous bug where VirtualConsole would overrun its buffer
and scribble right into some other object if we were interrupted while
processing a character. Slapped an InterruptDisabler onto onChar for now.

This provokes an interesting question though.. if a process is killed
while its in kernel space, how the heck do we release any locks it held?
I'm sure there are many different solutions to this problem, but I'll
have to think about it.
This commit is contained in:
Andreas Kling 2018-11-01 01:04:02 +01:00
parent 9a086b2d35
commit a685809e75
7 changed files with 36 additions and 8 deletions

View file

@ -518,6 +518,15 @@ void Task::dumpRegions()
}
}
void Task::notify_waiters(pid_t waitee, int exit_status, int signal)
{
ASSERT_INTERRUPTS_DISABLED();
for (auto* task = s_tasks->head(); task; task = task->next()) {
if (task->waitee() == waitee)
task->m_waiteeStatus = (exit_status << 8) | (signal);
}
}
void Task::sys$exit(int status)
{
cli();
@ -531,10 +540,7 @@ void Task::sys$exit(int status)
s_tasks->remove(this);
for (auto* task = s_tasks->head(); task; task = task->next()) {
if (task->waitee() == m_pid)
task->m_waiteeStatus = status << 8;
}
notify_waiters(m_pid, status, 0);
if (!scheduleNewTask()) {
kprintf("Task::sys$exit: Failed to schedule a new task :(\n");
@ -546,13 +552,17 @@ void Task::sys$exit(int status)
switchNow();
}
void Task::murder()
void Task::murder(int signal)
{
ASSERT_INTERRUPTS_DISABLED();
bool wasCurrent = current == this;
setState(Exiting);
s_tasks->remove(this);
notify_waiters(m_pid, 0, signal);
if (wasCurrent) {
kprintf("Current task committing suicide!\n");
MM.unmapRegionsForTask(*this);
if (!scheduleNewTask()) {
kprintf("Task::murder: Failed to schedule a new task :(\n");
@ -578,6 +588,8 @@ void Task::taskDidCrash(Task* crashedTask)
s_tasks->remove(crashedTask);
notify_waiters(crashedTask->m_pid, 0, SIGSEGV);
MM.unmapRegionsForTask(*crashedTask);
if (!scheduleNewTask()) {
@ -991,8 +1003,9 @@ int Task::sys$kill(pid_t pid, int sig)
auto* peer = Task::fromPID(pid);
if (!peer)
return -ESRCH;
if (sig == 9) {
peer->murder();
if (sig == SIGKILL) {
peer->murder(SIGKILL);
return 0;
} else {
ASSERT_NOT_REACHED();
}