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
waitpid_setup(void)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
waitpid_cleanup(void)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
waitpid_test(void)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
do_exit(int stop)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
waitpid_errno_check(int err,int exp_err)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
waitpid_ret_test(pid_t wp_pid,int * wp_status,int wp_opts,pid_t wp_ret,int wp_errno)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
reap_children(pid_t wp_pid,int wp_opts,pid_t * children,int len)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