Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.10.11.
  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
 29static pid_t sys_clone3(struct clone_args *args)
 30{
 31	return syscall(__NR_clone3, args, sizeof(struct clone_args));
 32}
 33
 34static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
 35		      struct rusage *ru)
 36{
 37	return syscall(__NR_waitid, which, pid, info, options, ru);
 38}
 39
 40TEST(wait_simple)
 41{
 42	int pidfd = -1;
 43	pid_t parent_tid = -1;
 44	struct clone_args args = {
 45		.parent_tid = ptr_to_u64(&parent_tid),
 46		.pidfd = ptr_to_u64(&pidfd),
 47		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
 48		.exit_signal = SIGCHLD,
 49	};
 50	pid_t pid;
 51	siginfo_t info = {
 52		.si_signo = 0,
 53	};
 54
 55	pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
 56	ASSERT_GE(pidfd, 0);
 57
 58	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
 59	ASSERT_NE(pid, 0);
 60	EXPECT_EQ(close(pidfd), 0);
 61	pidfd = -1;
 62
 63	pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
 64	ASSERT_GE(pidfd, 0);
 65
 66	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
 67	ASSERT_NE(pid, 0);
 68	EXPECT_EQ(close(pidfd), 0);
 69	pidfd = -1;
 70
 71	pid = sys_clone3(&args);
 72	ASSERT_GE(pid, 0);
 73
 74	if (pid == 0)
 75		exit(EXIT_SUCCESS);
 76
 77	pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
 78	ASSERT_GE(pid, 0);
 79	ASSERT_EQ(WIFEXITED(info.si_status), true);
 80	ASSERT_EQ(WEXITSTATUS(info.si_status), 0);
 81	EXPECT_EQ(close(pidfd), 0);
 82
 83	ASSERT_EQ(info.si_signo, SIGCHLD);
 84	ASSERT_EQ(info.si_code, CLD_EXITED);
 85	ASSERT_EQ(info.si_pid, parent_tid);
 86}
 87
 88TEST(wait_states)
 89{
 90	int pidfd = -1;
 91	pid_t parent_tid = -1;
 92	struct clone_args args = {
 93		.parent_tid = ptr_to_u64(&parent_tid),
 94		.pidfd = ptr_to_u64(&pidfd),
 95		.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
 96		.exit_signal = SIGCHLD,
 97	};
 98	int pfd[2];
 99	pid_t pid;
100	siginfo_t info = {
101		.si_signo = 0,
102	};
103
104	ASSERT_EQ(pipe(pfd), 0);
105	pid = sys_clone3(&args);
106	ASSERT_GE(pid, 0);
107
108	if (pid == 0) {
109		char buf[2];
110
111		close(pfd[1]);
112		kill(getpid(), SIGSTOP);
113		ASSERT_EQ(read(pfd[0], buf, 1), 1);
114		close(pfd[0]);
115		kill(getpid(), SIGSTOP);
116		exit(EXIT_SUCCESS);
117	}
118
119	close(pfd[0]);
120	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
121	ASSERT_EQ(info.si_signo, SIGCHLD);
122	ASSERT_EQ(info.si_code, CLD_STOPPED);
123	ASSERT_EQ(info.si_pid, parent_tid);
124
125	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
126
127	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL), 0);
128	ASSERT_EQ(write(pfd[1], "C", 1), 1);
129	close(pfd[1]);
130	ASSERT_EQ(info.si_signo, SIGCHLD);
131	ASSERT_EQ(info.si_code, CLD_CONTINUED);
132	ASSERT_EQ(info.si_pid, parent_tid);
133
134	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL), 0);
135	ASSERT_EQ(info.si_signo, SIGCHLD);
136	ASSERT_EQ(info.si_code, CLD_STOPPED);
137	ASSERT_EQ(info.si_pid, parent_tid);
138
139	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
140
141	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
142	ASSERT_EQ(info.si_signo, SIGCHLD);
143	ASSERT_EQ(info.si_code, CLD_KILLED);
144	ASSERT_EQ(info.si_pid, parent_tid);
145
146	EXPECT_EQ(close(pidfd), 0);
147}
148
149TEST(wait_nonblock)
150{
151	int pidfd;
152	unsigned int flags = 0;
153	pid_t parent_tid = -1;
154	struct clone_args args = {
155		.parent_tid = ptr_to_u64(&parent_tid),
156		.flags = CLONE_PARENT_SETTID,
157		.exit_signal = SIGCHLD,
158	};
159	int ret;
160	pid_t pid;
161	siginfo_t info = {
162		.si_signo = 0,
163	};
164
165	/*
166	 * Callers need to see ECHILD with non-blocking pidfds when no child
167	 * processes exists.
168	 */
169	pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
170	EXPECT_GE(pidfd, 0) {
171		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
172		ASSERT_EQ(errno, EINVAL);
173		SKIP(return, "Skipping PIDFD_NONBLOCK test");
174	}
175
176	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
177	ASSERT_LT(ret, 0);
178	ASSERT_EQ(errno, ECHILD);
179	EXPECT_EQ(close(pidfd), 0);
180
181	pid = sys_clone3(&args);
182	ASSERT_GE(pid, 0);
183
184	if (pid == 0) {
185		kill(getpid(), SIGSTOP);
186		exit(EXIT_SUCCESS);
187	}
188
189	pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
190	EXPECT_GE(pidfd, 0) {
191		/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
192		ASSERT_EQ(errno, EINVAL);
193		SKIP(return, "Skipping PIDFD_NONBLOCK test");
194	}
195
196	flags = fcntl(pidfd, F_GETFL, 0);
197	ASSERT_GT(flags, 0);
198	ASSERT_GT((flags & O_NONBLOCK), 0);
199
200	/*
201	 * Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
202	 * child processes exist but none have exited.
203	 */
204	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
205	ASSERT_LT(ret, 0);
206	ASSERT_EQ(errno, EAGAIN);
207
208	/*
209	 * Callers need to continue seeing 0 with non-blocking pidfd and
210	 * WNOHANG raised explicitly when child processes exist but none have
211	 * exited.
212	 */
213	ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL);
214	ASSERT_EQ(ret, 0);
215
216	ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
217
218	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
219	ASSERT_EQ(info.si_signo, SIGCHLD);
220	ASSERT_EQ(info.si_code, CLD_STOPPED);
221	ASSERT_EQ(info.si_pid, parent_tid);
222
223	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
224
225	ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
226	ASSERT_EQ(info.si_signo, SIGCHLD);
227	ASSERT_EQ(info.si_code, CLD_EXITED);
228	ASSERT_EQ(info.si_pid, parent_tid);
229
230	EXPECT_EQ(close(pidfd), 0);
231}
232
233TEST_HARNESS_MAIN