Kernel: Ensure only user processes are terminated properly in shutdown

This patch ensures that the shutdown procedure can complete due to the
fact we don't kill kernel processes anymore, and only stop the scheduler
from running after the filesystems unmount procedure.

We also need kernel processes during the shutdown procedure, because we
rely on the WorkQueue threads to run WorkQueue items to complete async
IO requests initiated by filesystem sync & unmounting, etc.

This is also simplifying the code around the killing processes, because
we don't need to worry about edge cases such as the FinalizerTask
anymore.
This commit is contained in:
Liav A 2023-08-19 19:07:17 +03:00 committed by Andrew Kaster
parent 7082a1f0c4
commit b81b2c3fe7
2 changed files with 21 additions and 22 deletions

View file

@ -90,14 +90,11 @@ ErrorOr<void> PowerStateSwitchTask::perform_shutdown()
g_in_system_shutdown = true;
// Make sure to kill all user processes first, otherwise we might get weird hangups.
TRY(kill_processes(ProcessKind::User, finalizer_process->pid()));
TRY(kill_processes(ProcessKind::Kernel, finalizer_process->pid()));
TRY(kill_all_user_processes());
finalizer_process->die();
finalizer_process->finalize();
size_t alive_process_count = 0;
Process::all_instances().for_each([&](Process& process) {
if (process.pid() != Process::current().pid() && !process.is_dead())
if (!process.is_kernel_process() && !process.is_dead())
alive_process_count++;
});
// Don't panic here (since we may panic in a bit anyways) but report the probable cause of an unclean shutdown.
@ -143,6 +140,12 @@ ErrorOr<void> PowerStateSwitchTask::perform_shutdown()
}
}
// NOTE: We don't really need to kill kernel processes, because in contrast
// to user processes, kernel processes will simply not make syscalls
// or do some other unexpected behavior.
// Therefore, we just lock the scheduler big lock to ensure nothing happens
// beyond this point forward.
SpinlockLocker lock(g_scheduler_lock);
dbgln("Attempting system shutdown...");
arch_specific_poweroff();
@ -152,15 +155,15 @@ ErrorOr<void> PowerStateSwitchTask::perform_shutdown()
Processor::halt();
}
ErrorOr<void> PowerStateSwitchTask::kill_processes(ProcessKind kind, ProcessID finalizer_pid)
ErrorOr<void> PowerStateSwitchTask::kill_all_user_processes()
{
bool kill_kernel_processes = kind == ProcessKind::Kernel;
Process::all_instances().for_each([&](Process& process) {
if (process.pid() != Process::current().pid() && process.pid() != finalizer_pid && process.is_kernel_process() == kill_kernel_processes) {
process.die();
}
});
{
SpinlockLocker lock(g_scheduler_lock);
Process::all_instances().for_each([&](Process& process) {
if (!process.is_kernel_process())
process.die();
});
}
// Although we *could* finalize processes ourselves (g_in_system_shutdown allows this),
// we're nice citizens and let the finalizer task perform final duties before we kill it.
@ -171,7 +174,7 @@ ErrorOr<void> PowerStateSwitchTask::kill_processes(ProcessKind kind, ProcessID f
Scheduler::yield();
alive_process_count = 0;
Process::all_instances().for_each([&](Process& process) {
if (process.pid() != Process::current().pid() && !process.is_dead() && process.pid() != finalizer_pid && process.is_kernel_process() == kill_kernel_processes)
if (!process.is_kernel_process() && !process.is_dead())
alive_process_count++;
});
@ -181,9 +184,9 @@ ErrorOr<void> PowerStateSwitchTask::kill_processes(ProcessKind kind, ProcessID f
if constexpr (PROCESS_DEBUG) {
Process::all_instances().for_each_const([&](Process const& process) {
if (process.pid() != Process::current().pid() && !process.is_dead() && process.pid() != finalizer_pid && process.is_kernel_process() == kill_kernel_processes) {
dbgln("Process {:2} kernel={} dead={} dying={} ({})",
process.pid(), process.is_kernel_process(), process.is_dead(), process.is_dying(),
if (!process.is_kernel_process() && !process.is_dead()) {
dbgln("Process (user) {:2} dead={} dying={} ({})",
process.pid(), process.is_dead(), process.is_dying(),
process.name().with([](auto& name) { return name.representable_view(); }));
}
});

View file

@ -32,11 +32,7 @@ private:
static ErrorOr<void> perform_reboot();
static ErrorOr<void> perform_shutdown();
enum class ProcessKind {
User,
Kernel,
};
static ErrorOr<void> kill_processes(ProcessKind, ProcessID finalizer_pid);
static ErrorOr<void> kill_all_user_processes();
};
}