Blame SOURCES/strace-rhbz1610774-0003-Implement-queueing-of-threads-before-dispatching-the.patch

d4bfbf
From c527f21b7528e14b13d2be13acf5c42359e94021 Mon Sep 17 00:00:00 2001
d4bfbf
From: Eugene Syromyatnikov <evgsyr@gmail.com>
d4bfbf
Date: Wed, 8 Aug 2018 21:41:39 +0200
d4bfbf
Subject: [PATCH 3/3] Implement queueing of threads before dispatching them
d4bfbf
d4bfbf
It is possible that some tracees call a lot of cheap syscalls too fast,
d4bfbf
and that can lead to starvation to the point some tracees are not served
d4bfbf
for indefinite amount of time.  In order to solve that unfairness, try
d4bfbf
to collect all the pending tracees first along with the relevant
d4bfbf
information and only then dispatch the events.
d4bfbf
d4bfbf
* defs.h: Include "list.h".
d4bfbf
(struct tcb): Add wait_data_idx and wait_list fields.
d4bfbf
* strace.c (struct tcb_wait_data): Add "msg" field.
d4bfbf
(tcb_wait_tab): New static variable.
d4bfbf
(expand_tcbtab): Resize tcb_wait_tab along with tcbtab, provide
d4bfbf
an additional slot for extra event.
d4bfbf
(droptcb): Remove tcp from wait_list.
d4bfbf
(maybe_switch_tcbs): Get old pid from
d4bfbf
tcb_wait_tab[tcp->wait_data_idx].msg.
d4bfbf
(next_event): Add pending_tcps, extra_tcp, wait_nohang, elem, and
d4bfbf
wait_tab_pos variables; check for elements in pending_tcps and skip
d4bfbf
waiting if the list is not empty; check for extra_tcp and skip waiting
d4bfbf
along with swapping wait_data_idx with wait_extra_data_idx;
d4bfbf
after the initial wait, call wait4() in loop with WNOHANG flag set;
d4bfbf
fetch siginfo on signal and eventmsg on PTRACE_EVENT_EXEC;
d4bfbf
return the first tcp in pending_tcps list.
d4bfbf
* tests/Makefile.am (XFAIL_TEST): Remove looping_threads.test.
d4bfbf
d4bfbf
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=478419
d4bfbf
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=526740
d4bfbf
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=851457
d4bfbf
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1609318
d4bfbf
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1610774
d4bfbf
Co-Authored-by: Dmitry V. Levin <ldv@altlinux.org>
d4bfbf
Co-Authored-by: Denys Vlasenko <dvlasenk@redhat.com>
d4bfbf
Co-Authored-by: Andreas Schwab <aschwab@redhat.com>
d4bfbf
Co-Authored-by: Jeff Law <law@redhat.com>
d4bfbf
Co-Authored-by: DJ Delorie <dj@redhat.com>
d4bfbf
---
d4bfbf
 defs.h            |  10 ++
d4bfbf
 strace.c          | 321 ++++++++++++++++++++++++++++++++++--------------------
d4bfbf
 tests/Makefile.am |   3 +-
d4bfbf
 3 files changed, 212 insertions(+), 122 deletions(-)
d4bfbf
d4bfbf
Index: strace-4.24/defs.h
d4bfbf
===================================================================
d4bfbf
--- strace-4.24.orig/defs.h	2018-09-12 23:52:48.978021943 +0200
d4bfbf
+++ strace-4.24/defs.h	2018-09-12 23:53:35.764480931 +0200
d4bfbf
@@ -57,6 +57,7 @@
d4bfbf
 #include "error_prints.h"
d4bfbf
 #include "gcc_compat.h"
d4bfbf
 #include "kernel_types.h"
d4bfbf
+#include "list.h"
d4bfbf
 #include "macros.h"
d4bfbf
 #include "mpers_type.h"
d4bfbf
 #include "string_to_uint.h"
