svn commit: r315484 - head/tests/sys/kern
Eric Badger
badger at FreeBSD.org
Sat Mar 18 15:25:53 UTC 2017
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. */
More information about the svn-src-head
mailing list