mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 01:20:25 +00:00
Kernel: Get rid of "main thread" concept
The idea of all processes reliably having a main thread was nice in some ways, but cumbersome in others. More importantly, it didn't match up with POSIX thread semantics, so let's move away from it. This thread gets rid of Process::main_thread() and you now we just have a bunch of Thread objects floating around each Process. When the finalizer nukes the last Thread in a Process, it will also tear down the Process. There's a bunch of more things to fix around this, but this is where we get started :^)
This commit is contained in:
parent
150837e7e8
commit
16812f0f98
Notes:
sideshowbarker
2024-07-19 10:46:27 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/16812f0f983
6 changed files with 123 additions and 113 deletions
|
@ -407,7 +407,8 @@ int Process::sys$gethostname(char* buffer, ssize_t size)
|
|||
|
||||
pid_t Process::sys$fork(RegisterDump& regs)
|
||||
{
|
||||
auto* child = new Process(m_name, m_uid, m_gid, m_pid, m_ring, m_cwd, m_executable, m_tty, this);
|
||||
Thread* child_first_thread = nullptr;
|
||||
auto* child = new Process(child_first_thread, m_name, m_uid, m_gid, m_pid, m_ring, m_cwd, m_executable, m_tty, this);
|
||||
|
||||
#ifdef FORK_DEBUG
|
||||
dbgprintf("fork: child=%p\n", child);
|
||||
|
@ -427,7 +428,7 @@ pid_t Process::sys$fork(RegisterDump& regs)
|
|||
for (auto gid : m_gids)
|
||||
child->m_gids.set(gid);
|
||||
|
||||
auto& child_tss = child->main_thread().m_tss;
|
||||
auto& child_tss = child_first_thread->m_tss;
|
||||
child_tss.eax = 0; // fork() returns 0 in the child :^)
|
||||
child_tss.ebx = regs.ebx;
|
||||
child_tss.ecx = regs.ecx;
|
||||
|
@ -457,8 +458,7 @@ pid_t Process::sys$fork(RegisterDump& regs)
|
|||
kprintf("Process %u (%s) forked from %u @ %p\n", child->pid(), child->name().characters(), m_pid, child_tss.eip);
|
||||
#endif
|
||||
|
||||
child->main_thread().set_state(Thread::State::Skip1SchedulerPass);
|
||||
|
||||
child_first_thread->set_state(Thread::State::Skip1SchedulerPass);
|
||||
return child->pid();
|
||||
}
|
||||
|
||||
|
@ -609,9 +609,21 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Should we just make a new Thread here instead?
|
||||
Thread* new_main_thread = nullptr;
|
||||
if (¤t->process() == this) {
|
||||
new_main_thread = current;
|
||||
} else {
|
||||
for_each_thread([&](auto& thread) {
|
||||
new_main_thread = &thread;
|
||||
return IterationDecision::Break;
|
||||
});
|
||||
}
|
||||
ASSERT(new_main_thread);
|
||||
|
||||
// NOTE: We create the new stack before disabling interrupts since it will zero-fault
|
||||
// and we don't want to deal with faults after this point.
|
||||
u32 new_userspace_esp = main_thread().make_userspace_stack_for_main_thread(move(arguments), move(environment));
|
||||
u32 new_userspace_esp = new_main_thread->make_userspace_stack_for_main_thread(move(arguments), move(environment));
|
||||
|
||||
// We cli() manually here because we don't want to get interrupted between do_exec() and Schedule::yield().
|
||||
// The reason is that the task redirection we've set up above will be clobbered by the timer IRQ.
|
||||
|
@ -621,39 +633,40 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
|
|||
|
||||
// NOTE: Be careful to not trigger any page faults below!
|
||||
|
||||
Scheduler::prepare_to_modify_tss(main_thread());
|
||||
Scheduler::prepare_to_modify_tss(*new_main_thread);
|
||||
|
||||
m_name = parts.take_last();
|
||||
main_thread().set_name(m_name);
|
||||
new_main_thread->set_name(m_name);
|
||||
|
||||
// ss0 sp!!!!!!!!!
|
||||
u32 old_esp0 = main_thread().m_tss.esp0;
|
||||
auto& tss = new_main_thread->m_tss;
|
||||
|
||||
u32 old_esp0 = tss.esp0;
|
||||
|
||||
m_master_tls_size = master_tls_size;
|
||||
m_master_tls_alignment = master_tls_alignment;
|
||||
|
||||
main_thread().make_thread_specific_region({});
|
||||
new_main_thread->make_thread_specific_region({});
|
||||
|
||||
memset(&main_thread().m_tss, 0, sizeof(main_thread().m_tss));
|
||||
main_thread().m_tss.eflags = 0x0202;
|
||||
main_thread().m_tss.eip = entry_eip;
|
||||
main_thread().m_tss.cs = 0x1b;
|
||||
main_thread().m_tss.ds = 0x23;
|
||||
main_thread().m_tss.es = 0x23;
|
||||
main_thread().m_tss.fs = 0x23;
|
||||
main_thread().m_tss.gs = thread_specific_selector() | 3;
|
||||
main_thread().m_tss.ss = 0x23;
|
||||
main_thread().m_tss.cr3 = page_directory().cr3();
|
||||
main_thread().m_tss.esp = new_userspace_esp;
|
||||
main_thread().m_tss.ss0 = 0x10;
|
||||
main_thread().m_tss.esp0 = old_esp0;
|
||||
main_thread().m_tss.ss2 = m_pid;
|
||||
memset(&tss, 0, sizeof(TSS32));
|
||||
tss.eflags = 0x0202;
|
||||
tss.eip = entry_eip;
|
||||
tss.cs = 0x1b;
|
||||
tss.ds = 0x23;
|
||||
tss.es = 0x23;
|
||||
tss.fs = 0x23;
|
||||
tss.gs = thread_specific_selector() | 3;
|
||||
tss.ss = 0x23;
|
||||
tss.cr3 = page_directory().cr3();
|
||||
tss.esp = new_userspace_esp;
|
||||
tss.ss0 = 0x10;
|
||||
tss.esp0 = old_esp0;
|
||||
tss.ss2 = m_pid;
|
||||
|
||||
#ifdef TASK_DEBUG
|
||||
kprintf("Process %u (%s) exec'd %s @ %p\n", pid(), name().characters(), path.characters(), main_thread().tss().eip);
|
||||
kprintf("Process %u (%s) exec'd %s @ %p\n", pid(), name().characters(), path.characters(), tss.eip);
|
||||
#endif
|
||||
|
||||
main_thread().set_state(Thread::State::Skip1SchedulerPass);
|
||||
new_main_thread->set_state(Thread::State::Skip1SchedulerPass);
|
||||
big_lock().unlock_if_locked();
|
||||
return 0;
|
||||
}
|
||||
|
@ -786,7 +799,7 @@ int Process::sys$execve(const char* filename, const char** argv, const char** en
|
|||
return rc;
|
||||
}
|
||||
|
||||
Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid, pid_t parent_pid, int& error, Vector<String>&& arguments, Vector<String>&& environment, TTY* tty)
|
||||
Process* Process::create_user_process(Thread*& first_thread, const String& path, uid_t uid, gid_t gid, pid_t parent_pid, int& error, Vector<String>&& arguments, Vector<String>&& environment, TTY* tty)
|
||||
{
|
||||
// FIXME: Don't split() the path twice (sys$spawn also does it...)
|
||||
auto parts = path.split('/');
|
||||
|
@ -803,7 +816,7 @@ Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid,
|
|||
if (!cwd)
|
||||
cwd = VFS::the().root_custody();
|
||||
|
||||
auto* process = new Process(parts.take_last(), uid, gid, parent_pid, Ring3, move(cwd), nullptr, tty);
|
||||
auto* process = new Process(first_thread, parts.take_last(), uid, gid, parent_pid, Ring3, move(cwd), nullptr, tty);
|
||||
|
||||
error = process->exec(path, move(arguments), move(environment));
|
||||
if (error != 0) {
|
||||
|
@ -816,30 +829,30 @@ Process* Process::create_user_process(const String& path, uid_t uid, gid_t gid,
|
|||
g_processes->prepend(process);
|
||||
}
|
||||
#ifdef TASK_DEBUG
|
||||
kprintf("Process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->main_thread().tss().eip);
|
||||
kprintf("Process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), first_thread->tss().eip);
|
||||
#endif
|
||||
error = 0;
|
||||
return process;
|
||||
}
|
||||
|
||||
Process* Process::create_kernel_process(String&& name, void (*e)())
|
||||
Process* Process::create_kernel_process(Thread*& first_thread, String&& name, void (*e)())
|
||||
{
|
||||
auto* process = new Process(move(name), (uid_t)0, (gid_t)0, (pid_t)0, Ring0);
|
||||
process->main_thread().tss().eip = (u32)e;
|
||||
auto* process = new Process(first_thread, move(name), (uid_t)0, (gid_t)0, (pid_t)0, Ring0);
|
||||
first_thread->tss().eip = (u32)e;
|
||||
|
||||
if (process->pid() != 0) {
|
||||
InterruptDisabler disabler;
|
||||
g_processes->prepend(process);
|
||||
#ifdef TASK_DEBUG
|
||||
kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), process->main_thread().tss().eip);
|
||||
kprintf("Kernel process %u (%s) spawned @ %p\n", process->pid(), process->name().characters(), first_thread->tss().eip);
|
||||
#endif
|
||||
}
|
||||
|
||||
process->main_thread().set_state(Thread::State::Runnable);
|
||||
first_thread->set_state(Thread::State::Runnable);
|
||||
return process;
|
||||
}
|
||||
|
||||
Process::Process(const String& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring, RefPtr<Custody> cwd, RefPtr<Custody> executable, TTY* tty, Process* fork_parent)
|
||||
Process::Process(Thread*& first_thread, const String& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring, RefPtr<Custody> cwd, RefPtr<Custody> executable, TTY* tty, Process* fork_parent)
|
||||
: m_name(move(name))
|
||||
, m_pid(next_pid++) // FIXME: RACE: This variable looks racy!
|
||||
, m_uid(uid)
|
||||
|
@ -861,9 +874,9 @@ Process::Process(const String& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel
|
|||
|
||||
// NOTE: fork() doesn't clone all threads; the thread that called fork() becomes the main thread in the new process.
|
||||
if (fork_parent)
|
||||
m_main_thread = current->clone(*this);
|
||||
first_thread = current->clone(*this);
|
||||
else
|
||||
m_main_thread = new Thread(*this);
|
||||
first_thread = new Thread(*this);
|
||||
|
||||
m_gids.set(m_gid);
|
||||
|
||||
|
@ -906,17 +919,8 @@ Process::Process(const String& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel
|
|||
|
||||
Process::~Process()
|
||||
{
|
||||
dbgprintf("~Process{%p} name=%s pid=%d, m_fds=%d\n", this, m_name.characters(), pid(), m_fds.size());
|
||||
delete m_main_thread;
|
||||
m_main_thread = nullptr;
|
||||
|
||||
Vector<Thread*, 16> my_threads;
|
||||
for_each_thread([&my_threads](auto& thread) {
|
||||
my_threads.append(&thread);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
for (auto* thread : my_threads)
|
||||
delete thread;
|
||||
dbgprintf("~Process{%p} name=%s pid=%d, m_fds=%d, m_thread_count=%u\n", this, m_name.characters(), pid(), m_fds.size(), m_thread_count);
|
||||
ASSERT(thread_count() == 0);
|
||||
}
|
||||
|
||||
void Process::dump_regions()
|
||||
|
@ -1782,7 +1786,7 @@ int Process::reap(Process& process)
|
|||
}
|
||||
}
|
||||
|
||||
dbgprintf("reap: %s(%u) {%s}\n", process.name().characters(), process.pid(), process.main_thread().state_string());
|
||||
dbgprintf("reap: %s(%u)\n", process.name().characters(), process.pid());
|
||||
ASSERT(process.is_dead());
|
||||
g_processes->remove(&process);
|
||||
}
|
||||
|
@ -1854,7 +1858,7 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
|
|||
if (waitee_process->is_dead()) {
|
||||
exit_status = reap(*waitee_process);
|
||||
} else {
|
||||
ASSERT(waitee_process->main_thread().state() == Thread::State::Stopped);
|
||||
ASSERT(waitee_process->any_thread().state() == Thread::State::Stopped);
|
||||
exit_status = 0x7f;
|
||||
}
|
||||
return waitee_pid;
|
||||
|
@ -2438,7 +2442,7 @@ void Process::finalize()
|
|||
InterruptDisabler disabler;
|
||||
if (auto* parent_process = Process::from_pid(m_ppid)) {
|
||||
// FIXME(Thread): What should we do here? Should we look at all threads' signal actions?
|
||||
if (parent_process->main_thread().m_signal_action_data[SIGCHLD].flags & SA_NOCLDWAIT) {
|
||||
if (parent_process->thread_count() && parent_process->any_thread().m_signal_action_data[SIGCHLD].flags & SA_NOCLDWAIT) {
|
||||
// NOTE: If the parent doesn't care about this process, let it go.
|
||||
m_ppid = 0;
|
||||
} else {
|
||||
|
@ -2465,6 +2469,7 @@ void Process::die()
|
|||
// Tell the threads to unwind and die.
|
||||
InterruptDisabler disabler;
|
||||
for_each_thread([](Thread& thread) {
|
||||
kprintf("Mark PID %u TID %u for death\n", thread.pid(), thread.tid());
|
||||
thread.set_should_die();
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
@ -2750,7 +2755,7 @@ int Process::sys$sched_setparam(pid_t pid, const struct sched_param* param)
|
|||
if (param->sched_priority < (int)ThreadPriority::First || param->sched_priority > (int)ThreadPriority::Last)
|
||||
return -EINVAL;
|
||||
|
||||
peer->main_thread().set_priority((ThreadPriority)param->sched_priority);
|
||||
peer->any_thread().set_priority((ThreadPriority)param->sched_priority);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2770,7 +2775,7 @@ int Process::sys$sched_getparam(pid_t pid, struct sched_param* param)
|
|||
if (!is_superuser() && m_euid != peer->m_uid && m_uid != peer->m_uid)
|
||||
return -EPERM;
|
||||
|
||||
param->sched_priority = (int)peer->main_thread().priority();
|
||||
param->sched_priority = (int)peer->any_thread().priority();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2976,17 +2981,7 @@ void Process::terminate_due_to_signal(u8 signal)
|
|||
void Process::send_signal(u8 signal, Process* sender)
|
||||
{
|
||||
// FIXME(Thread): Find the appropriate thread to deliver the signal to.
|
||||
main_thread().send_signal(signal, sender);
|
||||
}
|
||||
|
||||
int Process::thread_count() const
|
||||
{
|
||||
int count = 0;
|
||||
for_each_thread([&count](auto&) {
|
||||
++count;
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return count;
|
||||
any_thread().send_signal(signal, sender);
|
||||
}
|
||||
|
||||
int Process::sys$create_thread(void* (*entry)(void*), void* argument, const Syscall::SC_create_thread_params* params)
|
||||
|
@ -3045,13 +3040,8 @@ int Process::sys$create_thread(void* (*entry)(void*), void* argument, const Sysc
|
|||
|
||||
void Process::sys$exit_thread(void* exit_value)
|
||||
{
|
||||
current->m_exit_value = exit_value;
|
||||
cli();
|
||||
if (¤t->process().main_thread() == current) {
|
||||
// FIXME: For POSIXy reasons, we should only sys$exit once *all* threads have exited.
|
||||
sys$exit(0);
|
||||
return;
|
||||
}
|
||||
current->m_exit_value = exit_value;
|
||||
current->set_should_die();
|
||||
big_lock().unlock_if_locked();
|
||||
current->die_if_needed();
|
||||
|
@ -3147,13 +3137,7 @@ int Process::sys$set_thread_name(int tid, const char* buffer, int buffer_size)
|
|||
if (!thread)
|
||||
return -ESRCH;
|
||||
|
||||
// Forbid renaming the main thread of a process
|
||||
// That guy should always be named after the process
|
||||
if (thread == ¤t->process().main_thread())
|
||||
return -EINVAL;
|
||||
|
||||
thread->set_name({ buffer, (size_t)buffer_size });
|
||||
|
||||
return 0;
|
||||
}
|
||||
int Process::sys$get_thread_name(int tid, char* buffer, int buffer_size)
|
||||
|
@ -3767,3 +3751,14 @@ void* Process::sys$get_kernel_info_page()
|
|||
{
|
||||
return s_info_page_address_for_userspace.as_ptr();
|
||||
}
|
||||
|
||||
Thread& Process::any_thread()
|
||||
{
|
||||
Thread* found_thread = nullptr;
|
||||
for_each_thread([&](auto& thread) {
|
||||
found_thread = &thread;
|
||||
return IterationDecision::Break;
|
||||
});
|
||||
ASSERT(found_thread);
|
||||
return *found_thread;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ class Process : public InlineLinkedListNode<Process>
|
|||
friend class Thread;
|
||||
|
||||
public:
|
||||
static Process* create_kernel_process(String&& name, void (*entry)());
|
||||
static Process* create_user_process(const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr);
|
||||
static Process* create_kernel_process(Thread*& first_thread, String&& name, void (*entry)());
|
||||
static Process* create_user_process(Thread*& first_thread, const String& path, uid_t, gid_t, pid_t ppid, int& error, Vector<String>&& arguments = Vector<String>(), Vector<String>&& environment = Vector<String>(), TTY* = nullptr);
|
||||
~Process();
|
||||
|
||||
static Vector<pid_t> all_pids();
|
||||
|
@ -56,9 +56,6 @@ public:
|
|||
|
||||
bool is_dead() const { return m_dead; }
|
||||
|
||||
Thread& main_thread() { return *m_main_thread; }
|
||||
const Thread& main_thread() const { return *m_main_thread; }
|
||||
|
||||
bool is_ring0() const { return m_ring == Ring0; }
|
||||
bool is_ring3() const { return m_ring == Ring3; }
|
||||
|
||||
|
@ -297,7 +294,9 @@ public:
|
|||
void terminate_due_to_signal(u8 signal);
|
||||
void send_signal(u8, Process* sender);
|
||||
|
||||
int thread_count() const;
|
||||
u16 thread_count() const { return m_thread_count; }
|
||||
|
||||
Thread& any_thread();
|
||||
|
||||
Lock& big_lock() { return m_big_lock; }
|
||||
|
||||
|
@ -310,7 +309,7 @@ private:
|
|||
friend class Scheduler;
|
||||
friend class Region;
|
||||
|
||||
Process(const String& name, uid_t, gid_t, pid_t ppid, RingLevel, RefPtr<Custody> cwd = nullptr, RefPtr<Custody> executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr);
|
||||
Process(Thread*& first_thread, const String& name, uid_t, gid_t, pid_t ppid, RingLevel, RefPtr<Custody> cwd = nullptr, RefPtr<Custody> executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr);
|
||||
|
||||
Range allocate_range(VirtualAddress, size_t);
|
||||
|
||||
|
@ -325,8 +324,6 @@ private:
|
|||
KResult do_kill(Process&, int signal);
|
||||
KResult do_killpg(pid_t pgrp, int signal);
|
||||
|
||||
Thread* m_main_thread { nullptr };
|
||||
|
||||
RefPtr<PageDirectory> m_page_directory;
|
||||
|
||||
Process* m_prev { nullptr };
|
||||
|
@ -356,6 +353,7 @@ private:
|
|||
RingLevel m_ring { Ring0 };
|
||||
u8 m_termination_status { 0 };
|
||||
u8 m_termination_signal { 0 };
|
||||
u16 m_thread_count { 0 };
|
||||
|
||||
bool m_being_inspected { false };
|
||||
bool m_dead { false };
|
||||
|
@ -465,8 +463,8 @@ inline void Process::for_each_thread(Callback callback) const
|
|||
pid_t my_pid = pid();
|
||||
|
||||
if (my_pid == 0) {
|
||||
// NOTE: Special case the colonel thread, since its main thread is not in the global thread table.
|
||||
callback(const_cast<Thread&>(main_thread()));
|
||||
// NOTE: Special case the colonel process, since its main thread is not in the global thread table.
|
||||
callback(*g_colonel);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ static u32 time_slice_for(ThreadPriority priority)
|
|||
Thread* current;
|
||||
Thread* g_last_fpu_thread;
|
||||
Thread* g_finalizer;
|
||||
Thread* g_colonel;
|
||||
WaitQueue* g_finalizer_wait_queue;
|
||||
static Process* s_colonel_process;
|
||||
u64 g_uptime;
|
||||
|
@ -222,7 +223,7 @@ bool Thread::WaitBlocker::should_unblock(Thread& thread, time_t, long)
|
|||
return IterationDecision::Continue;
|
||||
|
||||
bool child_exited = child.is_dead();
|
||||
bool child_stopped = child.main_thread().state() == Thread::State::Stopped;
|
||||
bool child_stopped = child.thread_count() && child.any_thread().state() == Thread::State::Stopped;
|
||||
|
||||
bool wait_finished = ((m_wait_options & WEXITED) && child_exited)
|
||||
|| ((m_wait_options & WSTOPPED) && child_stopped);
|
||||
|
@ -288,7 +289,7 @@ bool Scheduler::pick_next()
|
|||
if (!current) {
|
||||
// XXX: The first ever context_switch() goes to the idle process.
|
||||
// This to setup a reliable place we can return to.
|
||||
return context_switch(s_colonel_process->main_thread());
|
||||
return context_switch(*g_colonel);
|
||||
}
|
||||
|
||||
struct timeval now;
|
||||
|
@ -305,7 +306,7 @@ bool Scheduler::pick_next()
|
|||
|
||||
Process::for_each([&](Process& process) {
|
||||
if (process.is_dead()) {
|
||||
if (current != &process.main_thread() && (!process.ppid() || !Process::from_pid(process.ppid()))) {
|
||||
if (current->pid() != process.pid() && (!process.ppid() || !Process::from_pid(process.ppid()))) {
|
||||
auto name = process.name();
|
||||
auto pid = process.pid();
|
||||
auto exit_status = Process::reap(process);
|
||||
|
@ -369,7 +370,7 @@ bool Scheduler::pick_next()
|
|||
|
||||
auto& runnable_list = g_scheduler_data->m_runnable_threads;
|
||||
if (runnable_list.is_empty())
|
||||
return context_switch(s_colonel_process->main_thread());
|
||||
return context_switch(*g_colonel);
|
||||
|
||||
auto* previous_head = runnable_list.first();
|
||||
for (;;) {
|
||||
|
@ -386,7 +387,7 @@ bool Scheduler::pick_next()
|
|||
|
||||
if (thread == previous_head) {
|
||||
// Back at process_head, nothing wants to run. Send in the colonel!
|
||||
return context_switch(s_colonel_process->main_thread());
|
||||
return context_switch(*g_colonel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -535,9 +536,9 @@ void Scheduler::initialize()
|
|||
g_finalizer_wait_queue = new WaitQueue;
|
||||
s_redirection.selector = gdt_alloc_entry();
|
||||
initialize_redirection();
|
||||
s_colonel_process = Process::create_kernel_process("colonel", nullptr);
|
||||
s_colonel_process = Process::create_kernel_process(g_colonel, "colonel", nullptr);
|
||||
// Make sure the colonel uses a smallish time slice.
|
||||
s_colonel_process->main_thread().set_priority(ThreadPriority::Idle);
|
||||
g_colonel->set_priority(ThreadPriority::Idle);
|
||||
load_task_register(s_redirection.selector);
|
||||
}
|
||||
|
||||
|
@ -614,7 +615,7 @@ static bool s_should_stop_idling = false;
|
|||
|
||||
void Scheduler::stop_idling()
|
||||
{
|
||||
if (current != &s_colonel_process->main_thread())
|
||||
if (current != g_colonel)
|
||||
return;
|
||||
|
||||
s_should_stop_idling = true;
|
||||
|
|
|
@ -14,6 +14,7 @@ struct SchedulerData;
|
|||
extern Thread* current;
|
||||
extern Thread* g_last_fpu_thread;
|
||||
extern Thread* g_finalizer;
|
||||
extern Thread* g_colonel;
|
||||
extern WaitQueue* g_finalizer_wait_queue;
|
||||
extern u64 g_uptime;
|
||||
extern SchedulerData* g_scheduler_data;
|
||||
|
|
|
@ -46,6 +46,7 @@ Thread::Thread(Process& process)
|
|||
, m_tid(process.m_next_tid++)
|
||||
, m_name(process.name())
|
||||
{
|
||||
process.m_thread_count++;
|
||||
dbgprintf("Thread{%p}: New thread TID=%u in %s(%u)\n", this, m_tid, process.name().characters(), process.pid());
|
||||
set_default_signal_dispositions();
|
||||
m_fpu_state = (FPUState*)kmalloc_aligned(sizeof(FPUState), 16);
|
||||
|
@ -121,6 +122,9 @@ Thread::~Thread()
|
|||
|
||||
if (m_userspace_stack_region)
|
||||
m_process.deallocate_region(*m_userspace_stack_region);
|
||||
|
||||
ASSERT(m_process.m_thread_count);
|
||||
m_process.m_thread_count--;
|
||||
}
|
||||
|
||||
void Thread::unblock()
|
||||
|
@ -135,8 +139,10 @@ void Thread::unblock()
|
|||
|
||||
void Thread::set_should_die()
|
||||
{
|
||||
if (m_should_die)
|
||||
if (m_should_die) {
|
||||
dbgprintf("Should already die (%u)\n", m_tid);
|
||||
return;
|
||||
}
|
||||
InterruptDisabler disabler;
|
||||
|
||||
// Remember that we should die instead of returning to
|
||||
|
@ -258,13 +264,6 @@ void Thread::finalize()
|
|||
|
||||
if (m_dump_backtrace_on_finalization)
|
||||
dbg() << backtrace_impl();
|
||||
|
||||
if (this == &m_process.main_thread()) {
|
||||
m_process.finalize();
|
||||
return;
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void Thread::finalize_dying_threads()
|
||||
|
@ -278,8 +277,15 @@ void Thread::finalize_dying_threads()
|
|||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
for (auto* thread : dying_threads)
|
||||
dbgprintf("Finalizing %u dying threads\n", dying_threads.size());
|
||||
for (auto* thread : dying_threads) {
|
||||
auto& process = thread->process();
|
||||
thread->finalize();
|
||||
delete thread;
|
||||
if (process.m_thread_count == 0)
|
||||
process.finalize();
|
||||
}
|
||||
dbgprintf("Done\n");
|
||||
}
|
||||
|
||||
bool Thread::tick()
|
||||
|
|
|
@ -169,22 +169,27 @@ VFS* vfs;
|
|||
// accept keyboard input.
|
||||
if (text_debug) {
|
||||
tty0->set_graphical(false);
|
||||
auto* shell_process = Process::create_user_process("/bin/Shell", (uid_t)0, (gid_t)0, (pid_t)0, error, {}, {}, tty0);
|
||||
Thread* thread = nullptr;
|
||||
Process::create_user_process(thread, "/bin/Shell", (uid_t)0, (gid_t)0, (pid_t)0, error, {}, {}, tty0);
|
||||
if (error != 0) {
|
||||
kprintf("init_stage2: error spawning Shell: %d\n", error);
|
||||
hang();
|
||||
}
|
||||
shell_process->main_thread().set_priority(ThreadPriority::High);
|
||||
thread->set_priority(ThreadPriority::High);
|
||||
} else {
|
||||
tty0->set_graphical(true);
|
||||
auto* system_server_process = Process::create_user_process("/bin/SystemServer", (uid_t)0, (gid_t)0, (pid_t)0, error, {}, {}, tty0);
|
||||
Thread* thread = nullptr;
|
||||
Process::create_user_process(thread, "/bin/SystemServer", (uid_t)0, (gid_t)0, (pid_t)0, error, {}, {}, tty0);
|
||||
if (error != 0) {
|
||||
kprintf("init_stage2: error spawning SystemServer: %d\n", error);
|
||||
hang();
|
||||
}
|
||||
system_server_process->main_thread().set_priority(ThreadPriority::High);
|
||||
thread->set_priority(ThreadPriority::High);
|
||||
}
|
||||
{
|
||||
Thread* thread = nullptr;
|
||||
Process::create_kernel_process(thread, "NetworkTask", NetworkTask_main);
|
||||
}
|
||||
Process::create_kernel_process("NetworkTask", NetworkTask_main);
|
||||
|
||||
current->process().sys$exit(0);
|
||||
ASSERT_NOT_REACHED();
|
||||
|
@ -308,15 +313,19 @@ extern "C" [[noreturn]] void init(u32 physical_address_for_kernel_page_tables)
|
|||
|
||||
Process::initialize();
|
||||
Thread::initialize();
|
||||
Process::create_kernel_process("init_stage2", init_stage2);
|
||||
Process::create_kernel_process("syncd", [] {
|
||||
|
||||
Thread* init_stage2_thread = nullptr;
|
||||
Process::create_kernel_process(init_stage2_thread, "init_stage2", init_stage2);
|
||||
|
||||
Thread* syncd_thread = nullptr;
|
||||
Process::create_kernel_process(syncd_thread, "syncd", [] {
|
||||
for (;;) {
|
||||
VFS::the().sync();
|
||||
current->sleep(1 * TICKS_PER_SECOND);
|
||||
}
|
||||
});
|
||||
Process::create_kernel_process("Finalizer", [] {
|
||||
g_finalizer = current;
|
||||
|
||||
Process::create_kernel_process(g_finalizer, "Finalizer", [] {
|
||||
current->set_priority(ThreadPriority::Low);
|
||||
for (;;) {
|
||||
current->wait_on(*g_finalizer_wait_queue);
|
||||
|
|
Loading…
Reference in a new issue