d4bfbf
@@ -236,6 +237,15 @@
d4bfbf
 
d4bfbf
 	struct mmap_cache_t *mmap_cache;
d4bfbf
 
d4bfbf
+	/*
d4bfbf
+	 * Data that is stored during process wait traversal.
d4bfbf
+	 * We use indices as the actual data is stored in an array
d4bfbf
+	 * that is realloc'ed in runtime.
d4bfbf
+	 */
d4bfbf
+	size_t wait_data_idx;
d4bfbf
+	struct list_item wait_list;
d4bfbf
+
d4bfbf
+
d4bfbf
 #ifdef HAVE_LINUX_KVM_H
d4bfbf
 	struct vcpu_info *vcpu_info_list;
d4bfbf
 #endif
d4bfbf
Index: strace-4.24/strace.c
d4bfbf
===================================================================
d4bfbf
--- strace-4.24.orig/strace.c	2018-09-12 23:53:30.371543291 +0200
d4bfbf
+++ strace-4.24/strace.c	2018-09-12 23:53:35.765480919 +0200
d4bfbf
@@ -161,10 +161,17 @@
d4bfbf
 struct tcb_wait_data {
d4bfbf
 	enum trace_event te; /**< Event passed to dispatch_event() */
d4bfbf
 	int status;          /**< status, returned by wait4() */
d4bfbf
+	unsigned long msg;   /**< Value returned by PTRACE_GETEVENTMSG */
d4bfbf
 	siginfo_t si;        /**< siginfo, returned by PTRACE_GETSIGINFO */
d4bfbf
 };
d4bfbf
 
d4bfbf
 static struct tcb **tcbtab;
d4bfbf
+/*
d4bfbf
+ * Since the queueing of tracees stops as soon as wait4() returns EAGAIN,
d4bfbf
+ * or at least two events for a single tracee, tab_wait_tab size shouldn't
d4bfbf
+ * exceed tcbtabsize + 1.
d4bfbf
+ */
d4bfbf
+static struct tcb_wait_data *tcb_wait_tab;
d4bfbf
 static unsigned int nprocs;
d4bfbf
 static size_t tcbtabsize;
d4bfbf
 
d4bfbf
@@ -750,6 +757,9 @@
d4bfbf
 	for (tcb_ptr = tcbtab + old_tcbtabsize;
d4bfbf
 	    tcb_ptr < tcbtab + tcbtabsize; tcb_ptr++, newtcbs++)
d4bfbf
 		*tcb_ptr = newtcbs;
d4bfbf
+
d4bfbf
+	tcb_wait_tab = xreallocarray(tcb_wait_tab, sizeof(*tcb_wait_tab),
d4bfbf
+				     tcbtabsize + 1);
d4bfbf
 }
d4bfbf
 
d4bfbf
 static struct tcb *
d4bfbf
@@ -853,6 +863,8 @@
d4bfbf
 	if (printing_tcp == tcp)
d4bfbf
 		printing_tcp = NULL;
d4bfbf
 
d4bfbf
+	list_remove(&tcp->wait_list);
d4bfbf
+
d4bfbf
 	memset(tcp, 0, sizeof(*tcp));
d4bfbf
 }
d4bfbf
 
d4bfbf
@@ -2071,10 +2083,8 @@
d4bfbf
 {
d4bfbf
 	FILE *fp;
d4bfbf
 	struct tcb *execve_thread;
d4bfbf
-	long old_pid = 0;
d4bfbf
+	long old_pid = tcb_wait_tab[tcp->wait_data_idx].msg;
d4bfbf
 
d4bfbf
-	if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &old_pid) < 0)
d4bfbf
-		return tcp;
d4bfbf
 	/* Avoid truncation in pid2tcb() param passing */
d4bfbf
 	if (old_pid <= 0 || old_pid == pid)
d4bfbf
 		return tcp;
