mirror of
https://github.com/RGBCube/serenity
synced 2025-05-28 03:35:09 +00:00
Kernel+LibC: Add sys$waitid(), and make sys$waitpid() wrap it
sys$waitid() takes an explicit description of whether it's waiting for a single process with the given PID, all of the children, a group, etc., and returns its info as a siginfo_t. It also doesn't automatically imply WEXITED, which clears up the confusion in the kernel.
This commit is contained in:
parent
a6cb7f759e
commit
b3a24d732d
5 changed files with 140 additions and 55 deletions
|
@ -2266,12 +2266,23 @@ mode_t Process::sys$umask(mode_t mask)
|
||||||
return old_mask;
|
return old_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Process::reap(Process& process)
|
siginfo_t Process::reap(Process& process)
|
||||||
{
|
{
|
||||||
int exit_status;
|
siginfo_t siginfo;
|
||||||
|
siginfo.si_signo = SIGCHLD;
|
||||||
|
siginfo.si_pid = process.pid();
|
||||||
|
siginfo.si_uid = process.uid();
|
||||||
|
|
||||||
|
if (process.m_termination_signal) {
|
||||||
|
siginfo.si_status = process.m_termination_signal;
|
||||||
|
siginfo.si_code = CLD_KILLED;
|
||||||
|
} else {
|
||||||
|
siginfo.si_status = process.m_termination_status;
|
||||||
|
siginfo.si_code = CLD_EXITED;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
exit_status = (process.m_termination_status << 8) | process.m_termination_signal;
|
|
||||||
|
|
||||||
if (process.ppid()) {
|
if (process.ppid()) {
|
||||||
auto* parent = Process::from_pid(process.ppid());
|
auto* parent = Process::from_pid(process.ppid());
|
||||||
|
@ -2288,85 +2299,102 @@ int Process::reap(Process& process)
|
||||||
g_processes->remove(&process);
|
g_processes->remove(&process);
|
||||||
}
|
}
|
||||||
delete &process;
|
delete &process;
|
||||||
return exit_status;
|
return siginfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
|
KResultOr<siginfo_t> Process::do_waitid(idtype_t idtype, int id, int options)
|
||||||
{
|
{
|
||||||
REQUIRE_PROMISE(stdio);
|
if (idtype == P_PID) {
|
||||||
|
|
||||||
#ifdef PROCESS_DEBUG
|
|
||||||
dbg() << "sys$waitpid(" << waitee << ", " << wstatus << ", " << options << ")";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!options) {
|
|
||||||
// FIXME: This can't be right.. can it? Figure out how this should actually work.
|
|
||||||
options = WEXITED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wstatus && !validate_write_typed(wstatus))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
int exit_status = 0;
|
|
||||||
|
|
||||||
{
|
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
if (waitee != -1 && !Process::from_pid(waitee))
|
if (idtype == P_PID && !Process::from_pid(id))
|
||||||
return -ECHILD;
|
return KResult(-ECHILD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options & WNOHANG) {
|
if (options & WNOHANG) {
|
||||||
// FIXME: Figure out what WNOHANG should do with stopped children.
|
// FIXME: Figure out what WNOHANG should do with stopped children.
|
||||||
if (waitee == -1) {
|
if (idtype == P_ALL) {
|
||||||
pid_t reaped_pid = 0;
|
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
for_each_child([&reaped_pid, &exit_status](Process& process) {
|
siginfo_t siginfo;
|
||||||
if (process.is_dead()) {
|
for_each_child([&siginfo](Process& process) {
|
||||||
reaped_pid = process.pid();
|
if (process.is_dead())
|
||||||
exit_status = reap(process);
|
siginfo = reap(process);
|
||||||
}
|
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
return reaped_pid;
|
return siginfo;
|
||||||
} else {
|
} else if (idtype == P_PID) {
|
||||||
ASSERT(waitee > 0); // FIXME: Implement other PID specs.
|
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
auto* waitee_process = Process::from_pid(waitee);
|
auto* waitee_process = Process::from_pid(id);
|
||||||
if (!waitee_process)
|
if (!waitee_process)
|
||||||
return -ECHILD;
|
return KResult(-ECHILD);
|
||||||
if (waitee_process->is_dead()) {
|
if (waitee_process->is_dead())
|
||||||
exit_status = reap(*waitee_process);
|
return reap(*waitee_process);
|
||||||
return waitee;
|
} else {
|
||||||
}
|
// FIXME: Implement other PID specs.
|
||||||
return 0;
|
return KResult(-EINVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t waitee_pid = waitee;
|
pid_t waitee_pid;
|
||||||
|
|
||||||
|
// FIXME: WaitBlocker should support idtype/id specs directly.
|
||||||
|
if (idtype == P_ALL) {
|
||||||
|
waitee_pid = -1;
|
||||||
|
} else if (idtype == P_PID) {
|
||||||
|
waitee_pid = id;
|
||||||
|
} else {
|
||||||
|
// FIXME: Implement other PID specs.
|
||||||
|
return KResult(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
if (current->block<Thread::WaitBlocker>(options, waitee_pid) != Thread::BlockResult::WokeNormally)
|
if (current->block<Thread::WaitBlocker>(options, waitee_pid) != Thread::BlockResult::WokeNormally)
|
||||||
return -EINTR;
|
return KResult(-EINTR);
|
||||||
|
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
|
|
||||||
// NOTE: If waitee was -1, m_waitee_pid will have been filled in by the scheduler.
|
// NOTE: If waitee was -1, m_waitee_pid will have been filled in by the scheduler.
|
||||||
Process* waitee_process = Process::from_pid(waitee_pid);
|
Process* waitee_process = Process::from_pid(waitee_pid);
|
||||||
if (!waitee_process)
|
if (!waitee_process)
|
||||||
return -ECHILD;
|
return KResult(-ECHILD);
|
||||||
|
|
||||||
ASSERT(waitee_process);
|
ASSERT(waitee_process);
|
||||||
if (waitee_process->is_dead()) {
|
if (waitee_process->is_dead()) {
|
||||||
exit_status = reap(*waitee_process);
|
return reap(*waitee_process);
|
||||||
} else {
|
} else {
|
||||||
auto* waitee_thread = Thread::from_tid(waitee_pid);
|
auto* waitee_thread = Thread::from_tid(waitee_pid);
|
||||||
if (!waitee_thread)
|
if (!waitee_thread)
|
||||||
return -ECHILD;
|
return KResult(-ECHILD);
|
||||||
ASSERT(waitee_thread->state() == Thread::State::Stopped);
|
ASSERT(waitee_thread->state() == Thread::State::Stopped);
|
||||||
exit_status = (waitee_thread->m_stop_signal << 8) | 0x7f;
|
siginfo_t siginfo;
|
||||||
|
siginfo.si_signo = SIGCHLD;
|
||||||
|
siginfo.si_pid = waitee_process->pid();
|
||||||
|
siginfo.si_uid = waitee_process->uid();
|
||||||
|
siginfo.si_status = CLD_STOPPED;
|
||||||
|
siginfo.si_code = waitee_thread->m_stop_signal;
|
||||||
|
return siginfo;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wstatus)
|
pid_t Process::sys$waitid(const Syscall::SC_waitid_params* user_params)
|
||||||
copy_to_user(wstatus, &exit_status);
|
{
|
||||||
return waitee_pid;
|
REQUIRE_PROMISE(stdio);
|
||||||
|
|
||||||
|
Syscall::SC_waitid_params params;
|
||||||
|
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (!validate_write_typed(params.infop))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
//#ifdef PROCESS_DEBUG
|
||||||
|
dbg() << "sys$waitid(" << params.idtype << ", " << params.id << ", " << params.infop << ", " << params.options << ")";
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
auto siginfo_or_error = do_waitid(static_cast<idtype_t>(params.idtype), params.id, params.options);
|
||||||
|
if (siginfo_or_error.is_error())
|
||||||
|
return siginfo_or_error.error();
|
||||||
|
|
||||||
|
copy_to_user(params.infop, &siginfo_or_error.value());
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Process::validate_read_from_kernel(VirtualAddress vaddr, size_t size) const
|
bool Process::validate_read_from_kernel(VirtualAddress vaddr, size_t size) const
|
||||||
|
|
|
@ -201,7 +201,7 @@ public:
|
||||||
int sys$kill(pid_t pid, int sig);
|
int sys$kill(pid_t pid, int sig);
|
||||||
[[noreturn]] void sys$exit(int status);
|
[[noreturn]] void sys$exit(int status);
|
||||||
int sys$sigreturn(RegisterDump& registers);
|
int sys$sigreturn(RegisterDump& registers);
|
||||||
pid_t sys$waitpid(pid_t, int* wstatus, int options);
|
pid_t sys$waitid(const Syscall::SC_waitid_params*);
|
||||||
void* sys$mmap(const Syscall::SC_mmap_params*);
|
void* sys$mmap(const Syscall::SC_mmap_params*);
|
||||||
int sys$munmap(void*, size_t size);
|
int sys$munmap(void*, size_t size);
|
||||||
int sys$set_mmap_name(const Syscall::SC_set_mmap_name_params*);
|
int sys$set_mmap_name(const Syscall::SC_set_mmap_name_params*);
|
||||||
|
@ -310,7 +310,7 @@ public:
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
|
||||||
[[noreturn]] void crash(int signal, u32 eip);
|
[[noreturn]] void crash(int signal, u32 eip);
|
||||||
[[nodiscard]] static int reap(Process&);
|
[[nodiscard]] static siginfo_t reap(Process&);
|
||||||
|
|
||||||
const TTY* tty() const { return m_tty; }
|
const TTY* tty() const { return m_tty; }
|
||||||
void set_tty(TTY* tty) { m_tty = tty; }
|
void set_tty(TTY* tty) { m_tty = tty; }
|
||||||
|
@ -430,6 +430,8 @@ private:
|
||||||
KResult do_kill(Process&, int signal);
|
KResult do_kill(Process&, int signal);
|
||||||
KResult do_killpg(pid_t pgrp, int signal);
|
KResult do_killpg(pid_t pgrp, int signal);
|
||||||
|
|
||||||
|
KResultOr<siginfo_t> do_waitid(idtype_t idtype, int id, int options);
|
||||||
|
|
||||||
KResultOr<String> get_syscall_path_argument(const char* user_path, size_t path_length) const;
|
KResultOr<String> get_syscall_path_argument(const char* user_path, size_t path_length) const;
|
||||||
KResultOr<String> get_syscall_path_argument(const Syscall::StringArgument&) const;
|
KResultOr<String> get_syscall_path_argument(const Syscall::StringArgument&) const;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ extern "C" {
|
||||||
struct timeval;
|
struct timeval;
|
||||||
struct timespec;
|
struct timespec;
|
||||||
struct sockaddr;
|
struct sockaddr;
|
||||||
|
struct siginfo;
|
||||||
typedef u32 socklen_t;
|
typedef u32 socklen_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ typedef u32 socklen_t;
|
||||||
__ENUMERATE_SYSCALL(exit) \
|
__ENUMERATE_SYSCALL(exit) \
|
||||||
__ENUMERATE_SYSCALL(getgid) \
|
__ENUMERATE_SYSCALL(getgid) \
|
||||||
__ENUMERATE_SYSCALL(getpid) \
|
__ENUMERATE_SYSCALL(getpid) \
|
||||||
__ENUMERATE_SYSCALL(waitpid) \
|
__ENUMERATE_SYSCALL(waitid) \
|
||||||
__ENUMERATE_SYSCALL(mmap) \
|
__ENUMERATE_SYSCALL(mmap) \
|
||||||
__ENUMERATE_SYSCALL(munmap) \
|
__ENUMERATE_SYSCALL(munmap) \
|
||||||
__ENUMERATE_SYSCALL(get_dir_entries) \
|
__ENUMERATE_SYSCALL(get_dir_entries) \
|
||||||
|
@ -404,6 +405,13 @@ struct SC_unveil_params {
|
||||||
StringArgument permissions;
|
StringArgument permissions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SC_waitid_params {
|
||||||
|
int idtype;
|
||||||
|
int id;
|
||||||
|
struct siginfo* infop;
|
||||||
|
int options;
|
||||||
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
int sync();
|
int sync();
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,52 @@ pid_t wait(int* wstatus)
|
||||||
|
|
||||||
pid_t waitpid(pid_t waitee, int* wstatus, int options)
|
pid_t waitpid(pid_t waitee, int* wstatus, int options)
|
||||||
{
|
{
|
||||||
int rc = syscall(SC_waitpid, waitee, wstatus, options);
|
siginfo_t siginfo;
|
||||||
|
idtype_t idtype;
|
||||||
|
id_t id;
|
||||||
|
|
||||||
|
if (waitee < -1) {
|
||||||
|
idtype = P_PGID;
|
||||||
|
id = -waitee;
|
||||||
|
} else if (waitee == -1) {
|
||||||
|
idtype = P_ALL;
|
||||||
|
id = 0;
|
||||||
|
} else if (waitee == 0) {
|
||||||
|
idtype = P_PGID;
|
||||||
|
id = getgid();
|
||||||
|
} else {
|
||||||
|
idtype = P_PID;
|
||||||
|
id = waitee;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc = waitid(idtype, id, &siginfo, options | WEXITED);
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (wstatus) {
|
||||||
|
switch (siginfo.si_code) {
|
||||||
|
case CLD_EXITED:
|
||||||
|
*wstatus = siginfo.si_status << 8;
|
||||||
|
break;
|
||||||
|
case CLD_KILLED:
|
||||||
|
*wstatus = siginfo.si_status;
|
||||||
|
break;
|
||||||
|
case CLD_STOPPED:
|
||||||
|
*wstatus = siginfo.si_status << 8 | 0x7f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return siginfo.si_pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
int waitid(idtype_t idtype, id_t id, siginfo_t* infop, int options)
|
||||||
|
{
|
||||||
|
Syscall::SC_waitid_params params { idtype, id, infop, options };
|
||||||
|
int rc = syscall(SC_waitid, ¶ms);
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ __BEGIN_DECLS
|
||||||
#define WSTOPSIG(status) WEXITSTATUS(status)
|
#define WSTOPSIG(status) WEXITSTATUS(status)
|
||||||
#define WTERMSIG(status) ((status)&0x7f)
|
#define WTERMSIG(status) ((status)&0x7f)
|
||||||
#define WIFEXITED(status) (WTERMSIG(status) == 0)
|
#define WIFEXITED(status) (WTERMSIG(status) == 0)
|
||||||
#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
|
#define WIFSTOPPED(status) (((status)&0xff) == 0x7f)
|
||||||
#define WIFSIGNALED(status) (((char)(((status)&0x7f) + 1) >> 1) > 0)
|
#define WIFSIGNALED(status) (((char)(((status)&0x7f) + 1) >> 1) > 0)
|
||||||
|
|
||||||
#define WNOHANG 1
|
#define WNOHANG 1
|
||||||
|
@ -52,5 +53,6 @@ typedef enum {
|
||||||
|
|
||||||
pid_t waitpid(pid_t, int* wstatus, int options);
|
pid_t waitpid(pid_t, int* wstatus, int options);
|
||||||
pid_t wait(int* wstatus);
|
pid_t wait(int* wstatus);
|
||||||
|
int waitid(idtype_t idtype, id_t id, siginfo_t* infop, int options);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue