]> granicus.if.org Git - procps-ng/commitdiff
ps thread support
authoralbert <>
Sat, 20 Sep 2003 08:29:55 +0000 (08:29 +0000)
committeralbert <>
Sat, 20 Sep 2003 08:29:55 +0000 (08:29 +0000)
16 files changed:
Makefile
NEWS
pgrep.c
proc/library.map
proc/readproc.c
proc/readproc.h
procps.lsm
procps.spec
ps/common.h
ps/display.c
ps/global.c
ps/output.c
ps/parser.c
ps/select.c
top.c
w.c

index 93e49350de7c8408301686ed1febeaa7e429966d..9538e6737952565efd03627580c573ec06c35f25 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -18,9 +18,9 @@
 
 VERSION      := 3
 SUBVERSION   := 1
-MINORVERSION := 12
-TARVERSION   := 3.1.12
-LIBVERSION   := 3.1.12
+MINORVERSION := 13
+TARVERSION   := 3.1.13
+LIBVERSION   := 3.1.13
 
 ############ vars
 
diff --git a/NEWS b/NEWS
index c8f729b2e993f8e69e9823749d1e9b0939a6f3f4..4eb11403ca550b41153bffdcb0d6ab87186774cb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,6 @@
 procps-3.1.12 --> procps-3.1.13
 
+ps: can display NPTL threads w/ kernel patch
 no seLinux for now (new kernel interface)
 
 procps-3.1.11 --> procps-3.1.12
diff --git a/pgrep.c b/pgrep.c
index 8ba1c65b59208091712c917fb5703994324f55b3..13e6768d1f31cc07453d4aa350faba8c10468241 100644 (file)
--- a/pgrep.c
+++ b/pgrep.c
@@ -375,7 +375,7 @@ select_procs (void)
        while (readproc (ptp, &task)) {
                int match = 1;
 
-               if (task.pid == myself)
+               if (task.XXXID == myself)
                        continue;
                else if (opt_newest && task.start_time < saved_start_time)
                        match = 0;
@@ -399,7 +399,7 @@ select_procs (void)
                        } else {
                                char tty[256];
                                dev_to_tty (tty, sizeof(tty) - 1,
-                                           task.tty, task.pid, ABBREV_DEV);
+                                           task.tty, task.XXXID, ABBREV_DEV);
                                match = match_strlist (tty, opt_term);
                        }
                }
@@ -433,26 +433,26 @@ select_procs (void)
                if (match ^ opt_negate) {       /* Exclusive OR is neat */
                        if (opt_newest) {
                                if (saved_start_time == task.start_time &&
-                                   saved_pid > task.pid)
+                                   saved_pid > task.XXXID)
                                        continue;
                                saved_start_time = task.start_time;
-                               saved_pid = task.pid;
+                               saved_pid = task.XXXID;
                                matches = 0;
                        }
                        if (opt_oldest) {
                                if (saved_start_time == task.start_time &&
-                                   saved_pid < task.pid)
+                                   saved_pid < task.XXXID)
                                        continue;
                                saved_start_time = task.start_time;
