On Mon, Apr 08 2024 at 20:49, Oleg Nesterov wrote: > To me this test should simply do > > ksft_test_result(!ctd_failed, "check signal distribution\n"); > return 0; Right. > but I am not familiar with tools/testing/selftests/ and I am not sure > I understand the last email from Thomas. The discussion started about running new tests on older kernels. As this is a feature and not a bug fix that obviously fails on older kernels. So something like the uncompiled below should work. Thanks, tglx --- --- a/tools/testing/selftests/timers/posix_timers.c +++ b/tools/testing/selftests/timers/posix_timers.c @@ -184,80 +184,83 @@ static int check_timer_create(int which) return 0; } -int remain; -__thread int got_signal; +static pthread_t ctd_thread; +static volatile int ctd_count, ctd_failed; -static void *distribution_thread(void *arg) +static void ctd_sighandler(int sig) { - while (__atomic_load_n(&remain, __ATOMIC_RELAXED)); - return NULL; -} - -static void distribution_handler(int nr) -{ - if (!__atomic_exchange_n(&got_signal, 1, __ATOMIC_RELAXED)) - __atomic_fetch_sub(&remain, 1, __ATOMIC_RELAXED); + if (pthread_self() != ctd_thread) + ctd_failed = 1; + ctd_count--; } -/* - * Test that all running threads _eventually_ receive CLOCK_PROCESS_CPUTIME_ID - * timer signals. This primarily tests that the kernel does not favour any one. - */ -static int check_timer_distribution(void) +static void *ctd_thread_func(void *arg) { - int err, i; - timer_t id; - const int nthreads = 10; - pthread_t threads[nthreads]; struct itimerspec val = { .it_value.tv_sec = 0, .it_value.tv_nsec = 1000 * 1000, .it_interval.tv_sec = 0, .it_interval.tv_nsec = 1000 * 1000, }; + timer_t id; - remain = nthreads + 1; /* worker threads + this thread */ - signal(SIGALRM, distribution_handler); - err = timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id); - if (err < 0) { - ksft_perror("Can't create timer"); - return -1; - } - err = timer_settime(id, 0, &val, NULL); - if (err < 0) { - ksft_perror("Can't set timer"); - return -1; - } + /* 1/10 seconds to ensure the leader sleeps */ + usleep(10000); - for (i = 0; i < nthreads; i++) { - err = pthread_create(&threads[i], NULL, distribution_thread, - NULL); - if (err) { - ksft_print_msg("Can't create thread: %s (%d)\n", - strerror(errno), errno); - return -1; - } - } + ctd_count = 100; + if (timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id)) + return "Can't create timer"; + if (timer_settime(id, 0, &val, NULL)) + return "Can't set timer"; - /* Wait for all threads to receive the signal. */ - while (__atomic_load_n(&remain, __ATOMIC_RELAXED)); + while (ctd_count > 0 && !ctd_failed) + ; - for (i = 0; i < nthreads; i++) { - err = pthread_join(threads[i], NULL); - if (err) { - ksft_print_msg("Can't join thread: %s (%d)\n", - strerror(errno), errno); - return -1; - } - } + if (timer_delete(id)) + return "Can't delete timer"; - if (timer_delete(id)) { - ksft_perror("Can't delete timer"); + return NULL; +} + +static bool check_kernel_version(unsigned int min_major, unsigned int min_minor) +{ + unsigned int major, minor; + struct utsname info; + + uname(&info); + if (sscanf(info.release, "%u.%u.", &major, &minor) != 2) + ksft_exit_fail(); + return major > min_major || (major == min_major && minor >= min_minor); +} + +/* + * Test that only the running thread receives the timer signal. + */ +static int check_timer_distribution(void) +{ + const char *errmsg; + + if (!check_kernel_version(6, 3)) { + ksft_test_result_skip("check signal distribution (old kernel)\n"); return 0; } - ksft_test_result_pass("check_timer_distribution\n"); + signal(SIGALRM, ctd_sighandler); + + errmsg = "Can't create thread"; + if (pthread_create(&ctd_thread, NULL, ctd_thread_func, NULL)) + goto err; + + errmsg = "Can't join thread"; + if (pthread_join(ctd_thread, (void **)&errmsg) || errmsg) + goto err; + + ksft_test_result(!ctd_failed, "check signal distribution\n"); return 0; + +err: + ksft_print_msg(errmsg); + return -1; } int main(int argc, char **argv)