d4bfbf
@@ -2235,17 +2245,27 @@
d4bfbf
 static const struct tcb_wait_data *
d4bfbf
 next_event(void)
d4bfbf
 {
d4bfbf
-	static struct tcb_wait_data wait_data;
d4bfbf
-
d4bfbf
-	int pid;
d4bfbf
-	int status;
d4bfbf
-	struct tcb *tcp;
d4bfbf
-	struct tcb_wait_data *wd = &wait_data;
d4bfbf
-	struct rusage ru;
d4bfbf
-
d4bfbf
 	if (interrupted)
d4bfbf
 		return NULL;
d4bfbf
 
d4bfbf
+	struct tcb *tcp = NULL;
d4bfbf
+	struct list_item *elem;
d4bfbf
+
d4bfbf
+	static EMPTY_LIST(pending_tcps);
d4bfbf
+	if (!list_is_empty(&pending_tcps))
d4bfbf
+		goto next_event_get_tcp;
d4bfbf
+
d4bfbf
+	static struct tcb *extra_tcp;
d4bfbf
+	static size_t wait_extra_data_idx;
d4bfbf
+	if (extra_tcp) {
d4bfbf
+		tcp = extra_tcp;
d4bfbf
+		extra_tcp = NULL;
d4bfbf
+		tcp->wait_data_idx = wait_extra_data_idx;
d4bfbf
+
d4bfbf
+		debug_msg("dequeued extra event for pid %u", tcp->pid);
d4bfbf
+		goto next_event_exit;
d4bfbf
+	}
d4bfbf
+
d4bfbf
 	/*
d4bfbf
 	 * Used to exit simply when nprocs hits zero, but in this testcase:
d4bfbf
 	 *  int main(void) { _exit(!!fork()); }
d4bfbf
@@ -2287,8 +2307,10 @@
d4bfbf
 	 * then the system call will be interrupted and
d4bfbf
 	 * the expiration will be handled by the signal handler.
d4bfbf
 	 */
d4bfbf
-	pid = wait4(-1, &status, __WALL, (cflag ? &ru : NULL));
d4bfbf
-	const int wait_errno = errno;
d4bfbf
+	int status;
d4bfbf
+	struct rusage ru;
d4bfbf
+	int pid = wait4(-1, &status, __WALL, (cflag ? &ru : NULL));
d4bfbf
+	int wait_errno = errno;
d4bfbf
 
d4bfbf
 	/*
d4bfbf
 	 * The window of opportunity to handle expirations
d4bfbf
@@ -2304,135 +2326,194 @@
d4bfbf
 			return NULL;
d4bfbf
 	}
d4bfbf
 
d4bfbf
-	if (pid < 0) {
d4bfbf
-		if (wait_errno == EINTR) {
d4bfbf
-			wd->te = TE_NEXT;
d4bfbf
-			return wd;
d4bfbf
+	size_t wait_tab_pos = 0;
d4bfbf
+	bool wait_nohang = false;
d4bfbf
+
d4bfbf
+	for (;;) {
d4bfbf
+		struct tcb_wait_data *wd;
d4bfbf
+
d4bfbf
+		if (pid < 0) {
d4bfbf
+			if (wait_errno == EINTR)
d4bfbf
+				break;
d4bfbf
+			if (wait_nohang)
d4bfbf
+				break;
d4bfbf
+			if (nprocs == 0 && wait_errno == ECHILD)
d4bfbf
+				return NULL;
d4bfbf
+			/*
d4bfbf
+			 * If nprocs > 0, ECHILD is not expected,
d4bfbf
+			 * treat it as any other error here:
d4bfbf
+			 */
d4bfbf
+			errno = wait_errno;
d4bfbf
+			perror_msg_and_die("wait4(__WALL)");
d4bfbf
 		}
