Skip to contentSkip to conversation

waitpid: new API (part 2) V2

LTP New Stanislav Kholmanskikh 2 participants 25 messages Aug 24, 2016 – Aug 26, 2016

lore
Share & tools
lore
#0 lore raw

Hi!

Summary of changes:
* Updated waitpid09
* Add TST_TRACE and use it for calls to reap_children(), waitpid_ret_test()
* Split waitpid13 into two patches: one is for waitpid_common.h, the other is for waitpid13.c

#1 lore raw

PATCH v2 1/11 waitpid09: use the new API

---
Changes since V1:
* remove code from case0() which is duplicated in case1()
* rewrite the tst_res(TPASS) messages
* use function pointers instead of the switch-case structure

 testcases/kernel/syscalls/waitpid/waitpid09.c |  374 ++++++++----------------
 1 files changed, 125 insertions(+), 249 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid09.c +125 -249
index 1339c82..43beeff 100644
@@ -1,57 +1,37 @@
 /*
+ * Copyright (c) International Business Machines  Corp., 2001
  *
- *   Copyright (c) International Business Machines  Corp., 2001
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- *   This program is free software;  you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
  *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
- *   the GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program;  if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * NAME
- *	waitpid09.c
- *
- * DESCRIPTION
- *	Check ability of parent to wait until child returns, and that the
- *	child's process id is returned through the waitpid. Check that
- *	waitpid returns immediately if no child is present.
- *
- * ALGORITHM
- *	case 0:
- *		Parent forks a child and waits. Parent should do nothing
- *		further until child returns. The pid of the forked child
- *		should match the returned value from the waitpid.
- *
- *	case 1:
- *		Parent calls a waitpid with no children waiting. Waitpid
- *		should return a -1 since there are no children to wait for.
- *
- * USAGE:  <for command-line>
- *      waitpid09 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
- *      where,  -c n : Run n copies concurrently.
- *              -e   : Turn on errno logging.
- *              -i n : Execute test n times.
- *              -I x : Execute test for x seconds.
- *              -P x : Pause for x seconds between iterations.
- *              -t   : Turn on syscall timing.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
  *
  * History
  *	07/2001 John George
  *		-Ported
  *      04/2002 wjhuie sigset cleanups
- *
- * Restrictions
- *	None
+ */
+
+/*
+ * case 0:
+ *        waitpid(pid, WNOHANG) should return 0 if there is a running child
+ * case 1:
+ *        waitpid(pid, WNOHANG) should return the pid of the child if
+ *        the child has exited
+ * case 2:
+ *        waitpid(-1, 0) should return -1 with ECHILD if
+ *        there are no children to wait for.
+ * case 3:
+ *        waitpid(-1, WNOHANG) should return -1 with ECHILD if
+ *        there are no children to wait for.
  */
 
 #define _GNU_SOURCE 1
@@ -60,243 +40,139 @@
 #include <errno.h>
 #include <sys/wait.h>
 #include <stdlib.h>
+#include "tst_test.h"
 
-#include "test.h"
-
-char *TCID = "waitpid09";
-int TST_TOTAL = 1;
-volatile int intintr;
-
-static void setup(void);
-static void cleanup(void);
-static void inthandlr();
-static void do_exit(void);
-static void setup_sigint(void);
-#ifdef UCLINUX
-static void do_exit_uclinux(void);
-#endif
-
-int main(int argc, char **argv)
+static void cleanup_pid(pid_t pid)
 {
-	int lc;
-
-	int fail, pid, status, ret;
-
-	tst_parse_opts(argc, argv, NULL, NULL);
-
-#ifdef UCLINUX
-	maybe_run_child(&do_exit_uclinux, "");
-#endif
-
-	setup();
-
-	pid = FORK_OR_VFORK();
-	if (pid < 0) {
-		tst_brkm(TFAIL, cleanup, "Fork Failed");
-	} else if (pid == 0) {
-		/*
-		 * Child:
-		 * Set up to catch SIGINT.  The kids will wait till a
-		 * SIGINT has been received before they proceed.
-		 */
-		setup_sigint();
-
-		/* check for looping state if -i option is given */
-		for (lc = 0; TEST_LOOPING(lc); lc++) {
-			/* reset tst_count in case we are looping */
-			tst_count = 0;
-
-			intintr = 0;
+	if (pid > 0) {
+		kill(pid, SIGKILL);
+		waitpid(pid, NULL, 0);
+	}
+}
 
-			fail = 0;
-			pid = FORK_OR_VFORK();
-			if (pid < 0) {
-				tst_brkm(TFAIL, cleanup, "Fork failed.");
-			} else if (pid == 0) {	/* child */
-#ifdef UCLINUX
-				if (self_exec(argv[0], "") < 0) {
-					tst_brkm(TFAIL, cleanup,
-						 "self_exec failed");
-				}
-#else
-				do_exit();
-#endif
-			} else {	/* parent */
+static void case0(void)
+{
+	pid_t pid, ret;
+	int status;
 
-				/*
-				 *Check that waitpid with WNOHANG returns zero
-				 */
-				while (((ret = waitpid(pid, &status, WNOHANG))
-					!= 0) || (errno == EINTR)) {
-					if (ret == -1)
-						continue;
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		TST_CHECKPOINT_WAIT(0);
 
-					tst_resm(TFAIL, "return value for "
-						 "WNOHANG expected 0 got %d",
-						 ret);
-					fail = 1;
-				}
-#ifdef UCLINUX
-				/* Give the kids a chance to setup SIGINT again, since
-				 * this is cleared by exec().
-				 */
-				sleep(3);
-#endif
+		exit(0);
+	}
 
-				/* send SIGINT to child to tell it to proceed */
-				if (kill(pid, SIGINT) < 0) {
-					tst_resm(TFAIL, "Kill of child failed, "
-						 "errno = %d", errno);
-					fail = 1;
-				}
+	for (;;) {
+		ret = waitpid(pid, &status, WNOHANG);
 
-				while (((ret = waitpid(pid, &status, 0)) != -1)
-				       || (errno == EINTR)) {
-					if (ret == -1)
-						continue;
+		if ((ret == -1) && (errno == EINTR))
+			continue;
 
-					if (ret != pid) {
-						tst_resm(TFAIL, "Expected %d "
-							 "got %d as proc id of "
-							 "child", pid, ret);
-						fail = 1;
-					}
+		if (ret == 0)
+			break;
 
-					if (status != 0) {
-						tst_resm(TFAIL, "status value "
-							 "got %d expected 0",
-							 status);
-						fail = 1;
-					}
-				}
-			}
+		tst_res(TFAIL, "waitpid(WNOHANG) returned %d, expected 0",
+			ret);
+		cleanup_pid(pid);
+		return;
+	}
 
-			pid = FORK_OR_VFORK();
-			if (pid < 0) {
-				tst_brkm(TFAIL, cleanup, "Second fork failed.");
-			} else if (pid == 0) {	/* child */
-				exit(0);
-			} else {	/* parent */
-				/* Give the child time to startup and exit */
-				sleep(2);
+	TST_CHECKPOINT_WAKE(0);
+	SAFE_WAITPID(pid, NULL, 0);
 
-				while (((ret = waitpid(pid, &status, WNOHANG))
-					!= -1) || (errno == EINTR)) {
-					if (ret == -1)
-						continue;
+	tst_res(TPASS, "waitpid(pid, WNOHANG) = 0 for a running child");
+}
 
-					if (ret != pid) {
-						tst_resm(TFAIL, "proc id %d "
-							 "and retval %d do not "
-							 "match", pid, ret);
-						fail = 1;
-					}
+static void case1(void)
+{
+	pid_t pid, ret;
+	int status;
 
-					if (status != 0) {
-						tst_resm(TFAIL, "non zero "
-							 "status received %d",
-							 status);
-						fail = 1;
-					}
-				}
-			}
+	pid = SAFE_FORK();
+	if (pid == 0)
+		exit(0);
 
-			if (fail)
-				tst_resm(TFAIL, "case 1 FAILED");
-			else
-				tst_resm(TPASS, "case 1 PASSED");
+	for (;;) {
+		ret = waitpid(pid, &status, WNOHANG);
 
-			fail = 0;
-			ret = waitpid(pid, &status, 0);
+		if ((ret == -1) && (errno == EINTR))
+			continue;
+		if (ret == 0)
+			continue;
 
-			if (ret != -1) {
-				tst_resm(TFAIL, "Expected -1 got %d", ret);
-				fail = 1;
-			}
-			if (errno != ECHILD) {
-				tst_resm(TFAIL, "Expected ECHILD got %d",
-					 errno);
-				fail = 1;
-			}
+		if (ret == pid)
+			break;
 
-			ret = waitpid(pid, &status, WNOHANG);
-			if (ret != -1) {
-				tst_resm(TFAIL, "WNOHANG: Expected -1 got %d",
-					 ret);
-				fail = 1;
-			}
-			if (errno != ECHILD) {
-				tst_resm(TFAIL, "WNOHANG: Expected ECHILD got "
-					 "%d", errno);
-				fail = 1;
-			}
+		tst_res(TFAIL, "waitpid(WNOHANG) returned %d, expected %d",
+			ret, pid);
+		cleanup_pid(pid);
+		return;
+	}
 
-			if (fail)
-				tst_resm(TFAIL, "case 2 FAILED");
-			else
-				tst_resm(TPASS, "case 2 PASSED");
-		}
+	if (!WIFEXITED(status)) {
+		tst_res(TFAIL, "Child exited abnormally");
+		return;
+	}
 
-		cleanup();
-	} else {
-		/* wait for the child to return */
-		waitpid(pid, &status, 0);
-		if (WEXITSTATUS(status) != 0) {
-			tst_brkm(TBROK, cleanup, "child returned bad "
-				 "status");
-		}
+	if (WEXITSTATUS(status) != 0) {
+		tst_res(TFAIL, "Child exited with %d, expected 0",
+			WEXITSTATUS(status));
+		return;
 	}
 
-	tst_exit();
+	tst_res(TPASS, "waitpid(pid, WNOHANG) = pid for an exited child");
 }
 
