Blame SOURCES/strace-rh851457.patch

7e4834
diff -Nrup a/defs.h b/defs.h
7e4834
--- a/defs.h	2016-05-29 20:29:14.000000000 -0400
7e4834
+++ b/defs.h	2016-07-22 16:52:17.891092163 -0400
7e4834
@@ -294,6 +294,9 @@ struct tcb {
7e4834
 	int pid;		/* If 0, this tcb is free */
7e4834
 	int qual_flg;		/* qual_flags[scno] or DEFAULT_QUAL_FLAGS + RAW */
7e4834
 	int u_error;		/* Error code */
7e4834
+	int wait_status;        /* Status from last wait() */
7e4834
+	struct tcb *next_need_service;
7e4834
+				/* Linked list of tracees found by wait()s */
7e4834
 	long scno;		/* System call number */
7e4834
 	long u_arg[MAX_ARGS];	/* System call arguments */
7e4834
 #if defined(LINUX_MIPSN32) || defined(X32)
7e4834
diff -Nrup a/strace.c b/strace.c
7e4834
--- a/strace.c	2016-05-26 11:34:28.000000000 -0400
7e4834
+++ b/strace.c	2016-07-22 16:52:17.895092175 -0400
7e4834
@@ -2095,17 +2095,40 @@ startup_tcb(struct tcb *tcp)
7e4834
 	}
7e4834
 }
7e4834
 
7e4834
+static int remembered_pid;
7e4834
+static int remembered_status;
7e4834
+
7e4834
 /* Returns true iff the main trace loop has to continue. */
7e4834
 static bool
7e4834
 trace(void)
