diff --git a/ps/common.h b/ps/common.h index 52524f9a..02100f02 100644 --- a/ps/common.h +++ b/ps/common.h @@ -12,6 +12,7 @@ #ifndef PROCPS_PS_H #define PROCPS_PS_H +#include "../proc/procps.h" #include "../proc/readproc.h" #include /* looks safe for glibc, we need PAGE_SIZE */ @@ -54,23 +55,18 @@ #define SOE 10 /* IBM's S/390 OpenEdition */ /* - * Must not overflow the output buffer: + * Try not to overflow the output buffer: * 32 pages for env+cmd - * 8 kB pages on the Alpha - * 5 chars for "\001 " + * 64 kB pages on IA-64 + * 4 chars for "\377" * plus some slack for other stuff - * That is about 1.3 MB on the Alpha - * - * This isn't good enough for setuid. If anyone cares, mmap() over the - * last page with something unwriteable. + * That is about 8.5 MB on IA-64, or 0.6 MB on i386 */ -/* maximum escape expansion is 6, for " */ -#define ESC_STRETCH 6 +/* maximum escape expansion is 4, for \377 */ +#define ESC_STRETCH 4 /* output buffer size */ #define OUTBUF_SIZE (32*PAGE_SIZE*ESC_STRETCH + 8*PAGE_SIZE) -/* spaces used to right-justify things */ -#define SPACE_AMOUNT (int)(PAGE_SIZE) /******************* PS DEFINE *******************/ @@ -223,15 +219,15 @@ typedef struct sf_node { /*********************** GENERAL GLOBALS *************************/ /* escape.c */ -extern int escape_strlist(char *dst, const char **src, size_t n); -extern int escape_str(char *dst, const char *src, size_t n); -extern int octal_escape_str(char *dst, const char *src, size_t n); -extern int simple_escape_str(char *dst, const char *src, size_t n); +extern int escape_strlist(char *restrict dst, const char *restrict const *restrict src, size_t n); +extern int escape_str(char *restrict dst, const char *restrict src, size_t n); +extern int octal_escape_str(char *restrict dst, const char *restrict src, size_t n); +extern int simple_escape_str(char *restrict dst, const char *restrict src, size_t n); /********************* UNDECIDED GLOBALS **************/ /* output.c */ -extern void show_one_proc(proc_t* p); +extern void show_one_proc(const proc_t *restrict const p); extern void print_format_specifiers(void); extern const aix_struct *search_aix_array(const int findme); extern const shortsort_struct *search_shortsort_array(const int findme); @@ -265,6 +261,7 @@ extern int lines_to_next_header; extern int max_line_width; extern const char *namelist_file; extern int negate_selection; +extern int page_size; // "int" for math reasons? extern unsigned personality; extern int prefer_bsd_defaults; extern int running_only; diff --git a/ps/display.c b/ps/display.c index 7f0fa8c3..3ddd97e4 100644 --- a/ps/display.c +++ b/ps/display.c @@ -48,7 +48,7 @@ static void signal_handler(int signo){ _exit(signo+128); } - +///////////////////////////////////////////////////////////////////////////////////// #undef DEBUG #ifdef DEBUG void init_stack_trace(char *prog_name); @@ -153,6 +153,7 @@ static void arg_show(void){ } #endif +////////////////////////////////////////////////////////////////////////// /***** check the header */ @@ -376,7 +377,7 @@ not_root: /***** sorted or forest */ static void fancy_spew(void){ proc_t *retbuf = NULL; - PROCTAB* ptp; + PROCTAB *restrict ptp; int n = 0; /* number of processes & index into array */ ptp = openproc(needs_for_format | needs_for_sort); if(!ptp) { diff --git a/ps/escape.c b/ps/escape.c index 0c613cc3..85293b2f 100644 --- a/ps/escape.c +++ b/ps/escape.c @@ -9,14 +9,16 @@ * GNU Library General Public License for more details. */ #include +#include "../proc/procps.h" +#include "common.h" /* sanitize a string, without the nice BSD library function: */ /* strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH) */ -int octal_escape_str(char *dst, const char *src, size_t n){ +int octal_escape_str(char *restrict dst, const char *restrict src, size_t n){ unsigned char c; char d; size_t i; - const char *codes = + const char codes[] = "Z------abtnvfr-------------e----" " *******************************" /* better: do not print any space */ "****************************\\***" @@ -57,10 +59,10 @@ leave: } /* sanitize a string via one-way mangle */ -int simple_escape_str(char *dst, const char *src, size_t n){ +int simple_escape_str(char *restrict dst, const char *restrict src, size_t n){ unsigned char c; size_t i; - const char *codes = + const char codes[] = "Z-------------------------------" "********************************" "********************************" @@ -90,16 +92,16 @@ leave: } /* escape a string as desired */ -int escape_str(char *dst, const char *src, size_t n){ +int escape_str(char *restrict dst, const char *restrict src, size_t n){ return simple_escape_str(dst, src, n); } /* escape an argv or environment string array */ -int escape_strlist(char *dst, const char **src, size_t n){ +int escape_strlist(char *restrict dst, const char *restrict const *restrict src, size_t n){ size_t i = 0; while(*src){ i += simple_escape_str(dst+i, *src, n-i); - if((n-i > 1) && (*(src+1))) dst[i++] = ' '; + if((n-i > 1) && src[1]) dst[i++] = ' '; src++; } return i; diff --git a/ps/global.c b/ps/global.c index 0769de2c..c23ec732 100644 --- a/ps/global.c +++ b/ps/global.c @@ -47,7 +47,7 @@ int bsd_c_option = -1; int bsd_e_option = -1; uid_t cached_euid = -1; dev_t cached_tty = -1; -char forest_prefix[4 * 32*1024 + 100]; +char forest_prefix[4 * 32*1024 + 100]; // FIXME int forest_type = -1; unsigned format_flags = 0xffffffff; /* -l -f l u s -j... */ format_node *format_list = (format_node *)0xdeadbeef; /* digested formatting options */ @@ -59,6 +59,7 @@ int lines_to_next_header = -1; const char *namelist_file = (const char *)0xdeadbeef; int negate_selection = -1; int running_only = -1; +int page_size = -1; // "int" for math reasons? unsigned personality = 0xffffffff; int prefer_bsd_defaults = -1; int screen_cols = -1; @@ -335,6 +336,7 @@ void reset_global(void){ lines_to_next_header = 1; namelist_file = NULL; negate_selection = 0; + page_size = getpagesize(); running_only = 0; seconds_since_boot = uptime(0,0); selection_list = NULL; @@ -388,14 +390,14 @@ void self_info(void){ screen_cols, screen_rows ); -/* open_psdb(namelist_file); */ fprintf(stderr, "personality=0x%08x (from \"%s\")\n" - "EUID=%d TTY=%d,%d Hertz=%Ld\n" -/* "namelist_file=\"%s\"\n" */ - , + "EUID=%d TTY=%d,%d Hertz=%Ld PAGE_SIZE=%d page_size=%d\n", personality, saved_personality_text, - cached_euid, (int)major(cached_tty), (int)minor(cached_tty), Hertz /* , - namelist_file?namelist_file:"" */ + cached_euid, (int)major(cached_tty), (int)minor(cached_tty), Hertz, + (int)(PAGE_SIZE), (int)(page_size) ); + + open_psdb(namelist_file); + fprintf(stderr,"namelist_file=\"%s\"\n",namelist_file?namelist_file:""); } diff --git a/ps/output.c b/ps/output.c index d8aaf770..e4e921c8 100644 --- a/ps/output.c +++ b/ps/output.c @@ -80,9 +80,8 @@ #define COLWID 240 /* satisfy snprintf, which is faster than sprintf */ -static char whitespace_and_outbuf[OUTBUF_SIZE + SPACE_AMOUNT + PAGE_SIZE*2]; -static char *outbuf = whitespace_and_outbuf+SPACE_AMOUNT; -static char *whitespace = whitespace_and_outbuf; +static char *outbuf; + static unsigned max_rightward = 0x12345678; /* space for RIGHT stuff */ static unsigned max_leftward = 0x12345678; /* space for LEFT stuff */ @@ -100,7 +99,7 @@ static unsigned max_leftward = 0x12345678; /* space for LEFT stuff */ static int wide_signals; /* true if we have room */ -static proc_t *pp; /* the process being printed */ +static const proc_t *pp; /* the process being printed */ static unsigned long seconds_since_1970; static unsigned long time_of_boot; @@ -1146,7 +1145,7 @@ static int sr_context ( const proc_t* P, const proc_t* Q ) { /* temporary hack -- mark new stuff grabbed from Debian ps */ #define LNx LNX -/* there are about 195 listed */ +/* there are about 211 listed */ /* Many of these are placeholders for unsupported options. */ static const format_struct format_array[] = { @@ -1605,7 +1604,7 @@ static void check_header_width(void){ /********** show one process (NULL proc prints header) **********/ -void show_one_proc(proc_t* p){ +void show_one_proc(const proc_t *restrict const p){ /* unknown: maybe set correct & actual to 1, remove +/- 1 below */ int correct = 0; /* screen position we should be at */ int actual = 0; /* screen position we are at */ @@ -1614,7 +1613,7 @@ void show_one_proc(proc_t* p){ int space = 0; /* amount of space we actually need to print */ int dospace = 0; /* previous column determined that we need a space */ int legit = 0; /* legitimately stolen extra space */ - format_node *fmt = format_list; + const format_node *restrict fmt = format_list; static int did_stuff = 0; /* have we ever printed anything? */ if(-1==(long)p){ /* true only once, at the end */ @@ -1724,7 +1723,7 @@ void show_one_proc(proc_t* p){ */ space = correct - actual + leftpad; if(space<1) space=dospace; - if(space>SPACE_AMOUNT) space=SPACE_AMOUNT; + if(space>page_size) space=page_size; // only have so much available /* print data, set x position stuff */ amount = strlen(outbuf); /* post-chop data width */ @@ -1759,6 +1758,7 @@ void show_one_proc(proc_t* p){ } } + #ifdef TESTING static void sanity_check(void){ format_struct *fs = format_array; @@ -1769,19 +1769,11 @@ static void sanity_check(void){ } #endif + void init_output(void){ - memset(whitespace, ' ', PAGE_SIZE); -#if 0 - mprotect(whitespace, PAGE_SIZE, PROT_READ); /* FIXME may fail if unaligned */ - mprotect( - (void *)((unsigned long)(whitespace_and_outbuf-PAGE_SIZE) &~ (PAGE_SIZE-1)), - PAGE_SIZE, PROT_NONE - ); -#endif - seconds_since_1970 = time(NULL); - time_of_boot = seconds_since_1970 - seconds_since_boot; - meminfo(); - switch(getpagesize()){ + int outbuf_pages; + + switch(page_size){ case 65536: page_shift = 16; break; case 32768: page_shift = 15; break; case 16384: page_shift = 14; break; @@ -1791,5 +1783,28 @@ void init_output(void){ case 2048: page_shift = 11; break; case 1024: page_shift = 10; break; } + + outbuf_pages = OUTBUF_SIZE/page_size+1; // round up + outbuf = mmap( + 0, + page_size * (1+1+outbuf_pages+1), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, + 0 + ); + mprotect(outbuf, page_size, PROT_NONE); // gaurd page + outbuf += page_size; + memset(outbuf, ' ', page_size); + mprotect(outbuf, page_size, PROT_READ); // space page + outbuf += page_size; + // now outbuf points where we want it + mprotect(outbuf + page_size * outbuf_pages, page_size, PROT_NONE); // gaurd page + + seconds_since_1970 = time(NULL); + time_of_boot = seconds_since_1970 - seconds_since_boot; + + meminfo(); + check_header_width(); } diff --git a/top.c b/top.c index 87d35a7b..5c76718d 100644 --- a/top.c +++ b/top.c @@ -116,14 +116,15 @@ static char Cap_clr_eol [CAPBUFSIZ] = "", Caps_off [CAPBUFSIZ] = ""; static int Cap_can_goto = 0; - /* Some optimization stuff... - The Pseudo_ guys are managed by reframewins and utilized in a macro. + /* Some optimization stuff reducing output demands... + The Pseudo_ guys are managed by wins_resize and frame_make. They + are exploited in a macro and represent 90% of our optimization. The Stdout_buf is transparent to our code and regardless of whose buffer is used, stdout is flushed at frame end or if interactive. */ static char *Pseudo_scrn; static int Pseudo_row, Pseudo_cols, Pseudo_size; #ifndef STDOUT_IOLBF - // much less than typical xterm but, with luck, mostly newlines anyway + // less than stdout's normal buffer but with luck mostly '\n' anyway static char Stdout_buf[2048]; #endif @@ -139,7 +140,7 @@ static WIN_t *Winstk [GROUPSMAX], /* Frame oriented stuff that can't remain local to any 1 function and/or that would be too cumbersome managed as parms, - and/or that are simply more efficient handle as globals */ + and/or that are simply more efficiently handled as globals */ static int Frame_libflgs; // current PROC_FIILxxx flags (0 = need new) static unsigned Frame_maxtask; // last known number of active tasks // ie. current 'size' of proc table @@ -148,7 +149,7 @@ static unsigned Frame_running, // state categories for this frame Frame_stopped, Frame_zombied; static float Frame_tscale; // so we can '*' vs. '/' WHEN 'pcpu' -static int Frame_srtflg, // the subject window sort direction +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 /* ////////////////////////////////////////////////////////////// */ @@ -780,7 +781,7 @@ static const char *scale_tics (TICS_t tics, const int width) * Handle our own memory stuff without the risk of leaving the * user's terminal in an ugly state should things go sour. */ -static void *alloc_c (unsigned numb) +static void *alloc_c (unsigned numb) MALLOC { void * p; @@ -791,7 +792,7 @@ static void *alloc_c (unsigned numb) } -static void *alloc_r (void *q, unsigned numb) +static void *alloc_r (void *q, unsigned numb) MALLOC { void *p; @@ -808,7 +809,7 @@ static void *alloc_r (void *q, unsigned numb) * as follows: * cpus[0] thru cpus[n] == tics for each separate cpu * cpus[Cpu_tot] == tics from the 1st /proc/stat line */ -static CPUS_t *cpus_refresh (CPUS_t *cpus) +static CPUS_t *cpus_refresh (CPUS_t *restrict cpus) { static FILE *fp = NULL; int i; @@ -955,7 +956,7 @@ static proc_t **procs_refresh (proc_t **table, int flags) #define ENTsz sizeof(proc_t) static unsigned savmax = 0; // first time, Bypass: (i) proc_t *ptsk = (proc_t *)-1; // first time, Force: (ii) - unsigned curmax = 0; // every time (jeeze) + unsigned curmax = 0; // every time (jeeze) PROCTAB* PT; prochlp(NULL); // prep for a new frame @@ -1272,13 +1273,13 @@ static void whack_terminal (void) NOT reflect the true field type found in proc_t -- this plus a cast when/if displayed provides minimal width protection. */ static FTAB_t Fieldstab[] = { -// .lflg anomolies: -// P_UID, L_NONE - natural outgrowth of 'stat()' in readproc (euid) -// P_CPU, L_stat - never filled by libproc, but requires times (pcpu) -// P_CMD, L_stat - may yet require L_CMDLINE in reframewins (cmd/cmdline) -// L_EITHER - must L_status, else 64-bit math, __udivdi3 on 32-bit ! -// head fmts width scale sort desc lflg -// ----------- ------- ------ ----- -------- ---------------------- -------- +/* .lflg anomolies: + P_UID, L_NONE - natural outgrowth of 'stat()' in readproc (euid) + P_CPU, L_stat - never filled by libproc, but requires times (pcpu) + P_CMD, L_stat - may yet require L_CMDLINE in reframewins (cmd/cmdline) + L_EITHER - must L_status, else 64-bit math, __udivdi3 on 32-bit ! + head fmts width scale sort desc lflg + ----------- ------- ------ ----- -------- ---------------------- -------- */ { " PID ", "%5u ", -1, -1, _SF(P_PID), "Process Id", L_EITHER }, { " PPID ", "%5u ", -1, -1, _SF(P_PPD), "Parent Process Pid", L_EITHER }, { " PGID ", "%5u ", -1, -1, _SF(P_PGD), "Process Group Id", L_stat }, @@ -1471,13 +1472,6 @@ static void reframewins (void) const char *h; int i, needpsdb = 0; - // should already be allocated and likely hasn't changed... - Pseudo_cols = Screen_cols + CLRBUFSIZ + 1; - if (Batch) Pseudo_size = ROWBUFSIZ + 1; - else Pseudo_size = Pseudo_cols * Screen_rows; - Pseudo_scrn = alloc_r(Pseudo_scrn, Pseudo_size); - memset(Pseudo_scrn, '\0', Pseudo_size); - // Frame_libflgs = 0; // should be called only when it's zero w = Curwin; do { @@ -1741,6 +1735,17 @@ static void wins_resize (int dont_care_sig) // we might disappoint some folks (but they'll deserve it) if (SCREENMAX < Screen_cols) Screen_cols = SCREENMAX; + + /* keep our support for output optimization in sync with current reality + note: when we're in Batch mode, we don't really need a Pseudo_scrn and + when not Batch, our buffer will contain 1 extra 'line' since + Msg_row is never represented -- but it's nice to have some space + between us and the great-beyond... */ + Pseudo_cols = Screen_cols + CLRBUFSIZ + 1; + if (Batch) Pseudo_size = ROWBUFSIZ + 1; + else Pseudo_size = Pseudo_cols * Screen_rows; + Pseudo_scrn = alloc_r(Pseudo_scrn, Pseudo_size); + // force rebuild of column headers AND libproc/readproc requirements Frame_libflgs = 0; } @@ -2163,11 +2168,11 @@ static void do_key (unsigned c) * 2) modest smp boxes with room for each cpu's percentages * 3) massive smp guys leaving little or no room for process * display and thus requiring the cpu summary toggle */ -static void summaryhlp (CPUS_t *restrict cpu, const char *restrict pfx) +static void summaryhlp (const CPUS_t *restrict cpu, const char *restrict const pfx) { /* we'll trim to zero if we get negative time ticks, which has happened with some SMP kernels (pre-2.4?) */ -#define TRIMz(x) ((tz = (STIC_t)x) < 0 ? 0 : tz) +#define TRIMz(x) ((tz = (STIC_t)(x)) < 0 ? 0 : tz) STIC_t u_frme, s_frme, n_frme, i_frme, w_frme, tot_frme, tz; float scale; @@ -2279,7 +2284,7 @@ static proc_t **summary_show (void) /* * Display information for a single task row. */ -static void task_show (WIN_t *q, proc_t *p) +static void task_show (const WIN_t *restrict q, const proc_t *restrict p) { /* the following macro is our means to 'inline' emitting a column -- next to procs_refresh, that's the most frequent and costly part of top's job ! */ @@ -2303,10 +2308,10 @@ static void task_show (WIN_t *q, proc_t *p) for (x = 0; x < q->maxpflgs; x++) { char cbuf[ROWBUFSIZ], _z[ROWBUFSIZ]; - PFLG_t i = q->procflags[x]; // support for our field/column - const char *f = Fieldstab[i].fmts; // macro AND sometimes the fmt - unsigned s = Fieldstab[i].scale; // string must be altered ! - unsigned w = Fieldstab[i].width; + PFLG_t i = q->procflags[x]; // support for our field/column + const char *restrict const f = Fieldstab[i].fmts; // macro AND sometimes the fmt + unsigned s = Fieldstab[i].scale; // string must be altered ! + unsigned w = Fieldstab[i].width; switch (i) { case P_CMD: @@ -2519,8 +2524,7 @@ static void window_show (proc_t **ppt, WIN_t *q, int *lscr) * remaining amount of screen real estate under multiple windows */ static void framehlp (int wix, int max) { - int i; - int rsvd, size, wins; + int i, rsvd, size, wins; // calc remaining number of visible windows + total 'user' lines for (i = wix, rsvd = 0, wins = 0; i < GROUPSMAX; i++) { @@ -2575,7 +2579,10 @@ static void frame_make (void) /* note: except for PROC_PID, all libproc flags are managed by reframewins(), who also builds each window's column headers */ - if (!Frame_libflgs) reframewins(); + if (!Frame_libflgs) { + reframewins(); + memset(Pseudo_scrn, '\0', Pseudo_size); + } Pseudo_row = Msg_row = scrlins = 0; ppt = summary_show(); Max_lines = (Screen_rows - Msg_row) - 1; diff --git a/top.h b/top.h index e2262c7d..97ffbdba 100644 --- a/top.h +++ b/top.h @@ -128,14 +128,14 @@ } while (0) #define PUFF(fmt,arg...) do { \ char _str[ROWBUFSIZ]; \ - register char *_ptr = &Pseudo_scrn[Pseudo_row * Pseudo_cols]; \ - register int _len = snprintf(_str, sizeof(_str), fmt, ## arg); \ - if (Batch) fputs(_str, stdout); \ + char *_ptr = &Pseudo_scrn[Pseudo_row * Pseudo_cols]; \ + int _len = 1 + snprintf(_str, sizeof(_str), fmt, ## arg); \ + if (Batch) putp(_str); \ else { \ if (!memcmp(_ptr, _str, _len)) \ - putchar('\n'); \ + putp("\n"); \ else { \ - memcpy(_ptr, _str, ++_len); \ + memcpy(_ptr, _str, _len); \ putp(_ptr); \ } } Pseudo_row++; \ } while (0) @@ -523,11 +523,11 @@ typedef struct win { /* for each possible field, in the form of: */ /*atic int sort_P_XXX (const proc_t **P, const proc_t **Q); */ /* additional specialized sort callback(s) */ -static int sort_HIST_t (const HIST_t *P, const HIST_t *Q); +//atic int sort_HIST_t (const HIST_t *P, const HIST_t *Q); /*------ Tiny useful routine(s) ----------------------------------------*/ //atic int chin (int ech, char *buf, unsigned cnt); //atic const char *fmtmk (const char *fmts, ...); -//atic inline char *scat (register char *dst, register const char *src); +//atic inline char *scat (char *dst, const char *src); //atic char *strim (int sp, char *str); //atic const char *tg2 (int x, int y); /*------ Exit/Interrput routines ---------------------------------------*/ @@ -551,7 +551,7 @@ static int sort_HIST_t (const HIST_t *P, const HIST_t *Q); //atic void *alloc_c (unsigned numb); //atic void *alloc_r (void *q, unsigned numb); //atic CPUS_t *cpus_refresh (CPUS_t *cpus); -//atic void prochlp (register proc_t *this); +//atic void prochlp (proc_t *this); //atic proc_t **procs_refresh (proc_t **table, int flags); /*------ Startup routines ----------------------------------------------*/ //atic void before (char *me);