diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 378ecb57..b96fb020 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -26,9 +26,11 @@ void reap_thread() { CPU::disable_interrupts(); auto dying_threads = Scheduler::check_for_dying_threads(); + auto dead_processes = Scheduler::check_for_dead_processes(); CPU::enable_interrupts(); dying_threads.consume([](Thread* thread) { Scheduler::reap_thread(thread); }); + dead_processes.consume([](Process* p) { Scheduler::reap_process(p); }); kernel_wait_for_event(); } diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index c952da8c..70101810 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -113,6 +113,7 @@ Result sys_execve(Registers* regs, SyscallArgs args) if (t != thread) t->quit(); return true; }); + Scheduler::signal_reap_thread(); current->thread_count = 1; @@ -145,6 +146,7 @@ Result sys_execve(Registers* regs, SyscallArgs args) } current->cmdline = cmdline.chars(); + thread->cmdline = cmdline.chars(); image->apply(thread); diff --git a/kernel/src/sys/waitpid.cpp b/kernel/src/sys/waitpid.cpp index 4241a131..3ad215c2 100644 --- a/kernel/src/sys/waitpid.cpp +++ b/kernel/src/sys/waitpid.cpp @@ -25,8 +25,8 @@ Result sys_waitpid(Registers* regs, SyscallArgs args) if (options & WNOHANG) return err(EAGAIN); wait_for_child: - if (target->alive()) kernel_wait(pid); - if (current->interrupted) + if (!target->dead()) kernel_wait(pid); + if (current->interrupted && current->pending_signal() != SIGCHLD) { kdbgln("signal: waitpid interrupted by signal"); if (current->will_ignore_pending_signal()) @@ -37,7 +37,7 @@ Result sys_waitpid(Registers* regs, SyscallArgs args) return err(EINTR); } - check(!target->alive()); + check(target->dead()); } else if (pid == -1) { @@ -50,7 +50,7 @@ Result sys_waitpid(Registers* regs, SyscallArgs args) wait_for_any_child: kernel_wait(pid); - if (current->interrupted) + if (current->interrupted && current->pending_signal() != SIGCHLD) { kdbgln("signal: waitpid interrupted by signal"); if (current->will_ignore_pending_signal()) @@ -64,7 +64,7 @@ Result sys_waitpid(Registers* regs, SyscallArgs args) check(current->child_being_waited_for != -1); target = TRY(Result::from_option(Scheduler::find_by_pid(current->child_being_waited_for), ESRCH)); - check(!target->alive()); + check(!target->dead()); } else target = child.value(); @@ -80,7 +80,8 @@ Result sys_waitpid(Registers* regs, SyscallArgs args) current->process->user_ticks_children += target->user_ticks_self + target->user_ticks_children; current->process->kernel_ticks_children += target->kernel_ticks_self + target->kernel_ticks_children; - Scheduler::reap_process(target); + target->thread_count = PROCESS_SHOULD_REAP; + Scheduler::signal_reap_thread(); if (status_ptr) if (!MemoryManager::copy_to_user_typed(status_ptr, &status)) return err(EFAULT); diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 263cbe11..a8247e7d 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -117,6 +117,7 @@ namespace Scheduler process->thread_count = 1; process->virtual_clock.set_resolution(1'000'000); process->profiling_clock.set_resolution(1'000'000); + process->cmdline = name; process->is_kernel = true; g_threads.append(thread); @@ -172,6 +173,7 @@ namespace Scheduler process->id = 1; process->pgid = 1; process->thread_count = 1; + process->cmdline = name; Vector args; auto name_string = TRY(String::from_cstring(name)); @@ -228,6 +230,8 @@ namespace Scheduler void reap_process(Process* process) { + CPU::disable_interrupts(); + // FIXME: Shouldn't all this be done when the timers' destructors are called? process->real_timer.disarm(); process->virtual_timer.disarm(); @@ -238,6 +242,8 @@ namespace Scheduler } delete process; + + CPU::enable_interrupts(); } void reap_thread(Thread* thread) @@ -378,6 +384,21 @@ namespace Scheduler return result; } + LinkedList check_for_dead_processes() + { + LinkedList result; + + g_processes.delayed_for_each([&](Process* p) { + if (p->thread_count == PROCESS_SHOULD_REAP) + { + g_processes.remove(p); + result.append(p); + } + }); + + return result; + } + Option find_by_pid(pid_t pid) { for (auto* const process : g_processes) @@ -405,7 +426,7 @@ namespace Scheduler Option result; for_each_child(process, [&](Process* child) { - if (!result.has_value() && !child->alive()) + if (!result.has_value() && child->dead()) { result = child; return false; @@ -469,6 +490,7 @@ void kernel_wait_for_event() [[noreturn]] void kernel_exit() { g_current->state = ThreadState::Dying; + g_current->process->thread_count = PROCESS_SHOULD_REAP; Scheduler::signal_reap_thread(); kernel_yield(); unreachable(); diff --git a/kernel/src/thread/Scheduler.h b/kernel/src/thread/Scheduler.h index 78b112a5..a7244947 100644 --- a/kernel/src/thread/Scheduler.h +++ b/kernel/src/thread/Scheduler.h @@ -35,6 +35,7 @@ namespace Scheduler void invoke(Registers* regs); LinkedList check_for_dying_threads(); + LinkedList check_for_dead_processes(); Option find_by_pid(pid_t pid); diff --git a/kernel/src/thread/Thread.cpp b/kernel/src/thread/Thread.cpp index 2d8211ea..967c8dc5 100644 --- a/kernel/src/thread/Thread.cpp +++ b/kernel/src/thread/Thread.cpp @@ -137,6 +137,7 @@ Result> Process::resolve_atfile(int dirfd, const String& p thread->quit(); return true; }); + Scheduler::signal_reap_thread(); thread_count = 0; @@ -276,6 +277,15 @@ void Thread::process_pending_signals(Registers* current_regs) } } +int Thread::pending_signal() +{ + for (int i = 0; i < NSIG; i++) + { + if (pending_signals.get(i)) { return i + 1; } + } + return 0; +} + bool Thread::will_ignore_pending_signal() { for (int i = 0; i < NSIG; i++) diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index 34fc0564..5bec29ea 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -20,6 +20,7 @@ #endif constexpr int MAX_POSIX_TIMERS = 64; +constexpr i64 PROCESS_SHOULD_REAP = -1; class Timer; @@ -49,7 +50,7 @@ struct Credentials struct Process : public LinkedListNode { - Atomic thread_count; + Atomic thread_count; pid_t id; Atomic pgid { 0 }; @@ -122,6 +123,11 @@ struct Process : public LinkedListNode return thread_count > 0; } + bool dead() + { + return thread_count == 0; + } + static Process* current(); [[noreturn]] void exit(int status); @@ -202,6 +208,7 @@ struct Thread : public LinkedListNode void process_pending_signals(Registers* current_regs); + int pending_signal(); bool will_ignore_pending_signal(); bool deliver_signal(int signo, Registers* current_regs);