2#include "pedigree/kernel/Log.h"
3#include "pedigree/kernel/process/Scheduler.h"
4#include "pedigree/kernel/process/Thread.h"
5#include "pedigree/kernel/processor/Processor.h"
6#include "pedigree/kernel/processor/ProcessorInformation.h"
7#include "pedigree/kernel/syscallError.h"
9#include "PosixProcess.h"
10#include "PosixSubsystem.h"
11#include "wait-state.h"
16 if (!child || child == parent || child->getType() != Process::Posix ||
20 if (request.selector == Selector::All)
22 if (request.selector == Selector::Pid)
23 return child->
getUserspaceId(parent->pidNamespace().
get()) ==
static_cast<size_t>(request.id);
25 return request.id >= 0 &&
26 static_cast<PosixProcess*
>(child)->getProcessGroupId(group,
27 parent->pidNamespace().
get()) &&
28 group ==
static_cast<size_t>(request.id);
31void terminalStatus(
int encoded, Report& report) {
32 if (!(encoded & 0x7F)) {
34 report.status = (encoded >> 8) & 0xFF;
36 report.cause = (encoded & 0x80) ? Dumped : Killed;
37 report.status = encoded & 0x7F;
41void snapshotTimes(
Process* child, Report& report) {
42 report.userNanoseconds = child->
getUserTime() + child->getReapedChildrenUserTime();
43 report.kernelNanoseconds = child->getKernelTime() + child->getReapedChildrenKernelTime();
47int collect(
const Request& request, Report& report) {
51 struct InterruptionScope {
53 ~InterruptionScope() {
57 } interruptionScope{thread};
59 WaitQueue::WakeReason previousWake = WaitQueue::WakeReason::Signalled;
64 Process* terminalChild =
nullptr;
66 bool hasResult =
false;
71 bool hasEligibleChild =
false;
72 for (
size_t i = 0;; ++i) {
76 if (!eligible(parent, child, request))
79 if (child->getState() == Process::Terminated) {
81 if (!(request.events & Exited))
93 FATAL(
"child wait lost sole reaper ownership for pid " <<
Dec << child->
getId());
97 terminalChild = child;
100 hasEligibleChild =
true;
101 auto* childSubsystem =
static_cast<PosixSubsystem*
>(child->getSubsystem());
102 if (childSubsystem &&
103 childSubsystem->traceContext().selectStop(
104 parent->
getId(), request.traceStops || (request.events & Stopped),
105 request.events & Continued, !request.noWait, selected)) {
113 request.events & Continued, !request.noWait,
117 if (transition.kind == Process::ChildTransitionKind::Stopped) {
118 selected.cause = Stop;
119 selected.status = transition.stopSignal;
121 selected.cause = Continue;
122 selected.status = 18;
124 snapshotTimes(child, selected);
127 selected.pid =
static_cast<int32_t
>(child->
getUserspaceId(parent->pidNamespace().
get()));
128 selected.uid =
static_cast<PosixProcess*
>(child)->snapshotCredentials().ruid;
133 if (!hasEligibleChild) {
134 SYSCALL_ERROR(NoChildren);
137 if (request.noHang) {
142 if (thread->getInterruptionReason() == Thread::InterruptedBySignal ||
143 previousWake == WaitQueue::WakeReason::Unwinding ||
144 previousWake == WaitQueue::WakeReason::Terminating) {
145 SYSCALL_ERROR(Interrupted);
149 reinterpret_cast<uintptr_t
>(__builtin_return_address(0)));
159 FATAL(
"child wait attempted to observe its own terminating process");
163 selected.kernelNanoseconds);
166 snapshotTimes(terminalChild, selected);
size_t getUserspaceId() const
@ Reaped
Terminal wait status is visible; the owner may still be on-stack.
void accountReapedChild(const Process *child, Time::Timestamp &user, Time::Timestamp &kernel)
WaitQueue::Guard acquireChildStateWait()
bool selectPendingChildTransition(bool includeStopped, bool includeContinued, bool consume, ChildTransition &transition)
bool waitUntilTerminationReapable()
Time::Timestamp getUserTime() const
ReaperClaim tryClaimReaper()
static ProcessorInformation & information()
Process * getChildProcess(Process *pParent, size_t n)
static Scheduler & instance()
void setErrno(size_t err)
bool retainTemporarySignalWaitInterruptionOrClear()
Process * getParent() const