public inbox for linux-rt-users@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1] cyclictest: Generate optstring dynamically from long_options
@ 2026-01-10 11:37 Costa Shulyupin
  2026-01-12 21:13 ` Crystal Wood
  0 siblings, 1 reply; 8+ messages in thread
From: Costa Shulyupin @ 2026-01-10 11:37 UTC (permalink / raw)
  To: linux-rt-users, John Kacur
  Cc: Sebastian Andrzej Siewior, Tomas Glozar, Crystal Wood,
	Costa Shulyupin

The hard-coded optstring in cyclictest has become bloated and
error-prone, even resulting in a duplicate 'D:' entry.

Modify the long_options array to use the 'val' member of struct option
to store the corresponding short-option character. Add getopt_auto() to
automatically construct the optstring from this array at runtime.

This eliminates the need to manually maintain a redundant optstring and
prevents synchronization errors when adding or modifying command-line
options.

Signed-off-by: Costa Shulyupin <costa.shul@redhat.com>
---
 Makefile                    |   3 +-
 src/cyclictest/cyclictest.c | 147 +++++++++++++++---------------------
 src/include/opt.h           |  11 +++
 src/lib/opt.c               |  29 +++++++
 4 files changed, 101 insertions(+), 89 deletions(-)
 create mode 100644 src/include/opt.h
 create mode 100644 src/lib/opt.c

diff --git a/Makefile b/Makefile
index e3d02cd25924..12bd42850bb1 100644
--- a/Makefile
+++ b/Makefile
@@ -194,7 +194,8 @@ oslat: $(OBJDIR)/oslat.o $(OBJDIR)/librttest.a $(OBJDIR)/librttestnuma.a
 	bzip2 -c $< > $@
 
 LIBOBJS =$(addprefix $(OBJDIR)/,rt-error.o rt-get_cpu.o rt-sched.o rt-utils.o \
-	histogram.o)
+	histogram.o opt.o)
+
 $(OBJDIR)/librttest.a: $(LIBOBJS)
 	$(AR) rcs $@ $^
 
diff --git a/src/cyclictest/cyclictest.c b/src/cyclictest/cyclictest.c
index b4bce8915b43..a1566159d398 100644
--- a/src/cyclictest/cyclictest.c
+++ b/src/cyclictest/cyclictest.c
@@ -17,7 +17,6 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <getopt.h>
 #include <pthread.h>
 #include <signal.h>
 #include <sched.h>
@@ -39,6 +38,7 @@
 #include "rt-numa.h"
 #include "rt-error.h"
 #include "histogram.h"
+#include "opt.h"
 
 #include <bionic.h>
 
@@ -1078,17 +1078,10 @@ static char *policyname(int policy)
 
 
 enum option_values {
-	OPT_AFFINITY=1, OPT_BREAKTRACE, OPT_CLOCK,
-	OPT_DEFAULT_SYSTEM, OPT_DISTANCE, OPT_DURATION, OPT_LATENCY,
-	OPT_FIFO, OPT_HISTOGRAM, OPT_HISTOFALL, OPT_HISTFILE,
-	OPT_INTERVAL, OPT_JSON, OPT_MAINAFFINITY, OPT_LOOPS, OPT_MLOCKALL,
-	OPT_REFRESH, OPT_NANOSLEEP, OPT_NSECS, OPT_OSCOPE, OPT_PRIORITY,
-	OPT_QUIET, OPT_PRIOSPREAD, OPT_RELATIVE, OPT_RESOLUTION,
-	OPT_SYSTEM, OPT_SMP, OPT_THREADS, OPT_TRIGGER,
-	OPT_TRIGGER_NODES, OPT_UNBUFFERED, OPT_NUMA, OPT_VERBOSE,
-	OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, OPT_NUMOPTS,
-	OPT_ALIGNED, OPT_SECALIGNED, OPT_LAPTOP, OPT_SMI,
-	OPT_TRACEMARK, OPT_POSIX_TIMERS, OPT_DEEPEST_IDLE_STATE,
+	OPT_DEFAULT_SYSTEM, OPT_LATENCY, OPT_HISTFILE, OPT_JSON,
+	OPT_MAINAFFINITY, OPT_PRIOSPREAD, OPT_SECALIGNED, OPT_SMI,
+	OPT_TRIGGER, OPT_TRIGGER_NODES, OPT_TRACEMARK, OPT_DBGCYCLIC,
+	OPT_POLICY, OPT_HELP, OPT_LAPTOP, OPT_DEEPEST_IDLE_STATE,
 };
 
 /* Process commandline options */
@@ -1097,63 +1090,63 @@ static void process_options(int argc, char *argv[], int max_cpus)
 	int error = 0;
 	int option_affinity = 0;
 
+	/*
+	 * Options for getopt
+	 * Ordered alphabetically by single letter name
+	 */
+	static struct option long_options[] = {
+		{"affinity",         optional_argument, NULL, 'a'},
+		{"aligned",          optional_argument, NULL, 'A'},
+		{"breaktrace",       required_argument, NULL, 'b'},
+		{"clock",            required_argument, NULL, 'c'},
+		{"default-system",   no_argument,       NULL, OPT_DEFAULT_SYSTEM },
+		{"distance",         required_argument, NULL, 'd'},
+		{"duration",         required_argument, NULL, 'D'},
+		{"latency",          required_argument, NULL, OPT_LATENCY },
+		{"fifo",             required_argument, NULL, 'F'},
+		{"histogram",        required_argument, NULL, 'h'},
+		{"histofall",        required_argument, NULL, 'H'},
+		{"histfile",	     required_argument, NULL, OPT_HISTFILE },
+		{"interval",         required_argument, NULL, 'i'},
+		{"json",             required_argument, NULL, OPT_JSON },
+		{"laptop",	     no_argument,	NULL, OPT_LAPTOP },
+		{"loops",            required_argument, NULL, 'l'},
+		{"mainaffinity",     required_argument, NULL, OPT_MAINAFFINITY},
+		{"mlockall",         no_argument,       NULL, 'm'},
+		{"refresh_on_max",   no_argument,       NULL, 'M'},
+		{"nsecs",            no_argument,       NULL, 'N'},
+		{"oscope",           required_argument, NULL, 'o'},
+		{"priority",         required_argument, NULL, 'p'},
+		{"quiet",            no_argument,       NULL, 'q'},
+		{"priospread",       no_argument,       NULL, OPT_PRIOSPREAD },
+		{"relative",         no_argument,       NULL, 'r'},
+		{"resolution",       no_argument,       NULL, 'R'},
+		{"secaligned",       optional_argument, NULL, OPT_SECALIGNED },
+		{"system",           no_argument,       NULL, 's'},
+		{"smi",              no_argument,       NULL, OPT_SMI },
+		{"smp",              no_argument,       NULL, 'S'},
+		{"spike",	     required_argument, NULL, OPT_TRIGGER },
+		{"spike-nodes",	     required_argument, NULL, OPT_TRIGGER_NODES },
+		{"threads",          optional_argument, NULL, 't'},
+		{"tracemark",	     no_argument,	NULL, OPT_TRACEMARK },
+		{"unbuffered",       no_argument,       NULL, 'u'},
+		{"verbose",          no_argument,       NULL, 'v'},
+		{"dbg_cyclictest",   no_argument,       NULL, OPT_DBGCYCLIC },
+		{"policy",           required_argument, NULL, OPT_POLICY },
+		{"help",             no_argument,       NULL, OPT_HELP },
+		{"posix_timers",     no_argument,	NULL, 'x'},
+		{"deepest-idle-state", required_argument,	NULL, OPT_DEEPEST_IDLE_STATE },
+		{NULL, 0, NULL, 0 },
+	};
+	char *opts = build_optstring(long_options);
+
 	for (;;) {
-		int option_index = 0;
-		/*
-		 * Options for getopt
-		 * Ordered alphabetically by single letter name
-		 */
-		static struct option long_options[] = {
-			{"affinity",         optional_argument, NULL, OPT_AFFINITY},
-			{"aligned",          optional_argument, NULL, OPT_ALIGNED },
-			{"breaktrace",       required_argument, NULL, OPT_BREAKTRACE },
-			{"clock",            required_argument, NULL, OPT_CLOCK },
-			{"default-system",   no_argument,       NULL, OPT_DEFAULT_SYSTEM },
-			{"distance",         required_argument, NULL, OPT_DISTANCE },
-			{"duration",         required_argument, NULL, OPT_DURATION },
-			{"latency",          required_argument, NULL, OPT_LATENCY },
-			{"fifo",             required_argument, NULL, OPT_FIFO },
-			{"histogram",        required_argument, NULL, OPT_HISTOGRAM },
-			{"histofall",        required_argument, NULL, OPT_HISTOFALL },
-			{"histfile",	     required_argument, NULL, OPT_HISTFILE },
-			{"interval",         required_argument, NULL, OPT_INTERVAL },
-			{"json",             required_argument, NULL, OPT_JSON },
-			{"laptop",	     no_argument,	NULL, OPT_LAPTOP },
-			{"loops",            required_argument, NULL, OPT_LOOPS },
-			{"mainaffinity",     required_argument, NULL, OPT_MAINAFFINITY},
-			{"mlockall",         no_argument,       NULL, OPT_MLOCKALL },
-			{"refresh_on_max",   no_argument,       NULL, OPT_REFRESH },
-			{"nsecs",            no_argument,       NULL, OPT_NSECS },
-			{"oscope",           required_argument, NULL, OPT_OSCOPE },
-			{"priority",         required_argument, NULL, OPT_PRIORITY },
-			{"quiet",            no_argument,       NULL, OPT_QUIET },
-			{"priospread",       no_argument,       NULL, OPT_PRIOSPREAD },
-			{"relative",         no_argument,       NULL, OPT_RELATIVE },
-			{"resolution",       no_argument,       NULL, OPT_RESOLUTION },
-			{"secaligned",       optional_argument, NULL, OPT_SECALIGNED },
-			{"system",           no_argument,       NULL, OPT_SYSTEM },
-			{"smi",              no_argument,       NULL, OPT_SMI },
-			{"smp",              no_argument,       NULL, OPT_SMP },
-			{"spike",	     required_argument, NULL, OPT_TRIGGER },
-			{"spike-nodes",	     required_argument, NULL, OPT_TRIGGER_NODES },
-			{"threads",          optional_argument, NULL, OPT_THREADS },
-			{"tracemark",	     no_argument,	NULL, OPT_TRACEMARK },
-			{"unbuffered",       no_argument,       NULL, OPT_UNBUFFERED },
-			{"verbose",          no_argument,       NULL, OPT_VERBOSE },
-			{"dbg_cyclictest",   no_argument,       NULL, OPT_DBGCYCLIC },
-			{"policy",           required_argument, NULL, OPT_POLICY },
-			{"help",             no_argument,       NULL, OPT_HELP },
-			{"posix_timers",     no_argument,	NULL, OPT_POSIX_TIMERS },
-			{"deepest-idle-state", required_argument,	NULL, OPT_DEEPEST_IDLE_STATE },
-			{NULL, 0, NULL, 0 },
-		};
-		int c = getopt_long(argc, argv, "a::A::b:c:d:D:F:h:H:i:l:MNo:p:mqrRsSt::uvD:x",
-				    long_options, &option_index);
+		int c = getopt_long(argc, argv, opts, long_options, NULL);
+
 		if (c == -1)
 			break;
 		switch (c) {
 		case 'a':
-		case OPT_AFFINITY:
 			option_affinity = 1;
 			/* smp sets AFFINITY_USEALL in OPT_SMP */
 			if (smp)
@@ -1181,7 +1174,6 @@ static void process_options(int argc, char *argv[], int max_cpus)
 					numa_bitmask_weight(affinity_mask));
 			break;
 		case 'A':
-		case OPT_ALIGNED:
 			aligned = 1;
 			if (optarg != NULL)
 				offset = atoi(optarg) * 1000;
@@ -1191,29 +1183,22 @@ static void process_options(int argc, char *argv[], int max_cpus)
 				offset = 0;
 			break;
 		case 'b':
-		case OPT_BREAKTRACE:
 			tracelimit = atoi(optarg); break;
 		case 'c':
-		case OPT_CLOCK:
 			clocksel = atoi(optarg); break;
 		case OPT_DEFAULT_SYSTEM:
 			power_management = 1; break;
 		case 'd':
-		case OPT_DISTANCE:
 			distance = atoi(optarg); break;
 		case 'D':
-		case OPT_DURATION:
 			duration = parse_time_string(optarg); break;
 		case 'F':
-		case OPT_FIFO:
 			use_fifo = 1;
 			strncpy(fifopath, optarg, strnlen(optarg, MAX_PATH-1));
 			break;
 		case 'H':
-		case OPT_HISTOFALL:
 			histofall = 1; /* fall through */
 		case 'h':
-		case OPT_HISTOGRAM:
 			histogram = atoi(optarg);
 			if (!histogram)
 				display_help(1);
@@ -1223,13 +1208,11 @@ static void process_options(int argc, char *argv[], int max_cpus)
 			strncpy(histfile, optarg, strnlen(optarg, MAX_PATH-1));
 			break;
 		case 'i':
-		case OPT_INTERVAL:
 			interval = atoi(optarg); break;
 		case OPT_JSON:
 			strncpy(jsonfile, optarg, strnlen(optarg, MAX_PATH-1));
 			break;
 		case 'l':
-		case OPT_LOOPS:
 			max_cycles = atoi(optarg); break;
 		case OPT_MAINAFFINITY:
 			if (optarg) {
@@ -1242,31 +1225,23 @@ static void process_options(int argc, char *argv[], int max_cpus)
 			}
 			break;
 		case 'm':
-		case OPT_MLOCKALL:
 			lockall = 1; break;
 		case 'M':
-		case OPT_REFRESH:
 			refresh_on_max = 1; break;
 		case 'N':
-		case OPT_NSECS:
 			use_nsecs = 1; break;
 		case 'o':
-		case OPT_OSCOPE:
 			oscope_reduction = atoi(optarg); break;
 		case 'p':
-		case OPT_PRIORITY:
 			priority = atoi(optarg);
 			if (policy != SCHED_FIFO && policy != SCHED_RR)
 				policy = SCHED_FIFO;
 			break;
 		case 'q':
-		case OPT_QUIET:
 			quiet = 1; break;
 		case 'r':
-		case OPT_RELATIVE:
 			timermode = TIMER_RELTIME; break;
 		case 'R':
-		case OPT_RESOLUTION:
 			check_clock_resolution = 1; break;
 		case OPT_SECALIGNED:
 			secaligned = 1;
@@ -1278,10 +1253,8 @@ static void process_options(int argc, char *argv[], int max_cpus)
 				offset = 0;
 			break;
 		case 's':
-		case OPT_SYSTEM:
 			use_system = MODE_SYS_OFFSET; break;
 		case 'S':
-		case OPT_SMP: /* SMP testing */
 			if (numa)
 				fatal("numa and smp options are mutually exclusive\n");
 			smp = 1;
@@ -1289,7 +1262,6 @@ static void process_options(int argc, char *argv[], int max_cpus)
 			setaffinity = AFFINITY_USEALL;
 			break;
 		case 't':
-		case OPT_THREADS:
 			if (smp) {
 				warn("-t ignored due to smp mode\n");
 				break;
@@ -1309,12 +1281,10 @@ static void process_options(int argc, char *argv[], int max_cpus)
 				trigger_list_size = atoi(optarg);
 			break;
 		case 'u':
-		case OPT_UNBUFFERED:
 			setvbuf(stdout, NULL, _IONBF, 0); break;
 		case 'v':
-		case OPT_VERBOSE: verbose = 1; break;
+			verbose = 1; break;
 		case 'x':
-		case OPT_POSIX_TIMERS:
 			use_nanosleep = MODE_CYCLIC; break;
 		case '?':
 		case OPT_HELP:
@@ -1437,6 +1407,7 @@ static void process_options(int argc, char *argv[], int max_cpus)
 			rt_bitmask_free(affinity_mask);
 		display_help(1);
 	}
+	free(opts);
 }
 
 static int check_timer(void)
diff --git a/src/include/opt.h b/src/include/opt.h
new file mode 100644
index 000000000000..4d01917be024
--- /dev/null
+++ b/src/include/opt.h
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#include <getopt.h>
+
+/*
+ * build_optstring - allocate and build optstring from long_options
+ *
+ * Free resulted optstring aftre use.
+ */
+char *build_optstring(const struct option *long_opts);
diff --git a/src/lib/opt.c b/src/lib/opt.c
new file mode 100644
index 000000000000..d235788001d9
--- /dev/null
+++ b/src/lib/opt.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdlib.h>
+
+#include "opt.h"
+
+char *build_optstring(const struct option *long_opts)
+{
+	char *opts = NULL;
+	int n = 0;
+
+	for (int i = 0; long_opts[i].name; i++) {
+		opts = realloc(opts, n + 4);
+
+		if (long_opts[i].flag || long_opts[i].val < 32 || long_opts[i].val > 127)
+			continue;
+
+		opts[n++] = long_opts[i].val;
+
+		if (long_opts[i].has_arg == required_argument)
+			opts[n++] = ':';
+		else if (long_opts[i].has_arg == optional_argument) {
+			opts[n++] = ':';
+			opts[n++] = ':';
+		}
+	}
+	opts[n] = '\0';
+
+	return opts;
+}
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] cyclictest: Generate optstring dynamically from long_options
  2026-01-10 11:37 [PATCH v1] cyclictest: Generate optstring dynamically from long_options Costa Shulyupin
@ 2026-01-12 21:13 ` Crystal Wood
  2026-01-13  8:13   ` Sebastian Andrzej Siewior
  2026-01-13 12:45   ` Costa Shulyupin
  0 siblings, 2 replies; 8+ messages in thread
