Merge tag 'thermal-v5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal...
[linux-2.6-microblaze.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.h"
21
22 #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
23
24 static pid_t sys_clone3(struct clone_args *args)
25 {
26         return syscall(__NR_clone3, args, sizeof(struct clone_args));
27 }
28
29 static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
30                       struct rusage *ru)
31 {
32         return syscall(__NR_waitid, which, pid, info, options, ru);
33 }
34
35 static int test_pidfd_wait_simple(void)
36 {
37         const char *test_name = "pidfd wait simple";
38         int pidfd = -1, status = 0;
39         pid_t parent_tid = -1;
40         struct clone_args args = {
41                 .parent_tid = ptr_to_u64(&parent_tid),
42                 .pidfd = ptr_to_u64(&pidfd),
43                 .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
44                 .exit_signal = SIGCHLD,
45         };
46         int ret;
47         pid_t pid;
48         siginfo_t info = {
49                 .si_signo = 0,
50         };
51
52         pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
53         if (pidfd < 0)
54                 ksft_exit_fail_msg("%s test: failed to open /proc/self %s\n",
55                                    test_name, strerror(errno));
56
57         pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
58         if (pid == 0)
59                 ksft_exit_fail_msg(
60                         "%s test: succeeded to wait on invalid pidfd %s\n",
61                         test_name, strerror(errno));
62         close(pidfd);
63         pidfd = -1;
64
65         pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
66         if (pidfd == 0)
67                 ksft_exit_fail_msg("%s test: failed to open /dev/null %s\n",
68                                    test_name, strerror(errno));
69
70         pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
71         if (pid == 0)
72                 ksft_exit_fail_msg(
73                         "%s test: succeeded to wait on invalid pidfd %s\n",
74                         test_name, strerror(errno));
75         close(pidfd);
76         pidfd = -1;
77
78         pid = sys_clone3(&args);
79         if (pid < 0)
80                 ksft_exit_fail_msg("%s test: failed to create new process %s\n",
81                                    test_name, strerror(errno));
82
83         if (pid == 0)
84                 exit(EXIT_SUCCESS);
85
86         pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
87         if (pid < 0)
88                 ksft_exit_fail_msg(
89                         "%s test: failed to wait on process with pid %d and pidfd %d: %s\n",
90                         test_name, parent_tid, pidfd, strerror(errno));
91
92         if (!WIFEXITED(info.si_status) || WEXITSTATUS(info.si_status))
93                 ksft_exit_fail_msg(
94                         "%s test: unexpected status received after waiting on process with pid %d and pidfd %d: %s\n",
95                         test_name, parent_tid, pidfd, strerror(errno));
96         close(pidfd);
97
98         if (info.si_signo != SIGCHLD)
99                 ksft_exit_fail_msg(
100                         "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
101                         test_name, info.si_signo, parent_tid, pidfd,
102                         strerror(errno));
103
104         if (info.si_code != CLD_EXITED)
105                 ksft_exit_fail_msg(
106                         "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
107                         test_name, info.si_code, parent_tid, pidfd,
108                         strerror(errno));
109
110         if (info.si_pid != parent_tid)
111                 ksft_exit_fail_msg(
112                         "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
113                         test_name, info.si_pid, parent_tid, pidfd,
114                         strerror(errno));
115
116         ksft_test_result_pass("%s test: Passed\n", test_name);
117         return 0;
118 }
119
120 static int test_pidfd_wait_states(void)
121 {
122         const char *test_name = "pidfd wait states";
123         int pidfd = -1, status = 0;
124         pid_t parent_tid = -1;
125         struct clone_args args = {
126                 .parent_tid = ptr_to_u64(&parent_tid),
127                 .pidfd = ptr_to_u64(&pidfd),
128                 .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
129                 .exit_signal = SIGCHLD,
130         };
131         int ret;
132         pid_t pid;
133         siginfo_t info = {
134                 .si_signo = 0,
135         };
136
137         pid = sys_clone3(&args);
138         if (pid < 0)
139                 ksft_exit_fail_msg("%s test: failed to create new process %s\n",
140                                    test_name, strerror(errno));
141
142         if (pid == 0) {
143                 kill(getpid(), SIGSTOP);
144                 kill(getpid(), SIGSTOP);
145                 exit(EXIT_SUCCESS);
146         }
147
148         ret = sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL);
149         if (ret < 0)
150                 ksft_exit_fail_msg(
151                         "%s test: failed to wait on WSTOPPED process with pid %d and pidfd %d: %s\n",
152                         test_name, parent_tid, pidfd, strerror(errno));
153
154         if (info.si_signo != SIGCHLD)
155                 ksft_exit_fail_msg(
156                         "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
157                         test_name, info.si_signo, parent_tid, pidfd,
158                         strerror(errno));
159
160         if (info.si_code != CLD_STOPPED)
161                 ksft_exit_fail_msg(
162                         "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
163                         test_name, info.si_code, parent_tid, pidfd,
164                         strerror(errno));
165
166         if (info.si_pid != parent_tid)
167                 ksft_exit_fail_msg(
168                         "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
169                         test_name, info.si_pid, parent_tid, pidfd,
170                         strerror(errno));
171
172         ret = sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0);
173         if (ret < 0)
174                 ksft_exit_fail_msg(
175                         "%s test: failed to send signal to process with pid %d and pidfd %d: %s\n",
176                         test_name, parent_tid, pidfd, strerror(errno));
177
178         ret = sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL);
179         if (ret < 0)
180                 ksft_exit_fail_msg(
181                         "%s test: failed to wait WCONTINUED on process with pid %d and pidfd %d: %s\n",
182                         test_name, parent_tid, pidfd, strerror(errno));
183
184         if (info.si_signo != SIGCHLD)
185                 ksft_exit_fail_msg(
186                         "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
187                         test_name, info.si_signo, parent_tid, pidfd,
188                         strerror(errno));
189
190         if (info.si_code != CLD_CONTINUED)
191                 ksft_exit_fail_msg(
192                         "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
193                         test_name, info.si_code, parent_tid, pidfd,
194                         strerror(errno));
195
196         if (info.si_pid != parent_tid)
197                 ksft_exit_fail_msg(
198                         "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
199                         test_name, info.si_pid, parent_tid, pidfd,
200                         strerror(errno));
201
202         ret = sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL);
203         if (ret < 0)
204                 ksft_exit_fail_msg(
205                         "%s test: failed to wait on WUNTRACED process with pid %d and pidfd %d: %s\n",
206                         test_name, parent_tid, pidfd, strerror(errno));
207
208         if (info.si_signo != SIGCHLD)
209                 ksft_exit_fail_msg(
210                         "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
211                         test_name, info.si_signo, parent_tid, pidfd,
212                         strerror(errno));
213
214         if (info.si_code != CLD_STOPPED)
215                 ksft_exit_fail_msg(
216                         "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
217                         test_name, info.si_code, parent_tid, pidfd,
218                         strerror(errno));
219
220         if (info.si_pid != parent_tid)
221                 ksft_exit_fail_msg(
222                         "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
223                         test_name, info.si_pid, parent_tid, pidfd,
224                         strerror(errno));
225
226         ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
227         if (ret < 0)
228                 ksft_exit_fail_msg(
229                         "%s test: failed to send SIGKILL to process with pid %d and pidfd %d: %s\n",
230                         test_name, parent_tid, pidfd, strerror(errno));
231
232         ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
233         if (ret < 0)
234                 ksft_exit_fail_msg(
235                         "%s test: failed to wait on WEXITED process with pid %d and pidfd %d: %s\n",
236                         test_name, parent_tid, pidfd, strerror(errno));
237
238         if (info.si_signo != SIGCHLD)
239                 ksft_exit_fail_msg(
240                         "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
241                         test_name, info.si_signo, parent_tid, pidfd,
242                         strerror(errno));
243
244         if (info.si_code != CLD_KILLED)
245                 ksft_exit_fail_msg(
246                         "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
247                         test_name, info.si_code, parent_tid, pidfd,
248                         strerror(errno));
249
250         if (info.si_pid != parent_tid)
251                 ksft_exit_fail_msg(
252                         "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
253                         test_name, info.si_pid, parent_tid, pidfd,
254                         strerror(errno));
255
256         close(pidfd);
257
258         ksft_test_result_pass("%s test: Passed\n", test_name);
259         return 0;
260 }
261
262 int main(int argc, char **argv)
263 {
264         ksft_print_header();
265         ksft_set_plan(2);
266
267         test_pidfd_wait_simple();
268         test_pidfd_wait_states();
269
270         return ksft_exit_pass();
271 }