Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <assert.h>
8#include <bits/pthread_cancel.h>
9#include <errno.h>
10#include <sys/wait.h>
11#include <syscall.h>
12#include <unistd.h>
13
14extern "C" {
15
16// https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html
17pid_t wait(int* wstatus)
18{
19 return waitpid(-1, wstatus, 0);
20}
21
22// https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitpid.html
23pid_t waitpid(pid_t waitee, int* wstatus, int options)
24{
25 __pthread_maybe_cancel();
26
27 siginfo_t siginfo;
28 idtype_t idtype;
29 id_t id;
30
31 if (waitee < -1) {
32 idtype = P_PGID;
33 id = -waitee;
34 } else if (waitee == -1) {
35 idtype = P_ALL;
36 id = 0;
37 } else if (waitee == 0) {
38 idtype = P_PGID;
39 id = getgid();
40 } else {
41 idtype = P_PID;
42 id = waitee;
43 }
44
45 // To be able to detect if a child was found when WNOHANG is set,
46 // we need to clear si_pid, which will only be set if it was found.
47 siginfo.si_pid = 0;
48 int rc = waitid(idtype, id, &siginfo, options | WEXITED);
49
50 if (rc < 0)
51 return rc;
52
53 if ((options & WNOHANG) && siginfo.si_pid == 0) {
54 // No child in a waitable state was found. All other fields
55 // in siginfo are undefined
56 return 0;
57 }
58
59 if (wstatus) {
60 switch (siginfo.si_code) {
61 case CLD_EXITED:
62 *wstatus = siginfo.si_status << 8;
63 break;
64 case CLD_KILLED:
65 *wstatus = siginfo.si_status;
66 break;
67 case CLD_STOPPED:
68 *wstatus = siginfo.si_status << 8 | 0x7f;
69 break;
70 case CLD_CONTINUED:
71 *wstatus = 0xffff;
72 break;
73 default:
74 VERIFY_NOT_REACHED();
75 }
76 }
77
78 return siginfo.si_pid;
79}
80
81// https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html
82int waitid(idtype_t idtype, id_t id, siginfo_t* infop, int options)
83{
84 __pthread_maybe_cancel();
85
86 Syscall::SC_waitid_params params { idtype, id, infop, options };
87 int rc = syscall(SC_waitid, ¶ms);
88 __RETURN_WITH_ERRNO(rc, rc, -1);
89}
90}