d4bfbf
-		if (nprocs == 0 && wait_errno == ECHILD)
d4bfbf
-			return NULL;
d4bfbf
-		/*
d4bfbf
-		 * If nprocs > 0, ECHILD is not expected,
d4bfbf
-		 * treat it as any other error here:
d4bfbf
-		 */
d4bfbf
-		errno = wait_errno;
d4bfbf
-		perror_msg_and_die("wait4(__WALL)");
d4bfbf
-	}
d4bfbf
 
d4bfbf
-	wd->status = status;
d4bfbf
+		if (!pid)
d4bfbf
+			break;
d4bfbf
 
d4bfbf
-	if (pid == popen_pid) {
d4bfbf
-		if (!WIFSTOPPED(status))
d4bfbf
-			popen_pid = 0;
d4bfbf
-		wd->te = TE_NEXT;
d4bfbf
-		return wd;
d4bfbf
-	}
d4bfbf
+		if (pid == popen_pid) {
d4bfbf
+			if (!WIFSTOPPED(status))
d4bfbf
+				popen_pid = 0;
d4bfbf
+			break;
d4bfbf
+		}
d4bfbf
 
d4bfbf
-	if (debug_flag)
d4bfbf
-		print_debug_info(pid, status);
d4bfbf
+		if (debug_flag)
d4bfbf
+			print_debug_info(pid, status);
d4bfbf
 
d4bfbf
-	/* Look up 'pid' in our table. */
d4bfbf
-	tcp = pid2tcb(pid);
d4bfbf
+		/* Look up 'pid' in our table. */
d4bfbf
+		tcp = pid2tcb(pid);
d4bfbf
 
d4bfbf
-	if (!tcp) {
d4bfbf
-		tcp = maybe_allocate_tcb(pid, status);
d4bfbf
 		if (!tcp) {
d4bfbf
-			wd->te = TE_NEXT;
d4bfbf
-			return wd;
d4bfbf
+			tcp = maybe_allocate_tcb(pid, status);
d4bfbf
+			if (!tcp)
d4bfbf
+				break;
d4bfbf
 		}
d4bfbf
-	}
d4bfbf
 
