1 /* COPYING ******************************************************************
2 For copyright and licensing terms, see the file named COPYING.
3 // **************************************************************************
4 */
5
6 #include <cerrno>
7 #include <csignal>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
11 #include "wait.h"
12
13 /* Waiting for child processes **********************************************
14 // **************************************************************************
15 */
16
17 #if defined(WEXITED)
18
19 static inline
20 void
make_status(const siginfo_t & si,int & status,int & code)21 make_status (
22 const siginfo_t & si,
23 int & status,
24 int & code
25 ) {
26 switch (si.si_code) {
27 case CLD_EXITED: status = WAIT_STATUS_EXITED; code = si.si_status; break;
28 case CLD_KILLED: status = WAIT_STATUS_SIGNALLED; code = si.si_status; break;
29 case CLD_DUMPED: status = WAIT_STATUS_SIGNALLED_CORE; code = si.si_status; break;
30 case CLD_STOPPED: status = WAIT_STATUS_PAUSED; code = si.si_status; break;
31 case CLD_TRAPPED: status = WAIT_STATUS_PAUSED; code = si.si_status; break;
32 default:
33 case CLD_CONTINUED: status = WAIT_STATUS_RUNNING; code = 0; break;
34 }
35 }
36
37 static inline
38 int /// \retval -1 error \retval 0 no child \retval >0 found child
wait_for_anychild(pid_t & child,int & status,int & code,int flags)39 wait_for_anychild (
40 pid_t & child,
41 int & status,
42 int & code,
43 int flags
44 ) {
45 for (;;) {
46 siginfo_t si;
47 // The Windows NT Linux subsystem needs this; actual Linux does not, despite the manual.
48 si.si_pid = si.si_signo = 0;
49 const int rc(waitid(P_ALL, static_cast<pid_t>(-1), &si, flags));
50 if (0 > rc) {
51 if (EINTR != errno) return -1;
52 } else
53 if (0 == si.si_pid || 0 == si.si_signo)
54 return 0;
55 else
56 {
57 make_status(si, status, code);
58 child = si.si_pid;
59 return 1;
60 }
61 }
62 }
63
64 int /// \retval -1 error \retval 0 no child \retval >0 found child
wait_blocking_for_anychild_exit(pid_t & child,int & status,int & code)65 wait_blocking_for_anychild_exit (
66 pid_t & child,
67 int & status,
68 int & code
69 ) {
70 return wait_for_anychild(child, status, code, WEXITED);
71 }
72
73 #else
74
75 static inline
76 void
make_status(int s,int & status,int & code)77 make_status (
78 int s,
79 int & status,
80 int & code
81 ) {
82 #if defined(WIFCONTINUED)
83 if (WIFCONTINUED(s)) {
84 status = WAIT_STATUS_RUNNING;
85 code = 0;
86 } else
87 #endif
88 if (WIFSTOPPED(s)) {
89 status = WAIT_STATUS_PAUSED;
90 code = WSTOPSIG(s);
91 } else
92 if (WIFEXITED(s)) {
93 status = WAIT_STATUS_EXITED;
94 code = WEXITSTATUS(s);
95 } else
96 if (WIFSIGNALED(s)) {
97 status = WCOREDUMP(s) ? WAIT_STATUS_SIGNALLED_CORE : WAIT_STATUS_SIGNALLED;
98 code = WTERMSIG(s);
99 } else
100 {
101 status = WAIT_STATUS_RUNNING;
102 code = 0;
103 }
104 }
105
106 static inline
107 int /// \retval -1 error \retval 0 no child \retval >0 found child
wait_for_anychild(pid_t & child,int & status,int & code,int flags)108 wait_for_anychild (
109 pid_t & child,
110 int & status,
111 int & code,
112 int flags
113 ) {
114 for (;;) {
115 int s;
116 const pid_t rc(waitpid(-1, &s, flags));
117 if (static_cast<pid_t>(-1) == rc) {
118 if (EINTR != errno) return -1;
119 } else
120 if (static_cast<pid_t>(0) == rc) {
121 return 0;
122 } else
123 {
124 make_status(s, status, code);
125 child = rc;
126 return 1;
127 }
128 }
129 }
130
131 int /// \retval -1 error \retval 0 no child \retval >0 found child
wait_blocking_for_anychild_exit(pid_t & child,int & status,int & code)132 wait_blocking_for_anychild_exit (
133 pid_t & child,
134 int & status,
135 int & code
136 ) {
137 return wait_for_anychild(child, status, code, 0);
138 }
139
140 #endif
141