#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));
        pidfd = -1;
 
        pid = sys_clone3(&args);
-       ASSERT_GE(pid, 1);
+       ASSERT_GE(pid, 0);
 
        if (pid == 0)
                exit(EXIT_SUCCESS);
        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