-/*
- * setup_sigint()
- *	sets up a SIGINT handler
- */
-static void setup_sigint(void)
+static void case2(void)
 {
-	if ((sig_t) signal(SIGINT, inthandlr) == SIG_ERR) {
-		tst_brkm(TFAIL, cleanup, "signal SIGINT failed, errno = %d",
-			 errno);
+	pid_t ret;
+	int status;
+
+	ret = waitpid(-1, &status, 0);
+
+	if (ret != -1) {
+		tst_res(TFAIL, "Expected -1, got %d", ret);
+		return;
+	}
+	if (errno != ECHILD) {
+		tst_res(TFAIL, "Expected %s, got %s",
+			tst_strerrno(ECHILD), tst_strerrno(errno));
+		return;
 	}
-}
 
-static void setup(void)
-{
-	TEST_PAUSE;
+	tst_res(TPASS, "waitpid(-1, 0) = -1 with ECHILD if no children");
 }
 
-static void cleanup(void)
+static void case3(void)
 {
-}
+	pid_t ret;
+	int status;
 
-static void inthandlr(void)
-{
-	intintr++;
-}
+	ret = waitpid(-1, &status, WNOHANG);
+	if (ret != -1) {
+		tst_res(TFAIL, "WNOHANG: Expected -1, got %d", ret);
+		return;
+	}
+	if (errno != ECHILD) {
+		tst_res(TFAIL, "WNOHANG: Expected %s, got %s",
+			tst_strerrno(ECHILD), tst_strerrno(errno));
+		return;
+	}
 
-static void wait_for_parent(void)
-{
-	int testvar;
-	while (!intintr)
-		testvar = 0;
+	tst_res(TPASS, "waitpid(-1, WNOHANG) = -1 with ECHILD if no children");
 }
 
-static void do_exit(void)
-{
-	wait_for_parent();
-	exit(0);
-}
+static void (*tests[])(void) = { case0, case1, case2, case3 };
 
-#ifdef UCLINUX
-/*
- * do_exit_uclinux()
- *	Sets up SIGINT handler again, then calls do_exit
- */
-static void do_exit_uclinux(void)
+static void waitpid09_test(unsigned int id)
 {
-	setup_sigint();
-	do_exit();
+	tests[id]();
 }
-#endif
+
+static struct tst_test test = {
+	.tid = "waitpid09",
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+	.test = waitpid09_test,
+	.tcnt = ARRAY_SIZE(tests),
+};
Signature · 1 line
1.7.1
#3 lore raw

PATCH v2 2/11 waitpid10: use the new API

In reply to Stanislav Kholmanskikh

* update the description to match the actions performed in the test
* make use of the new API
* make use of reap_children() in do_fork()
* put the test function inside do_child_1(), i.e. it forks one more time than in the original test. It's just for similarity with other test cases. This change brings no harm or improvements.

---
Changes since V1:
* Update the commit description to explain why I use do_child_1() here

 testcases/kernel/syscalls/waitpid/waitpid10.c |  312 ++++---------------------
 1 files changed, 47 insertions(+), 265 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid10.c +47 -265
index d239fda..a505ade 100644
@@ -14,263 +14,59 @@
  * the GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program;  if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * along with this program.
  */
 
 /*
- * Tests to see if pid's returned from fork and waitpid are same
+ * Tests to see if pids returned from fork and waitpid are same
  *
- * Set up to catch SIGINTs, SIGALRMs, and the real time timer. Until the timer
- * interrupts, do the following. Fork 8 kids, 2 will immediately exit, 2 will
- * sleep, 2 will be compute bound, and 2 will fork another child, both which
- * will do mkdirs on the same directory 50 times. When the timer expires, kill
- * all kids and remove the directory.
+ * Fork 8 kids, 2 will immediately exit, 2 will sleep, 2 will be compute bound
+ * and 2 will fork/reap a child for 50 times.
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
+#include "waitpid_common.h"
 
-#include <stdio.h>
-#include <signal.h>
-#include <errno.h>
-#include "test.h"
-
-#define	MAXKIDS	8
-
-char *TCID = "waitpid10";
-int TST_TOTAL = 1;
-
-volatile int intintr;
-
-static void setup(void);
-static void cleanup(void);
-static void inthandlr();
-static void wait_for_parent(void);
-static void do_exit(void);
 static void do_compute(void);
 static void do_fork(void);
 static void do_sleep(void);
 
-static int fail;
-static int fork_kid_pid[MAXKIDS];
-
-#ifdef UCLINUX
-static char *argv0;
-#endif
-
-int main(int ac, char **av)
+static void do_child_1(void)
 {
-	int kid_count, ret_val, status, nkids;
-	int i, j, k, found;
-	int wait_kid_pid[MAXKIDS];
-
-	int lc;
-
-	tst_parse_opts(ac, av, NULL, NULL);
-
-#ifdef UCLINUX
-	argv0 = av[0];
-
-	maybe_run_child(&do_exit, "n", 1);
-	maybe_run_child(&do_compute, "n", 2);
-	maybe_run_child(&do_fork, "n", 3);
-	maybe_run_child(&do_sleep, "n", 4);
-#endif
-
-	setup();
-
-	for (lc = 0; TEST_LOOPING(lc); lc++) {
-		fail = 0;
-		kid_count = 0;
-		intintr = 0;
-		for (i = 0; i < MAXKIDS; i++) {
-			ret_val = FORK_OR_VFORK();
-			if (ret_val < 0)
-				tst_brkm(TBROK|TERRNO, cleanup,
-					 "Fork kid %d failed.", i);
-
-			if (ret_val == 0) {
-				if (i == 0 || i == 1) {
-#ifdef UCLINUX
-					if (self_exec(argv0, "n", 1) < 0)
-						tst_brkm(TBROK|TERRNO, cleanup,
-							 "self_exec %d failed",
-							 i);
-#else
-					do_exit();
-#endif
-				}
-
-				if (i == 2 || i == 3) {
-#ifdef UCLINUX
-					if (self_exec(argv0, "n", 2) < 0)
-						tst_brkm(TBROK|TERRNO, cleanup,
-							 "self_exec %d failed",
-							 i);
-#else
-					do_compute();
-#endif
-				}
-
-				if (i == 4 || i == 5) {
-#ifdef UCLINUX
-					if (self_exec(argv0, "n", 3) < 0)
-						tst_brkm(TBROK|TERRNO, cleanup,
-							 "self_exec %d failed",
-							 i);
-#else
-					do_fork();
-#endif
-				}
-
-				if (i == 6 || i == 7) {
-#ifdef UCLINUX
-					if (self_exec(argv0, "n", 4) < 0)
-						tst_brkm(TBROK|TERRNO, cleanup,
-							 "self_exec %d failed",
-							 i);
-#else
-					do_sleep();
-#endif
-
-				}
-
-			}
-
-			fork_kid_pid[kid_count++] = ret_val;
-		}
-
-		nkids = kid_count;
-
-		/*
-		 * Now send all the kids a SIGUSR1 to tell them to
-		 * proceed. We sleep for a while first to allow the
-		 * children to initialize their "intintr" variables
-		 * and get set up.
-		 */
-		sleep(15);
+	pid_t pid;
+	int i;
 
-		for (i = 0; i < nkids; i++) {
-			if (kill(fork_kid_pid[i], SIGUSR1) < 0) {
-				tst_brkm(TBROK|TERRNO, cleanup, "Kill of child "
-						"%d failed", i);
-			}
-		}
+	for (i = 0; i < MAXKIDS; i++) {
+		pid = SAFE_FORK();
+		if (pid == 0) {
+			if (i == 0 || i == 1)
+				do_exit(0);
 
-		/* Wait till all kids have terminated. */
-		kid_count = 0;
-		errno = 0;
-		for (i = 0; i < nkids; i++) {
-			while (((ret_val = waitpid(fork_kid_pid[i],
-							&status, 0)) != -1)
-					|| (errno == EINTR)) {
-				if (ret_val == -1)
-					continue;
+			if (i == 2 || i == 3)
+				do_compute();
 
-				wait_kid_pid[kid_count++] = ret_val;
-			}
-		}
+			if (i == 4 || i == 5)
+				do_fork();
 
-		/*
-		 * Check that for every entry in the fork_kid_pid
-		 * array, there is a matching pid in the
-		 * wait_kid_pid array.
-		 */
-		for (i = 0; i < MAXKIDS; i++) {
-			found = 0;
-			for (j = 0; j < MAXKIDS; j++) {
-				if (fork_kid_pid[i] == wait_kid_pid[j]) {
-					found = 1;
-					break;
-				}
-			}
-			if (!found) {
-				tst_resm(TFAIL, "Did not find a "
-						"wait_kid_pid for the "
-						"fork_kid_pid of %d",
-						fork_kid_pid[i]);
-				for (k = 0; k < nkids; k++) {
-					tst_resm(TFAIL,
-							"fork_kid_pid[%d] = "
-							"%d", k,
-							fork_kid_pid[k]);
-				}
-				for (k = 0; k < kid_count; k++) {
-					tst_resm(TFAIL,
-							"wait_kid_pid[%d] = "
-							"%d", k,
-							wait_kid_pid[k]);
-				}
-				fail = 1;
-			}
+			if (i == 6 || i == 7)
+				do_sleep();
 		}
 
-		memset(fork_kid_pid, 0, sizeof(fork_kid_pid));
-
-		if (fail)
-			tst_resm(TFAIL, "Test FAILED");
-		else
-			tst_resm(TPASS, "Test PASSED");
+		fork_kid_pid[i] = pid;
 	}
 
-	cleanup();
-	tst_exit();
-}
-
-static void setup(void)
-{
-	struct sigaction act;
-
-	tst_sig(FORK, DEF_HANDLER, cleanup);
+	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-	TEST_PAUSE;
+	if (reap_children(0, 0, fork_kid_pid, MAXKIDS))
+		return;
 
-	act.sa_handler = inthandlr;
-	act.sa_flags = SA_RESTART;
-	sigemptyset(&act.sa_mask);
-
-	if (sigaction(SIGUSR1, &act, NULL) < 0)
-		tst_brkm(TBROK|TERRNO, cleanup,
-			 "sigaction(SIGUSR1, ...) failed");
-
-	intintr = 0;
-
-}
-
-static void cleanup(void)
-{
-	int i;
-
-	for (i = 0; i < MAXKIDS; i++) {
-		if (fork_kid_pid[i] > 0)
-			kill(fork_kid_pid[i], SIGKILL);
-	}
-}
-
-static void inthandlr(void)
-{
-	intintr++;
-}
-
-static void wait_for_parent(void)
-{
-	while (!intintr)
-		usleep(100);
-}
-
-static void do_exit(void)
-{
-	wait_for_parent();
-	exit(3);
+	tst_res(TPASS, "Test PASSED");
 }
 
 static void do_compute(void)
 {
 	int i;
 
-	wait_for_parent();
+	TST_CHECKPOINT_WAIT(0);
 
 	for (i = 0; i < 100000; i++) ;
 	for (i = 0; i < 100000; i++) ;
@@ -283,57 +79,43 @@ static void do_compute(void)
 	for (i = 0; i < 100000; i++) ;
 	for (i = 0; i < 100000; i++) ;
 
-	exit(4);
+	exit(3);
 }
 
 static void do_fork(void)
 {
-	int fork_pid, wait_pid;
-	int status, i;
+	pid_t fork_pid;
+	int i;
 
-	wait_for_parent();
+	TST_CHECKPOINT_WAIT(0);
 
 	for (i = 0; i < 50; i++) {
-		fork_pid = FORK_OR_VFORK();
-		if (fork_pid < 0) {
-			tst_brkm(TBROK|TERRNO, NULL, "Fork failed");
-		}
-		if (fork_pid == 0) {
-#ifdef UCLINUX
-			if (self_exec(argv0, "n", 1) < 0) {
-				tst_brkm(TFAIL, NULL,
-					 "do_fork self_exec failed");
-			}
-#else
-			do_exit();
-#endif
-		}
-
-		errno = 0;
-		while (((wait_pid = waitpid(fork_pid, &status, 0)) != -1) ||
-		       (errno == EINTR)) {
-			if (wait_pid == -1)
-				continue;
+		fork_pid = SAFE_FORK();
+		if (fork_pid == 0)
+			exit(3);
 
-			if (fork_pid != wait_pid) {
-				tst_resm(TFAIL, "Didnt get a pid returned "
-					 "from waitpid that matches the one "
-					 "returned by fork");
-				tst_resm(TFAIL, "fork pid = %d, wait pid = "
-					 "%d", fork_pid, wait_pid);
-				fail = 1;
-			}
-		}
+		if (reap_children(fork_pid, 0, &fork_pid, 1))
+			break;
 	}
 
-	exit(4);
+	exit(3);
 }
 
 static void do_sleep(void)
 {
-	wait_for_parent();
+	TST_CHECKPOINT_WAIT(0);
+
 	sleep(1);
 	sleep(1);
 
-	exit(4);
+	exit(3);
 }
+
+static struct tst_test test = {
+	.tid = "waitpid10",
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+	.setup = waitpid_setup,
+	.cleanup = waitpid_cleanup,
+	.test_all = waitpid_test,
+};
Signature · 1 line
1.7.1
#5 lore raw

PATCH v2 3/11 Add TST_TRACE

In reply to Stanislav Kholmanskikh

---
This is a new patch in the series.

 doc/test-writing-guidelines.txt |   38 ++++++++++++++++++++++++++++++++++++++
 include/tst_test.h              |    4 ++++
 2 files changed, 42 insertions(+), 0 deletions(-)
doc/test-writing-guidelines.txt +38 -0
index 740e90c..3a3e644 100644
@@ -1226,6 +1226,44 @@ the rest of the LTP test binaries.
 WARNING: All identifiers starting with TST_ or tst_ are reserved for the
          'test.sh' library.
 
+2.2.22 Code path tracing
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+'tst_res' is a macro, so on when you define a function in one file:
+
+[source,c]
+-------------------------------------------------------------------------------
+int do_action(void)
+{
+	...
+
+	if (ok) {
+		tst_res(TPASS, "...");
+		return 0;
+	} else {
+		tst_res(TFAIL, "...");
+		return -1;
+	}
+}
+-------------------------------------------------------------------------------
+
+and call it from another file, the file and line reported by 'tst_res' in this
+function will be from the former file.
+
+'TST_TRACE' can make the analysis of such situations easier. It's a macro which
+inserts a call to 'tst_res(TINFO, ...)' in case its argument is not zero.
+In this call to 'tst_res(TINFO, ...)' the file and line will be expanded using
+the actual location of 'TST_TRACE'.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include "tst_test.h"
+
+if (TST_TRACE(do_action())) {
+	...
+}
+-------------------------------------------------------------------------------
+
 2.3.1 Basic shell test structure
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
include/tst_test.h +4 -0
index 3e2ff5b..eb3f751 100644
@@ -59,6 +59,10 @@ pid_t safe_fork(const char *filename, unsigned int lineno);
 #define SAFE_FORK() \
 	safe_fork(__FILE__, __LINE__)
 
+#define TST_TRACE(expr)							\
+	({int ret = expr;						\
+		ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; })
+
 #include "tst_safe_macros.h"
 #include "tst_safe_file_ops.h"
 #include "tst_safe_net.h"
Signature · 1 line
1.7.1
#6 lore raw

PATCH v2 3/11 Add TST_TRACE

Hi!

Quoted 2 lines

+'TST_TRACE' can make the analysis of such situations easier. It's a macro which +inserts a call to 'tst_res(TINFO, ...)' in case its argument is not zero.

^
"evaluates to non-zero"

would be more clear in this case

doc/test-writing-guidelines.txt the rest of the LTP test binaries. · line 1265

Quoted 11 lines
doc/test-writing-guidelines.txt +11 -0
+In this call to 'tst_res(TINFO, ...)' the file and line will be expanded using
+the actual location of 'TST_TRACE'.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include "tst_test.h"
+
+if (TST_TRACE(do_action())) {
+	...
+}
+-------------------------------------------------------------------------------

Maybe we should also include example test output here. Otherise the description looks good to me.

Quoted 8 lines

2.3.1 Basic shell test structure
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

include/tst_test.h +0 -0
index 3e2ff5b..eb3f751 100644

include/tst_test.h pid_t safe_fork(const char *filename, unsigned int lineno); · line 65

Quoted 7 lines
include/tst_test.h +4 -0
@@ -59,6 +59,10 @@ pid_t safe_fork(const char *filename, unsigned int lineno);
 #define SAFE_FORK() \
 	safe_fork(__FILE__, __LINE__)
 
+#define TST_TRACE(expr)							\
+	({int ret = expr;						\
+		ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; })
+

I would format this to something as:

#define TST_TRACE(expr)	                                            \
	({int ret = expr;                                           \
	  ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; }) \

But that is very minor.

Signature · 2 lines
Cyril Hrubis
[email protected]
#7 lore raw

PATCH v2 3/11 Add TST_TRACE

Quoted 9 lines · Cyril Hrubis

Hi!

Quoted 2 lines

+'TST_TRACE' can make the analysis of such situations easier. It's a macro which +inserts a call to 'tst_res(TINFO, ...)' in case its argument is not zero.

^
"evaluates to non-zero"

would be more clear in this case

Ok.

Quoted 6 lines
Quoted 6 lines
doc/test-writing-guidelines.txt +6 -0
+In this call to 'tst_res(TINFO, ...)' the file and line will be expanded using
+the actual location of 'TST_TRACE'.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include "tst_test.h"
Quoted 8 lines

doc/test-writing-guidelines.txt the rest of the LTP test binaries. · line 1265

Quoted 5 lines
doc/test-writing-guidelines.txt +5 -0
+
+if (TST_TRACE(do_action())) {
+	...
+}
+-------------------------------------------------------------------------------

Maybe we should also include example test output here. Otherise the description looks good to me.

Ok. Will add one.

Quoted 19 lines
Quoted 9 lines

2.3.1 Basic shell test structure
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

include/tst_test.h +0 -0
index 3e2ff5b..eb3f751 100644

include/tst_test.h pid_t safe_fork(const char *filename, unsigned int lineno); · line 65

Quoted 7 lines
include/tst_test.h +4 -0
@@ -59,6 +59,10 @@ pid_t safe_fork(const char *filename, unsigned int lineno);
 #define SAFE_FORK() \
 	safe_fork(__FILE__, __LINE__)
 
+#define TST_TRACE(expr)							\
+	({int ret = expr;						\
+		ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; })
+

I would format this to something as:

Quoted 5 lines
#define TST_TRACE(expr)	                                            \
	({int ret = expr;                                           \
	  ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; }) \

But that is very minor.

No problem, will do it.

Quoted 1 line
#8 lore raw

PATCH v2 4/11 syscalls/waitpid: call reap_children() via TST_TRACE()

In reply to Stanislav Kholmanskikh

To make the tracing of the failed code path easier.

---
This is a new patch in the series.

 testcases/kernel/syscalls/waitpid/waitpid06.c |    2 +-
 testcases/kernel/syscalls/waitpid/waitpid07.c |    2 +-
 testcases/kernel/syscalls/waitpid/waitpid08.c |    2 +-
 testcases/kernel/syscalls/waitpid/waitpid10.c |    4 ++--
 testcases/kernel/syscalls/waitpid/waitpid11.c |    5 +++--
 5 files changed, 8 insertions(+), 7 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid06.c +1 -1
index 66d5ebc..20c30e1 100644
@@ -48,7 +48,7 @@ static void do_child_1(void)
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-	if (reap_children(-1, 0, fork_kid_pid, MAXKIDS))
+	if (TST_TRACE(reap_children(-1, 0, fork_kid_pid, MAXKIDS)))
 		return;
 
 	tst_res(TPASS, "Test PASSED");
testcases/kernel/syscalls/waitpid/waitpid07.c +1 -1
index 74da914..47ebf9a 100644
@@ -57,7 +57,7 @@ static void do_child_1(void)
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-	if (reap_children(-1, WNOHANG, fork_kid_pid, MAXKIDS))
+	if (TST_TRACE(reap_children(-1, WNOHANG, fork_kid_pid, MAXKIDS)))
 		return;
 
 	tst_res(TPASS, "Test PASSED");
testcases/kernel/syscalls/waitpid/waitpid08.c +1 -1
index 0f0ee9d..b95a308 100644
@@ -61,7 +61,7 @@ static void do_child_1(void)
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-	if (reap_children(-1, WUNTRACED, fork_kid_pid, MAXKIDS))
+	if (TST_TRACE(reap_children(-1, WUNTRACED, fork_kid_pid, MAXKIDS)))
 		return;
 
 	/*
testcases/kernel/syscalls/waitpid/waitpid10.c +2 -2
index a505ade..90b3800 100644
@@ -56,7 +56,7 @@ static void do_child_1(void)
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-	if (reap_children(0, 0, fork_kid_pid, MAXKIDS))
+	if (TST_TRACE(reap_children(0, 0, fork_kid_pid, MAXKIDS)))
 		return;
 
 	tst_res(TPASS, "Test PASSED");
@@ -94,7 +94,7 @@ static void do_fork(void)
 		if (fork_pid == 0)
 			exit(3);
 
-		if (reap_children(fork_pid, 0, &fork_pid, 1))
+		if (TST_TRACE(reap_children(fork_pid, 0, &fork_pid, 1)))
 			break;
 	}
 
testcases/kernel/syscalls/waitpid/waitpid11.c +3 -2
index 9b51e04..1067bca 100644
@@ -50,11 +50,12 @@ static void do_child_1(void)
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-	if (reap_children(0, 0, fork_kid_pid + (MAXKIDS / 2), MAXKIDS / 2))
+	if (TST_TRACE(reap_children(0, 0, fork_kid_pid + (MAXKIDS / 2),
+				    MAXKIDS / 2)))
 		return;
 
 	/* Make sure can pickup children in a diff. process group */
-	if (reap_children(-group, 0, fork_kid_pid, MAXKIDS / 2))
+	if (TST_TRACE(reap_children(-group, 0, fork_kid_pid, MAXKIDS / 2)))
 		return;
 
 	tst_res(TPASS, "Test PASSED");
Signature · 1 line
1.7.1
#9 lore raw

PATCH v2 4/11 syscalls/waitpid: call reap_children() via TST_TRACE()

Hi!
This is obviously correct.

testcases/kernel/syscalls/waitpid/waitpid11.c static void do_child_1(void) · line 55

Quoted 12 lines
testcases/kernel/syscalls/waitpid/waitpid11.c +2 -1
index 9b51e04..1067bca 100644
@@ -50,11 +50,12 @@ static void do_child_1(void)
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-	if (reap_children(0, 0, fork_kid_pid + (MAXKIDS / 2), MAXKIDS / 2))
+	if (TST_TRACE(reap_children(0, 0, fork_kid_pid + (MAXKIDS / 2),
+				    MAXKIDS / 2)))
 		return;

Hmm, if we drop the useless parenthesis and spaces around / we will fit into 80 chars:

	if (TST_TRACE(reap_children(0, 0, fork_kid_pid + MAXKIDS/2, MAXKIDS/2)))
		return;
Signature · 2 lines
Cyril Hrubis
[email protected]
#10 lore raw

PATCH v2 4/11 syscalls/waitpid: call reap_children() via TST_TRACE()

Quoted 19 lines · Cyril Hrubis

Hi!
This is obviously correct.

testcases/kernel/syscalls/waitpid/waitpid11.c static void do_child_1(void) · line 55

Quoted 12 lines
testcases/kernel/syscalls/waitpid/waitpid11.c +2 -1
index 9b51e04..1067bca 100644
@@ -50,11 +50,12 @@ static void do_child_1(void)
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-	if (reap_children(0, 0, fork_kid_pid + (MAXKIDS / 2), MAXKIDS / 2))
+	if (TST_TRACE(reap_children(0, 0, fork_kid_pid + (MAXKIDS / 2),
+				    MAXKIDS / 2)))
 		return;

Hmm, if we drop the useless parenthesis and spaces around / we will fit into 80 chars:

Quoted 3 lines
	if (TST_TRACE(reap_children(0, 0, fork_kid_pid + MAXKIDS/2, MAXKIDS/2)))
		return;

Ok.

#11 lore raw

PATCH v2 5/11 syscalls/waitpid: implement waitpid_ret_test()

In reply to Stanislav Kholmanskikh

Several test cases call waitpid() and then verify the returned value and errno set. Moved this code into a function.

---
Changes since V1:
* Use TST_TRACE

 testcases/kernel/syscalls/waitpid/waitpid07.c      |    6 +---
 testcases/kernel/syscalls/waitpid/waitpid08.c      |   25 +---------------
 testcases/kernel/syscalls/waitpid/waitpid_common.h |   29 ++++++++++++++++++++
 3 files changed, 32 insertions(+), 28 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid07.c +1 -5
index 47ebf9a..9166fbe 100644
@@ -48,12 +48,8 @@ static void do_child_1(void)
 	}
 
 	/* Check that waitpid with WNOHANG returns zero */