-                               saved_pid = task.pid;
+                               saved_pid = task.XXXID;
                                matches = 0;
                        }
                        if (opt_long) {
                                char buff[5096];  // FIXME
-                               sprintf (buff, "%d %s", task.pid, cmd);
+                               sprintf (buff, "%d %s", task.XXXID, cmd);
                                list[++matches].str = strdup (buff);
                        } else {
-                               list[++matches].num = task.pid;
+                               list[++matches].num = task.XXXID;
                        }
                        if (matches == size) {
                                size *= 2;
index 810440d60d35d442223c9923bcbc171e2724d865..fca514ef7d4d30db9841f1f2fd2e2faafa7a25b8 100644 (file)
@@ -2,7 +2,7 @@ _3_1_12 {
 global:
   __cyg_profile_func_enter; __cyg_profile_func_exit; main;
 
-  readproc; readproctab; look_up_our_self; escape_command;
+  readproc; readtask; readproctab; look_up_our_self; escape_command;
   escape_str; escape_strlist;
   openproc; closeproc;
   tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; wchan;
index 32ebc10e6637a3285d969051564875d127eee3a3..64ff0e53c1453f271383221305f1adfb6260f15f 100644 (file)
@@ -41,6 +41,8 @@ extern void __cyg_profile_func_enter(void*,void*);
 #define LEAVE(x)
 #endif
 
+static int task_dir_missing;
+
 ///////////////////////////////////////////////////////////////////////////
 
 typedef struct status_table_struct {
@@ -211,7 +213,7 @@ ENTER(0x220);
         P->ppid = strtol(S,&S,10);
         continue;
     case_Pid:
-        P->pid = strtol(S,&S,10);
+        P->tid = strtol(S,&S,10);
         continue;
 
     case_ShdPnd:
@@ -464,9 +466,10 @@ int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){
 // This reads process info from /proc in the traditional way, for one process.
 // The pid (tgid? tid?) is already in p, and a path to it in path, with some
 // room to spare.
-static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) {
+static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
     static struct stat sb;             // stat() buffer
     static char sbuf[1024];    // buffer for stat,statm
+    char *restrict const path = PT->path;
     unsigned flags = PT->flags;
 
     if (unlikely(stat(path, &sb) == -1))       /* no such dirent (anymore) */
@@ -530,40 +533,144 @@ next_proc:
     return NULL;
 }
 
+//////////////////////////////////////////////////////////////////////////////////
+// This reads /proc/*/task/* data, for one task.
+// p is the POSIX process (task group summary) (not needed by THIS implementation)
+// t is the POSIX thread (task group member, generally not the leader)
+// path is a path to the task, with some room to spare.
+static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict const t, char *restrict const path) {
+    static struct stat sb;             // stat() buffer
+    static char sbuf[1024];    // buffer for stat,statm
+    unsigned flags = PT->flags;
+
+    if (unlikely(stat(path, &sb) == -1))       /* no such dirent (anymore) */
+       goto next_task;
+
+//    if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
+//     goto next_task;                 /* not one of the requested uids */
+
+    t->euid = sb.st_uid;                       /* need a way to get real uid */
+    t->egid = sb.st_gid;                       /* need a way to get real gid */
+
+    if (flags & PROC_FILLSTAT) {         /* read, parse /proc/#/stat */
+       if (unlikely( file2str(path, "stat", sbuf, sizeof sbuf) == -1 ))
+           goto next_task;                     /* error reading /proc/#/stat */
+       stat2proc(sbuf, t);                             /* parse /proc/#/stat */
+    }
+
+    if (unlikely(flags & PROC_FILLMEM)) {      /* read, parse /proc/#/statm */
+       if (likely( file2str(path, "statm", sbuf, sizeof sbuf) != -1 ))
+           statm2proc(sbuf, t);                /* ignore statm errors here */
+    }                                          /* statm fields just zero */
+
+    if (flags & PROC_FILLSTATUS) {         /* read, parse /proc/#/status */
+       if (likely( file2str(path, "status", sbuf, sizeof sbuf) != -1 )){
+           status2proc(sbuf, t);
+       }
+    }
+
+    /* some number->text resolving which is time consuming */
+    if (flags & PROC_FILLUSR){
+       strncpy(t->euser,   user_from_uid(t->euid), sizeof t->euser);
+        if(flags & PROC_FILLSTATUS) {
+            strncpy(t->ruser,   user_from_uid(t->ruid), sizeof t->ruser);
+            strncpy(t->suser,   user_from_uid(t->suid), sizeof t->suser);
+            strncpy(t->fuser,   user_from_uid(t->fuid), sizeof t->fuser);
+        }
+    }
+
+    /* some number->text resolving which is time consuming */
+    if (flags & PROC_FILLGRP){
+        strncpy(t->egroup, group_from_gid(t->egid), sizeof t->egroup);
+        if(flags & PROC_FILLSTATUS) {
+            strncpy(t->rgroup, group_from_gid(t->rgid), sizeof t->rgroup);
+            strncpy(t->sgroup, group_from_gid(t->sgid), sizeof t->sgroup);
+            strncpy(t->fgroup, group_from_gid(t->fgid), sizeof t->fgroup);
+        }
+    }
+
+#if 0
+    if ((flags & PROC_FILLCOM) || (flags & PROC_FILLARG))      /* read+parse /proc/#/cmdline */
+       t->cmdline = file2strvec(path, "cmdline");
+    else
+        t->cmdline = NULL;
+
+    if (unlikely(flags & PROC_FILLENV))                        /* read+parse /proc/#/environ */
+       t->environ = file2strvec(path, "environ");
+    else
+        t->environ = NULL;
+#else
+    t->cmdline = p->cmdline;  // better not free these until done with all threads!
+    t->environ = p->environ;
+#endif
+
+    return t;
+next_task:
+    return NULL;
+}
+
 //////////////////////////////////////////////////////////////////////////////////
 // This finds processes in /proc in the traditional way.
 // Return non-zero on success.
-static int simple_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) {
+static int simple_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
   static struct direct *ent;           /* dirent handle */
+  char *restrict const path = PT->path;
   for (;;) {
     ent = readdir(PT->procfs);
     if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0;
     if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break;
   }
-  p->pid = strtoul(ent->d_name, NULL, 10);
+  p->tgid = strtoul(ent->d_name, NULL, 10);
+  p->tid = p->tgid;
   memcpy(path, "/proc/", 6);
   strcpy(path+6, ent->d_name);  // trust /proc to not contain evil top-level entries
   return 1;
 }
 
-#define PROCPATHLEN 64   // must hold /proc/2000222000/task/2000222000/cmdline
+//////////////////////////////////////////////////////////////////////////////////
+// This finds tasks in /proc/*/task/ in the traditional way.
+// Return non-zero on success.
+static int simple_nexttid(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict const t, char *restrict const path) {
+  static struct direct *ent;           /* dirent handle */
+  (void)p;
+  if(!PT->taskdir){
+    // use "path" as some tmp space
+    snprintf(path, PROCPATHLEN, "%s/task", PT->path);
+    PT->taskdir = opendir(path);
+    if(!PT->taskdir) return 0;
+  }
+  for (;;) {
+    ent = readdir(PT->taskdir);
+    if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0;
+    if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break;
+  }
+  t->tid = strtoul(ent->d_name, NULL, 10);
+  t->tgid = p->tgid;
+  t->ppid = p->ppid;  // cover for kernel behavior? we want both actually...?
+  snprintf(path, PROCPATHLEN, "%s/task/%s", PT->path, ent->d_name);
+  return 1;
+}
 
 //////////////////////////////////////////////////////////////////////////////////
 // This "finds" processes in a list that was given to openproc().
-// Return non-zero on success. (pid was handy)
-static int listed_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) {
-  pid_t pid = *(PT->pids)++;
-  if(likely( pid )){
-    snprintf(path, PROCPATHLEN, "/proc/%d", pid);
-    p->pid = pid;
+// Return non-zero on success. (tgid was handy)
+static int listed_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
+  char *restrict const path = PT->path;
+  pid_t tgid = *(PT->pids)++;
+  if(likely( tgid )){
+    snprintf(path, PROCPATHLEN, "/proc/%d", tgid);
+    p->tgid = tgid;
+    p->tid = tgid;  // they match for leaders
   }
-  return pid;
+  return tgid;
 }
 
 //////////////////////////////////////////////////////////////////////////////////
 // This "finds" processes by guessing every possible one of them!
 // Return non-zero on success. (pid was handy)
-static int stupid_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) {
+#if 0
+static int stupid_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
+  char *restrict const path = PT->path;
   pid_t pid = --PT->u;
   if(likely( pid )){
     snprintf(path, PROCPATHLEN, "/proc/%d", pid);
@@ -571,15 +678,16 @@ static int stupid_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p,
   }
   return pid;
 }
