162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#define _GNU_SOURCE
462306a36Sopenharmony_ci#include <errno.h>
562306a36Sopenharmony_ci#include <linux/types.h>
662306a36Sopenharmony_ci#include <poll.h>
762306a36Sopenharmony_ci#include <signal.h>
862306a36Sopenharmony_ci#include <stdbool.h>
962306a36Sopenharmony_ci#include <stdio.h>
1062306a36Sopenharmony_ci#include <stdlib.h>
1162306a36Sopenharmony_ci#include <string.h>
1262306a36Sopenharmony_ci#include <syscall.h>
1362306a36Sopenharmony_ci#include <sys/wait.h>
1462306a36Sopenharmony_ci#include <unistd.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "pidfd.h"
1762306a36Sopenharmony_ci#include "../kselftest.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic bool timeout;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic void handle_alarm(int sig)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	timeout = true;
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciint main(int argc, char **argv)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct pollfd fds;
2962306a36Sopenharmony_ci	int iter, nevents;
3062306a36Sopenharmony_ci	int nr_iterations = 10000;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	fds.events = POLLIN;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (argc > 2)
3562306a36Sopenharmony_ci		ksft_exit_fail_msg("Unexpected command line argument\n");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (argc == 2) {
3862306a36Sopenharmony_ci		nr_iterations = atoi(argv[1]);
3962306a36Sopenharmony_ci		if (nr_iterations <= 0)
4062306a36Sopenharmony_ci			ksft_exit_fail_msg("invalid input parameter %s\n",
4162306a36Sopenharmony_ci					argv[1]);
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	ksft_print_msg("running pidfd poll test for %d iterations\n",
4562306a36Sopenharmony_ci		nr_iterations);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	for (iter = 0; iter < nr_iterations; iter++) {
4862306a36Sopenharmony_ci		int pidfd;
4962306a36Sopenharmony_ci		int child_pid = fork();
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		if (child_pid < 0) {
5262306a36Sopenharmony_ci			if (errno == EAGAIN) {
5362306a36Sopenharmony_ci				iter--;
5462306a36Sopenharmony_ci				continue;
5562306a36Sopenharmony_ci			}
5662306a36Sopenharmony_ci			ksft_exit_fail_msg(
5762306a36Sopenharmony_ci				"%s - failed to fork a child process\n",
5862306a36Sopenharmony_ci				strerror(errno));
5962306a36Sopenharmony_ci		}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		if (child_pid == 0) {
6262306a36Sopenharmony_ci			/* Child process just sleeps for a min and exits */
6362306a36Sopenharmony_ci			sleep(60);
6462306a36Sopenharmony_ci			exit(EXIT_SUCCESS);
6562306a36Sopenharmony_ci		}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		/* Parent kills the child and waits for its death */
6862306a36Sopenharmony_ci		pidfd = sys_pidfd_open(child_pid, 0);
6962306a36Sopenharmony_ci		if (pidfd < 0)
7062306a36Sopenharmony_ci			ksft_exit_fail_msg("%s - pidfd_open failed\n",
7162306a36Sopenharmony_ci					strerror(errno));
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		/* Setup 3 sec alarm - plenty of time */
7462306a36Sopenharmony_ci		if (signal(SIGALRM, handle_alarm) == SIG_ERR)
7562306a36Sopenharmony_ci			ksft_exit_fail_msg("%s - signal failed\n",
7662306a36Sopenharmony_ci					strerror(errno));
7762306a36Sopenharmony_ci		alarm(3);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		/* Send SIGKILL to the child */
8062306a36Sopenharmony_ci		if (sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0))
8162306a36Sopenharmony_ci			ksft_exit_fail_msg("%s - pidfd_send_signal failed\n",
8262306a36Sopenharmony_ci					strerror(errno));
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		/* Wait for the death notification */
8562306a36Sopenharmony_ci		fds.fd = pidfd;
8662306a36Sopenharmony_ci		nevents = poll(&fds, 1, -1);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci		/* Check for error conditions */
8962306a36Sopenharmony_ci		if (nevents < 0)
9062306a36Sopenharmony_ci			ksft_exit_fail_msg("%s - poll failed\n",
9162306a36Sopenharmony_ci					strerror(errno));
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		if (nevents != 1)
9462306a36Sopenharmony_ci			ksft_exit_fail_msg("unexpected poll result: %d\n",
9562306a36Sopenharmony_ci					nevents);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci		if (!(fds.revents & POLLIN))
9862306a36Sopenharmony_ci			ksft_exit_fail_msg(
9962306a36Sopenharmony_ci				"unexpected event type received: 0x%x\n",
10062306a36Sopenharmony_ci				fds.revents);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		if (timeout)
10362306a36Sopenharmony_ci			ksft_exit_fail_msg(
10462306a36Sopenharmony_ci				"death notification wait timeout\n");
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		close(pidfd);
10762306a36Sopenharmony_ci		/* Wait for child to prevent zombies */
10862306a36Sopenharmony_ci		if (waitpid(child_pid, NULL, 0) < 0)
10962306a36Sopenharmony_ci			ksft_exit_fail_msg("%s - waitpid failed\n",
11062306a36Sopenharmony_ci					strerror(errno));
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	ksft_test_result_pass("pidfd poll test: pass\n");
11562306a36Sopenharmony_ci	return ksft_exit_pass();
11662306a36Sopenharmony_ci}
117