]> Git Repo - J-linux.git/blob - tools/testing/selftests/pidfd/pidfd_wait.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / pidfd / pidfd_wait.c
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
This page took 0.039578 seconds and 4 git commands to generate.