From: Crystal Wood @ 2026-01-12 21:13 UTC (permalink / raw)
  To: Costa Shulyupin, linux-rt-users, John Kacur
  Cc: Sebastian Andrzej Siewior, Tomas Glozar

On Sat, 2026-01-10 at 13:37 +0200, Costa Shulyupin wrote:

> diff --git a/src/include/opt.h b/src/include/opt.h
> new file mode 100644
> index 000000000000..4d01917be024
> --- /dev/null
> +++ b/src/include/opt.h
> @@ -0,0 +1,11 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#pragma once
> +
> +#include <getopt.h>
> +
> +/*
> + * build_optstring - allocate and build optstring from long_options
> + *
> + * Free resulted optstring aftre use.
> + */

"Free resulting optstring after use"

> +char *build_optstring(const struct option *long_opts);
> diff --git a/src/lib/opt.c b/src/lib/opt.c
> new file mode 100644
> index 000000000000..d235788001d9
> --- /dev/null
> +++ b/src/lib/opt.c
> @@ -0,0 +1,29 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#include <stdlib.h>
> +
> +#include "opt.h"
> +
> +char *build_optstring(const struct option *long_opts)
> +{
> +	char *opts = NULL;
> +	int n = 0;
> +
> +	for (int i = 0; long_opts[i].name; i++) {
> +		opts = realloc(opts, n + 4);

I realize this isn't going to be noticeable even if it ends up being a
copy each time, but linear realloc like this makes me twinge and think
of how just about every other language in common use would have a
readily available growable string implementation :-P

> +
> +		if (long_opts[i].flag || long_opts[i].val < 32 || long_opts[i].val > 127)
> +			continue;

What happens if the OPT enum grows beyond 32 entries?  It's already at
16.  Maybe start the enum at 0x100, and print an error if val is less
than that but not valid for getopt?

Why is the implementation (slightly) different here versus the rtla
patch?  We should probably use an enum in rtla instead of '4', '\1',
etc. as well.

-Crystal


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] cyclictest: Generate optstring dynamically from long_options
  2026-01-12 21:13 ` Crystal Wood
@ 2026-01-13  8:13   ` Sebastian Andrzej Siewior
  2026-01-13 10:00     ` Costa Shulyupin
  2026-01-13 23:34     ` Crystal Wood
  2026-01-13 12:45   ` Costa Shulyupin
  1 sibling, 2 replies; 8+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-01-13  8:13 UTC (permalink / raw)
  To: Crystal Wood; +Cc: Costa Shulyupin, linux-rt-users, John Kacur, Tomas Glozar

On 2026-01-12 15:13:22 [-0600], Crystal Wood wrote:
> > --- /dev/null
> > +++ b/src/lib/opt.c
> > @@ -0,0 +1,29 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +#include <stdlib.h>
> > +
> > +#include "opt.h"
> > +
> > +char *build_optstring(const struct option *long_opts)
> > +{
> > +	char *opts = NULL;
> > +	int n = 0;
> > +
> > +	for (int i = 0; long_opts[i].name; i++) {
> > +		opts = realloc(opts, n + 4);
> 
> I realize this isn't going to be noticeable even if it ends up being a
> copy each time, but linear realloc like this makes me twinge and think
> of how just about every other language in common use would have a
> readily available growable string implementation :-P

and assume you never run out of memory…

> > +
> > +		if (long_opts[i].flag || long_opts[i].val < 32 || long_opts[i].val > 127)
> > +			continue;
> 
> What happens if the OPT enum grows beyond 32 entries?  It's already at
> 16.  Maybe start the enum at 0x100, and print an error if val is less
> than that but not valid for getopt?
> 
> Why is the implementation (slightly) different here versus the rtla
> patch?  We should probably use an enum in rtla instead of '4', '\1',
> etc. as well.

GNU ARGP might be easier to parse and maintain in the long run
especially if 20 other options are added.
	https://www.gnu.org/software/libc/manual/html_node/Argp-Example-4.html

> -Crystal

Sebastian

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] cyclictest: Generate optstring dynamically from long_options
  2026-01-13  8:13   ` Sebastian Andrzej Siewior
@ 2026-01-13 10:00     ` Costa Shulyupin
  2026-01-13 11:14       ` Sebastian Andrzej Siewior
  2026-01-13 23:34     ` Crystal Wood
  1 sibling, 1 reply; 8+ messages in thread
From: Costa Shulyupin @ 2026-01-13 10:00 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Crystal Wood, linux-rt-users, John Kacur, Tomas Glozar

On Tue, 13 Jan 2026 at 10:13, Sebastian Andrzej Siewior
<bigeasy@linutronix.de> wrote:
> GNU ARGP might be easier to parse and maintain in the long run
> especially if 20 other options are added.
>         https://www.gnu.org/software/libc/manual/html_node/Argp-Example-4.html

It looks impossible to port to ARGP without CLI change: cyclictest has
options with optional arguments (e.g., -a can mean 'use all CPUs' or
-a 0,2,4 means 'use specific CPUs'). ARGP handles these differently
than getopt_long.

Costa


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] cyclictest: Generate optstring dynamically from long_options
  2026-01-13 10:00     ` Costa Shulyupin
@ 2026-01-13 11:14       ` Sebastian Andrzej Siewior
  2026-01-13 23:41         ` Crystal Wood
  0 siblings, 1 reply; 8+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-01-13 11:14 UTC (permalink / raw)
  To: Costa Shulyupin; +Cc: Crystal Wood, linux-rt-users, John Kacur, Tomas Glozar

On 2026-01-13 12:00:29 [+0200], Costa Shulyupin wrote:
> On Tue, 13 Jan 2026 at 10:13, Sebastian Andrzej Siewior
> <bigeasy@linutronix.de> wrote:
> > GNU ARGP might be easier to parse and maintain in the long run
> > especially if 20 other options are added.
> >         https://www.gnu.org/software/libc/manual/html_node/Argp-Example-4.html
> 
> It looks impossible to port to ARGP without CLI change: cyclictest has
> options with optional arguments (e.g., -a can mean 'use all CPUs' or
> -a 0,2,4 means 'use specific CPUs'). ARGP handles these differently
> than getopt_long.

I see. It looked nice and I assumed it supports the same features. But
if optional arguments to options are not supported then it is probably
not doable.

> Costa
Sebastian

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] cyclictest: Generate optstring dynamically from long_options
  2026-01-12 21:13 ` Crystal Wood
  2026-01-13  8:13   ` Sebastian Andrzej Siewior
