From 8eac5c27ec0b16c2ef8b7af3b0d0dca527adbb05 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 6 Nov 2025 11:33:26 -0800 Subject: [PATCH] tests: kernel/smp: rework signals in stress test The k_poll signal and event code is reworked a bit such that signal is raised and event is processed only when appropriate. We want to avoid changing the internal of event and signal objects at the same time we try to raise the signal (which changes the internal states too). In addition, print out some information on how many signals raised and received to indicate we are actually switching all related threads. Fixes #98136 Signed-off-by: Daniel Leung --- tests/kernel/smp/src/main.c | 59 +++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/tests/kernel/smp/src/main.c b/tests/kernel/smp/src/main.c index 990d56ebc18a3..84d29893e767f 100644 --- a/tests/kernel/smp/src/main.c +++ b/tests/kernel/smp/src/main.c @@ -1111,6 +1111,12 @@ ZTEST(smp, test_inc_concurrency) "total count %d is wrong(M)", global_cnt); } +/** Keep track of how many signals raised. */ +static unsigned int t_signal_raised; + +/** Keep track of how many signals received per thread. */ +static unsigned int t_signals_rcvd[MAX_NUM_THREADS]; + /** * @brief Torture test for context switching code * @@ -1125,27 +1131,56 @@ static void process_events(void *arg0, void *arg1, void *arg2) ARG_UNUSED(arg2); uintptr_t id = (uintptr_t) arg0; + unsigned int signaled; + int result; while (1) { - k_poll(&tevent[id], 1, K_FOREVER); + /* Retry if no event(s) are ready. + * For example, -EINTR where polling is interrupted. + */ + if (k_poll(&tevent[id], 1, K_FOREVER) != 0) { + continue; + } - if (tevent[id].signal->result != 0x55) { + /* Grab the raised signal. */ + k_poll_signal_check(tevent[id].signal, &signaled, &result); + + /* Check correct result. */ + if (result != 0x55) { ztest_test_fail(); } - tevent[id].signal->signaled = 0; - tevent[id].state = K_POLL_STATE_NOT_READY; + t_signals_rcvd[id]++; - k_poll_signal_reset(&tsignal[id]); + /* Reset both event and signal. */ + tevent[id].state = K_POLL_STATE_NOT_READY; + tevent[id].signal->result = 0; + k_poll_signal_reset(tevent[id].signal); } } static void signal_raise(void *arg0, void *arg1, void *arg2) { unsigned int num_threads = arch_num_cpus(); + unsigned int signaled; + int result; + + t_signal_raised = 0U; while (1) { for (uintptr_t i = 0; i < num_threads; i++) { + /* Only raise signal when it is okay to do so. + * We don't want to raise a signal while the signal + * and the associated event are still in the process + * of being reset (see above). + */ + k_poll_signal_check(tevent[i].signal, &signaled, &result); + + if (signaled != 0U) { + continue; + } + + t_signal_raised++; k_poll_signal_raise(&tsignal[i], 0x55); } } @@ -1169,6 +1204,8 @@ ZTEST(smp, test_smp_switch_torture) } for (uintptr_t i = 0; i < num_threads; i++) { + t_signals_rcvd[i] = 0; + k_poll_signal_init(&tsignal[i]); k_poll_event_init(&tevent[i], K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &tsignal[i]); @@ -1190,6 +1227,18 @@ ZTEST(smp, test_smp_switch_torture) k_thread_abort(&tthread[i]); k_thread_join(&tthread[i], K_FOREVER); } + + TC_PRINT("Total signals raised %u\n", t_signal_raised); + + for (unsigned int i = 0; i < num_threads; i++) { + TC_PRINT("Thread #%d received %u signals\n", i, t_signals_rcvd[i]); + } + + /* Check if we at least have done some switching. */ + for (unsigned int i = 0; i < num_threads; i++) { + zassert_not_equal(0, t_signals_rcvd[i], + "Thread #%d has not received any signals", i); + } } /**