mirror of
https://github.com/raspberrypi/pico-sdk.git
synced 2026-03-14 21:19:43 +01:00
Merge b3336355fe into bc5481455f
This commit is contained in:
commit
06cf8b4ef8
10 changed files with 567 additions and 1 deletions
|
|
@ -6,6 +6,7 @@ package(default_visibility = ["//visibility:public"])
|
|||
cc_library(
|
||||
name = "pico_sync_headers",
|
||||
hdrs = [
|
||||
"include/pico/cond.h",
|
||||
"include/pico/critical_section.h",
|
||||
"include/pico/lock_core.h",
|
||||
"include/pico/mutex.h",
|
||||
|
|
@ -22,6 +23,7 @@ cc_library(
|
|||
cc_library(
|
||||
name = "pico_sync",
|
||||
srcs = [
|
||||
"cond.c",
|
||||
"critical_section.c",
|
||||
"lock_core.c",
|
||||
"mutex.c",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ endif()
|
|||
if (NOT TARGET pico_sync)
|
||||
pico_add_impl_library(pico_sync)
|
||||
target_include_directories(pico_sync_headers SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
pico_mirrored_target_link_libraries(pico_sync INTERFACE pico_sync_sem pico_sync_mutex pico_sync_critical_section pico_time hardware_sync)
|
||||
pico_mirrored_target_link_libraries(pico_sync INTERFACE pico_sync_cond pico_sync_sem pico_sync_mutex pico_sync_critical_section pico_time hardware_sync)
|
||||
endif()
|
||||
|
||||
|
||||
|
|
@ -19,6 +19,14 @@ if (NOT TARGET pico_sync_core)
|
|||
)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET pico_sync_cond)
|
||||
pico_add_library(pico_sync_cond)
|
||||
target_sources(pico_sync_cond INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/cond.c
|
||||
)
|
||||
pico_mirrored_target_link_libraries(pico_sync_cond INTERFACE pico_sync_core)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET pico_sync_sem)
|
||||
pico_add_library(pico_sync_sem)
|
||||
target_sources(pico_sync_sem INTERFACE
|
||||
|
|
|
|||
163
src/common/pico_sync/cond.c
Normal file
163
src/common/pico_sync/cond.c
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2025 Paul Guyot <pguyot@kallisys.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/cond.h"
|
||||
|
||||
void cond_init(cond_t *cond) {
|
||||
lock_init(&cond->core, next_striped_spin_lock_num());
|
||||
cond->waiter = LOCK_INVALID_OWNER_ID;
|
||||
cond->broadcast_count = 0;
|
||||
cond->signaled = false;
|
||||
__mem_fence_release();
|
||||
}
|
||||
|
||||
bool __time_critical_func(cond_wait_until)(cond_t *cond, mutex_t *mtx, absolute_time_t until) {
|
||||
bool success = true;
|
||||
bool broadcast = false;
|
||||
bool mutex_acquired = false;
|
||||
lock_owner_id_t caller = lock_get_caller_owner_id();
|
||||
|
||||
// waiter and mtx_core are protected by the cv spin_lock
|
||||
uint32_t save = spin_lock_blocking(cond->core.spin_lock);
|
||||
uint64_t current_broadcast = cond->broadcast_count;
|
||||
if (lock_is_owner_id_valid(cond->waiter)) {
|
||||
// There is a valid owner of the condition variable: we are not the
|
||||
// first waiter.
|
||||
assert(cond->mtx_core.spin_lock == mtx->core.spin_lock);
|
||||
|
||||
// wait until it's released
|
||||
lock_internal_spin_unlock_with_wait(&cond->core, save);
|
||||
do {
|
||||
save = spin_lock_blocking(cond->core.spin_lock);
|
||||
if (cond->broadcast_count != current_broadcast) {
|
||||
// Condition variable was broadcast while we were waiting to
|
||||
// own it.
|
||||
spin_unlock(cond->core.spin_lock, save);
|
||||
broadcast = true;
|
||||
break;
|
||||
}
|
||||
if (!lock_is_owner_id_valid(cond->waiter)) {
|
||||
cond->waiter = caller;
|
||||
cond->mtx_core = mtx->core;
|
||||
spin_unlock(cond->core.spin_lock, save);
|
||||
break;
|
||||
}
|
||||
if (is_at_the_end_of_time(until)) {
|
||||
lock_internal_spin_unlock_with_wait(&cond->core, save);
|
||||
} else if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&cond->core, save, until)) {
|
||||
// timed out
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
} else {
|
||||
cond->waiter = caller;
|
||||
cond->mtx_core = mtx->core;
|
||||
spin_unlock(cond->core.spin_lock, save);
|
||||
}
|
||||
|
||||
save = spin_lock_blocking(mtx->core.spin_lock);
|
||||
assert(mtx->owner == caller);
|
||||
|
||||
if (success && !broadcast) {
|
||||
if (cond->signaled) {
|
||||
// as an optimization, do not release the mutex.
|
||||
cond->signaled = false;
|
||||
mutex_acquired = true;
|
||||
spin_unlock(mtx->core.spin_lock, save);
|
||||
} else {
|
||||
// release mutex
|
||||
mtx->owner = LOCK_INVALID_OWNER_ID;
|
||||
lock_internal_spin_unlock_with_notify(&mtx->core, save);
|
||||
do {
|
||||
if (cond->signaled) {
|
||||
cond->signaled = false;
|
||||
if (!lock_is_owner_id_valid(mtx->owner)) {
|
||||
// As an optimization, acquire the mutex here
|
||||
mtx->owner = caller;
|
||||
mutex_acquired = true;
|
||||
}
|
||||
spin_unlock(mtx->core.spin_lock, save);
|
||||
break;
|
||||
}
|
||||
if (!success) {
|
||||
if (!lock_is_owner_id_valid(mtx->owner)) {
|
||||
// As an optimization, acquire the mutex here
|
||||
mtx->owner = caller;
|
||||
mutex_acquired = true;
|
||||
}
|
||||
spin_unlock(mtx->core.spin_lock, save);
|
||||
break;
|
||||
}
|
||||
if (is_at_the_end_of_time(until)) {
|
||||
lock_internal_spin_unlock_with_wait(&mtx->core, save);
|
||||
} else if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&mtx->core, save, until)) {
|
||||
// timed out
|
||||
success = false;
|
||||
}
|
||||
save = spin_lock_blocking(mtx->core.spin_lock);
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
||||
// free the cond var
|
||||
save = spin_lock_blocking(cond->core.spin_lock);
|
||||
if (cond->waiter == caller) {
|
||||
cond->waiter = LOCK_INVALID_OWNER_ID;
|
||||
}
|
||||
lock_internal_spin_unlock_with_notify(&cond->core, save);
|
||||
|
||||
if (!mutex_acquired) {
|
||||
mutex_enter_blocking(mtx);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool __time_critical_func(cond_wait_timeout_ms)(cond_t *cond, mutex_t *mtx, uint32_t timeout_ms) {
|
||||
return cond_wait_until(cond, mtx, make_timeout_time_ms(timeout_ms));
|
||||
}
|
||||
|
||||
bool __time_critical_func(cond_wait_timeout_us)(cond_t *cond, mutex_t *mtx, uint32_t timeout_us) {
|
||||
return cond_wait_until(cond, mtx, make_timeout_time_us(timeout_us));
|
||||
}
|
||||
|
||||
void __time_critical_func(cond_wait)(cond_t *cond, mutex_t *mtx) {
|
||||
cond_wait_until(cond, mtx, at_the_end_of_time);
|
||||
}
|
||||
|
||||
void __time_critical_func(cond_signal)(cond_t *cond) {
|
||||
uint32_t save = spin_lock_blocking(cond->core.spin_lock);
|
||||
if (lock_is_owner_id_valid(cond->waiter)) {
|
||||
lock_core_t mtx_core = cond->mtx_core;
|
||||
// spin_locks can be identical
|
||||
if (mtx_core.spin_lock != cond->core.spin_lock) {
|
||||
spin_unlock(cond->core.spin_lock, save);
|
||||
save = spin_lock_blocking(mtx_core.spin_lock);
|
||||
}
|
||||
cond->signaled = true;
|
||||
lock_internal_spin_unlock_with_notify(&mtx_core, save);
|
||||
} else {
|
||||
spin_unlock(cond->core.spin_lock, save);
|
||||
}
|
||||
}
|
||||
|
||||
void __time_critical_func(cond_broadcast)(cond_t *cond) {
|
||||
uint32_t save = spin_lock_blocking(cond->core.spin_lock);
|
||||
if (lock_is_owner_id_valid(cond->waiter)) {
|
||||
cond->broadcast_count++;
|
||||
lock_core_t mtx_core = cond->mtx_core;
|
||||
// spin_locks can be identical
|
||||
if (mtx_core.spin_lock != cond->core.spin_lock) {
|
||||
lock_internal_spin_unlock_with_notify(&cond->core, save);
|
||||
save = spin_lock_blocking(mtx_core.spin_lock);
|
||||
}
|
||||
cond->signaled = true;
|
||||
lock_internal_spin_unlock_with_notify(&mtx_core, save);
|
||||
} else {
|
||||
spin_unlock(cond->core.spin_lock, save);
|
||||
}
|
||||
}
|
||||
128
src/common/pico_sync/include/pico/cond.h
Normal file
128
src/common/pico_sync/include/pico/cond.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2025 Paul Guyot <pguyot@kallisys.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM_COND_H
|
||||
#define _PLATFORM_COND_H
|
||||
|
||||
#include "pico/mutex.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file cond.h
|
||||
* \defgroup cond cond
|
||||
* \ingroup pico_sync
|
||||
* \brief Condition variable API for non IRQ mutual exclusion between cores
|
||||
*
|
||||
* Condition variables complement mutexes by providing a way to atomically
|
||||
* wait and release a held mutex. Then, the task on the other core can signal
|
||||
* the variable, which ends the wait. Often, the other core would also hold
|
||||
* the shared mutex, so the signaled task waits until the mutex is released.
|
||||
* In this implementation, the signaling core does not need to hold the mutex.
|
||||
*
|
||||
* The implementation is compatible with more than two cores, with the following
|
||||
* effects:
|
||||
* - there could be a race condition if two cores try to signal at the same
|
||||
* time (this would be solved by having them hold a shared mutex when signaling)
|
||||
* - every core that waits should wait using the same mutex. There is an
|
||||
* assert if this is not the case.
|
||||
* - broadcast is implemented and releases every waiting cores.
|
||||
*
|
||||
* The condition variables only work with non-recursive mutexes.
|
||||
*
|
||||
* Limitations of mutexes also apply to condition variables. See \ref mutex.h
|
||||
*/
|
||||
|
||||
typedef struct __packed_aligned
|
||||
{
|
||||
lock_core_t core;
|
||||
lock_owner_id_t waiter;
|
||||
lock_core_t mtx_core;
|
||||
uint32_t broadcast_count; // Overflow is unlikely
|
||||
bool signaled;
|
||||
} cond_t;
|
||||
|
||||
/*! \brief Initialize a condition variable structure
|
||||
* \ingroup cond
|
||||
*
|
||||
* \param cv Pointer to condition variable structure
|
||||
*/
|
||||
void cond_init(cond_t *cv);
|
||||
|
||||
/*! \brief Wait on a condition variable
|
||||
* \ingroup cond
|
||||
*
|
||||
* Wait until a condition variable is signaled or broadcast. The mutex should
|
||||
* be owned and is released atomically. It is reacquired when this function
|
||||
* returns.
|
||||
*
|
||||
* \param cv Condition variable to wait on
|
||||
* \param mtx Currently held mutex
|
||||
*/
|
||||
void cond_wait(cond_t *cv, mutex_t *mtx);
|
||||
|
||||
/*! \brief Wait on a condition variable with a timeout.
|
||||
* \ingroup cond
|
||||
*
|
||||
* Wait until a condition variable is signaled or broadcast until a given
|
||||
* time. The mutex is released atomically and reacquired even if the wait
|
||||
* timed out.
|
||||
*
|
||||
* \param cv Condition variable to wait on
|
||||
* \param mtx Currently held mutex
|
||||
* \param until The time after which to return if the condition variable was
|
||||
* not signaled.
|
||||
* \return true if the condition variable was signaled, false otherwise
|
||||
*/
|
||||
bool cond_wait_until(cond_t *cv, mutex_t *mtx, absolute_time_t until);
|
||||
|
||||
/*! \brief Wait on a condition variable with a timeout.
|
||||
* \ingroup cond
|
||||
*
|
||||
* Wait until a condition variable is signaled or broadcast until a given
|
||||
* time. The mutex is released atomically and reacquired even if the wait
|
||||
* timed out.
|
||||
*
|
||||
* \param cv Condition variable to wait on
|
||||
* \param mtx Currently held mutex
|
||||
* \param timeout_ms The timeout in milliseconds.
|
||||
* \return true if the condition variable was signaled, false otherwise
|
||||
*/
|
||||
bool cond_wait_timeout_ms(cond_t *cv, mutex_t *mtx, uint32_t timeout_ms);
|
||||
|
||||
/*! \brief Wait on a condition variable with a timeout.
|
||||
* \ingroup cond
|
||||
*
|
||||
* Wait until a condition variable is signaled or broadcast until a given
|
||||
* time. The mutex is released atomically and reacquired even if the wait
|
||||
* timed out.
|
||||
*
|
||||
* \param cv Condition variable to wait on
|
||||
* \param mtx Currently held mutex
|
||||
* \param timeout_ms The timeout in microseconds.
|
||||
* \return true if the condition variable was signaled, false otherwise
|
||||
*/
|
||||
bool cond_wait_timeout_us(cond_t *cv, mutex_t *mtx, uint32_t timeout_us);
|
||||
|
||||
/*! \brief Signal on a condition variable and wake the waiter
|
||||
* \ingroup cond
|
||||
*
|
||||
* \param cv Condition variable to signal
|
||||
*/
|
||||
void cond_signal(cond_t *cv);
|
||||
|
||||
/*! \brief Broadcast a condition variable and wake every waiters
|
||||
* \ingroup cond
|
||||
*
|
||||
* \param cv Condition variable to signal
|
||||
*/
|
||||
void cond_broadcast(cond_t *cv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -15,5 +15,6 @@
|
|||
#include "pico/sem.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "pico/critical_section.h"
|
||||
#include "pico/cond.h"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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_cond_test)
|
||||
endif()
|
||||
|
|
|
|||
16
test/pico_cond_test/BUILD.bazel
Normal file
16
test/pico_cond_test/BUILD.bazel
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
load("//bazel:defs.bzl", "compatible_with_rp2")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cc_binary(
|
||||
name = "pico_cond_test",
|
||||
testonly = True,
|
||||
srcs = ["pico_cond_test.c"],
|
||||
# Host doesn't support multicore
|
||||
target_compatible_with = compatible_with_rp2(),
|
||||
deps = [
|
||||
"//src/rp2_common/pico_multicore",
|
||||
"//src/rp2_common/pico_stdlib",
|
||||
"//test/pico_test",
|
||||
],
|
||||
)
|
||||
6
test/pico_cond_test/CMakeLists.txt
Normal file
6
test/pico_cond_test/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
if (TARGET pico_multicore)
|
||||
add_executable(pico_cond_test pico_cond_test.c)
|
||||
|
||||
target_link_libraries(pico_cond_test PRIVATE pico_test pico_sync pico_multicore pico_stdlib )
|
||||
pico_add_extra_outputs(pico_cond_test)
|
||||
endif()
|
||||
240
test/pico_cond_test/pico_cond_test.c
Normal file
240
test/pico_cond_test/pico_cond_test.c
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/**
|
||||
* Copyright (c) 2022-2023 Paul Guyot <pguyot@kallisys.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico/cond.h"
|
||||
#include "pico/test.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "pico/stdio.h"
|
||||
|
||||
PICOTEST_MODULE_NAME("COND", "condition variable test");
|
||||
|
||||
static cond_t cond;
|
||||
static mutex_t mutex;
|
||||
|
||||
static volatile bool test_cond_wait_done;
|
||||
static volatile bool test_cond_wait_ready;
|
||||
static void test_cond_wait(void) {
|
||||
busy_wait_ms(100);
|
||||
mutex_enter_blocking(&mutex);
|
||||
test_cond_wait_ready = true;
|
||||
cond_wait(&cond, &mutex);
|
||||
test_cond_wait_done = true;
|
||||
mutex_exit(&mutex);
|
||||
}
|
||||
|
||||
static volatile bool test_cond_wait_timedout;
|
||||
static void test_cond_wait_timeout(void) {
|
||||
busy_wait_ms(100);
|
||||
mutex_enter_blocking(&mutex);
|
||||
test_cond_wait_ready = true;
|
||||
test_cond_wait_timedout = cond_wait_timeout_ms(&cond, &mutex, 200);
|
||||
test_cond_wait_done = true;
|
||||
mutex_exit(&mutex);
|
||||
}
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
mutex_init(&mutex);
|
||||
cond_init(&cond);
|
||||
|
||||
PICOTEST_START();
|
||||
|
||||
PICOTEST_CHECK(cond.core.spin_lock != mutex.core.spin_lock, "spinlock are identical");
|
||||
|
||||
PICOTEST_START_SECTION("test cond wait / signal with mutex");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
multicore_launch_core1(test_cond_wait);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for signal");
|
||||
mutex_enter_blocking(&mutex);
|
||||
cond_signal(&cond);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for mutex release");
|
||||
mutex_exit(&mutex);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("test cond wait / signal without mutex");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
multicore_launch_core1(test_cond_wait);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for signal");
|
||||
cond_signal(&cond);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("test cond wait / broadcast with mutex");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
multicore_launch_core1(test_cond_wait);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for signal");
|
||||
mutex_enter_blocking(&mutex);
|
||||
cond_broadcast(&cond);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for mutex release");
|
||||
mutex_exit(&mutex);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("test cond wait / broadcast without mutex");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
multicore_launch_core1(test_cond_wait);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for signal");
|
||||
cond_broadcast(&cond);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("test cond wait with timeout and signal");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
test_cond_wait_timedout = false;
|
||||
multicore_launch_core1(test_cond_wait_timeout);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait");
|
||||
mutex_enter_blocking(&mutex);
|
||||
cond_signal(&cond);
|
||||
mutex_exit(&mutex);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_timedout, "core1 did time out");
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("test cond wait with timeout and no signal");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
test_cond_wait_timedout = false;
|
||||
multicore_launch_core1(test_cond_wait_timeout);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait");
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(!test_cond_wait_timedout, "core1 did not time out");
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
int tests = 0;
|
||||
while (cond.core.spin_lock != mutex.core.spin_lock && tests < (PICO_SPINLOCK_ID_STRIPED_LAST - PICO_SPINLOCK_ID_STRIPED_FIRST)) {
|
||||
cond_init(&cond);
|
||||
tests++;
|
||||
}
|
||||
|
||||
PICOTEST_CHECK(cond.core.spin_lock == mutex.core.spin_lock, "spinlock are different");
|
||||
|
||||
PICOTEST_START_SECTION("same spinlock -- test cond wait / signal with mutex");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
multicore_launch_core1(test_cond_wait);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for signal");
|
||||
mutex_enter_blocking(&mutex);
|
||||
cond_signal(&cond);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for mutex release");
|
||||
mutex_exit(&mutex);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("same spinlock -- test cond wait / signal without mutex");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
multicore_launch_core1(test_cond_wait);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for signal");
|
||||
cond_signal(&cond);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("same spinlock -- test cond wait / broadcast with mutex");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
multicore_launch_core1(test_cond_wait);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for signal");
|
||||
mutex_enter_blocking(&mutex);
|
||||
cond_broadcast(&cond);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for mutex release");
|
||||
mutex_exit(&mutex);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("same spinlock -- test cond wait / broadcast without mutex");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
multicore_launch_core1(test_cond_wait);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait for signal");
|
||||
cond_broadcast(&cond);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("same spinlock -- test cond wait with timeout and signal");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
test_cond_wait_timedout = false;
|
||||
multicore_launch_core1(test_cond_wait_timeout);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait");
|
||||
mutex_enter_blocking(&mutex);
|
||||
cond_signal(&cond);
|
||||
mutex_exit(&mutex);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_timedout, "core1 did time out");
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_START_SECTION("same spinlock -- test cond wait with timeout and no signal");
|
||||
test_cond_wait_ready = false;
|
||||
test_cond_wait_done = false;
|
||||
test_cond_wait_timedout = false;
|
||||
multicore_launch_core1(test_cond_wait_timeout);
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(test_cond_wait_ready, "core1 is not ready");
|
||||
PICOTEST_CHECK(!test_cond_wait_done, "core1 did not wait");
|
||||
busy_wait_ms(200);
|
||||
PICOTEST_CHECK(!test_cond_wait_timedout, "core1 did not time out");
|
||||
PICOTEST_CHECK(test_cond_wait_done, "core1 isn't done");
|
||||
multicore_reset_core1();
|
||||
PICOTEST_END_SECTION();
|
||||
|
||||
PICOTEST_END_TEST();
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ BUILD_CONFIGURATIONS = (
|
|||
"//test/kitchen_sink:kitchen_sink_cpp",
|
||||
"//test/kitchen_sink:kitchen_sink_lwip_poll",
|
||||
"//test/kitchen_sink:kitchen_sink_lwip_background",
|
||||
"//test/pico_cond_test:pico_cond_test",
|
||||
"//test/pico_divider_test:pico_divider_test",
|
||||
"//test/pico_divider_test:pico_divider_nesting_test",
|
||||
"//test/pico_float_test:pico_double_test",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue