Home | History | Annotate | Download | only in waitpid
      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 
     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 
     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 
     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 
     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 
     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 
     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 
    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