blob: 4063d6f31fa40234a819375083b4823bb5f846a4 [file] [log] [blame]
Christian Braunere63f3082019-07-28 00:22:30 +02001/* 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"
Christian Brauner09d1de12020-09-02 12:21:29 +020020#include "../kselftest_harness.h"
Christian Braunere63f3082019-07-28 00:22:30 +020021
22#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
23
Christian Braunercd895972020-09-02 12:21:30 +020024/* Attempt to de-conflict with the selftests tree. */
25#ifndef SKIP
26#define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__)
27#endif
28
Christian Braunere63f3082019-07-28 00:22:30 +020029static pid_t sys_clone3(struct clone_args *args)
30{
31 return syscall(__NR_clone3, args, sizeof(struct clone_args));
32}
33
34static 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
Christian Brauner09d1de12020-09-02 12:21:29 +020040TEST(wait_simple)
Christian Braunere63f3082019-07-28 00:22:30 +020041{
Christian Braunere63f3082019-07-28 00:22:30 +020042 int pidfd = -1, status = 0;
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 int ret;
51 pid_t pid;
52 siginfo_t info = {
53 .si_signo = 0,
54 };
55
56 pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
Christian Brauner09d1de12020-09-02 12:21:29 +020057 ASSERT_GE(pidfd, 0);
Christian Braunere63f3082019-07-28 00:22:30 +020058
59 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
Christian Brauner09d1de12020-09-02 12:21:29 +020060 ASSERT_NE(pid, 0);
61 EXPECT_EQ(close(pidfd), 0);
Christian Braunere63f3082019-07-28 00:22:30 +020062 pidfd = -1;
63
64 pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
Christian Brauner09d1de12020-09-02 12:21:29 +020065 ASSERT_GE(pidfd, 0);
Christian Braunere63f3082019-07-28 00:22:30 +020066
67 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
Christian Brauner09d1de12020-09-02 12:21:29 +020068 ASSERT_NE(pid, 0);
69 EXPECT_EQ(close(pidfd), 0);
Christian Braunere63f3082019-07-28 00:22:30 +020070 pidfd = -1;
71
72 pid = sys_clone3(&args);
Christian Braunercd895972020-09-02 12:21:30 +020073 ASSERT_GE(pid, 0);
Christian Braunere63f3082019-07-28 00:22:30 +020074
75 if (pid == 0)
76 exit(EXIT_SUCCESS);
77
78 pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
Christian Brauner09d1de12020-09-02 12:21:29 +020079 ASSERT_GE(pid, 0);
80 ASSERT_EQ(WIFEXITED(info.si_status), true);
81 ASSERT_EQ(WEXITSTATUS(info.si_status), 0);
82 EXPECT_EQ(close(pidfd), 0);
Christian Braunere63f3082019-07-28 00:22:30 +020083
Christian Brauner09d1de12020-09-02 12:21:29 +020084 ASSERT_EQ(info.si_signo, SIGCHLD);
85 ASSERT_EQ(info.si_code, CLD_EXITED);
86 ASSERT_EQ(info.si_pid, parent_tid);
Christian Braunere63f3082019-07-28 00:22:30 +020087}
88
Christian Brauner09d1de12020-09-02 12:21:29 +020089TEST(wait_states)
Christian Braunere63f3082019-07-28 00:22:30 +020090{
Christian Braunere63f3082019-07-28 00:22:30 +020091 int pidfd = -1, status = 0;
92 pid_t parent_tid = -1;
93 struct clone_args args = {
94 .parent_tid = ptr_to_u64(&parent_tid),
95 .pidfd = ptr_to_u64(&pidfd),
96 .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
97 .exit_signal = SIGCHLD,
98 };
99 int ret;
100 pid_t pid;
101 siginfo_t info = {
102 .si_signo = 0,
103 };
104
105 pid = sys_clone3(&args);
Christian Brauner09d1de12020-09-02 12:21:29 +0200106 ASSERT_GE(pid, 0);
Christian Braunere63f3082019-07-28 00:22:30 +0200107
108 if (pid == 0) {
109 kill(getpid(), SIGSTOP);
110 kill(getpid(), SIGSTOP);
111 exit(EXIT_SUCCESS);
112 }
113
Christian Brauner09d1de12020-09-02 12:21:29 +0200114 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
115 ASSERT_EQ(info.si_signo, SIGCHLD);
116 ASSERT_EQ(info.si_code, CLD_STOPPED);
117 ASSERT_EQ(info.si_pid, parent_tid);
Christian Braunere63f3082019-07-28 00:22:30 +0200118
Christian Brauner09d1de12020-09-02 12:21:29 +0200119 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
Christian Braunere63f3082019-07-28 00:22:30 +0200120
Christian Brauner09d1de12020-09-02 12:21:29 +0200121 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0);
122 ASSERT_EQ(info.si_signo, SIGCHLD);
123 ASSERT_EQ(info.si_code, CLD_CONTINUED);
124 ASSERT_EQ(info.si_pid, parent_tid);
Christian Braunere63f3082019-07-28 00:22:30 +0200125
Christian Brauner09d1de12020-09-02 12:21:29 +0200126 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0);
127 ASSERT_EQ(info.si_signo, SIGCHLD);
128 ASSERT_EQ(info.si_code, CLD_STOPPED);
129 ASSERT_EQ(info.si_pid, parent_tid);
Christian Braunere63f3082019-07-28 00:22:30 +0200130
Christian Brauner09d1de12020-09-02 12:21:29 +0200131 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
Christian Braunere63f3082019-07-28 00:22:30 +0200132
Christian Brauner09d1de12020-09-02 12:21:29 +0200133 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
134 ASSERT_EQ(info.si_signo, SIGCHLD);
135 ASSERT_EQ(info.si_code, CLD_KILLED);
136 ASSERT_EQ(info.si_pid, parent_tid);
Christian Braunere63f3082019-07-28 00:22:30 +0200137
Christian Brauner09d1de12020-09-02 12:21:29 +0200138 EXPECT_EQ(close(pidfd), 0);
Christian Braunere63f3082019-07-28 00:22:30 +0200139}
140
Christian Braunercd895972020-09-02 12:21:30 +0200141TEST(wait_nonblock)
142{
143 int pidfd, status = 0;
144 unsigned int flags = 0;
145 pid_t parent_tid = -1;
146 struct clone_args args = {
147 .parent_tid = ptr_to_u64(&parent_tid),
148 .flags = CLONE_PARENT_SETTID,
149 .exit_signal = SIGCHLD,
150 };
151 int ret;
152 pid_t pid;
153 siginfo_t info = {
154 .si_signo = 0,
155 };
156
157 /*
158 * Callers need to see ECHILD with non-blocking pidfds when no child
159 * processes exists.
160 */
161 pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
162 EXPECT_GE(pidfd, 0) {
163 /* pidfd_open() doesn't support PIDFD_NONBLOCK. */
164 ASSERT_EQ(errno, EINVAL);
165 SKIP(return, "Skipping PIDFD_NONBLOCK test");
166 }
167
168 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
169 ASSERT_LT(ret, 0);
170 ASSERT_EQ(errno, ECHILD);
171 EXPECT_EQ(close(pidfd), 0);
172
173 pid = sys_clone3(&args);
174 ASSERT_GE(pid, 0);
175
176 if (pid == 0) {
177 kill(getpid(), SIGSTOP);
178 exit(EXIT_SUCCESS);
179 }
180
181 pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
182 EXPECT_GE(pidfd, 0) {
183 /* pidfd_open() doesn't support PIDFD_NONBLOCK. */
184 ASSERT_EQ(errno, EINVAL);
185 SKIP(return, "Skipping PIDFD_NONBLOCK test");
186 }
187
188 flags = fcntl(pidfd, F_GETFL, 0);
189 ASSERT_GT(flags, 0);
190 ASSERT_GT((flags & O_NONBLOCK), 0);
191
192 /*
193 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
194 * child processes exist but none have exited.
195 */
196 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
197 ASSERT_LT(ret, 0);
198 ASSERT_EQ(errno, EAGAIN);
199
200 /*
201 * Callers need to continue seeing 0 with non-blocking pidfd and
202 * WNOHANG raised explicitly when child processes exist but none have
203 * exited.
204 */
205 ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL);
206 ASSERT_EQ(ret, 0);
207
208 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
209 ASSERT_EQ(info.si_signo, SIGCHLD);
210 ASSERT_EQ(info.si_code, CLD_STOPPED);
211 ASSERT_EQ(info.si_pid, parent_tid);
212
213 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
214
215 ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
216
217 ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
218 ASSERT_EQ(info.si_signo, SIGCHLD);
219 ASSERT_EQ(info.si_code, CLD_EXITED);
220 ASSERT_EQ(info.si_pid, parent_tid);
221
222 EXPECT_EQ(close(pidfd), 0);
223}
224
Christian Brauner09d1de12020-09-02 12:21:29 +0200225TEST_HARNESS_MAIN