Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/procps/top.c


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/procps/top.c

    r1765 r2725  
    55 * This is written specifically for the linux /proc/<PID>/stat(m)
    66 * files format.
    7 
     7 *
    88 * This reads the PIDs of all processes and their status and shows
    99 * the status of processes (first ones that fit to screen) at given
     
    1717 *
    1818 * Rewritten by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru>
    19  */
    20 
    21 /* Original code Copyrights */
    22 /*
     19 *
     20 * Sept 2008: Vineet Gupta <vineet.gupta@arc.com>
     21 * Added Support for reporting SMP Information
     22 * - CPU where Process was last seen running
     23 *   (to see effect of sched_setaffinity() etc)
     24 * - CPU Time Split (idle/IO/wait etc) PER CPU
     25 *
    2326 * Copyright (c) 1992 Branko Lankester
    2427 * Copyright (c) 1992 Roger Binns
    2528 * Copyright (C) 1994-1996 Charles L. Blake.
    2629 * Copyright (C) 1992-1998 Michael K. Johnson
    27  * May be distributed under the conditions of the
    28  * GNU Library General Public License
     30 *
     31 * Licensed under GPLv2, see file LICENSE in this source tree.
    2932 */
    3033
     
    4245    char state[4];
    4346    char comm[COMM_LEN];
     47#if ENABLE_FEATURE_TOP_SMP_PROCESS
     48    int last_seen_on_cpu;
     49#endif
    4450} top_status_t;
    4551
    4652typedef struct jiffy_counts_t {
    47     unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal;
     53    /* Linux 2.4.x has only first four */
     54    unsigned long long usr, nic, sys, idle;
     55    unsigned long long iowait, irq, softirq, steal;
    4856    unsigned long long total;
    4957    unsigned long long busy;
     
    5462typedef struct save_hist {
    5563    unsigned long ticks;
    56     unsigned pid;
     64    pid_t pid;
    5765} save_hist;
    5866
    5967typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q);
    6068
     69
    6170enum { SORT_DEPTH = 3 };
     71
    6272
    6373struct globals {
    6474    top_status_t *top;
    6575    int ntop;
     76#if ENABLE_FEATURE_TOPMEM
     77    smallint sort_field;
     78    smallint inverted;
     79#endif
     80#if ENABLE_FEATURE_TOP_SMP_CPU
     81    smallint smp_cpu_info; /* one/many cpu info lines? */
     82#endif
    6683#if ENABLE_FEATURE_USE_TERMIOS
    6784    struct termios initial_settings;
    6885#endif
    6986#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    70     cmp_funcp sort_function;
     87    cmp_funcp sort_function[1];
    7188#else
    7289    cmp_funcp sort_function[SORT_DEPTH];
    7390    struct save_hist *prev_hist;
    7491    int prev_hist_count;
    75     jiffy_counts_t jif, prev_jif;
     92    jiffy_counts_t cur_jif, prev_jif;
    7693    /* int hist_iterations; */
    7794    unsigned total_pcpu;
    7895    /* unsigned long total_vsz; */
    7996#endif
     97#if ENABLE_FEATURE_TOP_SMP_CPU
     98    /* Per CPU samples: current and last */
     99    jiffy_counts_t *cpu_jif, *cpu_prev_jif;
     100    int num_cpus;
     101#endif
     102    char line_buf[80];
     103}; //FIX_ALIASING; - large code growth
     104enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) };
     105#define G (*(struct globals*)&bb_common_bufsiz1)
     106struct BUG_bad_size {
     107    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
     108    char BUG_line_buf_too_small[LINE_BUF_SIZE > 80 ? 1 : -1];
    80109};
    81 #define G (*(struct globals*)&bb_common_bufsiz1)
     110#define INIT_G() do { } while (0)
    82111#define top              (G.top               )
    83112#define ntop             (G.ntop              )
    84 #if ENABLE_FEATURE_USE_TERMIOS
    85 #define initial_settings (G. initial_settings )
    86 #endif
     113#define sort_field       (G.sort_field        )
     114#define inverted         (G.inverted          )
     115#define smp_cpu_info     (G.smp_cpu_info      )
     116#define initial_settings (G.initial_settings  )
    87117#define sort_function    (G.sort_function     )
    88 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    89118#define prev_hist        (G.prev_hist         )
    90119#define prev_hist_count  (G.prev_hist_count   )
    91 #define jif              (G.jif               )
     120#define cur_jif          (G.cur_jif           )
    92121#define prev_jif         (G.prev_jif          )
     122#define cpu_jif          (G.cpu_jif           )
     123#define cpu_prev_jif     (G.cpu_prev_jif      )
     124#define num_cpus         (G.num_cpus          )
    93125#define total_pcpu       (G.total_pcpu        )
    94 #endif
    95 
    96 #define OPT_BATCH_MODE (option_mask32 & 0x4)
     126#define line_buf         (G.line_buf          )
     127
     128enum {
     129    OPT_d = (1 << 0),
     130    OPT_n = (1 << 1),
     131    OPT_b = (1 << 2),
     132    OPT_m = (1 << 3),
     133    OPT_EOF = (1 << 4), /* pseudo: "we saw EOF in stdin" */
     134};
     135#define OPT_BATCH_MODE (option_mask32 & OPT_b)
    97136
    98137
     
    142181}
    143182
     183static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif)
     184{
     185#if !ENABLE_FEATURE_TOP_SMP_CPU
     186    static const char fmt[] = "cpu %llu %llu %llu %llu %llu %llu %llu %llu";
     187#else
     188    static const char fmt[] = "cp%*s %llu %llu %llu %llu %llu %llu %llu %llu";
     189#endif
     190    int ret;
     191
     192    if (!fgets(line_buf, LINE_BUF_SIZE, fp) || line_buf[0] != 'c' /* not "cpu" */)
     193        return 0;
     194    ret = sscanf(line_buf, fmt,
     195            &p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle,
     196            &p_jif->iowait, &p_jif->irq, &p_jif->softirq,
     197            &p_jif->steal);
     198    if (ret >= 4) {
     199        p_jif->total = p_jif->usr + p_jif->nic + p_jif->sys + p_jif->idle
     200            + p_jif->iowait + p_jif->irq + p_jif->softirq + p_jif->steal;
     201        /* procps 2.x does not count iowait as busy time */
     202        p_jif->busy = p_jif->total - p_jif->idle - p_jif->iowait;
     203    }
     204
     205    return ret;
     206}
    144207
    145208static void get_jiffy_counts(void)
    146209{
    147     FILE* fp = xfopen("stat", "r");
    148     prev_jif = jif;
    149     if (fscanf(fp, "cpu  %lld %lld %lld %lld %lld %lld %lld %lld",
    150             &jif.usr,&jif.nic,&jif.sys,&jif.idle,
    151             &jif.iowait,&jif.irq,&jif.softirq,&jif.steal) < 4) {
    152         bb_error_msg_and_die("failed to read /proc/stat");
    153     }
     210    FILE* fp = xfopen_for_read("stat");
     211
     212    /* We need to parse cumulative counts even if SMP CPU display is on,
     213     * they are used to calculate per process CPU% */
     214    prev_jif = cur_jif;
     215    if (read_cpu_jiffy(fp, &cur_jif) < 4)
     216        bb_error_msg_and_die("can't read /proc/stat");
     217
     218#if !ENABLE_FEATURE_TOP_SMP_CPU
    154219    fclose(fp);
    155     jif.total = jif.usr + jif.nic + jif.sys + jif.idle
    156             + jif.iowait + jif.irq + jif.softirq + jif.steal;
    157     /* procps 2.x does not count iowait as busy time */
    158     jif.busy = jif.total - jif.idle - jif.iowait;
    159 }
    160 
     220    return;
     221#else
     222    if (!smp_cpu_info) {
     223        fclose(fp);
     224        return;
     225    }
     226
     227    if (!num_cpus) {
     228        /* First time here. How many CPUs?
     229         * There will be at least 1 /proc/stat line with cpu%d
     230         */
     231        while (1) {
     232            cpu_jif = xrealloc_vector(cpu_jif, 1, num_cpus);
     233            if (read_cpu_jiffy(fp, &cpu_jif[num_cpus]) <= 4)
     234                break;
     235            num_cpus++;
     236        }
     237        if (num_cpus == 0) /* /proc/stat with only "cpu ..." line?! */
     238            smp_cpu_info = 0;
     239
     240        cpu_prev_jif = xzalloc(sizeof(cpu_prev_jif[0]) * num_cpus);
     241
     242        /* Otherwise the first per cpu display shows all 100% idles */
     243        usleep(50000);
     244    } else { /* Non first time invocation */
     245        jiffy_counts_t *tmp;
     246        int i;
     247
     248        /* First switch the sample pointers: no need to copy */
     249        tmp = cpu_prev_jif;
     250        cpu_prev_jif = cpu_jif;
     251        cpu_jif = tmp;
     252
     253        /* Get the new samples */
     254        for (i = 0; i < num_cpus; i++)
     255            read_cpu_jiffy(fp, &cpu_jif[i]);
     256    }
     257#endif
     258    fclose(fp);
     259}
    161260
    162261static void do_stats(void)
     
    170269    total_pcpu = 0;
    171270    /* total_vsz = 0; */
    172     new_hist = xmalloc(sizeof(struct save_hist)*ntop);
     271    new_hist = xmalloc(sizeof(new_hist[0]) * ntop);
    173272    /*
    174273     * Make a pass through the data to get stats.
     
    211310    prev_hist_count = ntop;
    212311}
     312
    213313#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
    214314
     
    238338#endif
    239339
    240 /* display generic info (meminfo / loadavg) */
    241 static unsigned long display_generic(int scr_width)
     340#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
     341static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p)
     342{
     343    /*
     344     * xxx% = (cur_jif.xxx - prev_jif.xxx) / (cur_jif.total - prev_jif.total) * 100%
     345     */
     346    unsigned total_diff;
     347    jiffy_counts_t *p_jif, *p_prev_jif;
     348    int i;
     349# if ENABLE_FEATURE_TOP_SMP_CPU
     350    int n_cpu_lines;
     351# endif
     352
     353    /* using (unsigned) casts to make operations cheaper */
     354# define  CALC_TOTAL_DIFF do { \
     355    total_diff = (unsigned)(p_jif->total - p_prev_jif->total); \
     356    if (total_diff == 0) total_diff = 1; \
     357} while (0)
     358
     359# if ENABLE_FEATURE_TOP_DECIMALS
     360#  define CALC_STAT(xxx) char xxx[8]
     361#  define SHOW_STAT(xxx) fmt_100percent_8(xxx, (unsigned)(p_jif->xxx - p_prev_jif->xxx), total_diff)
     362#  define FMT "%s"
     363# else
     364#  define CALC_STAT(xxx) unsigned xxx = 100 * (unsigned)(p_jif->xxx - p_prev_jif->xxx) / total_diff
     365#  define SHOW_STAT(xxx) xxx
     366#  define FMT "%4u%% "
     367# endif
     368
     369# if !ENABLE_FEATURE_TOP_SMP_CPU
     370    {
     371        i = 1;
     372        p_jif = &cur_jif;
     373        p_prev_jif = &prev_jif;
     374# else
     375    /* Loop thru CPU(s) */
     376    n_cpu_lines = smp_cpu_info ? num_cpus : 1;
     377    if (n_cpu_lines > *lines_rem_p)
     378        n_cpu_lines = *lines_rem_p;
     379
     380    for (i = 0; i < n_cpu_lines; i++) {
     381        p_jif = &cpu_jif[i];
     382        p_prev_jif = &cpu_prev_jif[i];
     383# endif
     384        CALC_TOTAL_DIFF;
     385
     386        { /* Need a block: CALC_STAT are declarations */
     387            CALC_STAT(usr);
     388            CALC_STAT(sys);
     389            CALC_STAT(nic);
     390            CALC_STAT(idle);
     391            CALC_STAT(iowait);
     392            CALC_STAT(irq);
     393            CALC_STAT(softirq);
     394            /*CALC_STAT(steal);*/
     395
     396            snprintf(scrbuf, scr_width,
     397                /* Barely fits in 79 chars when in "decimals" mode. */
     398# if ENABLE_FEATURE_TOP_SMP_CPU
     399                "CPU%s:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq",
     400                (smp_cpu_info ? utoa(i) : ""),
     401# else
     402                "CPU:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq",
     403# endif
     404                SHOW_STAT(usr), SHOW_STAT(sys), SHOW_STAT(nic), SHOW_STAT(idle),
     405                SHOW_STAT(iowait), SHOW_STAT(irq), SHOW_STAT(softirq)
     406                /*, SHOW_STAT(steal) - what is this 'steal' thing? */
     407                /* I doubt anyone wants to know it */
     408            );
     409            puts(scrbuf);
     410        }
     411    }
     412# undef SHOW_STAT
     413# undef CALC_STAT
     414# undef FMT
     415    *lines_rem_p -= i;
     416}
     417#else  /* !ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS */
     418# define display_cpus(scr_width, scrbuf, lines_rem) ((void)0)
     419#endif
     420
     421static unsigned long display_header(int scr_width, int *lines_rem_p)
    242422{
    243423    FILE *fp;
     
    245425    char scrbuf[80];
    246426    unsigned long total, used, mfree, shared, buffers, cached;
    247 #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
    248     unsigned total_diff;
    249 #endif
    250427
    251428    /* read memory info */
    252     fp = xfopen("meminfo", "r");
     429    fp = xfopen_for_read("meminfo");
    253430
    254431    /*
     
    280457         * 2.6.
    281458         */
    282 
    283459        fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
    284460
     
    298474
    299475    /* output memory info */
    300     if (scr_width > sizeof(scrbuf))
     476    if (scr_width > (int)sizeof(scrbuf))
    301477        scr_width = sizeof(scrbuf);
    302478    snprintf(scrbuf, scr_width,
    303479        "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
    304480        used, mfree, shared, buffers, cached);
    305     /* clear screen & go to top */
    306     printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf);
    307 
    308 #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
    309     /*
    310      * xxx% = (jif.xxx - prev_jif.xxx) / (jif.total - prev_jif.total) * 100%
     481    /* go to top & clear to the end of screen */
     482    printf(OPT_BATCH_MODE ? "%s\n" : "\033[H\033[J%s\n", scrbuf);
     483    (*lines_rem_p)--;
     484
     485    /* Display CPU time split as percentage of total time
     486     * This displays either a cumulative line or one line per CPU
    311487     */
    312     /* using (unsigned) casts to make operations cheaper */
    313     total_diff = ((unsigned)(jif.total - prev_jif.total) ? : 1);
    314 #if ENABLE_FEATURE_TOP_DECIMALS
    315 /* Generated code is approx +0.3k */
    316 #define CALC_STAT(xxx) char xxx[8]
    317 #define SHOW_STAT(xxx) fmt_100percent_8(xxx, (unsigned)(jif.xxx - prev_jif.xxx), total_diff)
    318 #define FMT "%s"
    319 #else
    320 #define CALC_STAT(xxx) unsigned xxx = 100 * (unsigned)(jif.xxx - prev_jif.xxx) / total_diff
    321 #define SHOW_STAT(xxx) xxx
    322 #define FMT "%4u%% "
    323 #endif
    324     { /* need block: CALC_STAT are declarations */
    325         CALC_STAT(usr);
    326         CALC_STAT(sys);
    327         CALC_STAT(nic);
    328         CALC_STAT(idle);
    329         CALC_STAT(iowait);
    330         CALC_STAT(irq);
    331         CALC_STAT(softirq);
    332         //CALC_STAT(steal);
    333 
    334         snprintf(scrbuf, scr_width,
    335             /* Barely fits in 79 chars when in "decimals" mode. */
    336             "CPU:"FMT"usr"FMT"sys"FMT"nice"FMT"idle"FMT"io"FMT"irq"FMT"softirq",
    337             SHOW_STAT(usr), SHOW_STAT(sys), SHOW_STAT(nic), SHOW_STAT(idle),
    338             SHOW_STAT(iowait), SHOW_STAT(irq), SHOW_STAT(softirq)
    339             //, SHOW_STAT(steal) - what is this 'steal' thing?
    340             // I doubt anyone wants to know it
    341         );
    342     }
    343     puts(scrbuf);
    344 #undef SHOW_STAT
    345 #undef CALC_STAT
    346 #undef FMT
    347 #endif
     488    display_cpus(scr_width, scrbuf, lines_rem_p);
    348489
    349490    /* read load average as a string */
    350491    buf[0] = '\0';
    351     open_read_close("loadavg", buf, sizeof("N.NN N.NN N.NN")-1);
    352     buf[sizeof("N.NN N.NN N.NN")-1] = '\0';
     492    open_read_close("loadavg", buf, sizeof(buf) - 1);
     493    buf[sizeof(buf) - 1] = '\n';
     494    *strchr(buf, '\n') = '\0';
    353495    snprintf(scrbuf, scr_width, "Load average: %s", buf);
    354496    puts(scrbuf);
     497    (*lines_rem_p)--;
    355498
    356499    return total;
    357500}
    358501
    359 /* display process statuses */
    360 static void display_status(int count, int scr_width)
     502static NOINLINE void display_process_list(int lines_rem, int scr_width)
    361503{
    362504    enum {
    363         BITS_PER_INT = sizeof(int)*8
     505        BITS_PER_INT = sizeof(int) * 8
    364506    };
    365507
    366     top_status_t *s = top;
     508    top_status_t *s;
    367509    char vsz_str_buf[8];
    368     unsigned long total_memory = display_generic(scr_width); /* or use total_vsz? */
     510    unsigned long total_memory = display_header(scr_width, &lines_rem); /* or use total_vsz? */
    369511    /* xxx_shift and xxx_scale variables allow us to replace
    370512     * expensive divides with multiply and shift */
    371513    unsigned pmem_shift, pmem_scale, pmem_half;
    372514#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     515    unsigned tmp_unsigned;
    373516    unsigned pcpu_shift, pcpu_scale, pcpu_half;
    374517    unsigned busy_jifs;
     518#endif
    375519
    376520    /* what info of the processes is shown */
    377     printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
    378         "  PID  PPID USER     STAT   VSZ %MEM %CPU COMMAND");
    379 #define MIN_WIDTH \
    380     sizeof( "  PID  PPID USER     STAT   VSZ %MEM %CPU C")
     521    printf(OPT_BATCH_MODE ? "%.*s" : "\033[7m%.*s\033[0m", scr_width,
     522        "  PID  PPID USER     STAT   VSZ %MEM"
     523        IF_FEATURE_TOP_SMP_PROCESS(" CPU")
     524        IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU")
     525        " COMMAND");
     526    lines_rem--;
     527
     528#if ENABLE_FEATURE_TOP_DECIMALS
     529# define UPSCALE 1000
     530# define CALC_STAT(name, val) div_t name = div((val), 10)
     531# define SHOW_STAT(name) name.quot, '0'+name.rem
     532# define FMT "%3u.%c"
    381533#else
    382 
    383     /* !CPU_USAGE_PERCENTAGE */
    384     printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
    385         "  PID  PPID USER     STAT   VSZ %MEM COMMAND");
    386 #define MIN_WIDTH \
    387     sizeof( "  PID  PPID USER     STAT   VSZ %MEM C")
    388 #endif
    389 
    390 #if ENABLE_FEATURE_TOP_DECIMALS
    391 #define UPSCALE 1000
    392 #define CALC_STAT(name, val) div_t name = div((val), 10)
    393 #define SHOW_STAT(name) name.quot, '0'+name.rem
    394 #define FMT "%3u.%c"
    395 #else
    396 #define UPSCALE 100
    397 #define CALC_STAT(name, val) unsigned name = (val)
    398 #define SHOW_STAT(name) name
    399 #define FMT "%4u%%"
     534# define UPSCALE 100
     535# define CALC_STAT(name, val) unsigned name = (val)
     536# define SHOW_STAT(name) name
     537# define FMT "%4u%%"
    400538#endif
    401539    /*
     
    411549    pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2);
    412550#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    413     busy_jifs = jif.busy - prev_jif.busy;
     551    busy_jifs = cur_jif.busy - prev_jif.busy;
    414552    /* This happens if there were lots of short-lived processes
    415553     * between two top updates (e.g. compilation) */
     
    420558     * (pcpu is delta of sys+user time between samples)
    421559     */
    422     /* (jif.xxx - prev_jif.xxx) and s->pcpu are
     560    /* (cur_jif.xxx - prev_jif.xxx) and s->pcpu are
    423561     * in 0..~64000 range (HZ*update_interval).
    424562     * we assume that unsigned is at least 32-bit.
    425563     */
    426564    pcpu_shift = 6;
    427     pcpu_scale = (UPSCALE*64*(uint16_t)busy_jifs ? : 1);
    428     while (pcpu_scale < (1U<<(BITS_PER_INT-2))) {
     565    pcpu_scale = UPSCALE*64 * (uint16_t)busy_jifs;
     566    if (pcpu_scale == 0)
     567        pcpu_scale = 1;
     568    while (pcpu_scale < (1U << (BITS_PER_INT-2))) {
    429569        pcpu_scale *= 4;
    430570        pcpu_shift += 2;
    431571    }
    432     pcpu_scale /= ( (uint16_t)(jif.total-prev_jif.total)*total_pcpu ? : 1);
     572    tmp_unsigned = (uint16_t)(cur_jif.total - prev_jif.total) * total_pcpu;
     573    if (tmp_unsigned != 0)
     574        pcpu_scale /= tmp_unsigned;
    433575    /* we want (s->pcpu * pcpu_scale) to never overflow */
    434576    while (pcpu_scale >= 1024) {
     
    440582#endif
    441583
    442     /* Ok, all prelim data is ready, go thru the list */
    443     while (count-- > 0) {
    444         int col = scr_width;
     584    /* Ok, all preliminary data is ready, go through the list */
     585    scr_width += 2; /* account for leading '\n' and trailing NUL */
     586    if (lines_rem > ntop)
     587        lines_rem = ntop;
     588    s = top;
     589    while (--lines_rem >= 0) {
     590        unsigned col;
    445591        CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift);
    446592#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     
    448594#endif
    449595
    450         if (s->vsz >= 100*1024)
    451             sprintf(vsz_str_buf, "%6ldM", s->vsz/1024);
     596        if (s->vsz >= 100000)
     597            sprintf(vsz_str_buf, "%6ldm", s->vsz/1024);
    452598        else
    453599            sprintf(vsz_str_buf, "%7ld", s->vsz);
    454         // PID PPID USER STAT VSZ %MEM [%CPU] COMMAND
    455         col -= printf("\n" "%5u%6u %-8.8s %s%s" FMT
    456 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    457                 FMT
    458 #endif
     600        /* PID PPID USER STAT VSZ %MEM [%CPU] COMMAND */
     601        col = snprintf(line_buf, scr_width,
     602                "\n" "%5u%6u %-8.8s %s%s" FMT
     603                IF_FEATURE_TOP_SMP_PROCESS(" %3d")
     604                IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(FMT)
    459605                " ",
    460606                s->pid, s->ppid, get_cached_username(s->uid),
    461607                s->state, vsz_str_buf,
    462608                SHOW_STAT(pmem)
    463 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    464                 , SHOW_STAT(pcpu)
    465 #endif
     609                IF_FEATURE_TOP_SMP_PROCESS(, s->last_seen_on_cpu)
     610                IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(, SHOW_STAT(pcpu))
    466611        );
    467         if (col > 0) {
    468             char buf[col + 1];
    469             read_cmdline(buf, col, s->pid, s->comm);
    470             fputs(buf, stdout);
    471         }
     612        if ((int)(col + 1) < scr_width)
     613            read_cmdline(line_buf + col, scr_width - col, s->pid, s->comm);
     614        fputs(line_buf, stdout);
    472615        /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
    473             jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
     616            cur_jif.busy - prev_jif.busy, cur_jif.total - prev_jif.total); */
    474617        s++;
    475618    }
    476619    /* printf(" %d", hist_iterations); */
    477     putchar(OPT_BATCH_MODE ? '\n' : '\r');
    478     fflush(stdout);
     620    bb_putchar(OPT_BATCH_MODE ? '\n' : '\r');
     621    fflush_all();
    479622}
    480623#undef UPSCALE
     
    483626#undef FMT
    484627
    485 
    486628static void clearmems(void)
    487629{
    488630    clear_username_cache();
    489631    free(top);
    490     top = 0;
     632    top = NULL;
    491633    ntop = 0;
    492634}
    493635
    494 
    495636#if ENABLE_FEATURE_USE_TERMIOS
    496 #include <termios.h>
    497 #include <signal.h>
    498637
    499638static void reset_term(void)
    500639{
    501     tcsetattr(0, TCSANOW, (void *) &initial_settings);
    502 #if ENABLE_FEATURE_CLEAN_UP
    503     clearmems();
    504 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    505     free(prev_hist);
    506 #endif
    507 #endif /* FEATURE_CLEAN_UP */
    508 }
    509 
    510 static void sig_catcher(int sig ATTRIBUTE_UNUSED)
     640    tcsetattr_stdin_TCSANOW(&initial_settings);
     641    if (ENABLE_FEATURE_CLEAN_UP) {
     642        clearmems();
     643# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     644        free(prev_hist);
     645# endif
     646    }
     647}
     648
     649static void sig_catcher(int sig UNUSED_PARAM)
    511650{
    512651    reset_term();
    513     exit(1);
    514 }
     652    _exit(EXIT_FAILURE);
     653}
     654
    515655#endif /* FEATURE_USE_TERMIOS */
    516656
    517 
    518 int top_main(int argc, char **argv);
    519 int top_main(int argc, char **argv)
    520 {
    521     int count, lines, col;
    522     unsigned interval = 5; /* default update rate is 5 seconds */
    523     unsigned iterations = UINT_MAX; /* 2^32 iterations by default :) */
    524     char *sinterval, *siterations;
     657/*
     658 * TOPMEM support
     659 */
     660
     661typedef unsigned long mem_t;
     662
     663typedef struct topmem_status_t {
     664    unsigned pid;
     665    char comm[COMM_LEN];
     666    /* vsz doesn't count /dev/xxx mappings except /dev/zero */
     667    mem_t vsz     ;
     668    mem_t vszrw   ;
     669    mem_t rss     ;
     670    mem_t rss_sh  ;
     671    mem_t dirty   ;
     672    mem_t dirty_sh;
     673    mem_t stack   ;
     674} topmem_status_t;
     675
     676enum { NUM_SORT_FIELD = 7 };
     677
     678#define topmem ((topmem_status_t*)top)
     679
     680#if ENABLE_FEATURE_TOPMEM
     681
     682static int topmem_sort(char *a, char *b)
     683{
     684    int n;
     685    mem_t l, r;
     686
     687    n = offsetof(topmem_status_t, vsz) + (sort_field * sizeof(mem_t));
     688    l = *(mem_t*)(a + n);
     689    r = *(mem_t*)(b + n);
     690    if (l == r) {
     691        l = ((topmem_status_t*)a)->dirty;
     692        r = ((topmem_status_t*)b)->dirty;
     693    }
     694    /* We want to avoid unsigned->signed and truncation errors */
     695    /* l>r: -1, l=r: 0, l<r: 1 */
     696    n = (l > r) ? -1 : (l != r);
     697    return inverted ? -n : n;
     698}
     699
     700/* display header info (meminfo / loadavg) */
     701static void display_topmem_header(int scr_width, int *lines_rem_p)
     702{
     703    enum {
     704        TOTAL = 0, MFREE, BUF, CACHE,
     705        SWAPTOTAL, SWAPFREE, DIRTY,
     706        MWRITE, ANON, MAP, SLAB,
     707        NUM_FIELDS
     708    };
     709    static const char match[NUM_FIELDS][12] = {
     710        "\x09" "MemTotal:",  // TOTAL
     711        "\x08" "MemFree:",   // MFREE
     712        "\x08" "Buffers:",   // BUF
     713        "\x07" "Cached:",    // CACHE
     714        "\x0a" "SwapTotal:", // SWAPTOTAL
     715        "\x09" "SwapFree:",  // SWAPFREE
     716        "\x06" "Dirty:",     // DIRTY
     717        "\x0a" "Writeback:", // MWRITE
     718        "\x0a" "AnonPages:", // ANON
     719        "\x07" "Mapped:",    // MAP
     720        "\x05" "Slab:",      // SLAB
     721    };
     722    char meminfo_buf[4 * 1024];
     723    const char *Z[NUM_FIELDS];
     724    unsigned i;
     725    int sz;
     726
     727    for (i = 0; i < NUM_FIELDS; i++)
     728        Z[i] = "?";
     729
     730    /* read memory info */
     731    sz = open_read_close("meminfo", meminfo_buf, sizeof(meminfo_buf) - 1);
     732    if (sz >= 0) {
     733        char *p = meminfo_buf;
     734        meminfo_buf[sz] = '\0';
     735        /* Note that fields always appear in the match[] order */
     736        for (i = 0; i < NUM_FIELDS; i++) {
     737            char *found = strstr(p, match[i] + 1);
     738            if (found) {
     739                /* Cut "NNNN" out of "    NNNN kb" */
     740                char *s = skip_whitespace(found + match[i][0]);
     741                p = skip_non_whitespace(s);
     742                *p++ = '\0';
     743                Z[i] = s;
     744            }
     745        }
     746    }
     747
     748    snprintf(line_buf, LINE_BUF_SIZE,
     749        "Mem total:%s anon:%s map:%s free:%s",
     750        Z[TOTAL], Z[ANON], Z[MAP], Z[MFREE]);
     751    printf(OPT_BATCH_MODE ? "%.*s\n" : "\033[H\033[J%.*s\n", scr_width, line_buf);
     752
     753    snprintf(line_buf, LINE_BUF_SIZE,
     754        " slab:%s buf:%s cache:%s dirty:%s write:%s",
     755        Z[SLAB], Z[BUF], Z[CACHE], Z[DIRTY], Z[MWRITE]);
     756    printf("%.*s\n", scr_width, line_buf);
     757
     758    snprintf(line_buf, LINE_BUF_SIZE,
     759        "Swap total:%s free:%s", // TODO: % used?
     760        Z[SWAPTOTAL], Z[SWAPFREE]);
     761    printf("%.*s\n", scr_width, line_buf);
     762
     763    (*lines_rem_p) -= 3;
     764}
     765
     766static void ulltoa6_and_space(unsigned long long ul, char buf[6])
     767{
     768    /* see http://en.wikipedia.org/wiki/Tera */
     769    smart_ulltoa5(ul, buf, " mgtpezy");
     770    buf[5] = ' ';
     771}
     772
     773static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width)
     774{
     775#define HDR_STR "  PID   VSZ VSZRW   RSS (SHR) DIRTY (SHR) STACK"
     776#define MIN_WIDTH sizeof(HDR_STR)
     777    const topmem_status_t *s = topmem;
     778
     779    display_topmem_header(scr_width, &lines_rem);
     780    strcpy(line_buf, HDR_STR " COMMAND");
     781    line_buf[5 + sort_field * 6] = '*';
     782    printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf);
     783    lines_rem--;
     784
     785    if (lines_rem > ntop)
     786        lines_rem = ntop;
     787    while (--lines_rem >= 0) {
     788        /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */
     789        ulltoa6_and_space(s->pid     , &line_buf[0*6]);
     790        ulltoa6_and_space(s->vsz     , &line_buf[1*6]);
     791        ulltoa6_and_space(s->vszrw   , &line_buf[2*6]);
     792        ulltoa6_and_space(s->rss     , &line_buf[3*6]);
     793        ulltoa6_and_space(s->rss_sh  , &line_buf[4*6]);
     794        ulltoa6_and_space(s->dirty   , &line_buf[5*6]);
     795        ulltoa6_and_space(s->dirty_sh, &line_buf[6*6]);
     796        ulltoa6_and_space(s->stack   , &line_buf[7*6]);
     797        line_buf[8*6] = '\0';
     798        if (scr_width > (int)MIN_WIDTH) {
     799            read_cmdline(&line_buf[8*6], scr_width - MIN_WIDTH, s->pid, s->comm);
     800        }
     801        printf("\n""%.*s", scr_width, line_buf);
     802        s++;
     803    }
     804    bb_putchar(OPT_BATCH_MODE ? '\n' : '\r');
     805    fflush_all();
     806#undef HDR_STR
     807#undef MIN_WIDTH
     808}
     809
     810#else
     811void display_topmem_process_list(int lines_rem, int scr_width);
     812int topmem_sort(char *a, char *b);
     813#endif /* TOPMEM */
     814
     815/*
     816 * end TOPMEM support
     817 */
     818
     819enum {
     820    TOP_MASK = 0
     821        | PSSCAN_PID
     822        | PSSCAN_PPID
     823        | PSSCAN_VSZ
     824        | PSSCAN_STIME
     825        | PSSCAN_UTIME
     826        | PSSCAN_STATE
     827        | PSSCAN_COMM
     828        | PSSCAN_CPU
     829        | PSSCAN_UIDGID,
     830    TOPMEM_MASK = 0
     831        | PSSCAN_PID
     832        | PSSCAN_SMAPS
     833        | PSSCAN_COMM,
     834};
     835
     836int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     837int top_main(int argc UNUSED_PARAM, char **argv)
     838{
     839    int iterations;
     840    unsigned lines, col;
     841    int lines_rem;
     842    unsigned interval;
     843    char *str_interval, *str_iterations;
     844    unsigned scan_mask = TOP_MASK;
    525845#if ENABLE_FEATURE_USE_TERMIOS
    526846    struct termios new_settings;
    527     struct timeval tv;
    528     fd_set readfds;
     847    struct pollfd pfd[1];
    529848    unsigned char c;
    530 #endif /* FEATURE_USE_TERMIOS */
    531 
    532     interval = 5;
    533 
    534     /* do normal option parsing */
    535     opt_complementary = "-";
    536     getopt32(argv, "d:n:b", &sinterval, &siterations);
    537     if (option_mask32 & 0x1) interval = xatou(sinterval); // -d
    538     if (option_mask32 & 0x2) iterations = xatou(siterations); // -n
    539     //if (option_mask32 & 0x4) // -b
     849
     850    pfd[0].fd = 0;
     851    pfd[0].events = POLLIN;
     852#endif
     853
     854    INIT_G();
     855
     856    interval = 5; /* default update interval is 5 seconds */
     857    iterations = 0; /* infinite */
     858#if ENABLE_FEATURE_TOP_SMP_CPU
     859    /*num_cpus = 0;*/
     860    /*smp_cpu_info = 0;*/  /* to start with show aggregate */
     861    cpu_jif = &cur_jif;
     862    cpu_prev_jif = &prev_jif;
     863#endif
     864
     865    /* all args are options; -n NUM */
     866    opt_complementary = "-"; /* options can be specified w/o dash */
     867    col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations);
     868#if ENABLE_FEATURE_TOPMEM
     869    if (col & OPT_m) /* -m (busybox specific) */
     870        scan_mask = TOPMEM_MASK;
     871#endif
     872    if (col & OPT_d) {
     873        /* work around for "-d 1" -> "-d -1" done by getopt32
     874         * (opt_complementary == "-" does this) */
     875        if (str_interval[0] == '-')
     876            str_interval++;
     877        /* Need to limit it to not overflow poll timeout */
     878        interval = xatou16(str_interval);
     879    }
     880    if (col & OPT_n) {
     881        if (str_iterations[0] == '-')
     882            str_iterations++;
     883        iterations = xatou(str_iterations);
     884    }
    540885
    541886    /* change to /proc */
     
    543888#if ENABLE_FEATURE_USE_TERMIOS
    544889    tcgetattr(0, (void *) &initial_settings);
    545     memcpy(&new_settings, &initial_settings, sizeof(struct termios));
     890    memcpy(&new_settings, &initial_settings, sizeof(new_settings));
    546891    /* unbuffered input, turn off echo */
    547892    new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
    548893
    549     signal(SIGTERM, sig_catcher);
    550     signal(SIGINT, sig_catcher);
    551     tcsetattr(0, TCSANOW, (void *) &new_settings);
    552     atexit(reset_term);
    553 #endif /* FEATURE_USE_TERMIOS */
     894    bb_signals(BB_FATAL_SIGS, sig_catcher);
     895    tcsetattr_stdin_TCSANOW(&new_settings);
     896#endif
    554897
    555898#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     
    558901    sort_function[2] = time_sort;
    559902#else
    560     sort_function = mem_sort;
    561 #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
     903    sort_function[0] = mem_sort;
     904#endif
    562905
    563906    while (1) {
    564907        procps_status_t *p = NULL;
    565908
    566         /* Default to 25 lines - 5 lines for status */
    567         lines = 24 - 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( - 1);
     909        lines = 24; /* default */
    568910        col = 79;
    569911#if ENABLE_FEATURE_USE_TERMIOS
    570         get_terminal_width_height(0, &col, &lines);
    571         if (lines < 5 || col < MIN_WIDTH) {
     912        /* We output to stdout, we need size of stdout (not stdin)! */
     913        get_terminal_width_height(STDOUT_FILENO, &col, &lines);
     914        if (lines < 5 || col < 10) {
    572915            sleep(interval);
    573916            continue;
    574917        }
    575         lines -= 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( + 1);
    576 #endif /* FEATURE_USE_TERMIOS */
     918#endif
     919        if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */
     920            col = LINE_BUF_SIZE-2;
    577921
    578922        /* read process IDs & status for all the processes */
    579         while ((p = procps_scan(p, 0
    580                 | PSSCAN_PID
    581                 | PSSCAN_PPID
    582                 | PSSCAN_VSZ
    583                 | PSSCAN_STIME
    584                 | PSSCAN_UTIME
    585                 | PSSCAN_STATE
    586                 | PSSCAN_COMM
    587                 | PSSCAN_SID
    588                 | PSSCAN_UIDGID
    589         ))) {
    590             int n = ntop;
    591             top = xrealloc(top, (++ntop) * sizeof(*top));
    592             top[n].pid = p->pid;
    593             top[n].ppid = p->ppid;
    594             top[n].vsz = p->vsz;
     923        while ((p = procps_scan(p, scan_mask)) != NULL) {
     924            int n;
     925#if ENABLE_FEATURE_TOPMEM
     926            if (scan_mask != TOPMEM_MASK)
     927#endif
     928            {
     929                n = ntop;
     930                top = xrealloc_vector(top, 6, ntop++);
     931                top[n].pid = p->pid;
     932                top[n].ppid = p->ppid;
     933                top[n].vsz = p->vsz;
    595934#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    596             top[n].ticks = p->stime + p->utime;
    597 #endif
    598             top[n].uid = p->uid;
    599             strcpy(top[n].state, p->state);
    600             strcpy(top[n].comm, p->comm);
     935                top[n].ticks = p->stime + p->utime;
     936#endif
     937                top[n].uid = p->uid;
     938                strcpy(top[n].state, p->state);
     939                strcpy(top[n].comm, p->comm);
     940#if ENABLE_FEATURE_TOP_SMP_PROCESS
     941                top[n].last_seen_on_cpu = p->last_seen_on_cpu;
     942#endif
     943            }
     944#if ENABLE_FEATURE_TOPMEM
     945            else { /* TOPMEM */
     946                if (!(p->smaps.mapped_ro | p->smaps.mapped_rw))
     947                    continue; /* kernel threads are ignored */
     948                n = ntop;
     949                /* No bug here - top and topmem are the same */
     950                top = xrealloc_vector(topmem, 6, ntop++);
     951                strcpy(topmem[n].comm, p->comm);
     952                topmem[n].pid      = p->pid;
     953                topmem[n].vsz      = p->smaps.mapped_rw + p->smaps.mapped_ro;
     954                topmem[n].vszrw    = p->smaps.mapped_rw;
     955                topmem[n].rss_sh   = p->smaps.shared_clean + p->smaps.shared_dirty;
     956                topmem[n].rss      = p->smaps.private_clean + p->smaps.private_dirty + topmem[n].rss_sh;
     957                topmem[n].dirty    = p->smaps.private_dirty + p->smaps.shared_dirty;
     958                topmem[n].dirty_sh = p->smaps.shared_dirty;
     959                topmem[n].stack    = p->smaps.stack;
     960            }
     961#endif
     962        } /* end of "while we read /proc" */
     963        if (ntop == 0) {
     964            bb_error_msg("no process info in /proc");
     965            break;
    601966        }
    602         if (ntop == 0) {
    603             bb_error_msg_and_die("no process info in /proc");
     967
     968        if (scan_mask != TOPMEM_MASK) {
     969#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     970            if (!prev_hist_count) {
     971                do_stats();
     972                usleep(100000);
     973                clearmems();
     974                continue;
     975            }
     976            do_stats();
     977            /* TODO: we don't need to sort all 10000 processes, we need to find top 24! */
     978            qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
     979#else
     980            qsort(top, ntop, sizeof(top_status_t), (void*)(sort_function[0]));
     981#endif
    604982        }
    605 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    606         if (!prev_hist_count) {
    607             do_stats();
    608             sleep(1);
    609             clearmems();
    610             continue;
     983#if ENABLE_FEATURE_TOPMEM
     984        else { /* TOPMEM */
     985            qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort);
    611986        }
    612         do_stats();
    613 /* TODO: we don't need to sort all 10000 processes, we need to find top 24! */
    614         qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
     987#endif
     988        lines_rem = lines;
     989        if (OPT_BATCH_MODE) {
     990            lines_rem = INT_MAX;
     991        }
     992        if (scan_mask != TOPMEM_MASK)
     993            display_process_list(lines_rem, col);
     994#if ENABLE_FEATURE_TOPMEM
     995        else
     996            display_topmem_process_list(lines_rem, col);
     997#endif
     998        clearmems();
     999        if (iterations >= 0 && !--iterations)
     1000            break;
     1001#if !ENABLE_FEATURE_USE_TERMIOS
     1002        sleep(interval);
    6151003#else
    616         qsort(top, ntop, sizeof(top_status_t), (void*)sort_function);
    617 #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
    618         count = lines;
    619         if (OPT_BATCH_MODE || count > ntop) {
    620             count = ntop;
    621         }
    622         /* show status for each of the processes */
    623         display_status(count, col);
    624 #if ENABLE_FEATURE_USE_TERMIOS
    625         tv.tv_sec = interval;
    626         tv.tv_usec = 0;
    627         FD_ZERO(&readfds);
    628         FD_SET(0, &readfds);
    629         select(1, &readfds, NULL, NULL, &tv);
    630         if (FD_ISSET(0, &readfds)) {
    631             if (read(0, &c, 1) <= 0) {   /* signal */
    632                 return EXIT_FAILURE;
    633             }
    634             if (c == 'q' || c == initial_settings.c_cc[VINTR])
     1004        if (option_mask32 & (OPT_b|OPT_EOF))
     1005             /* batch mode, or EOF on stdin ("top </dev/null") */
     1006            sleep(interval);
     1007        else if (safe_poll(pfd, 1, interval * 1000) > 0) {
     1008            if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */
     1009                option_mask32 |= OPT_EOF;
     1010                continue;
     1011            }
     1012            if (c == initial_settings.c_cc[VINTR])
    6351013                break;
    636             if (c == 'M') {
    637 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     1014            c |= 0x20; /* lowercase */
     1015            if (c == 'q')
     1016                break;
     1017            if (c == 'n') {
     1018                IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
     1019                sort_function[0] = pid_sort;
     1020            }
     1021            if (c == 'm') {
     1022                IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
    6381023                sort_function[0] = mem_sort;
     1024# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    6391025                sort_function[1] = pcpu_sort;
    6401026                sort_function[2] = time_sort;
    641 #else
    642                 sort_function = mem_sort;
    643 #endif
    644             }
    645 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    646             if (c == 'P') {
     1027# endif
     1028            }
     1029# if ENABLE_FEATURE_SHOW_THREADS
     1030            if (c == 'h'
     1031             IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK)
     1032            ) {
     1033                scan_mask ^= PSSCAN_TASKS;
     1034            }
     1035# endif
     1036# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     1037            if (c == 'p') {
     1038                IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
    6471039                sort_function[0] = pcpu_sort;
    6481040                sort_function[1] = mem_sort;
    6491041                sort_function[2] = time_sort;
    6501042            }
    651             if (c == 'T') {
     1043            if (c == 't') {
     1044                IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
    6521045                sort_function[0] = time_sort;
    6531046                sort_function[1] = mem_sort;
    6541047                sort_function[2] = pcpu_sort;
    6551048            }
    656 #endif
    657             if (c == 'N') {
    658 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    659                 sort_function[0] = pid_sort;
    660 #else
    661                 sort_function = pid_sort;
    662 #endif
    663             }
     1049#  if ENABLE_FEATURE_TOPMEM
     1050            if (c == 's') {
     1051                scan_mask = TOPMEM_MASK;
     1052                free(prev_hist);
     1053                prev_hist = NULL;
     1054                prev_hist_count = 0;
     1055                sort_field = (sort_field + 1) % NUM_SORT_FIELD;
     1056            }
     1057            if (c == 'r')
     1058                inverted ^= 1;
     1059#  endif
     1060#  if ENABLE_FEATURE_TOP_SMP_CPU
     1061            /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */
     1062            if (c == 'c' || c == '1') {
     1063                /* User wants to toggle per cpu <> aggregate */
     1064                if (smp_cpu_info) {
     1065                    free(cpu_prev_jif);
     1066                    free(cpu_jif);
     1067                    cpu_jif = &cur_jif;
     1068                    cpu_prev_jif = &prev_jif;
     1069                } else {
     1070                    /* Prepare for xrealloc() */
     1071                    cpu_jif = cpu_prev_jif = NULL;
     1072                }
     1073                num_cpus = 0;
     1074                smp_cpu_info = !smp_cpu_info;
     1075                get_jiffy_counts();
     1076            }
     1077#  endif
     1078# endif
    6641079        }
    665         if (!--iterations)
    666             break;
    667 #else
    668         sleep(interval);
    6691080#endif /* FEATURE_USE_TERMIOS */
    670         clearmems();
    671     }
    672     if (ENABLE_FEATURE_CLEAN_UP)
    673         clearmems();
    674     putchar('\n');
     1081    } /* end of "while (1)" */
     1082
     1083    bb_putchar('\n');
     1084#if ENABLE_FEATURE_USE_TERMIOS
     1085    reset_term();
     1086#endif
    6751087    return EXIT_SUCCESS;
    6761088}
Note: See TracChangeset for help on using the changeset viewer.