91 lines
2.7 KiB
C++
91 lines
2.7 KiB
C++
#include "Log.h"
|
|
#include "Pledge.h"
|
|
#include "memory/MemoryManager.h"
|
|
#include "sys/Syscall.h"
|
|
#include "thread/Scheduler.h"
|
|
#include <bits/waitpid.h>
|
|
|
|
Result<u64> 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<Thread*>::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<Thread*>::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;
|
|
}
|