From: Christian Goeschel Ndjomouo Date: Wed, 22 Apr 2026 00:56:26 +0000 (-0400) Subject: tests: (helpers) add a thread creation helper X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=fec6b8bcdbeb4af1d05cbfe9b69e9b9be96da9d5;p=thirdparty%2Futil-linux.git tests: (helpers) add a thread creation helper This simple helper can be used to create an arbitrary amount of threads to be used in test scripts for tools like chrt(1). chrt(1) can perform tasks on multiple threads for a process and to conveniently test this 'test_threads_create' can be used to spawn threads for a specified amount of time to act on. Signed-off-by: Christian Goeschel Ndjomouo --- diff --git a/meson.build b/meson.build index 185f55977..bd5adb47c 100644 --- a/meson.build +++ b/meson.build @@ -4005,6 +4005,17 @@ if not is_disabler(exe) exes += exe endif +exe = executable( + 'test_threads_create', + 'tests/helpers/test_threads_create.c', + include_directories : includes, + dependencies : thread_libs, + link_with : lib_common, + build_by_default: program_tests) +if not is_disabler(exe) + exes += exe +endif + ############################################################ if conf.get('HAVE_OPENAT').to_string() == '1' diff --git a/tests/commands.sh b/tests/commands.sh index f1cdf52a6..4c08c4416 100644 --- a/tests/commands.sh +++ b/tests/commands.sh @@ -54,6 +54,7 @@ TS_HELPER_SIGSTATE="${ts_helpersdir}test_sigstate" TS_HELPER_STRERROR="${ts_helpersdir}test_strerror" TS_HELPER_STRUTILS="${ts_helpersdir}test_strutils" TS_HELPER_SYSINFO="${ts_helpersdir}test_sysinfo" +TS_HELPER_THREADS_CREATE="${ts_helpersdir}test_threads_create" TS_HELPER_TIOCSTI="${ts_helpersdir}test_tiocsti" TS_HELPER_UUID_PARSER="${ts_helpersdir}test_uuid_parser" TS_HELPER_UUID_NAMESPACE="${ts_helpersdir}test_uuid_namespace" diff --git a/tests/helpers/Makemodule.am b/tests/helpers/Makemodule.am index bdf2d2d8d..4b575ae38 100644 --- a/tests/helpers/Makemodule.am +++ b/tests/helpers/Makemodule.am @@ -63,3 +63,7 @@ endif check_PROGRAMS += test_open_twice test_open_twice_SOURCES = tests/helpers/test_open_twice.c + +check_PROGRAMS += test_threads_create +test_threads_create_SOURCES = tests/helpers/test_threads_create.c +test_threads_create_LDADD = $(LDADD) libcommon.la $(PTHREAD_LIBS) diff --git a/tests/helpers/test_threads_create.c b/tests/helpers/test_threads_create.c new file mode 100644 index 000000000..d50d74f83 --- /dev/null +++ b/tests/helpers/test_threads_create.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2026 Christian Goeschel Ndjomouo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xalloc.h" +#include "strutils.h" + +static void __attribute__((__noreturn__)) usage(void) +{ + printf("%s [options] \n\n", program_invocation_short_name); + fputs("Options:\n", stdout); + fputs(" -s, --sleep seconds threads should sleep (default: 3)\n", stdout); + + exit(EXIT_SUCCESS); +} + +#define DEFAULT_NUM_THREADS 5 +#define DEFAULT_THREAD_SLEEP_SEC 3 + +struct thread_ctl { + int thread_id; + uint16_t sleep_time; +}; + +static void* thread_func(void* arg) +{ + pid_t tid = syscall(SYS_gettid); + struct thread_ctl *tctl = (struct thread_ctl *)arg; + int id = tctl->thread_id + 2; + uint16_t sec = tctl->sleep_time; + + printf("Thread %d: %d\n", id, tid); + sleep(sec); + + free(arg); + return NULL; +} + +int main(int argc, char **argv) +{ + int c, rc = 0; + uint16_t sleep_time = DEFAULT_THREAD_SLEEP_SEC; + size_t t_cnt = DEFAULT_NUM_THREADS; + + static const struct option longopts[] = { + { "sleep", 1, NULL, 's' }, + { "help", 0, NULL, 'h' }, + { NULL, 0, NULL, 0 }, + }; + + while((c = getopt_long(argc, argv, "hs:", longopts, NULL)) != -1) { + switch(c) { + case 's': + sleep_time = strtou16_or_err(optarg, "invalid --sleep argument"); + break; + case 'h': + usage(); + break; + default: + err(EXIT_FAILURE, "try --help"); + } + } + + if (argc - optind > 1) + errx(EXIT_FAILURE, "too many arguments"); + + if (optind < argc) + t_cnt = strtou16_or_err(argv[optind], "invalid argument"); + + printf("Thread 1: %d\n", getpid()); + + pthread_t *threads = xcalloc(t_cnt, sizeof(pthread_t)); + + for (size_t i = 0; i < t_cnt; i++) { + struct thread_ctl *tctl = xmalloc(sizeof(struct thread_ctl)); + + tctl->thread_id = i; + tctl->sleep_time = sleep_time; + + rc = pthread_create(&threads[i], NULL, thread_func, tctl); + if (rc) + errx(EXIT_FAILURE, "failed to create thread %zu: %s", i, strerror(rc)); + } + + for (size_t i = 0; i < t_cnt; i++) { + rc = pthread_join(threads[i], NULL); + if (rc) + errx(EXIT_FAILURE, "failed to join thread %zu: %s", i, strerror(rc)); + } + + free(threads); + return EXIT_SUCCESS; +}