xref: /haiku/src/system/libroot/posix/sys/wait.cpp (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
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 | WEXITED, &info,
32 		usage_info);
33 
34 	pthread_testcancel();
35 
36 	if (child < 0) {
37 		// When not getting a child status when WNOHANG was specified, don't
38 		// fail.
39 		if (child == B_WOULD_BLOCK && (options & WNOHANG) != 0)
40 			return 0;
41 		RETURN_AND_SET_ERRNO(child);
42 	}
43 
44 	// prepare the status
45 	if (_status != NULL) {
46 		int status;
47 		switch (info.si_code) {
48 			case CLD_EXITED:
49 				// fill in exit status for WIFEXITED() and WEXITSTATUS()
50 				status = info.si_status & 0xff;
51 				break;
52 
53 			case CLD_KILLED:
54 			case CLD_DUMPED:
55 				// fill in signal for WIFSIGNALED() and WTERMSIG()
56 				status = (info.si_status << 8) & 0xff00;
57 				// if core dumped, set flag for WIFCORED()
58 				if (info.si_code == CLD_DUMPED)
59 					status |= 0x10000;
60 				break;
61 
62 			case CLD_CONTINUED:
63 				// set flag for WIFCONTINUED()
64 				status = 0x20000;
65 				break;
66 
67 			case CLD_STOPPED:
68 				// fill in signal for WIFSTOPPED() and WSTOPSIG()
69 				status = (info.si_status << 16) & 0xff0000;
70 				break;
71 
72 			case CLD_TRAPPED:
73 				// we don't do that
74 			default:
75 				// should never get here -- assume exited
76 				status = 0;
77 				break;
78 		}
79 
80 		*_status = status;
81 	}
82 
83 	return child;
84 }
85 
86 
87 pid_t
88 waitpid(pid_t pid, int* _status, int options)
89 {
90 	return _waitpid(pid, _status, options, NULL);
91 }
92 
93 
94 int
95 waitid(idtype_t idType, id_t id, siginfo_t* info, int options)
96 {
97 	// translate the idType, id pair to a waitpid() style ID
98 	switch (idType) {
99 		case P_ALL:
100 			// any child
101 			id = -1;
102 			break;
103 
104 		case P_PID:
105 			// the child with the given ID
106 			if (id <= 0)
107 				RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
108 			break;
109 
110 		case P_PGID:
111 			// any child in the given process group
112 			if (id <= 1)
113 				RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
114 			id = -id;
115 			break;
116 
117 		default:
118 			RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
119 	}
120 
121 	pid_t child = _kern_wait_for_child(id, options, info, NULL);
122 	if (child >= 0 || child == B_WOULD_BLOCK)
123 		return 0;
124 
125 	RETURN_AND_SET_ERRNO_TEST_CANCEL(child);
126 }
127