From ea9590448db08e7ac7058643a2ec7c568fd9310f Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Fri, 14 Feb 2020 15:06:19 +0100 Subject: [PATCH] kernel: Add k_delayed_work_pending to check if work has been submitted Add k_delayed_work_pending similar to k_work_pending to check if the delayed work item has been submitted but not yet completed. This would compliment the API since using k_work_pending or k_delayed_work_remaining_get is not enough to check this condition. This is because the timeout could have run out, but the timeout handler not yet processed and put the work into the workqueue. Signed-off-by: Joakim Andersson --- include/kernel.h | 19 ++++++++++++++ kernel/work_q.c | 6 +++++ tests/kernel/workq/work_queue/src/main.c | 32 ++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/include/kernel.h b/include/kernel.h index bd4cf2fa833..74905215b07 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -3233,6 +3233,25 @@ static inline bool k_work_pending(struct k_work *work) return atomic_test_bit(work->flags, K_WORK_STATE_PENDING); } +/** + * @brief Check if a delayed work item is pending. + * + * This routine indicates if the work item @a work is pending in a workqueue's + * queue or waiting for the delay timeout. + * + * @note Checking if the delayed work is pending gives no guarantee that the + * work will still be pending when this information is used. It is up to + * the caller to make sure that this information is used in a safe manner. + * + * @note Can be called by ISRs. + * + * @param work Address of delayed work item. + * + * @return true if work item is waiting for the delay to expire or pending on a + * work queue, or false if it is not pending. + */ +bool k_delayed_work_pending(struct k_delayed_work *work); + /** * @brief Start a workqueue. * diff --git a/kernel/work_q.c b/kernel/work_q.c index a0706d67946..d14e6bf72cc 100644 --- a/kernel/work_q.c +++ b/kernel/work_q.c @@ -143,4 +143,10 @@ int k_delayed_work_cancel(struct k_delayed_work *work) return ret; } +bool k_delayed_work_pending(struct k_delayed_work *work) +{ + return !z_is_inactive_timeout(&work->timeout) || + k_work_pending(&work->work); +} + #endif /* CONFIG_SYS_CLOCK_EXISTS */ diff --git a/tests/kernel/workq/work_queue/src/main.c b/tests/kernel/workq/work_queue/src/main.c index 6802aaaf5f4..f55bf965e02 100644 --- a/tests/kernel/workq/work_queue/src/main.c +++ b/tests/kernel/workq/work_queue/src/main.c @@ -316,6 +316,37 @@ static void test_delayed_cancel(void) check_results(0); } +static void test_delayed_pending(void) +{ + TC_PRINT("Starting delayed pending test\n"); + + k_delayed_work_init(&delayed_tests[0].work, delayed_work_handler); + + zassert_false(k_delayed_work_pending(&delayed_tests[0].work), NULL); + + TC_PRINT(" - Check pending delayed work when in workqueue\n"); + k_delayed_work_submit(&delayed_tests[0].work, K_NO_WAIT); + zassert_true(k_delayed_work_pending(&delayed_tests[0].work), NULL); + + k_msleep(1); + zassert_false(k_delayed_work_pending(&delayed_tests[0].work), NULL); + + TC_PRINT(" - Checking results\n"); + check_results(1); + reset_results(); + + TC_PRINT(" - Check pending delayed work with timeout\n"); + k_delayed_work_submit(&delayed_tests[0].work, K_MSEC(WORK_ITEM_WAIT)); + zassert_true(k_delayed_work_pending(&delayed_tests[0].work), NULL); + + k_msleep(WORK_ITEM_WAIT_ALIGNED); + zassert_false(k_delayed_work_pending(&delayed_tests[0].work), NULL); + + TC_PRINT(" - Checking results\n"); + check_results(1); + reset_results(); +} + static void delayed_resubmit_work_handler(struct k_work *work) { struct delayed_test_item *ti = @@ -758,6 +789,7 @@ void test_main(void) ztest_1cpu_unit_test(test_delayed_resubmit), ztest_1cpu_unit_test(test_delayed_resubmit_thread), ztest_1cpu_unit_test(test_delayed_cancel), + ztest_1cpu_unit_test(test_delayed_pending), ztest_1cpu_unit_test(test_triggered), ztest_1cpu_unit_test(test_already_triggered), ztest_1cpu_unit_test(test_triggered_resubmit),