diff options
Diffstat (limited to 'procps/top.c')
-rw-r--r-- | procps/top.c | 282 |
1 files changed, 169 insertions, 113 deletions
diff --git a/procps/top.c b/procps/top.c index ee6555188..011bbf183 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -92,9 +92,9 @@ enum { SORT_DEPTH = 3 }; | |||
92 | struct globals { | 92 | struct globals { |
93 | top_status_t *top; | 93 | top_status_t *top; |
94 | int ntop; | 94 | int ntop; |
95 | smallint inverted; | ||
95 | #if ENABLE_FEATURE_TOPMEM | 96 | #if ENABLE_FEATURE_TOPMEM |
96 | smallint sort_field; | 97 | smallint sort_field; |
97 | smallint inverted; | ||
98 | #endif | 98 | #endif |
99 | #if ENABLE_FEATURE_TOP_SMP_CPU | 99 | #if ENABLE_FEATURE_TOP_SMP_CPU |
100 | smallint smp_cpu_info; /* one/many cpu info lines? */ | 100 | smallint smp_cpu_info; /* one/many cpu info lines? */ |
@@ -194,9 +194,9 @@ static int mult_lvl_cmp(void* a, void* b) | |||
194 | for (i = 0; i < SORT_DEPTH; i++) { | 194 | for (i = 0; i < SORT_DEPTH; i++) { |
195 | cmp_val = (*sort_function[i])(a, b); | 195 | cmp_val = (*sort_function[i])(a, b); |
196 | if (cmp_val != 0) | 196 | if (cmp_val != 0) |
197 | return cmp_val; | 197 | break; |
198 | } | 198 | } |
199 | return 0; | 199 | return inverted ? -cmp_val : cmp_val; |
200 | } | 200 | } |
201 | 201 | ||
202 | static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) | 202 | static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) |
@@ -797,7 +797,7 @@ static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) | |||
797 | 797 | ||
798 | display_topmem_header(scr_width, &lines_rem); | 798 | display_topmem_header(scr_width, &lines_rem); |
799 | strcpy(line_buf, HDR_STR " COMMAND"); | 799 | strcpy(line_buf, HDR_STR " COMMAND"); |
800 | line_buf[5 + sort_field * 6] = '*'; | 800 | line_buf[11 + sort_field * 6] = "^_"[inverted]; |
801 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); | 801 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); |
802 | lines_rem--; | 802 | lines_rem--; |
803 | 803 | ||
@@ -850,8 +850,114 @@ enum { | |||
850 | | PSSCAN_PID | 850 | | PSSCAN_PID |
851 | | PSSCAN_SMAPS | 851 | | PSSCAN_SMAPS |
852 | | PSSCAN_COMM, | 852 | | PSSCAN_COMM, |
853 | EXIT_MASK = (unsigned)-1, | ||
853 | }; | 854 | }; |
854 | 855 | ||
856 | #if ENABLE_FEATURE_USE_TERMIOS | ||
857 | static unsigned handle_input(unsigned scan_mask, unsigned interval) | ||
858 | { | ||
859 | unsigned char c; | ||
860 | struct pollfd pfd[1]; | ||
861 | |||
862 | pfd[0].fd = 0; | ||
863 | pfd[0].events = POLLIN; | ||
864 | |||
865 | while (1) { | ||
866 | if (safe_poll(pfd, 1, interval * 1000) <= 0) | ||
867 | return scan_mask; | ||
868 | interval = 0; | ||
869 | |||
870 | if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ | ||
871 | option_mask32 |= OPT_EOF; | ||
872 | return scan_mask; | ||
873 | } | ||
874 | |||
875 | if (c == initial_settings.c_cc[VINTR]) | ||
876 | return EXIT_MASK; | ||
877 | if (c == initial_settings.c_cc[VEOF]) | ||
878 | return EXIT_MASK; | ||
879 | c |= 0x20; /* lowercase */ | ||
880 | if (c == 'q') | ||
881 | return EXIT_MASK; | ||
882 | |||
883 | if (c == 'n') { | ||
884 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
885 | sort_function[0] = pid_sort; | ||
886 | continue; | ||
887 | } | ||
888 | if (c == 'm') { | ||
889 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
890 | sort_function[0] = mem_sort; | ||
891 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
892 | sort_function[1] = pcpu_sort; | ||
893 | sort_function[2] = time_sort; | ||
894 | # endif | ||
895 | continue; | ||
896 | } | ||
897 | # if ENABLE_FEATURE_SHOW_THREADS | ||
898 | if (c == 'h' | ||
899 | IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) | ||
900 | ) { | ||
901 | scan_mask ^= PSSCAN_TASKS; | ||
902 | continue; | ||
903 | } | ||
904 | # endif | ||
905 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
906 | if (c == 'p') { | ||
907 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
908 | sort_function[0] = pcpu_sort; | ||
909 | sort_function[1] = mem_sort; | ||
910 | sort_function[2] = time_sort; | ||
911 | continue; | ||
912 | } | ||
913 | if (c == 't') { | ||
914 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
915 | sort_function[0] = time_sort; | ||
916 | sort_function[1] = mem_sort; | ||
917 | sort_function[2] = pcpu_sort; | ||
918 | continue; | ||
919 | } | ||
920 | # if ENABLE_FEATURE_TOPMEM | ||
921 | if (c == 's') { | ||
922 | scan_mask = TOPMEM_MASK; | ||
923 | free(prev_hist); | ||
924 | prev_hist = NULL; | ||
925 | prev_hist_count = 0; | ||
926 | sort_field = (sort_field + 1) % NUM_SORT_FIELD; | ||
927 | continue; | ||
928 | } | ||
929 | # endif | ||
930 | if (c == 'r') { | ||
931 | inverted ^= 1; | ||
932 | continue; | ||
933 | } | ||
934 | # if ENABLE_FEATURE_TOP_SMP_CPU | ||
935 | /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ | ||
936 | if (c == 'c' || c == '1') { | ||
937 | /* User wants to toggle per cpu <> aggregate */ | ||
938 | if (smp_cpu_info) { | ||
939 | free(cpu_prev_jif); | ||
940 | free(cpu_jif); | ||
941 | cpu_jif = &cur_jif; | ||
942 | cpu_prev_jif = &prev_jif; | ||
943 | } else { | ||
944 | /* Prepare for xrealloc() */ | ||
945 | cpu_jif = cpu_prev_jif = NULL; | ||
946 | } | ||
947 | num_cpus = 0; | ||
948 | smp_cpu_info = !smp_cpu_info; | ||
949 | get_jiffy_counts(); | ||
950 | continue; | ||
951 | } | ||
952 | # endif | ||
953 | # endif | ||
954 | break; /* unknown key -> force refresh */ | ||
955 | } | ||
956 | |||
957 | return scan_mask; | ||
958 | } | ||
959 | #endif | ||
960 | |||
855 | //usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU | 961 | //usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU |
856 | //usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__ | 962 | //usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__ |
857 | //usage:#else | 963 | //usage:#else |
@@ -871,8 +977,9 @@ enum { | |||
871 | //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu") | 977 | //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu") |
872 | //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time") | 978 | //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time") |
873 | //usage: IF_FEATURE_TOPMEM( | 979 | //usage: IF_FEATURE_TOPMEM( |
874 | //usage: "\n"" S: show memory, R: reverse memory sort" | 980 | //usage: "\n"" S: show memory" |
875 | //usage: ) | 981 | //usage: ) |
982 | //usage: "\n"" R: reverse sort" | ||
876 | //usage: IF_SHOW_THREADS_OR_TOP_SMP( | 983 | //usage: IF_SHOW_THREADS_OR_TOP_SMP( |
877 | //usage: "\n"" " | 984 | //usage: "\n"" " |
878 | //usage: IF_FEATURE_SHOW_THREADS("H: toggle threads") | 985 | //usage: IF_FEATURE_SHOW_THREADS("H: toggle threads") |
@@ -880,23 +987,36 @@ enum { | |||
880 | //usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP") | 987 | //usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP") |
881 | //usage: ) | 988 | //usage: ) |
882 | //usage: "\n"" Q,^C: exit" | 989 | //usage: "\n"" Q,^C: exit" |
990 | //usage: "\n" | ||
991 | //usage: "\n""Options:" | ||
992 | //usage: "\n"" -b Batch mode" | ||
993 | //usage: "\n"" -n N Exit after N iterations" | ||
994 | //usage: "\n"" -d N Delay between updates" | ||
995 | //usage: IF_FEATURE_TOPMEM( | ||
996 | //usage: "\n"" -m Same as 's' key" | ||
997 | //usage: ) | ||
998 | |||
999 | /* Interactive testing: | ||
1000 | * echo sss | ./busybox top | ||
1001 | * - shows memory screen | ||
1002 | * echo sss | ./busybox top -bn1 >mem | ||
1003 | * - saves memory screen - the *whole* list, not first NROWS processes! | ||
1004 | * echo .m.s.s.s.s.s.s.q | ./busybox top -b >z | ||
1005 | * - saves several different screens, and exits | ||
1006 | * | ||
1007 | * TODO: -i STRING param as a better alternative? | ||
1008 | */ | ||
883 | 1009 | ||
884 | int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1010 | int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
885 | int top_main(int argc UNUSED_PARAM, char **argv) | 1011 | int top_main(int argc UNUSED_PARAM, char **argv) |
886 | { | 1012 | { |
887 | int iterations; | 1013 | int iterations; |
888 | unsigned lines, col; | 1014 | unsigned lines, col; |
889 | int lines_rem; | ||
890 | unsigned interval; | 1015 | unsigned interval; |
891 | char *str_interval, *str_iterations; | 1016 | char *str_interval, *str_iterations; |
892 | unsigned scan_mask = TOP_MASK; | 1017 | unsigned scan_mask = TOP_MASK; |
893 | #if ENABLE_FEATURE_USE_TERMIOS | 1018 | #if ENABLE_FEATURE_USE_TERMIOS |
894 | struct termios new_settings; | 1019 | struct termios new_settings; |
895 | struct pollfd pfd[1]; | ||
896 | unsigned char c; | ||
897 | |||
898 | pfd[0].fd = 0; | ||
899 | pfd[0].events = POLLIN; | ||
900 | #endif | 1020 | #endif |
901 | 1021 | ||
902 | INIT_G(); | 1022 | INIT_G(); |
@@ -933,15 +1053,6 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
933 | 1053 | ||
934 | /* change to /proc */ | 1054 | /* change to /proc */ |
935 | xchdir("/proc"); | 1055 | xchdir("/proc"); |
936 | #if ENABLE_FEATURE_USE_TERMIOS | ||
937 | tcgetattr(0, (void *) &initial_settings); | ||
938 | memcpy(&new_settings, &initial_settings, sizeof(new_settings)); | ||
939 | /* unbuffered input, turn off echo */ | ||
940 | new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); | ||
941 | |||
942 | bb_signals(BB_FATAL_SIGS, sig_catcher); | ||
943 | tcsetattr_stdin_TCSANOW(&new_settings); | ||
944 | #endif | ||
945 | 1056 | ||
946 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 1057 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
947 | sort_function[0] = pcpu_sort; | 1058 | sort_function[0] = pcpu_sort; |
@@ -951,21 +1062,41 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
951 | sort_function[0] = mem_sort; | 1062 | sort_function[0] = mem_sort; |
952 | #endif | 1063 | #endif |
953 | 1064 | ||
954 | while (1) { | 1065 | #if ENABLE_FEATURE_USE_TERMIOS |
1066 | tcgetattr(0, (void *) &initial_settings); | ||
1067 | memcpy(&new_settings, &initial_settings, sizeof(new_settings)); | ||
1068 | if (!OPT_BATCH_MODE) { | ||
1069 | /* unbuffered input, turn off echo */ | ||
1070 | new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); | ||
1071 | tcsetattr_stdin_TCSANOW(&new_settings); | ||
1072 | } | ||
1073 | |||
1074 | bb_signals(BB_FATAL_SIGS, sig_catcher); | ||
1075 | |||
1076 | /* Eat initial input, if any */ | ||
1077 | scan_mask = handle_input(scan_mask, 0); | ||
1078 | #endif | ||
1079 | |||
1080 | while (scan_mask != EXIT_MASK) { | ||
955 | procps_status_t *p = NULL; | 1081 | procps_status_t *p = NULL; |
956 | 1082 | ||
957 | lines = 24; /* default */ | 1083 | if (OPT_BATCH_MODE) { |
958 | col = 79; | 1084 | lines = INT_MAX; |
1085 | col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ | ||
1086 | } else { | ||
1087 | lines = 24; /* default */ | ||
1088 | col = 79; | ||
959 | #if ENABLE_FEATURE_USE_TERMIOS | 1089 | #if ENABLE_FEATURE_USE_TERMIOS |
960 | /* We output to stdout, we need size of stdout (not stdin)! */ | 1090 | /* We output to stdout, we need size of stdout (not stdin)! */ |
961 | get_terminal_width_height(STDOUT_FILENO, &col, &lines); | 1091 | get_terminal_width_height(STDOUT_FILENO, &col, &lines); |
962 | if (lines < 5 || col < 10) { | 1092 | if (lines < 5 || col < 10) { |
963 | sleep(interval); | 1093 | sleep(interval); |
964 | continue; | 1094 | continue; |
965 | } | 1095 | } |
966 | #endif | 1096 | #endif |
967 | if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */ | 1097 | if (col > LINE_BUF_SIZE - 2) |
968 | col = LINE_BUF_SIZE-2; | 1098 | col = LINE_BUF_SIZE - 2; |
1099 | } | ||
969 | 1100 | ||
970 | /* read process IDs & status for all the processes */ | 1101 | /* read process IDs & status for all the processes */ |
971 | while ((p = procps_scan(p, scan_mask)) != NULL) { | 1102 | while ((p = procps_scan(p, scan_mask)) != NULL) { |
@@ -1033,15 +1164,11 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1033 | qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); | 1164 | qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); |
1034 | } | 1165 | } |
1035 | #endif | 1166 | #endif |
1036 | lines_rem = lines; | ||
1037 | if (OPT_BATCH_MODE) { | ||
1038 | lines_rem = INT_MAX; | ||
1039 | } | ||
1040 | if (scan_mask != TOPMEM_MASK) | 1167 | if (scan_mask != TOPMEM_MASK) |
1041 | display_process_list(lines_rem, col); | 1168 | display_process_list(lines, col); |
1042 | #if ENABLE_FEATURE_TOPMEM | 1169 | #if ENABLE_FEATURE_TOPMEM |
1043 | else | 1170 | else |
1044 | display_topmem_process_list(lines_rem, col); | 1171 | display_topmem_process_list(lines, col); |
1045 | #endif | 1172 | #endif |
1046 | clearmems(); | 1173 | clearmems(); |
1047 | if (iterations >= 0 && !--iterations) | 1174 | if (iterations >= 0 && !--iterations) |
@@ -1049,84 +1176,13 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1049 | #if !ENABLE_FEATURE_USE_TERMIOS | 1176 | #if !ENABLE_FEATURE_USE_TERMIOS |
1050 | sleep(interval); | 1177 | sleep(interval); |
1051 | #else | 1178 | #else |
1052 | if (option_mask32 & (OPT_b|OPT_EOF)) | 1179 | if (option_mask32 & OPT_EOF) |
1053 | /* batch mode, or EOF on stdin ("top </dev/null") */ | 1180 | /* EOF on stdin ("top </dev/null") */ |
1054 | sleep(interval); | 1181 | sleep(interval); |
1055 | else if (safe_poll(pfd, 1, interval * 1000) > 0) { | 1182 | else |
1056 | if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ | 1183 | scan_mask = handle_input(scan_mask, interval); |
1057 | option_mask32 |= OPT_EOF; | ||
1058 | continue; | ||
1059 | } | ||
1060 | if (c == initial_settings.c_cc[VINTR]) | ||
1061 | break; | ||
1062 | c |= 0x20; /* lowercase */ | ||
1063 | if (c == 'q') | ||
1064 | break; | ||
1065 | if (c == 'n') { | ||
1066 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
1067 | sort_function[0] = pid_sort; | ||
1068 | } | ||
1069 | if (c == 'm') { | ||
1070 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
1071 | sort_function[0] = mem_sort; | ||
1072 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
1073 | sort_function[1] = pcpu_sort; | ||
1074 | sort_function[2] = time_sort; | ||
1075 | # endif | ||
1076 | } | ||
1077 | # if ENABLE_FEATURE_SHOW_THREADS | ||
1078 | if (c == 'h' | ||
1079 | IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) | ||
1080 | ) { | ||
1081 | scan_mask ^= PSSCAN_TASKS; | ||
1082 | } | ||
1083 | # endif | ||
1084 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
1085 | if (c == 'p') { | ||
1086 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
1087 | sort_function[0] = pcpu_sort; | ||
1088 | sort_function[1] = mem_sort; | ||
1089 | sort_function[2] = time_sort; | ||
1090 | } | ||
1091 | if (c == 't') { | ||
1092 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | ||
1093 | sort_function[0] = time_sort; | ||
1094 | sort_function[1] = mem_sort; | ||
1095 | sort_function[2] = pcpu_sort; | ||
1096 | } | ||
1097 | # if ENABLE_FEATURE_TOPMEM | ||
1098 | if (c == 's') { | ||
1099 | scan_mask = TOPMEM_MASK; | ||
1100 | free(prev_hist); | ||
1101 | prev_hist = NULL; | ||
1102 | prev_hist_count = 0; | ||
1103 | sort_field = (sort_field + 1) % NUM_SORT_FIELD; | ||
1104 | } | ||
1105 | if (c == 'r') | ||
1106 | inverted ^= 1; | ||
1107 | # endif | ||
1108 | # if ENABLE_FEATURE_TOP_SMP_CPU | ||
1109 | /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ | ||
1110 | if (c == 'c' || c == '1') { | ||
1111 | /* User wants to toggle per cpu <> aggregate */ | ||
1112 | if (smp_cpu_info) { | ||
1113 | free(cpu_prev_jif); | ||
1114 | free(cpu_jif); | ||
1115 | cpu_jif = &cur_jif; | ||
1116 | cpu_prev_jif = &prev_jif; | ||
1117 | } else { | ||
1118 | /* Prepare for xrealloc() */ | ||
1119 | cpu_jif = cpu_prev_jif = NULL; | ||
1120 | } | ||
1121 | num_cpus = 0; | ||
1122 | smp_cpu_info = !smp_cpu_info; | ||
1123 | get_jiffy_counts(); | ||
1124 | } | ||
1125 | # endif | ||
1126 | # endif | ||
1127 | } | ||
1128 | #endif /* FEATURE_USE_TERMIOS */ | 1184 | #endif /* FEATURE_USE_TERMIOS */ |
1129 | } /* end of "while (1)" */ | 1185 | } /* end of "while (not Q)" */ |
1130 | 1186 | ||
1131 | bb_putchar('\n'); | 1187 | bb_putchar('\n'); |
1132 | #if ENABLE_FEATURE_USE_TERMIOS | 1188 | #if ENABLE_FEATURE_USE_TERMIOS |