Module Name:    src
Committed By:   kamil
Date:           Tue May  5 00:50:39 UTC 2020

Modified Files:
        src/tests/lib/libc/sys: t_ptrace_wait.c t_ptrace_wait.h
Added Files:
        src/tests/lib/libc/sys: t_ptrace_threads_wait.h

Log Message:
Move threads tests out of t_ptrace_wait.c to t_ptrace_threads_wait.h

The same tests are now included with the preprocessor in t_ptrace_wait.c.

No functional change intended.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/sys/t_ptrace_threads_wait.h
cvs rdiff -u -r1.187 -r1.188 src/tests/lib/libc/sys/t_ptrace_wait.c
cvs rdiff -u -r1.27 -r1.28 src/tests/lib/libc/sys/t_ptrace_wait.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/lib/libc/sys/t_ptrace_wait.c
diff -u src/tests/lib/libc/sys/t_ptrace_wait.c:1.187 src/tests/lib/libc/sys/t_ptrace_wait.c:1.188
--- src/tests/lib/libc/sys/t_ptrace_wait.c:1.187	Tue May  5 00:33:37 2020
+++ src/tests/lib/libc/sys/t_ptrace_wait.c	Tue May  5 00:50:39 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_ptrace_wait.c,v 1.187 2020/05/05 00:33:37 kamil Exp $	*/
+/*	$NetBSD: t_ptrace_wait.c,v 1.188 2020/05/05 00:50:39 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.187 2020/05/05 00:33:37 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.188 2020/05/05 00:50:39 kamil Exp $");
 
 #define __LEGACY_PT_LWPINFO
 
@@ -229,631 +229,6 @@ PTRACE_SIGINFO(siginfo_set_faked, true)
 
 /// ----------------------------------------------------------------------------
 
-#define TRACE_THREADS_NUM 100
-
-static volatile int done;
-pthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
-
-static void *
-trace_threads_cb(void *arg __unused)
-{
-
-	pthread_mutex_lock(&trace_threads_mtx);
-	done++;
-	pthread_mutex_unlock(&trace_threads_mtx);
-
-	while (done < TRACE_THREADS_NUM)
-		sched_yield();
-
-	return NULL;
-}
-
-static void
-trace_threads(bool trace_create, bool trace_exit, bool masked)
-{
-	const int sigval = SIGSTOP;
-	pid_t child, wpid;
-#if defined(TWAIT_HAVE_STATUS)
-	int status;
-#endif
-	ptrace_state_t state;
-	const int slen = sizeof(state);
-	ptrace_event_t event;
-	const int elen = sizeof(event);
-	struct ptrace_siginfo info;
-
-	sigset_t intmask;
-
-	pthread_t t[TRACE_THREADS_NUM];
-	int rv;
-	size_t n;
-	lwpid_t lid;
-
-	/* Track created and exited threads */
-	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
-
-	DPRINTF("Before forking process PID=%d\n", getpid());
-	SYSCALL_REQUIRE((child = fork()) != -1);
-	if (child == 0) {
-		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
-		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
-		if (masked) {
-			sigemptyset(&intmask);
-			sigaddset(&intmask, SIGTRAP);
-			sigprocmask(SIG_BLOCK, &intmask, NULL);
-		}
-
-		DPRINTF("Before raising %s from child\n", strsignal(sigval));
-		FORKEE_ASSERT(raise(sigval) == 0);
-
-		for (n = 0; n < __arraycount(t); n++) {
-			rv = pthread_create(&t[n], NULL, trace_threads_cb,
-			    NULL);
-			FORKEE_ASSERT(rv == 0);
-		}
-
-		for (n = 0; n < __arraycount(t); n++) {
-			rv = pthread_join(t[n], NULL);
-			FORKEE_ASSERT(rv == 0);
-		}
-
-		/*
-		 * There is race between _exit() and pthread_join() detaching
-		 * a thread. For simplicity kill the process after detecting
-		 * LWP events.
-		 */
-		while (true)
-			continue;
-
-		FORKEE_ASSERT(0 && "Not reached");
-	}
-	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
-	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_stopped(status, sigval);
-
-	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
-	SYSCALL_REQUIRE(
-	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
-	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
-	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
-	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
-	    info.psi_siginfo.si_errno);
-
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
-
-	DPRINTF("Set LWP event mask for the child %d\n", child);
-	memset(&event, 0, sizeof(event));
-	if (trace_create)
-		event.pe_set_event |= PTRACE_LWP_CREATE;
-	if (trace_exit)
-		event.pe_set_event |= PTRACE_LWP_EXIT;
-	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
-		DPRINTF("Before calling %s() for the child - expected stopped "
-		    "SIGTRAP\n", TWAIT_FNAME);
-		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
-		    child);
-
-		validate_status_stopped(status, SIGTRAP);
-
-		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
-		    "child\n");
-		SYSCALL_REQUIRE(
-		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
-		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
-		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
-		    "si_errno=%#x\n",
-		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
-		    info.psi_siginfo.si_errno);
-
-		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
-		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
-
-		SYSCALL_REQUIRE(
-		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
-
-		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
-		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
-
-		lid = state.pe_lwp;
-		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
-
-		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
-
-		DPRINTF("Before resuming the child process where it left off "
-		    "and without signal to be sent\n");
-		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-	}
-
-	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
-		DPRINTF("Before calling %s() for the child - expected stopped "
-		    "SIGTRAP\n", TWAIT_FNAME);
-		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
-		    child);
-
-		validate_status_stopped(status, SIGTRAP);
-
-		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
-		    "child\n");
-		SYSCALL_REQUIRE(
-		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
-		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
-		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
-		    "si_errno=%#x\n",
-		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
-		    info.psi_siginfo.si_errno);
-
-		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
-		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
-
-		SYSCALL_REQUIRE(
-		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
-
-		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
-		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
-
-		lid = state.pe_lwp;
-		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
-
-		if (trace_create) {
-			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
-			ATF_REQUIRE_EQ(*count, 1);
-			*count = 0;
-		}
-
-		DPRINTF("Before resuming the child process where it left off "
-		    "and without signal to be sent\n");
-		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-	}
-
-	kill(child, SIGKILL);
-
-	DPRINTF("Before calling %s() for the child - expected exited\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_signaled(status, SIGKILL, 0);
-
-	DPRINTF("Before calling %s() for the child - expected no process\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
-}
-
-#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
-ATF_TC(test);								\
-ATF_TC_HEAD(test, tc)							\
-{									\
-        atf_tc_set_md_var(tc, "descr",					\
-            "Verify spawning threads with%s tracing LWP create and"	\
-	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
-	    trace_exit ? "" : "out");					\
-}									\
-									\
-ATF_TC_BODY(test, tc)							\
-{									\
-									\
-        trace_threads(trace_create, trace_exit, mask);			\
-}
-
-TRACE_THREADS(trace_thread_nolwpevents, false, false, false)
-TRACE_THREADS(trace_thread_lwpexit, false, true, false)
-TRACE_THREADS(trace_thread_lwpcreate, true, false, false)
-TRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
-
-TRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
-TRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
-TRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
-
-/// ----------------------------------------------------------------------------
-
-static void *
-thread_and_exec_thread_cb(void *arg __unused)
-{
-
-	execlp("/bin/echo", "/bin/echo", NULL);
-
-	abort();
-}
-
-static void
-threads_and_exec(void)
-{
-	const int sigval = SIGSTOP;
-	pid_t child, wpid;
-#if defined(TWAIT_HAVE_STATUS)
-	int status;
-#endif
-	ptrace_state_t state;
-	const int slen = sizeof(state);
-	ptrace_event_t event;
-	const int elen = sizeof(event);
-	struct ptrace_siginfo info;
-
-	pthread_t t;
-	lwpid_t lid;
-
-	DPRINTF("Before forking process PID=%d\n", getpid());
-	SYSCALL_REQUIRE((child = fork()) != -1);
-	if (child == 0) {
-		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
-		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
-		DPRINTF("Before raising %s from child\n", strsignal(sigval));
-		FORKEE_ASSERT(raise(sigval) == 0);
-
-		FORKEE_ASSERT(pthread_create(&t, NULL,
-		    thread_and_exec_thread_cb, NULL) == 0);
-
-		for (;;)
-			continue;
-
-		FORKEE_ASSERT(0 && "Not reached");
-	}
-	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
-	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_stopped(status, sigval);
-
-	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
-	SYSCALL_REQUIRE(
-	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
-	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
-	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
-	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
-	    info.psi_siginfo.si_errno);
-
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
-
-	DPRINTF("Set LWP event mask for the child %d\n", child);
-	memset(&event, 0, sizeof(event));
-	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
-	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected stopped "
-	    "SIGTRAP\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
-	    child);
-
-	validate_status_stopped(status, SIGTRAP);
-
-	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
-	    "child\n");
-	SYSCALL_REQUIRE(
-	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
-	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
-	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
-	    "si_errno=%#x\n",
-	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
-	    info.psi_siginfo.si_errno);
-
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
-
-	SYSCALL_REQUIRE(
-	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
-
-	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
-	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
-
-	lid = state.pe_lwp;
-	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
-
-	DPRINTF("Before resuming the child process where it left off "
-	    "and without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected stopped "
-	    "SIGTRAP\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
-	    child);
-
-	validate_status_stopped(status, SIGTRAP);
-
-	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
-	    "child\n");
-	SYSCALL_REQUIRE(
-	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
-	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
-	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
-	    "si_errno=%#x\n",
-	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
-	    info.psi_siginfo.si_errno);
-
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
-
-	SYSCALL_REQUIRE(
-	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
-
-	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
-	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
-
-	lid = state.pe_lwp;
-	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
-
-	DPRINTF("Before resuming the child process where it left off "
-	    "and without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected stopped "
-	    "SIGTRAP\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
-	    child);
-
-	validate_status_stopped(status, SIGTRAP);
-
-	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
-	    "child\n");
-	SYSCALL_REQUIRE(
-	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
-	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
-	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
-	    "si_errno=%#x\n",
-	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
-	    info.psi_siginfo.si_errno);
-
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
-	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
-
-	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected exited\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_signaled(status, SIGKILL, 0);
-
-	DPRINTF("Before calling %s() for the child - expected no process\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
-}
-
-ATF_TC(threads_and_exec);
-ATF_TC_HEAD(threads_and_exec, tc)
-{
-        atf_tc_set_md_var(tc, "descr",
-            "Verify that multithreaded application on exec() will report "
-	    "LWP_EXIT events");
-}
-
-ATF_TC_BODY(threads_and_exec, tc)
-{
-
-        threads_and_exec();
-}
-
-/// ----------------------------------------------------------------------------
-
-ATF_TC(suspend_no_deadlock);
-ATF_TC_HEAD(suspend_no_deadlock, tc)
-{
-	atf_tc_set_md_var(tc, "descr",
-	    "Verify that the while the only thread within a process is "
-	    "suspended, the whole process cannot be unstopped");
-}
-
-ATF_TC_BODY(suspend_no_deadlock, tc)
-{
-	const int exitval = 5;
-	const int sigval = SIGSTOP;
-	pid_t child, wpid;
-#if defined(TWAIT_HAVE_STATUS)
-	int status;
-#endif
-	struct ptrace_siginfo psi;
-
-	DPRINTF("Before forking process PID=%d\n", getpid());
-	SYSCALL_REQUIRE((child = fork()) != -1);
-	if (child == 0) {
-		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
-		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
-		DPRINTF("Before raising %s from child\n", strsignal(sigval));
-		FORKEE_ASSERT(raise(sigval) == 0);
-
-		DPRINTF("Before exiting of the child process\n");
-		_exit(exitval);
-	}
-	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
-	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_stopped(status, sigval);
-
-	DPRINTF("Before reading siginfo and lwpid_t\n");
-	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
-
-	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
-	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	ATF_REQUIRE_ERRNO(EDEADLK,
-	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
-
-	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
-	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected exited\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_exited(status, exitval);
-
-	DPRINTF("Before calling %s() for the child - expected no process\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
-}
-
-/// ----------------------------------------------------------------------------
-
-static pthread_barrier_t barrier1_resume;
-static pthread_barrier_t barrier2_resume;
-
-static void *
-resume_thread(void *arg)
-{
-
-	raise(SIGUSR1);
-
-	pthread_barrier_wait(&barrier1_resume);
-
-	/* Debugger will suspend the process here */
-
-	pthread_barrier_wait(&barrier2_resume);
-
-	raise(SIGUSR2);
-
-	return infinite_thread(arg);
-}
-
-ATF_TC(resume);
-ATF_TC_HEAD(resume, tc)
-{
-	atf_tc_set_md_var(tc, "descr",
-	    "Verify that a thread can be suspended by a debugger and later "
-	    "resumed by the debugger");
-}
-
-ATF_TC_BODY(resume, tc)
-{
-	const int sigval = SIGSTOP;
-	pid_t child, wpid;
-#if defined(TWAIT_HAVE_STATUS)
-	int status;
-#endif
-	lwpid_t lid;
-	struct ptrace_siginfo psi;
-	pthread_t t;
-
-	DPRINTF("Before forking process PID=%d\n", getpid());
-	SYSCALL_REQUIRE((child = fork()) != -1);
-	if (child == 0) {
-		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
-		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
-		pthread_barrier_init(&barrier1_resume, NULL, 2);
-		pthread_barrier_init(&barrier2_resume, NULL, 2);
-
-		DPRINTF("Before raising %s from child\n", strsignal(sigval));
-		FORKEE_ASSERT(raise(sigval) == 0);
-
-		DPRINTF("Before creating new thread in child\n");
-		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
-
-		pthread_barrier_wait(&barrier1_resume);
-
-		pthread_barrier_wait(&barrier2_resume);
-
-		infinite_thread(NULL);
-	}
-	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
-	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_stopped(status, sigval);
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected stopped "
-	    "SIGUSR1\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_stopped(status, SIGUSR1);
-
-	DPRINTF("Before reading siginfo and lwpid_t\n");
-	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
-
-	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
-	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
-
-	lid = psi.psi_lwpid;
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
-	SYSCALL_REQUIRE(sleep(1) == 0);
-
-#if defined(TWAIT_HAVE_OPTIONS)
-	DPRINTF("Before calling %s() for the child - expected no status\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
-#endif
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected stopped "
-	    "SIGSTOP\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_stopped(status, SIGSTOP);
-
-	DPRINTF("Before resuming LWP %d\n", lid);
-	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected stopped "
-	    "SIGUSR2\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_stopped(status, SIGUSR2);
-
-	DPRINTF("Before resuming the child process where it left off and "
-	    "without signal to be sent\n");
-	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before calling %s() for the child - expected exited\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_signaled(status, SIGKILL, 0);
-
-	DPRINTF("Before calling %s() for the child - expected no process\n",
-	    TWAIT_FNAME);
-	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
-}
-
-/// ----------------------------------------------------------------------------
-
 static void
 user_va0_disable(int operation)
 {
@@ -1135,397 +510,6 @@ ATF_TC_BODY(core_dump_procinfo, tc)
 
 /// ----------------------------------------------------------------------------
 
-#if defined(TWAIT_HAVE_STATUS)
-
-#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
-#define THREAD_CONCURRENT_SIGNALS_NUM 50
-#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
-
-/* List of signals to use for the test */
-const int thread_concurrent_signals_list[] = {
-	SIGIO,
-	SIGXCPU,
-	SIGXFSZ,
-	SIGVTALRM,
-	SIGPROF,
-	SIGWINCH,
-	SIGINFO,
-	SIGUSR1,
-	SIGUSR2
-};
-
-enum thread_concurrent_signal_handling {
-	/* the signal is discarded by debugger */
-	TCSH_DISCARD,
-	/* the handler is set to SIG_IGN */
-	TCSH_SIG_IGN,
-	/* an actual handler is used */
-	TCSH_HANDLER
-};
-
-static pthread_barrier_t thread_concurrent_barrier;
-static pthread_key_t thread_concurrent_key;
-static uint32_t thread_concurrent_watchpoint_var = 0;
-
-static void *
-thread_concurrent_breakpoint_thread(void *arg)
-{
-	static volatile int watchme = 1;
-	pthread_barrier_wait(&thread_concurrent_barrier);
-	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
-	check_happy(watchme);
-	return NULL;
-}
-
-static void
-thread_concurrent_sig_handler(int sig)
-{
-	void *tls_val = pthread_getspecific(thread_concurrent_key);
-	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
-	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
-	    (void*)((uintptr_t)tls_val + 1)) == 0);
-}
-
-static void *
-thread_concurrent_signals_thread(void *arg)
-{
-	int sigval = thread_concurrent_signals_list[
-	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
-	enum thread_concurrent_signal_handling *signal_handle = arg;
-	void *tls_val;
-
-	pthread_barrier_wait(&thread_concurrent_barrier);
-	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
-		_lwp_self());
-	pthread_kill(pthread_self(), sigval);
-	if (*signal_handle == TCSH_HANDLER) {
-	    tls_val = pthread_getspecific(thread_concurrent_key);
-	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
-	    FORKEE_ASSERT(tls_val == (void*)1);
-	}
-	return NULL;
-}
-
-static void *
-thread_concurrent_watchpoint_thread(void *arg)
-{
-	pthread_barrier_wait(&thread_concurrent_barrier);
-	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
-	thread_concurrent_watchpoint_var = 1;
-	return NULL;
-}
-
-#if defined(__i386__) || defined(__x86_64__)
-enum thread_concurrent_sigtrap_event {
-	TCSE_UNKNOWN,
-	TCSE_BREAKPOINT,
-	TCSE_WATCHPOINT
-};
-
-static void
-thread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
-static enum thread_concurrent_sigtrap_event
-thread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
-#endif
-
-static void
-thread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
-    int breakpoint_threads, int signal_threads, int watchpoint_threads)
-{
-	const int exitval = 5;
-	const int sigval = SIGSTOP;
-	pid_t child, wpid;
-	int status;
-	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
-	    = {{0, 0}};
-	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
-	    = {{0, 0}};
-	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
-	    = {{0, 0}};
-	ptrace_event_t event;
-	int i;
-
-#if defined(HAVE_DBREGS)
-	if (!can_we_set_dbregs()) {
-		atf_tc_skip("Either run this test as root or set sysctl(3) "
-		            "security.models.extensions.user_set_dbregs to 1");
-        }
-#endif
-
-	atf_tc_skip("PR kern/54960");
-
-	/* Protect against out-of-bounds array access. */
-	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
-	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
-	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
-
-	DPRINTF("Before forking process PID=%d\n", getpid());
-	SYSCALL_REQUIRE((child = fork()) != -1);
-	if (child == 0) {
-		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
-		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
-		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
-
-		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
-		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
-		DPRINTF("Before raising %s from child\n", strsignal(sigval));
-		FORKEE_ASSERT(raise(sigval) == 0);
-
-		if (signal_handle != TCSH_DISCARD) {
-			struct sigaction sa;
-			unsigned int j;
-
-			memset(&sa, 0, sizeof(sa));
-			if (signal_handle == TCSH_SIG_IGN)
-				sa.sa_handler = SIG_IGN;
-			else
-				sa.sa_handler = thread_concurrent_sig_handler;
-			sigemptyset(&sa.sa_mask);
-
-			for (j = 0;
-			    j < __arraycount(thread_concurrent_signals_list);
-			    j++)
-				FORKEE_ASSERT(sigaction(
-				    thread_concurrent_signals_list[j], &sa, NULL)
-				    != -1);
-		}
-
-		DPRINTF("Before starting threads from the child\n");
-		FORKEE_ASSERT(pthread_barrier_init(
-		    &thread_concurrent_barrier, NULL,
-		    breakpoint_threads + signal_threads + watchpoint_threads)
-		    == 0);
-		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
-		    == 0);
-
-		for (i = 0; i < signal_threads; i++) {
-			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
-			    thread_concurrent_signals_thread,
-			    &signal_handle) == 0);
-		}
-		for (i = 0; i < breakpoint_threads; i++) {
-			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
-			    thread_concurrent_breakpoint_thread, NULL) == 0);
-		}
-		for (i = 0; i < watchpoint_threads; i++) {
-			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
-			    thread_concurrent_watchpoint_thread, NULL) == 0);
-		}
-
-		DPRINTF("Before joining threads from the child\n");
-		for (i = 0; i < watchpoint_threads; i++) {
-			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
-		}
-		for (i = 0; i < breakpoint_threads; i++) {
-			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
-		}
-		for (i = 0; i < signal_threads; i++) {
-			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
-		}
-
-		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
-		FORKEE_ASSERT(pthread_barrier_destroy(
-		    &thread_concurrent_barrier) == 0);
-
-		DPRINTF("Before exiting of the child process\n");
-		_exit(exitval);
-	}
-	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
-	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
-	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
-	validate_status_stopped(status, sigval);
-
-	DPRINTF("Set LWP event mask for the child process\n");
-	memset(&event, 0, sizeof(event));
-	event.pe_set_event |= PTRACE_LWP_CREATE;
-	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
-	    != -1);
-
-	DPRINTF("Before resuming the child process where it left off\n");
-	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
-	DPRINTF("Before entering signal collection loop\n");
-	while (1) {
-		ptrace_siginfo_t info;
-
-		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
-		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
-		    child);
-		if (WIFEXITED(status))
-			break;
-		/* Note: we use validate_status_stopped() to get nice error
-		 * message.  Signal is irrelevant since it won't be reached.
-		 */
-		else if (!WIFSTOPPED(status))
-			validate_status_stopped(status, 0);
-
-		DPRINTF("Before calling PT_GET_SIGINFO\n");
-		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
-		    sizeof(info)) != -1);
-
-		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
-		    info.psi_siginfo.si_signo, info.psi_lwpid,
-		    WSTOPSIG(status));
-
-		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
-		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
-		    WSTOPSIG(status), info.psi_siginfo.si_signo);
-
-		if (WSTOPSIG(status) != SIGTRAP) {
-			int expected_sig =
-			    thread_concurrent_signals_list[info.psi_lwpid %
-			    __arraycount(thread_concurrent_signals_list)];
-			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
-				"lwp=%d, expected %d, got %d", info.psi_lwpid,
-				expected_sig, WSTOPSIG(status));
-
-			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
-		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
-#if defined(__i386__) || defined(__x86_64__)
-			thread_concurrent_lwp_setup(child, info.psi_lwpid);
-#endif
-		} else {
-#if defined(__i386__) || defined(__x86_64__)
-			switch (thread_concurrent_handle_sigtrap(child, &info)) {
-				case TCSE_UNKNOWN:
-					/* already reported inside the function */
-					break;
-				case TCSE_BREAKPOINT:
-					*FIND_EVENT_COUNT(bp_counts,
-					    info.psi_lwpid) += 1;
-					break;
-				case TCSE_WATCHPOINT:
-					*FIND_EVENT_COUNT(wp_counts,
-					    info.psi_lwpid) += 1;
-					break;
-			}
-#else
-			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
-			    info.psi_siginfo.si_code);
-#endif
-		}
-
-		DPRINTF("Before resuming the child process\n");
-		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
-		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
-		     ? WSTOPSIG(status) : 0) != -1);
-	}
-
-	for (i = 0; i < signal_threads; i++)
-		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
-		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
-		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
-	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
-		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
-		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
-		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
-
-	for (i = 0; i < breakpoint_threads; i++)
-		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
-		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
-		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
-	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
-		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
-		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
-		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
-
-	for (i = 0; i < watchpoint_threads; i++)
-		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
-		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
-		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
-	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
-		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
-		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
-		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
-
-	validate_status_exited(status, exitval);
-}
-
-#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
-ATF_TC(test);								\
-ATF_TC_HEAD(test, tc)							\
-{									\
-	atf_tc_set_md_var(tc, "descr", descr);				\
-}									\
-									\
-ATF_TC_BODY(test, tc)							\
-{									\
-	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
-}
-
-THREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
-    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
-    "Verify that concurrent signals issued to a single thread are reported "
-    "correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
-    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
-    "Verify that concurrent signals issued to a single thread are reported "
-    "correctly and passed back to SIG_IGN handler");
-THREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
-    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
-    "Verify that concurrent signals issued to a single thread are reported "
-    "correctly and passed back to a handler function");
-
-#if defined(__i386__) || defined(__x86_64__)
-THREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
-    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
-    "Verify that concurrent breakpoints are reported correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
-    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
-    "Verify that concurrent breakpoints are reported correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
-    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
-    "Verify that concurrent breakpoints and watchpoints are reported "
-    "correctly");
-
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
-    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
-    "Verify that concurrent breakpoints and signals are reported correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
-    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
-    "Verify that concurrent breakpoints and signals are reported correctly "
-    "and passed back to SIG_IGN handler");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
-    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
-    "Verify that concurrent breakpoints and signals are reported correctly "
-    "and passed back to a handler function");
-
-THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
-    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
-    "Verify that concurrent watchpoints and signals are reported correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
-    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
-    "Verify that concurrent watchpoints and signals are reported correctly "
-    "and passed back to SIG_IGN handler");
-THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
-    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
-    "Verify that concurrent watchpoints and signals are reported correctly "
-    "and passed back to a handler function");
-
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
-    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
-    THREAD_CONCURRENT_WATCHPOINT_NUM,
-    "Verify that concurrent breakpoints, watchpoints and signals are reported "
-    "correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
-    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
-    THREAD_CONCURRENT_WATCHPOINT_NUM,
-    "Verify that concurrent breakpoints, watchpoints and signals are reported "
-    "correctly and passed back to SIG_IGN handler");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
-    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
-    THREAD_CONCURRENT_WATCHPOINT_NUM,
-    "Verify that concurrent breakpoints, watchpoints and signals are reported "
-    "correctly and passed back to a handler function");
-#endif
-
-#endif /*defined(TWAIT_HAVE_STATUS)*/
-
-/// ----------------------------------------------------------------------------
-
 #include "t_ptrace_register_wait.h"
 #include "t_ptrace_syscall_wait.h"
 #include "t_ptrace_step_wait.h"
