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