-	pid = waitpid(-1, &status, WNOHANG);
-	if (pid != 0) {
-		tst_res(TFAIL, "waitpid() returned %d, expected 0",
-			pid);
+	if (TST_TRACE(waitpid_ret_test(-1, &status, WNOHANG, 0, 0)))
 		return;
-	}
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
testcases/kernel/syscalls/waitpid/waitpid08.c +2 -23
index b95a308..6c8d3b9 100644
@@ -51,36 +51,15 @@ static void do_child_1(void)
 	/* Check that waitpid with WNOHANG|WUNTRACED returns
 	 * zero
 	 */
-	pid = waitpid(-1, &status, WNOHANG | WUNTRACED);
-	if (pid != 0) {
-		tst_res(TFAIL,
-			"waitpid(WNOHANG | WUNTRACED) returned %d, expected 0",
-			pid);
+	if (TST_TRACE(waitpid_ret_test(-1, &status, WNOHANG | WUNTRACED,
+				       0, 0)))
 		return;
-	}
 
 	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
 	if (TST_TRACE(reap_children(-1, WUNTRACED, fork_kid_pid, MAXKIDS)))
 		return;
 
-	/*
-	 * Check that waitpid(WUNTRACED) returns -1 when no
-	 * stopped children
-	 */
-	pid = waitpid(-1, &status, WUNTRACED);
-	if (pid != -1) {
-		tst_res(TFAIL, "waitpid(WUNTRACED) returned %d, expected -1",
-			pid);
-		return;
-	}
-
-	if (errno != ECHILD) {
-		tst_res(TFAIL, "waitpid(WUNTRACED) set errno %s, expected %s",
-			tst_strerrno(errno), tst_strerrno(ECHILD));
-		return;
-	}
-
 	tst_res(TPASS, "Test PASSED");
 }
 
