xref: /haiku/src/system/libroot/posix/sys/wait.cpp (revision 5f4f984a94d150153bcb00a2ed780d0437859543)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
4  * All rights reserved.
5  * Distributed under the terms of the MIT License.
6  */
7 
8 #include <sys/wait.h>
9 
10 #include <errno.h>
11 #include <pthread.h>
12 
13 #include <syscall_utils.h>
14 
15 #include <errno_private.h>
16 #include <syscalls.h>
17 #include <thread_defs.h>
18 
19 
20 pid_t
21 wait(int* _status)
22 {
23 	return waitpid(-1, _status, 0);
24 }
25 
26 extern "C" pid_t
27 _waitpid(pid_t pid, int* _status, int options, team_usage_info *usage_info)
28 {
29 	// wait
30 	siginfo_t info;
31 	pid_t child = _kern_wait_for_child(pid, options, &info, usage_info);
32 
33 	pthread_testcancel();
34 
35 	if (child < 0) {
36 		// When not getting a child status when WNOHANG was specified, don't
37 		// fail.
38 		if (child == B_WOULD_BLOCK && (options & WNOHANG) != 0)
39 			return 0;
40 		RETURN_AND_SET_ERRNO(child);
41 	}
42 
43 	// prepare the status
44 	if (_status != NULL) {
45 		int status;
46 		switch (info.si_code) {
47 			case CLD_EXITED:
48 				// fill in exit status for WIFEXITED() and WEXITSTATUS()
49 				status = info.si_status & 0xff;
50 				break;
51 
52 			case CLD_KILLED:
53 			case CLD_DUMPED:
54 				// fill in signal for WIFSIGNALED() and WTERMSIG()
55 				status = (info.si_status << 8) & 0xff00;
56 				// if core dumped, set flag for WIFCORED()
57 				if (info.si_code == CLD_DUMPED)
58 					status |= 0x10000;
59 				break;
60 
61 			case CLD_CONTINUED:
62 				// set flag for WIFCONTINUED()
63 				status = 0x20000;
64 				break;
65 
66 			case CLD_STOPPED:
67 				// fill in signal for WIFSTOPPED() and WSTOPSIG()
68 				status = (info.si_status << 16) & 0xff0000;
69 				break;
70 
71 			case CLD_TRAPPED:
72 				// we don't do that
73 			default:
74 				// should never get here -- assume exited
75 				status = 0;
76 				break;
77 		}
78 
79 		*_status = status;
80 	}
81 
82 	return child;
83 }
84 
85 
86 pid_t
87 waitpid(pid_t pid, int* _status, int options)
88 {
89 	return _waitpid(pid, _status, options, NULL);
90 }
91 
92 
93 int
94 waitid(idtype_t idType, id_t id, siginfo_t* info, int options)
95 {
96 	// translate the idType, id pair to a waitpid() style ID
97 	switch (idType) {
98 		case P_ALL:
99 			// any child
100 			id = -1;
101 			break;
102 
103 		case P_PID:
104 			// the child with the given ID
105 			if (id <= 0)
106 				RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
107 			break;
108 
109 		case P_PGID:
110 			// any child in the given process group
111 			if (id <= 1)
112 				RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
113 			id = -id;
114 			break;
115 
116 		default:
117 			RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
118 	}
119 
120 	pid_t child = _kern_wait_for_child(id, options, info, NULL);
121 	if (child >= 0 || child == B_WOULD_BLOCK)
122 		return 0;
123 
124 	RETURN_AND_SET_ERRNO_TEST_CANCEL(child);
125 }
126