mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:17:36 +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:
parent
e05237485c
commit
6cba80510e
5 changed files with 59 additions and 23 deletions
|
@ -62,21 +62,21 @@ void Process::initialize()
|
||||||
|
|
||||||
Vector<pid_t> Process::all_pids()
|
Vector<pid_t> Process::all_pids()
|
||||||
{
|
{
|
||||||
InterruptDisabler disabler;
|
|
||||||
Vector<pid_t> pids;
|
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())
|
for (auto* process = g_processes->head(); process; process = process->next())
|
||||||
pids.unchecked_append(process->pid());
|
pids.append(process->pid());
|
||||||
return pids;
|
return pids;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Process*> Process::all_processes()
|
Vector<Process*> Process::all_processes()
|
||||||
{
|
{
|
||||||
InterruptDisabler disabler;
|
|
||||||
Vector<Process*> processes;
|
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())
|
for (auto* process = g_processes->head(); process; process = process->next())
|
||||||
processes.unchecked_append(process);
|
processes.append(process);
|
||||||
return processes;
|
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);
|
kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
die();
|
|
||||||
m_termination_status = status;
|
m_termination_status = status;
|
||||||
m_termination_signal = 0;
|
m_termination_signal = 0;
|
||||||
|
die();
|
||||||
Scheduler::pick_next_and_switch_now();
|
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,7 +950,6 @@ void Process::crash()
|
||||||
m_termination_signal = SIGSEGV;
|
m_termination_signal = SIGSEGV;
|
||||||
dump_regions();
|
dump_regions();
|
||||||
die();
|
die();
|
||||||
Scheduler::pick_next_and_switch_now();
|
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2122,29 +2119,32 @@ int Process::sys$chmod(const char* pathname, mode_t mode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::die()
|
void Process::finalize()
|
||||||
{
|
{
|
||||||
// This is pretty hairy wrt interrupts. Once we set_state(Dead), we never get scheduled again.
|
ASSERT(current == g_finalizer);
|
||||||
// For this reason, we mark ourselves as Dying, which prevents the scheduler from dispatching signals in this process.
|
|
||||||
set_state(Dying);
|
|
||||||
InterruptFlagSaver saver;
|
|
||||||
|
|
||||||
// STI so we can take locks.
|
|
||||||
sti();
|
|
||||||
destroy_all_windows();
|
destroy_all_windows();
|
||||||
m_fds.clear();
|
m_fds.clear();
|
||||||
m_tty = nullptr;
|
m_tty = nullptr;
|
||||||
|
|
||||||
// CLI for Process::from_pid(). This should go away eventually.
|
{
|
||||||
cli();
|
InterruptDisabler disabler;
|
||||||
if (auto* parent_process = Process::from_pid(m_ppid)) {
|
if (auto* parent_process = Process::from_pid(m_ppid)) {
|
||||||
parent_process->send_signal(SIGCHLD, this);
|
parent_process->send_signal(SIGCHLD, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Good night.
|
|
||||||
set_state(Dead);
|
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 Process::amount_virtual() const
|
||||||
{
|
{
|
||||||
size_t amount = 0;
|
size_t amount = 0;
|
||||||
|
@ -2186,3 +2186,18 @@ size_t Process::amount_shared() const
|
||||||
}
|
}
|
||||||
return amount;
|
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();
|
||||||
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
|
|
||||||
static Vector<pid_t> all_pids();
|
static Vector<pid_t> all_pids();
|
||||||
static Vector<Process*> all_processes();
|
static Vector<Process*> all_processes();
|
||||||
|
static void finalize_dying_processes();
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
|
@ -70,6 +71,7 @@ public:
|
||||||
Dying,
|
Dying,
|
||||||
Dead,
|
Dead,
|
||||||
BeingInspected,
|
BeingInspected,
|
||||||
|
BlockedLurking,
|
||||||
BlockedSleep,
|
BlockedSleep,
|
||||||
BlockedWait,
|
BlockedWait,
|
||||||
BlockedRead,
|
BlockedRead,
|
||||||
|
@ -135,6 +137,7 @@ public:
|
||||||
void set_selector(word s) { m_far_ptr.selector = s; }
|
void set_selector(word s) { m_far_ptr.selector = s; }
|
||||||
void set_state(State s) { m_state = s; }
|
void set_state(State s) { m_state = s; }
|
||||||
void die();
|
void die();
|
||||||
|
void finalize();
|
||||||
|
|
||||||
pid_t sys$setsid();
|
pid_t sys$setsid();
|
||||||
pid_t sys$getsid(pid_t);
|
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::BlockedWrite: return "Write";
|
||||||
case Process::BlockedSignal: return "Signal";
|
case Process::BlockedSignal: return "Signal";
|
||||||
case Process::BlockedSelect: return "Select";
|
case Process::BlockedSelect: return "Select";
|
||||||
|
case Process::BlockedLurking: return "Lurking";
|
||||||
case Process::BeingInspected: return "Inspect";
|
case Process::BeingInspected: return "Inspect";
|
||||||
}
|
}
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
|
|
@ -12,6 +12,7 @@ static const dword time_slice = 5; // *10 = 50ms
|
||||||
|
|
||||||
Process* current;
|
Process* current;
|
||||||
Process* g_last_fpu_process;
|
Process* g_last_fpu_process;
|
||||||
|
Process* g_finalizer;
|
||||||
static Process* s_colonel_process;
|
static Process* s_colonel_process;
|
||||||
|
|
||||||
struct TaskRedirectionData {
|
struct TaskRedirectionData {
|
||||||
|
@ -127,6 +128,13 @@ bool Scheduler::pick_next()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.state() == Process::Dying) {
|
||||||
|
ASSERT(g_finalizer);
|
||||||
|
if (g_finalizer->state() == Process::BlockedLurking)
|
||||||
|
g_finalizer->unblock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -170,7 +178,7 @@ bool Scheduler::pick_next()
|
||||||
g_processes->append(g_processes->remove_head());
|
g_processes->append(g_processes->remove_head());
|
||||||
auto* process = g_processes->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
|
#ifdef SCHEDULER_DEBUG
|
||||||
dbgprintf("switch to %s(%u) @ %w:%x\n", process->name().characters(), process->pid(), process->tss().cs, process->tss().eip);
|
dbgprintf("switch to %s(%u) @ %w:%x\n", process->name().characters(), process->pid(), process->tss().cs, process->tss().eip);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,6 +7,7 @@ struct RegisterDump;
|
||||||
|
|
||||||
extern Process* current;
|
extern Process* current;
|
||||||
extern Process* g_last_fpu_process;
|
extern Process* g_last_fpu_process;
|
||||||
|
extern Process* g_finalizer;
|
||||||
|
|
||||||
class Scheduler {
|
class Scheduler {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -187,6 +187,14 @@ void init()
|
||||||
sleep(10 * TICKS_PER_SECOND);
|
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();
|
Scheduler::pick_next();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue