File Index
Files and directories
Sign in
FILE

pidfd_wait.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/pidfd/pidfd_wait.c C
  1/* SPDX-License-Identifier: GPL-2.0 */
  2
  3#define _GNU_SOURCE
  4#include <errno.h>
  5#include <linux/sched.h>
  6#include <linux/types.h>
  7#include <signal.h>
  8#include <stdint.h>
  9#include <stdio.h>
 10#include <stdlib.h>
 11#include <sched.h>
 12#include <string.h>
 13#include <sys/resource.h>
 14#include <sys/time.h>
 15#include <sys/types.h>
 16#include <sys/wait.h>
 17#include <unistd.h>
 18
 19#include "pidfd.h"
 20#include "kselftest_harness.h"
 21
 22#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
 23
 24/* Attempt to de-conflict with the selftests tree. */
 25#ifndef SKIP
 26#define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)
 27#endif
 28
 29TEST(wait_simple)
 30{
 31	int pidfd = -1;
 32	pid_t parent_tid = -1;
 33	struct __clone_args args = {
 34		.parent_tid = ptr_to_u64(&parent_tid),
 35		.pidfd = ptr_to_u64(&pidfd),
 36		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
 37		.exit_signal = SIGCHLD,
 38	};
 39	pid_t pid;
 40	siginfo_t info = {
 41		.si_signo = 0,
 42	};
 43
 44	pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
 45	ASSERT_GE(pidfd, 0);
 46
 47	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED);
 48	ASSERT_NE(pid, 0);
 49	EXPECT_EQ(close(pidfd), 0);
 50	pidfd = -1;
 51
 52	pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
 53	ASSERT_GE(pidfd, 0);
 54
 55	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED);
 56	ASSERT_NE(pid, 0);
 57	EXPECT_EQ(close(pidfd), 0);
 58	pidfd = -1;
 59
 60	pid = sys_clone3(&args, sizeof(args));
 61	ASSERT_GE(pid, 0);
 62
 63	if (pid == 0)
 64		exit(EXIT_SUCCESS);
 65
 66	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED);
 67	ASSERT_GE(pid, 0);
 68	ASSERT_EQ(WIFEXITED(info.si_status), true);
 69	ASSERT_EQ(WEXITSTATUS(info.si_status), 0);
 70	EXPECT_EQ(close(pidfd), 0);
 71
 72	ASSERT_EQ(info.si_signo, SIGCHLD);
 73	ASSERT_EQ(info.si_code, CLD_EXITED);
 74	ASSERT_EQ(info.si_pid, parent_tid);
 75}
 76
 77TEST(wait_states)
 78{
 79	int pidfd = -1;
 80	pid_t parent_tid = -1;
 81	struct __clone_args args = {
 82		.parent_tid = ptr_to_u64(&parent_tid),
 83		.pidfd = ptr_to_u64(&pidfd),
 84		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
 85		.exit_signal = SIGCHLD,
 86	};
 87	int pfd[2];
 88	pid_t pid;
 89	siginfo_t info = {
 90		.si_signo = 0,
 91	};
 92
 93	ASSERT_EQ(pipe(pfd), 0);
 94	pid = sys_clone3(&args, sizeof(args));
 95	ASSERT_GE(pid, 0);
 96
 97	if (pid == 0) {
 98		char buf[2];
 99
100		close(pfd[1]);
101		kill(getpid(), SIGSTOP);
102		ASSERT_EQ(read(pfd[0], buf, 1), 1);
103		close(pfd[0]);
104		kill(getpid(), SIGSTOP);
105		exit(EXIT_SUCCESS);
106	}
107
108	close(pfd[0]);
109	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED), 0);
110	ASSERT_EQ(info.si_signo, SIGCHLD);
111	ASSERT_EQ(info.si_code, CLD_STOPPED);
112	ASSERT_EQ(info.si_pid, parent_tid);
113
114	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
115
116	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED), 0);
117	ASSERT_EQ(write(pfd[1], "C", 1), 1);
118	close(pfd[1]);
119	ASSERT_EQ(info.si_signo, SIGCHLD);
120	ASSERT_EQ(info.si_code, CLD_CONTINUED);
121	ASSERT_EQ(info.si_pid, parent_tid);
122
123	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED), 0);
124	ASSERT_EQ(info.si_signo, SIGCHLD);
125	ASSERT_EQ(info.si_code, CLD_STOPPED);
126	ASSERT_EQ(info.si_pid, parent_tid);
127
128	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
129
130	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED), 0);
131	ASSERT_EQ(info.si_signo, SIGCHLD);
132	ASSERT_EQ(info.si_code, CLD_KILLED);
133	ASSERT_EQ(info.si_pid, parent_tid);
134
135	EXPECT_EQ(close(pidfd), 0);
136}
137
138TEST(wait_nonblock)
139{
140	int pidfd;
141	unsigned int flags = 0;
142	pid_t parent_tid = -1;
143	struct __clone_args args = {
144		.parent_tid = ptr_to_u64(&parent_tid),
145		.flags = CLONE_PARENT_SETTID,
146		.exit_signal = SIGCHLD,
147	};
148	int ret;
149	pid_t pid;
150	siginfo_t info = {
151		.si_signo = 0,
152	};
153
154	/*
155	 * Callers need to see ECHILD with non-blocking pidfds when no child
156	 * processes exists.
157	 */
158	pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
159	EXPECT_GE(pidfd, 0) {
160		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
161		ASSERT_EQ(errno, EINVAL);
162		SKIP(return, "Skipping PIDFD_NONBLOCK test");
163	}
164
165	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED);
166	ASSERT_LT(ret, 0);
167	ASSERT_EQ(errno, ECHILD);
168	EXPECT_EQ(close(pidfd), 0);
169
170	pid = sys_clone3(&args, sizeof(args));
171	ASSERT_GE(pid, 0);
172
173	if (pid == 0) {
174		kill(getpid(), SIGSTOP);
175		exit(EXIT_SUCCESS);
176	}
177
178	pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
179	EXPECT_GE(pidfd, 0) {
180		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
181		ASSERT_EQ(errno, EINVAL);
182		SKIP(return, "Skipping PIDFD_NONBLOCK test");
183	}
184
185	flags = fcntl(pidfd, F_GETFL, 0);
186	ASSERT_GT(flags, 0);
187	ASSERT_GT((flags & O_NONBLOCK), 0);
188
189	/*
190	 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
191	 * child processes exist but none have exited.
192	 */
193	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED);
194	ASSERT_LT(ret, 0);
195	ASSERT_EQ(errno, EAGAIN);
196
197	/*
198	 * Callers need to continue seeing 0 with non-blocking pidfd and
199	 * WNOHANG raised explicitly when child processes exist but none have
200	 * exited.
201	 */
202	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG);
203	ASSERT_EQ(ret, 0);
204
205	ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
206
207	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED), 0);
208	ASSERT_EQ(info.si_signo, SIGCHLD);
209	ASSERT_EQ(info.si_code, CLD_STOPPED);
210	ASSERT_EQ(info.si_pid, parent_tid);
211
212	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
213
214	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED), 0);
215	ASSERT_EQ(info.si_signo, SIGCHLD);
216	ASSERT_EQ(info.si_code, CLD_EXITED);
217	ASSERT_EQ(info.si_pid, parent_tid);
218
219	EXPECT_EQ(close(pidfd), 0);
220}
221
222TEST_HARNESS_MAIN
~/ Read-only file preview.