+#endif
 
 //////////////////////////////////////////////////////////////////////////////////
 // This reads process info from proc_t structs already attached to a PROCTAB.
 // Yeah, we don't retain any pointer for freeing the memory later. Oh well.
 // This code is for development only.
-static proc_t* predone_readproc(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) {
+#if 0
+static proc_t* predone_readproc(PROCTAB *restrict const PT, proc_t *restrict const p) {
   proc_t *tmp;
   proc_t *ret = NULL;
-  (void)path;
   for(;;){
     tmp = PT->vp;
     if(!tmp) _exit(49);  // can't happen
@@ -598,15 +706,17 @@ static proc_t* predone_readproc(PROCTAB *restrict const PT, proc_t *restrict con
   }
   return ret;
 }
+#endif
 
 //////////////////////////////////////////////////////////////////////////////////
 // This "finds" processes by pulling them off of a list.
 // Return non-zero on success.
-static int predone_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) {
+#if 0
+static int predone_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p) {
   (void)p;
-  (void)path;
   return !!PT->vp;
 }
+#endif
 
 //////////////////////////////////////////////////////////////////////////////////
 /* readproc: return a pointer to a proc_t filled with requested info about the
@@ -620,29 +730,70 @@ static int predone_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p,
  * fairly complex, but it does try to not to do any unnecessary work.
  */
 proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) {
-  static char path[PROCPATHLEN];       // must hold /proc/2000222000/task/2000222000/cmdline
   proc_t *ret;
   proc_t *saved_p;
 
+  if (PT->did_fake) PT->did_fake=0;
+  if (PT->taskdir) {
+    closedir(PT->taskdir);
+    PT->taskdir = NULL;
+  }
+
   saved_p = p;
   if(!p) p = xcalloc(p, sizeof *p); /* passed buf or alloced mem */
 
   for(;;){
-    // fills in the path and the p->pid
-    if (unlikely(! PT->finder(PT,p,path) )) goto out;
+    // fills in the path, plus p->tid and p->tgid
+    if (unlikely(! PT->finder(PT,p) )) goto out;
 
     // go read the process data
-    ret = PT->reader(PT,p,path);
+    ret = PT->reader(PT,p);
     if(ret) return ret;
   }
 
 out:
   if(!saved_p) free(p);
+  // FIXME: maybe set tid to -1 here, for "-" in display?
+  return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// readtask: return a pointer to a proc_t filled with requested info about the
+// next task available.  If no more such tasks are available, return a null
+// pointer (boolean false).  Use the passed buffer instead of allocating
+// space if it is non-NULL.
+proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t) {
+  static char path[PROCPATHLEN];       // must hold /proc/2000222000/task/2000222000/cmdline
+  proc_t *ret;
+  proc_t *saved_t;
+
+  saved_t = t;
+  if(!t) t = xcalloc(t, sizeof *t); /* passed buf or alloced mem */
+
+  if(task_dir_missing){  // got to fake a thread for old kernels
+    if(PT->did_fake) goto out;
+    PT->did_fake=1;
+    memcpy(t,p,sizeof(proc_t));
+    return t;
+  }
+
+  for(;;){
+    // fills in the path, plus t->tid and t->tgid
+    if (unlikely(! PT->taskfinder(PT,p,t,path) )) goto out;  // simple_nexttid
+
+    // go read the task data
+    ret = PT->taskreader(PT,p,t,path);          // simple_readtask
+    if(ret) return ret;
+  }
+
+out:
+  if(!saved_t) free(t);
   return NULL;
 }
 
 //////////////////////////////////////////////////////////////////////////////////
 
