Blame SOURCES/strace-rh851457.patch

1ca6dd
diff -Nrup a/defs.h b/defs.h
1ca6dd
--- a/defs.h	2013-05-14 08:10:42.000000000 -0600
1ca6dd
+++ b/defs.h	2013-06-13 09:46:36.972244927 -0600
1ca6dd
@@ -398,6 +398,9 @@ struct tcb {
1ca6dd
 	int pid;		/* Process Id of this entry */
1ca6dd
 	int qual_flg;		/* qual_flags[scno] or DEFAULT_QUAL_FLAGS + RAW */
1ca6dd
 	int u_error;		/* Error code */
1ca6dd
+	int wait_status;	/* Status from last wait() */
1ca6dd
+	struct tcb *next_need_service;
1ca6dd
+				/* Linked list of tracees found by wait()s */
1ca6dd
 	long scno;		/* System call number */
1ca6dd
 	long u_arg[MAX_ARGS];	/* System call arguments */
1ca6dd
 #if defined(LINUX_MIPSN32) || defined(X32)
1ca6dd
diff -Nrup a/strace.c b/strace.c
1ca6dd
--- a/strace.c	2013-05-28 15:49:16.000000000 -0600
1ca6dd
+++ b/strace.c	2013-06-13 09:46:45.381217727 -0600
1ca6dd
@@ -1895,21 +1895,42 @@ interrupt(int sig)
1ca6dd
 	interrupted = sig;
1ca6dd
 }
1ca6dd
 