d4bfbf
-	clear_regs(tcp);
d4bfbf
+		if (cflag) {
d4bfbf
+			struct timespec stime = {
d4bfbf
+				.tv_sec = ru.ru_stime.tv_sec,
d4bfbf
+				.tv_nsec = ru.ru_stime.tv_usec * 1000
d4bfbf
+			};
d4bfbf
+			ts_sub(&tcp->dtime, &stime, &tcp->stime);
d4bfbf
+			tcp->stime = stime;
d4bfbf
+		}
d4bfbf
+
d4bfbf
+		if (wait_tab_pos > tcbtabsize)
d4bfbf
+			error_func_msg_and_die("Wait data storage overflow "
d4bfbf
+					       "(wait_tab_pos %zu, nprocs %u, "
d4bfbf
+					       "tcbtabsize %zu)", wait_tab_pos,
d4bfbf
+					       nprocs, tcbtabsize);
d4bfbf
+
d4bfbf
+		wd = tcb_wait_tab + wait_tab_pos;
d4bfbf
+		memset(wd, 0, sizeof(*wd));
d4bfbf
+
d4bfbf
+		if (WIFSIGNALED(status)) {
d4bfbf
+			wd->te = TE_SIGNALLED;
d4bfbf
+		} else if (WIFEXITED(status)) {
d4bfbf
+			wd->te = TE_EXITED;
d4bfbf
+		} else {
d4bfbf
+			/*
d4bfbf
+			 * As WCONTINUED flag has not been specified to wait4,
d4bfbf
+			 * it cannot be WIFCONTINUED(status), so the only case
d4bfbf
+			 * that remains is WIFSTOPPED(status).
d4bfbf
+			 */
d4bfbf
 
d4bfbf
-	/* Set current output file */
d4bfbf
-	set_current_tcp(tcp);
d4bfbf
+			const unsigned int sig = WSTOPSIG(status);
d4bfbf
+			const unsigned int event = (unsigned int) status >> 16;
d4bfbf
 
d4bfbf
-	if (cflag) {
d4bfbf
-		struct timespec stime = {
d4bfbf
-			.tv_sec = ru.ru_stime.tv_sec,
d4bfbf
-			.tv_nsec = ru.ru_stime.tv_usec * 1000
d4bfbf
-		};
d4bfbf
-		ts_sub(&tcp->dtime, &stime, &tcp->stime);
d4bfbf
-		tcp->stime = stime;
d4bfbf
-	}
d4bfbf
+			switch (event) {
d4bfbf
+			case 0:
d4bfbf
+				/*
d4bfbf
+				 * Is this post-attach SIGSTOP?
d4bfbf
+				 * Interestingly, the process may stop
d4bfbf
+				 * with STOPSIG equal to some other signal
d4bfbf
+				 * than SIGSTOP if we happened to attach
d4bfbf
+				 * just before the process takes a signal.
d4bfbf
+				 */
d4bfbf
+				if (sig == SIGSTOP &&
d4bfbf
+				    (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)) {
d4bfbf
+					debug_func_msg("ignored SIGSTOP on "
d4bfbf
+						       "pid %d", tcp->pid);
d4bfbf
+					tcp->flags &= ~TCB_IGNORE_ONE_SIGSTOP;
d4bfbf
+					wd->te = TE_RESTART;
d4bfbf
+				} else if (sig == syscall_trap_sig) {
d4bfbf
+					wd->te = TE_SYSCALL_STOP;
d4bfbf
+				} else {
d4bfbf
+					/*
d4bfbf
+					 * True if tracee is stopped by signal
d4bfbf
+					 * (as opposed to "tracee received
d4bfbf
+					 * signal").
d4bfbf
+					 * TODO: shouldn't we check for
d4bfbf
+					 * errno == EINVAL too?
d4bfbf
+					 * We can get ESRCH instead, you know...
d4bfbf
+					 */
d4bfbf
+					bool stopped = ptrace(PTRACE_GETSIGINFO,
d4bfbf
+						pid, 0, &wd->si) < 0;
d4bfbf
 
d4bfbf
-	if (WIFSIGNALED(status)) {
d4bfbf
-		wd->te = TE_SIGNALLED;
d4bfbf
-		return wd;
d4bfbf
-	}
d4bfbf
+					wd->te = stopped ? TE_GROUP_STOP
d4bfbf
+							 : TE_SIGNAL_DELIVERY_STOP;
d4bfbf
+				}
d4bfbf
+				break;
d4bfbf
+			case PTRACE_EVENT_STOP:
d4bfbf
+				/*
d4bfbf
+				 * PTRACE_INTERRUPT-stop or group-stop.
d4bfbf
+				 * PTRACE_INTERRUPT-stop has sig == SIGTRAP here.
d4bfbf
+				 */
d4bfbf
+				switch (sig) {
d4bfbf
+				case SIGSTOP:
d4bfbf
+				case SIGTSTP:
d4bfbf
+				case SIGTTIN:
d4bfbf
+				case SIGTTOU:
d4bfbf
+					wd->te = TE_GROUP_STOP;
d4bfbf
+					break;
d4bfbf
+				default:
d4bfbf
+					wd->te = TE_RESTART;
d4bfbf
+				}
d4bfbf
+				break;
d4bfbf
+			case PTRACE_EVENT_EXEC:
d4bfbf
+					/*
d4bfbf
+					 * TODO: shouldn't we check for
d4bfbf
+					 * errno == EINVAL here, too?
d4bfbf
+					 * We can get ESRCH instead, you know...
d4bfbf
+					 */
d4bfbf
+				if (ptrace(PTRACE_GETEVENTMSG, pid, NULL,
d4bfbf
+				    &wd->msg) < 0)
d4bfbf
+					wd->msg = 0;
d4bfbf
 
d4bfbf
-	if (WIFEXITED(status)) {
d4bfbf
-		wd->te = TE_EXITED;
d4bfbf
-		return wd;
d4bfbf
+				wd->te = TE_STOP_BEFORE_EXECVE;
d4bfbf
+				break;
d4bfbf
+			case PTRACE_EVENT_EXIT:
d4bfbf
+				wd->te = TE_STOP_BEFORE_EXIT;
d4bfbf
+				break;
d4bfbf
+			default:
d4bfbf
+				wd->te = TE_RESTART;
d4bfbf
+			}
d4bfbf
+		}
d4bfbf
+
d4bfbf
+		if (tcp->wait_list.next) {
d4bfbf
+			wait_extra_data_idx = wait_tab_pos;
d4bfbf
+			extra_tcp = tcp;
d4bfbf
+			debug_func_msg("queued extra pid %d", tcp->pid);
d4bfbf
+		} else {
d4bfbf
+			tcp->wait_data_idx = wait_tab_pos;
d4bfbf
+			list_append(&pending_tcps, &tcp->wait_list);
d4bfbf
+			debug_func_msg("queued pid %d", tcp->pid);
d4bfbf
+		}
d4bfbf
+
d4bfbf
+		wd->status = status;
d4bfbf
+		wait_tab_pos++;
d4bfbf
+
d4bfbf
+		if (extra_tcp)
d4bfbf
+			break;
d4bfbf
+
d4bfbf
+		pid = wait4(-1, &status, __WALL | WNOHANG, (cflag ? &ru : NULL));
d4bfbf
+		wait_errno = errno;
d4bfbf
+		wait_nohang = true;
d4bfbf
 	}