+#if 0
 static void evil_grouping_hack(PROCTAB* PT){
   proc_t *tp;
   // first we read them
@@ -676,13 +827,23 @@ static void evil_grouping_hack(PROCTAB* PT){
   PT->finder = predone_nextpid;
   PT->reader = predone_readproc;
 }
-
+#endif
 
 // initiate a process table scan
 PROCTAB* openproc(int flags, ...) {
     va_list ap;
+    struct stat sbuf;
+    static int did_stat;
     PROCTAB* PT = xmalloc(sizeof(PROCTAB));
-    
+
+    if(!did_stat){
+      task_dir_missing = stat("/proc/self/task", &sbuf);
+      did_stat = 1;
+    }
+    PT->taskdir = NULL;
+    PT->taskfinder = simple_nexttid;
+    PT->taskreader = simple_readtask;
+
     PT->reader = simple_readproc;
     if (flags & PROC_PID){
       PT->procfs = NULL;
@@ -694,10 +855,12 @@ PROCTAB* openproc(int flags, ...) {
     }
     PT->flags = flags;
 
+#if 0
     if(getenv("EVIL_FINDER_HACK")){  // for development only
       PT->finder = stupid_nextpid;
       PT->u = 10000;
     }
+#endif
 
     va_start(ap, flags);               /*  Init args list */
     if (flags & PROC_PID)
@@ -708,7 +871,9 @@ PROCTAB* openproc(int flags, ...) {
     }
     va_end(ap);                                /*  Clean up args list */
 
+#if 0
     if(getenv("EVIL_GROUPING_HACK")) evil_grouping_hack(PT);
+#endif
 
     return PT;
 }
@@ -717,6 +882,7 @@ PROCTAB* openproc(int flags, ...) {
 void closeproc(PROCTAB* PT) {
     if (PT){
         if (PT->procfs) closedir(PT->procfs);
+        if (PT->taskdir) closedir(PT->taskdir);
         free(PT);
     }
 }
index 82a1b7c41f68b165e79004e9b51c55e5e487fb40..6617b3b5dcfd30e882f230b3320c709fcb299aa6 100644 (file)
@@ -26,6 +26,11 @@ EXTERN_C_BEGIN
  lu    start_time, vsize, wchan, nswap, cnswap,
 */
 
+// This is to help document a transition from pid to tgid/tid caused
+// by the introduction of thread support. It is used in cases where
+// neither tgid nor tid seemed correct. (in other words, FIXME)
+#define XXXID tid
+
 /* Basic data structure which holds all information we can get about a process.
  * (unless otherwise specified, fields are read from /proc/#/stat)
  *
@@ -34,7 +39,7 @@ EXTERN_C_BEGIN
 typedef struct proc_t {
 // 1st 16 bytes
     int
-        pid,           /* process id */
+        tid,           /* process id */
        ppid;           /* pid of parent process */
     unsigned
         pcpu;           /* %CPU usage (is not filled in by readproc!!!) */
@@ -144,10 +149,17 @@ typedef struct proc_t {
 #include <sys/types.h>
 #include <dirent.h>
 #include <unistd.h>
+
+#define PROCPATHLEN 64  // must hold /proc/2000222000/task/2000222000/cmdline
+
 typedef struct PROCTAB {
     DIR*       procfs;
-    int(*finder)(struct PROCTAB *restrict const, proc_t *restrict const, char *restrict const);
-    proc_t*(*reader)(struct PROCTAB *restrict const, proc_t *restrict const, char *restrict const);
+    DIR*       taskdir;  // for threads
+    int         did_fake; // used when taskdir is missing
+    int(*finder)(struct PROCTAB *restrict const, proc_t *restrict const);
+    proc_t*(*reader)(struct PROCTAB *restrict const, proc_t *restrict const);
+    int(*taskfinder)(struct PROCTAB *restrict const, const proc_t *restrict const, proc_t *restrict const, char *restrict const);
+    proc_t*(*taskreader)(struct PROCTAB *restrict const, const proc_t *restrict const, proc_t *restrict const, char *restrict const);
     unsigned   flags;
     pid_t*     pids;   /* pids of the procs */
     uid_t*     uids;   /* uids of procs */
@@ -155,6 +167,8 @@ typedef struct PROCTAB {
     int         i;  // generic
     unsigned    u;  // generic
     void *      vp; // generic
+    char        path[PROCPATHLEN];  // must hold /proc/2000222000/task/2000222000/cmdline
+    unsigned pathlen;        // length of string in the above (w/o '\0')
 } PROCTAB;
 
 // initialize a PROCTAB structure holding needed call-to-call persistent data
@@ -172,7 +186,8 @@ extern proc_t** readproctab(int flags, ... /* same as openproc */ );
 extern void closeproc(PROCTAB* PT);
 
 // retrieve the next process matching the criteria set by the openproc()
-extern proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict const return_buf);
+extern proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p);
+extern proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t);
 
 // warning: interface may change
 extern int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid);
@@ -207,8 +222,6 @@ extern void freeproc(proc_t* p);
 #define PROC_FILLWCHAN  0x0080 /* look up WCHAN name */
 #define PROC_FILLARG    0x0100 /* alloc and fill in `cmdline' */
 
-#define PROC_FILLANY    0x0000 /* either stat or status will do */
-
 /* Obsolete, consider only processes with one of the passed: */
 #define PROC_PID     0x1000  /* process id numbers ( 0   terminated) */
 #define PROC_UID     0x4000  /* user id numbers    ( length needed ) */
index 3191206692a18588ef0cfc410f06a2587f9d36da..77fbe1971c4bf0f71f178e8b4c15cb8970017689 100644 (file)
@@ -1,15 +1,15 @@
 Begin4
 Title: procps
-Version: 3.1.12
-Entered-date: 2003-08-10
+Version: 3.1.13
+Entered-date: 2003-09-17
 Description: Linux system utilities
 Keywords: procps /proc libproc sysctl pmap ps uptime tload
        free w top vmstat watch skill snice kill pgrep pkill
 Author: Albert Cahalan, Michael K. Johnson, Jim Warner, etc.
 Maintained-by: various <procps-feedback@lists.sf.net>
 Primary-site: http://procps.sf.net/
-       242kB procps-3.1.12.tar.gz
+       242kB procps-3.1.13.tar.gz
 Alternate-site: http://www.debian.org/Packages/unstable/base/procps.html
-       242kB procps-3.1.12.tar.gz
+       242kB procps-3.1.13.tar.gz
 Copying-policy: mixed
 End
index 79f6f1a2f0214e561bb644dd30b4e0844dc16300..2d5074b3e62b2a067a467e79edef1a68b5514230 100644 (file)
@@ -3,7 +3,7 @@ Summary: System and process monitoring utilities
 Name: procps
 %define major_version 3
 %define minor_version 1
-%define revision 12
+%define revision 13
 %define version %{major_version}.%{minor_version}.%{revision}
 Version: %{version}
 Release: 1
index e9ba85beef701017ec5e2cb188088e568cfc4f6e..c254ec5f3fb7a102ce2aa18833aa998247dc4d8a 100644 (file)
 
 #define needs_for_select (PROC_FILLSTAT | PROC_FILLSTATUS)
 
+/* thread_flags */
+#define TF_show_proc 0x0001  // show the summary line
+#define TF_show_task 0x0002  // show the per-thread lines
+
 /* personality control flags */
 #define PER_BROKEN_o      0x0001
 #define PER_BSD_h         0x0002
@@ -270,6 +274,7 @@ extern const char     *sysv_f_format;
 extern const char     *sysv_fl_format;
 extern const char     *sysv_j_format;
 extern const char     *sysv_l_format;
+extern unsigned        thread_flags;
 extern int             unix_f_option;
 extern int             user_is_number;
 extern int             wchan_is_number;
index 2d5222b514acddf06fd898bc5550f4931d9d6e83..39bb895ca587f9911876f318421c6e78a42d24c1 100644 (file)
@@ -81,12 +81,12 @@ void hex_dump(void *vp){
   }
 }
 
