Skip to content

ISR versions of mutex_try_enter and mutex_exit #1549

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/common/pico_sync/include/pico/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ extern "C" {
typedef struct __packed_aligned {
lock_core_t core;
lock_owner_id_t owner; //! owner id LOCK_INVALID_OWNER_ID for unowned
uint32_t save;
uint8_t enter_count; //! ownership count
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
bool recursive;
Expand All @@ -60,6 +61,7 @@ typedef struct __packed_aligned {
typedef struct __packed_aligned mutex {
lock_core_t core;
lock_owner_id_t owner; //! owner id LOCK_INVALID_OWNER_ID for unowned
uint32_t save;
} mutex_t;
#else
typedef recursive_mutex_t mutex_t; // they are one and the same when backwards compatible with SDK1.2.0
Expand Down Expand Up @@ -114,6 +116,19 @@ void recursive_mutex_enter_blocking(recursive_mutex_t *mtx);
*/
bool mutex_try_enter(mutex_t *mtx, uint32_t *owner_out);

/*! \brief Attempt to take ownership of a mutex
* \ingroup mutex
*
* If the mutex wasn't owned, this will claim the mutex for the caller and return true.
* Otherwise (if the mutex was already owned) this will return false and the
* caller will NOT own the mutex.
*
* \param mtx Pointer to mutex structure
* \param owner_out If mutex was already owned, and this pointer is non-zero, it will be filled in with the owner id of the current owner of the mutex
* \return true if mutex now owned, false otherwise
*/
bool mutex_try_enter_isr(mutex_t *mtx, uint32_t *owner_out);

/*! \brief Attempt to take ownership of a mutex until the specified time
* \ingroup mutex
*
Expand Down Expand Up @@ -142,6 +157,20 @@ bool mutex_try_enter_block_until(mutex_t *mtx, absolute_time_t until);
*/
bool recursive_mutex_try_enter(recursive_mutex_t *mtx, uint32_t *owner_out);

/*! \brief Attempt to take ownership of a recursive mutex
* \ingroup mutex
*
* If the mutex wasn't owned or was owned by the caller, this will claim the mutex and return true.
* Otherwise (if the mutex was already owned by another owner) this will return false and the
* caller will NOT own the mutex.
*
* \param mtx Pointer to recursive mutex structure
* \param owner_out If mutex was already owned by another owner, and this pointer is non-zero,
* it will be filled in with the owner id of the current owner of the mutex
* \return true if the recursive mutex (now) owned, false otherwise
*/
bool recursive_mutex_try_enter_isr(recursive_mutex_t *mtx, uint32_t *owner_out);

/*! \brief Wait for mutex with timeout
* \ingroup mutex
*
Expand Down Expand Up @@ -232,13 +261,27 @@ bool recursive_mutex_enter_block_until(recursive_mutex_t *mtx, absolute_time_t u
*/
void mutex_exit(mutex_t *mtx);

/*! \brief Release ownership of a mutex
* \ingroup mutex
*
* \param mtx Pointer to mutex structure
*/
void mutex_exit_isr(mutex_t *mtx);

/*! \brief Release ownership of a recursive mutex
* \ingroup mutex
*
* \param mtx Pointer to recursive mutex structure
*/
void recursive_mutex_exit(recursive_mutex_t *mtx);

/*! \brief Release ownership of a recursive mutex
* \ingroup mutex
*
* \param mtx Pointer to recursive mutex structure
*/
void recursive_mutex_exit_isr(recursive_mutex_t *mtx);

/*! \brief Test for mutex initialized state
* \ingroup mutex
*
Expand Down
57 changes: 57 additions & 0 deletions src/common/pico_sync/mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,24 @@ bool __time_critical_func(mutex_try_enter)(mutex_t *mtx, uint32_t *owner_out) {
return entered;
}

bool __time_critical_func(mutex_try_enter_isr)(mutex_t *mtx, uint32_t *owner_out) {
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
if (mtx->recursive) {
return recursive_mutex_try_enter_isr(mtx, owner_out);
}
#endif
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (!lock_is_owner_id_valid(mtx->owner)) {
mtx->owner = lock_get_caller_owner_id();
mtx->save = save;
return true;
} else {
if (owner_out) *owner_out = (uint32_t) mtx->owner;
spin_unlock(mtx->core.spin_lock, save);
return false;
}
}

bool __time_critical_func(mutex_try_enter_block_until)(mutex_t *mtx, absolute_time_t until) {
// not using lock_owner_id_t to avoid backwards incompatibility change to mutex_try_enter API
static_assert(sizeof(lock_owner_id_t) <= 4, "");
Expand Down Expand Up @@ -108,6 +126,22 @@ bool __time_critical_func(recursive_mutex_try_enter)(recursive_mutex_t *mtx, uin
return entered;
}

bool __time_critical_func(recursive_mutex_try_enter_isr)(recursive_mutex_t *mtx, uint32_t *owner_out) {
lock_owner_id_t caller = lock_get_caller_owner_id();
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
if (!lock_is_owner_id_valid(mtx->owner) || mtx->owner == caller) {
mtx->owner = caller;
uint __unused total = ++mtx->enter_count;
assert(total); // check for overflow
mtx->save = save;
return true;
} else {
if (owner_out) *owner_out = (uint32_t) mtx->owner;
spin_unlock(mtx->core.spin_lock, save);
return false;
}
}

bool __time_critical_func(mutex_enter_timeout_ms)(mutex_t *mtx, uint32_t timeout_ms) {
return mutex_enter_block_until(mtx, make_timeout_time_ms(timeout_ms));
}
Expand Down Expand Up @@ -182,6 +216,18 @@ void __time_critical_func(mutex_exit)(mutex_t *mtx) {
lock_internal_spin_unlock_with_notify(&mtx->core, save);
}

void __time_critical_func(mutex_exit_isr)(mutex_t *mtx) {
#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
if (mtx->recursive) {
recursive_mutex_exit_isr(mtx);
return;
}
#endif
assert(lock_is_owner_id_valid(mtx->owner));
mtx->owner = LOCK_INVALID_OWNER_ID;
lock_internal_spin_unlock_with_notify(&mtx->core, mtx->save);
}

void __time_critical_func(recursive_mutex_exit)(recursive_mutex_t *mtx) {
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
assert(lock_is_owner_id_valid(mtx->owner));
Expand All @@ -192,4 +238,15 @@ void __time_critical_func(recursive_mutex_exit)(recursive_mutex_t *mtx) {
} else {
spin_unlock(mtx->core.spin_lock, save);
}
}

void __time_critical_func(recursive_mutex_exit_isr)(recursive_mutex_t *mtx) {
assert(lock_is_owner_id_valid(mtx->owner));
assert(mtx->enter_count);
if (!--mtx->enter_count) {
mtx->owner = LOCK_INVALID_OWNER_ID;
lock_internal_spin_unlock_with_notify(&mtx->core, mtx->save);
} else {
spin_unlock(mtx->core.spin_lock, mtx->save);
}
}
4 changes: 2 additions & 2 deletions src/rp2_common/pico_stdio_usb/stdio_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
}

static void low_priority_worker_irq(void) {
if (mutex_try_enter(&stdio_usb_mutex, NULL)) {
if (mutex_try_enter_isr(&stdio_usb_mutex, NULL)) {
tud_task();
mutex_exit(&stdio_usb_mutex);
mutex_exit_isr(&stdio_usb_mutex);
} else {
// if the mutex is already owned, then we are in non IRQ code in this file.
//
Expand Down