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