1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2016 Linux Test Project
4 */
5
6 #ifndef WAITPID_COMMON_H__
7 #define WAITPID_COMMON_H__
8
9 #include <sys/types.h>
10 #include <errno.h>
11 #include <sys/wait.h>
12 #include <stdlib.h>
13 #include "tst_test.h"
14
15 #define MAXKIDS 8
16
17 static pid_t *fork_kid_pid;
18 static pid_t child_1_pid;
19
20 static void do_child_1(void);
21
waitpid_setup(void)22 static void waitpid_setup(void)
23 {
24 fork_kid_pid = SAFE_MMAP(NULL, sizeof(*fork_kid_pid) * MAXKIDS,
25 PROT_READ | PROT_WRITE,
26 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
27 }
28
waitpid_cleanup(void)29 static void waitpid_cleanup(void)
30 {
31 int i;
32
33 for (i = 0; i < MAXKIDS; i++) {
34 if (fork_kid_pid[i] > 0)
35 kill(fork_kid_pid[i], SIGKILL);
36 }
37
38 if (child_1_pid > 0)
39 kill(child_1_pid, SIGKILL);
40
41 munmap(fork_kid_pid, sizeof(*fork_kid_pid) * MAXKIDS);
42 }
43
waitpid_test(void)44 static void waitpid_test(void)
45 {
46 child_1_pid = SAFE_FORK();
47 if (child_1_pid == 0) {
48 do_child_1();
49 } else {
50 tst_reap_children();
51 child_1_pid = 0;
52 }
53 }
54
do_exit(int stop)55 static void do_exit(int stop)
56 {
57 TST_CHECKPOINT_WAIT(0);
58
59 if (stop)
60 kill(getpid(), SIGSTOP);
61
62 exit(3);
63 }
64
waitpid_errno_check(int err,int exp_err)65 static int waitpid_errno_check(int err, int exp_err)
66 {
67 if (err != exp_err) {
68 tst_res(TFAIL, "waitpid() set errno to %s, expected %s",
69 tst_strerrno(err), tst_strerrno(exp_err));
70 return -1;
71 }
72
73 return 0;
74 }
75
waitpid_ret_test(pid_t wp_pid,int * wp_status,int wp_opts,pid_t wp_ret,int wp_errno)76 int waitpid_ret_test(pid_t wp_pid, int *wp_status, int wp_opts,
77 pid_t wp_ret, int wp_errno)
78 {
79 pid_t ret;
80
81 ret = waitpid(wp_pid, wp_status, wp_opts);
82 if (ret != wp_ret) {
83 tst_res(TFAIL, "waitpid() returned %d, expected %d",
84 ret, wp_ret);
85 return -1;
86 }
87
88 if ((ret == -1) && waitpid_errno_check(errno, wp_errno))
89 return -1;
90
91 return 0;
92 }
93
reap_children(pid_t wp_pid,int wp_opts,pid_t * children,int len)94 static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len)
95 {
96 pid_t pid;
97 int i;
98 int status;
99
100 for (;;) {
101 pid = waitpid(wp_pid, &status, wp_opts);
102
103 if (pid == -1) {
104 if (errno == EINTR)
105 continue;
106
107 if (waitpid_errno_check(errno, ECHILD))
108 return -1;
109
110 break;
111 }
112
113 if (pid == 0) {
114 if (wp_opts & WNOHANG)
115 continue;
116
117 tst_res(TFAIL, "waitpid() returned 0 unexpectedly");
118 return -1;
119 }
120
121 if (WIFSTOPPED(status)) {
122 if (WSTOPSIG(status) != SIGSTOP) {
123 tst_res(TFAIL,
124 "Pid %d: expected SIGSTOP, got %d",
125 pid, WSTOPSIG(status));
126 return -1;
127 }
128
129 tst_res(TINFO, "Sending SIGCONT to %d", pid);
130
131 if (kill(pid, SIGCONT) < 0) {
132 tst_res(TFAIL | TERRNO,
133 "kill(%d, SIGCONT) failed", pid);
134 return -1;
135 }
136
137 continue;
138 }
139
140 for (i = 0; i < len; i++) {
141 if (pid == children[i]) {
142 children[i] = 0;
143 break;
144 }
145 }
146
147 if (i == len) {
148 tst_res(TFAIL, "Pid %d not found", pid);
149 return -1;
150 }
151
152 if (!WIFEXITED(status)) {
153 tst_res(TFAIL, "Pid %d exited abnormally", pid);
154 return -1;
155 }
156
157 if (WEXITSTATUS(status) != 3) {
158 tst_res(TFAIL, "Pid %d exited with %d, expected 3",
159 pid, WEXITSTATUS(status));
160 return -1;
161 }
162 }
163
164 for (i = 0; i < len; i++) {
165 if (children[i]) {
166 tst_res(TFAIL, "Pid %d not reaped", children[i]);
167 return -1;
168 }
169 }
170
171 return 0;
172 }
173
174 #endif /* WAITPID_COMMON_H__ */
175