1 /* 2 * Copyright (c) 2016 Linux Test Project 3 * 4 * Licensed under the GNU GPLv2 or later. 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. 17 */ 18 19 #ifndef WAITPID_COMMON_H__ 20 #define WAITPID_COMMON_H__ 21 22 #include <sys/types.h> 23 #include <errno.h> 24 #include <sys/wait.h> 25 #include <stdlib.h> 26 #include "tst_test.h" 27 28 #define MAXKIDS 8 29 30 static pid_t *fork_kid_pid; 31 static pid_t child_1_pid; 32 33 static void do_child_1(void); 34 35 static void waitpid_setup(void) 36 { 37 fork_kid_pid = SAFE_MMAP(NULL, sizeof(*fork_kid_pid) * MAXKIDS, 38 PROT_READ | PROT_WRITE, 39 MAP_SHARED | MAP_ANONYMOUS, -1, 0); 40 } 41 42 static void waitpid_cleanup(void) 43 { 44 int i; 45 46 for (i = 0; i < MAXKIDS; i++) { 47 if (fork_kid_pid[i] > 0) 48 kill(fork_kid_pid[i], SIGKILL); 49 } 50 51 if (child_1_pid > 0) 52 kill(child_1_pid, SIGKILL); 53 54 munmap(fork_kid_pid, sizeof(*fork_kid_pid) * MAXKIDS); 55 } 56 57 static void waitpid_test(void) 58 { 59 child_1_pid = SAFE_FORK(); 60 if (child_1_pid == 0) { 61 do_child_1(); 62 } else { 63 tst_reap_children(); 64 child_1_pid = 0; 65 } 66 } 67 68 static void do_exit(int stop) 69 { 70 TST_CHECKPOINT_WAIT(0); 71 72 if (stop) 73 kill(getpid(), SIGSTOP); 74 75 exit(3); 76 } 77 78 static int waitpid_errno_check(int err, int exp_err) 79 { 80 if (err != exp_err) { 81 tst_res(TFAIL, "waitpid() set errno to %s, expected %s", 82 tst_strerrno(err), tst_strerrno(exp_err)); 83 return -1; 84 } 85 86 return 0; 87 } 88 89 int waitpid_ret_test(pid_t wp_pid, int *wp_status, int wp_opts, 90 pid_t wp_ret, int wp_errno) 91 { 92 pid_t ret; 93 94 ret = waitpid(wp_pid, wp_status, wp_opts); 95 if (ret != wp_ret) { 96 tst_res(TFAIL, "waitpid() returned %d, expected %d", 97 ret, wp_ret); 98 return -1; 99 } 100 101 if ((ret == -1) && waitpid_errno_check(errno, wp_errno)) 102 return -1; 103 104 return 0; 105 } 106 107 static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len) 108 { 109 pid_t pid; 110 int i; 111 int status; 112 113 for (;;) { 114 pid = waitpid(wp_pid, &status, wp_opts); 115 116 if (pid == -1) { 117 if (errno == EINTR) 118 continue; 119 120 if (waitpid_errno_check(errno, ECHILD)) 121 return -1; 122 123 break; 124 } 125 126 if (pid == 0) { 127 if (wp_opts & WNOHANG) 128 continue; 129 130 tst_res(TFAIL, "waitpid() returned 0 unexpectedly"); 131 return -1; 132 } 133 134 if (WIFSTOPPED(status)) { 135 if (WSTOPSIG(status) != SIGSTOP) { 136 tst_res(TFAIL, 137 "Pid %d: expected SIGSTOP, got %d", 138 pid, WSTOPSIG(status)); 139 return -1; 140 } 141 142 tst_res(TINFO, "Sending SIGCONT to %d", pid); 143 144 if (kill(pid, SIGCONT) < 0) { 145 tst_res(TFAIL | TERRNO, 146 "kill(%d, SIGCONT) failed", pid); 147 return -1; 148 } 149 150 continue; 151 } 152 153 for (i = 0; i < len; i++) { 154 if (pid == children[i]) { 155 children[i] = 0; 156 break; 157 } 158 } 159 160 if (i == len) { 161 tst_res(TFAIL, "Pid %d not found", pid); 162 return -1; 163 } 164 165 if (!WIFEXITED(status)) { 166 tst_res(TFAIL, "Pid %d exited abnormally", pid); 167 return -1; 168 } 169 170 if (WEXITSTATUS(status) != 3) { 171 tst_res(TFAIL, "Pid %d exited with %d, expected 3", 172 pid, WEXITSTATUS(status)); 173 return -1; 174 } 175 } 176 177 for (i = 0; i < len; i++) { 178 if (children[i]) { 179 tst_res(TFAIL, "Pid %d not reaped", children[i]); 180 return -1; 181 } 182 } 183 184 return 0; 185 } 186 187 #endif /* WAITPID_COMMON_H__ */ 188