diff --git a/src/common/pico_sync/include/pico/sem.h b/src/common/pico_sync/include/pico/sem.h index 6244e32..f9f724b 100644 --- a/src/common/pico_sync/include/pico/sem.h +++ b/src/common/pico_sync/include/pico/sem.h @@ -122,6 +122,17 @@ bool sem_acquire_timeout_us(semaphore_t *sem, uint32_t timeout_us); */ bool sem_acquire_block_until(semaphore_t *sem, absolute_time_t until); +/*! \brief Attempt to acquire a permit from a semaphore without blocking + * \ingroup sem + * + * This function will return false without blocking if no permits are + * available, otherwise it will acquire a permit and return true. + * + * \param sem Pointer to semaphore structure + * \return true if permit was acquired. + */ +bool sem_try_acquire(semaphore_t *sem); + #ifdef __cplusplus } #endif diff --git a/src/common/pico_sync/sem.c b/src/common/pico_sync/sem.c index 06b4946..5578a49 100644 --- a/src/common/pico_sync/sem.c +++ b/src/common/pico_sync/sem.c @@ -52,6 +52,17 @@ bool __time_critical_func(sem_acquire_block_until)(semaphore_t *sem, absolute_ti } while (true); } +bool __time_critical_func(sem_try_acquire)(semaphore_t *sem) { + uint32_t save = spin_lock_blocking(sem->core.spin_lock); + if (sem->permits > 0) { + sem->permits--; + lock_internal_spin_unlock_with_notify(&sem->core, save); + return true; + } + spin_unlock(sem->core.spin_lock, save); + return false; +} + // todo this should really have a blocking variant for when permits are maxed out bool __time_critical_func(sem_release)(semaphore_t *sem) { uint32_t save = spin_lock_blocking(sem->core.spin_lock); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7396605..a61388a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,4 +9,5 @@ if (PICO_ON_DEVICE) add_subdirectory(hardware_irq_test) add_subdirectory(hardware_pwm_test) add_subdirectory(cmsis_test) -endif() \ No newline at end of file + add_subdirectory(pico_sem_test) +endif() diff --git a/test/pico_sem_test/CMakeLists.txt b/test/pico_sem_test/CMakeLists.txt new file mode 100644 index 0000000..786963c --- /dev/null +++ b/test/pico_sem_test/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(pico_sem_test pico_sem_test.c) + +target_link_libraries(pico_sem_test PRIVATE pico_test pico_sync) +pico_add_extra_outputs(pico_sem_test) diff --git a/test/pico_sem_test/pico_sem_test.c b/test/pico_sem_test/pico_sem_test.c new file mode 100644 index 0000000..8647c19 --- /dev/null +++ b/test/pico_sem_test/pico_sem_test.c @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "pico/sem.h" +#include "pico/test.h" +#include "pico/stdio.h" + +PICOTEST_MODULE_NAME("SEM", "semaphore test"); + +int main() { + semaphore_t sem; + + stdio_init_all(); + sem_init(&sem, 1, 1); + + PICOTEST_START(); + + PICOTEST_START_SECTION("sem_try_acquire"); + PICOTEST_CHECK(sem_try_acquire(&sem), "available permit not acquired"); + PICOTEST_CHECK(!sem_try_acquire(&sem), "success with no permits"); + PICOTEST_END_SECTION(); + + PICOTEST_END_TEST(); +}