brintos

brintos / linux-shallow public Read only

0
0
Text · 5.5 KiB · 0dcb836 Raw
234 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2 3#define _GNU_SOURCE4#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 SKIP26#define SKIP(s, ...)	XFAIL(s, ##__VA_ARGS__)27#endif28 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 child167	 * 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 when202	 * 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 and210	 * WNOHANG raised explicitly when child processes exist but none have211	 * 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_MAIN234