xref: /linux/tools/testing/selftests/pidfd/pidfd_wait.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #define _GNU_SOURCE
4 #include <errno.h>
5 #include <linux/sched.h>
6 #include <linux/types.h>
7 #include <signal.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sched.h>
12 #include <string.h>
13 #include <sys/resource.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <sys/wait.h>
17 #include <unistd.h>
18 
19 #include "pidfd.h"
20 #include "../kselftest_harness.h"
21 
22 #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
23 
24 /* Attempt to de-conflict with the selftests tree. */
25 #ifndef SKIP
26 #define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)
27 #endif
28 
29 static pid_t sys_clone3(struct clone_args *args)
30 {
31 	return syscall(__NR_clone3, args, sizeof(struct clone_args));
32 }
33 
34 static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
35 		      struct rusage *ru)
36 {
37 	return syscall(__NR_waitid, which, pid, info, options, ru);
38 }
39 
40 TEST(wait_simple)
41 {
42 	int pidfd = -1;
43 	pid_t parent_tid = -1;
44 	struct clone_args args = {
45 		.parent_tid = ptr_to_u64(&parent_tid),
46 		.pidfd = ptr_to_u64(&pidfd),
47 		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
48 		.exit_signal = SIGCHLD,
49 	};
50 	pid_t pid;
51 	siginfo_t info = {
52 		.si_signo = 0,
53 	};
54 
55 	pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
56 	ASSERT_GE(pidfd, 0);
57 
58 	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
59 	ASSERT_NE(pid, 0);
60 	EXPECT_EQ(close(pidfd), 0);
61 	pidfd = -1;
62 
63 	pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
64 	ASSERT_GE(pidfd, 0);
65 
66 	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
67 	ASSERT_NE(pid, 0);
68 	EXPECT_EQ(close(pidfd), 0);
69 	pidfd = -1;
70 
71 	pid = sys_clone3(&args);
72 	ASSERT_GE(pid, 0);
73 
74 	if (pid == 0)
75 		exit(EXIT_SUCCESS);
76 
77 	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
78 	ASSERT_GE(pid, 0);
79 	ASSERT_EQ(WIFEXITED(info.si_status), true);
80 	ASSERT_EQ(WEXITSTATUS(info.si_status), 0);
81 	EXPECT_EQ(close(pidfd), 0);
82 
83 	ASSERT_EQ(info.si_signo, SIGCHLD);
84 	ASSERT_EQ(info.si_code, CLD_EXITED);
85 	ASSERT_EQ(info.si_pid, parent_tid);
86 }
87 
88 TEST(wait_states)
89 {
90 	int pidfd = -1;
91 	pid_t parent_tid = -1;
92 	struct clone_args args = {
93 		.parent_tid = ptr_to_u64(&parent_tid),
94 		.pidfd = ptr_to_u64(&pidfd),
95 		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
96 		.exit_signal = SIGCHLD,
97 	};
98 	int pfd[2];
99 	pid_t pid;
100 	siginfo_t info = {
101 		.si_signo = 0,
102 	};
103 
104 	ASSERT_EQ(pipe(pfd), 0);
105 	pid = sys_clone3(&args);
106 	ASSERT_GE(pid, 0);
107 
108 	if (pid == 0) {
109 		char buf[2];
110 
111 		close(pfd[1]);
112 		kill(getpid(), SIGSTOP);
113 		ASSERT_EQ(read(pfd[0], buf, 1), 1);
114 		close(pfd[0]);
115 		kill(getpid(), SIGSTOP);
116 		exit(EXIT_SUCCESS);
117 	}
118 
119 	close(pfd[0]);
120 	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
121 	ASSERT_EQ(info.si_signo, SIGCHLD);
122 	ASSERT_EQ(info.si_code, CLD_STOPPED);
123 	ASSERT_EQ(info.si_pid, parent_tid);
124 
125 	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
126 
127 	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0);
128 	ASSERT_EQ(write(pfd[1], "C", 1), 1);
129 	close(pfd[1]);
130 	ASSERT_EQ(info.si_signo, SIGCHLD);
131 	ASSERT_EQ(info.si_code, CLD_CONTINUED);
132 	ASSERT_EQ(info.si_pid, parent_tid);
133 
134 	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0);
135 	ASSERT_EQ(info.si_signo, SIGCHLD);
136 	ASSERT_EQ(info.si_code, CLD_STOPPED);
137 	ASSERT_EQ(info.si_pid, parent_tid);
138 
139 	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
140 
141 	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
142 	ASSERT_EQ(info.si_signo, SIGCHLD);
143 	ASSERT_EQ(info.si_code, CLD_KILLED);
144 	ASSERT_EQ(info.si_pid, parent_tid);
145 
146 	EXPECT_EQ(close(pidfd), 0);
147 }
148 
149 TEST(wait_nonblock)
150 {
151 	int pidfd;
152 	unsigned int flags = 0;
153 	pid_t parent_tid = -1;
154 	struct clone_args args = {
155 		.parent_tid = ptr_to_u64(&parent_tid),
156 		.flags = CLONE_PARENT_SETTID,
157 		.exit_signal = SIGCHLD,
158 	};
159 	int ret;
160 	pid_t pid;
161 	siginfo_t info = {
162 		.si_signo = 0,
163 	};
164 
165 	/*
166 	 * Callers need to see ECHILD with non-blocking pidfds when no child
167 	 * processes exists.
168 	 */
169 	pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
170 	EXPECT_GE(pidfd, 0) {
171 		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
172 		ASSERT_EQ(errno, EINVAL);
173 		SKIP(return, "Skipping PIDFD_NONBLOCK test");
174 	}
175 
176 	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
177 	ASSERT_LT(ret, 0);
178 	ASSERT_EQ(errno, ECHILD);
179 	EXPECT_EQ(close(pidfd), 0);
180 
181 	pid = sys_clone3(&args);
182 	ASSERT_GE(pid, 0);
183 
184 	if (pid == 0) {
185 		kill(getpid(), SIGSTOP);
186 		exit(EXIT_SUCCESS);
187 	}
188 
189 	pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
190 	EXPECT_GE(pidfd, 0) {
191 		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
192 		ASSERT_EQ(errno, EINVAL);
193 		SKIP(return, "Skipping PIDFD_NONBLOCK test");
194 	}
195 
196 	flags = fcntl(pidfd, F_GETFL, 0);
197 	ASSERT_GT(flags, 0);
198 	ASSERT_GT((flags & O_NONBLOCK), 0);
199 
200 	/*
201 	 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
202 	 * child processes exist but none have exited.
203 	 */
204 	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
205 	ASSERT_LT(ret, 0);
206 	ASSERT_EQ(errno, EAGAIN);
207 
208 	/*
209 	 * Callers need to continue seeing 0 with non-blocking pidfd and
210 	 * WNOHANG raised explicitly when child processes exist but none have
211 	 * exited.
212 	 */
213 	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL);
214 	ASSERT_EQ(ret, 0);
215 
216 	ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
217 
218 	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
219 	ASSERT_EQ(info.si_signo, SIGCHLD);
220 	ASSERT_EQ(info.si_code, CLD_STOPPED);
221 	ASSERT_EQ(info.si_pid, parent_tid);
222 
223 	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
224 
225 	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
226 	ASSERT_EQ(info.si_signo, SIGCHLD);
227 	ASSERT_EQ(info.si_code, CLD_EXITED);
228 	ASSERT_EQ(info.si_pid, parent_tid);
229 
230 	EXPECT_EQ(close(pidfd), 0);
231 }
232 
233 TEST_HARNESS_MAIN
234