testcases/kernel/syscalls/waitpid/waitpid_common.h +29 -0
index 008577a..f5e9519 100644
@@ -75,6 +75,35 @@ static void do_exit(int stop)
 	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;
Signature · 1 line
1.7.1
#12 lore raw

PATCH v2 5/11 syscalls/waitpid: implement waitpid_ret_test()

Hi!

testcases/kernel/syscalls/waitpid/waitpid08.c static void do_child_1(void) · line 56

Quoted 3 lines
testcases/kernel/syscalls/waitpid/waitpid08.c +2 -0
+	if (TST_TRACE(waitpid_ret_test(-1, &status, WNOHANG | WUNTRACED,
+				       0, 0)))
 		return;

Hmm, I know this is merely cosmetic but as far as I can tell the line fits into 80 chars. Or did checkpatch complained since it has precisely 80 chars?

If that is the case what about shortening the waitpid_ret_test() to waitpid_test()?

Signature · 2 lines
Cyril Hrubis
[email protected]
#13 lore raw

PATCH v2 5/11 syscalls/waitpid: implement waitpid_ret_test()

Quoted 8 lines · Cyril Hrubis

Hi!

testcases/kernel/syscalls/waitpid/waitpid08.c static void do_child_1(void) · line 56

Quoted 3 lines
testcases/kernel/syscalls/waitpid/waitpid08.c +2 -0
+	if (TST_TRACE(waitpid_ret_test(-1, &status, WNOHANG | WUNTRACED,
+				       0, 0)))
 		return;

