Patch to support Linux threaded programs even better

Ganesan R rganesan at myrealbox.com
Mon Apr 2 09:55:15 UTC 2001


Wichert,

I don't know if you've already released 4.3, the attached patch fixes some
more problems using strace with multi-threaded programs on Linux. Please
include it in the release if possible. 

When I submitted my previous patch, I had commented that strace exits with a
message SIGRT_0 and I couldn't understand what was going on. It turns out
that LinuxThreads uses SIGRTMIN, SIGRTMIN + 1 and SIGRTMIN + 2 internally
for thread restarting, cancellation and debugging internally. My first
attempt at the patch simply handled these as a special case. Then I dug in
further to see *why* these signals didn't appear in the "caught" signals for
the process.

Digging into the kernel sources I found this comment for the /proc/pid/stat
interface.

-- from fs/proc/array.c

/* The signal information here is obsolete.
 * It must be decimal for Linux 2.0 compatibility.
 * Use /proc/#/status for real-time signals.
 */

-- end snippet

No wonder strace thinks these signals are not handled! The attached patch
parses the /proc/pid/status file instead. Tracing LinuxThreads programs works
much better now. 

The only remaining problem is that when strace exits while tracing a
threaded process (for eg when the user hits Ctrl-C), the process is left in
the STOPPED state. This may be a kernel bug, I'll investigate further when I
have some time. 

Parsing /proc/#/status every time is going to be a big performance hit for
MT programs, I am planning to work on a patch that caches the information
and re-parse it only when the process makes a signal related syscall.
Meanwhile, the attached patch at least works :-).

Ganesan

-- 
Ganesan R <rganesan at myrealbox.com>   | Ph: 91-422-549 860 (Home)
Novell India, Bangalore              | #include <std_disclaimer.h>
-------------- next part --------------
Index: signal.c
===================================================================
RCS file: /cvsroot/strace/strace/signal.c,v
retrieving revision 1.28
diff -u -r1.28 signal.c
--- signal.c	2001/03/28 20:29:17	1.28
+++ signal.c	2001/04/02 09:35:58
@@ -378,40 +378,54 @@
 #ifdef LINUX
 	int sfd;
 	char sname[32];
-	char buf[1024];
+	char buf[2048];
 	char *s;
 	int i;
-	unsigned int signalled, blocked, ignored, caught;
+	/* We also need to handle RT signals */
+	unsigned long long signalled, blocked, ignored, caught;
 
 	/* This is incredibly costly but it's worth it. */
-	sprintf(sname, "/proc/%d/stat", tcp->pid);
+	/* NOTE: LinuxThreads internally uses SIGRTMIN, SIGRTMIN + 1 and
+	   SIGRTMIN + 2, so we can't use the obsolete /proc/%d/stat which
+	   doesn't handle real-time signals). */
+	sprintf(sname, "/proc/%d/status", tcp->pid);
 	if ((sfd = open(sname, O_RDONLY)) == -1) {
 		perror(sname);
 		return 1;
 	}
-	i = read(sfd, buf, 1024);
+	i = read(sfd, buf, sizeof(buf));
 	buf[i] = '\0';
 	close(sfd);
 	/*
-	 * Skip the extraneous fields. This loses if the
+	 * Skip the extraneous fields. We need to skip
 	 * command name has any spaces in it.  So be it.
 	 */
-	for (i = 0, s = buf; i < 30; i++) {
-		while (*++s != ' ') {
-			if (!*s)
-				break;
-		}
-	}
-	if (sscanf(s, "%u%u%u%u",
-		   &signalled, &blocked, &ignored, &caught) != 4) {
-		fprintf(stderr, "/proc/pid/stat format error\n");
+	s = strstr(buf, "SigPnd:\t");
+
+	if (!s)
+	{
+		fprintf(stderr, "/proc/pid/status format error\n");
 		return 1;
 	}
+
+	while (*s && *s++ != '\t')
+		;
+	s += sscanf(s, "%qx", &signalled);
+	while (*s && *s++ != '\t')
+		;
+	s += sscanf(s, "%qx", &blocked);
+	while (*s && *s++ != '\t')
+		;
+	s += sscanf(s, "%qx", &ignored);
+	while (*s && *s++ != '\t')
+		;
+	s += sscanf(s, "%qx", &caught);
+
 #ifdef DEBUG
 	fprintf(stderr, "sigs: %08x %08x %08x %08x\n",
 		signalled, blocked, ignored, caught);
 #endif
-	if ((ignored & sigmask(sig)) || (caught & sigmask(sig)))
+	if ((ignored & (1ULL << sig)) || (caught & (1ULL << sig)))
 		return 1;
 #endif /* LINUX */
 


More information about the Strace-devel mailing list