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. */
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to