Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/procps/top.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/procps/top.c
r1765 r2725 5 5 * This is written specifically for the linux /proc/<PID>/stat(m) 6 6 * files format. 7 7 * 8 8 * This reads the PIDs of all processes and their status and shows 9 9 * the status of processes (first ones that fit to screen) at given … … 17 17 * 18 18 * 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 * 23 26 * Copyright (c) 1992 Branko Lankester 24 27 * Copyright (c) 1992 Roger Binns 25 28 * Copyright (C) 1994-1996 Charles L. Blake. 26 29 * Copyright (C) 1992-1998 Michael K. Johnson 27 * May be distributed under the conditions of the28 * GNU Library General Public License30 * 31 * Licensed under GPLv2, see file LICENSE in this source tree. 29 32 */ 30 33 … … 42 45 char state[4]; 43 46 char comm[COMM_LEN]; 47 #if ENABLE_FEATURE_TOP_SMP_PROCESS 48 int last_seen_on_cpu; 49 #endif 44 50 } top_status_t; 45 51 46 52 typedef 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; 48 56 unsigned long long total; 49 57 unsigned long long busy; … … 54 62 typedef struct save_hist { 55 63 unsigned long ticks; 56 unsignedpid;64 pid_t pid; 57 65 } save_hist; 58 66 59 67 typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q); 60 68 69 61 70 enum { SORT_DEPTH = 3 }; 71 62 72 63 73 struct globals { 64 74 top_status_t *top; 65 75 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 66 83 #if ENABLE_FEATURE_USE_TERMIOS 67 84 struct termios initial_settings; 68 85 #endif 69 86 #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 70 cmp_funcp sort_function ;87 cmp_funcp sort_function[1]; 71 88 #else 72 89 cmp_funcp sort_function[SORT_DEPTH]; 73 90 struct save_hist *prev_hist; 74 91 int prev_hist_count; 75 jiffy_counts_t jif, prev_jif;92 jiffy_counts_t cur_jif, prev_jif; 76 93 /* int hist_iterations; */ 77 94 unsigned total_pcpu; 78 95 /* unsigned long total_vsz; */ 79 96 #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 104 enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; 105 #define G (*(struct globals*)&bb_common_bufsiz1) 106 struct 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]; 80 109 }; 81 #define G (*(struct globals*)&bb_common_bufsiz1)110 #define INIT_G() do { } while (0) 82 111 #define top (G.top ) 83 112 #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 ) 87 117 #define sort_function (G.sort_function ) 88 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE89 118 #define prev_hist (G.prev_hist ) 90 119 #define prev_hist_count (G.prev_hist_count ) 91 #define jif (G.jif)120 #define cur_jif (G.cur_jif ) 92 121 #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 ) 93 125 #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 128 enum { 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) 97 136 98 137 … … 142 181 } 143 182 183 static 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 } 144 207 145 208 static void get_jiffy_counts(void) 146 209 { 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 154 219 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 } 161 260 162 261 static void do_stats(void) … … 170 269 total_pcpu = 0; 171 270 /* total_vsz = 0; */ 172 new_hist = xmalloc(sizeof( struct save_hist)*ntop);271 new_hist = xmalloc(sizeof(new_hist[0]) * ntop); 173 272 /* 174 273 * Make a pass through the data to get stats. … … 211 310 prev_hist_count = ntop; 212 311 } 312 213 313 #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ 214 314 … … 238 338 #endif 239 339 240 /* display generic info (meminfo / loadavg) */ 241 static unsigned long display_generic(int scr_width) 340 #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS 341 static 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 421 static unsigned long display_header(int scr_width, int *lines_rem_p) 242 422 { 243 423 FILE *fp; … … 245 425 char scrbuf[80]; 246 426 unsigned long total, used, mfree, shared, buffers, cached; 247 #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS248 unsigned total_diff;249 #endif250 427 251 428 /* read memory info */ 252 fp = xfopen ("meminfo", "r");429 fp = xfopen_for_read("meminfo"); 253 430 254 431 /* … … 280 457 * 2.6. 281 458 */ 282 283 459 fscanf(fp, "MemFree: %lu %s\n", &mfree, buf); 284 460 … … 298 474 299 475 /* output memory info */ 300 if (scr_width > sizeof(scrbuf))476 if (scr_width > (int)sizeof(scrbuf)) 301 477 scr_width = sizeof(scrbuf); 302 478 snprintf(scrbuf, scr_width, 303 479 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached", 304 480 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 311 487 */ 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); 348 489 349 490 /* read load average as a string */ 350 491 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'; 353 495 snprintf(scrbuf, scr_width, "Load average: %s", buf); 354 496 puts(scrbuf); 497 (*lines_rem_p)--; 355 498 356 499 return total; 357 500 } 358 501 359 /* display process statuses */ 360 static void display_status(int count, int scr_width) 502 static NOINLINE void display_process_list(int lines_rem, int scr_width) 361 503 { 362 504 enum { 363 BITS_PER_INT = sizeof(int) *8505 BITS_PER_INT = sizeof(int) * 8 364 506 }; 365 507 366 top_status_t *s = top;508 top_status_t *s; 367 509 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? */ 369 511 /* xxx_shift and xxx_scale variables allow us to replace 370 512 * expensive divides with multiply and shift */ 371 513 unsigned pmem_shift, pmem_scale, pmem_half; 372 514 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 515 unsigned tmp_unsigned; 373 516 unsigned pcpu_shift, pcpu_scale, pcpu_half; 374 517 unsigned busy_jifs; 518 #endif 375 519 376 520 /* 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" 381 533 #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%%" 400 538 #endif 401 539 /* … … 411 549 pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2); 412 550 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 413 busy_jifs = jif.busy - prev_jif.busy;551 busy_jifs = cur_jif.busy - prev_jif.busy; 414 552 /* This happens if there were lots of short-lived processes 415 553 * between two top updates (e.g. compilation) */ … … 420 558 * (pcpu is delta of sys+user time between samples) 421 559 */ 422 /* ( jif.xxx - prev_jif.xxx) and s->pcpu are560 /* (cur_jif.xxx - prev_jif.xxx) and s->pcpu are 423 561 * in 0..~64000 range (HZ*update_interval). 424 562 * we assume that unsigned is at least 32-bit. 425 563 */ 426 564 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))) { 429 569 pcpu_scale *= 4; 430 570 pcpu_shift += 2; 431 571 } 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; 433 575 /* we want (s->pcpu * pcpu_scale) to never overflow */ 434 576 while (pcpu_scale >= 1024) { … … 440 582 #endif 441 583 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; 445 591 CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); 446 592 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE … … 448 594 #endif 449 595 450 if (s->vsz >= 100 *1024)451 sprintf(vsz_str_buf, "%6ld M", s->vsz/1024);596 if (s->vsz >= 100000) 597 sprintf(vsz_str_buf, "%6ldm", s->vsz/1024); 452 598 else 453 599 sprintf(vsz_str_buf, "%7ld", s->vsz); 454 / / PID PPID USER STAT VSZ %MEM [%CPU] COMMAND455 col -= printf("\n" "%5u%6u %-8.8s %s%s" FMT456 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 457 FMT458 #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) 459 605 " ", 460 606 s->pid, s->ppid, get_cached_username(s->uid), 461 607 s->state, vsz_str_buf, 462 608 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)) 466 611 ); 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); 472 615 /* 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); */ 474 617 s++; 475 618 } 476 619 /* 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(); 479 622 } 480 623 #undef UPSCALE … … 483 626 #undef FMT 484 627 485 486 628 static void clearmems(void) 487 629 { 488 630 clear_username_cache(); 489 631 free(top); 490 top = 0;632 top = NULL; 491 633 ntop = 0; 492 634 } 493 635 494 495 636 #if ENABLE_FEATURE_USE_TERMIOS 496 #include <termios.h>497 #include <signal.h>498 637 499 638 static void reset_term(void) 500 639 { 501 tcsetattr (0, TCSANOW, (void *)&initial_settings);502 #if ENABLE_FEATURE_CLEAN_UP 503 clearmems();504 # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE505 free(prev_hist);506 # endif507 #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 649 static void sig_catcher(int sig UNUSED_PARAM) 511 650 { 512 651 reset_term(); 513 exit(1); 514 } 652 _exit(EXIT_FAILURE); 653 } 654 515 655 #endif /* FEATURE_USE_TERMIOS */ 516 656 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 661 typedef unsigned long mem_t; 662 663 typedef 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 676 enum { NUM_SORT_FIELD = 7 }; 677 678 #define topmem ((topmem_status_t*)top) 679 680 #if ENABLE_FEATURE_TOPMEM 681 682 static 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) */ 701 static 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 766 static 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 773 static 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 811 void display_topmem_process_list(int lines_rem, int scr_width); 812 int topmem_sort(char *a, char *b); 813 #endif /* TOPMEM */ 814 815 /* 816 * end TOPMEM support 817 */ 818 819 enum { 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 836 int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 837 int 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; 525 845 #if ENABLE_FEATURE_USE_TERMIOS 526 846 struct termios new_settings; 527 struct timeval tv; 528 fd_set readfds; 847 struct pollfd pfd[1]; 529 848 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 } 540 885 541 886 /* change to /proc */ … … 543 888 #if ENABLE_FEATURE_USE_TERMIOS 544 889 tcgetattr(0, (void *) &initial_settings); 545 memcpy(&new_settings, &initial_settings, sizeof( struct termios));890 memcpy(&new_settings, &initial_settings, sizeof(new_settings)); 546 891 /* unbuffered input, turn off echo */ 547 892 new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); 548 893 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 554 897 555 898 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE … … 558 901 sort_function[2] = time_sort; 559 902 #else 560 sort_function = mem_sort;561 #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */903 sort_function[0] = mem_sort; 904 #endif 562 905 563 906 while (1) { 564 907 procps_status_t *p = NULL; 565 908 566 /* Default to 25 lines - 5 lines for status */ 567 lines = 24 - 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( - 1); 909 lines = 24; /* default */ 568 910 col = 79; 569 911 #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) { 572 915 sleep(interval); 573 916 continue; 574 917 } 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; 577 921 578 922 /* 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; 595 934 #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; 601 966 } 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 604 982 } 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); 611 986 } 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); 615 1003 #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]) 635 1013 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;) 638 1023 sort_function[0] = mem_sort; 1024 # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE 639 1025 sort_function[1] = pcpu_sort; 640 1026 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;) 647 1039 sort_function[0] = pcpu_sort; 648 1040 sort_function[1] = mem_sort; 649 1041 sort_function[2] = time_sort; 650 1042 } 651 if (c == 'T') { 1043 if (c == 't') { 1044 IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) 652 1045 sort_function[0] = time_sort; 653 1046 sort_function[1] = mem_sort; 654 1047 sort_function[2] = pcpu_sort; 655 1048 } 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 664 1079 } 665 if (!--iterations)666 break;667 #else668 sleep(interval);669 1080 #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 675 1087 return EXIT_SUCCESS; 676 1088 }
Note:
See TracChangeset
for help on using the changeset viewer.