Commit | Line | Data |
---|---|---|
e63f3085 CB |
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" | |
09d1de1a | 20 | #include "../kselftest_harness.h" |
e63f3085 CB |
21 | |
22 | #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr))) | |
23 | ||
cd89597b CB |
24 | /* Attempt to de-conflict with the selftests tree. */ |
25 | #ifndef SKIP | |
26 | #define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__) | |
27 | #endif | |
28 | ||
e63f3085 CB |
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 | ||
09d1de1a | 40 | TEST(wait_simple) |
e63f3085 | 41 | { |
e63f3085 CB |
42 | 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); | |
09d1de1a | 57 | ASSERT_GE(pidfd, 0); |
e63f3085 CB |
58 | |
59 | pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); | |
09d1de1a CB |
60 | ASSERT_NE(pid, 0); |
61 | EXPECT_EQ(close(pidfd), 0); | |
e63f3085 CB |
62 | pidfd = -1; |
63 | ||
64 | pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC); | |
09d1de1a | 65 | ASSERT_GE(pidfd, 0); |
e63f3085 CB |
66 | |
67 | pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); | |
09d1de1a CB |
68 | ASSERT_NE(pid, 0); |
69 | EXPECT_EQ(close(pidfd), 0); | |
e63f3085 CB |
70 | pidfd = -1; |
71 | ||
72 | pid = sys_clone3(&args); | |
cd89597b | 73 | ASSERT_GE(pid, 0); |
e63f3085 CB |
74 | |
75 | if (pid == 0) | |
76 | exit(EXIT_SUCCESS); | |
77 | ||
78 | pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL); | |
09d1de1a CB |
79 | 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); | |
83 | ||
84 | ASSERT_EQ(info.si_signo, SIGCHLD); | |
85 | ASSERT_EQ(info.si_code, CLD_EXITED); | |
86 | ASSERT_EQ(info.si_pid, parent_tid); | |
e63f3085 CB |
87 | } |
88 | ||
09d1de1a | 89 | TEST(wait_states) |
e63f3085 | 90 | { |
e63f3085 CB |
91 | 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); | |
09d1de1a | 106 | ASSERT_GE(pid, 0); |
e63f3085 CB |
107 | |
108 | if (pid == 0) { | |
109 | kill(getpid(), SIGSTOP); | |
110 | kill(getpid(), SIGSTOP); | |
111 | exit(EXIT_SUCCESS); | |
112 | } | |
113 | ||
09d1de1a CB |
114 | 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); | |
e63f3085 | 118 | |
09d1de1a | 119 | ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0); |
e63f3085 | 120 | |
09d1de1a CB |
121 | 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); | |
e63f3085 | 125 | |
09d1de1a CB |
126 | 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); | |
e63f3085 | 130 | |
09d1de1a | 131 | ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0); |
e63f3085 | 132 | |
09d1de1a CB |
133 | 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); | |
e63f3085 | 137 | |
09d1de1a | 138 | EXPECT_EQ(close(pidfd), 0); |
e63f3085 CB |
139 | } |
140 | ||
cd89597b CB |
141 | TEST(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 | ||
01361b66 CB |
208 | ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0); |
209 | ||
cd89597b CB |
210 | ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0); |
211 | ASSERT_EQ(info.si_signo, SIGCHLD); | |
212 | ASSERT_EQ(info.si_code, CLD_STOPPED); | |
213 | ASSERT_EQ(info.si_pid, parent_tid); | |
214 | ||
215 | ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0); | |
216 | ||
cd89597b CB |
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 | ||
09d1de1a | 225 | TEST_HARNESS_MAIN |