1ca6dd
-static int
1ca6dd
-trace(void)
1ca6dd
+static int remembered_pid;
1ca6dd
+static int remembered_status;
1ca6dd
+
1ca6dd
+static struct tcb *
1ca6dd
+collect_stopped_tcbs(void)
1ca6dd
 {
1ca6dd
 	struct rusage ru;
1ca6dd
 	struct rusage *rup = cflag ? &ru : NULL;
1ca6dd
+	struct tcb *found_tcps;
1ca6dd
+	struct tcb **nextp;
1ca6dd
+	int wnohang = 0;
1ca6dd
+	int pid;
1ca6dd
+	struct tcb *tcp;
1ca6dd
+
1ca6dd
 #ifdef __WALL
1ca6dd
 	static int wait4_options = __WALL;
1ca6dd
 #endif
1ca6dd
 
1ca6dd
+	if (remembered_pid) {
1ca6dd
+		pid = remembered_pid;
1ca6dd
+		remembered_pid = 0;
1ca6dd
+		if (debug_flag)
1ca6dd
+			fprintf(stderr, " [remembered wait(%#x) = %u]\n",
1ca6dd
+						remembered_status, pid);
1ca6dd
+		tcp = pid2tcb(pid); /* can't be NULL */
1ca6dd
+		tcp->wait_status = remembered_status;
1ca6dd
+		tcp->next_need_service = NULL;
1ca6dd
+		return tcp;
1ca6dd
+	}
1ca6dd
+
1ca6dd
+	nextp = &found_tcps;
1ca6dd
+	found_tcps = NULL;
1ca6dd
+
1ca6dd
 	while (nprocs != 0) {
1ca6dd
-		int pid;
1ca6dd
 		int wait_errno;
1ca6dd
-		int status, sig;
1ca6dd
-		int stopped;
1ca6dd
-		struct tcb *tcp;
1ca6dd
+		int status;
1ca6dd
 		unsigned event;
1ca6dd
 
1ca6dd
 		if (interrupted)
1ca6dd
@@ -1917,26 +1938,36 @@ trace(void)
1ca6dd
 		if (interactive)
1ca6dd
 			sigprocmask(SIG_SETMASK, &empty_set, NULL);
1ca6dd
 #ifdef __WALL
1ca6dd
-		pid = wait4(-1, &status, wait4_options, rup);
1ca6dd
+		pid = wait4(-1, &status, wait4_options | wnohang, rup);
1ca6dd
 		if (pid < 0 && (wait4_options & __WALL) && errno == EINVAL) {
1ca6dd
 			/* this kernel does not support __WALL */
1ca6dd
 			wait4_options &= ~__WALL;
1ca6dd
-			pid = wait4(-1, &status, wait4_options, rup);
1ca6dd
+			pid = wait4(-1, &status, wait4_options | wnohang, rup);
1ca6dd
 		}
1ca6dd
 		if (pid < 0 && !(wait4_options & __WALL) && errno == ECHILD) {
1ca6dd
 			/* most likely a "cloned" process */
1ca6dd
-			pid = wait4(-1, &status, __WCLONE, rup);
1ca6dd
-			if (pid < 0) {
1ca6dd
+			pid = wait4(-1, &status, __WCLONE | wnohang, rup);
1ca6dd
+			if (pid < 0 && errno != ECHILD) {
1ca6dd
 				perror_msg("wait4(__WCLONE) failed");
1ca6dd
 			}
1ca6dd
 		}
1ca6dd
 #else
1ca6dd
-		pid = wait4(-1, &status, 0, rup);
1ca6dd
+		pid = wait4(-1, &status, wnohang, rup);
1ca6dd
 #endif /* __WALL */
1ca6dd
 		wait_errno = errno;
1ca6dd
 		if (interactive)
1ca6dd
 			sigprocmask(SIG_BLOCK, &blocked_set, NULL);
1ca6dd
 
1ca6dd
+		if (pid == 0 && wnohang) {
1ca6dd
+			/* We had at least one successful
1ca6dd
+			 * wait() before. We waited
1ca6dd
+			 * with WNOHANG second time.
1ca6dd
+			 * Stop collecting more tracees,
1ca6dd
+			 * process what we already have.
1ca6dd
+			 */
1ca6dd
+			break;
1ca6dd
+		}
1ca6dd
+
1ca6dd
 		if (pid < 0) {
1ca6dd
 			switch (wait_errno) {
1ca6dd
 			case EINTR:
1ca6dd
@@ -1948,11 +1979,11 @@ trace(void)
1ca6dd
 				 * version of SunOS sometimes reports
1ca6dd
 				 * ECHILD before sending us SIGCHILD.
1ca6dd
 				 */
1ca6dd
-				return 0;
1ca6dd
+				return found_tcps;
1ca6dd
 			default:
1ca6dd
 				errno = wait_errno;
1ca6dd
 				perror_msg("wait");
1ca6dd
-				return -1;
1ca6dd
+				return (struct tcb *) -1;
1ca6dd
 			}
1ca6dd
 		}
1ca6dd
 		if (pid == popen_pid) {
1ca6dd
@@ -2092,14 +2123,68 @@ trace(void)
1ca6dd
 			skip_one_b_execve = 0;
1ca6dd
 		}
1ca6dd
 
1ca6dd
-		/* Set current output file */
1ca6dd
-		current_tcp = tcp;
1ca6dd
-
1ca6dd
 		if (cflag) {
1ca6dd
 			tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
1ca6dd
 			tcp->stime = ru.ru_stime;
1ca6dd
 		}
1ca6dd
 
1ca6dd
+		/* If we waited and got a stopped task notification,
1ca6dd
+		 * subsequent wait may return the same pid again, for example,
1ca6dd
+		 * with SIGKILL notification. SIGKILL kills even stopped tasks.
1ca6dd
+		 * We must not add it to the list
1ca6dd
+		 * (one task can't be inserted twice in the list).
1ca6dd
+		 */
1ca6dd
+		{
1ca6dd
+			struct tcb *f = found_tcps;
1ca6dd
+			while (f) {
1ca6dd
+				if (f == tcp) {
1ca6dd
+					remembered_pid = pid;
1ca6dd
+					remembered_status = status;
1ca6dd
+					return found_tcps;
1ca6dd
+				}
1ca6dd
+				f = f->next_need_service;
1ca6dd
+			}
1ca6dd
+		}
1ca6dd
+
1ca6dd
+		/* It is important to not invert the order of tasks
1ca6dd
+		 * to process. For one, alloc_tcb() above picks newly forked
1ca6dd
+		 * threads in some order, processing of them and their parent
1ca6dd
+		 * should be in the same order, otherwise bad things happen
1ca6dd
+		 * (misinterpreted SIGSTOPs and such).
1ca6dd
+		 */
1ca6dd
+		tcp->wait_status = status;
1ca6dd
+		*nextp = tcp;
1ca6dd
+		nextp = &tcp->next_need_service;
1ca6dd
+		*nextp = NULL;
1ca6dd
+		wnohang = WNOHANG;
1ca6dd
+	}
1ca6dd
+	return found_tcps;
1ca6dd
+}
1ca6dd
+
1ca6dd
+static int
1ca6dd
+handle_stopped_tcbs(struct tcb *tcp)
1ca6dd
+{
1ca6dd
+	struct tcb *next;
1ca6dd
+
1ca6dd
+	for (; tcp; tcp = next) {
1ca6dd
+		int pid;
1ca6dd
+		int status;
1ca6dd
+		int sig;
1ca6dd
+		int event;
1ca6dd
+		int stopped;
1ca6dd
+
1ca6dd
+
1ca6dd
+		/* If the child exits, the TCP will get dropped and
1ca6dd
+		   thus we can't use it to find the next TCP needing
1ca6dd
+		   service.  So we save the next TCP needing service
1ca6dd
+		   and used the saved value when the loop iterates.  */
1ca6dd
+		next = tcp->next_need_service;
1ca6dd
+
1ca6dd
+		current_tcp = tcp;
1ca6dd
+		status = tcp->wait_status;
1ca6dd
+		pid = tcp->pid;
1ca6dd
+
1ca6dd
+                event = ((unsigned)status >> 16);
1ca6dd
 		if (WIFSIGNALED(status)) {
1ca6dd
 			if (pid == strace_child)
1ca6dd
 				exit_code = 0x100 | WTERMSIG(status);
1ca6dd
@@ -2302,6 +2387,27 @@ trace(void)
1ca6dd
 	return 0;
1ca6dd
 }
1ca6dd
 
1ca6dd
+static int
1ca6dd
+trace(void)
1ca6dd
+{
1ca6dd
+	int rc;
1ca6dd
+	struct tcb *tcbs;
1ca6dd
+
1ca6dd
+	while (nprocs != 0) {
1ca6dd
+		if (interrupted)
1ca6dd
+			return 0;
1ca6dd
+		tcbs = collect_stopped_tcbs();
1ca6dd
+		if (!tcbs)
1ca6dd
+			break;
1ca6dd
+		if (tcbs == (struct tcb *) -1)
1ca6dd
+			return -1;
1ca6dd
+		rc = handle_stopped_tcbs(tcbs);
1ca6dd
+		if (rc)
1ca6dd
+			return rc;
1ca6dd
+	}
1ca6dd
+ 	return 0;
1ca6dd
+}
1ca6dd
+
1ca6dd
 int
1ca6dd
 main(int argc, char *argv[])
1ca6dd
 {
1ca6dd
diff -Nrup a/tests/Makefile.am b/tests/Makefile.am
1ca6dd
--- a/tests/Makefile.am	2013-05-07 20:06:39.000000000 -0600
1ca6dd
+++ b/tests/Makefile.am	2013-06-13 10:01:52.103302835 -0600
1ca6dd
@@ -4,7 +4,8 @@ AM_CFLAGS = $(WARN_CFLAGS)
1ca6dd
 
1ca6dd
 check_PROGRAMS = net-accept-connect
1ca6dd
 
1ca6dd
-TESTS = ptrace_setoptions strace-f qual_syscall stat net
1ca6dd
+# "net" test disabled as it is highly dependent on timing issues
1ca6dd
+TESTS = ptrace_setoptions strace-f qual_syscall stat
1ca6dd
 
1ca6dd
 EXTRA_DIST = init.sh $(TESTS)
1ca6dd
 
1ca6dd
diff -Nrup a/tests/Makefile.in b/tests/Makefile.in
1ca6dd
--- a/tests/Makefile.in	2013-06-04 18:02:45.000000000 -0600
1ca6dd
+++ b/tests/Makefile.in	2013-06-13 10:02:17.535221388 -0600
1ca6dd
@@ -201,7 +201,7 @@ top_build_prefix = @top_build_prefix@
1ca6dd
 top_builddir = @top_builddir@
1ca6dd
 top_srcdir = @top_srcdir@
1ca6dd
 AM_CFLAGS = $(WARN_CFLAGS)
1ca6dd
-TESTS = ptrace_setoptions strace-f qual_syscall stat net
1ca6dd
+TESTS = ptrace_setoptions strace-f qual_syscall stat 
1ca6dd
 EXTRA_DIST = init.sh $(TESTS)
1ca6dd
 CLEANFILES = check.log
1ca6dd
 all: all-am