Hmm, I know this is merely cosmetic but as far as I can tell the line fits into 80 chars. Or did checkpatch complained since it has precisely 80 chars?

No, it didn't complain about that. I'll put this all on one line.

Quoted 4 lines

If that is the case what about shortening the waitpid_ret_test() to waitpid_test()?

#14 lore raw

PATCH v2 6/11 syscalls/waitpid: make reap_children() fail if errno is not ECHILD

In reply to Stanislav Kholmanskikh

We expect that waitpid() may fail only with EINTR or ECHILD. All other errno values signal about an error.

---
No changes since V1.

 testcases/kernel/syscalls/waitpid/waitpid_common.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid_common.h +3 -0
index f5e9519..f724a17 100644
@@ -117,6 +117,9 @@ static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len)
 			if (errno == EINTR)
 				continue;
 
+			if (waitpid_errno_check(errno, ECHILD))
+				return -1;
+
 			break;
 		}
 
Signature · 1 line
1.7.1
#15 lore raw

PATCH v2 7/11 waitpid11: update the description

In reply to Stanislav Kholmanskikh

---
No changes since V1.

 testcases/kernel/syscalls/waitpid/waitpid11.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid11.c +1 -1
index 1067bca..532c1db 100644
@@ -25,7 +25,7 @@
  *	Tests to see if pids returned from fork and waitpid are same
  *
  * ALGORITHM
- * 	Check proper functioning of waitpid with pid = -1 and arg = 0
+ *	Check proper functioning of waitpid with pid = 0 and < -1 with arg 0
  */
 
 #include "waitpid_common.h"
Signature · 1 line
1.7.1
#16 lore raw

PATCH v2 8/11 waitpid12: use the new API

In reply to Stanislav Kholmanskikh

---
No changes since V1.

 testcases/kernel/syscalls/waitpid/waitpid12.c |  353 ++++---------------------
 1 files changed, 52 insertions(+), 301 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid12.c +52 -301
index bf64662..b2db49d 100644
@@ -1,329 +1,80 @@
 /*
+ * Copyright (c) International Business Machines  Corp., 2001
  *
- *   Copyright (c) International Business Machines  Corp., 2001
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- *   This program is free software;  you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
  *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
- *   the GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program;  if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * NAME
- *	waitpid12.c
- *
- * DESCRIPTION
- *	Tests to see if pid's returned from fork and waitpid are same
- *
- * ALGORITHM
- *	Check proper functioning of waitpid with pid = -1 and arg = WNOHANG
- *
- * USAGE:  <for command-line>
- *      waitpid12 [-c n] [-t]
- *      where,  -c n : Run n copies concurrently.
- *              -t   : Turn on syscall timing.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
  *
  * History
  *	07/2001 John George
  *		-Ported
  *      04/2002 wjhuie sigset testx for SIG_ERR not < 0, TPASS|TFAIL issued
  *      04/2002 wjhuie sigset cleanups
- *
- * Restrictions
- *	None
  */
 
-#include <sys/types.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include "test.h"
-
-#define	MAXKIDS	8
-
-char *TCID = "waitpid12";
-int TST_TOTAL = 1;
-
-volatile int intintr;
-static void setup(void);
-static void cleanup(void);
-static void inthandlr();
-static void wait_for_parent(void);
-static void do_exit(void);
-static void setup_sigint(void);
-#ifdef UCLINUX
-static void do_exit_uclinux(void);
-#endif
+/*
+ * DESCRIPTION
+ *	Tests to see if pids returned from fork and waitpid are same
+ *
+ * ALGORITHM
+ *	Check proper functioning of waitpid with pid = 0 and < -1 with arg
+ *	WNOHANG
+ */
 
-static int fail;
+#include "waitpid_common.h"
 
-int main(int argc, char **argv)
+static void do_child_1(void)
 {
-	int kid_count, ret_val, status;
-	int i, j, k, found;
-	int group1, group2;
-	int fork_kid_pid[MAXKIDS], wait_kid_pid[MAXKIDS];
-	int pid;
-
-	tst_parse_opts(argc, argv, NULL, NULL);
-
-#ifdef UCLINUX
-	maybe_run_child(&do_exit_uclinux, "");
-#endif
-
-	setup();
-
-	tst_count = 0;
-	fail = 0;
-
-	/*
-	 * Need to have test run from child as test driver causes
-	 * test to be a session leader and setpgrp fails.
-	 */
-
-	pid = FORK_OR_VFORK();
-	if (pid > 0) {
-		waitpid(pid, &status, 0);
-		if (WEXITSTATUS(status) != 0) {
-			tst_resm(TFAIL, "child returned bad status");
-			fail = 1;
-		}
-		if (fail)
-			tst_resm(TFAIL, "%s FAILED", TCID);
-		else
-			tst_resm(TPASS, "%s PASSED", TCID);
-		cleanup();
-		tst_exit();
-	} else if (pid < 0) {
-		tst_brkm(TBROK, cleanup, "fork failed");
-	}
-
-	/*
-	 * Set up to catch SIGINT.  The kids will wait till a SIGINT
-	 * has been received before they proceed.
-	 */
-	setup_sigint();
-
-	group1 = getpgrp();
-
-	for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
-		if (kid_count == (MAXKIDS / 2))
-			group2 = setpgrp();
-
-		intintr = 0;
-		ret_val = FORK_OR_VFORK();
-		if (ret_val == 0) {
-#ifdef UCLINUX
-			if (self_exec(argv[0], "") < 0)
-				tst_resm(TFAIL, "self_exec kid %d "
-					 "failed", kid_count);
-#else
-			do_exit();
-#endif
-		}
-
-		if (ret_val < 0)
-			tst_resm(TFAIL | TERRNO, "forking kid %d failed",
-				 kid_count);
-
-		/* parent */
-		fork_kid_pid[kid_count] = ret_val;
-	}
-
-	/* Check that waitpid with WNOHANG returns zero */
-	ret_val = waitpid(0, &status, WNOHANG);
-	if (ret_val != 0) {
-		tst_resm(TFAIL, "Waitpid returned wrong value");
-		tst_resm(TFAIL, "Expected 0 got %d", ret_val);
-		fail = 1;
-	}
-#ifdef UCLINUX
-	/* Give the kids a chance to setup SIGINT again, since this is
-	 * cleared by exec().
-	 */
-	sleep(3);
-#endif
-
-	/* Now send all the kids a SIGINT to tell them to proceed */
-	for (i = 0; i < MAXKIDS; i++)
-		if (kill(fork_kid_pid[i], SIGINT) < 0)
-			tst_resm(TFAIL | TERRNO, "killing child %d failed", i);
-
-	/*
-	 * Wait till all kids have terminated.  Stash away their
-	 * pid's in an array.
-	 */
-	kid_count = 0;
-	errno = 0;
-	sleep(2);
-	while (((ret_val = waitpid(0, &status, WNOHANG)) != -1) ||
-	       (errno == EINTR)) {
-		if ((ret_val == -1) || (ret_val == 0))
-			continue;
-
-		if (!WIFEXITED(status)) {
-			tst_resm(TFAIL, "Child %d did not exit "
-				 "normally", ret_val);
-			fail = 1;
-		} else {
-			if (WEXITSTATUS(status) != 3) {
-				tst_resm(TFAIL, "Child %d exited with "
-					 "wrong status", ret_val);
-				tst_resm(TFAIL, "Expected 3 got %d",
-					 WEXITSTATUS(status));
-				fail = 1;
-			}
-		}
-		wait_kid_pid[kid_count++] = ret_val;
-	}
-
-	/*
-	 * Check that for every entry in the fork_kid_pid array,
-	 * there is a matching pid in the wait_kid_pid array.  If
-	 * not, it's an error.
-	 */
-	for (i = 0; i < kid_count; i++) {
-		found = 0;
-		for (j = (MAXKIDS / 2); j < MAXKIDS; j++) {
-			if (fork_kid_pid[j] == wait_kid_pid[i]) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found) {
-			tst_resm(TFAIL, "Did not find a wait_kid_pid "
-				 "for the fork_kid_pid of %d", wait_kid_pid[i]);
-			for (k = 0; k < MAXKIDS; k++)
-				tst_resm(TFAIL, "fork_kid_pid[%d] = "
-					 "%d", k, fork_kid_pid[k]);
-			for (k = 0; k < kid_count; k++)
-				tst_resm(TFAIL, "wait_kid_pid[%d] = "
-					 "%d", k, wait_kid_pid[k]);
-			fail = 1;
-		}
-	}
+	pid_t pid, group;
+	int i;
+	int status;
 
