From 77dc22b9101af39fc30306e36d65cad2b396cc9e Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Wed, 19 Aug 2015 00:00:00 -0500 Subject: [PATCH] top: exploit those new library task/threads provisions This patch adapts top to exploit the new interface. And it appears to have reduced top's weight by a considerable margin. Gone were the sort callbacks and manipulation of those library flags. Gosh, all top needs to do now is track some enumerators of interest. [ whoa, wait just a damn minute. it now appears some ] [ that weight loss was solely the result of a theft. ] [ jeeze, we turn our back for just a minute & newlib ] [ up & steals our pids hashing logic for his history ] [ needs. oh well, i guess life's just not that fair. ] Signed-off-by: Jim Warner --- top/top.c | 1189 ++++++++++++++++++------------------------------- top/top.h | 65 +-- top/top_nls.c | 5 +- top/top_nls.h | 24 +- 4 files changed, 450 insertions(+), 833 deletions(-) diff --git a/top/top.c b/top/top.c index 00658018..44f70517 100644 --- a/top/top.c +++ b/top/top.c @@ -52,6 +52,7 @@ #include "../proc/devname.h" #include +#include #include "../proc/procps.h" #include "../proc/readproc.h" #include @@ -89,10 +90,6 @@ static char Rc_name [OURPATHSZ]; static RCF_t Rc = DEF_RCFILE; static int Rc_questions; - /* The run-time acquired page stuff */ -static long Page_size; -static unsigned Pg2K_shft = 0; - /* SMP, Irix/Solaris mode, Linux 2.5.xx support (and beyond) */ static long Hertz; static int Cpu_cnt; @@ -124,7 +121,7 @@ static char Scroll_fmts [SMLBUFSIZ]; static int Batch = 0, // batch mode, collect no input, dumb output Loops = -1, // number of iterations, -1 loops forever Secure_mode = 0, // set if some functionality restricted - Thread_mode = 0, // set w/ 'H' - show threads via readeither() + Thread_mode = 0, // set w/ 'H' - show threads via pids_reap() Width_mode = 0; // set w/ 'w' - potential output override /* Unchangeable cap's stuff built just once (if at all) and @@ -177,30 +174,8 @@ static WIN_t *Curwin; [ 'Frames_...' (plural) stuff persists beyond 1 frame ] [ or are used in response to async signals received ! ] */ static volatile int Frames_signal; // time to rebuild all column headers -static int Frames_libflags; // PROC_FILLxxx flags -static int Frame_maxtask; // last known number of active tasks // ie. current 'size' of proc table static float Frame_etscale; // so we can '*' vs. '/' WHEN 'pcpu' -static unsigned Frame_running, // state categories for this frame - Frame_sleepin, - Frame_stopped, - Frame_zombied; -static int Frame_srtflg, // the subject window's sort direction - Frame_ctimes, // the subject window's ctimes flag - Frame_cmdlin; // the subject window's cmdlin flag - - /* Support for 'history' processing so we can calculate %cpu */ -static int HHist_siz; // max number of HST_t structs -static HST_t *PHist_sav, // alternating 'old/new' HST_t anchors - *PHist_new; -#ifndef OFF_HST_HASH -#define HHASH_SIZ 1024 -static int HHash_one [HHASH_SIZ], // actual hash tables ( hereafter known - HHash_two [HHASH_SIZ], // as PHash_sav/PHash_new ) - HHash_nul [HHASH_SIZ]; // 'empty' hash table image -static int *PHash_sav = HHash_one, // alternating 'old/new' hash tables - *PHash_new = HHash_two; -#endif /* Support for automatically sized fixed-width column expansions. * (hopefully, the macros help clarify/document our new 'feature') */ @@ -251,6 +226,7 @@ static const char Graph_bars[] = "|||||||||||||||||||||||||||||||||||||||||||||| /* Support for the new library API -- acquired (if necessary) at program startup and referenced throughout our lifetime */ + // ---------------------------------------------- static struct procps_meminfo *Mem_ctx; static struct meminfo_stack *Mem_stack; static enum meminfo_item Mem_items[] = { @@ -262,94 +238,24 @@ enum Rel_items { mem_FREE, mem_USED, mem_TOTAL, mem_CACHE, mem_BUFFS, mem_AVAIL, swp_TOTAL, swp_FREE, swp_USED }; + // mem stack results extractor macro, where e=rel enum #define MEM_VAL(e) Mem_stack->head[e].result.ul_int - + // --------------------------------------------- static struct procps_stat *Cpu_ctx; static struct procps_jiffs_hist *Cpu_jiffs; - -/*###### Sort callbacks ################################################*/ - - /* - * These happen to be coded in the enum identifier alphabetic order, - * not the order of the enum 'pflgs' value. Also note that a callback - * routine may serve more than one column. - */ - -SCB_STRS(CGR, cgroup[0]) -SCB_STRV(CMD, Frame_cmdlin, cmdline, cmd) -SCB_NUM1(COD, trs) -SCB_NUMx(CPN, processor) -SCB_NUM1(CPU, pcpu) -SCB_NUM1(DAT, drs) -SCB_NUM1(DRT, dt) -SCB_STRS(ENV, environ[0]) -SCB_NUM1(FL1, maj_flt) -SCB_NUM1(FL2, min_flt) -SCB_NUM1(FLG, flags) -SCB_NUM1(FV1, maj_delta) -SCB_NUM1(FV2, min_delta) -SCB_NUMx(GID, egid) -SCB_STRS(GRP, egroup) -SCB_STRS(LXC, lxcname) -SCB_NUMx(NCE, nice) -SCB_NUM1(NS1, ns[IPCNS]) -SCB_NUM1(NS2, ns[MNTNS]) -SCB_NUM1(NS3, ns[NETNS]) -SCB_NUM1(NS4, ns[PIDNS]) -SCB_NUM1(NS5, ns[USERNS]) -SCB_NUM1(NS6, ns[UTSNS]) -#ifdef OOMEM_ENABLE -SCB_NUM1(OOA, oom_adj) -SCB_NUM1(OOM, oom_score) -#endif -SCB_NUMx(PGD, pgrp) -SCB_NUMx(PID, tid) -SCB_NUMx(PPD, ppid) -SCB_NUMx(PRI, priority) -SCB_NUM1(RES, vm_rss) // also serves MEM ! -SCB_STRX(SGD, supgid) -SCB_STRS(SGN, supgrp) -SCB_NUM1(SHR, share) -SCB_NUM1(SID, session) -SCB_NUMx(STA, state) -SCB_NUM1(SWP, vm_swap) -SCB_NUMx(TGD, tgid) -SCB_NUMx(THD, nlwp) - // also serves TM2 ! -static int SCB_NAME(TME) (const proc_t **P, const proc_t **Q) { - if (Frame_ctimes) { - if (((*P)->cutime + (*P)->cstime + (*P)->utime + (*P)->stime) - < ((*Q)->cutime + (*Q)->cstime + (*Q)->utime + (*Q)->stime)) - return SORT_lt; - if (((*P)->cutime + (*P)->cstime + (*P)->utime + (*P)->stime) - > ((*Q)->cutime + (*Q)->cstime + (*Q)->utime + (*Q)->stime)) - return SORT_gt; - } else { - if (((*P)->utime + (*P)->stime) < ((*Q)->utime + (*Q)->stime)) - return SORT_lt; - if (((*P)->utime + (*P)->stime) > ((*Q)->utime + (*Q)->stime)) - return SORT_gt; - } - return SORT_eq; -} -SCB_NUM1(TPG, tpgid) -SCB_NUMx(TTY, tty) -SCB_NUMx(UED, euid) -SCB_STRS(UEN, euser) -SCB_NUMx(URD, ruid) -SCB_STRS(URN, ruser) -SCB_NUMx(USD, suid) -SCB_NUM2(USE, vm_rss, vm_swap) -SCB_STRS(USN, suser) -SCB_NUM1(VRT, size) -SCB_NUM1(WCH, wchan) - -#ifdef OFF_HST_HASH - /* special sort for procs_hlp() ! ------------------------ */ -static int sort_HST_t (const HST_t *P, const HST_t *Q) { - return P->pid - Q->pid; -} -#endif + // ------------------------------------------------- +static struct procps_pidsinfo *Pids_ctx; +static int Pids_itms_cur; // 'current' max (<= Fieldstab) +static enum pids_item *Pids_itms; // allocated as MAXTBL(Fieldstab) +static enum pids_reap_type Pids_type[] = { // indexed via Thread_mode w/ reap + PROCPS_REAP_TASKS_ONLY, PROCPS_REAP_THREADS_TOO +}; +static struct pids_stack **Pids_stks; // for either reap or monpids +static struct pids_counts *Pids_cnts; // for either reap or monpids +static struct pids_reap *Pids_reap; // for reap only +static struct pids_stacks *Pids_fill; // for fill only (w/ monpids) + // pid stack results extractor macro, where e=rel enum, t=type, s=stack +#define PID_VAL(e,t,s) s ->head [Fieldstab[ e ].erel].result. t /*###### Tiny useful routine(s) ########################################*/ @@ -429,17 +335,15 @@ static void bye_bye (const char *str) NORETURN; static void bye_bye (const char *str) { at_eoj(); // restore tty in preparation for exit #ifdef ATEOJ_RPTSTD -{ proc_t *p; +{ struct pids_stack *p; if (!str && !Frames_signal && Ttychanged) { fprintf(stderr, "\n%s's Summary report:" "\n\tProgram" "\n\t %s" "\n\t Hertz = %u (%u bytes, %u-bit time)" - "\n\t page_bytes = %d, Cpu_faux_cnt = %d, Cpu_cnt = %d" - "\n\t sizeof(HST_t) = %u (%d HST_t's/Page), HHist_siz = %u" - "\n\t sizeof(proc_t) = %u, sizeof(proc_t.cmd) = %u, sizeof(proc_t*) = %u" - "\n\t sizeof(procps_jiffs) = %u, sizeof(procps_jiffs_hist) = %u, sizeof(procps_sys_result) = %u" - "\n\t Frames_libflags = %08lX" + "\n\t Cpu_faux_cnt = %d, Cpu_cnt = %d" + "\n\t sizeof(procps_jiffs) = %u, sizeof(procps_jiffs_hist) = %u" + "\n\t sizeof(struct pids_stack) = %u, Pids_cnts->total = %u,, total overhead = %u" "\n\t SCREENMAX = %u, ROWMINSIZ = %u, ROWMAXSIZ = %u" "\n\t PACKAGE = '%s', LOCALEDIR = '%s'" "\n\tTerminal: %s" @@ -457,20 +361,18 @@ static void bye_bye (const char *str) { #ifdef CASEUP_HEXES "\n\t winflags = %08X, maxpflgs = %d" #else - "\n\t winflags = %08x, maxpflgs = %d" + "\n\t winflags = x%08x, maxpflgs = %d" #endif - "\n\t sortindx = %d, fieldscur = %s" - "\n\t maxtasks = %d, varcolsz = %d, winlines = %d" + "\n\t sortindx = %d, maxtasks = %d" + "\n\t varcolsz = %d, winlines = %d" "\n\t strlen(columnhdr) = %d" "\n" , __func__ , PACKAGE_STRING , (unsigned)Hertz, (unsigned)sizeof(Hertz), (unsigned)sizeof(Hertz) * 8 - , (int)Page_size, Cpu_faux_cnt, (int)Cpu_cnt - , (unsigned)sizeof(HST_t), ((int)Page_size / (int)sizeof(HST_t)), HHist_siz - , (unsigned)sizeof(proc_t), (unsigned)sizeof(p->cmd), (unsigned)sizeof(proc_t*) - , (unsigned)sizeof(struct procps_jiffs), (unsigned)sizeof(struct procps_jiffs_hist), (unsigned)sizeof(struct procps_sys_result) - , (long)Frames_libflags + , Cpu_faux_cnt, (int)Cpu_cnt + , (unsigned)sizeof(struct procps_jiffs), (unsigned)sizeof(struct procps_jiffs_hist) + , (unsigned)sizeof(*p), Pids_cnts->total, (unsigned)sizeof(p) * Pids_cnts->total , (unsigned)SCREENMAX, (unsigned)ROWMINSIZ, (unsigned)ROWMAXSIZ , PACKAGE, LOCALEDIR #ifdef PRETENDNOCAP @@ -489,92 +391,17 @@ static void bye_bye (const char *str) { , (unsigned)sizeof(WIN_t), GROUPSMAX , Curwin->rc.winname, Curwin->grpname , Curwin->rc.winflags, Curwin->maxpflgs - , Curwin->rc.sortindx, Curwin->rc.fieldscur - , Curwin->rc.maxtasks, Curwin->varcolsz, Curwin->winlines + , Curwin->rc.sortindx, Curwin->rc.maxtasks + , Curwin->varcolsz, Curwin->winlines , (int)strlen(Curwin->columnhdr) ); } } #endif // end: ATEOJ_RPTSTD -#ifndef OFF_HST_HASH -#ifdef ATEOJ_RPTHSH - if (!str && !Frames_signal && Ttychanged) { - int i, j, pop, total_occupied, maxdepth, maxdepth_sav, numdepth - , cross_foot, sz = HHASH_SIZ * (unsigned)sizeof(int); - int depths[HHASH_SIZ]; - - for (i = 0, total_occupied = 0, maxdepth = 0; i < HHASH_SIZ; i++) { - int V = PHash_new[i]; - j = 0; - if (-1 < V) { - ++total_occupied; - while (-1 < V) { - V = PHist_new[V].lnk; - if (-1 < V) j++; - } - } - depths[i] = j; - if (maxdepth < j) maxdepth = j; - } - maxdepth_sav = maxdepth; - - fprintf(stderr, - "\n%s's Supplementary HASH report:" - "\n\tTwo Tables providing for %d entries each + 1 extra for 'empty' image" - "\n\t%dk (%d bytes) per table, %d total bytes (including 'empty' image)" - "\n\tResults from latest hash (PHash_new + PHist_new)..." - "\n" - "\n\tTotal hashed = %d" - "\n\tLevel-0 hash entries = %d (%d%% occupied)" - "\n\tMax Depth = %d" - "\n\n" - , __func__ - , HHASH_SIZ, sz / 1024, sz, sz * 3 - , Frame_maxtask - , total_occupied, (total_occupied * 100) / HHASH_SIZ - , maxdepth + 1); - - if (total_occupied) { - for (pop = total_occupied, cross_foot = 0; maxdepth; maxdepth--) { - for (i = 0, numdepth = 0; i < HHASH_SIZ; i++) - if (depths[i] == maxdepth) ++numdepth; - fprintf(stderr, - "\t %5d (%3d%%) hash table entries at depth %d\n" - , numdepth, (numdepth * 100) / total_occupied, maxdepth + 1); - pop -= numdepth; - cross_foot += numdepth; - if (0 == pop && cross_foot == total_occupied) break; - } - if (pop) { - fprintf(stderr, "\t %5d (%3d%%) unchained hash table entries\n" - , pop, (pop * 100) / total_occupied); - cross_foot += pop; - } - fprintf(stderr, - "\t -----\n" - "\t %5d total entries occupied\n", cross_foot); - - if (maxdepth_sav) { - fprintf(stderr, "\nPIDs at max depth: "); - for (i = 0; i < HHASH_SIZ; i++) - if (depths[i] == maxdepth_sav) { - j = PHash_new[i]; - fprintf(stderr, "\n\tpos %4d: %05d", i, PHist_new[j].pid); - while (-1 < j) { - j = PHist_new[j].lnk; - if (-1 < j) fprintf(stderr, ", %05d", PHist_new[j].pid); - } - } - fprintf(stderr, "\n"); - } - } - } -#endif // end: ATEOJ_RPTHSH -#endif // end: OFF_HST_HASH - procps_stat_unref(&Cpu_ctx); procps_meminfo_unref(&Mem_ctx); + procps_pids_unref(&Pids_ctx); #ifndef NUMA_DISABLE if (Libnuma_handle) dlclose(Libnuma_handle); #endif @@ -1461,9 +1288,11 @@ static const char *user_certify (WIN_t *q, const char *str, char typ) { char *endp; uid_t num; + if (Pids_fill) + procps_pids_stacks_dealloc(Pids_ctx, &Pids_fill); + Monpidsidx = 0; q->usrseltyp = 0; q->usrselflg = 1; - Monpidsidx = 0; if (*str) { if ('!' == *str) { ++str; q->usrselflg = 0; } num = (uid_t)strtoul(str, &endp, 0); @@ -1484,29 +1313,6 @@ static const char *user_certify (WIN_t *q, const char *str, char typ) { } return NULL; } // end: user_certify - - - /* - * Determine if this proc_t matches the 'u/U' selection criteria - * for a given window -- it's called from only one place, and - * likely inlined even without the directive */ -static inline int user_matched (const WIN_t *q, const proc_t *p) { - switch(q->usrseltyp) { - case 0: // uid selection inactive - return 1; - case 'U': // match any uid - if (p->ruid == q->usrseluid) return q->usrselflg; - if (p->suid == q->usrseluid) return q->usrselflg; - if (p->fuid == q->usrseluid) return q->usrselflg; - // fall through... - case 'u': // match effective uid - if (p->euid == q->usrseluid) return q->usrselflg; - // fall through... - default: // no match... - ; - } - return !q->usrselflg; -} // end: user_matched /*###### Basic Formatting support ######################################*/ @@ -1704,30 +1510,16 @@ end_justifies: /*###### Fields Management support #####################################*/ - /* These are the Fieldstab.lflg values used here and in calibrate_fields. - (own identifiers as documentation and protection against changes) */ -#define L_stat PROC_FILLSTAT -#define L_statm PROC_FILLMEM -#define L_status PROC_FILLSTATUS -#define L_CGROUP PROC_EDITCGRPCVT | PROC_FILLCGROUP -#define L_CMDLINE PROC_EDITCMDLCVT | PROC_FILLARG -#define L_ENVIRON PROC_EDITENVRCVT | PROC_FILLENV -#define L_EUSER PROC_FILLUSR -#define L_OUSER PROC_FILLSTATUS | PROC_FILLUSR -#define L_EGROUP PROC_FILLSTATUS | PROC_FILLGRP -#define L_SUPGRP PROC_FILLSTATUS | PROC_FILLSUPGRP -#define L_NS PROC_FILLNS -#define L_LXC PROC_FILL_LXC - // make 'none' non-zero (used to be important to Frames_libflags) -#define L_NONE PROC_SPARE_1 - // from either 'stat' or 'status' (preferred), via bits not otherwise used -#define L_EITHER PROC_SPARE_2 - // for calibrate_fields and summary_show 1st pass -#define L_DEFAULT PROC_FILLSTAT - /* These are our gosh darn 'Fields' ! They MUST be kept in sync with pflags !! */ -static FLD_t Fieldstab[] = { +static struct { + int width; // field width, if applicable + int scale; // scaled target, if applicable + const int align; // the default column alignment flag + int esel; // set when our enum is selected + int erel; // relative position in dynamic Pids_itms + const enum pids_item item; // the new libproc item enum identifier +} Fieldstab[] = { // a temporary macro, soon to be undef'd... #define SF(f) (QFP_t)SCB_NAME(f) // these identifiers reflect the default column alignment but they really @@ -1738,87 +1530,93 @@ static FLD_t Fieldstab[] = { /* .width anomalies: a -1 width represents variable width columns a 0 width represents columns set once at startup (see zap_fieldstab) - .lflg anomalies: - EU_UED, L_NONE - natural outgrowth of 'stat()' in readproc (euid) - EU_CPU, L_stat - never filled by libproc, but requires times (pcpu) - EU_CMD, L_stat - may yet require L_CMDLINE in calibrate_fields (cmd/cmdline) - L_EITHER - must L_status, else L_stat == 64-bit math (__udivdi3) on 32-bit ! - - .width .scale .align .sort .lflg - ------ ------ -------- -------- -------- */ - { 0, -1, A_right, SF(PID), L_NONE }, - { 0, -1, A_right, SF(PPD), L_EITHER }, - { 5, -1, A_right, SF(UED), L_NONE }, - { 8, -1, A_left, SF(UEN), L_EUSER }, - { 5, -1, A_right, SF(URD), L_status }, - { 8, -1, A_left, SF(URN), L_OUSER }, - { 5, -1, A_right, SF(USD), L_status }, - { 8, -1, A_left, SF(USN), L_OUSER }, - { 5, -1, A_right, SF(GID), L_NONE }, - { 8, -1, A_left, SF(GRP), L_EGROUP }, - { 0, -1, A_right, SF(PGD), L_stat }, - { 8, -1, A_left, SF(TTY), L_stat }, - { 0, -1, A_right, SF(TPG), L_stat }, - { 0, -1, A_right, SF(SID), L_stat }, - { 3, -1, A_right, SF(PRI), L_stat }, - { 3, -1, A_right, SF(NCE), L_stat }, - { 3, -1, A_right, SF(THD), L_EITHER }, - { 0, -1, A_right, SF(CPN), L_stat }, - { 0, -1, A_right, SF(CPU), L_stat }, - { 6, -1, A_right, SF(TME), L_stat }, - { 9, -1, A_right, SF(TME), L_stat }, // EU_TM2 slot + + .width .scale .align .esel .erel .item + ------ ------ -------- ----- ----- ------------------------- */ + { 0, -1, A_right, 0, 0, PROCPS_PIDS_ID_PID }, // s_int EU_PID + { 0, -1, A_right, 0, 0, PROCPS_PIDS_ID_PPID }, // s_int EU_PPD + { 5, -1, A_right, 0, 0, PROCPS_PIDS_ID_EUID }, // u_int EU_UED + { 8, -1, A_left, 0, 0, PROCPS_PIDS_ID_EUSER }, // str EU_UEN + { 5, -1, A_right, 0, 0, PROCPS_PIDS_ID_RUID }, // u_int EU_URD + { 8, -1, A_left, 0, 0, PROCPS_PIDS_ID_RUSER }, // str EU_URN + { 5, -1, A_right, 0, 0, PROCPS_PIDS_ID_SUID }, // u_int EU_USD + { 8, -1, A_left, 0, 0, PROCPS_PIDS_ID_SUSER }, // str EU_USN + { 5, -1, A_right, 0, 0, PROCPS_PIDS_ID_EGID }, // u_int EU_GID + { 8, -1, A_left, 0, 0, PROCPS_PIDS_ID_EGROUP }, // str EU_GRP + { 0, -1, A_right, 0, 0, PROCPS_PIDS_ID_PGRP }, // s_int EU_PGD + { 8, -1, A_left, 0, 0, PROCPS_PIDS_TTY }, // s_int EU_TTY + { 0, -1, A_right, 0, 0, PROCPS_PIDS_ID_TPGID }, // s_int EU_TPG + { 0, -1, A_right, 0, 0, PROCPS_PIDS_ID_SESSION }, // s_int EU_SID + { 3, -1, A_right, 0, 0, PROCPS_PIDS_PRIORITY }, // s_int EU_PRI + { 3, -1, A_right, 0, 0, PROCPS_PIDS_NICE }, // sl_int EU_NCE + { 3, -1, A_right, 0, 0, PROCPS_PIDS_NLWP }, // s_int EU_THD + { 0, -1, A_right, 0, 0, PROCPS_PIDS_PROCESSOR }, // u_int EU_CPN + { 0, -1, A_right, 0, 0, PROCPS_PIDS_TICS_DELTA }, // u_int EU_CPU + { 6, -1, A_right, 0, 0, PROCPS_PIDS_TICS_ALL }, // ull_int EU_TME + { 9, -1, A_right, 0, 0, PROCPS_PIDS_TICS_ALL }, // ull_int EU_TM2 #ifdef BOOST_PERCNT - { 5, -1, A_right, SF(RES), L_status }, // EU_MEM slot + { 5, -1, A_right, 0, 0, PROCPS_PIDS_VM_RSS }, // ul_int EU_MEM #else - { 4, -1, A_right, SF(RES), L_status }, // EU_MEM slot + { 4, -1, A_right, 0, 0, PROCPS_PIDS_VM_RSS }, // ul_int EU_MEM, #endif #ifndef NOBOOST_MEMS - { 7, SK_Kb, A_right, SF(VRT), L_statm }, - { 6, SK_Kb, A_right, SF(SWP), L_status }, - { 6, SK_Kb, A_right, SF(RES), L_status }, - { 6, SK_Kb, A_right, SF(COD), L_statm }, - { 7, SK_Kb, A_right, SF(DAT), L_statm }, - { 6, SK_Kb, A_right, SF(SHR), L_statm }, + { 7, SK_Kb, A_right, 0, 0, PROCPS_PIDS_MEM_VIRT_KIB }, // sl_int EU_VRT + { 6, SK_Kb, A_right, 0, 0, PROCPS_PIDS_VM_SWAP }, // ul_int EU_SWP + { 6, SK_Kb, A_right, 0, 0, PROCPS_PIDS_VM_RSS }, // ul_int EU_RES + { 6, SK_Kb, A_right, 0, 0, PROCPS_PIDS_MEM_CODE_KIB }, // sl_int EU_COD + { 7, SK_Kb, A_right, 0, 0, PROCPS_PIDS_MEM_DATA_KIB }, // sl_int EU_DAT + { 6, SK_Kb, A_right, 0, 0, PROCPS_PIDS_MEM_SHR_KIB }, // sl_int EU_SHR #else - { 5, SK_Kb, A_right, SF(VRT), L_statm }, - { 4, SK_Kb, A_right, SF(SWP), L_status }, - { 4, SK_Kb, A_right, SF(RES), L_status }, - { 4, SK_Kb, A_right, SF(COD), L_statm }, - { 5, SK_Kb, A_right, SF(DAT), L_statm }, - { 4, SK_Kb, A_right, SF(SHR), L_statm }, + { 5, SK_Kb, A_right, 0, 0, PROCPS_PIDS_MEM_VIRT_KIB }, // sl_int EU_VRT + { 4, SK_Kb, A_right, 0, 0, PROCPS_PIDS_VM_SWAP }, // ul_int EU_SWP + { 4, SK_Kb, A_right, 0, 0, PROCPS_PIDS_VM_RSS }, // ul_int EU_RES + { 4, SK_Kb, A_right, 0, 0, PROCPS_PIDS_MEM_CODE_KIB }, // sl_int EU_COD + { 5, SK_Kb, A_right, 0, 0, PROCPS_PIDS_MEM_DATA_KIB }, // sl_int EU_DAT + { 4, SK_Kb, A_right, 0, 0, PROCPS_PIDS_MEM_SHR_KIB }, // sl_int EU_SHR #endif - { 4, -1, A_right, SF(FL1), L_stat }, - { 4, -1, A_right, SF(FL2), L_stat }, - { 4, -1, A_right, SF(DRT), L_statm }, - { 1, -1, A_right, SF(STA), L_EITHER }, - { -1, -1, A_left, SF(CMD), L_EITHER }, - { 10, -1, A_left, SF(WCH), L_stat }, - { 8, -1, A_left, SF(FLG), L_stat }, - { -1, -1, A_left, SF(CGR), L_CGROUP }, - { -1, -1, A_left, SF(SGD), L_status }, - { -1, -1, A_left, SF(SGN), L_SUPGRP }, - { 0, -1, A_right, SF(TGD), L_status }, + { 4, -1, A_right, 0, 0, PROCPS_PIDS_FLT_MAJ }, // ul_int EU_FL1 + { 4, -1, A_right, 0, 0, PROCPS_PIDS_FLT_MIN }, // ul_int EU_FL2 + { 4, -1, A_right, 0, 0, PROCPS_PIDS_MEM_DT }, // sl_int EU_DRT ( always 0 w/ since 2.6 ) + { 1, -1, A_right, 0, 0, PROCPS_PIDS_STATE }, // s_ch EU_STA + { -1, -1, A_left, 0, 0, PROCPS_PIDS_CMD }, // str EU_CMD + { 10, -1, A_left, 0, 0, PROCPS_PIDS_WCHAN_NAME }, // str EU_WCH + { 8, -1, A_left, 0, 0, PROCPS_PIDS_FLAGS }, // ul_int EU_FLG + { -1, -1, A_left, 0, 0, PROCPS_PIDS_CGROUP }, // str EU_CGR + { -1, -1, A_left, 0, 0, PROCPS_PIDS_SUPGIDS }, // str EU_SGD + { -1, -1, A_left, 0, 0, PROCPS_PIDS_SUPGROUPS }, // str EU_SGN + { 0, -1, A_right, 0, 0, PROCPS_PIDS_ID_TGID }, // s_int EU_TGD #ifdef OOMEM_ENABLE -#define L_oom PROC_FILLOOM - { 3, -1, A_right, SF(OOA), L_oom }, - { 8, -1, A_right, SF(OOM), L_oom }, -#undef L_oom + #define L_oom PROC_FILLOOM + { 3, -1, A_right, 0, 0, PROCPS_PIDS_OOM_ADJ }, // s_int EU_OOA + { 8, -1, A_right, 0, 0, PROCPS_PIDS_OOM_SCORE }, // s_int EU_OOM + #undef L_oom #endif - { -1, -1, A_left, SF(ENV), L_ENVIRON }, - { 3, -1, A_right, SF(FV1), L_stat }, - { 3, -1, A_right, SF(FV2), L_stat }, + { -1, -1, A_left, 0, 0, PROCPS_PIDS_ENVIRON }, // str EU_ENV + { 3, -1, A_right, 0, 0, PROCPS_PIDS_FLT_MAJ_DELTA }, // ul_int EU_FV1 + { 3, -1, A_right, 0, 0, PROCPS_PIDS_FLT_MIN_DELTA }, // ul_int EU_FV2 #ifndef NOBOOST_MEMS - { 6, SK_Kb, A_right, SF(USE), L_status }, + { 6, SK_Kb, A_right, 0, 0, PROCPS_PIDS_VM_USED }, // ul_int EU_USE #else - { 4, SK_Kb, A_right, SF(USE), L_status }, + { 4, SK_Kb, A_right, 0, 0, PROCPS_PIDS_VM_USED }, // ul_int EU_USE #endif - { 10, -1, A_right, SF(NS1), L_NS }, // IPCNS - { 10, -1, A_right, SF(NS2), L_NS }, // MNTNS - { 10, -1, A_right, SF(NS3), L_NS }, // NETNS - { 10, -1, A_right, SF(NS4), L_NS }, // PIDNS - { 10, -1, A_right, SF(NS5), L_NS }, // USERNS - { 10, -1, A_right, SF(NS6), L_NS }, // UTSNS - { 8, -1, A_left, SF(LXC), L_LXC } + { 10, -1, A_right, 0, 0, PROCPS_PIDS_NS_IPC }, // ul_int EU_NS1 + { 10, -1, A_right, 0, 0, PROCPS_PIDS_NS_MNT }, // ul_int EU_NS2 + { 10, -1, A_right, 0, 0, PROCPS_PIDS_NS_NET }, // ul_int EU_NS3 + { 10, -1, A_right, 0, 0, PROCPS_PIDS_NS_PID }, // ul_int EU_NS4 + { 10, -1, A_right, 0, 0, PROCPS_PIDS_NS_USER }, // ul_int EU_NS5 + { 10, -1, A_right, 0, 0, PROCPS_PIDS_NS_UTS }, // ul_int EU_NS6 + { 8, -1, A_left, 0, 0, PROCPS_PIDS_LXCNAME }, // str EU_LXC ( the last real pflag ) +// xtra Fieldstab 'pseudo pflag' entries for the newlib interface . . . ------------------------------------------ +#define eu_CMDLINE EU_LXC +1 +#define eu_TICS_ALL_C EU_LXC +2 +#define eu_TIME_START EU_LXC +3 +#define eu_ID_FUID EU_LXC +4 +#define eu_NOOP EU_LXC +5 + { -1, -1, -1, -1, -1, PROCPS_PIDS_CMDLINE }, // str ( if Show_CMDLIN ) + { -1, -1, -1, -1, -1, PROCPS_PIDS_TICS_ALL_C }, // ull_int ( if Show_CTIMES ) + { -1, -1, -1, -1, -1, PROCPS_PIDS_TIME_START }, // ull_int ( if Show_FOREST ) + { -1, -1, -1, -1, -1, PROCPS_PIDS_ID_FUID }, // u_int ( if a usrseltyp ) + { -1, -1, -1, -1, -1, PROCPS_PIDS_noop } // n/a ( why not? ) #undef SF #undef A_left #undef A_right @@ -1916,6 +1714,10 @@ static void adj_geometry (void) { * A calibrate_fields() *Helper* function to build the * actual column headers and required library flags */ static void build_headers (void) { + #define ckITEM(f) do { if (!Fieldstab[f].esel) { Fieldstab[f].erel = Pids_itms_cur; \ + Pids_itms[Pids_itms_cur++] = Fieldstab[f].item; Fieldstab[f].esel = 1; } } while (0) + #define ckCMDS(w) do { if (CHKw(w, Show_CMDLIN)) ckITEM(eu_CMDLINE); \ + else ckITEM(EU_CMD); } while (0) FLG_t f; char *s; WIN_t *w = Curwin; @@ -1924,12 +1726,21 @@ static void build_headers (void) { #endif int i; - Frames_libflags = 0; + // reset the newlib enum selected indicator + Pids_itms_cur = 0; + for (i = 0; i < MAXTBL(Fieldstab); i++) + Fieldstab[i].esel = Fieldstab[i].erel = 0; + ckITEM(EU_PID); // these 5 fields may not display, + ckITEM(EU_STA); // yet we'll always need the 1st 2 + ckITEM(EU_CMD); + ckITEM(EU_UED); // plus the last 3 would have been + ckITEM(EU_GID); // guaranteed under old lib scheme do { if (VIZISw(w)) { memset((s = w->columnhdr), 0, sizeof(w->columnhdr)); if (Rc.mode_altscr) s = scat(s, fmtmk("%d", w->winnum)); + for (i = 0; i < w->maxpflgs; i++) { f = w->procflgs[i]; #ifdef USE_X_COLHDR @@ -1940,8 +1751,9 @@ static void build_headers (void) { #else if (EU_MAXPFLGS <= f) continue; #endif - if (EU_CMD == f && CHKw(w, Show_CMDLIN)) Frames_libflags |= L_CMDLINE; - Frames_libflags |= Fieldstab[f].lflg; + if (EU_CMD == f) ckCMDS(w); + else ckITEM(f); + s = scat(s, justify_pad(N_col(f) , VARcol(f) ? w->varcolsz : Fieldstab[f].width , CHKw(w, Fieldstab[f].align))); @@ -1956,14 +1768,22 @@ static void build_headers (void) { // prepare to even out column header lengths... if (hdrmax + w->hdrcaplen < (x = strlen(w->columnhdr))) hdrmax = x - w->hdrcaplen; #endif - // with forest view mode, we'll need tgid, ppid & start_time... - if (CHKw(w, Show_FOREST)) Frames_libflags |= (L_status | L_stat); - // for 'busy' only processes, we'll need pcpu (utime & stime)... - if (!CHKw(w, Show_IDLEPS)) Frames_libflags |= L_stat; + // cpu calculations depend on number of threads + if (Fieldstab[EU_CPU].esel) ckITEM(EU_THD); + // for 'busy' only processes, we'll need elapsed tics + if (!CHKw(w, Show_IDLEPS)) ckITEM(EU_CPU); + // with forest view mode, we'll need pid, tgid, ppid & start_time... + if (CHKw(w, Show_FOREST)) { ckITEM(EU_PPD); ckITEM(EU_TGD); ckITEM(eu_TIME_START); } + // for 'cumulative' times, we'll need equivalent of cutime & cstime + if (Fieldstab[EU_TME].esel && CHKw(w, Show_CTIMES)) ckITEM(eu_TICS_ALL_C); + if (Fieldstab[EU_TM2].esel && CHKw(w, Show_CTIMES)) ckITEM(eu_TICS_ALL_C); + // for 'u/U' filtering we need these too (old top forgot that, oops) + if (w->usrseltyp) { ckITEM(EU_URD); ckITEM(EU_USD); ckITEM(eu_ID_FUID); } + // we must also accommodate an out of view sort field... f = w->rc.sortindx; - Frames_libflags |= Fieldstab[f].lflg; - if (EU_CMD == f && CHKw(w, Show_CMDLIN)) Frames_libflags |= L_CMDLINE; + if (EU_CMD == f) ckCMDS(w); + else ckITEM(f); } // end: VIZISw(w) if (Rc.mode_altscr) w = w->next; @@ -1981,11 +1801,8 @@ static void build_headers (void) { } #endif - // finalize/touchup the libproc PROC_FILLxxx flags for current config... - if ((Frames_libflags & L_EITHER) && !(Frames_libflags & L_stat)) - Frames_libflags |= L_status; - if (!Frames_libflags) Frames_libflags = L_DEFAULT; - if (Monpidsidx) Frames_libflags |= PROC_PID; + #undef ckITEM + #undef ckCMDS } // end: build_headers @@ -2076,6 +1893,10 @@ static void calibrate_fields (void) { } while (w != Curwin); build_headers(); + + if (procps_pids_reset(Pids_ctx, Pids_itms_cur, Pids_itms)) + error_exit(fmtmk(N_fmt(LIB_errorpid_fmt),__LINE__)); + if (CHKw(Curwin, View_SCROLL)) updt_scroll_msg(); } // end: calibrate_fields @@ -2398,10 +2219,10 @@ static void cpus_refresh (void) { // 'hist_fill' also implies 'read', saving us one more call Cpu_faux_cnt = procps_stat_jiffs_hist_fill(Cpu_ctx, Cpu_jiffs, sumSLOT); if (Cpu_faux_cnt < 0) - error_exit(N_txt(LIB_errorcpu_txt)); + error_exit(fmtmk(N_fmt(LIB_errorcpu_fmt),__LINE__)); // 2nd, retrieve just the cpu summary jiffs if (procps_stat_jiffs_hist_get(Cpu_ctx, &Cpu_jiffs[sumSLOT], -1) < 0) - error_exit(N_txt(LIB_errorcpu_txt)); + error_exit(fmtmk(N_fmt(LIB_errorcpu_fmt),__LINE__)); #ifndef NUMA_DISABLE /* henceforth, with just a little more arithmetic we can avoid @@ -2448,203 +2269,54 @@ static void cpus_refresh (void) { } // end: cpus_refresh -#ifdef OFF_HST_HASH - /* - * Binary Search for HST_t's put/get support */ - -static inline HST_t *hstbsrch (HST_t *hst, int max, int pid) { - int mid, min = 0; - - while (min <= max) { - mid = (min + max) / 2; - if (pid < hst[mid].pid) max = mid - 1; - else if (pid > hst[mid].pid) min = mid + 1; - else return &hst[mid]; - } - return NULL; -} // end: hstbsrch - -#else - /* - * Hashing functions for HST_t's put/get support - * (not your normal 'chaining', those damn HST_t's might move!) */ - -#define _HASH_(K) (K & (HHASH_SIZ - 1)) - -static inline HST_t *hstget (int pid) { - int V = PHash_sav[_HASH_(pid)]; - - while (-1 < V) { - if (PHist_sav[V].pid == pid) return &PHist_sav[V]; - V = PHist_sav[V].lnk; } - return NULL; -} // end: hstget - - -static inline void hstput (unsigned idx) { - int V = _HASH_(PHist_new[idx].pid); - - PHist_new[idx].lnk = PHash_new[V]; - PHash_new[V] = idx; -} // end: hstput - -#undef _HASH_ -#endif - /* - * Refresh procs *Helper* function to eliminate yet one more need - * to loop through our darn proc_t table. He's responsible for: - * 1) calculating the elapsed time since the previous frame - * 2) counting the number of tasks in each state (run, sleep, etc) - * 3) maintaining the HST_t's and priming the proc_t pcpu field - * 4) establishing the total number tasks for this frame */ -static void procs_hlp (proc_t *this) { -#ifdef OFF_HST_HASH - static unsigned maxt_sav = 0; // prior frame's max tasks -#endif - TIC_t tics; - HST_t *h; - - if (!this) { - static double uptime_sav; - double uptime_cur; - float et; - void *v; - - procps_uptime(&uptime_cur, NULL); - et = uptime_cur - uptime_sav; - if (et < 0.01) et = 0.005; - uptime_sav = uptime_cur; - - // if in Solaris mode, adjust our scaling for all cpus - Frame_etscale = 100.0f / ((float)Hertz * (float)et * (Rc.mode_irixps ? 1 : Cpu_cnt)); -#ifdef OFF_HST_HASH - maxt_sav = Frame_maxtask; -#endif - Frame_maxtask = Frame_running = Frame_sleepin = Frame_stopped = Frame_zombied = 0; - - // prep for saving this frame's HST_t's (and reuse mem each time around) - v = PHist_sav; - PHist_sav = PHist_new; - PHist_new = v; -#ifdef OFF_HST_HASH - // prep for binary search by sorting the last frame's HST_t's - qsort(PHist_sav, maxt_sav, sizeof(HST_t), (QFP_t)sort_HST_t); -#else - v = PHash_sav; - PHash_sav = PHash_new; - PHash_new = v; - memcpy(PHash_new, HHash_nul, sizeof(HHash_nul)); -#endif - return; - } - - switch (this->state) { - case 'R': - Frame_running++; - break; - case 'S': - case 'D': - Frame_sleepin++; - break; - case 'T': - Frame_stopped++; - break; - case 'Z': - Frame_zombied++; - break; - default: // keep gcc happy - break; - } - - if (Frame_maxtask+1 >= HHist_siz) { - HHist_siz = HHist_siz * 5 / 4 + 100; - PHist_sav = alloc_r(PHist_sav, sizeof(HST_t) * HHist_siz); - PHist_new = alloc_r(PHist_new, sizeof(HST_t) * HHist_siz); - } - - /* 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! */ - PHist_new[Frame_maxtask].pid = this->tid; - PHist_new[Frame_maxtask].tics = tics = (this->utime + this->stime); - // finally, save major/minor fault counts in case the deltas are displayable - PHist_new[Frame_maxtask].maj = this->maj_flt; - PHist_new[Frame_maxtask].min = this->min_flt; - -#ifdef OFF_HST_HASH - // find matching entry from previous frame and make stuff elapsed - if ((h = hstbsrch(PHist_sav, maxt_sav - 1, this->tid))) { - tics -= h->tics; - this->maj_delta = this->maj_flt - h->maj; - this->min_delta = this->min_flt - h->min; - } -#else - // hash & save for the next frame - hstput(Frame_maxtask); - // find matching entry from previous frame and make stuff elapsed - if ((h = hstget(this->tid))) { - tics -= h->tics; - this->maj_delta = this->maj_flt - h->maj; - this->min_delta = this->min_flt - h->min; - } -#endif - - /* we're just saving elapsed tics, to be converted into %cpu if - this task wins it's displayable screen row lottery... */ - this->pcpu = tics; - - // shout this to the world with the final call (or us the next time in) - Frame_maxtask++; -} // end: procs_hlp - - - /* - * This guy's modeled on libproc's 'readproctab' function except - * we reuse and extend any prior proc_t's. He's been customized - * for our specific needs and to avoid the use of */ + * This guy's responsible for interfacing with the library 'reap' pids + * and 'fill' stacks capabilities and refreshing the individual WIN_t + * head-of-stacks arrays, growing them as appropirate. */ static void procs_refresh (void) { - #define n_used Frame_maxtask // maintained by procs_hlp() - static proc_t **private_ppt; // our base proc_t ptr table - static int n_alloc = 0; // size of our private_ppt - static int n_saved = 0; // last window ppt size - proc_t *ptask; - PROCTAB* PT; + #define nALIGN(n,m) (((n + m - 1) / m) * m) // unconditionally align + #define nALGN2(n,m) ((n + m - 1) & ~(m - 1)) // with power of 2 align + #define n_reap Pids_cnts->total // maintained by newlib + static double uptime_sav; + static int n_alloc; // size of windows stacks arrays + double uptime_cur; + float et; int i; - proc_t*(*read_something)(PROCTAB*, proc_t*); - procs_hlp(NULL); // prep for a new frame - if (NULL == (PT = openproc(Frames_libflags, Monpids))) - error_exit(fmtmk(N_fmt(FAIL_openlib_fmt), strerror(errno))); - read_something = Thread_mode ? readeither : readproc; - - for (;;) { - if (n_used == n_alloc) { - n_alloc = 10 + ((n_alloc * 5) / 4); // grow by over 25% - private_ppt = alloc_r(private_ppt, sizeof(proc_t*) * n_alloc); - // ensure NULL pointers for the additional memory just acquired - memset(private_ppt + n_used, 0, sizeof(proc_t*) * (n_alloc - n_used)); - } - // on the way to n_alloc, the library will allocate the underlying - // proc_t storage whenever our private_ppt[] pointer is NULL... - if (!(ptask = read_something(PT, private_ppt[n_used]))) break; - procs_hlp((private_ppt[n_used] = ptask)); // tally this proc_t + procps_uptime(&uptime_cur, NULL); + et = uptime_cur - uptime_sav; + if (et < 0.01) et = 0.005; + uptime_sav = uptime_cur; + // if in Solaris mode, adjust our scaling for all cpus + Frame_etscale = 100.0f / ((float)Hertz * (float)et * (Rc.mode_irixps ? 1 : Cpu_cnt)); + + if (Pids_fill) { + if (!(Pids_cnts = procps_pids_stacks_fill(Pids_ctx, Pids_fill + , Monpidsidx, PROCPS_FILL_PID))) + error_exit(fmtmk(N_fmt(LIB_errorpid_fmt),__LINE__)); + Pids_stks = Pids_fill->stacks; + } else { + if (!(Pids_reap = procps_pids_reap(Pids_ctx, Pids_type[Thread_mode]))) + error_exit(fmtmk(N_fmt(LIB_errorpid_fmt),__LINE__)); + Pids_stks = Pids_reap->reaped.stacks; + Pids_cnts = &Pids_reap->counts; } - closeproc(PT); - - // lastly, refresh each window's proc pointers table... - if (n_saved == n_alloc) - for (i = 0; i < GROUPSMAX; i++) - memcpy(Winstk[i].ppt, private_ppt, sizeof(proc_t*) * n_used); - else { - n_saved = n_alloc; + // now refresh each window's stack heads pointers table... + if (n_alloc < n_reap) { +// n_alloc = nALIGN(n_reap, 100); + n_alloc = nALGN2(n_reap, 128); for (i = 0; i < GROUPSMAX; i++) { - Winstk[i].ppt = alloc_r(Winstk[i].ppt, sizeof(proc_t*) * n_alloc); - memcpy(Winstk[i].ppt, private_ppt, sizeof(proc_t*) * n_used); + Winstk[i].ppt = alloc_r(Winstk[i].ppt, sizeof(void*) * n_alloc); + memcpy(Winstk[i].ppt, Pids_stks, sizeof(void*) * n_reap); } + } else { + for (i = 0; i < GROUPSMAX; i++) + memcpy(Winstk[i].ppt, Pids_stks, sizeof(void*) * n_reap); } - #undef n_used + #undef n_reap + #undef nALGN2 + #undef nALIGN } // end: procs_refresh @@ -2664,7 +2336,7 @@ static void sysinfo_refresh (int forced) { if (3 <= cur_secs - mem_secs) { // 'stack_fill' also implies 'read', saving us one more call if ((procps_meminfo_stack_fill(Mem_ctx, Mem_stack) < 0)) - error_exit(N_txt(LIB_errormem_txt)); + error_exit(fmtmk(N_fmt(LIB_errormem_fmt),__LINE__)); mem_secs = cur_secs; } #ifndef PRETEND8CPUS @@ -3034,7 +2706,7 @@ static inline void insp_show_pgs (int col, int row, int max) { /* * This guy is responsible for displaying the Insp_buf contents and * managing all scrolling/locate requests until the user gives up. */ -static int insp_view_choice (proc_t *obj) { +static int insp_view_choice (struct pids_stack *obj) { #ifdef INSP_SLIDE_1 #define hzAMT 1 #else @@ -3042,8 +2714,8 @@ static int insp_view_choice (proc_t *obj) { #endif #define maxLN (Screen_rows - (Msg_row +1)) #define makHD(b1,b2) { \ - snprintf(b1, sizeof(b1), "%d", obj->tid); \ - snprintf(b2, sizeof(b2), "%s", obj->cmd); } + snprintf(b1, sizeof(b1), "%d", PID_VAL(EU_PID, s_int, obj)); \ + snprintf(b2, sizeof(b2), "%s", PID_VAL(EU_CMD, str, obj)); } #define makFS(dst) { if (Insp_sel->flen < 22) \ snprintf(dst, sizeof(dst), "%s", Insp_sel->fstr); \ else snprintf(dst, sizeof(dst), "%.19s...", Insp_sel->fstr); } @@ -3153,10 +2825,10 @@ static void inspection_utility (int pid) { char sels[MEDBUFSIZ]; static int sel; int i, key; - proc_t *p; + struct pids_stack *p; - for (i = 0, p = NULL; i < Frame_maxtask; i++) - if (pid == Curwin->ppt[i]->tid) { + for (i = 0, p = NULL; i < Pids_cnts->total; i++) + if (pid == PID_VAL(EU_PID, s_int, Curwin->ppt[i])) { p = Curwin->ppt[i]; break; } @@ -3175,7 +2847,7 @@ signify_that: mkSEL(sels); putp(Cap_home); show_special(1, fmtmk(N_unq(YINSP_hdsels_fmt) - , pid, p->cmd, sels)); + , pid, PID_VAL(EU_CMD, str, Curwin->ppt[i]), sels)); INSP_MKSL(0, " "); if (Frames_signal) goto signify_that; @@ -3243,7 +2915,6 @@ static void before (char *me) { // establish cpu particulars Hertz = procps_hertz_get(); Cpu_cnt = procps_cpu_count(); - Page_size = getpagesize(); #ifdef PRETEND8CPUS Cpu_cnt = 8; #endif @@ -3256,24 +2927,20 @@ static void before (char *me) { if (linux_version_code >= LINUX_VERSION(2, 6, 11)) Cpu_States_fmts = N_unq(STATE_lin2x7_fmt); - // get virtual page stuff - i = Page_size; - while (i > 1024) { i >>= 1; Pg2K_shft++; } - // prepare for new library API ... if (procps_meminfo_new(&Mem_ctx) < 0) - error_exit(N_txt(LIB_errormem_txt)); + error_exit(fmtmk(N_fmt(LIB_errormem_fmt),__LINE__)); if (!(Mem_stack = procps_meminfo_stack_alloc(Mem_ctx, MAXTBL(Mem_items), Mem_items))) - error_exit(N_txt(LIB_errormem_txt)); + error_exit(fmtmk(N_fmt(LIB_errormem_fmt),__LINE__)); if (procps_stat_new(&Cpu_ctx) < 0) - error_exit(N_txt(LIB_errorcpu_txt)); - -#ifndef OFF_HST_HASH - // prep for HST_t's put/get hashing optimizations - for (i = 0; i < HHASH_SIZ; i++) HHash_nul[i] = -1; - memcpy(HHash_one, HHash_nul, sizeof(HHash_nul)); - memcpy(HHash_two, HHash_nul, sizeof(HHash_nul)); -#endif + error_exit(fmtmk(N_fmt(LIB_errorcpu_fmt),__LINE__)); + // establish max depth for newlib pids stack (# of result structs) + Pids_itms = alloc_c(sizeof(enum pids_item) * MAXTBL(Fieldstab)); + for (i = 0; i < MAXTBL(Fieldstab); i++) + Pids_itms[i] = Fieldstab[i].item; + Pids_itms_cur = i; + if (procps_pids_new(&Pids_ctx, Pids_itms_cur, Pids_itms)) + error_exit(fmtmk(N_fmt(LIB_errorpid_fmt),__LINE__)); #ifndef NUMA_DISABLE #if defined(PRETEND_NUMA) || defined(PRETEND8CPUS) @@ -3690,8 +3357,8 @@ static void parse_args (char **args) { for (i = 0; i < EU_MAXPFLGS; i++) puts(N_col(i)); bye_bye(NULL); - case 'p': { - int pid; char *p; + case 'p': + { int pid; char *p; if (Curwin->usrseltyp) error_exit(N_txt(SELECT_clash_txt)); do { if (cp[1]) cp++; @@ -3711,7 +3378,12 @@ static void parse_args (char **args) { if (!(p = strchr(cp, ','))) break; cp = p; } while (*cp); - } break; + } + if (!(Pids_fill = procps_pids_stacks_alloc(Pids_ctx, Monpidsidx))) + error_exit(fmtmk(N_fmt(LIB_errorpid_fmt),__LINE__)); + for (i = 0; i < Monpidsidx; i++) + Pids_fill->stacks[i]->fill_id = Monpids[i]; + break; case 's': Secure_mode = 1; break; @@ -3727,8 +3399,8 @@ static void parse_args (char **args) { else error_exit(fmtmk(N_fmt(MISSING_args_fmt), ch)); if ((errmsg = user_certify(Curwin, cp, ch))) error_exit(errmsg); cp += strlen(cp); - break; } + break; case 'w': { const char *pn = NULL; int ai = 0, ci = 0; @@ -3742,7 +3414,8 @@ static void parse_args (char **args) { cp++; args += ai; if (pn) cp = pn + ci; - } continue; + } + continue; default : error_exit(fmtmk(N_fmt(UNKNOWN_opts_fmt) , *cp, Myname, N_txt(USAGE_abbrev_txt))); @@ -3843,8 +3516,10 @@ static void win_reset (WIN_t *q) { #else q->rc.maxtasks = q->usrseltyp = q->begpflg = q->begtask = 0; #endif - Monpidsidx = 0; osel_clear(q); + if (Pids_fill) + procps_pids_stacks_dealloc(Pids_ctx, &Pids_fill); + Monpidsidx = 0; } // end: win_reset @@ -4105,6 +3780,32 @@ static void wins_stage_2 (void) { sigaddset(&Sigwinch_set, SIGWINCH); #endif } // end: wins_stage_2 + + + /* + * Determine if this task matches the 'u/U' selection criteria + * for a given window -- it is called from only one place, and + * will likely be inlined even without the following directive */ +static inline int wins_usrselect (const WIN_t *q, struct pids_stack *p) { + // our 'results stack value' extractor macro + #define rSv(E) PID_VAL(E, u_int, p) + switch(q->usrseltyp) { + case 0: // uid selection inactive + return 1; + case 'U': // match any uid + if (rSv(EU_URD) == q->usrseluid) return q->usrselflg; + if (rSv(EU_USD) == q->usrseluid) return q->usrselflg; + if (rSv(eu_ID_FUID) == q->usrseluid) return q->usrselflg; + // fall through... + case 'u': // match effective uid + if (rSv(EU_UED) == q->usrseluid) return q->usrselflg; + // fall through... + default: // no match... + ; + } + return !q->usrselflg; + #undef rSv +} // end: wins_usrselect /*###### Interactive Input Tertiary support ############################*/ @@ -4132,7 +3833,7 @@ static inline int find_ofs (const WIN_t *q, const char *buf) { /* This is currently the one true prototype require by top. It is placed here, instead of top.h, so as to avoid a compiler warning when top_nls.c is compiled. */ -static const char *task_show (const WIN_t *q, const proc_t *p); +static const char *task_show (const WIN_t *, const int); static void find_string (int ch) { #define reDUX (found) ? N_txt(WORD_another_txt) : "" @@ -4156,8 +3857,8 @@ static void find_string (int ch) { } if (Curwin->findstr[0]) { SETw(Curwin, INFINDS_xxx); - for (i = Curwin->begtask; i < Frame_maxtask; i++) { - const char *row = task_show(Curwin, Curwin->ppt[i]); + for (i = Curwin->begtask; i < Pids_cnts->total; i++) { + const char *row = task_show(Curwin, i); if (*row && -1 < find_ofs(Curwin, row)) { found = 1; if (i == Curwin->begtask) continue; @@ -4393,7 +4094,7 @@ static void keys_global (int ch) { show_msg(N_txt(NOT_onsecure_txt)); } else { int sig = SIGTERM, - def = w->ppt[w->begtask]->tid, + def = PID_VAL(EU_PID, s_int, w->ppt[w->begtask]), pid = get_int(fmtmk(N_txt(GET_pid2kill_fmt), def)); if (pid > GET_NUM_ESC) { char *str; @@ -4415,7 +4116,7 @@ static void keys_global (int ch) { show_msg(N_txt(NOT_onsecure_txt)); else { int val, - def = w->ppt[w->begtask]->tid, + def = PID_VAL(EU_PID, s_int, w->ppt[w->begtask]), pid = get_int(fmtmk(N_txt(GET_pid2nice_fmt), def)); if (pid > GET_NUM_ESC) { if (pid == GET_NUM_NOT) pid = def; @@ -4439,7 +4140,7 @@ static void keys_global (int ch) { if (!Inspect.total) ioline(N_txt(YINSP_noents_txt)); else { - int def = w->ppt[w->begtask]->tid, + int def = PID_VAL(EU_PID, s_int, w->ppt[w->begtask]), pid = get_int(fmtmk(N_fmt(YINSP_pidsee_fmt), def)); if (pid > GET_NUM_ESC) { if (pid == GET_NUM_NOT) pid = def; @@ -4720,7 +4421,7 @@ static void keys_window (int ch) { if (VIZCHKw(w)) if (0 < w->begtask) w->begtask -= 1; break; case kbd_DOWN: - if (VIZCHKw(w)) if (w->begtask < Frame_maxtask - 1) w->begtask += 1; + if (VIZCHKw(w)) if (w->begtask < Pids_cnts->total -1) w->begtask += 1; break; #ifdef USE_X_COLHDR // ------------------------------------ case kbd_LEFT: @@ -4794,9 +4495,9 @@ static void keys_window (int ch) { } break; case kbd_PGDN: - if (VIZCHKw(w)) if (w->begtask < Frame_maxtask - 1) { + if (VIZCHKw(w)) if (w->begtask < Pids_cnts->total -1) { w->begtask += (w->winlines - 1); - if (w->begtask > Frame_maxtask - 1) w->begtask = Frame_maxtask - 1; + if (w->begtask > Pids_cnts->total -1) w->begtask = Pids_cnts->total -1; if (0 > w->begtask) w->begtask = 0; } break; @@ -4809,7 +4510,7 @@ static void keys_window (int ch) { break; case kbd_END: if (VIZCHKw(w)) { - w->begtask = (Frame_maxtask - w->winlines) + 1; + w->begtask = (Pids_cnts->total - w->winlines) +1; if (0 > w->begtask) w->begtask = 0; w->begpflg = w->endpflg; #ifndef SCROLLVAR_NO @@ -4866,89 +4567,92 @@ static void keys_xtra (int ch) { * ( plus, maintain alphabetical order with carefully chosen ) * ( function names: forest_a, forest_b, forest_c & forest_d ) * ( each with exactly one letter more than its predecessor! ) */ -static proc_t **Seed_ppt; // temporary win ppt pointer -static proc_t **Tree_ppt; // forest_create will resize -static int Tree_idx; // frame_make resets to zero +static struct pids_stack **Seed_ppt; // temporary win stacks ptrs +static struct pids_stack **Tree_ppt; // forest_create will resize +static int Tree_idx; // frame_make resets to zero +static int *Seed_lvl; // level array for Seeds ('from') +static int *Tree_lvl; // level array for Trees ('to') /* * This little recursive guy is the real forest view workhorse. * He fills in the Tree_ppt array and also sets the child indent - * level which is stored in an unused proc_t padding byte. */ + * level which is stored in the same slot of separate array. */ static void forest_adds (const int self, int level) { + // our 'results stack value' extractor macro + #define rSv(E,X) PID_VAL(E, s_int, Seed_ppt[X]) int i; - if (Tree_idx < Frame_maxtask) { // immunize against insanity + if (Tree_idx < Pids_cnts->total) { // immunize against insanity if (level > 100) level = 101; // our arbitrary nests limit Tree_ppt[Tree_idx] = Seed_ppt[self]; // add this as root or child - Tree_ppt[Tree_idx++]->pad_3 = level; // borrow 1 byte, 127 levels + Tree_lvl[Tree_idx++] = level; // while recording its level + Seed_lvl[self] = level; // then, note it's been seen #ifdef TREE_SCANALL - for (i = 0; i < Frame_maxtask; i++) { + for (i = 0; i < Pids_cnts->total; i++) { if (i == self) continue; #else - for (i = self + 1; i < Frame_maxtask; i++) { + for (i = self + 1; i < Pids_cnts->total; i++) { #endif - if (Seed_ppt[self]->tid == Seed_ppt[i]->tgid - || (Seed_ppt[self]->tid == Seed_ppt[i]->ppid && Seed_ppt[i]->tid == Seed_ppt[i]->tgid)) + if (rSv(EU_PID, self) == rSv(EU_TGD, i) + || (rSv(EU_PID, self) == rSv(EU_PPD, i) && rSv(EU_PID, i) == rSv(EU_TGD, i))) forest_adds(i, level + 1); // got one child any others? } } + #undef rSv } // end: forest_adds -#ifndef TREE_SCANALL - /* - * Our qsort callback to order a ppt by the non-display start_time - * which will make us immune from any pid, ppid or tgid anomalies - * if/when pid values are wrapped by the kernel! */ -static int forest_based (const proc_t **x, const proc_t **y) { - if ( (*x)->start_time > (*y)->start_time ) return 1; - if ( (*x)->start_time < (*y)->start_time ) return -1; - return 0; -} // end: forest_based -#endif - - /* - * This routine is responsible for preparing the proc_t's for + * This routine is responsible for preparing the stacks array for * a forest display in the designated window. Upon completion, * he'll replace the original window ppt with our specially * ordered forest version. */ static void forest_create (WIN_t *q) { + static int *lvl_arrays; // supports both 'lvl' arrays static int hwmsav; int i; - Seed_ppt = q->ppt; // avoid passing WIN_t ptrs - if (!Tree_idx) { // do just once per frame - if (hwmsav < Frame_maxtask) { // grow, but never shrink - hwmsav = Frame_maxtask; - Tree_ppt = alloc_r(Tree_ppt, sizeof(proc_t*) * hwmsav); + Seed_ppt = q->ppt; // avoid passing WIN_t ptrs + if (!Tree_idx) { // do just once per frame + if (hwmsav < Pids_cnts->total) { // grow, but never shrink + hwmsav = Pids_cnts->total; + Tree_ppt = alloc_r(Tree_ppt, sizeof(void*) * hwmsav); + lvl_arrays = alloc_r(lvl_arrays, sizeof(int) * hwmsav * 2); } + memset(lvl_arrays, 0, sizeof(int) * Pids_cnts->total * 2); + Tree_lvl = lvl_arrays; + Seed_lvl = Tree_lvl + Pids_cnts->total; #ifndef TREE_SCANALL - qsort(Seed_ppt, Frame_maxtask, sizeof(proc_t*), (QFP_t)forest_based); + if (!(procps_pids_stacks_sort(Pids_ctx, Seed_ppt, Pids_cnts->total + , PROCPS_PIDS_TIME_START, PROCPS_SORT_ASCEND))) + error_exit(fmtmk(N_fmt(LIB_errorpid_fmt),__LINE__)); #endif - for (i = 0; i < Frame_maxtask; i++) // avoid any hidepid distortions - if (!Seed_ppt[i]->pad_3) // identify real or pretend trees - forest_adds(i, 1); // add as parent plus its children + for (i = 0; i < Pids_cnts->total; i++) // avoid any hidepid distortions + if (!Seed_lvl[i]) // identify real or pretend trees + forest_adds(i, 1); // add as parent plus its children } - memcpy(Seed_ppt, Tree_ppt, sizeof(proc_t*) * Frame_maxtask); + memcpy(Seed_ppt, Tree_ppt, sizeof(void*) * Pids_cnts->total); } // end: forest_create /* - * This guy adds the artwork to either p->cmd or p->cmdline + * This guy adds the artwork to either a 'cmd' or 'cmdline' * when in forest view mode, otherwise he just returns 'em. */ -static inline const char *forest_display (const WIN_t *q, const proc_t *p) { +static inline const char *forest_display (const WIN_t *q, const int idx) { + // our 'results stack value' extractor macro + #define rSv(E) PID_VAL(E, str, q->ppt[idx]) #ifndef SCROLLVAR_NO - static char buf[1024*64*2]; // the same as readproc's MAX_BUFSZ + static char buf[1024*64*2]; // the same as libray's max buffer size #else static char buf[ROWMINSIZ]; #endif - const char *which = (CHKw(q, Show_CMDLIN)) ? *p->cmdline : p->cmd; + const char *which = (CHKw(q, Show_CMDLIN)) ? rSv(eu_CMDLINE) : rSv(EU_CMD); - if (!CHKw(q, Show_FOREST) || 1 == p->pad_3) return which; - if (p->pad_3 > 100) snprintf(buf, sizeof(buf), "%400s%s", " + ", which); - else snprintf(buf, sizeof(buf), "%*s%s", 4 * (p->pad_3 - 1), " `- ", which); + if (!CHKw(q, Show_FOREST) || Tree_lvl[idx] < 2) return which; + if (Tree_lvl[idx] > 100) snprintf(buf, sizeof(buf), "%400s%s", " + ", which); + else snprintf(buf, sizeof(buf), "%*s%s", 4 * (Tree_lvl[idx] - 1), " `- ", which); return buf; + #undef rSv } // end: forest_display /*###### Main Screen routines ##########################################*/ @@ -5116,8 +4820,8 @@ static void summary_show (void) { if (isROOM(View_STATES, 2)) { show_special(0, fmtmk(N_unq(STATE_line_1_fmt) , Thread_mode ? N_txt(WORD_threads_txt) : N_txt(WORD_process_txt) - , Frame_maxtask, Frame_running, Frame_sleepin - , Frame_stopped, Frame_zombied)); + , Pids_cnts->total, Pids_cnts->running, Pids_cnts->sleeping + , Pids_cnts->stopped, Pids_cnts->zombied)); Msg_row += 1; cpus_refresh(); @@ -5268,15 +4972,15 @@ numa_nope: /* * Build the information for a single task row and * display the results or return them to the caller. */ -static const char *task_show (const WIN_t *q, const proc_t *p) { +static const char *task_show (const WIN_t *q, const int idx) { + // our 'results stack value' extractor macro + #define rSv(E,T) PID_VAL(E, T, q->ppt[idx]) #ifndef SCROLLVAR_NO - #define makeVAR(v) { const char *pv = v; \ - if (!q->varcolbeg) cp = make_str(pv, q->varcolsz, Js, AUTOX_NO); \ - else cp = make_str(q->varcolbeg < (int)strlen(pv) ? pv + q->varcolbeg : "", q->varcolsz, Js, AUTOX_NO); } + #define makeVAR(P) { if (!q->varcolbeg) cp = make_str(P, q->varcolsz, Js, AUTOX_NO); \ + else cp = make_str(q->varcolbeg < (int)strlen(P) ? P + q->varcolbeg : "", q->varcolsz, Js, AUTOX_NO); } #else - #define makeVAR(v) cp = make_str(v, q->varcolsz, Js, AUTOX_NO) + #define makeVAR(P) cp = make_str(P, q->varcolsz, Js, AUTOX_NO) #endif - #define pages2K(n) (unsigned long)( (n) << Pg2K_shft ) static char rbuf[ROWMINSIZ]; char *rp; int x; @@ -5293,187 +4997,145 @@ static const char *task_show (const WIN_t *q, const proc_t *p) { #define Js CHKw(q, Show_JRSTRS) // represent them as #defines #define Jn CHKw(q, Show_JRNUMS) // and only exec code if used + /* except for the XOF/XON pseudo flags, the following case labels are gouped + by result type according to capacity (small -> large) and then ordered by + additional processing requirements (as in plain, scaled, decorated, etc.) */ + switch (i) { #ifndef USE_X_COLHDR // these 2 aren't real procflgs, they're used in column highlighting! - case EU_XON: case EU_XOF: + case EU_XON: cp = NULL; if (!CHKw(q, INFINDS_xxx | NOHIFND_xxx | NOHISEL_xxx)) { /* treat running tasks specially - entire row may get highlighted so we needn't turn it on and we MUST NOT turn it off */ - if (!('R' == p->state && CHKw(q, Show_HIROWS))) + if (!('R' == rSv(EU_STA, s_ch) && CHKw(q, Show_HIROWS))) cp = (EU_XON == i ? q->capclr_rowhigh : q->capclr_rownorm); } break; #endif - case EU_CGR: - makeVAR(p->cgroup[0]); + /* s_ch, make_chr */ + case EU_STA: + cp = make_chr(rSv(EU_STA, s_ch), W, Js); break; - case EU_CMD: - makeVAR(forest_display(q, p)); + /* s_int, make_num without auto width */ + case EU_OOA: + case EU_OOM: + case EU_PGD: + case EU_PID: + case EU_PPD: + case EU_SID: + case EU_TGD: + case EU_THD: + case EU_TPG: + cp = make_num(rSv(i, s_int), W, Jn, AUTOX_NO); break; - case EU_COD: - cp = scale_mem(S, pages2K(p->trs), W, Jn); + /* s_int, make_num or make_str */ + case EU_PRI: + if (-99 > rSv(EU_PRI, s_int) || 999 < rSv(EU_PRI, s_int)) { + cp = make_str("rt", W, Jn, AUTOX_NO); + } else + cp = make_num(rSv(EU_PRI, s_int), W, Jn, AUTOX_NO); break; + /* s_int, scale_mem */ + case EU_RES: + case EU_SWP: + case EU_USE: + cp = scale_mem(S, rSv(i, s_int), W, Jn); + break; + /* s_int, scale_pcnt */ + case EU_MEM: + cp = scale_pcnt((float)rSv(EU_RES, s_int) * 100 / MEM_VAL(mem_TOTAL), W, Jn); + break; + /* u_int, make_num without auto width */ case EU_CPN: - cp = make_num(p->processor, W, Jn, AUTOX_NO); + cp = make_num(rSv(i, u_int), W, Jn, AUTOX_NO); + break; + /* u_int, make_num with auto width */ + case EU_GID: + case EU_UED: + case EU_URD: + case EU_USD: + cp = make_num(rSv(i, u_int), W, Jn, i); break; + /* u_int, scale_pcnt with special handling */ case EU_CPU: - { float u = (float)p->pcpu * Frame_etscale; + { float u = (float)rSv(EU_CPU, u_int) * Frame_etscale; + int n = rSv(EU_THD, s_int); /* process can't use more %cpu than number of threads it has ( thanks Jaromir Capik ) */ - if (u > 100.0 * p->nlwp) u = 100.0 * p->nlwp; + if (u > 100.0 * n) u = 100.0 * n; if (u > Cpu_pmax) u = Cpu_pmax; cp = scale_pcnt(u, W, Jn); } break; - case EU_DAT: - cp = scale_mem(S, pages2K(p->drs), W, Jn); - break; - case EU_DRT: - cp = scale_num(p->dt, W, Jn); + /* sl_int, make_num */ + case EU_NCE: + cp = make_num(rSv(EU_NCE, sl_int), W, Jn, AUTOX_NO); break; - case EU_ENV: - makeVAR(p->environ[0]); + /* ul_int, scale_mem */ + case EU_COD: + case EU_DAT: + case EU_DRT: // really # pgs & sl_int, but always zero since 2.6 + case EU_SHR: + case EU_VRT: + cp = scale_mem(S, rSv(i, ul_int), W, Jn); break; + /* ul_int, scale_num */ case EU_FL1: - cp = scale_num(p->maj_flt, W, Jn); - break; case EU_FL2: - cp = scale_num(p->min_flt, W, Jn); - break; - case EU_FLG: - cp = make_str(hex_make(p->flags, 1), W, Js, AUTOX_NO); - break; case EU_FV1: - cp = scale_num(p->maj_delta, W, Jn); - break; case EU_FV2: - cp = scale_num(p->min_delta, W, Jn); - break; - case EU_GID: - cp = make_num(p->egid, W, Jn, EU_GID); + cp = scale_num(rSv(i, ul_int), W, Jn); break; - case EU_GRP: - cp = make_str(p->egroup, W, Js, EU_GRP); - break; - case EU_LXC: - cp = make_str(p->lxcname, W, Js, EU_LXC); - break; - case EU_MEM: - cp = scale_pcnt((float)p->vm_rss * 100 / MEM_VAL(mem_TOTAL), W, Jn); - break; - case EU_NCE: - cp = make_num(p->nice, W, Jn, AUTOX_NO); + /* ul_int, make_str with special handling */ + case EU_FLG: + cp = make_str(hex_make(rSv(EU_FLG, ul_int), 1), W, Js, AUTOX_NO); break; - case EU_NS1: // IPCNS - case EU_NS2: // MNTNS - case EU_NS3: // NETNS - case EU_NS4: // PIDNS - case EU_NS5: // USERNS - case EU_NS6: // UTSNS - { long ino = p->ns[i - EU_NS1]; + /* ul_int, make_num or make_str */ + case EU_NS1: + case EU_NS2: + case EU_NS3: + case EU_NS4: + case EU_NS5: + case EU_NS6: + { long ino = rSv(i, ul_int); if (ino > 0) cp = make_num(ino, W, Jn, i); else cp = make_str("-", W, Js, i); } break; -#ifdef OOMEM_ENABLE - case EU_OOA: - cp = make_num(p->oom_adj, W, Jn, AUTOX_NO); - break; - case EU_OOM: - cp = make_num(p->oom_score, W, Jn, AUTOX_NO); - break; -#endif - case EU_PGD: - cp = make_num(p->pgrp, W, Jn, AUTOX_NO); - break; - case EU_PID: - cp = make_num(p->tid, W, Jn, AUTOX_NO); - break; - case EU_PPD: - cp = make_num(p->ppid, W, Jn, AUTOX_NO); - break; - case EU_PRI: - if (-99 > p->priority || 999 < p->priority) { - cp = make_str("rt", W, Jn, AUTOX_NO); - } else - cp = make_num(p->priority, W, Jn, AUTOX_NO); - break; - case EU_RES: - cp = scale_mem(S, p->vm_rss, W, Jn); - break; - case EU_SGD: - makeVAR(p->supgid); - break; - case EU_SGN: - makeVAR(p->supgrp); - break; - case EU_SHR: - cp = scale_mem(S, pages2K(p->share), W, Jn); - break; - case EU_SID: - cp = make_num(p->session, W, Jn, AUTOX_NO); - break; - case EU_STA: - cp = make_chr(p->state, W, Js); - break; - case EU_SWP: - cp = scale_mem(S, p->vm_swap, W, Jn); - break; - case EU_TGD: - cp = make_num(p->tgid, W, Jn, AUTOX_NO); - break; - case EU_THD: - cp = make_num(p->nlwp, W, Jn, AUTOX_NO); - break; + /* ull_int, scale_tics */ case EU_TM2: case EU_TME: - { TIC_t t = p->utime + p->stime; - if (CHKw(q, Show_CTIMES)) t += (p->cutime + p->cstime); + { TIC_t t; + if (CHKw(q, Show_CTIMES)) t = rSv(eu_TICS_ALL_C, ull_int); + else t = rSv(i, ull_int); cp = scale_tics(t, W, Jn); } break; - case EU_TPG: - cp = make_num(p->tpgid, W, Jn, AUTOX_NO); - break; - case EU_TTY: - { char tmp[SMLBUFSIZ]; - dev_to_tty(tmp, W, p->tty, p->tid, ABBREV_DEV); - cp = make_str(tmp, W, Js, EU_TTY); - } - break; - case EU_UED: - cp = make_num(p->euid, W, Jn, EU_UED); - break; + /* str, make_str */ + case EU_GRP: + case EU_LXC: case EU_UEN: - cp = make_str(p->euser, W, Js, EU_UEN); - break; - case EU_URD: - cp = make_num(p->ruid, W, Jn, EU_URD); - break; case EU_URN: - cp = make_str(p->ruser, W, Js, EU_URN); - break; - case EU_USD: - cp = make_num(p->suid, W, Jn, EU_USD); - break; - case EU_USE: - cp = scale_mem(S, (p->vm_swap + p->vm_rss), W, Jn); - break; case EU_USN: - cp = make_str(p->suser, W, Js, EU_USN); + case EU_WCH: + cp = make_str(rSv(i, str), W, Js, i); break; - case EU_VRT: - cp = scale_mem(S, pages2K(p->size), W, Jn); + /* str, make_str with varialbe width */ + case EU_CGR: + case EU_ENV: + case EU_SGD: + case EU_SGN: + makeVAR(rSv(i, str)); break; - case EU_WCH: - cp = make_str(lookup_wchan(p->tid), W, Js, EU_WCH); + /* str, make_str with varialbe width + additional decoration */ + case EU_CMD: + makeVAR(forest_display(q, idx)); break; - default: // keep gcc happy + default: // keep gcc happy continue; - } // end: switch 'procflag' if (cp) { @@ -5487,7 +5149,7 @@ static const char *task_show (const WIN_t *q, const proc_t *p) { } // end: for 'maxpflgs' if (!CHKw(q, INFINDS_xxx)) { - const char *cap = ((CHKw(q, Show_HIROWS) && 'R' == p->state)) + const char *cap = ((CHKw(q, Show_HIROWS) && 'R' == rSv(EU_STA, s_ch))) ? q->capclr_rowhigh : q->capclr_rownorm; char *row = rbuf; int ofs; @@ -5511,19 +5173,17 @@ static const char *task_show (const WIN_t *q, const proc_t *p) { PUFF("\n%s%s%s", cap, row, Caps_endline); } return rbuf; + #undef rSv #undef makeVAR - #undef pages2K } // end: task_show - /* - * Squeeze as many tasks as we can into a single window, - * after sorting the passed proc table. */ static int window_show (WIN_t *q, int wmax) { + #define sORDER CHKw(q, Qsrt_NORMAL) ? PROCPS_SORT_DESCEND : PROCPS_SORT_ASCEND /* the isBUSY macro determines if a task is 'active' -- it returns true if some cpu was used since the last sample. ( actual 'running' tasks will be a subset of those selected ) */ - #define isBUSY(x) (0 < x->pcpu) + #define isBUSY(x) (0 < PID_VAL(EU_CPU, u_int, x)) #define winMIN(a,b) ((a < b) ? a : b) int i, lwin; @@ -5533,11 +5193,14 @@ static int window_show (WIN_t *q, int wmax) { if (CHKw(q, Show_FOREST)) forest_create(q); else { - if (CHKw(q, Qsrt_NORMAL)) Frame_srtflg = 1; // this is always needed! - else Frame_srtflg = -1; - Frame_ctimes = CHKw(q, Show_CTIMES); // this & next, only maybe - Frame_cmdlin = CHKw(q, Show_CMDLIN); - qsort(q->ppt, Frame_maxtask, sizeof(proc_t*), Fieldstab[q->rc.sortindx].sort); + enum pids_item item = Fieldstab[q->rc.sortindx].item; + if (item == PROCPS_PIDS_CMD && CHKw(q, Show_CMDLIN)) + item = PROCPS_PIDS_CMDLINE; + else if (item == PROCPS_PIDS_TICS_ALL && CHKw(q, Show_CTIMES)) + item = PROCPS_PIDS_TICS_ALL_C; + if (!(procps_pids_stacks_sort(Pids_ctx, q->ppt + , Pids_cnts->total, item, sORDER))) + error_exit(fmtmk(N_fmt(LIB_errorpid_fmt),__LINE__)); } i = q->begtask; @@ -5547,20 +5210,22 @@ static int window_show (WIN_t *q, int wmax) { /* the least likely scenario is also the most costly, so we'll try to avoid checking some stuff with each iteration and check it just once... */ if (CHKw(q, Show_IDLEPS) && !q->usrseltyp) - while (i < Frame_maxtask && lwin < wmax) { - if (*task_show(q, q->ppt[i++])) + while (i < Pids_cnts->total && lwin < wmax) { + if (*task_show(q, i++)) ++lwin; } else - while (i < Frame_maxtask && lwin < wmax) { + while (i < Pids_cnts->total && lwin < wmax) { if ((CHKw(q, Show_IDLEPS) || isBUSY(q->ppt[i])) - && user_matched(q, q->ppt[i]) - && *task_show(q, q->ppt[i])) + && wins_usrselect(q, q->ppt[i]) + && *task_show(q, i)) ++lwin; ++i; } return lwin; + #undef sORDER + #undef sFIELD #undef winMIN #undef isBUSY } // end: window_show @@ -5634,7 +5299,7 @@ static void frame_make (void) { [ now that this is positioned after the call to summary_show(), ] [ we no longer need or employ tg2(0, Msg_row) since all summary ] [ lines end with a newline, and header lines begin with newline ] */ - if (VIZISw(w) && CHKw(w, View_SCROLL)) PUTT(Scroll_fmts, Frame_maxtask); + if (VIZISw(w) && CHKw(w, View_SCROLL)) PUTT(Scroll_fmts, Pids_cnts->total); else putp(Cap_clr_eol); if (!Rc.mode_altscr) { diff --git a/top/top.h b/top/top.h index c6207ff8..2f144a66 100644 --- a/top/top.h +++ b/top/top.h @@ -20,6 +20,8 @@ #ifndef _Itop #define _Itop +#include +#include #include "../proc/readproc.h" /* Defines represented in configure.ac ----------------------------- */ @@ -31,7 +33,6 @@ //#define SIGNALS_LESS /* favor reduced signal load over response */ /* Development/Debugging defines ----------------------------------- */ -//#define ATEOJ_RPTHSH /* report on hash specifics, at end-of-job */ //#define ATEOJ_RPTSTD /* report on misc stuff, at end-of-job */ //#define CASEUP_HEXES /* show any hex values in upper case */ //#define CASEUP_SUFIX /* show time/mem/cnts suffix in upper case */ @@ -41,7 +42,6 @@ //#define INSP_SAVEBUF /* preserve 'Insp_buf' contents in a file */ //#define INSP_SLIDE_1 /* when scrolling left/right don't move 8 */ //#define MEMGRAPH_OLD /* don't use 'available' when graphing Mem */ -//#define OFF_HST_HASH /* use BOTH qsort+bsrch vs. hashing scheme */ //#define OFF_NUMASKIP /* do NOT skip numa nodes if discontinuous */ //#define OFF_SCROLLBK /* disable tty emulators scrollback buffer */ //#define OFF_STDERROR /* disable our stderr buffering (redirect) */ @@ -223,39 +223,6 @@ typedef long long SIC_t; /* Sort support, callback function signature */ typedef int (*QFP_t)(const void *, const void *); - /* This structure consolidates the information that's used - in a variety of display roles. */ -typedef struct FLD_t { - int width; // field width, if applicable - int scale; // scaled target, if applicable - const int align; // the default column alignment flag - const QFP_t sort; // sort function - const int lflg; // PROC_FILLxxx flag(s) needed by this field -} FLD_t; - -#ifdef OFF_HST_HASH - /* This structure supports 'history' processing and records the - bare minimum of needed information from one frame to the next -- - we don't calc and save data that goes unused like the old top. */ -typedef struct HST_t { - TIC_t tics; // last frame's tics count - unsigned long maj, min; // last frame's maj/min_flt counts - int pid; // record 'key' -} HST_t; -#else - /* This structure supports 'history' processing and records the bare - minimum of needed information from one frame to the next -- we do - not calc and save data that goes unused like the old top nor will - we incur the additional overhead of sort to support binary search - (or worse, a friggin' for loop) when retrievals become necessary! */ -typedef struct HST_t { - TIC_t tics; // last frame's tics count - unsigned long maj, min; // last frame's maj/min_flt counts - int pid; // record 'key' - int lnk; // next on hash chain -} HST_t; -#endif - /* /////////////////////////////////////////////////////////////// */ /* Special Section: multiple windows/field groups --------------- */ /* ( kind of a header within a header: constants, types & macros ) */ @@ -397,7 +364,7 @@ typedef struct WIN_t { char *osel_prt; // other stuff printable as status line char *findstr; // window's current/active search string int findlen; // above's strlen, without call overhead - proc_t **ppt; // this window's proc_t ptr array + struct pids_stack **ppt; // this window's stacks ptr array struct WIN_t *next, // next window in window stack *prev; // prior window in window stack } WIN_t; @@ -606,9 +573,6 @@ typedef struct WIN_t { /*###### For Piece of mind #############################################*/ /* just sanity check(s)... */ -#if defined(ATEOJ_RPTHSH) && defined(OFF_HST_HASH) -# error 'ATEOJ_RPTHSH' conflicts with 'OFF_HST_HASH' -#endif #if defined(RECALL_FIXED) && defined(TERMIOS_ONLY) # error 'RECALL_FIXED' conflicts with 'TERMIOS_ONLY' #endif @@ -633,9 +597,6 @@ typedef struct WIN_t { /* These 'prototypes' are here exclusively for documentation purposes. */ /* ( see the find_string function for the one true required protoype ) */ -/*------ Sort callbacks ------------------------------------------------*/ -/* for each possible field, in the form of: */ -/*atic int sort_EU_XXX (const proc_t **P, const proc_t **Q); */ /*------ Tiny useful routine(s) ----------------------------------------*/ //atic const char *fmtmk (const char *fmts, ...); //atic inline char *scat (char *dst, const char *src); @@ -672,7 +633,6 @@ typedef struct WIN_t { //atic void osel_clear (WIN_t *q); //atic inline int osel_matched (const WIN_t *q, FLG_t enu, const char *str); //atic const char *user_certify (WIN_t *q, const char *str, char typ); -//atic inline int user_matched (const WIN_t *q, const proc_t *p); /*------ Basic Formatting support --------------------------------------*/ //atic inline const char *justify_pad (const char *str, int width, int justr); //atic inline const char *make_chr (const char ch, int width, int justr); @@ -693,13 +653,6 @@ typedef struct WIN_t { //atic void zap_fieldstab (void); /*------ Library Interface ---------------------------------------------*/ //atic void cpus_refresh (void); -#ifdef OFF_HST_HASH -//atic inline HST_t *hstbsrch (HST_t *hst, int max, int pid); -#else -//atic inline HST_t *hstget (int pid); -//atic inline void hstput (unsigned idx); -#endif -//atic void procs_hlp (proc_t *p); //atic void procs_refresh (void); //atic void sysinfo_refresh (int forced); /*------ Inspect Other Output ------------------------------------------*/ @@ -713,7 +666,7 @@ typedef struct WIN_t { //atic void insp_find_str (int ch, int *col, int *row); //atic inline void insp_make_row (int col, int row); //atic void insp_show_pgs (int col, int row, int max); -//atic int insp_view_choice (proc_t *obj); +//atic int insp_view_choice (struct pids_stack *obj); //atic void inspection_utility (int pid); /*------ Startup routines ----------------------------------------------*/ //atic void before (char *me); @@ -731,6 +684,7 @@ typedef struct WIN_t { //atic void wins_reflag (int what, int flg); //atic void wins_stage_1 (void); //atic void wins_stage_2 (void); +//atic inline int wins_usrselect (const WIN_t *q, struct pids_stack *p); /*------ Interactive Input Tertiary support ----------------------------*/ //atic inline int find_ofs (const WIN_t *q, const char *buf); //atic void find_string (int ch); @@ -745,16 +699,13 @@ typedef struct WIN_t { //atic void keys_xtra (int ch); /*------ Forest View support -------------------------------------------*/ //atic void forest_adds (const int self, int level); -#ifndef TREE_SCANALL -//atic int forest_based (const proc_t **x, const proc_t **y); -#endif //atic void forest_create (WIN_t *q); -//atic inline const char *forest_display (const WIN_t *q, const proc_t *p); +//atic inline const char *forest_display (const WIN_t *q, const int idx); /*------ Main Screen routines ------------------------------------------*/ //atic void do_key (int ch); -//atic void summary_hlp (CPU_t *cpu, const char *pfx); +//atic void summary_hlp (struct procps_jiffs_hist *cpu, const char *pfx); //atic void summary_show (void); -//atic const char *task_show (const WIN_t *q, const proc_t *p); +//atic const char *task_show (const WIN_t *q, const int idx); //atic int window_show (WIN_t *q, int wmax); /*------ Entry point plus two ------------------------------------------*/ //atic void frame_hlp (int wix, int max); diff --git a/top/top_nls.c b/top/top_nls.c index 7bd1aa32..6d30e605 100644 --- a/top/top_nls.c +++ b/top/top_nls.c @@ -470,8 +470,9 @@ static void build_norm_nlstab (void) { . padding with extra spaces as necessary */ Norm_nlstab[WORD_abv_mem_txt] = _("Mem "); Norm_nlstab[WORD_abv_swp_txt] = _("Swap"); - Norm_nlstab[LIB_errormem_txt] = _("library failed memory statistics"); - Norm_nlstab[LIB_errorcpu_txt] = _("library failed cpu statistics"); + Norm_nlstab[LIB_errormem_fmt] = _("library failed memory statistics, at %d"); + Norm_nlstab[LIB_errorcpu_fmt] = _("library failed cpu statistics, at %d"); + Norm_nlstab[LIB_errorpid_fmt] = _("library failed pids statistics, at %d"); } diff --git a/top/top_nls.h b/top/top_nls.h index 361ea8ca..dd0a9969 100644 --- a/top/top_nls.h +++ b/top/top_nls.h @@ -73,18 +73,18 @@ enum norm_nls { FAIL_widepid_txt, FIND_no_find_fmt, FIND_no_next_txt, FOREST_modes_fmt, FOREST_views_txt, GET_find_str_txt, GET_max_task_fmt, GET_nice_num_fmt, GET_pid2kill_fmt, GET_pid2nice_fmt, GET_sigs_num_fmt, GET_user_ids_txt, - HELP_cmdline_fmt, IRIX_curmode_fmt, LIB_errorcpu_txt, LIB_errormem_txt, - LIMIT_exceed_fmt, MISSING_args_fmt, NAME_windows_fmt, NOT_onsecure_txt, - NOT_smp_cpus_txt, NUMA_nodebad_txt, NUMA_nodeget_fmt, NUMA_nodenam_fmt, - NUMA_nodenot_txt, OFF_one_word_txt, ON_word_only_txt, OSEL_casenot_txt, - OSEL_caseyes_txt, OSEL_errdelm_fmt, OSEL_errdups_txt, OSEL_errvalu_fmt, - OSEL_prompts_fmt, OSEL_statlin_fmt, RC_bad_entry_fmt, RC_bad_files_fmt, - SCROLL_coord_fmt, SELECT_clash_txt, THREADS_show_fmt, TIME_accumed_fmt, - UNKNOWN_cmds_txt, UNKNOWN_opts_fmt, USAGE_abbrev_txt, WORD_abv_mem_txt, - WORD_abv_swp_txt, WORD_allcpus_txt, WORD_another_txt, WORD_eachcpu_fmt, - WORD_exclude_txt, WORD_include_txt, WORD_noneone_txt, WORD_process_txt, - WORD_threads_txt, WRITE_rcfile_fmt, WRONG_switch_fmt, XTRA_badflds_fmt, - XTRA_fixwide_fmt, XTRA_warncfg_txt, XTRA_winsize_txt, + HELP_cmdline_fmt, IRIX_curmode_fmt, LIB_errorcpu_fmt, LIB_errormem_fmt, + LIB_errorpid_fmt, LIMIT_exceed_fmt, MISSING_args_fmt, NAME_windows_fmt, + NOT_onsecure_txt, NOT_smp_cpus_txt, NUMA_nodebad_txt, NUMA_nodeget_fmt, + NUMA_nodenam_fmt, NUMA_nodenot_txt, OFF_one_word_txt, ON_word_only_txt, + OSEL_casenot_txt, OSEL_caseyes_txt, OSEL_errdelm_fmt, OSEL_errdups_txt, + OSEL_errvalu_fmt, OSEL_prompts_fmt, OSEL_statlin_fmt, RC_bad_entry_fmt, + RC_bad_files_fmt, SCROLL_coord_fmt, SELECT_clash_txt, THREADS_show_fmt, + TIME_accumed_fmt, UNKNOWN_cmds_txt, UNKNOWN_opts_fmt, USAGE_abbrev_txt, + WORD_abv_mem_txt, WORD_abv_swp_txt, WORD_allcpus_txt, WORD_another_txt, + WORD_eachcpu_fmt, WORD_exclude_txt, WORD_include_txt, WORD_noneone_txt, + WORD_process_txt, WORD_threads_txt, WRITE_rcfile_fmt, WRONG_switch_fmt, + XTRA_badflds_fmt, XTRA_fixwide_fmt, XTRA_warncfg_txt, XTRA_winsize_txt, #ifndef INSP_OFFDEMO YINSP_demo01_txt, YINSP_demo02_txt, YINSP_demo03_txt, YINSP_deqfmt_txt, YINSP_deqtyp_txt, YINSP_dstory_txt, -- 2.40.0