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

Kernel: Add a Finalizer process to take care of dying processes.

Instead of processes themselves getting scheduled to finish dying,
let's have a Finalizer process that wakes up whenever someone is dying.
This way we can do all kinds of lock-taking in process cleanup without
risking reentering the scheduler.
This commit is contained in:
Andreas Kling 2019-02-06 18:45:21 +01:00
parent e05237485c
commit 6cba80510e
5 changed files with 59 additions and 23 deletions

View file

@ -62,21 +62,21 @@ void Process::initialize()
Vector<pid_t> Process::all_pids()
{
InterruptDisabler disabler;
Vector<pid_t> pids;
pids.ensure_capacity(g_processes->size_slow());
pids.ensure_capacity(system.nprocess);
InterruptDisabler disabler;
for (auto* process = g_processes->head(); process; process = process->next())
pids.unchecked_append(process->pid());
pids.append(process->pid());
return pids;
}
Vector<Process*> Process::all_processes()
{
InterruptDisabler disabler;
Vector<Process*> processes;
processes.ensure_capacity(g_processes->size_slow());
processes.ensure_capacity(system.nprocess);
InterruptDisabler disabler;
for (auto* process = g_processes->head(); process; process = process->next())
processes.unchecked_append(process);
processes.append(process);
return processes;
}
@ -747,11 +747,9 @@ void Process::sys$exit(int status)
kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
#endif
die();
m_termination_status = status;
m_termination_signal = 0;
Scheduler::pick_next_and_switch_now();
die();
ASSERT_NOT_REACHED();
}
@ -952,7 +950,6 @@ void Process::crash()
m_termination_signal = SIGSEGV;
dump_regions();
die();
Scheduler::pick_next_and_switch_now();
ASSERT_NOT_REACHED();
}
@ -2122,29 +2119,32 @@ int Process::sys$chmod(const char* pathname, mode_t mode)
return 0;
}
void Process::die()
void Process::finalize()
{
// This is pretty hairy wrt interrupts. Once we set_state(Dead), we never get scheduled again.
// For this reason, we mark ourselves as Dying, which prevents the scheduler from dispatching signals in this process.
set_state(Dying);
InterruptFlagSaver saver;
ASSERT(current == g_finalizer);
// STI so we can take locks.
sti();
destroy_all_windows();
m_fds.clear();
m_tty = nullptr;
// CLI for Process::from_pid(). This should go away eventually.
cli();
if (auto* parent_process = Process::from_pid(m_ppid)) {
parent_process->send_signal(SIGCHLD, this);
{
InterruptDisabler disabler;
if (auto* parent_process = Process::from_pid(m_ppid)) {
parent_process->send_signal(SIGCHLD, this);
}
}
// Good night.
set_state(Dead);
}
void Process::die()
{
set_state(Dying);
if (!Scheduler::is_active())
Scheduler::pick_next_and_switch_now();
}
size_t Process::amount_virtual() const
{
size_t amount = 0;
@ -2186,3 +2186,18 @@ size_t Process::amount_shared() const
}
return amount;
}
void Process::finalize_dying_processes()
{
Vector<Process*> dying_processes;
{
InterruptDisabler disabler;
dying_processes.ensure_capacity(system.nprocess);
for (auto* process = g_processes->head(); process; process = process->next()) {
if (process->state() == Process::Dying)
dying_processes.append(process);
}
}
for (auto* process : dying_processes)
process->finalize();
}