git: 5f72125339b1 - main - top: improve sort field storage/lookup

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Sat, 09 Aug 2025 16:00:50 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=5f72125339b1d14d1b04329ac561354f5e8133fe

commit 5f72125339b1d14d1b04329ac561354f5e8133fe
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-08-09 16:00:31 +0000
Commit:     Kyle Evans <kevans@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);