-	if (kid_count != (MAXKIDS / 2)) {
-		tst_resm(TFAIL, "Wrong number of children waited on "
-			 "for pid = 0");
-		tst_resm(TFAIL, "Expected 4 got %d", kid_count);
-		fail = 1;
-	}
+	group = SAFE_GETPGID(0);
 
-	/* Make sure can pickup children in a diff. process group */
+	for (i = 0; i < MAXKIDS; i++) {
+		if (i == (MAXKIDS / 2))
+			SAFE_SETPGID(0, 0);
 
-	kid_count = 0;
-	errno = 0;
-	while (((ret_val = waitpid(-(group1), &status, WNOHANG)) !=
-		-1) || (errno == EINTR)) {
-		if (ret_val == -1 || ret_val == 0)
-			continue;
+		pid = SAFE_FORK();
+		if (pid == 0)
+			do_exit(0);
 
-		if (!WIFEXITED(status)) {
-			tst_resm(TFAIL, "Child %d did not exit "
-				 "normally", ret_val);
-			fail = 1;
-		} else {
-			if (WEXITSTATUS(status) != 3) {
-				tst_resm(TFAIL, "Child %d exited with "
-					 "wrong status", ret_val);
-				tst_resm(TFAIL, "Expected 3 got %d",
-					 WEXITSTATUS(status));
-				fail = 1;
-			}
-		}
-		wait_kid_pid[kid_count++] = ret_val;
+		fork_kid_pid[i] = pid;
 	}
 
-	/*
-	 * Check that for every entry in the fork_kid_pid array,
-	 * there is a matching pid in the wait_kid_pid array.  If
-	 * not, it's an error.
-	 */
-	for (i = 0; i < kid_count; i++) {
-		found = 0;
-		for (j = 0; j < (MAXKIDS / 2); j++) {
-			if (fork_kid_pid[j] == wait_kid_pid[i]) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found) {
-			tst_resm(TFAIL, "Did not find a wait_kid_pid "
-				 "for the fork_kid_pid of %d", fork_kid_pid[j]);
-			for (k = 0; k < MAXKIDS; k++)
-				tst_resm(TFAIL, "fork_kid_pid[%d] = "
-					 "%d", k, fork_kid_pid[k]);
-			for (k = 0; k < kid_count; k++)
-				tst_resm(TFAIL, "wait_kid_pid[%d] = "
-					 "%d", k, wait_kid_pid[k]);
-			fail = 1;
-		}
-	}
-	if (kid_count != (MAXKIDS / 2)) {
-		tst_resm(TFAIL, "Wrong number of children waited on "
-			 "for pid = 0");
-		tst_resm(TFAIL, "Expected 4 got %d", kid_count);
-		fail = 1;
-	}
+	if (TST_TRACE(waitpid_ret_test(0, &status, WNOHANG, 0, 0)))
+		return;
 
-	if (fail)
-		tst_resm(TFAIL, "Test FAILED");
-	else
-		tst_resm(TPASS, "Test PASSED");
+	if (TST_TRACE(waitpid_ret_test(-group, &status, WNOHANG, 0, 0)))
+		return;
 
-	tst_exit();
-}
+	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-static void setup_sigint(void)
-{
-	if (signal(SIGINT, inthandlr) == SIG_ERR)
-		tst_brkm(TFAIL | TERRNO, NULL, "signal SIGINT failed");
-}
+	if (TST_TRACE(reap_children(0, WNOHANG, fork_kid_pid + (MAXKIDS / 2),
+				    MAXKIDS / 2)))
+		return;
 
-static void setup(void)
-{
-	tst_sig(FORK, DEF_HANDLER, cleanup);
+	if (TST_TRACE(reap_children(-group, WNOHANG, fork_kid_pid,
+				    MAXKIDS / 2)))
+		return;
 
-	TEST_PAUSE;
+	tst_res(TPASS, "Test PASSED");
 }
 
-static void cleanup(void)
-{
-}
-
-static void inthandlr(void)
-{
-	intintr++;
-}
-
-static void wait_for_parent(void)
-{
-	int testvar;
-
-	while (!intintr)
-		testvar = 0;
-}
-
-static void do_exit(void)
-{
-	wait_for_parent();
-	exit(3);
-}
-
-#ifdef UCLINUX
-static void do_exit_uclinux(void)
-{
-	setup_sigint();
-	do_exit();
-}
-#endif
+static struct tst_test test = {
+	.tid = "waitpid12",
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+	.setup = waitpid_setup,
+	.cleanup = waitpid_cleanup,
+	.test_all = waitpid_test,
+};
Signature · 1 line
1.7.1
#17 lore raw

PATCH v2 9/11 syscalls/waitpid: adapt reap_children() to test stopped children

In reply to Stanislav Kholmanskikh

If the pid returned by waitpid() is the pid of a stopped child, we send it the SIGCONT signal.

---
This is a new patch in the series, extracted from V1 of waitpid13.c

 testcases/kernel/syscalls/waitpid/waitpid_common.h |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid_common.h +17 -0
index f724a17..7b67a06 100644
@@ -131,6 +131,23 @@ static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len)
 			return -1;
 		}
 
+		if (WIFSTOPPED(status)) {
+			if (WSTOPSIG(status) != SIGSTOP) {
+				tst_res(TFAIL,
+					"Pid %d: expected SIGSTOP, got %d",
+					pid, WSTOPSIG(status));
+				return -1;
+			}
+
+			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;
Signature · 1 line
1.7.1
#18 lore raw

PATCH v2 9/11 syscalls/waitpid: adapt reap_children() to test stopped children

Hi!

Quoted 15 lines

If the pid returned by waitpid() is the pid of a stopped child, we send it the SIGCONT signal.

---
This is a new patch in the series, extracted from V1 of waitpid13.c

 testcases/kernel/syscalls/waitpid/waitpid_common.h |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid_common.h +0 -0
index f724a17..7b67a06 100644

testcases/kernel/syscalls/waitpid/waitpid_common.h static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len) · line 140

Quoted 10 lines
testcases/kernel/syscalls/waitpid/waitpid_common.h +7 -0
@@ -131,6 +131,23 @@ static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len)
 			return -1;
 		}
 
+		if (WIFSTOPPED(status)) {
+			if (WSTOPSIG(status) != SIGSTOP) {
+				tst_res(TFAIL,
+					"Pid %d: expected SIGSTOP, got %d",
+					pid, WSTOPSIG(status));
+				return -1;
+			}

Maybe we should print tst_res(TINFO, "Seding SIGCONT to %i", pid); here.

testcases/kernel/syscalls/waitpid/waitpid_common.h static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len) · line 153

Quoted 12 lines
testcases/kernel/syscalls/waitpid/waitpid_common.h +9 -0
+			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;

Otherwise it looks good.

