From 6cba80510e2d5310c6ec545e93ab85b18bc7e3c4 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 6 Feb 2019 18:45:21 +0100 Subject: [PATCH] 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. --- Kernel/Process.cpp | 59 +++++++++++++++++++++++++++----------------- Kernel/Process.h | 4 +++ Kernel/Scheduler.cpp | 10 +++++++- Kernel/Scheduler.h | 1 + Kernel/init.cpp | 8 ++++++ 5 files changed, 59 insertions(+), 23 deletions(-) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 128b10af295..f44e9347c7e 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -62,21 +62,21 @@ void Process::initialize() Vector Process::all_pids() { - InterruptDisabler disabler; Vector 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::all_processes() { - InterruptDisabler disabler; Vector 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 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(); +} diff --git a/Kernel/Process.h b/Kernel/Process.h index fa516f5700d..41339740c89 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -60,6 +60,7 @@ public: static Vector all_pids(); static Vector all_processes(); + static void finalize_dying_processes(); enum State { Invalid = 0, @@ -70,6 +71,7 @@ public: Dying, Dead, BeingInspected, + BlockedLurking, BlockedSleep, BlockedWait, BlockedRead, @@ -135,6 +137,7 @@ public: void set_selector(word s) { m_far_ptr.selector = s; } void set_state(State s) { m_state = s; } void die(); + void finalize(); pid_t sys$setsid(); pid_t sys$getsid(pid_t); @@ -453,6 +456,7 @@ static inline const char* to_string(Process::State state) case Process::BlockedWrite: return "Write"; case Process::BlockedSignal: return "Signal"; case Process::BlockedSelect: return "Select"; + case Process::BlockedLurking: return "Lurking"; case Process::BeingInspected: return "Inspect"; } ASSERT_NOT_REACHED(); diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 20f3b2020fe..036803fa6b4 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -12,6 +12,7 @@ static const dword time_slice = 5; // *10 = 50ms Process* current; Process* g_last_fpu_process; +Process* g_finalizer; static Process* s_colonel_process; struct TaskRedirectionData { @@ -127,6 +128,13 @@ bool Scheduler::pick_next() return true; } + if (process.state() == Process::Dying) { + ASSERT(g_finalizer); + if (g_finalizer->state() == Process::BlockedLurking) + g_finalizer->unblock(); + return true; + } + return true; }); @@ -170,7 +178,7 @@ bool Scheduler::pick_next() g_processes->append(g_processes->remove_head()); auto* process = g_processes->head(); - if (process->state() == Process::Runnable || process->state() == Process::Running || process->state() == Process::Dying) { + if (process->state() == Process::Runnable || process->state() == Process::Running) { #ifdef SCHEDULER_DEBUG dbgprintf("switch to %s(%u) @ %w:%x\n", process->name().characters(), process->pid(), process->tss().cs, process->tss().eip); #endif diff --git a/Kernel/Scheduler.h b/Kernel/Scheduler.h index 795b5dda4b4..b6db08dddb9 100644 --- a/Kernel/Scheduler.h +++ b/Kernel/Scheduler.h @@ -7,6 +7,7 @@ struct RegisterDump; extern Process* current; extern Process* g_last_fpu_process; +extern Process* g_finalizer; class Scheduler { public: diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 47f00183576..545d94357da 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -187,6 +187,14 @@ void init() sleep(10 * TICKS_PER_SECOND); } }); + Process::create_kernel_process("Finalizer", [] { + g_finalizer = current; + for (;;) { + Process::finalize_dying_processes(); + current->block(Process::BlockedLurking); + Scheduler::yield(); + } + }); Scheduler::pick_next();