From: Christian Goeschel Ndjomouo Date: Thu, 23 Apr 2026 01:01:43 +0000 (-0400) Subject: tests: (helpers) simple tool to create a child process X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=de4e565ba60a7fac32ceee306a462a796ed259b1;p=thirdparty%2Futil-linux.git tests: (helpers) simple tool to create a child process This basic helper program can be used to create a child process to test process attribute inheritances between parent and child processes, e.g. real-time scheduling attributes with chrt(1) or utilization clamp settings with uclampset(1), where options like --reset-on-fork need to be tested. Signed-off-by: Christian Goeschel Ndjomouo --- diff --git a/meson.build b/meson.build index 48070b741..0e5248da2 100644 --- a/meson.build +++ b/meson.build @@ -4006,6 +4006,16 @@ if not is_disabler(exe) exes += exe endif +exe = executable( + 'test_child_create', + 'tests/helpers/test_child_create.c', + include_directories : includes, + 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 e68d0b3e3..07a147382 100644 --- a/tests/commands.sh +++ b/tests/commands.sh @@ -5,6 +5,7 @@ TS_TESTUSER=${TS_TESTUSER:-"nobody"} TS_HELPER_BOILERPLATE="${ts_helpersdir}test_boilerplate" TS_HELPER_BYTESWAP="${ts_helpersdir}test_byteswap" TS_HELPER_CANONICALIZE="${ts_helpersdir}test_canonicalize" +TS_HELPER_CHILD_CREATE="${ts_helpersdir}test_child_create" TS_HELPER_COLORS="${ts_helpersdir}test_colors" TS_HELPER_CONFIGS="${ts_helpersdir}test_configs" TS_HELPER_CPUSET="${ts_helpersdir}test_cpuset" diff --git a/tests/helpers/Makemodule.am b/tests/helpers/Makemodule.am index 1e02e68a7..d374c0db1 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_child_create +test_child_create_SOURCES = tests/helpers/test_child_create.c +test_child_create_LDADD = $(LDADD) libcommon.la diff --git a/tests/helpers/test_child_create.c b/tests/helpers/test_child_create.c new file mode 100644 index 000000000..1e06659e0 --- /dev/null +++ b/tests/helpers/test_child_create.c @@ -0,0 +1,104 @@ +/* + * 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 "strutils.h" + +#define DEFAULT_CHILD_SLEEP_SEC 2 +#define DEFAULT_FORK_DELAY_SEC 1 + +static void __attribute__((__noreturn__)) usage(void) +{ + printf("%s [options] \n\n", program_invocation_short_name); + fputs("Options:\n", stdout); + fputs(" -d, --delay delay (in seconds) before forking\n", stdout); + fputs(" -h, --help show this usage information\n", stdout); + + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + int c, status, rc = 0; + uint16_t sleep_time = DEFAULT_CHILD_SLEEP_SEC; + uint16_t fork_delay = DEFAULT_FORK_DELAY_SEC; + pid_t pid = 0; + + static const struct option longopts[] = { + { "delay", 1, NULL, 'd' }, + { "help", 0, NULL, 'h' }, + { NULL, 0, NULL, 0 }, + }; + + while((c = getopt_long(argc, argv, "hd:", longopts, NULL)) != -1) { + switch(c) { + case 'd': + fork_delay = strtou16_or_err(optarg, "invalid --delay 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) + sleep_time = strtou16_or_err(argv[optind], "invalid argument"); + + + printf("Parent PID: %d\n", getpid()); + fflush(stdout); + + sleep(fork_delay); + + errno = 0; + pid = fork(); + switch (pid) { + case -1: + err(EXIT_FAILURE, "failed to create child process"); + case 0: + errno = 0; + rc = prctl(PR_SET_PDEATHSIG, SIGTERM); + if (rc < 0) + err(EXIT_FAILURE, "prctl() failed"); + + sleep(sleep_time); + return EXIT_SUCCESS; + default: + printf("Child PID: %d\n", pid); + fflush(stdout); + + errno = 0; + rc = waitpid(pid, &status, 0); + if (rc < 0 && errno != ECHILD) { + err(EXIT_FAILURE, "waitpid() failed for child process %d", pid); + } + } + return EXIT_SUCCESS; +}