tests: add waitid() tests for non-blocking pidfds
Verify that the PIDFD_NONBLOCK flag works with pidfd_open() and that waitid() with a non-blocking pidfd returns EAGAIN: TAP version 13 1..3 # Starting 3 tests from 1 test cases. # RUN global.wait_simple ... # OK global.wait_simple ok 1 global.wait_simple # RUN global.wait_states ... # OK global.wait_states ok 2 global.wait_states # RUN global.wait_nonblock ... # OK global.wait_nonblock ok 3 global.wait_nonblock # PASSED: 3 / 3 tests passed. # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0 Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com> Reviewed-by: Josh Triplett <josh@joshtriplett.org> Cc: Shuah Khan <shuah@kernel.org> Cc: linux-kselftest@vger.kernel.org Link: https://lore.kernel.org/r/20200902102130.147672-5-christian.brauner@ubuntu.com
This commit is contained in:
parent
09d1de1a8e
commit
cd89597bbe
|
@ -46,6 +46,10 @@
|
|||
#define __NR_pidfd_getfd -1
|
||||
#endif
|
||||
|
||||
#ifndef PIDFD_NONBLOCK
|
||||
#define PIDFD_NONBLOCK O_NONBLOCK
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c
|
||||
* That means, when it wraps around any pid < 300 will be skipped.
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
|
||||
#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
|
||||
|
||||
/* Attempt to de-conflict with the selftests tree. */
|
||||
#ifndef SKIP
|
||||
#define SKIP(s, ...) XFAIL(s, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
static pid_t sys_clone3(struct clone_args *args)
|
||||
{
|
||||
return syscall(__NR_clone3, args, sizeof(struct clone_args));
|
||||
|
@ -65,7 +70,7 @@ TEST(wait_simple)
|
|||
pidfd = -1;
|
||||
|
||||
pid = sys_clone3(&args);
|
||||
ASSERT_GE(pid, 1);
|
||||
ASSERT_GE(pid, 0);
|
||||
|
||||
if (pid == 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -133,4 +138,88 @@ TEST(wait_states)
|
|||
EXPECT_EQ(close(pidfd), 0);
|
||||
}
|
||||
|
||||
TEST(wait_nonblock)
|
||||
{
|
||||
int pidfd, status = 0;
|
||||
unsigned int flags = 0;
|
||||
pid_t parent_tid = -1;
|
||||
struct clone_args args = {
|
||||
.parent_tid = ptr_to_u64(&parent_tid),
|
||||
.flags = CLONE_PARENT_SETTID,
|
||||
.exit_signal = SIGCHLD,
|
||||
};
|
||||
int ret;
|
||||
pid_t pid;
|
||||
siginfo_t info = {
|
||||
.si_signo = 0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Callers need to see ECHILD with non-blocking pidfds when no child
|
||||
* processes exists.
|
||||
*/
|
||||
pidfd = sys_pidfd_open(getpid(), PIDFD_NONBLOCK);
|
||||
EXPECT_GE(pidfd, 0) {
|
||||
/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
|
||||
ASSERT_EQ(errno, EINVAL);
|
||||
SKIP(return, "Skipping PIDFD_NONBLOCK test");
|
||||
}
|
||||
|
||||
ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
|
||||
ASSERT_LT(ret, 0);
|
||||
ASSERT_EQ(errno, ECHILD);
|
||||
EXPECT_EQ(close(pidfd), 0);
|
||||
|
||||
pid = sys_clone3(&args);
|
||||
ASSERT_GE(pid, 0);
|
||||
|
||||
if (pid == 0) {
|
||||
kill(getpid(), SIGSTOP);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
pidfd = sys_pidfd_open(pid, PIDFD_NONBLOCK);
|
||||
EXPECT_GE(pidfd, 0) {
|
||||
/* pidfd_open() doesn't support PIDFD_NONBLOCK. */
|
||||
ASSERT_EQ(errno, EINVAL);
|
||||
SKIP(return, "Skipping PIDFD_NONBLOCK test");
|
||||
}
|
||||
|
||||
flags = fcntl(pidfd, F_GETFL, 0);
|
||||
ASSERT_GT(flags, 0);
|
||||
ASSERT_GT((flags & O_NONBLOCK), 0);
|
||||
|
||||
/*
|
||||
* Callers need to see EAGAIN/EWOULDBLOCK with non-blocking pidfd when
|
||||
* child processes exist but none have exited.
|
||||
*/
|
||||
ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
|
||||
ASSERT_LT(ret, 0);
|
||||
ASSERT_EQ(errno, EAGAIN);
|
||||
|
||||
/*
|
||||
* Callers need to continue seeing 0 with non-blocking pidfd and
|
||||
* WNOHANG raised explicitly when child processes exist but none have
|
||||
* exited.
|
||||
*/
|
||||
ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED | WNOHANG, NULL);
|
||||
ASSERT_EQ(ret, 0);
|
||||
|
||||
ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL), 0);
|
||||
ASSERT_EQ(info.si_signo, SIGCHLD);
|
||||
ASSERT_EQ(info.si_code, CLD_STOPPED);
|
||||
ASSERT_EQ(info.si_pid, parent_tid);
|
||||
|
||||
ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0), 0);
|
||||
|
||||
ASSERT_EQ(fcntl(pidfd, F_SETFL, (flags & ~O_NONBLOCK)), 0);
|
||||
|
||||
ASSERT_EQ(sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL), 0);
|
||||
ASSERT_EQ(info.si_signo, SIGCHLD);
|
||||
ASSERT_EQ(info.si_code, CLD_EXITED);
|
||||
ASSERT_EQ(info.si_pid, parent_tid);
|
||||
|
||||
EXPECT_EQ(close(pidfd), 0);
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
|
|
Loading…
Reference in New Issue