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.h"
  21
  22#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
  23
  24static pid_t sys_clone3(struct clone_args *args)
  25{
  26        return syscall(__NR_clone3, args, sizeof(struct clone_args));
  27}
  28
  29static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
  30                      struct rusage *ru)
  31{
  32        return syscall(__NR_waitid, which, pid, info, options, ru);
  33}
  34
  35static int test_pidfd_wait_simple(void)
  36{
  37        const char *test_name = "pidfd wait simple";
  38        int pidfd = -1, status = 0;
  39        pid_t parent_tid = -1;
  40        struct clone_args args = {
  41                .parent_tid = ptr_to_u64(&parent_tid),
  42                .pidfd = ptr_to_u64(&pidfd),
  43                .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
  44                .exit_signal = SIGCHLD,
  45        };
  46        int ret;
  47        pid_t pid;
  48        siginfo_t info = {
  49                .si_signo = 0,
  50        };
  51
  52        pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
  53        if (pidfd < 0)
  54                ksft_exit_fail_msg("%s test: failed to open /proc/self %s\n",
  55                                   test_name, strerror(errno));
  56
  57        pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
  58        if (pid == 0)
  59                ksft_exit_fail_msg(
  60                        "%s test: succeeded to wait on invalid pidfd %s\n",
  61                        test_name, strerror(errno));
  62        close(pidfd);
  63        pidfd = -1;
  64
  65        pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
  66        if (pidfd == 0)
  67                ksft_exit_fail_msg("%s test: failed to open /dev/null %s\n",
  68                                   test_name, strerror(errno));
  69
  70        pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
  71        if (pid == 0)
  72                ksft_exit_fail_msg(
  73                        "%s test: succeeded to wait on invalid pidfd %s\n",
  74                        test_name, strerror(errno));
  75        close(pidfd);
  76        pidfd = -1;
  77
  78        pid = sys_clone3(&args);
  79        if (pid < 0)
  80                ksft_exit_fail_msg("%s test: failed to create new process %s\n",
  81                                   test_name, strerror(errno));
  82
  83        if (pid == 0)
  84                exit(EXIT_SUCCESS);
  85
  86        pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
  87        if (pid < 0)
  88                ksft_exit_fail_msg(
  89                        "%s test: failed to wait on process with pid %d and pidfd %d: %s\n",
  90                        test_name, parent_tid, pidfd, strerror(errno));
  91
  92        if (!WIFEXITED(info.si_status) || WEXITSTATUS(info.si_status))
  93                ksft_exit_fail_msg(
  94                        "%s test: unexpected status received after waiting on process with pid %d and pidfd %d: %s\n",
  95                        test_name, parent_tid, pidfd, strerror(errno));
  96        close(pidfd);
  97
  98        if (info.si_signo != SIGCHLD)
  99                ksft_exit_fail_msg(
 100                        "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 101                        test_name, info.si_signo, parent_tid, pidfd,
 102                        strerror(errno));
 103
 104        if (info.si_code != CLD_EXITED)
 105                ksft_exit_fail_msg(
 106                        "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 107                        test_name, info.si_code, parent_tid, pidfd,
 108                        strerror(errno));
 109
 110        if (info.si_pid != parent_tid)
 111                ksft_exit_fail_msg(
 112                        "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 113                        test_name, info.si_pid, parent_tid, pidfd,
 114                        strerror(errno));
 115
 116        ksft_test_result_pass("%s test: Passed\n", test_name);
 117        return 0;
 118}
 119
 120static int test_pidfd_wait_states(void)
 121{
 122        const char *test_name = "pidfd wait states";
 123        int pidfd = -1, status = 0;
 124        pid_t parent_tid = -1;
 125        struct clone_args args = {
 126                .parent_tid = ptr_to_u64(&parent_tid),
 127                .pidfd = ptr_to_u64(&pidfd),
 128                .flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
 129                .exit_signal = SIGCHLD,
 130        };
 131        int ret;
 132        pid_t pid;
 133        siginfo_t info = {
 134                .si_signo = 0,
 135        };
 136
 137        pid = sys_clone3(&args);
 138        if (pid < 0)
 139                ksft_exit_fail_msg("%s test: failed to create new process %s\n",
 140                                   test_name, strerror(errno));
 141
 142        if (pid == 0) {
 143                kill(getpid(), SIGSTOP);
 144                kill(getpid(), SIGSTOP);
 145                exit(EXIT_SUCCESS);
 146        }
 147
 148        ret = sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL);
 149        if (ret < 0)
 150                ksft_exit_fail_msg(
 151                        "%s test: failed to wait on WSTOPPED process with pid %d and pidfd %d: %s\n",
 152                        test_name, parent_tid, pidfd, strerror(errno));
 153
 154        if (info.si_signo != SIGCHLD)
 155                ksft_exit_fail_msg(
 156                        "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 157                        test_name, info.si_signo, parent_tid, pidfd,
 158                        strerror(errno));
 159
 160        if (info.si_code != CLD_STOPPED)
 161                ksft_exit_fail_msg(
 162                        "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 163                        test_name, info.si_code, parent_tid, pidfd,
 164                        strerror(errno));
 165
 166        if (info.si_pid != parent_tid)
 167                ksft_exit_fail_msg(
 168                        "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 169                        test_name, info.si_pid, parent_tid, pidfd,
 170                        strerror(errno));
 171
 172        ret = sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0);
 173        if (ret < 0)
 174                ksft_exit_fail_msg(
 175                        "%s test: failed to send signal to process with pid %d and pidfd %d: %s\n",
 176                        test_name, parent_tid, pidfd, strerror(errno));
 177
 178        ret = sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL);
 179        if (ret < 0)
 180                ksft_exit_fail_msg(
 181                        "%s test: failed to wait WCONTINUED on process with pid %d and pidfd %d: %s\n",
 182                        test_name, parent_tid, pidfd, strerror(errno));
 183
 184        if (info.si_signo != SIGCHLD)
 185                ksft_exit_fail_msg(
 186                        "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 187                        test_name, info.si_signo, parent_tid, pidfd,
 188                        strerror(errno));
 189
 190        if (info.si_code != CLD_CONTINUED)
 191                ksft_exit_fail_msg(
 192                        "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 193                        test_name, info.si_code, parent_tid, pidfd,
 194                        strerror(errno));
 195
 196        if (info.si_pid != parent_tid)
 197                ksft_exit_fail_msg(
 198                        "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 199                        test_name, info.si_pid, parent_tid, pidfd,
 200                        strerror(errno));
 201
 202        ret = sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL);
 203        if (ret < 0)
 204                ksft_exit_fail_msg(
 205                        "%s test: failed to wait on WUNTRACED process with pid %d and pidfd %d: %s\n",
 206                        test_name, parent_tid, pidfd, strerror(errno));
 207
 208        if (info.si_signo != SIGCHLD)
 209                ksft_exit_fail_msg(
 210                        "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 211                        test_name, info.si_signo, parent_tid, pidfd,
 212                        strerror(errno));
 213
 214        if (info.si_code != CLD_STOPPED)
 215                ksft_exit_fail_msg(
 216                        "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 217                        test_name, info.si_code, parent_tid, pidfd,
 218                        strerror(errno));
 219
 220        if (info.si_pid != parent_tid)
 221                ksft_exit_fail_msg(
 222                        "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 223                        test_name, info.si_pid, parent_tid, pidfd,
 224                        strerror(errno));
 225
 226        ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
 227        if (ret < 0)
 228                ksft_exit_fail_msg(
 229                        "%s test: failed to send SIGKILL to process with pid %d and pidfd %d: %s\n",
 230                        test_name, parent_tid, pidfd, strerror(errno));
 231
 232        ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
 233        if (ret < 0)
 234                ksft_exit_fail_msg(
 235                        "%s test: failed to wait on WEXITED process with pid %d and pidfd %d: %s\n",
 236                        test_name, parent_tid, pidfd, strerror(errno));
 237
 238        if (info.si_signo != SIGCHLD)
 239                ksft_exit_fail_msg(
 240                        "%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 241                        test_name, info.si_signo, parent_tid, pidfd,
 242                        strerror(errno));
 243
 244        if (info.si_code != CLD_KILLED)
 245                ksft_exit_fail_msg(
 246                        "%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 247                        test_name, info.si_code, parent_tid, pidfd,
 248                        strerror(errno));
 249
 250        if (info.si_pid != parent_tid)
 251                ksft_exit_fail_msg(
 252                        "%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
 253                        test_name, info.si_pid, parent_tid, pidfd,
 254                        strerror(errno));
 255
 256        close(pidfd);
 257
 258        ksft_test_result_pass("%s test: Passed\n", test_name);
 259        return 0;
 260}
 261
 262int main(int argc, char **argv)
 263{
 264        ksft_print_header();
 265        ksft_set_plan(2);
 266
 267        test_pidfd_wait_simple();
 268        test_pidfd_wait_states();
 269
 270        return ksft_exit_pass();
 271}
 272