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