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