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