-static void show_pid(char *s, int n, sel_union *data){
+static void show_tgid(char *s, int n, sel_union *data){
   printf("%s  ", s);
   while(--n){
-    printf("%d,", data[n].pid);
+    printf("%d,", data[n].tgid);
   }
-  printf("%d\n", data[0].pid);
+  printf("%d\n", data[0].tgid);
 }
 
 static void show_uid(char *s, int n, sel_union *data){
@@ -247,9 +247,18 @@ static void simple_spew(void){
     fprintf(stderr, "Error: can not access /proc.\n");
     exit(1);
   }
+  if(!thread_flags) thread_flags=TF_show_proc;
   memset(&buf, '#', sizeof(proc_t));
   while(readproc(ptp,&buf)){
-    if(want_this_proc(&buf)) show_one_proc(&buf);
+    if(want_this_proc(&buf)){
+      if(thread_flags & TF_show_proc) show_one_proc(&buf);
+      if(thread_flags & TF_show_task){
+        proc_t buf2;
+        // must still have the process allocated
+        while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2);
+        // must not attempt to free cmdline and environ
+      }
+    }
     if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
     if(buf.environ) free((void*)*buf.environ); // ought to reuse
 //    memset(&buf, '#', sizeof(proc_t));
@@ -331,7 +340,7 @@ static void show_tree(const int self, const int n, const int level, const int ha
 //  if(processes[self]->environ) free((void*)*processes[self]->environ);
   for(;;){  /* look for children */
     if(i >= n) return; /* no children */
-    if(processes[i]->ppid == processes[self]->pid) break;
+    if(processes[i]->ppid == processes[self]->XXXID) break;
     i++;
   }
   if(level){
@@ -344,7 +353,7 @@ static void show_tree(const int self, const int n, const int level, const int ha
     int self_pid;
     int more_children = 1;
     if(i >= n) break; /* over the edge */
-    self_pid=processes[self]->pid;
+    self_pid=processes[self]->XXXID;
     if(i+1 >= n)
       more_children = 0;
     else
@@ -367,7 +376,7 @@ static void show_forest(const int n){
   while(i--){   /* cover whole array looking for trees */
     j = n;
     while(j--){   /* search for parent: if none, i is a tree! */
-      if(processes[j]->pid == processes[i]->ppid) goto not_root;
+      if(processes[j]->XXXID == processes[i]->ppid) goto not_root;
     }
     show_tree(i,n,0,0);
 not_root:
@@ -381,6 +390,10 @@ static void fancy_spew(void){
   proc_t *retbuf = NULL;
   PROCTAB *restrict ptp;
   int n = 0;  /* number of processes & index into array */
+  if(thread_flags){
+    fprintf(stderr, "can't have threads with sorting or forest output\n");
+    exit(49);
+  }
   ptp = openproc(needs_for_format | needs_for_sort | needs_for_select);
   if(!ptp) {
     fprintf(stderr, "Error: can not access /proc.\n");
index edd4cf9aa405c3de7dc8a633689bb35f5f6a4306..ea77d91631372b24bb83a9120ca553e02c990858 100644 (file)
@@ -73,6 +73,7 @@ const char     *sysv_f_format = (const char *)0xdeadbeef;
 const char     *sysv_fl_format = (const char *)0xdeadbeef;
 const char     *sysv_j_format = (const char *)0xdeadbeef;
 const char     *sysv_l_format = (const char *)0xdeadbeef;
+unsigned        thread_flags = 0xffffffff;
 int             unix_f_option = -1;
 int             user_is_number = -1;
 int             wchan_is_number = -1;
@@ -343,6 +344,7 @@ void reset_global(void){
   selection_list        = NULL;
   simple_select         = 0;
   sort_list             = NULL;
+  thread_flags          = 0;
   unix_f_option         = 0;
   user_is_number        = 0;
   wchan_is_number       = 0;
index e20114ad19948c1c0079ca10d8cb4fa905b49ad6..97e958f9fd2c9e55c5e2aa2181b18717fd510820 100644 (file)
@@ -201,7 +201,8 @@ CMP_INT(suid)
 CMP_INT(sgid)
 CMP_INT(fuid)
 CMP_INT(fgid)
-CMP_SMALL(pid)
+CMP_SMALL(tid)
+CMP_SMALL(tgid)
 CMP_SMALL(ppid)
 CMP_SMALL(pgrp)
 CMP_SMALL(session)
@@ -457,7 +458,7 @@ static int pr_pgid(char *restrict const outbuf, const proc_t *restrict const pp)
   return snprintf(outbuf, COLWID, "%u", pp->pgrp);
 }
 static int pr_pid(char *restrict const outbuf, const proc_t *restrict const pp){
-  return snprintf(outbuf, COLWID, "%u", pp->pid);
+  return snprintf(outbuf, COLWID, "%u", pp->tgid);
 }
 static int pr_ppid(char *restrict const outbuf, const proc_t *restrict const pp){
   return snprintf(outbuf, COLWID, "%u", pp->ppid);
@@ -561,20 +562,20 @@ static int pr_wchan(char *restrict const outbuf, const proc_t *restrict const pp
  */
     if(!(pp->wchan & 0xffffff)) return snprintf(outbuf, COLWID, "%s", "-");
     if(wchan_is_number) return snprintf(outbuf, COLWID, "%x", (unsigned)(pp->wchan) & 0xffffffu);
-    return snprintf(outbuf, COLWID, "%s", wchan(pp->wchan, pp->pid));
+    return snprintf(outbuf, COLWID, "%s", wchan(pp->wchan, pp->XXXID));
 }
 
 /* Terrible trunctuation, like BSD crap uses: I999 J999 K999 */
 /* FIXME: disambiguate /dev/tty69 and /dev/pts/69. */
 static int pr_tty4(char *restrict const outbuf, const proc_t *restrict const pp){
 /* snprintf(outbuf, COLWID, "%02x:%02x", pp->tty>>8, pp->tty&0xff); */
-  return dev_to_tty(outbuf, 4, pp->tty, pp->pid, ABBREV_DEV|ABBREV_TTY|ABBREV_PTS);
+  return dev_to_tty(outbuf, 4, pp->tty, pp->XXXID, ABBREV_DEV|ABBREV_TTY|ABBREV_PTS);
 }
 
 /* Unix98: format is unspecified, but must match that used by who(1). */
 static int pr_tty8(char *restrict const outbuf, const proc_t *restrict const pp){
 /* snprintf(outbuf, COLWID, "%02x:%02x", pp->tty>>8, pp->tty&0xff); */
-  return dev_to_tty(outbuf, PAGE_SIZE-1, pp->tty, pp->pid, ABBREV_DEV);
+  return dev_to_tty(outbuf, PAGE_SIZE-1, pp->tty, pp->XXXID, ABBREV_DEV);
 }
 
 #if 0
@@ -767,7 +768,7 @@ static int pr_wname(char *restrict const outbuf, const proc_t *restrict const pp
  * more than one thread waiting in the kernel.
  */
     if(!(pp->wchan & 0xffffff)) return snprintf(outbuf, COLWID, "%s", "-");
-    return snprintf(outbuf, COLWID, "%s", wchan(pp->wchan, pp->pid));
+    return snprintf(outbuf, COLWID, "%s", wchan(pp->wchan, pp->XXXID));
 }
 
 static int pr_nwchan(char *restrict const outbuf, const proc_t *restrict const pp){
@@ -937,7 +938,7 @@ static int pr_suser(char *restrict const outbuf, const proc_t *restrict const pp
 
 
 static int pr_thread(char *restrict const outbuf, const proc_t *restrict const pp){  /* TID tid LWP lwp SPID spid */
-  return snprintf(outbuf, COLWID, "%u", pp->pid);  /* for now... FIXME */
+  return snprintf(outbuf, COLWID, "%u", pp->tid);
 }
 static int pr_nlwp(char *restrict const outbuf, const proc_t *restrict const pp){  /* THCNT thcount NLWP nlwp */
   (void)pp; // FIXME
@@ -1215,7 +1216,7 @@ static const format_struct format_array[] = {
 {"lstart",    "STARTED", pr_lstart,   sr_nop,    24,   0,    XXX, RIGHT},
 {"luid",      "LUID",    pr_nop,      sr_nop,     5,   0,    LNX, RIGHT}, /* login ID */
 {"luser",     "LUSER",   pr_nop,      sr_nop,     8, USR,    LNX, USER}, /* login USER */
-{"lwp",       "LWP",     pr_thread,   sr_nop,     5,   0,    SUN, PIDMAX|RIGHT},
+{"lwp",       "LWP",     pr_thread,   sr_tid,     5,   0,    SUN, PIDMAX|RIGHT},
 {"m_drs",     "DRS",     pr_drs,      sr_drs,     5, MEM,    LNx, RIGHT},
 {"m_dt",      "DT",      pr_nop,      sr_dt,      4, MEM,    LNx, RIGHT},
 {"m_lrs",     "LRS",     pr_nop,      sr_lrs,     5, MEM,    LNx, RIGHT},
@@ -1250,7 +1251,7 @@ static const format_struct format_array[] = {
 {"pending",   "PENDING", pr_sig,      sr_nop,     9,   0,    BSD, SIGNAL}, /*sig*/
 {"pgid",      "PGID",    pr_pgid,     sr_pgrp,    5,   0,    U98, PIDMAX|RIGHT},
 {"pgrp",      "PGRP",    pr_pgid,     sr_pgrp,    5,   0,    LNX, PIDMAX|RIGHT},
-{"pid",       "PID",     pr_pid,      sr_pid,     5,   0,    U98, PIDMAX|RIGHT},
+{"pid",       "PID",     pr_pid,      sr_tgid,    5,   0,    U98, PIDMAX|RIGHT},
 {"pmem",      "%MEM",    pr_pmem,     sr_nop,     4,   0,    XXX, RIGHT}, /*%mem*/
 {"poip",      "-",       pr_nop,      sr_nop,     1,   0,    BSD, RIGHT},
 {"policy",    "POL",     pr_class,    sr_sched,   3,   0,    DEC, LEFT},
@@ -1296,7 +1297,7 @@ static const format_struct format_array[] = {
 {"sigmask",   "BLOCKED", pr_sigmask,  sr_nop,     9,   0,    XXX, SIGNAL}, /*blocked*/
 {"size",      "SZ",      pr_swapable, sr_swapable, 1,  0,    SCO, RIGHT},
 {"sl",        "SL",      pr_nop,      sr_nop,     3,   0,    XXX, RIGHT},
-{"spid",      "SPID",    pr_thread,   sr_nop,     5,   0,    SGI, PIDMAX|RIGHT},
+{"spid",      "SPID",    pr_thread,   sr_tid,     5,   0,    SGI, PIDMAX|RIGHT},
 {"stackp",    "STACKP",  pr_stackp,   sr_nop,     8,   0,    LNX, RIGHT}, /*start_stack*/
 {"start",     "STARTED", pr_start,    sr_nop,     8,   0,    XXX, RIGHT},
 {"start_code", "S_CODE",  pr_nop,     sr_start_code, 8, 0,   LNx, RIGHT},
@@ -1316,7 +1317,7 @@ static const format_struct format_array[] = {
 {"sz",        "SZ",      pr_sz,       sr_nop,     5,   0,    HPU, RIGHT},
 {"tdev",      "TDEV",    pr_nop,      sr_nop,     4,   0,    XXX, RIGHT},
 {"thcount",   "THCNT",   pr_nlwp,     sr_nop,     5,   0,    AIX, RIGHT},
-{"tid",       "TID",     pr_thread,   sr_nop,     5,   0,    AIX, PIDMAX|RIGHT},
+{"tid",       "TID",     pr_thread,   sr_tid,     5,   0,    AIX, PIDMAX|RIGHT},
 {"time",      "TIME",    pr_time,     sr_nop,     8,   0,    U98, CUMUL|RIGHT}, /*cputime*/ /* was 6 wide */
 {"timeout",   "TMOUT",   pr_timeout,  sr_timeout, 5,   0,    LNX, RIGHT},
 {"tmout",     "TMOUT",   pr_timeout,  sr_timeout, 5,   0,    LNX, RIGHT},
index 331cd08463d15319de7a9aab1f451dc0b236a427..168532750d0da9b42a58cee0bf6a8d14eb987e76 100644 (file)
@@ -264,6 +264,7 @@ static const char *parse_sysv_option(void){
        * SCO UnixWare uses -L too.
        */
       trace("-L Print LWP (thread) info.\n");
+      thread_flags |= TF_show_task;
       format_modifiers |= FM_L;
       break;
     case 'M':  /* someday, maybe, we will have MAC like SGI's Irix */
@@ -298,6 +299,7 @@ static const char *parse_sysv_option(void){
        * Also, testing shows PID==SPID for all normal processes.
        */
       trace("-T adds strange SPID column (old sproc() threads?)\n");
+      thread_flags |= TF_show_task;
       format_modifiers |= FM_T;
       break;
     case 'U': /* end */
@@ -367,7 +369,8 @@ static const char *parse_sysv_option(void){
     case 'm':
       trace("-m shows threads.\n");
       /* note that AIX shows 2 lines for a normal process */
-      /* not implemented -- silently ignore the option */
+      thread_flags |= TF_show_proc;
+      thread_flags |= TF_show_task;
       break;
     case 'n': /* end */
       trace("-n sets namelist file.\n");
@@ -494,6 +497,11 @@ static const char *parse_bsd_option(void){
       return "Option C is reserved.";
       break;
 #endif
+    case 'H':    // The FreeBSD way (NetBSD:s OpenBSD:k FreeBSD:H  -- NIH???)
+      trace("H Print LWP (thread) info.\n");   // was: Use /vmcore as c-dumpfile\n");
+      thread_flags |= TF_show_task;  // FIXME: determine if TF_show_proc is needed
+      //format_modifiers |= FM_L;    // FIXME: determine if we need something like this
+      break;
     case 'L': /* single */
       trace("L List all format specifiers\n");
       exclusive("L");
@@ -587,12 +595,11 @@ static const char *parse_bsd_option(void){
       trace("j job control format\n");
       format_flags |= FF_Bj;
       break;
-#if 0
-    case 'k':
-      trace("k N/A Use /vmcore as c-dumpfile\n");
-      return "Obsolete k option not supported.";
+    case 'k':    // The OpenBSD way (NetBSD:s OpenBSD:k FreeBSD:H  -- NIH???)
+      trace("k Print LWP (thread) info.\n");   // was: Use /vmcore as c-dumpfile\n");
+      thread_flags |= TF_show_task;  // FIXME: determine if TF_show_proc is needed
+      //format_modifiers |= FM_L;    // FIXME: determine if we need something like this
       break;
-#endif
     case 'l':
       trace("l Display long format\n");
       format_flags |= FF_Bl;
@@ -607,7 +614,8 @@ static const char *parse_bsd_option(void){
         defer_sf_option("pmem", SF_B_m);
         break;
       }
-      /* not implemented -- silently ignore the option */
+      thread_flags |= TF_show_proc;
+      thread_flags |= TF_show_task;
       break;
     case 'n':
       trace("n Numeric output for WCHAN, and USER replaced by UID\n");
index ef41972bb1f0df5d8b72e18fb9a5fae1d21366ba..9ef4ff80c2b21cb18c6c88ec1ce31379656c5935 100644 (file)
@@ -17,8 +17,8 @@
 #include "../proc/readproc.h"
 #include "../proc/procps.h"
 
-#define session_leader(p)       ((p)->session == (p)->pid)
-#define process_group_leader(p) ((p)->pgid    == (p)->pid)
+#define session_leader(p)       ((p)->session == (p)->tgid)
+#define process_group_leader(p) ((p)->pgid    == (p)->tgid)
 #define without_a_tty(p)        ((unsigned short)((p)->tty) == (unsigned short)0)
 #define some_other_user(p)      ((p)->euid    != cached_euid)
 #define running(p)              (((p)->state=='R')||((p)->state=='D'))
@@ -101,7 +101,7 @@ static int proc_was_listed(proc_t *buf){
     break; case SEL_FGID: return_if_match(fgid,gid);
 
     break; case SEL_PGRP: return_if_match(pgrp,pid);
-    break; case SEL_PID : return_if_match(pid,pid);
+    break; case SEL_PID : return_if_match(tgid,pid);
     break; case SEL_PPID: return_if_match(ppid,ppid);
     break; case SEL_TTY : return_if_match(tty,tty);
     break; case SEL_SESS: return_if_match(session,pid);
diff --git a/top.c b/top.c
index 5a6d1efb1e32e3424f34f3c84bd2a13974fc3e34..9cd58399fc76dab886d674825556519a2f4fb1bb 100644 (file)
--- a/top.c
+++ b/top.c
@@ -175,7 +175,7 @@ static int       Frame_srtflg,          // the subject window's sort direction
          * 2 columns each.
          */
 
-SCB_NUMx(P_PID, pid)
+SCB_NUMx(P_PID, XXXID)
 SCB_NUMx(P_PPD, ppid)
 SCB_STRx(P_URR, ruser)
 SCB_NUMx(P_UID, euid)
@@ -976,7 +976,7 @@ static void prochlp (proc_t *this)
    /* calculate time in this process; the sum of user time (utime) and
       system time (stime) -- but PLEASE dont waste time and effort on
       calcs and saves that go unused, like the old top! */
-   hist_new[Frame_maxtask].pid  = this->pid;
+   hist_new[Frame_maxtask].pid  = this->tid;
    hist_new[Frame_maxtask].tics = tics = (this->utime + this->stime);
 
 #if 0
@@ -987,9 +987,9 @@ static void prochlp (proc_t *this)
    // find matching entry from previous frame and make ticks elapsed
    while (lo <= hi) {
       i = (lo + hi) / 2;
-      if (this->pid < hist_sav[i].pid)
+      if (this->tid < hist_sav[i].pid)
          hi = i - 1;
-      else if (likely(this->pid > hist_sav[i].pid))
+      else if (likely(this->tid > hist_sav[i].pid))
          lo = i + 1;
       else {
          tics -= hist_sav[i].tics;
@@ -1001,7 +1001,7 @@ static void prochlp (proc_t *this)
 {
    HST_t tmp;
    const HST_t *ptr;
-   tmp.pid = this->pid;
+   tmp.pid = this->tid;
    ptr = bsearch(&tmp, hist_sav, maxt_sav, sizeof tmp, sort_HST_t);
    if(ptr) tics -= ptr->tics;
 }
@@ -1066,7 +1066,7 @@ static proc_t **procs_refresh (proc_t **table, int flags)
       savmax = curmax + 1;
    }
    // this frame's end, but not necessarily end of allocated space
-   table[curmax]->pid = -1;
+   table[curmax]->tid = -1;
    return table;
 
 #undef PTRsz
@@ -2974,7 +2974,7 @@ static void task_show (const WIN_t *q, const proc_t *p)
             MKCOL((int)p->nice);
             break;
          case P_PID:
-            MKCOL((unsigned)p->pid);
+            MKCOL((unsigned)p->XXXID);
             break;
          case P_PPD:
             MKCOL((unsigned)p->ppid);
@@ -3012,7 +3012,7 @@ static void task_show (const WIN_t *q, const proc_t *p)
             break;
          case P_TTY:
          {  char tmp[TNYBUFSIZ];
-            dev_to_tty(tmp, (int)w, p->tty, p->pid, ABBREV_DEV);
+            dev_to_tty(tmp, (int)w, p->tty, p->XXXID, ABBREV_DEV);
             MKCOL(tmp);
          }
             break;
@@ -3037,7 +3037,7 @@ static void task_show (const WIN_t *q, const proc_t *p)
 #endif
                MKCOL((long)p->wchan);
             } else {
-               MKCOL(wchan(p->wchan, p->pid));
+               MKCOL(wchan(p->wchan, p->XXXID));
             }
             break;
 
@@ -3094,7 +3094,7 @@ static void window_show (proc_t **ppt, WIN_t *q, int *lscr)
    lwin = 1;
    i = 0;
 
-   while ( -1 != ppt[i]->pid && *lscr < Max_lines  &&  (!q->winlines || (lwin <= q->winlines)) ) {
+   while ( -1 != ppt[i]->tid && *lscr < Max_lines  &&  (!q->winlines || (lwin <= q->winlines)) ) {
       if ((CHKw(q, Show_IDLEPS) || ('S' != ppt[i]->state && 'Z' != ppt[i]->state))
       && good_uid(ppt[i]) ) {
          /*
diff --git a/w.c b/w.c
index 9fa711fbda2d022b27e48da7a5d59e89d6eb67e9..cebb4c983378ae0771bb5b118f8821bdff407fd0 100644 (file)
--- a/w.c
+++ b/w.c
@@ -146,7 +146,7 @@ static const proc_t *getproc(const utmp_t *restrict const u, const char *restric
     *found_utpid = 0;
     for(; *pptr; pptr++) {
        const proc_t *restrict const tmp = *pptr;
-       if(unlikely(tmp->pid == u->ut_pid)) {
+       if(unlikely(tmp->tgid == u->ut_pid)) {
            *found_utpid = 1;
            best = tmp;
        }
@@ -158,7 +158,7 @@ static const proc_t *getproc(const utmp_t *restrict const u, const char *restric
            secondbest = tmp;
        }
        if(!ignoreuser && uid != tmp->euid && uid != tmp->ruid) continue;
-       if(tmp->pid != tmp->tpgid) continue;
+       if(tmp->tgid != tmp->tpgid) continue;
        if(best && tmp->start_time <= best->start_time) continue;
        best = tmp;
     }