diff --git a/NEWS b/NEWS index 924f0e48..ff87c19b 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ procps-3.1.13 --> procps-3.1.14 handle 32-bit dev_t of Linux 2.6 +ps: finally, m and -m satisfy the original design +ps: distinct per-thread and whole-process pending signals procps-3.1.12 --> procps-3.1.13 diff --git a/TODO b/TODO index a54446de..2b982a0c 100644 --- a/TODO +++ b/TODO @@ -14,27 +14,11 @@ Cache results of dev_to_tty. Add an "adopted child" flag to mark processes that are not natural children of init. This can make --forest work better. -Add a thread group ID, to be shared by all tasks that are related by -the clone() system call. This ID might be made unique from boot to -shutdown, perhaps being a 16-bit CPU number and 48-bit per-CPU -serial number. - -Make the kernel group /proc listing output by thread group. -Without this, a thread-aware ps must always sort processes. - -Supply the task ID (the "PID"/"TID") of the thread group leader. -I define "leader" as the first process of a thread group. - -Don't reuse the task ID of a thread group leader until all threads -are dead. Better yet, don't let the leader exit. - Supply better data for top's CPU state display. Currently top has to subtract old numbers from new numbers and divide that result by the number of processors. The kernel won't even supply the number of processors in a portable way. -Mark threads, and supply a list of other threads. - Supply data for the ADDR and JOBC fields. Support & supply data for SL and RE. @@ -42,9 +26,6 @@ Support & supply data for SL and RE. Add a /proc/*/tty symlink to eliminate guessing when /proc/*/fd is not accessable. -Put unique ID at the top of System.map and in /proc, to make sure -there is never a mismatch. - Add /proc/*/.bindata files to avoid string parsing. It should be an array of 64-bit values on all machines. New entries go on the end and obsolete ones get filled in with something logical -- entries must never be deleted! @@ -61,9 +42,7 @@ arbitrary data for the FROM column. (could set root's VGA color map!) ---------------------- vmstat -------------------------- -Extract /proc/stat parsing from vmstat into libproc somewhere. - -Let the user choose: 1000, 1024, PAGE_SIZE, 1000000, 0x100000 +Extract /proc/diskstats parsing from vmstat into libproc somewhere. --------------------- libproc ---------------------- @@ -74,6 +53,8 @@ units: kB and pages, seconds and jiffies) in the proc_t struct. Share more stuff with ps. +'H' command + ---------------- ps for now, maybe move to libproc ------------------ With forest output and a tty named /dev/this_is_my_tty, the position @@ -139,10 +120,6 @@ Try to make -jl fit in 80 columns. Do we need more than 1000 pty devices, 9 flag bits, etc.? (hmmm, Linux supports 2048 pty devices now, and we might also want to steal whitespace there when the time column overflows) -When not in strict Unix98 mode, let foo=8 specify that foo is 8 -characters wide. Debian did that. Then foo=8=bar and foo=bar=8 -could change both header and width. - Better unmangling of '?' as a tty. The shell destroys '?' when there is a filename that matches. If the argument seems like garbage, check for a file that might have screwed up the '?'. diff --git a/proc/readproc.c b/proc/readproc.c index fc45e65e..fa503da0 100644 --- a/proc/readproc.c +++ b/proc/readproc.c @@ -218,8 +218,8 @@ ENTER(0x220); continue; case_ShdPnd: - memcpy(P->signal, S, 16); - P->signal[16] = '\0'; + memcpy(ShdPnd, S, 16); + // we know it to be 16 char, so no '\0' needed continue; case_SigBlk: memcpy(P->blocked, S, 16); @@ -622,6 +622,8 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric t->environ = p->environ; #endif + t->ppid = p->ppid; // ought to put the per-task ppid somewhere + return t; next_task: return NULL; diff --git a/ps/common.h b/ps/common.h index 615bee50..f9f96ad1 100644 --- a/ps/common.h +++ b/ps/common.h @@ -84,11 +84,12 @@ // Then the other flags #define CF_CUMUL 0x00000010 // mark cumulative (Summed) headers with 'C' */ #define CF_PIDMAX 0x00000020 // react to pid_max +// Only one allowed; use separate bits to catch errors. #define CF_PRINT_THREAD_ONLY 0x10000000 #define CF_PRINT_PROCESS_ONLY 0x20000000 #define CF_PRINT_EVERY_TIME 0x40000000 #define CF_PRINT_AS_NEEDED 0x80000000 // means we have no clue, so assume EVERY TIME - +#define CF_PRINT_MASK 0xf0000000 #define needs_for_select (PROC_FILLSTAT | PROC_FILLSTATUS) @@ -252,6 +253,7 @@ extern const shortsort_struct *search_shortsort_array(const int findme); extern const format_struct *search_format_array(const char *findme); extern const macro_struct *search_macro_array(const char *findme); extern void init_output(void); +extern int pr_nop(char *restrict const outbuf, const proc_t *restrict const pp); /* global.c */ extern void reset_global(void); diff --git a/ps/display.c b/ps/display.c index 0871bbee..e39f9a3b 100644 --- a/ps/display.c +++ b/ps/display.c @@ -187,29 +187,116 @@ static void check_headers(void){ if(!head_normal) lines_to_next_header = -1; /* how UNIX does --noheader */ } -static unsigned needs_for_format; -static unsigned needs_for_sort; +/***** check sort needs */ +/* see what files need to be read, etc. */ +static unsigned check_sort_needs(sort_node *walk){ + unsigned needs = 0; + while(walk){ + needs |= walk->need; + walk = walk->next; + } + return needs; +} /***** check needs */ /* see what files need to be read, etc. */ -static void check_needs(void){ - format_node *walk_pr = format_list; - sort_node *walk_sr = sort_list; - /* selection doesn't currently have expensive needs */ - - while(walk_pr){ - needs_for_format |= walk_pr->need; - walk_pr = walk_pr->next; +static unsigned collect_format_needs(format_node *walk){ + unsigned needs = 0; + while(walk){ + needs |= walk->need; + walk = walk->next; } - if(bsd_e_option) needs_for_format |= PROC_FILLENV; - - while(walk_sr){ - needs_for_sort |= walk_sr->need; - walk_sr = walk_sr->next; - } - + return needs; } +static format_node *proc_format_list; +static format_node *task_format_list; + +static unsigned needs_for_sort; +static unsigned proc_format_needs; +static unsigned task_format_needs; + +#define needs_for_format (proc_format_needs|task_format_needs) + +#define PROC_ONLY_FLAGS (PROC_FILLENV|PROC_FILLARG|PROC_FILLCOM|PROC_FILLMEM) + +/***** munge lists and determine openproc() flags */ +static void lists_and_needs(void){ + check_headers(); + + // only care about the difference when showing both + if( (thread_flags & (TF_show_proc|TF_show_task)) == (TF_show_proc|TF_show_task) ){ + format_node pfn, tfn; // junk, to handle special case at begin of list + format_node *walk = format_list; + format_node *p_end = &pfn; + format_node *t_end = &tfn; + while(walk){ + format_node *new = malloc(sizeof(format_node)); + memcpy(new,walk,sizeof(format_node)); + p_end->next = walk; + t_end->next = new; + p_end = walk; + t_end = new; + switch(walk->flags & CF_PRINT_MASK){ + case CF_PRINT_THREAD_ONLY: + p_end->pr = pr_nop; + p_end->need = 0; + break; + case CF_PRINT_PROCESS_ONLY: + t_end->pr = pr_nop; + t_end->need = 0; + break; + default: + fprintf(stderr, "please report this bug\n"); + // FALL THROUGH + case CF_PRINT_AS_NEEDED: + case CF_PRINT_EVERY_TIME: + break; + } + walk = walk->next; + } + t_end->next = NULL; + p_end->next = NULL; + proc_format_list = pfn.next; + task_format_list = tfn.next; + }else{ + proc_format_list = format_list; + task_format_list = format_list; + } + + proc_format_needs = collect_format_needs(proc_format_list); + task_format_needs = collect_format_needs(task_format_list); + + needs_for_sort = check_sort_needs(sort_list); + + // move process-only flags to the process + proc_format_needs |= (task_format_needs &~ PROC_ONLY_FLAGS); + task_format_needs &= ~PROC_ONLY_FLAGS; + + if(bsd_c_option){ + proc_format_needs &= ~PROC_FILLARG; + needs_for_sort &= ~PROC_FILLARG; + } + if(!unix_f_option){ + proc_format_needs &= ~PROC_FILLCOM; + needs_for_sort &= ~PROC_FILLCOM; + } + // convert ARG to COM as a standard + if(proc_format_needs & PROC_FILLARG){ + proc_format_needs |= PROC_FILLCOM; + proc_format_needs &= ~PROC_FILLARG; + } + if(bsd_e_option){ + if(proc_format_needs&PROC_FILLCOM) proc_format_needs |= PROC_FILLENV; + } + + /* FIXME broken filthy hack -- got to unify some stuff here */ + if( ( (proc_format_needs|task_format_needs|needs_for_sort) & PROC_FILLWCHAN) && !wchan_is_number) + if (open_psdb(namelist_file)) wchan_is_number = 1; +} + +////////////////////////////////////////////////////////////////////////// + /***** fill in %CPU; not in libproc because of include_dead_children */ /* Note: for sorting, not display, so 0..0x7fffffff would be OK */ static void fill_pcpu(proc_t *buf){ @@ -226,18 +313,6 @@ static void fill_pcpu(proc_t *buf){ buf->pcpu = pcpu; // fits in an int, summing children on 128 CPUs } -/***** figure out what we need */ -static void compute_needs(void){ - if(bsd_c_option){ - needs_for_format &= ~PROC_FILLARG; - needs_for_sort &= ~PROC_FILLARG; - } - if(!unix_f_option){ - needs_for_format &= ~PROC_FILLCOM; - needs_for_sort &= ~PROC_FILLCOM; - } -} - /***** just display */ static void simple_spew(void){ proc_t buf; @@ -251,11 +326,11 @@ static void simple_spew(void){ memset(&buf, '#', sizeof(proc_t)); while(readproc(ptp,&buf)){ if(want_this_proc(&buf)){ - if(thread_flags & TF_show_proc) show_one_proc(&buf,format_list); + if(thread_flags & TF_show_proc) show_one_proc(&buf, proc_format_list); if(thread_flags & TF_show_task){ proc_t buf2; // must still have the process allocated - while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2,format_list); + while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list); // must not attempt to free cmdline and environ } } @@ -451,13 +526,8 @@ int main(int argc, char *argv[]){ trace("======= ps output follows =======\n"); init_output(); /* must be between parser and output */ - check_headers(); - check_needs(); - /* filthy hack -- got to unify some stuff here */ - if( ( (needs_for_format|needs_for_sort) & PROC_FILLWCHAN) && !wchan_is_number) - if (open_psdb(namelist_file)) wchan_is_number = 1; - compute_needs(); + lists_and_needs(); if(forest_type || sort_list) fancy_spew(); /* sort or forest */ else simple_spew(); /* no sort, no forest */ diff --git a/ps/output.c b/ps/output.c index 5290994b..3ce71613 100644 --- a/ps/output.c +++ b/ps/output.c @@ -210,7 +210,8 @@ static int sr_swapable(const proc_t* P, const proc_t* Q) { /***************************************************************************/ /************ Lots of format functions, starting with the NOP **************/ -static int pr_nop(char *restrict const outbuf, const proc_t *restrict const pp){ +// so popular it can't be "static" +int pr_nop(char *restrict const outbuf, const proc_t *restrict const pp){ (void)pp; return snprintf(outbuf, COLWID, "%c", '-'); } @@ -1175,14 +1176,14 @@ static const format_struct format_array[] = { {"cursig", "CURSIG", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT}, {"cutime", "-", pr_nop, sr_cutime, 1, 0, LNX, AN|RIGHT}, {"cwd", "CWD", pr_nop, sr_nop, 3, 0, LNX, AN|LEFT}, -{"drs", "DRS", pr_drs, sr_drs, 4, MEM, LNX, ET|RIGHT}, -{"dsiz", "DSIZ", pr_dsiz, sr_nop, 4, 0, LNX, ET|RIGHT}, +{"drs", "DRS", pr_drs, sr_drs, 4, MEM, LNX, PO|RIGHT}, +{"dsiz", "DSIZ", pr_dsiz, sr_nop, 4, 0, LNX, PO|RIGHT}, {"egid", "EGID", pr_egid, sr_egid, 5, 0, LNX, ET|RIGHT}, {"egroup", "EGROUP", pr_egroup, sr_egroup, 8, GRP, LNX, ET|USER}, {"eip", "EIP", pr_eip, sr_kstk_eip, 8, 0, LNX, TO|RIGHT}, {"end_code", "E_CODE", pr_nop, sr_end_code, 8, 0, LNx, PO|RIGHT}, {"environ","ENVIRONMENT",pr_nop, sr_nop, 11, ENV, LNx, PO|UNLIMITED}, -{"esp", "ESP", pr_esp, sr_kstk_esp, 8, 0, LNX, PO|RIGHT}, +{"esp", "ESP", pr_esp, sr_kstk_esp, 8, 0, LNX, TO|RIGHT}, {"etime", "ELAPSED", pr_etime, sr_nop, 11, 0, U98, AN|RIGHT}, /* was 7 wide */ {"euid", "EUID", pr_euid, sr_euid, 5, 0, LNX, ET|RIGHT}, {"euser", "EUSER", pr_euser, sr_euser, 8, USR, LNX, ET|USER}, @@ -1211,7 +1212,7 @@ static const format_struct format_array[] = { {"lim", "LIM", pr_lim, sr_rss_rlim, 5, 0, BSD, AN|RIGHT}, {"login", "LOGNAME", pr_nop, sr_nop, 8, 0, BSD, AN|LEFT}, /*logname*/ /* double check */ {"logname", "LOGNAME", pr_nop, sr_nop, 8, 0, XXX, AN|LEFT}, /*login*/ -{"longtname", "TTY", pr_tty8, sr_tty, 8, 0, DEC, AN|LEFT}, +{"longtname", "TTY", pr_tty8, sr_tty, 8, 0, DEC, PO|LEFT}, {"lstart", "STARTED", pr_lstart, sr_nop, 24, 0, XXX, AN|RIGHT}, {"luid", "LUID", pr_nop, sr_nop, 5, 0, LNX, ET|RIGHT}, /* login ID */ {"luser", "LUSER", pr_nop, sr_nop, 8, USR, LNX, ET|USER}, /* login USER */ @@ -1230,7 +1231,7 @@ static const format_struct format_array[] = { {"minflt", "MINFLT", pr_minflt, sr_min_flt, 6, 0, XXX, AN|RIGHT}, {"msgrcv", "MSGRCV", pr_nop, sr_nop, 6, 0, XXX, AN|RIGHT}, {"msgsnd", "MSGSND", pr_nop, sr_nop, 6, 0, XXX, AN|RIGHT}, -{"mwchan", "MWCHAN", pr_nop, sr_nop, 6, WCH, BSD, AN|WCHAN}, /* mutex (FreeBSD) */ +{"mwchan", "MWCHAN", pr_nop, sr_nop, 6, WCH, BSD, TO|WCHAN}, /* mutex (FreeBSD) */ {"ni", "NI", pr_nice, sr_nice, 3, 0, BSD, TO|RIGHT}, /*nice*/ {"nice", "NI", pr_nice, sr_nice, 3, 0, U98, TO|RIGHT}, /*ni*/ {"nivcsw", "IVCSW", pr_nop, sr_nop, 5, 0, XXX, AN|RIGHT}, @@ -1247,7 +1248,7 @@ static const format_struct format_array[] = { {"p_ru", "P_RU", pr_nop, sr_nop, 6, 0, BSD, AN|RIGHT}, {"paddr", "PADDR", pr_nop, sr_nop, 6, 0, BSD, AN|RIGHT}, {"pagein", "PAGEIN", pr_majflt, sr_nop, 6, 0, XXX, AN|RIGHT}, -{"pcpu", "%CPU", pr_pcpu, sr_pcpu, 4, 0, U98, TO|RIGHT}, /*%cpu*/ +{"pcpu", "%CPU", pr_pcpu, sr_pcpu, 4, 0, U98, ET|RIGHT}, /*%cpu*/ {"pending", "PENDING", pr_sig, sr_nop, 9, 0, BSD, ET|SIGNAL}, /*sig*/ {"pgid", "PGID", pr_pgid, sr_pgrp, 5, 0, U98, PO|PIDMAX|RIGHT}, {"pgrp", "PGRP", pr_pgid, sr_pgrp, 5, 0, LNX, PO|PIDMAX|RIGHT}, @@ -1255,7 +1256,7 @@ static const format_struct format_array[] = { {"pmem", "%MEM", pr_pmem, sr_nop, 4, 0, XXX, PO|RIGHT}, /*%mem*/ {"poip", "-", pr_nop, sr_nop, 1, 0, BSD, AN|RIGHT}, {"policy", "POL", pr_class, sr_sched, 3, 0, DEC, TO|LEFT}, -{"ppid", "PPID", pr_ppid, sr_ppid, 5, 0, U98, AN|PIDMAX|RIGHT}, +{"ppid", "PPID", pr_ppid, sr_ppid, 5, 0, U98, PO|PIDMAX|RIGHT}, {"pri", "PRI", pr_pri, sr_nop, 3, 0, XXX, TO|RIGHT}, {"priority", "PRI", pr_priority, sr_priority, 3, 0, LNX, TO|RIGHT}, /*ni,nice*/ /* from Linux sorting names */ {"prmgrp", "-", pr_nop, sr_nop, 1, 0, HPU, PO|RIGHT}, @@ -1274,7 +1275,7 @@ static const format_struct format_array[] = { {"rtprio", "RTPRIO", pr_rtprio, sr_rtprio, 6, 0, BSD, TO|RIGHT}, {"ruid", "RUID", pr_ruid, sr_ruid, 5, 0, XXX, ET|RIGHT}, {"ruser", "RUSER", pr_ruser, sr_ruser, 8, USR, U98, ET|USER}, -{"s", "S", pr_s, sr_state, 1, 0, SUN, ET|LEFT}, /*stat,state*/ +{"s", "S", pr_s, sr_state, 1, 0, SUN, TO|LEFT}, /*stat,state*/ {"sched", "SCH", pr_sched, sr_sched, 3, 0, AIX, TO|RIGHT}, {"scnt", "SCNT", pr_nop, sr_nop, 4, 0, DEC, AN|RIGHT}, /* man page misspelling of scount? */ {"scount", "SC", pr_nop, sr_nop, 4, 0, AIX, AN|RIGHT}, /* scnt==scount, DEC claims both */ @@ -1321,17 +1322,17 @@ static const format_struct format_array[] = { {"time", "TIME", pr_time, sr_nop, 8, 0, U98, ET|CUMUL|RIGHT}, /*cputime*/ /* was 6 wide */ {"timeout", "TMOUT", pr_timeout, sr_timeout, 5, 0, LNX, AN|RIGHT}, {"tmout", "TMOUT", pr_timeout, sr_timeout, 5, 0, LNX, AN|RIGHT}, -{"tname", "TTY", pr_tty8, sr_tty, 8, 0, DEC, AN|LEFT}, +{"tname", "TTY", pr_tty8, sr_tty, 8, 0, DEC, PO|LEFT}, {"tpgid", "TPGID", pr_tpgid, sr_tpgid, 5, 0, XXX, AN|PIDMAX|RIGHT}, {"trs", "TRS", pr_trs, sr_trs, 4, MEM, AIX, PO|RIGHT}, {"trss", "TRSS", pr_trs, sr_trs, 4, MEM, BSD, PO|RIGHT}, /* 4.3BSD NET/2 */ {"tsess", "TSESS", pr_nop, sr_nop, 5, 0, BSD, AN|PIDMAX|RIGHT}, {"tsession", "TSESS", pr_nop, sr_nop, 5, 0, DEC, AN|PIDMAX|RIGHT}, -{"tsiz", "TSIZ", pr_tsiz, sr_nop, 4, 0, BSD, AN|RIGHT}, -{"tt", "TT", pr_tty8, sr_tty, 8, 0, BSD, AN|LEFT}, -{"tty", "TT", pr_tty8, sr_tty, 8, 0, U98, AN|LEFT}, /* Unix98 requires "TT" but has "TTY" too. :-( */ /* was 3 wide */ -{"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, AN|LEFT}, -{"tty8", "TTY", pr_tty8, sr_tty, 8, 0, LNX, AN|LEFT}, +{"tsiz", "TSIZ", pr_tsiz, sr_nop, 4, 0, BSD, PO|RIGHT}, +{"tt", "TT", pr_tty8, sr_tty, 8, 0, BSD, PO|LEFT}, +{"tty", "TT", pr_tty8, sr_tty, 8, 0, U98, PO|LEFT}, /* Unix98 requires "TT" but has "TTY" too. :-( */ /* was 3 wide */ +{"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, PO|LEFT}, +{"tty8", "TTY", pr_tty8, sr_tty, 8, 0, LNX, PO|LEFT}, {"u_procp", "UPROCP", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT}, {"ucmd", "CMD", pr_comm, sr_cmd, 16, COM, DEC, PO|UNLIMITED}, /*ucomm*/ {"ucomm", "COMMAND", pr_comm, sr_nop, 16, COM, XXX, PO|UNLIMITED}, /*comm*/ diff --git a/ps/sortformat.c b/ps/sortformat.c index 0c247d5a..ff82be9e 100644 --- a/ps/sortformat.c +++ b/ps/sortformat.c @@ -188,7 +188,7 @@ double_percent: fnode->pr = NULL; /* checked for */ fnode->need = 0; fnode->vendor = AIX; - fnode->flags = 0; + fnode->flags = CF_PRINT_EVERY_TIME; fnode->next = NULL; } @@ -695,7 +695,7 @@ static const char *generate_sysv_list(void){ fn->pr = NULL; /* checked for */ fn->need = 0; fn->vendor = AIX; /* yes, for SGI weirdness */ - fn->flags = 0; + fn->flags = CF_PRINT_EVERY_TIME; fn->next = format_list; format_list=fn; }