I guess that there is no real chance that some of the children in testcases that use this function would be SIGSTOPed accidentally and this code will make that bug disappear...

Signature · 2 lines
Cyril Hrubis
[email protected]
#19 lore raw

PATCH v2 9/11 syscalls/waitpid: adapt reap_children() to test stopped children

Quoted 19 lines · Cyril Hrubis

Hi!

Quoted 18 lines

If the pid returned by waitpid() is the pid of a stopped child, we send it the SIGCONT signal.

---
This is a new patch in the series, extracted from V1 of waitpid13.c

 testcases/kernel/syscalls/waitpid/waitpid_common.h |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid_common.h +0 -0
index f724a17..7b67a06 100644
@@ -131,6 +131,23 @@ static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len)
 			return -1;
 		}
 
Quoted 9 lines

testcases/kernel/syscalls/waitpid/waitpid_common.h static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len) · line 140

Quoted 7 lines
testcases/kernel/syscalls/waitpid/waitpid_common.h +7 -0
+		if (WIFSTOPPED(status)) {
+			if (WSTOPSIG(status) != SIGSTOP) {
+				tst_res(TFAIL,
+					"Pid %d: expected SIGSTOP, got %d",
+					pid, WSTOPSIG(status));
+				return -1;
+			}

Maybe we should print tst_res(TINFO, "Seding SIGCONT to %i", pid); here.

Ok.

Quoted 16 lines

testcases/kernel/syscalls/waitpid/waitpid_common.h static int reap_children(pid_t wp_pid, int wp_opts, pid_t *children, int len) · line 153

Quoted 13 lines
testcases/kernel/syscalls/waitpid/waitpid_common.h +9 -0
+			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;

Otherwise it looks good.

Quoted 4 lines

I guess that there is no real chance that some of the children in testcases that use this function would be SIGSTOPed accidentally and this code will make that bug disappear...

Yes. I agree.

#20 lore raw

PATCH v2 10/11 waitpid13: use the new API

In reply to Stanislav Kholmanskikh

---
Changes since V1:
* the part modifying waitpid_common.h is in a separate (the previous) patch

 testcases/kernel/syscalls/waitpid/waitpid13.c |  401 +++----------------------
 1 files changed, 50 insertions(+), 351 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid13.c +50 -351
index 5f03592..13377c8 100644
@@ -1,382 +1,81 @@
 /*
+ * Copyright (c) International Business Machines  Corp., 2001
  *
- *   Copyright (c) International Business Machines  Corp., 2001
+ * This program is free software;  you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- *   This program is free software;  you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or
- *   (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ * the GNU General Public License for more details.
  *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
- *   the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
  *
- *   You should have received a copy of the GNU General Public License
- *   along with this program;  if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * History
+ *	07/2001 John George
+ *		-Ported
+ *      04/2002 wjhuie sigset cleanups
  */
 
 /*
- * NAME
- *	waitpid13.c
- *
  * DESCRIPTION
- *	Tests to see if pid's returned from fork and waitpid are same
+ *	Tests to see if pids returned from fork and waitpid are same
  *
  * ALGORITHM
  *	Check proper functioning of waitpid with pid = 0 and < -1 with arg
  *	WUNTRACED
- *
- * USAGE:  <for command-line>
- *      waitpid13 [-c n] [-t]
- *      where,  -c n : Run n copies concurrently.
- *              -t   : Turn on syscall timing.
- *
- * History
- *	07/2001 John George
- *		-Ported
- *      04/2002 wjhuie sigset cleanups
- *
- * Restrictions
- *	None
  */
 
-#include <sys/types.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include "test.h"
-
-#define	MAXKIDS	8
-
-char *TCID = "waitpid13";
-int TST_TOTAL = 1;
-
-volatile int intintr;
-static void setup(void);
-static void cleanup(void);
-static void inthandlr();
-static void wait_for_parent(void);
-static void do_exit(void);
-static void setup_sigint(void);
-#ifdef UCLINUX
-static void do_exit_uclinux(void);
-#endif
-
-static int fail;
+#include "waitpid_common.h"
 
-int main(int ac, char **av)
+static void do_child_1(void)
 {
-	int kid_count, ret_val, status;
-	int i, j, k, found;
-	int group1, group2;
-	int fork_kid_pid[MAXKIDS], wait_kid_pid[MAXKIDS];
-	int pid;
+	pid_t pid, group;
+	int i;
+	int status;
 
-	tst_parse_opts(ac, av, NULL, NULL);
-
-#ifdef UCLINUX
-	maybe_run_child(&do_exit_uclinux, "");
-#endif
-
-	setup();
-
-	tst_count = 0;
-	fail = 0;
-
-	/*
-	 * Need to have test run from child as test driver causes
-	 * test to be a session leader and setpgrp fails.
-	 */
-	pid = FORK_OR_VFORK();
-	if (pid > 0) {
-		waitpid(pid, &status, 0);
-		if (WEXITSTATUS(status) != 0) {
-			tst_resm(TFAIL, "child returned bad status");
-			fail = 1;
-		}
-		if (fail)
-			tst_resm(TFAIL, "%s FAILED", TCID);
-		else
-			tst_resm(TPASS, "%s PASSED", TCID);
-
-		cleanup();
-		tst_exit();
-	} else if (pid < 0) {
-		tst_brkm(TBROK, cleanup, "fork failed");
-	}
-
-	/*
-	 * Set up to catch SIGINT.  The kids will wait till a SIGINT
-	 * has been received before they proceed.
-	 */
-	setup_sigint();
-
-	group1 = getpgrp();
-
-	for (kid_count = 0; kid_count < MAXKIDS; kid_count++) {
-		if (kid_count == (MAXKIDS / 2))
-			group2 = setpgrp();
-
-		intintr = 0;
-		ret_val = FORK_OR_VFORK();
-		if (ret_val == 0) {
-#ifdef UCLINUX
-			if (self_exec(av[0], "") < 0) {
-				tst_resm(TFAIL | TERRNO, "self_exec kid %d "
-					 "failed", kid_count);
-
-			}
-#else
-			do_exit();
-#endif
-		}
-
-		if (ret_val < 0)
-			tst_resm(TFAIL | TERRNO, "forking kid %d failed",
-				 kid_count);
-
-		/* parent */
-		fork_kid_pid[kid_count] = ret_val;
-	}
-
-	/* Check that waitpid with WNOHANG|WUNTRACED returns zero */
-	ret_val = waitpid(0, &status, WNOHANG | WUNTRACED);
-	if (ret_val != 0) {
-		tst_resm(TFAIL, "Waitpid returned wrong value"
-			 "from waitpid(WNOHANG|WUNTRACED)");
-		tst_resm(TFAIL, "Expected 0 got %d", ret_val);
-		fail = 1;
-	}
-#ifdef UCLINUX
-	/* Give the kids a chance to setup SIGINT again, since this is
-	 * cleared by exec().
-	 */
-	sleep(3);
-#endif
+	group = SAFE_GETPGID(0);
 
-	/* Now send all the kids a SIGINT to tell them to proceed */
 	for (i = 0; i < MAXKIDS; i++) {
-		if (kill(fork_kid_pid[i], SIGINT) < 0) {
-			tst_resm(TFAIL | TERRNO, "killing child %d failed", i);
-			fail = 1;
-		}
-	}
-
-	/*
-	 * Wait till all kids have terminated.  Stash away their
-	 * pid's in an array.
-	 */
-	kid_count = 0;
-	errno = 0;
-	while (((ret_val = waitpid(0, &status, WUNTRACED)) != -1) ||
-	       (errno == EINTR)) {
-		if (ret_val == -1)
-			continue;
-
-		if (!WIFEXITED(status)) {
-			if (!WIFSTOPPED(status)) {
-				tst_resm(TFAIL, "Child %d is not "
-					 "stopped", ret_val);
-				fail = 1;
-			} else {
-				if (WSTOPSIG(status) != SIGSTOP) {
-					tst_resm(TFAIL, "Child %d "
-						 "exited with wrong "
-						 "status", ret_val);
-					tst_resm(TFAIL, "Expected "
-						 "SIGSTOP got %d",
-						 WEXITSTATUS(status));
-					fail = 1;
-				}
-			}
-			if (kill(ret_val, SIGCONT) < 0) {
-				tst_resm(TFAIL | TERRNO,
-					 "killing child %d failed", ret_val);
-				fail = 1;
-			}
-		}
-		found = 0;
-		for (j = 0; j < kid_count; j++) {
-			if (ret_val == wait_kid_pid[j]) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			wait_kid_pid[kid_count++] = ret_val;
-	}
-
-	/*
-	 * Check that for every entry in the fork_kid_pid array,
-	 * there is a matching pid in the wait_kid_pid array.  If
-	 * not, it's an error.
-	 */
-	for (i = 0; i < kid_count; i++) {
-		found = 0;
-		for (j = (MAXKIDS / 2); j < MAXKIDS; j++) {
-			if (fork_kid_pid[j] == wait_kid_pid[i]) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found) {
-			tst_resm(TFAIL, "Did not find a wait_kid_pid "
-				 "for the fork_kid_pid of %d", wait_kid_pid[i]);
-			for (k = 0; k < MAXKIDS; k++)
-				tst_resm(TFAIL, "fork_kid_pid[%d] = "
-					 "%d", k, fork_kid_pid[k]);
-			for (k = 0; k < kid_count; k++)
-				tst_resm(TFAIL, "wait_kid_pid[%d] = "
-					 "%d", k, wait_kid_pid[k]);
-			fail = 1;
-		}
-	}
-
-	if (kid_count != (MAXKIDS / 2)) {
-		tst_resm(TFAIL, "Wrong number of children waited on "
-			 "for pid = 0");
-		tst_resm(TFAIL, "Expected %d got %d", MAXKIDS, kid_count);
-		fail = 1;
-	}
+		if (i == (MAXKIDS / 2))
+			SAFE_SETPGID(0, 0);
 
-	/* Make sure can pickup children in a diff. process group */
+		pid = SAFE_FORK();
+		if (pid == 0)
+			do_exit(1);
 
-	kid_count = 0;
-	errno = 0;
-	while (((ret_val = waitpid(-(group1), &status, WUNTRACED)) !=
-		-1) || (errno == EINTR)) {
-		if (ret_val == -1)
-			continue;
-		if (!WIFEXITED(status)) {
-			if (!WIFSTOPPED(status)) {
-				tst_resm(TFAIL, "Child %d is not "
-					 "stopped", ret_val);
-				fail = 1;
-			} else {
-				if (WSTOPSIG(status) != SIGSTOP) {
-					tst_resm(TFAIL, "Child %d "
-						 "exited with wrong "
-						 "status", ret_val);
-					tst_resm(TFAIL, "Expected "
-						 "SIGSTOP got %d",
-						 WEXITSTATUS(status));
-					fail = 1;
-				}
-			}
-			if (kill(ret_val, SIGCONT) < 0) {
-				tst_resm(TFAIL | TERRNO,
-					 "Killing child %d failed", ret_val);
-				fail = 1;
-			}
-		}
-		found = 0;
-		for (j = 0; j < kid_count; j++) {
-			if (ret_val == wait_kid_pid[j]) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			wait_kid_pid[kid_count++] = ret_val;
+		fork_kid_pid[i] = pid;
 	}
 
-	/*
-	 * Check that for every entry in the fork_kid_pid array,
-	 * there is a matching pid in the wait_kid_pid array.  If
-	 * not, it's an error.
-	 */
-	for (i = 0; i < kid_count; i++) {
-		found = 0;
-		for (j = 0; j < (MAXKIDS / 2); j++) {
-			if (fork_kid_pid[j] == wait_kid_pid[i]) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found) {
-			tst_resm(TFAIL, "Did not find a wait_kid_pid "
-				 "for the fork_kid_pid of %d", fork_kid_pid[j]);
-			for (k = 0; k < MAXKIDS; k++)
-				tst_resm(TFAIL, "fork_kid_pid[%d] = "
-					 "%d", k, fork_kid_pid[k]);
-			for (k = 0; k < kid_count; k++)
-				tst_resm(TFAIL, "wait_kid_pid[%d] = "
-					 "%d", k, wait_kid_pid[k]);
-			fail = 1;
-		}
-	}
-	if (kid_count != (MAXKIDS / 2)) {
-		tst_resm(TFAIL, "Wrong number of children waited on "
-			 "for pid = 0");
-		tst_resm(TFAIL, "Expected %d got %d", MAXKIDS, kid_count);
-		fail = 1;
-	}
-
-	/*
-	 * Check that waitpid(WUNTRACED) returns -1 when no stopped
-	 * children
-	 */
-	ret_val = waitpid(-1, &status, WUNTRACED);
-	if (ret_val != -1) {
-		tst_resm(TFAIL, "Waitpid returned wrong value.");
-		tst_resm(TFAIL, "Expected -1 got %d", ret_val);
-		fail = 1;
-	}
-
-	if (errno != ECHILD) {
-		tst_resm(TFAIL, "Expected ECHILD from waitpid(WUNTRACED)");
-		fail = 1;
-	}
-
-	if (fail)
-		tst_resm(TFAIL, "Test FAILED");
-	else
-		tst_resm(TPASS, "Test PASSED");
-
-	tst_exit();
-}
-
-static void setup_sigint(void)
-{
-	if (signal(SIGINT, inthandlr) == SIG_ERR)
-		tst_brkm(TFAIL | TERRNO, NULL, "signal SIGINT failed");
-}
+	if (TST_TRACE(waitpid_ret_test(0, &status, WNOHANG | WUNTRACED,
+				       0, 0)))
+		return;
 
-static void setup(void)
-{
-	TEST_PAUSE;
-}
-
-static void cleanup(void)
-{
-}
+	if (TST_TRACE(waitpid_ret_test(-group, &status, WNOHANG | WUNTRACED,
+				       0, 0)))
+		return;
 
-static void inthandlr(void)
-{
-	intintr++;
-}
+	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-static void wait_for_parent(void)
-{
-	int testvar;
+	if (TST_TRACE(reap_children(0, WUNTRACED, fork_kid_pid + (MAXKIDS / 2),
+				    MAXKIDS / 2)))
+		return;
 
-	while (!intintr)
-		testvar = 0;
-}
+	if (TST_TRACE(reap_children(-group, WUNTRACED, fork_kid_pid,
+				    MAXKIDS / 2)))
+		return;
 
-static void do_exit(void)
-{
-	wait_for_parent();
-	kill(getpid(), SIGSTOP);
-	exit(3);
+	tst_res(TPASS, "Test PASSED");
 }
 
-#ifdef UCLINUX
-static void do_exit_uclinux(void)
-{
-	setup_sigint();
-	do_exit();
-}
-#endif
+static struct tst_test test = {
+	.tid = "waitpid13",
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+	.setup = waitpid_setup,
+	.cleanup = waitpid_cleanup,
+	.test_all = waitpid_test,
+};
Signature · 1 line
1.7.1
#21 lore raw

PATCH v2 10/11 waitpid13: use the new API

Hi!

Quoted 25 lines
testcases/kernel/syscalls/waitpid/waitpid13.c +7 -15
+	if (TST_TRACE(waitpid_ret_test(0, &status, WNOHANG | WUNTRACED,
+				       0, 0)))
+		return;
 
-static void setup(void)
-{
-	TEST_PAUSE;
-}
-
-static void cleanup(void)
-{
-}
+	if (TST_TRACE(waitpid_ret_test(-group, &status, WNOHANG | WUNTRACED,
+				       0, 0)))
+		return;
 
-static void inthandlr(void)
-{
-	intintr++;
-}
+	TST_CHECKPOINT_WAKE2(0, MAXKIDS);
 
-static void wait_for_parent(void)
-{
-	int testvar;

testcases/kernel/syscalls/waitpid/waitpid13.c line 69

Quoted 10 lines
testcases/kernel/syscalls/waitpid/waitpid13.c +6 -3
+	if (TST_TRACE(reap_children(0, WUNTRACED, fork_kid_pid + (MAXKIDS / 2),
+				    MAXKIDS / 2)))
+		return;
 
-	while (!intintr)
-		testvar = 0;
-}
+	if (TST_TRACE(reap_children(-group, WUNTRACED, fork_kid_pid,
+				    MAXKIDS / 2)))
+		return;

Again, these are just cosmetic, but if we shorten the group to just grp and the waitpid_ret_test to waitpid_test, all but one of these would fit to one line.

Otherwise this looks good.

Signature · 2 lines
Cyril Hrubis
[email protected]
#22 lore raw

PATCH v2 11/11 waitpid08: test stopped children

In reply to Stanislav Kholmanskikh

The whole purpose of WUNTRACED is to help with handling of stopped children. Therefore, let's expand the scope of testing by making the children stop before we call waitpid() (similarly to waitpid13).

---
No changes since V1.

 testcases/kernel/syscalls/waitpid/waitpid08.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
testcases/kernel/syscalls/waitpid/waitpid08.c +1 -1
index 6c8d3b9..dc29e07 100644
@@ -43,7 +43,7 @@ static void do_child_1(void)
 
 		pid = SAFE_FORK();
 		if (pid == 0)
-			do_exit(0);
+			do_exit(1);
 
 		fork_kid_pid[i] = pid;
 	}
Signature · 1 line
1.7.1
#23 lore raw

PATCH v2 11/11 waitpid08: test stopped children

Hi!
The rest of the patches, including this one, looks good.

Signature · 2 lines
Cyril Hrubis
[email protected]
#24 lore raw

PATCH v2 11/11 waitpid08: test stopped children

Hi,

Quoted 3 lines · Cyril Hrubis

Hi!
The rest of the patches, including this one, looks good.

I updated the patches and addressed all of your comments, except renaming 'waitpid_ret_test()' and 'group', and pushed the series. As a result, I have +1 of two-line expressions which could be fit into one line. I think it's acceptable though...

Thank you very much for your review!