From 7efcc0609047298b28e6f57949fa5eac76763822 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 24 Mar 2023 17:37:04 +0100 Subject: [PATCH] kernel+init+sh: Implement parent processes and waitpid(-1, ...) --- apps/init.c | 4 ++-- apps/sh.c | 1 + kernel/src/sys/exec.cpp | 1 + kernel/src/sys/exit.cpp | 2 ++ kernel/src/sys/waitpid.cpp | 35 ++++++++++++++++++++++++++++----- kernel/src/thread/Scheduler.cpp | 24 ++++++++++++++++++++++ kernel/src/thread/Scheduler.h | 11 +++++++++++ kernel/src/thread/Thread.h | 1 + 8 files changed, 72 insertions(+), 7 deletions(-) diff --git a/apps/init.c b/apps/init.c index 982af948..9964d791 100644 --- a/apps/init.c +++ b/apps/init.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #define xmknod(path, mode, maj, min) \ @@ -46,6 +47,5 @@ int main() return 1; } - while (1) - ; + while (1) { waitpid(-1, NULL, 0); } } diff --git a/apps/sh.c b/apps/sh.c index a61a4188..115ea7c9 100644 --- a/apps/sh.c +++ b/apps/sh.c @@ -107,3 +107,4 @@ int main() return 1; } } +} diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index a4342c82..656eb8d0 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -110,6 +110,7 @@ Result sys_fork(Registers* regs, SyscallArgs) thread->state = ThreadState::Runnable; thread->is_kernel = false; + thread->parent_id = current->id; thread->fp_data.save(); for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; } diff --git a/kernel/src/sys/exit.cpp b/kernel/src/sys/exit.cpp index 56802709..3f05ee50 100644 --- a/kernel/src/sys/exit.cpp +++ b/kernel/src/sys/exit.cpp @@ -7,6 +7,8 @@ Result sys_exit(Registers*, SyscallArgs args) Thread* current = Scheduler::current(); + Scheduler::for_each_child((pid_t)current->id, [](Thread* child) { child->parent_id = 1; }); + current->status = status; current->state = ThreadState::Exited; diff --git a/kernel/src/sys/waitpid.cpp b/kernel/src/sys/waitpid.cpp index c15648bd..7d366c24 100644 --- a/kernel/src/sys/waitpid.cpp +++ b/kernel/src/sys/waitpid.cpp @@ -9,13 +9,38 @@ Result sys_waitpid(Registers*, SyscallArgs args) int* status_ptr = (int*)args[1]; int options = (int)args[2]; - Thread* thread = TRY(Result::from_option(Scheduler::find_by_pid(pid), ESRCH)); + Thread* current = Scheduler::current(); - while (thread->state != ThreadState::Exited) + Thread* thread; + + if (pid > 0) { - if (options & WNOHANG) return err(EAGAIN); - kernel_sleep(10); + thread = TRY(Result::from_option(Scheduler::find_by_pid(pid), ESRCH)); + + if (thread->parent_id != current->id) return err(ECHILD); + + while (thread->state != ThreadState::Exited) + { + if (options & WNOHANG) return err(EAGAIN); + kernel_sleep(10); + } } + else if (pid == -1) + { + if (!Scheduler::has_children((pid_t)current->id)) return err(ECHILD); + + Option child; + + while (child = Scheduler::find_exited_child((pid_t)current->id), !child.has_value()) + { + if (options & WNOHANG) return err(EAGAIN); + kernel_sleep(10); + } + + thread = child.value(); + } + else + return err(ENOTSUP); int status = (int)thread->status; @@ -24,5 +49,5 @@ Result sys_waitpid(Registers*, SyscallArgs args) if (status_ptr) if (!MemoryManager::copy_to_user_typed(status_ptr, &status)) return err(EFAULT); - return (u64)pid; + return thread->id; } diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 477850d6..21ba8b5b 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -23,6 +23,7 @@ namespace Scheduler g_idle.set_ip((u64)CPU::idle_loop); g_idle.state = ThreadState::Idle; g_idle.is_kernel = true; + g_idle.parent_id = 0; g_idle.ticks_left = 1; @@ -64,6 +65,8 @@ namespace Scheduler thread->stack = thread_stack; + thread->parent_id = 0; + thread->is_kernel = true; g_threads.append(thread); @@ -106,6 +109,7 @@ namespace Scheduler Thread* const thread = TRY(new_thread()); thread->is_kernel = false; + thread->parent_id = 0; auto guard = make_scope_guard([&] { delete thread; }); @@ -264,6 +268,26 @@ namespace Scheduler return result; } + + bool has_children(pid_t pid) + { + bool result { false }; + + for_each_child(pid, [&](Thread*) { result = true; }); + + return result; + } + + Option find_exited_child(pid_t pid) + { + Option result; + + for_each_child(pid, [&](Thread* child) { + if (!result.has_value() && child->state == ThreadState::Exited) result = child; + }); + + return result; + } } void kernel_sleep(u64 ms) diff --git a/kernel/src/thread/Scheduler.h b/kernel/src/thread/Scheduler.h index 4b331f04..67bf8707 100644 --- a/kernel/src/thread/Scheduler.h +++ b/kernel/src/thread/Scheduler.h @@ -28,6 +28,17 @@ namespace Scheduler LinkedList check_for_dying_threads(); Option find_by_pid(pid_t pid); + + template void for_each_child(pid_t pid, Callback callback) + { + g_threads.for_each([&](Thread* thread) { + if (thread->parent_id == (u64)pid) callback(thread); + }); + } + + bool has_children(pid_t pid); + + Option find_exited_child(pid_t pid); } extern "C" void kernel_yield(); diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index 3d637f77..1e4a8d21 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -42,6 +42,7 @@ struct Thread : public LinkedListNode Registers regs; u64 id; + u64 parent_id; u64 ticks = 0; u64 ticks_in_user = 0;