@ 2026-01-13 12:45   ` Costa Shulyupin
  1 sibling, 0 replies; 8+ messages in thread
From: Costa Shulyupin @ 2026-01-13 12:45 UTC (permalink / raw)
  To: Crystal Wood
  Cc: linux-rt-users, John Kacur, Sebastian Andrzej Siewior,
	Tomas Glozar

On Mon, 12 Jan 2026 at 23:13, Crystal Wood <crwood@redhat.com> wrote:
> Why is the implementation (slightly) different here versus the rtla
> patch?  We should probably use an enum in rtla instead of '4', '\1',
> etc. as well.
Just another alternative idea. Let's choose the most suitable implementation.

Costa.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] cyclictest: Generate optstring dynamically from long_options
  2026-01-13  8:13   ` Sebastian Andrzej Siewior
  2026-01-13 10:00     ` Costa Shulyupin
@ 2026-01-13 23:34     ` Crystal Wood
  1 sibling, 0 replies; 8+ messages in thread
From: Crystal Wood @ 2026-01-13 23:34 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Costa Shulyupin, linux-rt-users, John Kacur, Tomas Glozar

On Tue, 2026-01-13 at 09:13 +0100, Sebastian Andrzej Siewior wrote:
> On 2026-01-12 15:13:22 [-0600], Crystal Wood wrote:
> > > --- /dev/null
> > > +++ b/src/lib/opt.c
> > > @@ -0,0 +1,29 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +#include <stdlib.h>
> > > +
> > > +#include "opt.h"
> > > +
> > > +char *build_optstring(const struct option *long_opts)
> > > +{
> > > +	char *opts = NULL;
> > > +	int n = 0;
> > > +
> > > +	for (int i = 0; long_opts[i].name; i++) {
> > > +		opts = realloc(opts, n + 4);
> > 
> > I realize this isn't going to be noticeable even if it ends up being a
> > copy each time, but linear realloc like this makes me twinge and think
> > of how just about every other language in common use would have a
> > readily available growable string implementation :-P
> 
> and assume you never run out of memory…

Exceptions are a thing, though in practice a small allocation failing
means things are pretty screwed regardless.  And it's not like each of
those error paths is getting test coverage...  For most non-critical
userspace code, might as well keep things simple and crash out on OOM
(with top-level exception/atexit cleanup in one place, if needed).

-Crystal


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1] cyclictest: Generate optstring dynamically from long_options
  2026-01-13 11:14       ` Sebastian Andrzej Siewior
@ 2026-01-13 23:41         ` Crystal Wood
  0 siblings, 0 replies; 8+ messages in thread
From: Crystal Wood @ 2026-01-13 23:41 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior, Costa Shulyupin
  Cc: linux-rt-users, John Kacur, Tomas Glozar

On Tue, 2026-01-13 at 12:14 +0100, Sebastian Andrzej Siewior wrote:
> On 2026-01-13 12:00:29 [+0200], Costa Shulyupin wrote:
> > On Tue, 13 Jan 2026 at 10:13, Sebastian Andrzej Siewior
> > <bigeasy@linutronix.de> wrote:
> > > GNU ARGP might be easier to parse and maintain in the long run
> > > especially if 20 other options are added.
> > >         https://www.gnu.org/software/libc/manual/html_node/Argp-Example-4.html
> > 
> > It looks impossible to port to ARGP without CLI change: cyclictest has
> > options with optional arguments (e.g., -a can mean 'use all CPUs' or
> > -a 0,2,4 means 'use specific CPUs'). ARGP handles these differently
> > than getopt_long.
> 
> I see. It looked nice and I assumed it supports the same features. But
> if optional arguments to options are not supported then it is probably
> not doable.

It does support optional arguments (OPTION_ARG_OPTIONAL) but
rtla/cyclictest use nonstandard syntax: "-a foo" rather than "-afoo" or
"--arg=foo".  We get away with this because there's no mixing of
argument and non-argument options to create ambiguity, and it's not
worth changing at this point.

-Crystal


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-01-13 23:41 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-10 11:37 [PATCH v1] cyclictest: Generate optstring dynamically from long_options Costa Shulyupin
2026-01-12 21:13 ` Crystal Wood
2026-01-13  8:13   ` Sebastian Andrzej Siewior
2026-01-13 10:00     ` Costa Shulyupin
2026-01-13 11:14       ` Sebastian Andrzej Siewior
2026-01-13 23:41         ` Crystal Wood
2026-01-13 23:34     ` Crystal Wood
2026-01-13 12:45   ` Costa Shulyupin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox