1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #define _GNU_SOURCE |
4 | #include <errno.h> |
5 | #include <linux/types.h> |
6 | #include <poll.h> |
7 | #include <signal.h> |
8 | #include <stdbool.h> |
9 | #include <stdio.h> |
10 | #include <stdlib.h> |
11 | #include <string.h> |
12 | #include <syscall.h> |
13 | #include <sys/wait.h> |
14 | #include <unistd.h> |
15 | |
16 | #include "pidfd.h" |
17 | #include "../kselftest.h" |
18 | |
19 | static bool timeout; |
20 | |
21 | static void handle_alarm(int sig) |
22 | { |
23 | timeout = true; |
24 | } |
25 | |
26 | int main(int argc, char **argv) |
27 | { |
28 | struct pollfd fds; |
29 | int iter, nevents; |
30 | int nr_iterations = 10000; |
31 | |
32 | fds.events = POLLIN; |
33 | |
34 | if (argc > 2) |
35 | ksft_exit_fail_msg(msg: "Unexpected command line argument\n" ); |
36 | |
37 | if (argc == 2) { |
38 | nr_iterations = atoi(argv[1]); |
39 | if (nr_iterations <= 0) |
40 | ksft_exit_fail_msg(msg: "invalid input parameter %s\n" , |
41 | argv[1]); |
42 | } |
43 | |
44 | ksft_print_msg(msg: "running pidfd poll test for %d iterations\n" , |
45 | nr_iterations); |
46 | |
47 | for (iter = 0; iter < nr_iterations; iter++) { |
48 | int pidfd; |
49 | int child_pid = fork(); |
50 | |
51 | if (child_pid < 0) { |
52 | if (errno == EAGAIN) { |
53 | iter--; |
54 | continue; |
55 | } |
56 | ksft_exit_fail_msg( |
57 | msg: "%s - failed to fork a child process\n" , |
58 | strerror(errno)); |
59 | } |
60 | |
61 | if (child_pid == 0) { |
62 | /* Child process just sleeps for a min and exits */ |
63 | sleep(60); |
64 | exit(EXIT_SUCCESS); |
65 | } |
66 | |
67 | /* Parent kills the child and waits for its death */ |
68 | pidfd = sys_pidfd_open(pid: child_pid, flags: 0); |
69 | if (pidfd < 0) |
70 | ksft_exit_fail_msg(msg: "%s - pidfd_open failed\n" , |
71 | strerror(errno)); |
72 | |
73 | /* Setup 3 sec alarm - plenty of time */ |
74 | if (signal(SIGALRM, handle_alarm) == SIG_ERR) |
75 | ksft_exit_fail_msg(msg: "%s - signal failed\n" , |
76 | strerror(errno)); |
77 | alarm(3); |
78 | |
79 | /* Send SIGKILL to the child */ |
80 | if (sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0)) |
81 | ksft_exit_fail_msg(msg: "%s - pidfd_send_signal failed\n" , |
82 | strerror(errno)); |
83 | |
84 | /* Wait for the death notification */ |
85 | fds.fd = pidfd; |
86 | nevents = poll(&fds, 1, -1); |
87 | |
88 | /* Check for error conditions */ |
89 | if (nevents < 0) |
90 | ksft_exit_fail_msg(msg: "%s - poll failed\n" , |
91 | strerror(errno)); |
92 | |
93 | if (nevents != 1) |
94 | ksft_exit_fail_msg(msg: "unexpected poll result: %d\n" , |
95 | nevents); |
96 | |
97 | if (!(fds.revents & POLLIN)) |
98 | ksft_exit_fail_msg( |
99 | msg: "unexpected event type received: 0x%x\n" , |
100 | fds.revents); |
101 | |
102 | if (timeout) |
103 | ksft_exit_fail_msg( |
104 | msg: "death notification wait timeout\n" ); |
105 | |
106 | close(pidfd); |
107 | /* Wait for child to prevent zombies */ |
108 | if (waitpid(child_pid, NULL, 0) < 0) |
109 | ksft_exit_fail_msg(msg: "%s - waitpid failed\n" , |
110 | strerror(errno)); |
111 | |
112 | } |
113 | |
114 | ksft_test_result_pass(msg: "pidfd poll test: pass\n" ); |
115 | return ksft_exit_pass(); |
116 | } |
117 | |