7e4834
 {
7e4834
 	int pid;
7e4834
+	struct tcb *tcp;
7e4834
+	struct tcb *found_tcps;
7e4834
+	struct tcb **nextp;
7e4834
+	struct tcb *next;
7e4834
+	int wnohang = 0;
7e4834
+
7e4834
+	if (remembered_pid) {
7e4834
+		pid = remembered_pid;
7e4834
+		remembered_pid = 0;
7e4834
+		if (debug_flag)
7e4834
+			fprintf(stderr, " [remembered wait(%#x) = %u]\n",
7e4834
+						remembered_status, pid);
7e4834
+		tcp = pid2tcb(pid); /* can't be NULL */
7e4834
+		tcp->wait_status = remembered_status;
7e4834
+		tcp->next_need_service = NULL;
7e4834
+		found_tcps = tcp;
7e4834
+		goto process_saved_tcbs;
7e4834
+	}
7e4834
+
7e4834
+	nextp = &found_tcps;
7e4834
+	found_tcps = NULL;
7e4834
+
7e4834
+	while (1) { /* RH 851457 - collect tcbs */
7e4834
 	int wait_errno;
7e4834
 	int status;
7e4834
-	bool stopped;
7e4834
-	unsigned int sig;
7e4834
 	unsigned int event;
7e4834
-	struct tcb *tcp;
7e4834
 	struct rusage ru;
7e4834
 
7e4834
 	if (interrupted)
7e4834
@@ -2134,14 +2157,24 @@ trace(void)
7e4834
 
7e4834
 	if (interactive)
7e4834
 		sigprocmask(SIG_SETMASK, &empty_set, NULL);
7e4834
-	pid = wait4(-1, &status, __WALL, (cflag ? &ru : NULL));
7e4834
+	pid = wait4(-1, &status, __WALL | wnohang, (cflag ? &ru : NULL));
7e4834
 	wait_errno = errno;
7e4834
 	if (interactive)
7e4834
 		sigprocmask(SIG_BLOCK, &blocked_set, NULL);
7e4834
 
7e4834
+	if (pid <= 0 && wnohang) {
7e4834
+		/* We had at least one successful
7e4834
+		 * wait() before. We waited
7e4834
+		 * with WNOHANG second time.
7e4834
+		 * Stop collecting more tracees,
7e4834
+		 * process what we already have.
7e4834
+		 */
7e4834
+		break; /* out of collect tcbs */
7e4834
+	}
7e4834
+
7e4834
 	if (pid < 0) {
7e4834
 		if (wait_errno == EINTR)
7e4834
-			return true;
7e4834
+			break; /* out of collect tcbs */
7e4834
 		if (nprocs == 0 && wait_errno == ECHILD)
7e4834
 			return false;
7e4834
 		/*
7e4834
@@ -2155,7 +2188,7 @@ trace(void)
7e4834
 	if (pid == popen_pid) {
7e4834
 		if (!WIFSTOPPED(status))
7e4834
 			popen_pid = 0;
7e4834
-		return true;
7e4834
+		break; /* out of collect tcbs */
7e4834
 	}
7e4834
 
7e4834
 	if (debug_flag)
7e4834
@@ -2167,14 +2200,9 @@ trace(void)
7e4834
 	if (!tcp) {
7e4834
 		tcp = maybe_allocate_tcb(pid, status);
7e4834
 		if (!tcp)
7e4834
-			return true;
7e4834
+			break; /* out of collect tcbs */
7e4834
 	}
7e4834
 
7e4834
-	if (WIFSTOPPED(status))
7e4834
-		get_regs(pid);
7e4834
-	else
7e4834
-		clear_regs();
7e4834
-
7e4834
 	event = (unsigned int) status >> 16;
7e4834
 
7e4834
 	if (event == PTRACE_EVENT_EXEC) {
7e4834
@@ -2198,29 +2226,86 @@ trace(void)
7e4834
 
7e4834
 		if (detach_on_execve && !skip_one_b_execve) {
7e4834
 			detach(tcp); /* do "-b execve" thingy */
7e4834
-			return true;
7e4834
+			break; /* out of collect tcbs */
7e4834
 		}
7e4834
 		skip_one_b_execve = 0;
7e4834
 	}
7e4834
 
7e4834
-	/* Set current output file */
7e4834
-	current_tcp = tcp;
7e4834
-
7e4834
 	if (cflag) {
7e4834
 		tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
7e4834
 		tcp->stime = ru.ru_stime;
7e4834
 	}
7e4834
 
7e4834
+	/* If we waited and got a stopped task notification,
7e4834
+	 * subsequent wait may return the same pid again, for example,
7e4834
+	 * with SIGKILL notification. SIGKILL kills even stopped tasks.
7e4834
+	 * We must not add it to the list
7e4834
+	 * (one task can't be inserted twice in the list).
7e4834
+	 */
7e4834
+	{
7e4834
+		struct tcb *f = found_tcps;
7e4834
+		while (f) {
7e4834
+			if (f == tcp) {
7e4834
+				remembered_pid = pid;
7e4834
+				remembered_status = status;
7e4834
+				goto process_saved_tcbs;
7e4834
+			}
7e4834
+			f = f->next_need_service;
7e4834
+		}
7e4834
+	}
7e4834
+	/* It is important to not invert the order of tasks
7e4834
+	 * to process. For one, alloc_tcb() above picks newly forked
7e4834
+	 * threads in some order, processing of them and their parent
7e4834
+	 * should be in the same order, otherwise bad things happen
7e4834
+	 * (misinterpreted SIGSTOPs and such).
7e4834
+	 */
7e4834
+	tcp->wait_status = status;
7e4834
+	*nextp = tcp;
7e4834
+	nextp = &tcp->next_need_service;
7e4834
+	*nextp = NULL;
7e4834
+	wnohang = WNOHANG;
7e4834
+
7e4834
+	} /* RH 851457 - collect tcbs */
7e4834
+
7e4834
+process_saved_tcbs:
7e4834
+
7e4834
+	for (tcp = found_tcps;
7e4834
+	     tcp;
7e4834
+	     tcp = next) { /* RH 851457 - process tcbs */
7e4834
+	int status;
7e4834
+	bool stopped;
7e4834
+	unsigned int sig;
7e4834
+	unsigned int event;
7e4834
+
7e4834
+	/* If the child exits, the TCP will get dropped and
7e4834
+	   thus we can't use it to find the next TCP needing
7e4834
+	   service.  So we save the next TCP needing service
7e4834
+	   and used the saved value when the loop iterates.  */
7e4834
+	next = tcp->next_need_service;
7e4834
+
7e4834
+	status = tcp->wait_status;
7e4834
+	pid = tcp->pid;
7e4834
+
7e4834
+	event = ((unsigned)status >> 16);
7e4834
+
7e4834
+	if (WIFSTOPPED(status))
7e4834
+		get_regs(pid);
7e4834
+	else
7e4834
+		clear_regs();
7e4834
+
7e4834
+	/* Set current output file */
7e4834
+	current_tcp = tcp;
7e4834
+
7e4834
 	if (WIFSIGNALED(status)) {
7e4834
 		print_signalled(tcp, pid, status);
7e4834
 		droptcb(tcp);
7e4834
-		return true;
7e4834
+		continue; /* processing tcbs */
7e4834
 	}
7e4834
 
7e4834
 	if (WIFEXITED(status)) {
7e4834
 		print_exited(tcp, pid, status);
7e4834
 		droptcb(tcp);
7e4834
-		return true;
7e4834
+		continue; /* processing tcbs */
7e4834
 	}
7e4834
 
7e4834
 	if (!WIFSTOPPED(status)) {
7e4834
@@ -2230,7 +2315,7 @@ trace(void)
7e4834
 		 */
7e4834
 		error_msg("pid %u not stopped!", pid);
7e4834
 		droptcb(tcp);
7e4834
-		return true;
7e4834
+		continue; /* processing tcbs */
7e4834
 	}
7e4834
 
7e4834
 	/* Is this the very first time we see this tracee stopped? */
7e4834
@@ -2308,7 +2393,7 @@ show_stopsig:
7e4834
 				exit_code = 1;
7e4834
 				return false;
7e4834
 			}
7e4834
-			return true;
7e4834
+			continue; /* processing tcbs */
7e4834
 		}
7e4834
 		/* We don't have PTRACE_LISTEN support... */
7e4834
 		goto restart_tracee;
7e4834
@@ -2334,7 +2419,7 @@ show_stopsig:
7e4834
 		 * we can let this process to report its death to us
7e4834
 		 * normally, via WIFEXITED or WIFSIGNALED wait status.
7e4834
 		 */
7e4834
-		return true;
7e4834
+		continue; /* processing tcbs */
7e4834
 	}
7e4834
 
7e4834
 restart_tracee_with_sig_0:
7e4834
@@ -2347,6 +2432,8 @@ restart_tracee:
7e4834
 		return false;
7e4834
 	}
7e4834
 
7e4834
+	} /* RH 851457 - process tcbs */
7e4834
+
7e4834
 	return true;
7e4834
 }
7e4834