The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=5f72125339b1d14d1b04329ac561354f5e8133fe
commit 5f72125339b1d14d1b04329ac561354f5e8133fe Author: Kyle Evans <kev...@freebsd.org> AuthorDate: 2025-08-09 16:00:31 +0000 Commit: Kyle Evans <kev...@freebsd.org> CommitDate: 2025-08-09 16:00:31 +0000 top: improve sort field storage/lookup Switch up comparator mapping to avoid these kinds of errors, use a simple array of (name, comparator) pairs rather than having to maintain entries in two separate arrays that must have matching indices. Reviewed by: obiwac MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D37083 --- usr.bin/top/machine.c | 155 ++++++++++++++++++++++++++++++++++++++++---------- usr.bin/top/machine.h | 7 ++- usr.bin/top/top.c | 29 ++++------ usr.bin/top/utils.c | 21 ------- usr.bin/top/utils.h | 1 - 5 files changed, 142 insertions(+), 71 deletions(-) diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c index 8c035b5df383..1f70ee9281e8 100644 --- a/usr.bin/top/machine.c +++ b/usr.bin/top/machine.c @@ -190,15 +190,6 @@ static int pageshift; /* log base 2 of the pagesize */ #define ki_swap(kip) \ ((kip)->ki_swrss > (kip)->ki_rssize ? (kip)->ki_swrss - (kip)->ki_rssize : 0) -/* - * Sorting orders. The first element is the default. - */ -static const char *ordernames[] = { - "cpu", "size", "res", "time", "pri", "threads", - "total", "read", "write", "fault", "vcsw", "ivcsw", - "jid", "swap", "pid", NULL -}; - /* Per-cpu time states */ static int maxcpu; static int maxid; @@ -214,6 +205,18 @@ static int *pcpu_cpu_states; static int battery_units; static int battery_life; +static int compare_cpu(const void *a, const void *b); +static int compare_size(const void *a, const void *b); +static int compare_res(const void *a, const void *b); +static int compare_time(const void *a, const void *b); +static int compare_prio(const void *a, const void *b); +static int compare_threads(const void *a, const void *b); +static int compare_iototal(const void *a, const void *b); +static int compare_ioread(const void *a, const void *b); +static int compare_iowrite(const void *a, const void *b); +static int compare_iofault(const void *a, const void *b); +static int compare_vcsw(const void *a, const void *b); +static int compare_ivcsw(const void *a, const void *b); static int compare_swap(const void *a, const void *b); static int compare_jid(const void *a, const void *b); static int compare_pid(const void *a, const void *b); @@ -225,6 +228,77 @@ static void update_layout(void); static int find_uid(uid_t needle, int *haystack); static int cmd_matches(struct kinfo_proc *, const char *); +/* + * Sorting orders. The first element is the default. + */ + +typedef int (compare_fn)(const void *arg1, const void *arg2); +static const struct sort_info { + const char *si_name; + compare_fn *si_compare; +} sortdata[] = { + { + .si_name = "cpu", + .si_compare = &compare_cpu, + }, + { + .si_name = "size", + .si_compare = &compare_size, + }, + { + .si_name = "res", + .si_compare = &compare_res, + }, + { + .si_name = "time", + .si_compare = &compare_time, + }, + { + .si_name = "pri", + .si_compare = &compare_prio, + }, + { + .si_name = "threads", + .si_compare = &compare_threads, + }, + { + .si_name = "total", + .si_compare = &compare_iototal, + }, + { + .si_name = "read", + .si_compare = &compare_ioread, + }, + { + .si_name = "write", + .si_compare = &compare_iowrite, + }, + { + .si_name = "fault", + .si_compare = &compare_iofault, + }, + { + .si_name = "vcsw", + .si_compare = &compare_vcsw, + }, + { + .si_name = "ivcsw", + .si_compare = &compare_ivcsw, + }, + { + .si_name = "jid", + .si_compare = &compare_jid, + }, + { + .si_name = "swap", + .si_compare = &compare_swap, + }, + { + .si_name = "pid", + .si_compare = &compare_pid, + }, +}; + static int find_uid(uid_t needle, int *haystack) { @@ -353,7 +427,6 @@ machine_init(struct statics *statics) statics->swap_names = swapnames; else statics->swap_names = NULL; - statics->order_names = ordernames; /* Allocate state for per-CPU stats. */ GETSYSCTL("kern.smp.maxcpus", maxcpu); @@ -742,7 +815,7 @@ static struct handle handle; void * get_process_info(struct system_info *si, struct process_select *sel, - int (*compare)(const void *, const void *)) + const struct sort_info *sort_info) { int i; int total_procs; @@ -753,6 +826,9 @@ get_process_info(struct system_info *si, struct process_select *sel, struct kinfo_proc **prefp; struct kinfo_proc *pp; struct timespec previous_proc_uptime; + compare_fn *compare; + + compare = sort_info->si_compare; /* * If thread state was toggled, don't cache the previous processes. @@ -899,6 +975,43 @@ get_process_info(struct system_info *si, struct process_select *sel, return (&handle); } +/* + * Returns the sort info associated with the specified order. Currently, that's + * really only the comparator that we'll later use. Specifying a NULL ordername + * will return the default comparator. + */ +const struct sort_info * +get_sort_info(const char *ordername) +{ + const struct sort_info *info; + size_t idx; + + if (ordername == NULL) + return (&sortdata[0]); + + for (idx = 0; idx < nitems(sortdata); idx++) { + info = &sortdata[idx]; + + if (strcmp(info->si_name, ordername) == 0) + return (info); + } + + return (NULL); +} + +void +dump_sort_names(FILE *fp) +{ + const struct sort_info *info; + size_t idx; + + for (idx = 0; idx < nitems(sortdata); idx++) { + info = &sortdata[idx]; + + fprintf(fp, " %s", info->si_name); + } +} + static int cmd_matches(struct kinfo_proc *proc, const char *term) { @@ -1559,26 +1672,6 @@ compare_ivcsw(const void *arg1, const void *arg2) return (flp2 - flp1); } -int (*compares[])(const void *arg1, const void *arg2) = { - compare_cpu, - compare_size, - compare_res, - compare_time, - compare_prio, - compare_threads, - compare_iototal, - compare_ioread, - compare_iowrite, - compare_iofault, - compare_vcsw, - compare_ivcsw, - compare_jid, - compare_swap, - compare_pid, - NULL -}; - - static int swapmode(int *retavail, int *retfree) { diff --git a/usr.bin/top/machine.h b/usr.bin/top/machine.h index 57f2846cdba5..b4f2f1a8bd50 100644 --- a/usr.bin/top/machine.h +++ b/usr.bin/top/machine.h @@ -89,10 +89,15 @@ void get_system_info(struct system_info *si); int machine_init(struct statics *statics); /* non-int routines typically used by the machine dependent module */ +struct sort_info; + extern struct process_select ps; void * get_process_info(struct system_info *si, struct process_select *sel, - int (*compare)(const void *, const void *)); + const struct sort_info *); + +const struct sort_info *get_sort_info(const char *name); +void dump_sort_names(FILE *fp); #endif /* MACHINE_H */ diff --git a/usr.bin/top/top.c b/usr.bin/top/top.c index 856ad838dc1c..f0458a4037af 100644 --- a/usr.bin/top/top.c +++ b/usr.bin/top/top.c @@ -252,7 +252,7 @@ main(int argc, const char *argv[]) char no_command = 1; struct timeval timeout; char *order_name = NULL; - int order_index = 0; + const struct sort_info *sort_info = NULL; fd_set readfds; char *nptr; @@ -505,21 +505,18 @@ main(int argc, const char *argv[]) /* determine sorting order index, if necessary */ if (order_name != NULL) { - if ((order_index = string_index(order_name, statics.order_names)) == -1) - { - const char * const *pp; - + if ((sort_info = get_sort_info(order_name)) == NULL) { warnx("'%s' is not a recognized sorting order.", order_name); fprintf(stderr, "\tTry one of these:"); - pp = statics.order_names; - while (*pp != NULL) - { - fprintf(stderr, " %s", *pp++); - } + dump_sort_names(stderr); fputc('\n', stderr); exit(1); } } + else + { + sort_info = get_sort_info(NULL); + } /* initialize termcap */ init_termcap(interactive); @@ -602,17 +599,13 @@ restart: while ((displays == -1) || (displays-- > 0)) { - int (*compare)(const void * const, const void * const); - /* get the current stats */ get_system_info(&system_info); - compare = compares[order_index]; - /* get the current set of processes */ processes = - get_process_info(&system_info, &ps, compare); + get_process_info(&system_info, &ps, sort_info); /* display the load averages */ (*d_loadave)(system_info.last_pid, @@ -1047,7 +1040,9 @@ restart: "Order to sort: "); if (readline(tempbuf2, sizeof(tempbuf2), false) > 0) { - if ((i = string_index(tempbuf2, statics.order_names)) == -1) + const struct sort_info *new_sort_info; + + if ((new_sort_info = get_sort_info(tempbuf2)) == NULL) { new_message(MT_standout, " %s: unrecognized sorting order", tempbuf2); @@ -1055,7 +1050,7 @@ restart: } else { - order_index = i; + sort_info = new_sort_info; } putchar('\r'); } diff --git a/usr.bin/top/utils.c b/usr.bin/top/utils.c index cde89a211b53..a8ddb3eb63a0 100644 --- a/usr.bin/top/utils.c +++ b/usr.bin/top/utils.c @@ -116,27 +116,6 @@ digits(int val) return(cnt); } -/* - * string_index(string, array) - find string in array and return index - */ - -int -string_index(const char *string, const char * const *array) -{ - size_t i = 0; - - while (*array != NULL) - { - if (strcmp(string, *array) == 0) - { - return(i); - } - array++; - i++; - } - return(-1); -} - /* * argparse(line, cntp) - parse arguments in string "line", separating them * out into an argv-like array, and setting *cntp to the number of diff --git a/usr.bin/top/utils.h b/usr.bin/top/utils.h index a730e339d200..bbc63803b6e1 100644 --- a/usr.bin/top/utils.h +++ b/usr.bin/top/utils.h @@ -19,6 +19,5 @@ const char **argparse(char *, int *); long percentages(int, int *, long *, long *, long *); const char *format_time(long); char *format_k(int64_t); -int string_index(const char *string, const char * const *array); int find_pid(pid_t pid);