diff options
Diffstat (limited to 'tools/testing/selftests/pidfd/pidfd_poll_test.c')
-rw-r--r-- | tools/testing/selftests/pidfd/pidfd_poll_test.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/tools/testing/selftests/pidfd/pidfd_poll_test.c b/tools/testing/selftests/pidfd/pidfd_poll_test.c new file mode 100644 index 000000000000..4b115444dfe9 --- /dev/null +++ b/tools/testing/selftests/pidfd/pidfd_poll_test.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include <errno.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <poll.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syscall.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "pidfd.h" +#include "../kselftest.h" + +static bool timeout; + +static void handle_alarm(int sig) +{ + timeout = true; +} + +int main(int argc, char **argv) +{ + struct pollfd fds; + int iter, nevents; + int nr_iterations = 10000; + + fds.events = POLLIN; + + if (argc > 2) + ksft_exit_fail_msg("Unexpected command line argument\n"); + + if (argc == 2) { + nr_iterations = atoi(argv[1]); + if (nr_iterations <= 0) + ksft_exit_fail_msg("invalid input parameter %s\n", + argv[1]); + } + + ksft_print_msg("running pidfd poll test for %d iterations\n", + nr_iterations); + + for (iter = 0; iter < nr_iterations; iter++) { + int pidfd; + int child_pid = fork(); + + if (child_pid < 0) { + if (errno == EAGAIN) { + iter--; + continue; + } + ksft_exit_fail_msg( + "%s - failed to fork a child process\n", + strerror(errno)); + } + + if (child_pid == 0) { + /* Child process just sleeps for a min and exits */ + sleep(60); + exit(EXIT_SUCCESS); + } + + /* Parent kills the child and waits for its death */ + pidfd = sys_pidfd_open(child_pid, 0); + if (pidfd < 0) + ksft_exit_fail_msg("%s - pidfd_open failed\n", + strerror(errno)); + + /* Setup 3 sec alarm - plenty of time */ + if (signal(SIGALRM, handle_alarm) == SIG_ERR) + ksft_exit_fail_msg("%s - signal failed\n", + strerror(errno)); + alarm(3); + + /* Send SIGKILL to the child */ + if (sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0)) + ksft_exit_fail_msg("%s - pidfd_send_signal failed\n", + strerror(errno)); + + /* Wait for the death notification */ + fds.fd = pidfd; + nevents = poll(&fds, 1, -1); + + /* Check for error conditions */ + if (nevents < 0) + ksft_exit_fail_msg("%s - poll failed\n", + strerror(errno)); + + if (nevents != 1) + ksft_exit_fail_msg("unexpected poll result: %d\n", + nevents); + + if (!(fds.revents & POLLIN)) + ksft_exit_fail_msg( + "unexpected event type received: 0x%x\n", + fds.revents); + + if (timeout) + ksft_exit_fail_msg( + "death notification wait timeout\n"); + + close(pidfd); + /* Wait for child to prevent zombies */ + if (waitpid(child_pid, NULL, 0) < 0) + ksft_exit_fail_msg("%s - waitpid failed\n", + strerror(errno)); + + } + + ksft_test_result_pass("pidfd poll test: pass\n"); + return ksft_exit_pass(); +} |