xref: /haiku/src/system/libroot/posix/sys/wait.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
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 
27 pid_t
28 waitpid(pid_t pid, int* _status, int options)
29 {
30 	// wait
31 	siginfo_t info;
32 	pid_t child = _kern_wait_for_child(pid, options, &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 int
88 waitid(idtype_t idType, id_t id, siginfo_t* info, int options)
89 {
90 	// translate the idType, id pair to a waitpid() style ID
91 	switch (idType) {
92 		case P_ALL:
93 			// any child
94 			id = -1;
95 			break;
96 
97 		case P_PID:
98 			// the child with the given ID
99 			if (id <= 0)
100 				RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
101 			break;
102 
103 		case P_PGID:
104 			// any child in the given process group
105 			if (id <= 1)
106 				RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
107 			id = -id;
108 			break;
109 
110 		default:
111 			RETURN_AND_SET_ERRNO_TEST_CANCEL(EINVAL);
112 	}
113 
114 	pid_t child = _kern_wait_for_child(id, options, info);
115 	if (child >= 0 || child == B_WOULD_BLOCK)
116 		return 0;
117 
118 	RETURN_AND_SET_ERRNO_TEST_CANCEL(child);
119 }
120