2#include "pedigree/kernel/process/Thread.h"
3#include "pedigree/kernel/processor/Processor.h"
4#include "pedigree/kernel/processor/ProcessorInformation.h"
5#include "pedigree/kernel/processor/VirtualAddressSpace.h"
6#include "pedigree/kernel/syscallError.h"
7#include "pedigree/kernel/time/Time.h"
9#include "PosixProcess.h"
10#include "PosixSubsystem.h"
11#include "linux-resource-abi.h"
12#include "wait-state.h"
13#include "wait-syscalls.h"
16constexpr unsigned NoHang = 1, Stopped = 2, Exited = 4, Continued = 8;
17constexpr unsigned NoWait = 0x01000000;
18constexpr unsigned DeferredOptions = 0xE0000000;
20struct LinuxWaitInformation {
28 uint8_t remainder[100];
30static_assert(
sizeof(LinuxWaitInformation) == 128,
"Linux amd64 siginfo size changed");
31static_assert(offsetof(LinuxWaitInformation, pid) == 16,
"Linux amd64 child PID offset changed");
32static_assert(offsetof(LinuxWaitInformation, status) == 24,
33 "Linux amd64 child status offset changed");
37 WaitResult() : thread(*
Processor::information().getCurrentThread()) {}
39 thread.setErrno(error);
41 int finish(
int result) {
42 error = result < 0 ? thread.getErrno() : 0;
55 request.id = process->getProcessGroupId(group, process->pidNamespace().
get())
56 ?
static_cast<int32_t
>(group)
61 request.events = ((
options & Exited) ?
static_cast<unsigned>(PosixWait::Exited) : 0U) |
62 ((
options & Stopped) ?
static_cast<unsigned>(PosixWait::Stopped) : 0U) |
63 ((
options & Continued) ? static_cast<unsigned>(PosixWait::Continued) : 0U);
64 request.noHang =
options & NoHang;
65 request.noWait =
options & NoWait;
69 if (
options & ~(NoHang | Stopped | Continued | DeferredOptions)) {
70 SYSCALL_ERROR(InvalidArgument);
73 if (pid == INT32_MIN) {
74 SYSCALL_ERROR(NoSuchProcess);
77 if (
options & DeferredOptions) {
78 SYSCALL_ERROR(OperationNotSupported);
81 eventOptions(
options | Exited, request);
82 request.traceStops =
true;
84 request.selector = PosixWait::Selector::Pid;
86 }
else if (pid != -1) {
87 request.selector = PosixWait::Selector::Pgid;
89 snapshotCurrentGroup(request);
97 if ((
options & ~(NoHang | NoWait | Exited | Stopped | Continued | DeferredOptions)) ||
98 !(
options & (Exited | Stopped | Continued))) {
99 SYSCALL_ERROR(InvalidArgument);
102 if (which < 0 || which > 3 || (which == 1 &&
id <= 0) || (which >= 2 &&
id < 0)) {
103 SYSCALL_ERROR(InvalidArgument);
106 if ((
options & DeferredOptions) || which == 3) {
107 SYSCALL_ERROR(OperationNotSupported);
110 eventOptions(
options, request);
112 request.selector = PosixWait::Selector::Pid;
114 }
else if (which == 2) {
115 request.selector = PosixWait::Selector::Pgid;
118 snapshotCurrentGroup(request);
125 usage.userSeconds = report.userNanoseconds / Time::Multiplier::Second;
126 usage.userMicroseconds =
127 (report.userNanoseconds % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
128 usage.systemSeconds = report.kernelNanoseconds / Time::Multiplier::Second;
129 usage.systemMicroseconds =
130 (report.kernelNanoseconds % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
135 switch (report.cause) {
136 case PosixWait::Exit:
137 return (report.status & 0xFF) << 8;
138 case PosixWait::Trapped:
139 case PosixWait::Stop:
140 return ((report.status & 0xFF) << 8) | 0x7F;
141 case PosixWait::Continue:
144 return (report.status & 0x7F) | (report.cause == PosixWait::Dumped ? 0x80 : 0);
148bool copyInformation(
void* destination,
const PosixWait::Report& report,
bool selected) {
149 const uintptr_t address =
reinterpret_cast<uintptr_t
>(destination);
150 constexpr size_t extent =
sizeof(LinuxWaitInformation);
154 if (address > ~uintptr_t(0) - (extent - 1))
156 const uintptr_t end = address + extent - 1;
162 LinuxWaitInformation snapshot = {};
164 snapshot.signal = 17;
165 snapshot.code = report.cause;
166 snapshot.pid = report.pid;
167 snapshot.uid = report.uid;
168 snapshot.status = report.status;
170 constexpr size_t offsets[] = {0, 4, 8, 16, 20, 24};
171 const auto* bytes =
reinterpret_cast<const uint8_t*
>(&snapshot);
172 for (
size_t offset : offsets) {
183 WaitResult completion;
185 if (prepareWait4(pid,
static_cast<unsigned>(
options), request) < 0)
186 return completion.finish(-1);
188 const int result = PosixWait::collect(request, report);
190 return completion.finish(result);
194 const int encoded = encodedStatus(report);
196 SYSCALL_ERROR(BadAddress);
197 return completion.finish(-1);
200 const auto snapshot = usageFor(report);
202 SYSCALL_ERROR(BadAddress);
203 return completion.finish(-1);
206 return completion.finish(report.pid);
210 WaitResult completion;
213 int result = prepareWaitId(which,
id,
static_cast<unsigned>(
options), request);
215 result = PosixWait::collect(request, report);
217 const size_t savedError = result < 0 ? thread->
getErrno() : 0;
218 if (result > 0 &&
usage) {
219 const auto snapshot = usageFor(report);
221 SYSCALL_ERROR(BadAddress);
222 return completion.finish(-1);
227 if (information && !copyInformation(information, report, result > 0)) {
228 SYSCALL_ERROR(BadAddress);
229 return completion.finish(-1);
232 return completion.finish(result < 0 ? -1 : 0);
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static ProcessorInformation & information()
void setErrno(size_t err)
virtual uintptr_t getUserStart() const =0
virtual uintptr_t getKernelStart() const =0
virtual bool isAddressValid(void *virtualAddress)=0