Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 18 Mar 2017 15:25:51 +0000 (UTC)
From:      Eric Badger <badger@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r315484 - head/tests/sys/kern
Message-ID:  <201703181525.v2IFPpF0094754@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: badger
Date: Sat Mar 18 15:25:51 2017
New Revision: 315484
URL: https://svnweb.freebsd.org/changeset/base/315484

Log:
  ptrace_test: eliminate assumption about thread scheduling
  
  A couple of the ptrace tests make assumptions about which thread in a
  multithreaded process will run after a halt. This makes the tests less
  portable across branches, and susceptible to future breakage. Instead,
  twiddle thread scheduling and priorities to match the tests'
  expectation.
  
  X-MFC with:	r313992
  Sponsored by:	Dell EMC

Modified:
  head/tests/sys/kern/ptrace_test.c

Modified: head/tests/sys/kern/ptrace_test.c
==============================================================================
--- head/tests/sys/kern/ptrace_test.c	Sat Mar 18 13:58:25 2017	(r315483)
+++ head/tests/sys/kern/ptrace_test.c	Sat Mar 18 15:25:51 2017	(r315484)
@@ -33,6 +33,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/time.h>
 #include <sys/procctl.h>
 #include <sys/ptrace.h>
+#include <sys/queue.h>
+#include <sys/runq.h>
 #include <sys/syscall.h>
 #include <sys/sysctl.h>
 #include <sys/user.h>
@@ -40,6 +42,7 @@ __FBSDID("$FreeBSD$");
 #include <errno.h>
 #include <machine/cpufunc.h>
 #include <pthread.h>
+#include <sched.h>
 #include <semaphore.h>
 #include <signal.h>
 #include <stdio.h>
@@ -1872,15 +1875,11 @@ ATF_TC_BODY(ptrace__PT_KILL_competing_si
 	cpuset_t setmask;
 	pthread_t t;
 	pthread_barrier_t barrier;
+	struct sched_param sched_param;
 
 	ATF_REQUIRE((fpid = fork()) != -1);
 	if (fpid == 0) {
-		/*
-		 * Bind to one CPU so only one thread at a time will run. This
-		 * test expects that the first thread created (the main thread)
-		 * will be unsuspended first and will block the second thread
-		 * from running.
-		 */
+		/* Bind to one CPU so only one thread at a time will run. */
 		CPU_ZERO(&setmask);
 		CPU_SET(0, &setmask);
 		cpusetid_t setid;
@@ -1893,6 +1892,20 @@ ATF_TC_BODY(ptrace__PT_KILL_competing_si
 		CHILD_REQUIRE(pthread_create(&t, NULL, mask_usr1_thread,
 		    (void*)&barrier) == 0);
 
+		/*
+		 * Give the main thread higher priority. The test always
+		 * assumes that, if both threads are able to run, the main
+		 * thread runs first.
+		 */
+		sched_param.sched_priority =
+		    (sched_get_priority_max(SCHED_FIFO) +
+		    sched_get_priority_min(SCHED_FIFO)) / 2;
+		CHILD_REQUIRE(pthread_setschedparam(pthread_self(),
+		    SCHED_FIFO, &sched_param) == 0);
+		sched_param.sched_priority -= RQ_PPQ;
+		CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO,
+		    &sched_param) == 0);
+
 		sigset_t sigmask;
 		sigemptyset(&sigmask);
 		sigaddset(&sigmask, SIGUSR2);
@@ -1952,23 +1965,19 @@ ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_comp
 ATF_TC_BODY(ptrace__PT_KILL_competing_stop, tc)
 {
 	pid_t fpid, wpid;
-	int status, i;
+	int status;
 	cpuset_t setmask;
 	pthread_t t;
 	pthread_barrier_t barrier;
 	lwpid_t main_lwp;
 	struct ptrace_lwpinfo pl;
+	struct sched_param sched_param;
 
 	ATF_REQUIRE((fpid = fork()) != -1);
 	if (fpid == 0) {
 		trace_me();
 
-		/*
-		 * Bind to one CPU so only one thread at a time will run. This
-		 * test expects that the first thread created (the main thread)
-		 * will be unsuspended first and will block the second thread
-		 * from running.
-		 */
+		/* Bind to one CPU so only one thread at a time will run. */
 		CPU_ZERO(&setmask);
 		CPU_SET(0, &setmask);
 		cpusetid_t setid;
@@ -1981,6 +1990,20 @@ ATF_TC_BODY(ptrace__PT_KILL_competing_st
 		CHILD_REQUIRE(pthread_create(&t, NULL, mask_usr1_thread,
 		    (void*)&barrier) == 0);
 
+		/*
+		 * Give the main thread higher priority. The test always
+		 * assumes that, if both threads are able to run, the main
+		 * thread runs first.
+		 */
+		sched_param.sched_priority =
+		    (sched_get_priority_max(SCHED_FIFO) +
+		    sched_get_priority_min(SCHED_FIFO)) / 2;
+		CHILD_REQUIRE(pthread_setschedparam(pthread_self(),
+		    SCHED_FIFO, &sched_param) == 0);
+		sched_param.sched_priority -= RQ_PPQ;
+		CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO,
+		    &sched_param) == 0);
+
 		sigset_t sigmask;
 		sigemptyset(&sigmask);
 		sigaddset(&sigmask, SIGUSR2);
@@ -2027,34 +2050,43 @@ ATF_TC_BODY(ptrace__PT_KILL_competing_st
 		ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0);
 	}
 
-	/* Let both threads hit their syscall entries. */
-	for (i = 0; i < 2; ++i) {
-		ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0);
+	/* Proceed, allowing main thread to hit syscall entry for getpid(). */
+	ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0);
 
