diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 81647ee9..f0c19437 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,4 +13,5 @@ if (PICO_ON_DEVICE) add_subdirectory(cmsis_test) add_subdirectory(pico_sem_test) add_subdirectory(pico_sha256_test) + add_subdirectory(pico_async_context_test) endif() diff --git a/test/pico_async_context_test/BUILD.bazel b/test/pico_async_context_test/BUILD.bazel new file mode 100644 index 00000000..2028e58b --- /dev/null +++ b/test/pico_async_context_test/BUILD.bazel @@ -0,0 +1,15 @@ +load("//bazel:defs.bzl", "compatible_with_rp2") + +package(default_visibility = ["//visibility:public"]) + +cc_binary( + name = "pico_async_context_test", + testonly = True, + srcs = ["pico_async_context_test.c"], + target_compatible_with = compatible_with_rp2(), + deps = [ + "//src/rp2_common/pico_stdlib", + "//src/rp2_common/pico_async_context:pico_async_context_threadsafe_background", + "//test/pico_test", + ], +) diff --git a/test/pico_async_context_test/CMakeLists.txt b/test/pico_async_context_test/CMakeLists.txt new file mode 100644 index 00000000..ab1de432 --- /dev/null +++ b/test/pico_async_context_test/CMakeLists.txt @@ -0,0 +1,10 @@ +if (TARGET pico_async_context_threadsafe_background) + add_executable(pico_async_context_test + pico_async_context_test.c + ) + target_link_libraries(pico_async_context_test PRIVATE + pico_test + pico_async_context_threadsafe_background + ) + pico_add_extra_outputs(pico_async_context_test) +endif() diff --git a/test/pico_async_context_test/pico_async_context_test.c b/test/pico_async_context_test/pico_async_context_test.c new file mode 100644 index 00000000..6eaa796c --- /dev/null +++ b/test/pico_async_context_test/pico_async_context_test.c @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2026 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "pico/stdlib.h" +#include "pico/async_context_threadsafe_background.h" +#include "pico/test.h" + +PICOTEST_MODULE_NAME("pico_async_context_test", "pico_async_context_test test harness"); + +static void at_time_worker_fn(async_context_t *context, async_at_time_worker_t *worker) { + worker->user_data = (void*)true; +} +static async_at_time_worker_t at_time_worker = { .do_work = at_time_worker_fn }; + +static void pending_worker_fn(async_context_t *async_context, async_when_pending_worker_t *worker) { + worker->user_data = (void*)true; + async_context_remove_at_time_worker(async_context, &at_time_worker); // remove at time worker +} +static async_when_pending_worker_t pending_worker = { .do_work = pending_worker_fn }; + +static int issue_2836_test(void) { + + async_context_threadsafe_background_t async_context; + + // Set everything up + hard_assert(async_context_threadsafe_background_init_with_defaults(&async_context)); + async_context_add_when_pending_worker(&async_context.core, &pending_worker); + + // set an "at time" worker to run a long time in the future + hard_assert(!at_time_worker.user_data); + async_context_add_at_time_worker_at(&async_context.core, &at_time_worker, make_timeout_time_ms(100)); // .1s + + // run a "pending" now, this will remove the "at time" worker we just setup above + hard_assert(!pending_worker.user_data); + async_context_set_work_pending(&async_context.core, &pending_worker); + busy_wait_us_32(500); // Pending worker should run pretty quickly + hard_assert(pending_worker.user_data); + hard_assert(!at_time_worker.user_data); + + // Setup the "at time" worker again in .1s + async_context_add_at_time_worker_at(&async_context.core, &at_time_worker, make_timeout_time_ms(100)); // .1s + + // Wait long enough that the "at time" worker to happen + busy_wait_us_32(200000); // .2s + if (!at_time_worker.user_data) { // this should be set by the "at time" worker, it's a bug if it doesn't! + panic("test fail: async at time worker did not run"); + } + return 0; +} + +int main() { + setup_default_uart(); + + PICOTEST_START(); + + PICOTEST_START_SECTION("Issue #2836 defect - async at time worker problem"); + issue_2836_test(); + PICOTEST_END_SECTION(); + + PICOTEST_END_TEST(); +} \ No newline at end of file diff --git a/tools/bazel_build.py b/tools/bazel_build.py index 522f2831..a500916f 100755 --- a/tools/bazel_build.py +++ b/tools/bazel_build.py @@ -47,6 +47,7 @@ BUILD_CONFIGURATIONS = ( "//test/pico_sha256_test:pico_sha256_test", "//test/pico_stdio_test:pico_stdio_test", "//test/pico_time_test:pico_time_test", + "//test/pico_async_context_test:pico_async_context_test", # Pretty much only Picotool and pioasm build on Windows. "//..." if os.name == "nt" else "",