162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#define _GNU_SOURCE
462306a36Sopenharmony_ci#include <errno.h>
562306a36Sopenharmony_ci#include <linux/sched.h>
662306a36Sopenharmony_ci#include <linux/types.h>
762306a36Sopenharmony_ci#include <signal.h>
862306a36Sopenharmony_ci#include <stdint.h>
962306a36Sopenharmony_ci#include <stdio.h>
1062306a36Sopenharmony_ci#include <stdlib.h>
1162306a36Sopenharmony_ci#include <sched.h>
1262306a36Sopenharmony_ci#include <string.h>
1362306a36Sopenharmony_ci#include <sys/resource.h>
1462306a36Sopenharmony_ci#include <sys/time.h>
1562306a36Sopenharmony_ci#include <sys/types.h>
1662306a36Sopenharmony_ci#include <sys/wait.h>
1762306a36Sopenharmony_ci#include <unistd.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "pidfd.h"
2062306a36Sopenharmony_ci#include "../kselftest_harness.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Attempt to de-conflict with the selftests tree. */
2562306a36Sopenharmony_ci#ifndef SKIP
2662306a36Sopenharmony_ci#define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)
2762306a36Sopenharmony_ci#endif
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic pid_t sys_clone3(struct clone_args *args)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	return syscall(__NR_clone3, args, sizeof(struct clone_args));
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
3562306a36Sopenharmony_ci		      struct rusage *ru)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	return syscall(__NR_waitid, which, pid, info, options, ru);
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciTEST(wait_simple)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	int pidfd = -1;
4362306a36Sopenharmony_ci	pid_t parent_tid = -1;
4462306a36Sopenharmony_ci	struct clone_args args = {
4562306a36Sopenharmony_ci		.parent_tid = ptr_to_u64(&parent_tid),
4662306a36Sopenharmony_ci		.pidfd = ptr_to_u64(&pidfd),
4762306a36Sopenharmony_ci		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
4862306a36Sopenharmony_ci		.exit_signal = SIGCHLD,
4962306a36Sopenharmony_ci	};
5062306a36Sopenharmony_ci	pid_t pid;
5162306a36Sopenharmony_ci	siginfo_t info = {
5262306a36Sopenharmony_ci		.si_signo = 0,
5362306a36Sopenharmony_ci	};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
5662306a36Sopenharmony_ci	ASSERT_GE(pidfd, 0);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
5962306a36Sopenharmony_ci	ASSERT_NE(pid, 0);
6062306a36Sopenharmony_ci	EXPECT_EQ(close(pidfd), 0);
6162306a36Sopenharmony_ci	pidfd = -1;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
6462306a36Sopenharmony_ci	ASSERT_GE(pidfd, 0);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
6762306a36Sopenharmony_ci	ASSERT_NE(pid, 0);
6862306a36Sopenharmony_ci	EXPECT_EQ(close(pidfd), 0);
6962306a36Sopenharmony_ci	pidfd = -1;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	pid = sys_clone3(&args);
7262306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (pid == 0)
7562306a36Sopenharmony_ci		exit(EXIT_SUCCESS);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
7862306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
7962306a36Sopenharmony_ci	ASSERT_EQ(WIFEXITED(info.si_status), true);
8062306a36Sopenharmony_ci	ASSERT_EQ(WEXITSTATUS(info.si_status), 0);
8162306a36Sopenharmony_ci	EXPECT_EQ(close(pidfd), 0);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	ASSERT_EQ(info.si_signo, SIGCHLD);
8462306a36Sopenharmony_ci	ASSERT_EQ(info.si_code, CLD_EXITED);
8562306a36Sopenharmony_ci	ASSERT_EQ(info.si_pid, parent_tid);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciTEST(wait_states)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	int pidfd = -1;
9162306a36Sopenharmony_ci	pid_t parent_tid = -1;
9262306a36Sopenharmony_ci	struct clone_args args = {
9362306a36Sopenharmony_ci		.parent_tid = ptr_to_u64(&parent_tid),
9462306a36Sopenharmony_ci		.pidfd = ptr_to_u64(&pidfd),
9562306a36Sopenharmony_ci		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
9662306a36Sopenharmony_ci		.exit_signal = SIGCHLD,
9762306a36Sopenharmony_ci	};
9862306a36Sopenharmony_ci	int pfd[2];
9962306a36Sopenharmony_ci	pid_t pid;
10062306a36Sopenharmony_ci	siginfo_t info = {
10162306a36Sopenharmony_ci		.si_signo = 0,
10262306a36Sopenharmony_ci	};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	ASSERT_EQ(pipe(pfd), 0);
10562306a36Sopenharmony_ci	pid = sys_clone3(&args);
10662306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (pid == 0) {
10962306a36Sopenharmony_ci		char buf[2];
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		close(pfd[1]);
11262306a36Sopenharmony_ci		kill(getpid(), SIGSTOP);
11362306a36Sopenharmony_ci		ASSERT_EQ(read(pfd[0], buf, 1), 1);
11462306a36Sopenharmony_ci		close(pfd[0]);
11562306a36Sopenharmony_ci		kill(getpid(), SIGSTOP);
11662306a36Sopenharmony_ci		exit(EXIT_SUCCESS);
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	close(pfd[0]);
12062306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
12162306a36Sopenharmony_ci	ASSERT_EQ(info.si_signo, SIGCHLD);
12262306a36Sopenharmony_ci	ASSERT_EQ(info.si_code, CLD_STOPPED);
12362306a36Sopenharmony_ci	ASSERT_EQ(info.si_pid, parent_tid);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0);
12862306a36Sopenharmony_ci	ASSERT_EQ(write(pfd[1], "C", 1), 1);
12962306a36Sopenharmony_ci	close(pfd[1]);
13062306a36Sopenharmony_ci	ASSERT_EQ(info.si_signo, SIGCHLD);
13162306a36Sopenharmony_ci	ASSERT_EQ(info.si_code, CLD_CONTINUED);
13262306a36Sopenharmony_ci	ASSERT_EQ(info.si_pid, parent_tid);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0);
13562306a36Sopenharmony_ci	ASSERT_EQ(info.si_signo, SIGCHLD);
13662306a36Sopenharmony_ci	ASSERT_EQ(info.si_code, CLD_STOPPED);
13762306a36Sopenharmony_ci	ASSERT_EQ(info.si_pid, parent_tid);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
14262306a36Sopenharmony_ci	ASSERT_EQ(info.si_signo, SIGCHLD);
14362306a36Sopenharmony_ci	ASSERT_EQ(info.si_code, CLD_KILLED);
14462306a36Sopenharmony_ci	ASSERT_EQ(info.si_pid, parent_tid);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	EXPECT_EQ(close(pidfd), 0);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ciTEST(wait_nonblock)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	int pidfd;
15262306a36Sopenharmony_ci	unsigned int flags = 0;
15362306a36Sopenharmony_ci	pid_t parent_tid = -1;
15462306a36Sopenharmony_ci	struct clone_args args = {
15562306a36Sopenharmony_ci		.parent_tid = ptr_to_u64(&parent_tid),
15662306a36Sopenharmony_ci		.flags = CLONE_PARENT_SETTID,
15762306a36Sopenharmony_ci		.exit_signal = SIGCHLD,
15862306a36Sopenharmony_ci	};
15962306a36Sopenharmony_ci	int ret;
16062306a36Sopenharmony_ci	pid_t pid;
16162306a36Sopenharmony_ci	siginfo_t info = {
16262306a36Sopenharmony_ci		.si_signo = 0,
16362306a36Sopenharmony_ci	};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/*
16662306a36Sopenharmony_ci	 * Callers need to see ECHILD with non-blocking pidfds when no child
16762306a36Sopenharmony_ci	 * processes exists.
16862306a36Sopenharmony_ci	 */
16962306a36Sopenharmony_ci	pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
17062306a36Sopenharmony_ci	EXPECT_GE(pidfd, 0) {
17162306a36Sopenharmony_ci		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
17262306a36Sopenharmony_ci		ASSERT_EQ(errno, EINVAL);
17362306a36Sopenharmony_ci		SKIP(return, "Skipping PIDFD_NONBLOCK test");
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
17762306a36Sopenharmony_ci	ASSERT_LT(ret, 0);
17862306a36Sopenharmony_ci	ASSERT_EQ(errno, ECHILD);
17962306a36Sopenharmony_ci	EXPECT_EQ(close(pidfd), 0);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	pid = sys_clone3(&args);
18262306a36Sopenharmony_ci	ASSERT_GE(pid, 0);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (pid == 0) {
18562306a36Sopenharmony_ci		kill(getpid(), SIGSTOP);
18662306a36Sopenharmony_ci		exit(EXIT_SUCCESS);
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
19062306a36Sopenharmony_ci	EXPECT_GE(pidfd, 0) {
19162306a36Sopenharmony_ci		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
19262306a36Sopenharmony_ci		ASSERT_EQ(errno, EINVAL);
19362306a36Sopenharmony_ci		SKIP(return, "Skipping PIDFD_NONBLOCK test");
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	flags = fcntl(pidfd, F_GETFL, 0);
19762306a36Sopenharmony_ci	ASSERT_GT(flags, 0);
19862306a36Sopenharmony_ci	ASSERT_GT((flags & O_NONBLOCK), 0);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/*
20162306a36Sopenharmony_ci	 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
20262306a36Sopenharmony_ci	 * child processes exist but none have exited.
20362306a36Sopenharmony_ci	 */
20462306a36Sopenharmony_ci	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
20562306a36Sopenharmony_ci	ASSERT_LT(ret, 0);
20662306a36Sopenharmony_ci	ASSERT_EQ(errno, EAGAIN);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/*
20962306a36Sopenharmony_ci	 * Callers need to continue seeing 0 with non-blocking pidfd and
21062306a36Sopenharmony_ci	 * WNOHANG raised explicitly when child processes exist but none have
21162306a36Sopenharmony_ci	 * exited.
21262306a36Sopenharmony_ci	 */
21362306a36Sopenharmony_ci	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL);
21462306a36Sopenharmony_ci	ASSERT_EQ(ret, 0);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
21962306a36Sopenharmony_ci	ASSERT_EQ(info.si_signo, SIGCHLD);
22062306a36Sopenharmony_ci	ASSERT_EQ(info.si_code, CLD_STOPPED);
22162306a36Sopenharmony_ci	ASSERT_EQ(info.si_pid, parent_tid);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
22662306a36Sopenharmony_ci	ASSERT_EQ(info.si_signo, SIGCHLD);
22762306a36Sopenharmony_ci	ASSERT_EQ(info.si_code, CLD_EXITED);
22862306a36Sopenharmony_ci	ASSERT_EQ(info.si_pid, parent_tid);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	EXPECT_EQ(close(pidfd), 0);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ciTEST_HARNESS_MAIN
234