Blob Blame History Raw
--- lsof_4.78C-rh/dialects/linux/dproc.c.kzak	2006-06-12 19:10:05.000000000 +0200
+++ lsof_4.78C-rh/dialects/linux/dproc.c	2006-08-09 23:25:14.000000000 +0200
@@ -69,7 +69,8 @@
 _PROTOTYPE(static int read_proc_stat,(char *p, int pid, char **cmd, int *ppid,
 	   int *pgid));
 _PROTOTYPE(static int statEx,(char *p, struct stat *s, int *ss));
- 
+_PROTOTYPE(static int get_other_thread,(int pid, char **tid));
+
 
 #if	defined(HASSELINUX)
 _PROTOTYPE(static int cmp_cntx_eq,(char *pcntx, char *ucntx));
@@ -148,6 +149,7 @@
 	static char *path = (char *)NULL;
 	static int pathl = 0;
 	int pgid, pid, ppid;
+	char *tid = NULL;
 	static char *pidpath = (char *)NULL;
 	static MALLOC_S pidpathl = 0;
 	static MALLOC_S pidx = 0;
@@ -253,6 +255,13 @@
 	    }
 	    if (f)
 		continue;
+
+	    tid = NULL;
+	    if (get_other_thread(pid, &tid) < 0)
+		continue;
+	    if (tid)
+		n += sizeof("task/") + strlen(tid);
+
 	/*
 	 * Build path to PID's directory.
 	 */
@@ -266,7 +275,14 @@
 		    Exit(1);
 		}
 	    }
-	    (void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name);
+	    if (tid) {
+		/* /proc/<pid> is useless (zombie), we have to use /proc/<pid>/task/<tid>
+		 * where is still running thread
+		 */
+		(void) snpf(pidpath + pidx, pidpathl - pidx, "%s/task/%s/", dp->d_name, tid);
+		free(tid);
+	    } else
+		(void) snpf(pidpath + pidx, pidpathl - pidx, "%s/", dp->d_name);
 	    n += (pidx + 1);
 	/*
 	 * Process the PID's stat info.
@@ -897,6 +913,60 @@
 	(void) fclose(ms);
 }
 
+/* fill tid if the initial thread is zombie, 
+ * but other thread still alive 
+ *
+ * returns -1=error, 0=nothing, 1=ok
+ */
+static int
+get_other_thread(pid, tid)
+	int pid;
+	char **tid;
+{
+	char path[MAXPATHLEN];
+	DIR *tdp;
+	struct dirent *td;
+	char pstate;
+	FILE *f;
+	int _pid;
+	int re = 0;
+
+	snpf(path, sizeof(path), "%s/%d/stat", PROCFS, pid);
+	if (!(f = fopen(path, "r")))
+		return;
+	fscanf(f, "%d %*s %c", &_pid, &pstate);
+	fclose(f);
+	if (_pid != pid)
+		return -1;		/* corrupted /proc? */
+	if (pstate!='Z') 
+		return 0;		/* ignore normal proceses */
+
+	snpf(path, sizeof(path), "%s/%d/task", PROCFS, pid);
+
+	/* open /proc/<pid>/task */
+	if (!(tdp = opendir(path)))
+		return 0;		/* kernel < 2.6.x */
+	
+	/* look for first alive thread */
+	while ((td = readdir(tdp))) {
+		if (strcmp(td->d_name, ".")==0 || strcmp(td->d_name, "..")==0)
+			continue;
+		
+		/* /proc/<pid>/task/<tid>/stat */
+		snpf(path, sizeof(path), "%s/%d/task/%s/stat", PROCFS, pid, td->d_name);
+		if (!(f = fopen(path, "r")))
+			continue;
+		fscanf(f, "%*d %*s %c", &pstate);
+		fclose(f);
+		if (pstate!='Z') {
+			re = 1;
+			*tid = strdup(td->d_name);
+			break;
+		}
+	}
+	closedir(tdp);
+	return re;
+}
 
 /*
  * read_proc_stat() - read process status
@@ -931,12 +1001,6 @@
 	if ((nf = get_fields(buf, (char *)NULL, &fp, (int *)NULL, 0)) < 5)
 	    return(1);
 /*
- * Convert the first field to an integer; its conversion must match the
- * PID argument.
- */
-	if (atoi(fp[0]) != pid)
-	    return(1);
-/*
  * Get the command name from the second field.  Strip a starting '(' and
  * an ending ')'.  Allocate space to hold the result and return the space
  * pointer.