diff --git a/Makefile b/Makefile index 93e49350..9538e673 100644 --- 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 c8f729b2..4eb11403 100644 --- 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 8ba1c65b..13e6768d 100644 --- 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; diff --git a/proc/library.map b/proc/library.map index 810440d6..fca514ef 100644 --- a/proc/library.map +++ b/proc/library.map @@ -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; diff --git a/proc/readproc.c b/proc/readproc.c index 32ebc10e..64ff0e53 100644 --- a/proc/readproc.c +++ b/proc/readproc.c @@ -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); } } diff --git a/proc/readproc.h b/proc/readproc.h index 82a1b7c4..6617b3b5 100644 --- a/proc/readproc.h +++ b/proc/readproc.h @@ -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 #include #include + +#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 ) */ diff --git a/procps.lsm b/procps.lsm index 31912066..77fbe197 100644 --- a/procps.lsm +++ b/procps.lsm @@ -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 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 diff --git a/procps.spec b/procps.spec index 79f6f1a2..2d5074b3 100644 --- a/procps.spec +++ b/procps.spec @@ -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 diff --git a/ps/common.h b/ps/common.h index e9ba85be..c254ec5f 100644 --- a/ps/common.h +++ b/ps/common.h @@ -73,6 +73,10 @@ #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; diff --git a/ps/display.c b/ps/display.c index 2d5222b5..39bb895c 100644 --- a/ps/display.c +++ b/ps/display.c @@ -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"); diff --git a/ps/global.c b/ps/global.c index edd4cf9a..ea77d916 100644 --- a/ps/global.c +++ b/ps/global.c @@ -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; diff --git a/ps/output.c b/ps/output.c index e20114ad..97e958f9 100644 --- a/ps/output.c +++ b/ps/output.c @@ -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}, diff --git a/ps/parser.c b/ps/parser.c index 331cd084..16853275 100644 --- a/ps/parser.c +++ b/ps/parser.c @@ -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"); diff --git a/ps/select.c b/ps/select.c index ef41972b..9ef4ff80 100644 --- a/ps/select.c +++ b/ps/select.c @@ -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 5a6d1efb..9cd58399 100644 --- 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 9fa711fb..cebb4c98 100644 --- 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; }