source: mainline/uspace/app/top/top.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 18.4 KB
Line 
1/*
2 * Copyright (c) 2010 Stanislav Kozina
3 * Copyright (c) 2010 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup top
31 * @brief Top utility.
32 * @{
33 */
34/**
35 * @file
36 */
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <task.h>
41#include <thread.h>
42#include <sys/time.h>
43#include <errno.h>
44#include <gsort.h>
45#include <str.h>
46#include "screen.h"
47#include "top.h"
48
49#define NAME "top"
50
51#define UPDATE_INTERVAL 1
52
53#define DAY 86400
54#define HOUR 3600
55#define MINUTE 60
56
57typedef enum {
58 OP_TASKS,
59 OP_IPC,
60 OP_EXCS,
61} op_mode_t;
62
63static const column_t task_columns[] = {
64 {"taskid", 't', 8},
65 {"thrds", 'h', 7},
66 {"resident", 'r', 10},
67 {"%resi", 'R', 7},
68 {"virtual", 'v', 9},
69 {"%virt", 'V', 7},
70 {"%user", 'U', 7},
71 {"%kern", 'K', 7},
72 {"name", 'd', 0},
73};
74
75enum {
76 TASK_COL_ID = 0,
77 TASK_COL_NUM_THREADS,
78 TASK_COL_RESIDENT,
79 TASK_COL_PERCENT_RESIDENT,
80 TASK_COL_VIRTUAL,
81 TASK_COL_PERCENT_VIRTUAL,
82 TASK_COL_PERCENT_USER,
83 TASK_COL_PERCENT_KERNEL,
84 TASK_COL_NAME,
85 TASK_NUM_COLUMNS,
86};
87
88static const column_t ipc_columns[] = {
89 {"taskid", 't', 8},
90 {"cls snt", 'c', 9},
91 {"cls rcv", 'C', 9},
92 {"ans snt", 'a', 9},
93 {"ans rcv", 'A', 9},
94 {"forward", 'f', 9},
95 {"name", 'd', 0},
96};
97
98enum {
99 IPC_COL_TASKID = 0,
100 IPC_COL_CLS_SNT,
101 IPC_COL_CLS_RCV,
102 IPC_COL_ANS_SNT,
103 IPC_COL_ANS_RCV,
104 IPC_COL_FORWARD,
105 IPC_COL_NAME,
106 IPC_NUM_COLUMNS,
107};
108
109static const column_t exception_columns[] = {
110 {"exc", 'e', 8},
111 {"count", 'n', 10},
112 {"%count", 'N', 8},
113 {"cycles", 'c', 10},
114 {"%cycles", 'C', 9},
115 {"description", 'd', 0},
116};
117
118enum {
119 EXCEPTION_COL_ID = 0,
120 EXCEPTION_COL_COUNT,
121 EXCEPTION_COL_PERCENT_COUNT,
122 EXCEPTION_COL_CYCLES,
123 EXCEPTION_COL_PERCENT_CYCLES,
124 EXCEPTION_COL_DESCRIPTION,
125 EXCEPTION_NUM_COLUMNS,
126};
127
128screen_mode_t screen_mode = SCREEN_TABLE;
129static op_mode_t op_mode = OP_TASKS;
130static size_t sort_column = TASK_COL_PERCENT_USER;
131static int sort_reverse = -1;
132static bool excs_all = false;
133
134static const char *read_data(data_t *target)
135{
136 /* Initialize data */
137 target->load = NULL;
138 target->cpus = NULL;
139 target->cpus_perc = NULL;
140 target->tasks = NULL;
141 target->tasks_perc = NULL;
142 target->threads = NULL;
143 target->exceptions = NULL;
144 target->exceptions_perc = NULL;
145 target->physmem = NULL;
146 target->ucycles_diff = NULL;
147 target->kcycles_diff = NULL;
148 target->ecycles_diff = NULL;
149 target->ecount_diff = NULL;
150 target->table.name = NULL;
151 target->table.num_columns = 0;
152 target->table.columns = NULL;
153 target->table.num_fields = 0;
154 target->table.fields = NULL;
155
156 /* Get current time */
157 struct timeval time;
158 gettimeofday(&time, NULL);
159
160 target->hours = (time.tv_sec % DAY) / HOUR;
161 target->minutes = (time.tv_sec % HOUR) / MINUTE;
162 target->seconds = time.tv_sec % MINUTE;
163
164 /* Get uptime */
165 struct timeval uptime;
166 getuptime(&uptime);
167
168 target->udays = uptime.tv_sec / DAY;
169 target->uhours = (uptime.tv_sec % DAY) / HOUR;
170 target->uminutes = (uptime.tv_sec % HOUR) / MINUTE;
171 target->useconds = uptime.tv_sec % MINUTE;
172
173 /* Get load */
174 target->load = stats_get_load(&(target->load_count));
175 if (target->load == NULL)
176 return "Cannot get system load";
177
178 /* Get CPUs */
179 target->cpus = stats_get_cpus(&(target->cpus_count));
180 if (target->cpus == NULL)
181 return "Cannot get CPUs";
182
183 target->cpus_perc =
184 (perc_cpu_t *) calloc(target->cpus_count, sizeof(perc_cpu_t));
185 if (target->cpus_perc == NULL)
186 return "Not enough memory for CPU utilization";
187
188 /* Get tasks */
189 target->tasks = stats_get_tasks(&(target->tasks_count));
190 if (target->tasks == NULL)
191 return "Cannot get tasks";
192
193 target->tasks_perc =
194 (perc_task_t *) calloc(target->tasks_count, sizeof(perc_task_t));
195 if (target->tasks_perc == NULL)
196 return "Not enough memory for task utilization";
197
198 /* Get threads */
199 target->threads = stats_get_threads(&(target->threads_count));
200 if (target->threads == NULL)
201 return "Cannot get threads";
202
203 /* Get Exceptions */
204 target->exceptions = stats_get_exceptions(&(target->exceptions_count));
205 if (target->exceptions == NULL)
206 return "Cannot get exceptions";
207
208 target->exceptions_perc =
209 (perc_exc_t *) calloc(target->exceptions_count, sizeof(perc_exc_t));
210 if (target->exceptions_perc == NULL)
211 return "Not enough memory for exception utilization";
212
213 /* Get physical memory */
214 target->physmem = stats_get_physmem();
215 if (target->physmem == NULL)
216 return "Cannot get physical memory";
217
218 target->ucycles_diff = calloc(target->tasks_count,
219 sizeof(uint64_t));
220 if (target->ucycles_diff == NULL)
221 return "Not enough memory for user utilization";
222
223 /* Allocate memory for computed values */
224 target->kcycles_diff = calloc(target->tasks_count,
225 sizeof(uint64_t));
226 if (target->kcycles_diff == NULL)
227 return "Not enough memory for kernel utilization";
228
229 target->ecycles_diff = calloc(target->exceptions_count,
230 sizeof(uint64_t));
231 if (target->ecycles_diff == NULL)
232 return "Not enough memory for exception cycles utilization";
233
234 target->ecount_diff = calloc(target->exceptions_count,
235 sizeof(uint64_t));
236 if (target->ecount_diff == NULL)
237 return "Not enough memory for exception count utilization";
238
239 return NULL;
240}
241
242/** Computes percentage differencies from old_data to new_data
243 *
244 * @param old_data Pointer to old data strucutre.
245 * @param new_data Pointer to actual data where percetages are stored.
246 *
247 */
248static void compute_percentages(data_t *old_data, data_t *new_data)
249{
250 /* For each CPU: Compute total cycles and divide it between
251 user and kernel */
252
253 size_t i;
254 for (i = 0; i < new_data->cpus_count; i++) {
255 uint64_t idle =
256 new_data->cpus[i].idle_cycles - old_data->cpus[i].idle_cycles;
257 uint64_t busy =
258 new_data->cpus[i].busy_cycles - old_data->cpus[i].busy_cycles;
259 uint64_t sum = idle + busy;
260
261 FRACTION_TO_FLOAT(new_data->cpus_perc[i].idle, idle * 100, sum);
262 FRACTION_TO_FLOAT(new_data->cpus_perc[i].busy, busy * 100, sum);
263 }
264
265 /* For all tasks compute sum and differencies of all cycles */
266
267 uint64_t virtmem_total = 0;
268 uint64_t resmem_total = 0;
269 uint64_t ucycles_total = 0;
270 uint64_t kcycles_total = 0;
271
272 for (i = 0; i < new_data->tasks_count; i++) {
273 /* Match task with the previous instance */
274
275 bool found = false;
276 size_t j;
277 for (j = 0; j < old_data->tasks_count; j++) {
278 if (new_data->tasks[i].task_id == old_data->tasks[j].task_id) {
279 found = true;
280 break;
281 }
282 }
283
284 if (!found) {
285 /* This is newly borned task, ignore it */
286 new_data->ucycles_diff[i] = 0;
287 new_data->kcycles_diff[i] = 0;
288 continue;
289 }
290
291 new_data->ucycles_diff[i] =
292 new_data->tasks[i].ucycles - old_data->tasks[j].ucycles;
293 new_data->kcycles_diff[i] =
294 new_data->tasks[i].kcycles - old_data->tasks[j].kcycles;
295
296 virtmem_total += new_data->tasks[i].virtmem;
297 resmem_total += new_data->tasks[i].resmem;
298 ucycles_total += new_data->ucycles_diff[i];
299 kcycles_total += new_data->kcycles_diff[i];
300 }
301
302 /* For each task compute percential change */
303
304 for (i = 0; i < new_data->tasks_count; i++) {
305 FRACTION_TO_FLOAT(new_data->tasks_perc[i].virtmem,
306 new_data->tasks[i].virtmem * 100, virtmem_total);
307 FRACTION_TO_FLOAT(new_data->tasks_perc[i].resmem,
308 new_data->tasks[i].resmem * 100, resmem_total);
309 FRACTION_TO_FLOAT(new_data->tasks_perc[i].ucycles,
310 new_data->ucycles_diff[i] * 100, ucycles_total);
311 FRACTION_TO_FLOAT(new_data->tasks_perc[i].kcycles,
312 new_data->kcycles_diff[i] * 100, kcycles_total);
313 }
314
315 /* For all exceptions compute sum and differencies of cycles */
316
317 uint64_t ecycles_total = 0;
318 uint64_t ecount_total = 0;
319
320 for (i = 0; i < new_data->exceptions_count; i++) {
321 /*
322 * March exception with the previous instance.
323 * This is quite paranoid since exceptions do not
324 * usually disappear, but it does not hurt.
325 */
326
327 bool found = false;
328 size_t j;
329 for (j = 0; j < old_data->exceptions_count; j++) {
330 if (new_data->exceptions[i].id == old_data->exceptions[j].id) {
331 found = true;
332 break;
333 }
334 }
335
336 if (!found) {
337 /* This is a new exception, ignore it */
338 new_data->ecycles_diff[i] = 0;
339 new_data->ecount_diff[i] = 0;
340 continue;
341 }
342
343 new_data->ecycles_diff[i] =
344 new_data->exceptions[i].cycles - old_data->exceptions[j].cycles;
345 new_data->ecount_diff[i] =
346 new_data->exceptions[i].count - old_data->exceptions[i].count;
347
348 ecycles_total += new_data->ecycles_diff[i];
349 ecount_total += new_data->ecount_diff[i];
350 }
351
352 /* For each exception compute percential change */
353
354 for (i = 0; i < new_data->exceptions_count; i++) {
355 FRACTION_TO_FLOAT(new_data->exceptions_perc[i].cycles,
356 new_data->ecycles_diff[i] * 100, ecycles_total);
357 FRACTION_TO_FLOAT(new_data->exceptions_perc[i].count,
358 new_data->ecount_diff[i] * 100, ecount_total);
359 }
360}
361
362static int cmp_data(void *a, void *b, void *arg)
363{
364 field_t *fa = (field_t *)a + sort_column;
365 field_t *fb = (field_t *)b + sort_column;
366
367 if (fa->type > fb->type)
368 return 1 * sort_reverse;
369
370 if (fa->type < fb->type)
371 return -1 * sort_reverse;
372
373 switch (fa->type) {
374 case FIELD_EMPTY:
375 return 0;
376 case FIELD_UINT_SUFFIX_BIN: /* fallthrough */
377 case FIELD_UINT_SUFFIX_DEC: /* fallthrough */
378 case FIELD_UINT:
379 if (fa->uint > fb->uint)
380 return 1 * sort_reverse;
381 if (fa->uint < fb->uint)
382 return -1 * sort_reverse;
383 return 0;
384 case FIELD_PERCENT:
385 if (fa->fixed.upper * fb->fixed.lower
386 > fb->fixed.upper * fa->fixed.lower)
387 return 1 * sort_reverse;
388 if (fa->fixed.upper * fb->fixed.lower
389 < fb->fixed.upper * fa->fixed.lower)
390 return -1 * sort_reverse;
391 return 0;
392 case FIELD_STRING:
393 return str_cmp(fa->string, fb->string) * sort_reverse;
394 }
395
396 return 0;
397}
398
399static void sort_table(table_t *table)
400{
401 if (sort_column >= table->num_columns)
402 sort_column = 0;
403 /* stable sort is probably best, so we use gsort */
404 gsort((void *) table->fields, table->num_fields / table->num_columns,
405 sizeof(field_t) * table->num_columns, cmp_data, NULL);
406}
407
408static const char *fill_task_table(data_t *data)
409{
410 data->table.name = "Tasks";
411 data->table.num_columns = TASK_NUM_COLUMNS;
412 data->table.columns = task_columns;
413 data->table.num_fields = data->tasks_count * TASK_NUM_COLUMNS;
414 data->table.fields = calloc(data->table.num_fields,
415 sizeof(field_t));
416 if (data->table.fields == NULL)
417 return "Not enough memory for table fields";
418
419 field_t *field = data->table.fields;
420 for (size_t i = 0; i < data->tasks_count; i++) {
421 stats_task_t *task = &data->tasks[i];
422 perc_task_t *perc = &data->tasks_perc[i];
423 field[TASK_COL_ID].type = FIELD_UINT;
424 field[TASK_COL_ID].uint = task->task_id;
425 field[TASK_COL_NUM_THREADS].type = FIELD_UINT;
426 field[TASK_COL_NUM_THREADS].uint = task->threads;
427 field[TASK_COL_RESIDENT].type = FIELD_UINT_SUFFIX_BIN;
428 field[TASK_COL_RESIDENT].uint = task->resmem;
429 field[TASK_COL_PERCENT_RESIDENT].type = FIELD_PERCENT;
430 field[TASK_COL_PERCENT_RESIDENT].fixed = perc->resmem;
431 field[TASK_COL_VIRTUAL].type = FIELD_UINT_SUFFIX_BIN;
432 field[TASK_COL_VIRTUAL].uint = task->virtmem;
433 field[TASK_COL_PERCENT_VIRTUAL].type = FIELD_PERCENT;
434 field[TASK_COL_PERCENT_VIRTUAL].fixed = perc->virtmem;
435 field[TASK_COL_PERCENT_USER].type = FIELD_PERCENT;
436 field[TASK_COL_PERCENT_USER].fixed = perc->ucycles;
437 field[TASK_COL_PERCENT_KERNEL].type = FIELD_PERCENT;
438 field[TASK_COL_PERCENT_KERNEL].fixed = perc->kcycles;
439 field[TASK_COL_NAME].type = FIELD_STRING;
440 field[TASK_COL_NAME].string = task->name;
441 field += TASK_NUM_COLUMNS;
442 }
443
444 return NULL;
445}
446
447static const char *fill_ipc_table(data_t *data)
448{
449 data->table.name = "IPC";
450 data->table.num_columns = IPC_NUM_COLUMNS;
451 data->table.columns = ipc_columns;
452 data->table.num_fields = data->tasks_count * IPC_NUM_COLUMNS;
453 data->table.fields = calloc(data->table.num_fields,
454 sizeof(field_t));
455 if (data->table.fields == NULL)
456 return "Not enough memory for table fields";
457
458 field_t *field = data->table.fields;
459 for (size_t i = 0; i < data->tasks_count; i++) {
460 field[IPC_COL_TASKID].type = FIELD_UINT;
461 field[IPC_COL_TASKID].uint = data->tasks[i].task_id;
462 field[IPC_COL_CLS_SNT].type = FIELD_UINT_SUFFIX_DEC;
463 field[IPC_COL_CLS_SNT].uint = data->tasks[i].ipc_info.call_sent;
464 field[IPC_COL_CLS_RCV].type = FIELD_UINT_SUFFIX_DEC;
465 field[IPC_COL_CLS_RCV].uint = data->tasks[i].ipc_info.call_received;
466 field[IPC_COL_ANS_SNT].type = FIELD_UINT_SUFFIX_DEC;
467 field[IPC_COL_ANS_SNT].uint = data->tasks[i].ipc_info.answer_sent;
468 field[IPC_COL_ANS_RCV].type = FIELD_UINT_SUFFIX_DEC;
469 field[IPC_COL_ANS_RCV].uint = data->tasks[i].ipc_info.answer_received;
470 field[IPC_COL_FORWARD].type = FIELD_UINT_SUFFIX_DEC;
471 field[IPC_COL_FORWARD].uint = data->tasks[i].ipc_info.forwarded;
472 field[IPC_COL_NAME].type = FIELD_STRING;
473 field[IPC_COL_NAME].string = data->tasks[i].name;
474 field += IPC_NUM_COLUMNS;
475 }
476
477 return NULL;
478}
479
480static const char *fill_exception_table(data_t *data)
481{
482 data->table.name = "Exceptions";
483 data->table.num_columns = EXCEPTION_NUM_COLUMNS;
484 data->table.columns = exception_columns;
485 data->table.num_fields = data->exceptions_count *
486 EXCEPTION_NUM_COLUMNS;
487 data->table.fields = calloc(data->table.num_fields, sizeof(field_t));
488 if (data->table.fields == NULL)
489 return "Not enough memory for table fields";
490
491 field_t *field = data->table.fields;
492 for (size_t i = 0; i < data->exceptions_count; i++) {
493 if (!excs_all && !data->exceptions[i].hot)
494 continue;
495 field[EXCEPTION_COL_ID].type = FIELD_UINT;
496 field[EXCEPTION_COL_ID].uint = data->exceptions[i].id;
497 field[EXCEPTION_COL_COUNT].type = FIELD_UINT_SUFFIX_DEC;
498 field[EXCEPTION_COL_COUNT].uint = data->exceptions[i].count;
499 field[EXCEPTION_COL_PERCENT_COUNT].type = FIELD_PERCENT;
500 field[EXCEPTION_COL_PERCENT_COUNT].fixed = data->exceptions_perc[i].count;
501 field[EXCEPTION_COL_CYCLES].type = FIELD_UINT_SUFFIX_DEC;
502 field[EXCEPTION_COL_CYCLES].uint = data->exceptions[i].cycles;
503 field[EXCEPTION_COL_PERCENT_CYCLES].type = FIELD_PERCENT;
504 field[EXCEPTION_COL_PERCENT_CYCLES].fixed = data->exceptions_perc[i].cycles;
505 field[EXCEPTION_COL_DESCRIPTION].type = FIELD_STRING;
506 field[EXCEPTION_COL_DESCRIPTION].string = data->exceptions[i].desc;
507 field += EXCEPTION_NUM_COLUMNS;
508 }
509
510 /* in case any cold exceptions were ignored */
511 data->table.num_fields = field - data->table.fields;
512
513 return NULL;
514}
515
516static const char *fill_table(data_t *data)
517{
518 if (data->table.fields != NULL) {
519 free(data->table.fields);
520 data->table.fields = NULL;
521 }
522
523 switch (op_mode) {
524 case OP_TASKS:
525 return fill_task_table(data);
526 case OP_IPC:
527 return fill_ipc_table(data);
528 case OP_EXCS:
529 return fill_exception_table(data);
530 }
531 return NULL;
532}
533
534static void free_data(data_t *target)
535{
536 if (target->load != NULL)
537 free(target->load);
538
539 if (target->cpus != NULL)
540 free(target->cpus);
541
542 if (target->cpus_perc != NULL)
543 free(target->cpus_perc);
544
545 if (target->tasks != NULL)
546 free(target->tasks);
547
548 if (target->tasks_perc != NULL)
549 free(target->tasks_perc);
550
551 if (target->threads != NULL)
552 free(target->threads);
553
554 if (target->exceptions != NULL)
555 free(target->exceptions);
556
557 if (target->exceptions_perc != NULL)
558 free(target->exceptions_perc);
559
560 if (target->physmem != NULL)
561 free(target->physmem);
562
563 if (target->ucycles_diff != NULL)
564 free(target->ucycles_diff);
565
566 if (target->kcycles_diff != NULL)
567 free(target->kcycles_diff);
568
569 if (target->ecycles_diff != NULL)
570 free(target->ecycles_diff);
571
572 if (target->ecount_diff != NULL)
573 free(target->ecount_diff);
574
575 if (target->table.fields != NULL)
576 free(target->table.fields);
577}
578
579int main(int argc, char *argv[])
580{
581 data_t data;
582 data_t data_prev;
583 const char *ret = NULL;
584
585 screen_init();
586 printf("Reading initial data...\n");
587
588 if ((ret = read_data(&data)) != NULL)
589 goto out;
590
591 /* Compute some rubbish to have initialised values */
592 compute_percentages(&data, &data);
593
594 /* And paint screen until death */
595 while (true) {
596 int c = tgetchar(UPDATE_INTERVAL);
597
598 if (c < 0) { /* timeout */
599 data_prev = data;
600 if ((ret = read_data(&data)) != NULL) {
601 free_data(&data_prev);
602 goto out;
603 }
604
605 compute_percentages(&data_prev, &data);
606 free_data(&data_prev);
607
608 c = -1;
609 }
610
611 if (screen_mode == SCREEN_HELP && c >= 0) {
612 if (c == 'h' || c == '?')
613 c = -1;
614 /* go back to table and handle the key */
615 screen_mode = SCREEN_TABLE;
616 }
617
618 if (screen_mode == SCREEN_SORT && c >= 0) {
619 for (size_t i = 0; i < data.table.num_columns; i++) {
620 if (data.table.columns[i].key == c) {
621 sort_column = i;
622 screen_mode = SCREEN_TABLE;
623 }
624 }
625
626 c = -1;
627 }
628
629 switch (c) {
630 case -1: /* do nothing */
631 break;
632 case 't':
633 op_mode = OP_TASKS;
634 break;
635 case 'i':
636 op_mode = OP_IPC;
637 break;
638 case 'e':
639 op_mode = OP_EXCS;
640 break;
641 case 's':
642 screen_mode = SCREEN_SORT;
643 break;
644 case 'r':
645 sort_reverse = -sort_reverse;
646 break;
647 case 'h':
648 case '?':
649 screen_mode = SCREEN_HELP;
650 break;
651 case 'q':
652 goto out;
653 case 'a':
654 if (op_mode == OP_EXCS) {
655 excs_all = !excs_all;
656 if (excs_all)
657 show_warning("Showing all exceptions");
658 else
659 show_warning("Showing only hot exceptions");
660 break;
661 }
662 /* Fallthrough */
663 default:
664 show_warning("Unknown command \"%c\", use \"h\" for help", c);
665 continue; /* don't redraw */
666 }
667
668 if ((ret = fill_table(&data)) != NULL) {
669 goto out;
670 }
671 sort_table(&data.table);
672 print_data(&data);
673 }
674
675out:
676 screen_done();
677 free_data(&data);
678
679 if (ret != NULL) {
680 fprintf(stderr, "%s: %s\n", NAME, ret);
681 return 1;
682 }
683
684 return 0;
685}
686
687/** @}
688 */
Note: See TracBrowser for help on using the repository browser.