more per-process stuff

This commit is contained in:
albert 2003-09-29 04:09:52 +00:00
parent 35859fb0a8
commit 71312f1516
7 changed files with 137 additions and 83 deletions

2
NEWS
View File

@ -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

29
TODO
View File

@ -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 '?'.

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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*/

View File

@ -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;
}