tests: kernel: workq: work: Fix potential race in the test

Test was setting up timer for 1 system tick and then work was
cancelled. It was assumed that work will be cancelled before
timer expires. This is the case for low frequency system clock
(e.g. qemu targets using 100Hz) but there are cases when system
clock has higher frequency (32kHz on nRF). In that case, timer
was occasionally expiring before cancellation and test was
randomly failing.

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2022-05-19 14:05:25 +02:00 committed by Carles Cufí
commit 2a2856e88e

View file

@ -694,6 +694,7 @@ static void test_1cpu_running_cancel(void)
{
struct test_running_cancel_timer *ctx = &test_running_cancel_ctx;
struct k_work *wp = &ctx->work;
static const uint32_t ms_timeout = 10;
int rc;
/* Reset state and use the blocking handler */
@ -713,7 +714,7 @@ static void test_1cpu_running_cancel(void)
ctx->submit_rc = INT_MAX;
ctx->busy_rc = INT_MAX;
k_timer_init(&ctx->timer, test_running_cancel_cb, NULL);
k_timer_start(&ctx->timer, K_TICKS(1), K_NO_WAIT);
k_timer_start(&ctx->timer, K_MSEC(ms_timeout), K_NO_WAIT);
/* Cancellation should not complete. */
zassert_equal(k_work_cancel(wp), K_WORK_RUNNING | K_WORK_CANCELING,
@ -722,6 +723,13 @@ static void test_1cpu_running_cancel(void)
/* Handler should not have run. */
zassert_equal(coophi_counter(), 0, NULL);
/* Busy wait until timer expires. Thread context is blocked so cancelling
* of work won't be completed.
*/
k_busy_wait(1000 * (ms_timeout + 1));
zassert_equal(k_timer_status_get(&ctx->timer), 1, NULL);
/* Wait for cancellation to complete. */
zassert_true(k_work_cancel_sync(wp, &work_sync), NULL);
@ -730,8 +738,7 @@ static void test_1cpu_running_cancel(void)
zassert_equal(rc, 0, NULL);
/* Handler should have detected running and canceling. */
zassert_equal(ctx->busy_rc, K_WORK_RUNNING | K_WORK_CANCELING,
NULL);
zassert_equal(ctx->busy_rc, K_WORK_RUNNING | K_WORK_CANCELING, NULL);
/* Attempt to submit while cancelling should have been
* rejected.
@ -750,6 +757,7 @@ static void test_1cpu_running_cancel_sync(void)
{
struct test_running_cancel_timer *ctx = &test_running_cancel_ctx;
struct k_work *wp = &ctx->work;
static const uint32_t ms_timeout = 10;
int rc;
/* Reset state and use the blocking handler */
@ -769,7 +777,7 @@ static void test_1cpu_running_cancel_sync(void)
ctx->submit_rc = INT_MAX;
ctx->busy_rc = INT_MAX;
k_timer_init(&ctx->timer, test_running_cancel_cb, NULL);
k_timer_start(&ctx->timer, K_TICKS(1), K_NO_WAIT);
k_timer_start(&ctx->timer, K_MSEC(ms_timeout), K_NO_WAIT);
/* Cancellation should wait. */
zassert_true(k_work_cancel_sync(wp, &work_sync), NULL);
@ -777,6 +785,13 @@ static void test_1cpu_running_cancel_sync(void)
/* Handler should have run. */
zassert_equal(coophi_counter(), 1, NULL);
/* Busy wait until timer expires. Thread context is blocked so cancelling
* of work won't be completed.
*/
k_busy_wait(1000 * (ms_timeout + 1));
zassert_equal(k_timer_status_get(&ctx->timer), 1, NULL);
/* Verify completion */
rc = k_sem_take(&sync_sem, K_NO_WAIT);
zassert_equal(rc, 0, NULL);