175 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			C
		
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * Copyright (c) 2016 Linux Test Project
 | |
|  */
 | |
| 
 | |
| #ifndef WAITPID_COMMON_H__
 | |
| #define WAITPID_COMMON_H__
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <errno.h>
 | |
| #include <sys/wait.h>
 | |
| #include <stdlib.h>
 | |
| #include "tst_test.h"
 | |
| 
 | |
| #define	MAXKIDS	8
 | |
| 
 | |
| static pid_t *fork_kid_pid;
 | |
| static pid_t child_1_pid;
 | |
| 
 | |
| static void do_child_1(void);
 | |
| 
 | |
| static void waitpid_setup(void)
 | |
| {
 | |
| 	fork_kid_pid = SAFE_MMAP(NULL, sizeof(*fork_kid_pid) * MAXKIDS,
 | |
| 				 PROT_READ | PROT_WRITE,
 | |
| 				 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 | |
| }
 | |
| 
 | |
| static void waitpid_cleanup(void)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < MAXKIDS; i++) {
 | |
| 		if (fork_kid_pid[i] > 0)
 | |
| 			kill(fork_kid_pid[i], SIGKILL);
 | |
| 	}
 | |
| 
 | |
| 	if (child_1_pid > 0)
 | |
| 		kill(child_1_pid, SIGKILL);
 | |
| 
 | |
| 	munmap(fork_kid_pid, sizeof(*fork_kid_pid) * MAXKIDS);
 | |
| }
 | |
| 
 | |
| static void waitpid_test(void)
 | |
| {
 | |
| 	child_1_pid = SAFE_FORK();
 | |
| 	if (child_1_pid == 0) {
 | |
| 		do_child_1();
 | |
| 	} else {
 | |
| 		tst_reap_children();
 | |
| 		child_1_pid = 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void do_exit(int stop)
 | |
| {
 | |
| 	TST_CHECKPOINT_WAIT(0);
 | |
| 
 | |
| 	if (stop)
 | |
| 		kill(getpid(), SIGSTOP);
 | |
| 
 | |
| 	exit(3);
 | |
| }
 | |
| 
 | |
| static int waitpid_errno_check(int err, int exp_err)
 | |
| {
 | |
| 	if (err != exp_err) {
 | |
| 		tst_res(TFAIL, "waitpid() set errno to %s, expected %s",
 | |
| 			tst_strerrno(err), tst_strerrno(exp_err));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int waitpid_ret_test(pid_t wp_pid, int *wp_status, int wp_opts,
 | |
| 		     pid_t wp_ret, int wp_errno)
 | |
| {
 | |
| 	pid_t ret;
 | |
| 
 | |
| 	ret = waitpid(wp_pid, wp_status, wp_opts);
 | |
| 	if (ret != wp_ret) {
 | |
| 		tst_res(TFAIL, "waitpid() returned %d, expected %d",
 | |
| 			ret, wp_ret);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	if ((ret == -1) && waitpid_errno_check(errno, wp_errno))
 | |
| 		return -1;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len)
 | |
| {
 | |
| 	pid_t pid;
 | |
| 	int i;
 | |
| 	int status;
 | |
| 
 | |
| 	for (;;) {
 | |
| 		pid = waitpid(wp_pid, &status, wp_opts);
 | |
| 
 | |
| 		if (pid == -1) {
 | |
| 			if (errno == EINTR)
 | |
| 				continue;
 | |
| 
 | |
| 			if (waitpid_errno_check(errno, ECHILD))
 | |
| 				return -1;
 | |
| 
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		if (pid == 0) {
 | |
| 			if (wp_opts & WNOHANG)
 | |
| 				continue;
 | |
| 
 | |
| 			tst_res(TFAIL, "waitpid() returned 0 unexpectedly");
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		if (WIFSTOPPED(status)) {
 | |
| 			if (WSTOPSIG(status) != SIGSTOP) {
 | |
| 				tst_res(TFAIL,
 | |
| 					"Pid %d: expected SIGSTOP, got %d",
 | |
| 					pid, WSTOPSIG(status));
 | |
| 				return -1;
 | |
| 			}
 | |
| 
 | |
| 			tst_res(TINFO, "Sending SIGCONT to %d", pid);
 | |
| 
 | |
| 			if (kill(pid, SIGCONT) < 0) {
 | |
| 				tst_res(TFAIL | TERRNO,
 | |
| 					"kill(%d, SIGCONT) failed", pid);
 | |
| 				return -1;
 | |
| 			}
 | |
| 
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		for (i = 0; i < len; i++) {
 | |
| 			if (pid == children[i]) {
 | |
| 				children[i] = 0;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (i == len) {
 | |
| 			tst_res(TFAIL, "Pid %d not found", pid);
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		if (!WIFEXITED(status)) {
 | |
| 			tst_res(TFAIL, "Pid %d exited abnormally", pid);
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		if (WEXITSTATUS(status) != 3) {
 | |
| 			tst_res(TFAIL, "Pid %d exited with %d, expected 3",
 | |
| 				pid, WEXITSTATUS(status));
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < len; i++) {
 | |
| 		if (children[i]) {
 | |
| 			tst_res(TFAIL, "Pid %d not reaped", children[i]);
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #endif /* WAITPID_COMMON_H__ */
 |