d4bfbf
 
d4bfbf
-	/*
d4bfbf
-	 * As WCONTINUED flag has not been specified to wait4,
d4bfbf
-	 * it cannot be WIFCONTINUED(status), so the only case
d4bfbf
-	 * that remains is WIFSTOPPED(status).
d4bfbf
-	 */
d4bfbf
+next_event_get_tcp:
d4bfbf
+	elem = list_remove_head(&pending_tcps);
d4bfbf
+
d4bfbf
+	if (!elem) {
d4bfbf
+		memset(tcb_wait_tab, 0, sizeof(*tcb_wait_tab));
d4bfbf
+		tcb_wait_tab->te = TE_NEXT;
d4bfbf
+
d4bfbf
+		return tcb_wait_tab;
d4bfbf
+	} else {
d4bfbf
+		tcp = list_elem(elem, struct tcb, wait_list);
d4bfbf
+		debug_func_msg("dequeued pid %d", tcp->pid);
d4bfbf
+	}
d4bfbf
 
d4bfbf
+next_event_exit:
d4bfbf
 	/* Is this the very first time we see this tracee stopped? */
d4bfbf
 	if (tcp->flags & TCB_STARTUP)
d4bfbf
 		startup_tcb(tcp);
d4bfbf
 
d4bfbf
-	const unsigned int sig = WSTOPSIG(status);
d4bfbf
-	const unsigned int event = (unsigned int) status >> 16;
d4bfbf
+	clear_regs(tcp);
d4bfbf
 
