Commit | Line | Data |
---|---|---|
575a0ae9 CB |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | ||
3 | #define _GNU_SOURCE | |
4 | #include <errno.h> | |
5 | #include <fcntl.h> | |
6 | #include <linux/types.h> | |
740378dc | 7 | #include <pthread.h> |
575a0ae9 CB |
8 | #include <sched.h> |
9 | #include <signal.h> | |
10 | #include <stdio.h> | |
bb91c0ca | 11 | #include <stdbool.h> |
575a0ae9 CB |
12 | #include <stdlib.h> |
13 | #include <string.h> | |
14 | #include <syscall.h> | |
740378dc JFG |
15 | #include <sys/epoll.h> |
16 | #include <sys/mman.h> | |
575a0ae9 CB |
17 | #include <sys/mount.h> |
18 | #include <sys/wait.h> | |
740378dc | 19 | #include <time.h> |
575a0ae9 CB |
20 | #include <unistd.h> |
21 | ||
172bb24a | 22 | #include "pidfd.h" |
575a0ae9 CB |
23 | #include "../kselftest.h" |
24 | ||
740378dc JFG |
25 | #define str(s) _str(s) |
26 | #define _str(s) #s | |
27 | #define CHILD_THREAD_MIN_WAIT 3 /* seconds */ | |
28 | ||
29 | #define MAX_EVENTS 5 | |
740378dc | 30 | |
bb91c0ca PB |
31 | static bool have_pidfd_send_signal; |
32 | ||
740378dc JFG |
33 | static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *)) |
34 | { | |
35 | size_t stack_size = 1024; | |
36 | char *stack[1024] = { 0 }; | |
37 | ||
38 | #ifdef __ia64__ | |
39 | return __clone2(fn, stack, stack_size, flags | SIGCHLD, NULL, pidfd); | |
40 | #else | |
41 | return clone(fn, stack + stack_size, flags | SIGCHLD, NULL, pidfd); | |
42 | #endif | |
43 | } | |
44 | ||
575a0ae9 CB |
45 | static int signal_received; |
46 | ||
47 | static void set_signal_received_on_sigusr1(int sig) | |
48 | { | |
49 | if (sig == SIGUSR1) | |
50 | signal_received = 1; | |
51 | } | |
52 | ||
53 | /* | |
54 | * Straightforward test to see whether pidfd_send_signal() works is to send | |
55 | * a signal to ourself. | |
56 | */ | |
57 | static int test_pidfd_send_signal_simple_success(void) | |
58 | { | |
59 | int pidfd, ret; | |
60 | const char *test_name = "pidfd_send_signal send SIGUSR1"; | |
61 | ||
bb91c0ca PB |
62 | if (!have_pidfd_send_signal) { |
63 | ksft_test_result_skip( | |
64 | "%s test: pidfd_send_signal() syscall not supported\n", | |
65 | test_name); | |
66 | return 0; | |
67 | } | |
68 | ||
575a0ae9 CB |
69 | pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); |
70 | if (pidfd < 0) | |
71 | ksft_exit_fail_msg( | |
72 | "%s test: Failed to open process file descriptor\n", | |
73 | test_name); | |
74 | ||
75 | signal(SIGUSR1, set_signal_received_on_sigusr1); | |
76 | ||
77 | ret = sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0); | |
78 | close(pidfd); | |
79 | if (ret < 0) | |
80 | ksft_exit_fail_msg("%s test: Failed to send signal\n", | |
81 | test_name); | |
82 | ||
83 | if (signal_received != 1) | |
84 | ksft_exit_fail_msg("%s test: Failed to receive signal\n", | |
85 | test_name); | |
86 | ||
87 | signal_received = 0; | |
88 | ksft_test_result_pass("%s test: Sent signal\n", test_name); | |
89 | return 0; | |
90 | } | |
91 | ||
575a0ae9 CB |
92 | static int test_pidfd_send_signal_exited_fail(void) |
93 | { | |
94 | int pidfd, ret, saved_errno; | |
95 | char buf[256]; | |
96 | pid_t pid; | |
97 | const char *test_name = "pidfd_send_signal signal exited process"; | |
98 | ||
bb91c0ca PB |
99 | if (!have_pidfd_send_signal) { |
100 | ksft_test_result_skip( | |
101 | "%s test: pidfd_send_signal() syscall not supported\n", | |
102 | test_name); | |
103 | return 0; | |
104 | } | |
105 | ||
575a0ae9 CB |
106 | pid = fork(); |
107 | if (pid < 0) | |
108 | ksft_exit_fail_msg("%s test: Failed to create new process\n", | |
109 | test_name); | |
110 | ||
111 | if (pid == 0) | |
112 | _exit(EXIT_SUCCESS); | |
113 | ||
114 | snprintf(buf, sizeof(buf), "/proc/%d", pid); | |
115 | ||
116 | pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); | |
117 | ||
118 | (void)wait_for_pid(pid); | |
119 | ||
120 | if (pidfd < 0) | |
121 | ksft_exit_fail_msg( | |
122 | "%s test: Failed to open process file descriptor\n", | |
123 | test_name); | |
124 | ||
125 | ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); | |
126 | saved_errno = errno; | |
127 | close(pidfd); | |
128 | if (ret == 0) | |
129 | ksft_exit_fail_msg( | |
130 | "%s test: Managed to send signal to process even though it should have failed\n", | |
131 | test_name); | |
132 | ||
133 | if (saved_errno != ESRCH) | |
134 | ksft_exit_fail_msg( | |
135 | "%s test: Expected to receive ESRCH as errno value but received %d instead\n", | |
136 | test_name, saved_errno); | |
137 | ||
138 | ksft_test_result_pass("%s test: Failed to send signal as expected\n", | |
139 | test_name); | |
140 | return 0; | |
141 | } | |
142 | ||
575a0ae9 CB |
143 | /* |
144 | * Maximum number of cycles we allow. This is equivalent to PID_MAX_DEFAULT. | |
145 | * If users set a higher limit or we have cycled PIDFD_MAX_DEFAULT number of | |
146 | * times then we skip the test to not go into an infinite loop or block for a | |
147 | * long time. | |
148 | */ | |
149 | #define PIDFD_MAX_DEFAULT 0x8000 | |
150 | ||
575a0ae9 CB |
151 | static int test_pidfd_send_signal_recycled_pid_fail(void) |
152 | { | |
153 | int i, ret; | |
154 | pid_t pid1; | |
155 | const char *test_name = "pidfd_send_signal signal recycled pid"; | |
156 | ||
bb91c0ca PB |
157 | if (!have_pidfd_send_signal) { |
158 | ksft_test_result_skip( | |
159 | "%s test: pidfd_send_signal() syscall not supported\n", | |
160 | test_name); | |
161 | return 0; | |
162 | } | |
163 | ||
575a0ae9 | 164 | ret = unshare(CLONE_NEWPID); |
05790fd7 PB |
165 | if (ret < 0) { |
166 | if (errno == EPERM) { | |
167 | ksft_test_result_skip("%s test: Unsharing pid namespace not permitted\n", | |
168 | test_name); | |
169 | return 0; | |
170 | } | |
575a0ae9 CB |
171 | ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n", |
172 | test_name); | |
05790fd7 | 173 | } |
575a0ae9 CB |
174 | |
175 | ret = unshare(CLONE_NEWNS); | |
05790fd7 PB |
176 | if (ret < 0) { |
177 | if (errno == EPERM) { | |
178 | ksft_test_result_skip("%s test: Unsharing mount namespace not permitted\n", | |
179 | test_name); | |
180 | return 0; | |
181 | } | |
182 | ksft_exit_fail_msg("%s test: Failed to unshare mount namespace\n", | |
183 | test_name); | |
184 | } | |
575a0ae9 CB |
185 | |
186 | ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); | |
187 | if (ret < 0) | |
188 | ksft_exit_fail_msg("%s test: Failed to remount / private\n", | |
189 | test_name); | |
190 | ||
191 | /* pid 1 in new pid namespace */ | |
192 | pid1 = fork(); | |
193 | if (pid1 < 0) | |
194 | ksft_exit_fail_msg("%s test: Failed to create new process\n", | |
195 | test_name); | |
196 | ||
197 | if (pid1 == 0) { | |
198 | char buf[256]; | |
199 | pid_t pid2; | |
200 | int pidfd = -1; | |
201 | ||
202 | (void)umount2("/proc", MNT_DETACH); | |
203 | ret = mount("proc", "/proc", "proc", 0, NULL); | |
204 | if (ret < 0) | |
205 | _exit(PIDFD_ERROR); | |
206 | ||
207 | /* grab pid PID_RECYCLE */ | |
208 | for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { | |
209 | pid2 = fork(); | |
210 | if (pid2 < 0) | |
211 | _exit(PIDFD_ERROR); | |
212 | ||
213 | if (pid2 == 0) | |
214 | _exit(PIDFD_PASS); | |
215 | ||
216 | if (pid2 == PID_RECYCLE) { | |
217 | snprintf(buf, sizeof(buf), "/proc/%d", pid2); | |
218 | ksft_print_msg("pid to recycle is %d\n", pid2); | |
219 | pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); | |
220 | } | |
221 | ||
222 | if (wait_for_pid(pid2)) | |
223 | _exit(PIDFD_ERROR); | |
224 | ||
225 | if (pid2 >= PID_RECYCLE) | |
226 | break; | |
227 | } | |
228 | ||
229 | /* | |
230 | * We want to be as predictable as we can so if we haven't been | |
231 | * able to grab pid PID_RECYCLE skip the test. | |
232 | */ | |
233 | if (pid2 != PID_RECYCLE) { | |
234 | /* skip test */ | |
235 | close(pidfd); | |
236 | _exit(PIDFD_SKIP); | |
237 | } | |
238 | ||
239 | if (pidfd < 0) | |
240 | _exit(PIDFD_ERROR); | |
241 | ||
242 | for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { | |
243 | char c; | |
244 | int pipe_fds[2]; | |
245 | pid_t recycled_pid; | |
246 | int child_ret = PIDFD_PASS; | |
247 | ||
248 | ret = pipe2(pipe_fds, O_CLOEXEC); | |
249 | if (ret < 0) | |
250 | _exit(PIDFD_ERROR); | |
251 | ||
252 | recycled_pid = fork(); | |
253 | if (recycled_pid < 0) | |
254 | _exit(PIDFD_ERROR); | |
255 | ||
256 | if (recycled_pid == 0) { | |
257 | close(pipe_fds[1]); | |
258 | (void)read(pipe_fds[0], &c, 1); | |
259 | close(pipe_fds[0]); | |
260 | ||
261 | _exit(PIDFD_PASS); | |
262 | } | |
263 | ||
264 | /* | |
265 | * Stop the child so we can inspect whether we have | |
266 | * recycled pid PID_RECYCLE. | |
267 | */ | |
268 | close(pipe_fds[0]); | |
269 | ret = kill(recycled_pid, SIGSTOP); | |
270 | close(pipe_fds[1]); | |
271 | if (ret) { | |
272 | (void)wait_for_pid(recycled_pid); | |
273 | _exit(PIDFD_ERROR); | |
274 | } | |
275 | ||
276 | /* | |
277 | * We have recycled the pid. Try to signal it. This | |
278 | * needs to fail since this is a different process than | |
279 | * the one the pidfd refers to. | |
280 | */ | |
281 | if (recycled_pid == PID_RECYCLE) { | |
282 | ret = sys_pidfd_send_signal(pidfd, SIGCONT, | |
283 | NULL, 0); | |
284 | if (ret && errno == ESRCH) | |
285 | child_ret = PIDFD_XFAIL; | |
286 | else | |
287 | child_ret = PIDFD_FAIL; | |
288 | } | |
289 | ||
290 | /* let the process move on */ | |
291 | ret = kill(recycled_pid, SIGCONT); | |
292 | if (ret) | |
293 | (void)kill(recycled_pid, SIGKILL); | |
294 | ||
295 | if (wait_for_pid(recycled_pid)) | |
296 | _exit(PIDFD_ERROR); | |
297 | ||
298 | switch (child_ret) { | |
299 | case PIDFD_FAIL: | |
300 | /* fallthrough */ | |
301 | case PIDFD_XFAIL: | |
302 | _exit(child_ret); | |
303 | case PIDFD_PASS: | |
304 | break; | |
305 | default: | |
306 | /* not reached */ | |
307 | _exit(PIDFD_ERROR); | |
308 | } | |
309 | ||
310 | /* | |
311 | * If the user set a custom pid_max limit we could be | |
312 | * in the millions. | |
313 | * Skip the test in this case. | |
314 | */ | |
315 | if (recycled_pid > PIDFD_MAX_DEFAULT) | |
316 | _exit(PIDFD_SKIP); | |
317 | } | |
318 | ||
319 | /* failed to recycle pid */ | |
320 | _exit(PIDFD_SKIP); | |
321 | } | |
322 | ||
323 | ret = wait_for_pid(pid1); | |
324 | switch (ret) { | |
325 | case PIDFD_FAIL: | |
326 | ksft_exit_fail_msg( | |
327 | "%s test: Managed to signal recycled pid %d\n", | |
328 | test_name, PID_RECYCLE); | |
329 | case PIDFD_PASS: | |
330 | ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n", | |
331 | test_name, PID_RECYCLE); | |
332 | case PIDFD_SKIP: | |
0b18fed9 | 333 | ksft_test_result_skip("%s test: Skipping test\n", test_name); |
575a0ae9 CB |
334 | ret = 0; |
335 | break; | |
336 | case PIDFD_XFAIL: | |
337 | ksft_test_result_pass( | |
338 | "%s test: Failed to signal recycled pid as expected\n", | |
339 | test_name); | |
340 | ret = 0; | |
341 | break; | |
342 | default /* PIDFD_ERROR */: | |
343 | ksft_exit_fail_msg("%s test: Error while running tests\n", | |
344 | test_name); | |
345 | } | |
346 | ||
347 | return ret; | |
348 | } | |
349 | ||
350 | static int test_pidfd_send_signal_syscall_support(void) | |
351 | { | |
352 | int pidfd, ret; | |
353 | const char *test_name = "pidfd_send_signal check for support"; | |
354 | ||
355 | pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); | |
356 | if (pidfd < 0) | |
357 | ksft_exit_fail_msg( | |
358 | "%s test: Failed to open process file descriptor\n", | |
359 | test_name); | |
360 | ||
361 | ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); | |
362 | if (ret < 0) { | |
bb91c0ca PB |
363 | if (errno == ENOSYS) { |
364 | ksft_test_result_skip( | |
3884ae44 | 365 | "%s test: pidfd_send_signal() syscall not supported\n", |
575a0ae9 | 366 | test_name); |
bb91c0ca PB |
367 | return 0; |
368 | } | |
575a0ae9 CB |
369 | ksft_exit_fail_msg("%s test: Failed to send signal\n", |
370 | test_name); | |
371 | } | |
372 | ||
bb91c0ca | 373 | have_pidfd_send_signal = true; |
575a0ae9 CB |
374 | close(pidfd); |
375 | ksft_test_result_pass( | |
376 | "%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n", | |
377 | test_name); | |
378 | return 0; | |
379 | } | |
380 | ||
740378dc JFG |
381 | static void *test_pidfd_poll_exec_thread(void *priv) |
382 | { | |
383 | ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", | |
384 | getpid(), syscall(SYS_gettid)); | |
385 | ksft_print_msg("Child Thread: doing exec of sleep\n"); | |
386 | ||
387 | execl("/bin/sleep", "sleep", str(CHILD_THREAD_MIN_WAIT), (char *)NULL); | |
388 | ||
389 | ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", | |
390 | getpid(), syscall(SYS_gettid)); | |
391 | return NULL; | |
392 | } | |
393 | ||
394 | static void poll_pidfd(const char *test_name, int pidfd) | |
395 | { | |
396 | int c; | |
397 | int epoll_fd = epoll_create1(EPOLL_CLOEXEC); | |
398 | struct epoll_event event, events[MAX_EVENTS]; | |
399 | ||
400 | if (epoll_fd == -1) | |
401 | ksft_exit_fail_msg("%s test: Failed to create epoll file descriptor " | |
402 | "(errno %d)\n", | |
403 | test_name, errno); | |
404 | ||
405 | event.events = EPOLLIN; | |
406 | event.data.fd = pidfd; | |
407 | ||
408 | if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pidfd, &event)) { | |
409 | ksft_exit_fail_msg("%s test: Failed to add epoll file descriptor " | |
410 | "(errno %d)\n", | |
411 | test_name, errno); | |
412 | } | |
413 | ||
414 | c = epoll_wait(epoll_fd, events, MAX_EVENTS, 5000); | |
415 | if (c != 1 || !(events[0].events & EPOLLIN)) | |
416 | ksft_exit_fail_msg("%s test: Unexpected epoll_wait result (c=%d, events=%x) ", | |
417 | "(errno %d)\n", | |
418 | test_name, c, events[0].events, errno); | |
419 | ||
420 | close(epoll_fd); | |
421 | return; | |
422 | ||
423 | } | |
424 | ||
425 | static int child_poll_exec_test(void *args) | |
426 | { | |
427 | pthread_t t1; | |
428 | ||
429 | ksft_print_msg("Child (pidfd): starting. pid %d tid %d\n", getpid(), | |
430 | syscall(SYS_gettid)); | |
431 | pthread_create(&t1, NULL, test_pidfd_poll_exec_thread, NULL); | |
432 | /* | |
433 | * Exec in the non-leader thread will destroy the leader immediately. | |
434 | * If the wait in the parent returns too soon, the test fails. | |
435 | */ | |
436 | while (1) | |
437 | sleep(1); | |
438 | } | |
439 | ||
440 | static void test_pidfd_poll_exec(int use_waitpid) | |
441 | { | |
442 | int pid, pidfd = 0; | |
443 | int status, ret; | |
444 | pthread_t t1; | |
445 | time_t prog_start = time(NULL); | |
446 | const char *test_name = "pidfd_poll check for premature notification on child thread exec"; | |
447 | ||
448 | ksft_print_msg("Parent: pid: %d\n", getpid()); | |
449 | pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_exec_test); | |
450 | if (pid < 0) | |
451 | ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", | |
452 | test_name, pid, errno); | |
453 | ||
454 | ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); | |
455 | ||
456 | if (use_waitpid) { | |
457 | ret = waitpid(pid, &status, 0); | |
458 | if (ret == -1) | |
459 | ksft_print_msg("Parent: error\n"); | |
460 | ||
461 | if (ret == pid) | |
462 | ksft_print_msg("Parent: Child process waited for.\n"); | |
463 | } else { | |
464 | poll_pidfd(test_name, pidfd); | |
465 | } | |
466 | ||
467 | time_t prog_time = time(NULL) - prog_start; | |
468 | ||
469 | ksft_print_msg("Time waited for child: %lu\n", prog_time); | |
470 | ||
471 | close(pidfd); | |
472 | ||
473 | if (prog_time < CHILD_THREAD_MIN_WAIT || prog_time > CHILD_THREAD_MIN_WAIT + 2) | |
474 | ksft_exit_fail_msg("%s test: Failed\n", test_name); | |
475 | else | |
476 | ksft_test_result_pass("%s test: Passed\n", test_name); | |
477 | } | |
478 | ||
479 | static void *test_pidfd_poll_leader_exit_thread(void *priv) | |
480 | { | |
481 | ksft_print_msg("Child Thread: starting. pid %d tid %d ; and sleeping\n", | |
482 | getpid(), syscall(SYS_gettid)); | |
483 | sleep(CHILD_THREAD_MIN_WAIT); | |
484 | ksft_print_msg("Child Thread: DONE. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); | |
485 | return NULL; | |
486 | } | |
487 | ||
488 | static time_t *child_exit_secs; | |
489 | static int child_poll_leader_exit_test(void *args) | |
490 | { | |
491 | pthread_t t1, t2; | |
492 | ||
493 | ksft_print_msg("Child: starting. pid %d tid %d\n", getpid(), syscall(SYS_gettid)); | |
494 | pthread_create(&t1, NULL, test_pidfd_poll_leader_exit_thread, NULL); | |
495 | pthread_create(&t2, NULL, test_pidfd_poll_leader_exit_thread, NULL); | |
496 | ||
497 | /* | |
498 | * glibc exit calls exit_group syscall, so explicity call exit only | |
499 | * so that only the group leader exits, leaving the threads alone. | |
500 | */ | |
501 | *child_exit_secs = time(NULL); | |
502 | syscall(SYS_exit, 0); | |
503 | } | |
504 | ||
505 | static void test_pidfd_poll_leader_exit(int use_waitpid) | |
506 | { | |
507 | int pid, pidfd = 0; | |
508 | int status, ret; | |
509 | time_t prog_start = time(NULL); | |
510 | const char *test_name = "pidfd_poll check for premature notification on non-empty" | |
511 | "group leader exit"; | |
512 | ||
513 | child_exit_secs = mmap(NULL, sizeof *child_exit_secs, PROT_READ | PROT_WRITE, | |
514 | MAP_SHARED | MAP_ANONYMOUS, -1, 0); | |
515 | ||
516 | if (child_exit_secs == MAP_FAILED) | |
517 | ksft_exit_fail_msg("%s test: mmap failed (errno %d)\n", | |
518 | test_name, errno); | |
519 | ||
520 | ksft_print_msg("Parent: pid: %d\n", getpid()); | |
521 | pid = pidfd_clone(CLONE_PIDFD, &pidfd, child_poll_leader_exit_test); | |
522 | if (pid < 0) | |
523 | ksft_exit_fail_msg("%s test: pidfd_clone failed (ret %d, errno %d)\n", | |
524 | test_name, pid, errno); | |
525 | ||
526 | ksft_print_msg("Parent: Waiting for Child (%d) to complete.\n", pid); | |
527 | ||
528 | if (use_waitpid) { | |
529 | ret = waitpid(pid, &status, 0); | |
530 | if (ret == -1) | |
531 | ksft_print_msg("Parent: error\n"); | |
532 | } else { | |
533 | /* | |
534 | * This sleep tests for the case where if the child exits, and is in | |
535 | * EXIT_ZOMBIE, but the thread group leader is non-empty, then the poll | |
536 | * doesn't prematurely return even though there are active threads | |
537 | */ | |
538 | sleep(1); | |
539 | poll_pidfd(test_name, pidfd); | |
540 | } | |
541 | ||
542 | if (ret == pid) | |
543 | ksft_print_msg("Parent: Child process waited for.\n"); | |
544 | ||
545 | time_t since_child_exit = time(NULL) - *child_exit_secs; | |
546 | ||
547 | ksft_print_msg("Time since child exit: %lu\n", since_child_exit); | |
548 | ||
549 | close(pidfd); | |
550 | ||
551 | if (since_child_exit < CHILD_THREAD_MIN_WAIT || | |
552 | since_child_exit > CHILD_THREAD_MIN_WAIT + 2) | |
553 | ksft_exit_fail_msg("%s test: Failed\n", test_name); | |
554 | else | |
555 | ksft_test_result_pass("%s test: Passed\n", test_name); | |
556 | } | |
557 | ||
575a0ae9 CB |
558 | int main(int argc, char **argv) |
559 | { | |
560 | ksft_print_header(); | |
bb91c0ca | 561 | ksft_set_plan(8); |
575a0ae9 | 562 | |
740378dc JFG |
563 | test_pidfd_poll_exec(0); |
564 | test_pidfd_poll_exec(1); | |
565 | test_pidfd_poll_leader_exit(0); | |
566 | test_pidfd_poll_leader_exit(1); | |
575a0ae9 CB |
567 | test_pidfd_send_signal_syscall_support(); |
568 | test_pidfd_send_signal_simple_success(); | |
569 | test_pidfd_send_signal_exited_fail(); | |
570 | test_pidfd_send_signal_recycled_pid_fail(); | |
571 | ||
572 | return ksft_exit_pass(); | |
573 | } |