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
This commit is contained in:
parent
782a8e7ca3
commit
bc2be1d35b
@ -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_signal, tc)
|
||||
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_signal, tc)
|
||||
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_competing_stop);
|
||||
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_stop, tc)
|
||||
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_stop, tc)
|
||||
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_stop, tc)
|
||||
|
||||
/*
|
||||
* 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. */
|
||||
|
Loading…
Reference in New Issue
Block a user