From 616efeb2f2b1648d78cc8fc41e9713c0780a83f9 Mon Sep 17 00:00:00 2001 From: Lucas Dietrich Date: Wed, 4 May 2022 15:28:09 +0000 Subject: [PATCH] tests: workq: Add a regression test for issue #45267 When an object availability event triggers a k_work_poll item, the object lock should not be held anymore during the execution of the work callback. Signed-off-by: Lucas Dietrich --- tests/kernel/workq/work_queue/prj.conf | 2 + tests/kernel/workq/work_queue/src/main.c | 103 ++++++++++++++++++++++- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/tests/kernel/workq/work_queue/prj.conf b/tests/kernel/workq/work_queue/prj.conf index 2484f419797..509a371f9f4 100644 --- a/tests/kernel/workq/work_queue/prj.conf +++ b/tests/kernel/workq/work_queue/prj.conf @@ -1,6 +1,8 @@ CONFIG_ZTEST=y CONFIG_POLL=y +CONFIG_ASSERT=y + # Not a single test case here is SMP-safe. Save the cycles needed for # all the ztest_1cpu spinning. CONFIG_MP_NUM_CPUS=1 diff --git a/tests/kernel/workq/work_queue/src/main.c b/tests/kernel/workq/work_queue/src/main.c index 175b0b3a4ce..7ac93690fcb 100644 --- a/tests/kernel/workq/work_queue/src/main.c +++ b/tests/kernel/workq/work_queue/src/main.c @@ -63,6 +63,28 @@ static int results[NUM_TEST_ITEMS]; static int num_results; static int expected_poll_result; +#define MSG_PROVIDER_THREAD_STACK_SIZE 0x400U +#define MSG_CONSUMER_WORKQ_STACK_SIZE 0x400U + +#define MSG_PROVIDER_THREAD_PRIO K_PRIO_PREEMPT(8) +#define MSG_CONSUMER_WORKQ_PRIO K_PRIO_COOP(7) +#define MSG_SIZE 16U + +static K_THREAD_STACK_DEFINE(provider_thread_stack, MSG_PROVIDER_THREAD_STACK_SIZE); +static K_THREAD_STACK_DEFINE(consumer_workq_stack, MSG_CONSUMER_WORKQ_STACK_SIZE); + +struct triggered_from_msgq_test_item { + k_tid_t tid; + struct k_thread msg_provider_thread; + struct k_work_q msg_consumer_workq; + struct k_work_poll work; + char msgq_buf[1][MSG_SIZE]; + struct k_msgq msgq; + struct k_poll_event event; +}; + +static struct triggered_from_msgq_test_item triggered_from_msgq_test; + static void work_handler(struct k_work *work) { struct delayed_test_item *ti = @@ -701,12 +723,86 @@ static void test_triggered_wait_expired(void) reset_results(); } + +static void msg_provider_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + char msg[MSG_SIZE]; + + k_msgq_put(&triggered_from_msgq_test.msgq, &msg, K_NO_WAIT); +} + +static void triggered_from_msgq_work_handler(struct k_work *work) +{ + char msg[MSG_SIZE]; + + k_msgq_get(&triggered_from_msgq_test.msgq, &msg, K_NO_WAIT); +} + +static void test_triggered_from_msgq_init(void) +{ + struct triggered_from_msgq_test_item *const ctx = &triggered_from_msgq_test; + + ctx->tid = k_thread_create(&ctx->msg_provider_thread, + provider_thread_stack, + MSG_PROVIDER_THREAD_STACK_SIZE, + msg_provider_thread, + NULL, NULL, NULL, + MSG_PROVIDER_THREAD_PRIO, 0, K_FOREVER); + k_work_queue_init(&ctx->msg_consumer_workq); + k_msgq_init(&ctx->msgq, + (char *)ctx->msgq_buf, + MSG_SIZE, 1U); + k_work_poll_init(&ctx->work, triggered_from_msgq_work_handler); + k_poll_event_init(&ctx->event, K_POLL_TYPE_MSGQ_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, &ctx->msgq); + + k_work_queue_start(&ctx->msg_consumer_workq, consumer_workq_stack, + MSG_CONSUMER_WORKQ_STACK_SIZE, MSG_CONSUMER_WORKQ_PRIO, + NULL); + k_work_poll_submit_to_queue(&ctx->msg_consumer_workq, &ctx->work, + &ctx->event, 1U, K_FOREVER); +} + +static void test_triggered_from_msgq_start(void) +{ + k_thread_start(triggered_from_msgq_test.tid); +} +/** + * @brief Test triggered work item, triggered by a msgq message. + * + * Regression test for issue #45267: + * + * When an object availability event triggers a k_work_poll item, + * the object lock should not be held anymore during the execution + * of the work callback. + * + * Tested with msgq with K_POLL_TYPE_MSGQ_DATA_AVAILABLE. + * + * @ingroup kernel_workqueue_tests + * + * @see k_work_poll_init(), k_work_poll_submit() + * + */ +static void test_triggered_from_msgq(void) +{ + TC_PRINT("Starting triggered from msgq test\n"); + + TC_PRINT(" - Initializing kernel objects\n"); + test_triggered_from_msgq_init(); + + TC_PRINT(" - Starting the thread\n"); + test_triggered_from_msgq_start(); + + reset_results(); +} + /** * @brief Test delayed work queue define macro. * - * The macro should initialize the k_delayed_work exactly the same as - * @ref k_delayed_work_init does. - * * @ingroup kernel_workqueue_tests * * @see K_DELAYED_WORK_DEFINE() @@ -773,6 +869,7 @@ void test_main(void) ztest_1cpu_unit_test(test_triggered_no_wait_expired), ztest_1cpu_unit_test(test_triggered_wait), ztest_1cpu_unit_test(test_triggered_wait_expired), + ztest_1cpu_unit_test(test_triggered_from_msgq), ztest_1cpu_unit_test(test_delayed_work_define), ztest_1cpu_unit_test(test_triggered_cancel) );