-		wpid = waitpid(fpid, &status, 0);
-		ATF_REQUIRE(wpid == fpid);
-		ATF_REQUIRE(WIFSTOPPED(status));
-		ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+	wpid = waitpid(fpid, &status, 0);
+	ATF_REQUIRE(wpid == fpid);
+	ATF_REQUIRE(WIFSTOPPED(status));
+	ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
 
-		ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
-		    sizeof(pl)) != -1);
-		ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
+	ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+	    sizeof(pl)) != -1);
+	ATF_REQUIRE(pl.pl_lwpid == main_lwp);
+	ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
+	/* Prevent the main thread from hitting its syscall exit for now. */
+	ATF_REQUIRE(ptrace(PT_SUSPEND, main_lwp, 0, 0) == 0);
 
-		/*
-		 * Prevent the main thread from hitting its syscall exit for
-		 * now.
-		 */
-		if (pl.pl_lwpid == main_lwp)
-			ATF_REQUIRE(ptrace(PT_SUSPEND, main_lwp, 0, 0) == 0);
+	/*
+	 * Proceed, allowing second thread to hit syscall exit for
+	 * pthread_barrier_wait().
+	 */
+	ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0);
 
-	}
+	wpid = waitpid(fpid, &status, 0);
+	ATF_REQUIRE(wpid == fpid);
+	ATF_REQUIRE(WIFSTOPPED(status));
+	ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+	ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
+	    sizeof(pl)) != -1);
+	ATF_REQUIRE(pl.pl_lwpid != main_lwp);
+	ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
 
 	/* Send a signal that only the second thread can handle. */
 	ATF_REQUIRE(kill(fpid, SIGUSR2) == 0);
 
 	ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0);
 
-	/* The second wait() should report the SIGUSR2. */
+	/* The next wait() should report the SIGUSR2. */
 	wpid = waitpid(fpid, &status, 0);
 	ATF_REQUIRE(wpid == fpid);
 	ATF_REQUIRE(WIFSTOPPED(status));
@@ -2065,10 +2097,11 @@ ATF_TC_BODY(ptrace__PT_KILL_competing_st
 
 	/*
 	 * At this point, the main thread is in the middle of a system call and
-	 * has been resumed. The second thread has taken a signal which will be
-	 * replaced with a SIGKILL. We expect the main thread will get to run
-	 * first. It should notice the kill request and exit accordingly and
-	 * not stop for the system call exit event.
+	 * has been resumed. The second thread has taken a SIGUSR2 which will
+	 * be replaced with a SIGKILL below. The main thread will get to run
+	 * first. It should notice the kill request (even though the signal
+	 * replacement occurred in the other thread) and exit accordingly.  It
+	 * should not stop for the system call exit event.
 	 */
 
 	/* Replace the SIGUSR2 with a kill. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703181525.v2IFPpF0094754>