• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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