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
20pid_t
21wait(int* _status)
22{
23	return waitpid(-1, _status, 0);
24}
25
26extern "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
87pid_t
88waitpid(pid_t pid, int* _status, int options)
89{
90	return _waitpid(pid, _status, options, NULL);
91}
92
93
94int
95waitid(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