#include "Log.h" #include "Pledge.h" #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include Result sys_waitpid(Registers* regs, SyscallArgs args) { pid_t pid = (pid_t)args[0]; int* status_ptr = (int*)args[1]; int options = (int)args[2]; Thread* current = Scheduler::current(); TRY(check_pledge(current, Promise::p_stdio)); Thread* thread; if (pid > 0) { thread = TRY(Result::from_option(Scheduler::find_by_pid(pid), ESRCH)); if (thread->parent && thread->parent != current) return err(ECHILD); if (options & WNOHANG) return err(EAGAIN); wait_for_child: if (thread->state != ThreadState::Exited) kernel_wait(pid); if (current->interrupted) { kdbgln("signal: waitpid interrupted by signal"); if (current->will_ignore_pending_signal()) { current->process_pending_signals(regs); goto wait_for_child; } return err(EINTR); } check(thread->state == ThreadState::Exited); } else if (pid == -1) { if (!Scheduler::has_children(current)) return err(ECHILD); auto child = Scheduler::find_exited_child(current); if (!child.has_value()) { if (options & WNOHANG) return err(EAGAIN); wait_for_any_child: kernel_wait(pid); if (current->interrupted) { kdbgln("signal: waitpid interrupted by signal"); if (current->will_ignore_pending_signal()) { current->process_pending_signals(regs); goto wait_for_any_child; } return err(EINTR); } check(current->child_being_waited_for.value_or(-1) != -1); thread = TRY(Result::from_option(Scheduler::find_by_pid(*current->child_being_waited_for), ESRCH)); check(thread->state == ThreadState::Exited); } else thread = child.value(); } else // FIXME: Now that we have process groups, implement the cases where pid = 0 and pid < -1. return err(ENOTSUP); current->child_being_waited_for = {}; int status = (int)thread->status; u64 id = thread->id; current->user_ticks_children += thread->user_ticks_self + thread->user_ticks_children; current->kernel_ticks_children += thread->kernel_ticks_self + thread->kernel_ticks_children; thread->state = ThreadState::Dying; Scheduler::signal_reap_thread(); if (status_ptr) if (!MemoryManager::copy_to_user_typed(status_ptr, &status)) return err(EFAULT); return id; }