1 | /* Wait for process to change state. Linux version. |
2 | Copyright (C) 2019-2020 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <sys/wait.h> |
20 | #include <sys/resource.h> |
21 | #include <sysdep-cancel.h> |
22 | |
23 | pid_t |
24 | __wait4 (pid_t pid, int *stat_loc, int options, struct rusage *usage) |
25 | { |
26 | #ifdef __NR_wait4 |
27 | return SYSCALL_CANCEL (wait4, pid, stat_loc, options, usage); |
28 | #elif defined (__ASSUME_WAITID_PID0_P_PGID) |
29 | idtype_t idtype = P_PID; |
30 | |
31 | if (pid < -1) |
32 | { |
33 | idtype = P_PGID; |
34 | pid *= -1; |
35 | } |
36 | else if (pid == -1) |
37 | idtype = P_ALL; |
38 | else if (pid == 0) |
39 | idtype = P_PGID; |
40 | |
41 | options |= WEXITED; |
42 | |
43 | siginfo_t infop; |
44 | if (SYSCALL_CANCEL (waitid, idtype, pid, &infop, options, usage) < 0) |
45 | return -1; |
46 | |
47 | if (stat_loc) |
48 | { |
49 | switch (infop.si_code) |
50 | { |
51 | case CLD_EXITED: |
52 | *stat_loc = W_EXITCODE (infop.si_status, 0); |
53 | break; |
54 | case CLD_DUMPED: |
55 | *stat_loc = WCOREFLAG | infop.si_status; |
56 | break; |
57 | case CLD_KILLED: |
58 | *stat_loc = infop.si_status; |
59 | break; |
60 | case CLD_TRAPPED: |
61 | case CLD_STOPPED: |
62 | *stat_loc = W_STOPCODE (infop.si_status); |
63 | break; |
64 | case CLD_CONTINUED: |
65 | *stat_loc = __W_CONTINUED; |
66 | break; |
67 | default: |
68 | *stat_loc = 0; |
69 | break; |
70 | } |
71 | } |
72 | |
73 | return infop.si_pid; |
74 | # else |
75 | /* Linux waitid prior kernel 5.4 does not support waiting for the current |
76 | process. It is possible to emulate wait4 it by calling getpgid for |
77 | PID 0, however, it would require an additional syscall and it is inherent |
78 | racy: after the current process group is received and before it is passed |
79 | to waitid a signal could arrive causing the current process group to |
80 | change. */ |
81 | # error "The kernel ABI does not provide a way to implement wait4" |
82 | #endif |
83 | } |
84 | libc_hidden_def (__wait4); |
85 | weak_alias (__wait4, wait4) |
86 | |