@@ -1538,6 +522,7 @@ THREAD_CONCURRENT_TEST(thread_concurrent
 #include "t_ptrace_lwp_wait.h"
 #include "t_ptrace_exec_wait.h"
 #include "t_ptrace_topology_wait.h"
+#include "t_ptrace_threads_wait.h"
 
 /// ----------------------------------------------------------------------------
 
@@ -1571,47 +556,12 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
 	ATF_TP_ADD_TC(tp, siginfo_set_faked);
 
-	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
-	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
-	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
-	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
-
-	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
-	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
-	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
-
-	ATF_TP_ADD_TC(tp, threads_and_exec);
-
-	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
-
-	ATF_TP_ADD_TC(tp, resume);
-
 	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
 	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
 	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
 
 	ATF_TP_ADD_TC(tp, core_dump_procinfo);
 
-#if defined(TWAIT_HAVE_STATUS)
-	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
-	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
-	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
-#if defined(__i386__) || defined(__x86_64__)
-	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
-	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
-	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
-	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
-	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
-	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
-	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
-	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
-	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
-	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
-	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
-	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
-#endif
-#endif
-
 	ATF_TP_ADD_TCS_PTRACE_WAIT_REGISTER();
 	ATF_TP_ADD_TCS_PTRACE_WAIT_SYSCALL();
 	ATF_TP_ADD_TCS_PTRACE_WAIT_STEP();
@@ -1624,6 +574,7 @@ ATF_TP_ADD_TCS(tp)
 	ATF_TP_ADD_TCS_PTRACE_WAIT_LWP();
 	ATF_TP_ADD_TCS_PTRACE_WAIT_EXEC();
 	ATF_TP_ADD_TCS_PTRACE_WAIT_TOPOLOGY();
+	ATF_TP_ADD_TCS_PTRACE_WAIT_THREADS();
 
 	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
 	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();

Index: src/tests/lib/libc/sys/t_ptrace_wait.h
diff -u src/tests/lib/libc/sys/t_ptrace_wait.h:1.27 src/tests/lib/libc/sys/t_ptrace_wait.h:1.28
--- src/tests/lib/libc/sys/t_ptrace_wait.h:1.27	Sun Mar  8 15:07:44 2020
+++ src/tests/lib/libc/sys/t_ptrace_wait.h	Tue May  5 00:50:39 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_ptrace_wait.h,v 1.27 2020/03/08 15:07:44 martin Exp $	*/
+/*	$NetBSD: t_ptrace_wait.h,v 1.28 2020/05/05 00:50:39 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -744,6 +744,18 @@ find_event_count(struct lwp_event_count 
 #define ATF_TP_ADD_TC_HAVE_PID(a,b)
 #endif
 
+#if defined(TWAIT_HAVE_STATUS)
+#define ATF_TP_ADD_TC_HAVE_STATUS(a,b)	ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_HAVE_STATUS(a,b)
+#endif
+
+#if defined(TWAIT_HAVE_STATUS) && (defined(__i386__) || defined(__x86_64__))
+#define ATF_TP_ADD_TC_HAVE_STATUS_X86(a,b)	ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_HAVE_STATUS_X86(a,b)
+#endif
+
 #if defined(HAVE_GPREGS)
 #define ATF_TP_ADD_TC_HAVE_GPREGS(a,b)	ATF_TP_ADD_TC(a,b)
 #else

Added files:

Index: src/tests/lib/libc/sys/t_ptrace_threads_wait.h
diff -u /dev/null src/tests/lib/libc/sys/t_ptrace_threads_wait.h:1.1
--- /dev/null	Tue May  5 00:50:39 2020
+++ src/tests/lib/libc/sys/t_ptrace_threads_wait.h	Tue May  5 00:50:39 2020
@@ -0,0 +1,1069 @@
+/*	$NetBSD: t_ptrace_threads_wait.h,v 1.1 2020/05/05 00:50:39 kamil Exp $	*/
+
+/*-
+ * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#define TRACE_THREADS_NUM 100
+
+static volatile int done;
+pthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+static void *
+trace_threads_cb(void *arg __unused)
+{
+
+	pthread_mutex_lock(&trace_threads_mtx);
+	done++;
+	pthread_mutex_unlock(&trace_threads_mtx);
+
+	while (done < TRACE_THREADS_NUM)
+		sched_yield();
+
+	return NULL;
+}
+
+static void
+trace_threads(bool trace_create, bool trace_exit, bool masked)
+{
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	ptrace_state_t state;
+	const int slen = sizeof(state);
+	ptrace_event_t event;
+	const int elen = sizeof(event);
+	struct ptrace_siginfo info;
+
+	sigset_t intmask;
+
+	pthread_t t[TRACE_THREADS_NUM];
+	int rv;
+	size_t n;
+	lwpid_t lid;
+
+	/* Track created and exited threads */
+	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
+
+	DPRINTF("Before forking process PID=%d\n", getpid());
+	SYSCALL_REQUIRE((child = fork()) != -1);
+	if (child == 0) {
+		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+		if (masked) {
+			sigemptyset(&intmask);
+			sigaddset(&intmask, SIGTRAP);
+			sigprocmask(SIG_BLOCK, &intmask, NULL);
+		}
+
+		DPRINTF("Before raising %s from child\n", strsignal(sigval));
+		FORKEE_ASSERT(raise(sigval) == 0);
+
+		for (n = 0; n < __arraycount(t); n++) {
+			rv = pthread_create(&t[n], NULL, trace_threads_cb,
+			    NULL);
+			FORKEE_ASSERT(rv == 0);
+		}
+
+		for (n = 0; n < __arraycount(t); n++) {
+			rv = pthread_join(t[n], NULL);
+			FORKEE_ASSERT(rv == 0);
+		}
+
+		/*
+		 * There is race between _exit() and pthread_join() detaching
+		 * a thread. For simplicity kill the process after detecting
+		 * LWP events.
+		 */
+		while (true)
+			continue;
+
+		FORKEE_ASSERT(0 && "Not reached");
+	}
+	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_stopped(status, sigval);
+
+	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+	SYSCALL_REQUIRE(
+	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
+	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+	    info.psi_siginfo.si_errno);
+
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+
+	DPRINTF("Set LWP event mask for the child %d\n", child);
+	memset(&event, 0, sizeof(event));
+	if (trace_create)
+		event.pe_set_event |= PTRACE_LWP_CREATE;
+	if (trace_exit)
+		event.pe_set_event |= PTRACE_LWP_EXIT;
+	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
+		DPRINTF("Before calling %s() for the child - expected stopped "
+		    "SIGTRAP\n", TWAIT_FNAME);
+		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+		    child);
+
+		validate_status_stopped(status, SIGTRAP);
+
+		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+		    "child\n");
+		SYSCALL_REQUIRE(
+		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+		    "si_errno=%#x\n",
+		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+		    info.psi_siginfo.si_errno);
+
+		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
+
+		SYSCALL_REQUIRE(
+		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+
+		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
+		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
+
+		lid = state.pe_lwp;
+		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
+
+		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
+
+		DPRINTF("Before resuming the child process where it left off "
+		    "and without signal to be sent\n");
+		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+	}
+
+	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
+		DPRINTF("Before calling %s() for the child - expected stopped "
+		    "SIGTRAP\n", TWAIT_FNAME);
+		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+		    child);
+
+		validate_status_stopped(status, SIGTRAP);
+
+		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+		    "child\n");
+		SYSCALL_REQUIRE(
+		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+		    "si_errno=%#x\n",
+		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+		    info.psi_siginfo.si_errno);
+
+		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
+
+		SYSCALL_REQUIRE(
+		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+
+		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
+		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
+
+		lid = state.pe_lwp;
+		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
+
+		if (trace_create) {
+			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
+			ATF_REQUIRE_EQ(*count, 1);
+			*count = 0;
+		}
+
+		DPRINTF("Before resuming the child process where it left off "
+		    "and without signal to be sent\n");
+		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+	}
+
+	kill(child, SIGKILL);
+
+	DPRINTF("Before calling %s() for the child - expected exited\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_signaled(status, SIGKILL, 0);
+
+	DPRINTF("Before calling %s() for the child - expected no process\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
+ATF_TC(test);								\
+ATF_TC_HEAD(test, tc)							\
+{									\
+        atf_tc_set_md_var(tc, "descr",					\
+            "Verify spawning threads with%s tracing LWP create and"	\
+	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
+	    trace_exit ? "" : "out");					\
+}									\
+									\
+ATF_TC_BODY(test, tc)							\
+{									\
+									\
+        trace_threads(trace_create, trace_exit, mask);			\
+}
+
+TRACE_THREADS(trace_thread_nolwpevents, false, false, false)
+TRACE_THREADS(trace_thread_lwpexit, false, true, false)
+TRACE_THREADS(trace_thread_lwpcreate, true, false, false)
+TRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
+
+TRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
+TRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
+TRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
+
+/// ----------------------------------------------------------------------------
+
+static void *
+thread_and_exec_thread_cb(void *arg __unused)
+{
+
+	execlp("/bin/echo", "/bin/echo", NULL);
+
+	abort();
+}
+
+static void
+threads_and_exec(void)
+{
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	ptrace_state_t state;
+	const int slen = sizeof(state);
+	ptrace_event_t event;
+	const int elen = sizeof(event);
+	struct ptrace_siginfo info;
+
+	pthread_t t;
+	lwpid_t lid;
+
+	DPRINTF("Before forking process PID=%d\n", getpid());
+	SYSCALL_REQUIRE((child = fork()) != -1);
+	if (child == 0) {
+		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+		DPRINTF("Before raising %s from child\n", strsignal(sigval));
+		FORKEE_ASSERT(raise(sigval) == 0);
+
+		FORKEE_ASSERT(pthread_create(&t, NULL,
+		    thread_and_exec_thread_cb, NULL) == 0);
+
+		for (;;)
+			continue;
+
+		FORKEE_ASSERT(0 && "Not reached");
+	}
+	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_stopped(status, sigval);
+
+	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+	SYSCALL_REQUIRE(
+	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
+	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+	    info.psi_siginfo.si_errno);
+
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+
+	DPRINTF("Set LWP event mask for the child %d\n", child);
+	memset(&event, 0, sizeof(event));
+	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
+	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected stopped "
+	    "SIGTRAP\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+	    child);
+
+	validate_status_stopped(status, SIGTRAP);
+
+	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+	    "child\n");
+	SYSCALL_REQUIRE(
+	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+	    "si_errno=%#x\n",
+	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+	    info.psi_siginfo.si_errno);
+
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
+
+	SYSCALL_REQUIRE(
+	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+
+	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
+	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
+
+	lid = state.pe_lwp;
+	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
+
+	DPRINTF("Before resuming the child process where it left off "
+	    "and without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected stopped "
+	    "SIGTRAP\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+	    child);
+
+	validate_status_stopped(status, SIGTRAP);
+
+	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+	    "child\n");
+	SYSCALL_REQUIRE(
+	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+	    "si_errno=%#x\n",
+	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+	    info.psi_siginfo.si_errno);
+
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
+
+	SYSCALL_REQUIRE(
+	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+
+	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
+	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
+
+	lid = state.pe_lwp;
+	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
+
+	DPRINTF("Before resuming the child process where it left off "
+	    "and without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected stopped "
+	    "SIGTRAP\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+	    child);
+
+	validate_status_stopped(status, SIGTRAP);
+
+	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+	    "child\n");
+	SYSCALL_REQUIRE(
+	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+	    "si_errno=%#x\n",
+	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+	    info.psi_siginfo.si_errno);
+
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
+
+	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected exited\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_signaled(status, SIGKILL, 0);
+
+	DPRINTF("Before calling %s() for the child - expected no process\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(threads_and_exec);
+ATF_TC_HEAD(threads_and_exec, tc)
+{
+        atf_tc_set_md_var(tc, "descr",
+            "Verify that multithreaded application on exec() will report "
+	    "LWP_EXIT events");
+}
+
+ATF_TC_BODY(threads_and_exec, tc)
+{
+
+        threads_and_exec();
+}
+
+/// ----------------------------------------------------------------------------
+
+ATF_TC(suspend_no_deadlock);
+ATF_TC_HEAD(suspend_no_deadlock, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that the while the only thread within a process is "
+	    "suspended, the whole process cannot be unstopped");
+}
+
+ATF_TC_BODY(suspend_no_deadlock, tc)
+{
+	const int exitval = 5;
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	struct ptrace_siginfo psi;
+
+	DPRINTF("Before forking process PID=%d\n", getpid());
+	SYSCALL_REQUIRE((child = fork()) != -1);
+	if (child == 0) {
+		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+		DPRINTF("Before raising %s from child\n", strsignal(sigval));
+		FORKEE_ASSERT(raise(sigval) == 0);
+
+		DPRINTF("Before exiting of the child process\n");
+		_exit(exitval);
+	}
+	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_stopped(status, sigval);
+
+	DPRINTF("Before reading siginfo and lwpid_t\n");
+	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
+
+	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
+	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	ATF_REQUIRE_ERRNO(EDEADLK,
+	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
+
+	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
+	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected exited\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_exited(status, exitval);
+
+	DPRINTF("Before calling %s() for the child - expected no process\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+/// ----------------------------------------------------------------------------
+
+static pthread_barrier_t barrier1_resume;
+static pthread_barrier_t barrier2_resume;
+
+static void *
+resume_thread(void *arg)
+{
+
+	raise(SIGUSR1);
+
+	pthread_barrier_wait(&barrier1_resume);
+
+	/* Debugger will suspend the process here */
+
+	pthread_barrier_wait(&barrier2_resume);
+
+	raise(SIGUSR2);
+
+	return infinite_thread(arg);
+}
+
+ATF_TC(resume);
+ATF_TC_HEAD(resume, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that a thread can be suspended by a debugger and later "
+	    "resumed by the debugger");
+}
+
+ATF_TC_BODY(resume, tc)
+{
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+	int status;
+#endif
+	lwpid_t lid;
+	struct ptrace_siginfo psi;
+	pthread_t t;
+
+	DPRINTF("Before forking process PID=%d\n", getpid());
+	SYSCALL_REQUIRE((child = fork()) != -1);
+	if (child == 0) {
+		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+		pthread_barrier_init(&barrier1_resume, NULL, 2);
+		pthread_barrier_init(&barrier2_resume, NULL, 2);
+
+		DPRINTF("Before raising %s from child\n", strsignal(sigval));
+		FORKEE_ASSERT(raise(sigval) == 0);
+
+		DPRINTF("Before creating new thread in child\n");
+		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
+
+		pthread_barrier_wait(&barrier1_resume);
+
+		pthread_barrier_wait(&barrier2_resume);
+
+		infinite_thread(NULL);
+	}
+	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_stopped(status, sigval);
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected stopped "
+	    "SIGUSR1\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_stopped(status, SIGUSR1);
+
+	DPRINTF("Before reading siginfo and lwpid_t\n");
+	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
+
+	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
+	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
+
+	lid = psi.psi_lwpid;
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
+	SYSCALL_REQUIRE(sleep(1) == 0);
+
+#if defined(TWAIT_HAVE_OPTIONS)
+	DPRINTF("Before calling %s() for the child - expected no status\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
+#endif
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected stopped "
+	    "SIGSTOP\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_stopped(status, SIGSTOP);
+
+	DPRINTF("Before resuming LWP %d\n", lid);
+	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected stopped "
+	    "SIGUSR2\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_stopped(status, SIGUSR2);
+
+	DPRINTF("Before resuming the child process where it left off and "
+	    "without signal to be sent\n");
+	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before calling %s() for the child - expected exited\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_signaled(status, SIGKILL, 0);
+
+	DPRINTF("Before calling %s() for the child - expected no process\n",
+	    TWAIT_FNAME);
+	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+/// ----------------------------------------------------------------------------
+
+#if defined(TWAIT_HAVE_STATUS)
+
+#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
+#define THREAD_CONCURRENT_SIGNALS_NUM 50
+#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
+
+/* List of signals to use for the test */
+const int thread_concurrent_signals_list[] = {
+	SIGIO,
+	SIGXCPU,
+	SIGXFSZ,
+	SIGVTALRM,
+	SIGPROF,
+	SIGWINCH,
+	SIGINFO,
+	SIGUSR1,
+	SIGUSR2
+};
+
+enum thread_concurrent_signal_handling {
+	/* the signal is discarded by debugger */
+	TCSH_DISCARD,
+	/* the handler is set to SIG_IGN */
+	TCSH_SIG_IGN,
+	/* an actual handler is used */
+	TCSH_HANDLER
+};
+
+static pthread_barrier_t thread_concurrent_barrier;
+static pthread_key_t thread_concurrent_key;
+static uint32_t thread_concurrent_watchpoint_var = 0;
+
+static void *
+thread_concurrent_breakpoint_thread(void *arg)
+{
+	static volatile int watchme = 1;
+	pthread_barrier_wait(&thread_concurrent_barrier);
+	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
+	check_happy(watchme);
+	return NULL;
+}
+
+static void
+thread_concurrent_sig_handler(int sig)
+{
+	void *tls_val = pthread_getspecific(thread_concurrent_key);
+	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
+	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
+	    (void*)((uintptr_t)tls_val + 1)) == 0);
+}
+
+static void *
+thread_concurrent_signals_thread(void *arg)
+{
+	int sigval = thread_concurrent_signals_list[
+	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
+	enum thread_concurrent_signal_handling *signal_handle = arg;
+	void *tls_val;
+
+	pthread_barrier_wait(&thread_concurrent_barrier);
+	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
+		_lwp_self());
+	pthread_kill(pthread_self(), sigval);
+	if (*signal_handle == TCSH_HANDLER) {
+	    tls_val = pthread_getspecific(thread_concurrent_key);
+	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
+	    FORKEE_ASSERT(tls_val == (void*)1);
+	}
+	return NULL;
+}
+
+static void *
+thread_concurrent_watchpoint_thread(void *arg)
+{
+	pthread_barrier_wait(&thread_concurrent_barrier);
+	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
+	thread_concurrent_watchpoint_var = 1;
+	return NULL;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+enum thread_concurrent_sigtrap_event {
+	TCSE_UNKNOWN,
+	TCSE_BREAKPOINT,
+	TCSE_WATCHPOINT
+};
+
+static void
+thread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
+static enum thread_concurrent_sigtrap_event
+thread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
+#endif
+
+static void
+thread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
+    int breakpoint_threads, int signal_threads, int watchpoint_threads)
+{
+	const int exitval = 5;
+	const int sigval = SIGSTOP;
+	pid_t child, wpid;
+	int status;
+	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
+	    = {{0, 0}};
+	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
+	    = {{0, 0}};
+	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
+	    = {{0, 0}};
+	ptrace_event_t event;
+	int i;
+
+#if defined(HAVE_DBREGS)
+	if (!can_we_set_dbregs()) {
+		atf_tc_skip("Either run this test as root or set sysctl(3) "
+		            "security.models.extensions.user_set_dbregs to 1");
+        }
+#endif
+
+	atf_tc_skip("PR kern/54960");
+
+	/* Protect against out-of-bounds array access. */
+	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
+	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
+	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
+
+	DPRINTF("Before forking process PID=%d\n", getpid());
+	SYSCALL_REQUIRE((child = fork()) != -1);
+	if (child == 0) {
+		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
+		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
+		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
+
+		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+		DPRINTF("Before raising %s from child\n", strsignal(sigval));
+		FORKEE_ASSERT(raise(sigval) == 0);
+
+		if (signal_handle != TCSH_DISCARD) {
+			struct sigaction sa;
+			unsigned int j;
+
+			memset(&sa, 0, sizeof(sa));
+			if (signal_handle == TCSH_SIG_IGN)
+				sa.sa_handler = SIG_IGN;
+			else
+				sa.sa_handler = thread_concurrent_sig_handler;
+			sigemptyset(&sa.sa_mask);
+
+			for (j = 0;
+			    j < __arraycount(thread_concurrent_signals_list);
+			    j++)
+				FORKEE_ASSERT(sigaction(
+				    thread_concurrent_signals_list[j], &sa, NULL)
+				    != -1);
+		}
+
+		DPRINTF("Before starting threads from the child\n");
+		FORKEE_ASSERT(pthread_barrier_init(
+		    &thread_concurrent_barrier, NULL,
+		    breakpoint_threads + signal_threads + watchpoint_threads)
+		    == 0);
+		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
+		    == 0);
+
+		for (i = 0; i < signal_threads; i++) {
+			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
+			    thread_concurrent_signals_thread,
+			    &signal_handle) == 0);
+		}
+		for (i = 0; i < breakpoint_threads; i++) {
+			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
+			    thread_concurrent_breakpoint_thread, NULL) == 0);
+		}
+		for (i = 0; i < watchpoint_threads; i++) {
+			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
+			    thread_concurrent_watchpoint_thread, NULL) == 0);
+		}
+
+		DPRINTF("Before joining threads from the child\n");
+		for (i = 0; i < watchpoint_threads; i++) {
+			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
+		}
+		for (i = 0; i < breakpoint_threads; i++) {
+			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
+		}
+		for (i = 0; i < signal_threads; i++) {
+			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
+		}
+
+		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
+		FORKEE_ASSERT(pthread_barrier_destroy(
+		    &thread_concurrent_barrier) == 0);
+
+		DPRINTF("Before exiting of the child process\n");
+		_exit(exitval);
+	}
+	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+	validate_status_stopped(status, sigval);
+
+	DPRINTF("Set LWP event mask for the child process\n");
+	memset(&event, 0, sizeof(event));
+	event.pe_set_event |= PTRACE_LWP_CREATE;
+	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
+	    != -1);
+
+	DPRINTF("Before resuming the child process where it left off\n");
+	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+	DPRINTF("Before entering signal collection loop\n");
+	while (1) {
+		ptrace_siginfo_t info;
+
+		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+		    child);
+		if (WIFEXITED(status))
+			break;
+		/* Note: we use validate_status_stopped() to get nice error
+		 * message.  Signal is irrelevant since it won't be reached.
+		 */
+		else if (!WIFSTOPPED(status))
+			validate_status_stopped(status, 0);
+
+		DPRINTF("Before calling PT_GET_SIGINFO\n");
+		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
+		    sizeof(info)) != -1);
+
+		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
+		    info.psi_siginfo.si_signo, info.psi_lwpid,
+		    WSTOPSIG(status));
+
+		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
+		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
+		    WSTOPSIG(status), info.psi_siginfo.si_signo);
+
+		if (WSTOPSIG(status) != SIGTRAP) {
+			int expected_sig =
+			    thread_concurrent_signals_list[info.psi_lwpid %
+			    __arraycount(thread_concurrent_signals_list)];
+			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
+				"lwp=%d, expected %d, got %d", info.psi_lwpid,
+				expected_sig, WSTOPSIG(status));
+
+			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
+		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
+#if defined(__i386__) || defined(__x86_64__)
+			thread_concurrent_lwp_setup(child, info.psi_lwpid);
+#endif
+		} else {
+#if defined(__i386__) || defined(__x86_64__)
+			switch (thread_concurrent_handle_sigtrap(child, &info)) {
+				case TCSE_UNKNOWN:
+					/* already reported inside the function */
+					break;
+				case TCSE_BREAKPOINT:
+					*FIND_EVENT_COUNT(bp_counts,
+					    info.psi_lwpid) += 1;
+					break;
+				case TCSE_WATCHPOINT:
+					*FIND_EVENT_COUNT(wp_counts,
+					    info.psi_lwpid) += 1;
+					break;
+			}
+#else
+			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
+			    info.psi_siginfo.si_code);
+#endif
+		}
+
+		DPRINTF("Before resuming the child process\n");
+		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
+		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
+		     ? WSTOPSIG(status) : 0) != -1);
+	}
+
+	for (i = 0; i < signal_threads; i++)
+		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
+		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
+		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
+	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
+		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
+		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
+		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
+
+	for (i = 0; i < breakpoint_threads; i++)
+		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
+		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
+		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
+	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
+		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
+		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
+		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
+
+	for (i = 0; i < watchpoint_threads; i++)
+		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
+		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
+		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
+	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
+		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
+		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
+		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
+
+	validate_status_exited(status, exitval);
+}
+
+#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
+ATF_TC(test);								\
+ATF_TC_HEAD(test, tc)							\
+{									\
+	atf_tc_set_md_var(tc, "descr", descr);				\
+}									\
+									\
+ATF_TC_BODY(test, tc)							\
+{									\
+	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
+}
+
+THREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
+    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+    "Verify that concurrent signals issued to a single thread are reported "
+    "correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
+    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+    "Verify that concurrent signals issued to a single thread are reported "
+    "correctly and passed back to SIG_IGN handler");
+THREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
+    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+    "Verify that concurrent signals issued to a single thread are reported "
+    "correctly and passed back to a handler function");
+
+#if defined(__i386__) || defined(__x86_64__)
+THREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
+    "Verify that concurrent breakpoints are reported correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
+    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
+    "Verify that concurrent breakpoints are reported correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
+    "Verify that concurrent breakpoints and watchpoints are reported "
+    "correctly");
+
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+    "Verify that concurrent breakpoints and signals are reported correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+    "Verify that concurrent breakpoints and signals are reported correctly "
+    "and passed back to SIG_IGN handler");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+    "Verify that concurrent breakpoints and signals are reported correctly "
+    "and passed back to a handler function");
+
+THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
+    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
+    "Verify that concurrent watchpoints and signals are reported correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
+    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
+    "Verify that concurrent watchpoints and signals are reported correctly "
+    "and passed back to SIG_IGN handler");
+THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
+    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
+    "Verify that concurrent watchpoints and signals are reported correctly "
+    "and passed back to a handler function");
+
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
+    THREAD_CONCURRENT_WATCHPOINT_NUM,
+    "Verify that concurrent breakpoints, watchpoints and signals are reported "
+    "correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
+    THREAD_CONCURRENT_WATCHPOINT_NUM,
+    "Verify that concurrent breakpoints, watchpoints and signals are reported "
+    "correctly and passed back to SIG_IGN handler");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
+    THREAD_CONCURRENT_WATCHPOINT_NUM,
+    "Verify that concurrent breakpoints, watchpoints and signals are reported "
+    "correctly and passed back to a handler function");
+#endif
+
+#endif /*defined(TWAIT_HAVE_STATUS)*/
+
+#define ATF_TP_ADD_TCS_PTRACE_WAIT_THREADS() \
+	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents); \
+	ATF_TP_ADD_TC(tp, trace_thread_lwpexit); \
+	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate); \
+	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit); \
+	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap); \
+	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap); \
+	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap); \
+	ATF_TP_ADD_TC(tp, threads_and_exec); \
+	ATF_TP_ADD_TC(tp, suspend_no_deadlock); \
+	ATF_TP_ADD_TC(tp, resume); \
+	ATF_TP_ADD_TC_HAVE_STATUS(tp, thread_concurrent_signals); \
+	ATF_TP_ADD_TC_HAVE_STATUS(tp, thread_concurrent_signals_sig_ign); \
+	ATF_TP_ADD_TC_HAVE_STATUS(tp, thread_concurrent_signals_handler); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_breakpoints); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_watchpoints); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_wp); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_sig); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_sig_sig_ign); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_sig_handler); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_wp_sig); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_wp_sig_sig_ign); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_wp_sig_handler); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_wp_sig); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_wp_sig_sig_ign); \
+	ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_wp_sig_handler);

Reply via email to