d4bfbf
-	switch (event) {
d4bfbf
-	case 0:
d4bfbf
-		/*
d4bfbf
-		 * Is this post-attach SIGSTOP?
d4bfbf
-		 * Interestingly, the process may stop
d4bfbf
-		 * with STOPSIG equal to some other signal
d4bfbf
-		 * than SIGSTOP if we happened to attach
d4bfbf
-		 * just before the process takes a signal.
d4bfbf
-		 */
d4bfbf
-		if (sig == SIGSTOP && (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)) {
d4bfbf
-			debug_func_msg("ignored SIGSTOP on pid %d", tcp->pid);
d4bfbf
-			tcp->flags &= ~TCB_IGNORE_ONE_SIGSTOP;
d4bfbf
-			wd->te = TE_RESTART;
d4bfbf
-		} else if (sig == syscall_trap_sig) {
d4bfbf
-			wd->te = TE_SYSCALL_STOP;
d4bfbf
-		} else {
d4bfbf
-			memset(&wd->si, 0, sizeof(wd->si));
d4bfbf
-			/*
d4bfbf
-			 * True if tracee is stopped by signal
d4bfbf
-			 * (as opposed to "tracee received signal").
d4bfbf
-			 * TODO: shouldn't we check for errno == EINVAL too?
d4bfbf
-			 * We can get ESRCH instead, you know...
d4bfbf
-			 */
d4bfbf
-			bool stopped = ptrace(PTRACE_GETSIGINFO, pid, 0, &wd->si) < 0;
d4bfbf
-			wd->te = stopped ? TE_GROUP_STOP : TE_SIGNAL_DELIVERY_STOP;
d4bfbf
-		}
d4bfbf
-		break;
d4bfbf
-	case PTRACE_EVENT_STOP:
d4bfbf
-		/*
d4bfbf
-		 * PTRACE_INTERRUPT-stop or group-stop.
d4bfbf
-		 * PTRACE_INTERRUPT-stop has sig == SIGTRAP here.
d4bfbf
-		 */
d4bfbf
-		switch (sig) {
d4bfbf
-		case SIGSTOP:
d4bfbf
-		case SIGTSTP:
d4bfbf
-		case SIGTTIN:
d4bfbf
-		case SIGTTOU:
d4bfbf
-			wd->te = TE_GROUP_STOP;
d4bfbf
-			break;
d4bfbf
-		default:
d4bfbf
-			wd->te = TE_RESTART;
d4bfbf
-		}
d4bfbf
-		break;
d4bfbf
-	case PTRACE_EVENT_EXEC:
d4bfbf
-		wd->te = TE_STOP_BEFORE_EXECVE;
d4bfbf
-		break;
d4bfbf
-	case PTRACE_EVENT_EXIT:
d4bfbf
-		wd->te = TE_STOP_BEFORE_EXIT;
d4bfbf
-		break;
d4bfbf
-	default:
d4bfbf
-		wd->te = TE_RESTART;
d4bfbf
-	}
d4bfbf
+	/* Set current output file */
d4bfbf
+	set_current_tcp(tcp);
d4bfbf
 
d4bfbf
-	return wd;
d4bfbf
+	return tcb_wait_tab + tcp->wait_data_idx;
d4bfbf
 }
d4bfbf
 
d4bfbf
 static int
d4bfbf
Index: strace-4.24/tests/Makefile.am
d4bfbf
===================================================================
d4bfbf
--- strace-4.24.orig/tests/Makefile.am	2018-09-12 23:53:31.739527473 +0200
d4bfbf
+++ strace-4.24/tests/Makefile.am	2018-09-12 23:53:35.765480919 +0200
d4bfbf
@@ -367,8 +367,7 @@
d4bfbf
 XFAIL_TESTS_mx32 = $(STACKTRACE_TESTS)
d4bfbf
 XFAIL_TESTS_x86_64 = int_0x80.gen.test
d4bfbf
 XFAIL_TESTS_x32 = int_0x80.gen.test
d4bfbf
-XFAIL_TESTS = $(XFAIL_TESTS_$(MPERS_NAME)) $(XFAIL_TESTS_$(ARCH)) \
d4bfbf
-	      looping_threads.test
d4bfbf
+XFAIL_TESTS = $(XFAIL_TESTS_$(MPERS_NAME)) $(XFAIL_TESTS_$(ARCH))
d4bfbf
 
d4bfbf
 TEST_LOG_COMPILER = env
d4bfbf
 AM_TEST_LOG_FLAGS = STRACE_ARCH=$(ARCH) STRACE_NATIVE_ARCH=$(NATIVE_ARCH) \