Merge pull request #2782 from openmv/update_mutex
Some checks are pending
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (DOCKER) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_AE3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_N6) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions

common/mutex: Use C11 atomic operations.
This commit is contained in:
Ibrahim Abdelkader 2025-07-26 18:42:35 +03:00 committed by GitHub
commit fe1f36e867
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 49 additions and 91 deletions

View File

@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright (C) 2013-2024 OpenMV, LLC.
* Copyright (C) 2013-2025 OpenMV, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -22,89 +22,39 @@
* THE SOFTWARE.
*
* Mutex implementation.
* This is a standard implementation of mutexs on ARM processors following the ARM guide.
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHEJCHB.html
*
* Note: The Cortex-M0/M0+ does Not have the Load/Store exclusive instructions, on these
* CPUs the locking function is implemented with atomic access using disable/enable IRQs.
*/
#include "mutex.h"
#include "cmsis_compiler.h"
#include "py/mphal.h"
#include "common/mutex.h"
void mutex_init0(omv_mutex_t *mutex) {
__DMB();
mutex->tid = 0;
mutex->lock = 0;
mutex->last_tid = 0;
void mutex_init0(mutex_t *m) {
atomic_store_explicit(&m->tid, 0, memory_order_relaxed);
atomic_flag_clear_explicit(&m->lock, memory_order_relaxed);
}
static void _mutex_lock(omv_mutex_t *mutex, uint32_t tid, bool blocking) {
#if (__ARM_ARCH < 7)
do {
__disable_irq();
if (mutex->lock == 0) {
mutex->lock = 1;
mutex->tid = tid;
}
__enable_irq();
} while (mutex->tid != tid && blocking);
#else
do {
// Attempt to lock the mutex
if (__LDREXW(&mutex->lock) == 0) {
if (__STREXW(1, &mutex->lock) == 0) {
// Set TID if mutex is locked
mutex->tid = tid;
}
}
} while (mutex->tid != tid && blocking);
#endif
__DMB();
void mutex_lock(mutex_t *m, size_t tid) {
while (atomic_flag_test_and_set_explicit(&m->lock, memory_order_acquire));
atomic_store_explicit(&m->tid, tid, memory_order_release);
}
void mutex_lock(omv_mutex_t *mutex, uint32_t tid) {
_mutex_lock(mutex, tid, true);
bool mutex_try_lock(mutex_t *m, size_t tid) {
if (!atomic_flag_test_and_set_explicit(&m->lock, memory_order_acquire)) {
atomic_store_explicit(&m->tid, tid, memory_order_release);
return true;
}
return false;
}
int mutex_try_lock(omv_mutex_t *mutex, uint32_t tid) {
// If the mutex is already locked by the current thread then
// release it and return without locking, otherwise try to lock it.
if (mutex->tid == tid) {
mutex_unlock(mutex, tid);
} else {
_mutex_lock(mutex, tid, false);
bool mutex_try_lock_fair(mutex_t *m, size_t tid) {
if (atomic_load_explicit(&m->tid, memory_order_acquire) != tid) {
if (!atomic_flag_test_and_set_explicit(&m->lock, memory_order_acquire)) {
atomic_store_explicit(&m->tid, tid, memory_order_release);
return true;
}
return (mutex->tid == tid);
}
return false;
}
int mutex_try_lock_alternate(omv_mutex_t *mutex, uint32_t tid) {
if (mutex->last_tid != tid) {
if (mutex_try_lock(mutex, tid)) {
mutex->last_tid = tid;
return 1;
}
}
return 0;
}
int mutex_lock_timeout(omv_mutex_t *mutex, uint32_t tid, uint32_t timeout) {
mp_uint_t tick_start = mp_hal_ticks_ms();
while ((mp_hal_ticks_ms() - tick_start) >= timeout) {
if (mutex_try_lock(mutex, tid)) {
return 1;
}
__WFI();
}
return 0;
}
void mutex_unlock(omv_mutex_t *mutex, uint32_t tid) {
if (mutex->tid == tid) {
__DMB();
mutex->tid = 0;
mutex->lock = 0;
void mutex_unlock(mutex_t *m, size_t tid) {
if (atomic_load_explicit(&m->tid, memory_order_acquire) == tid) {
atomic_flag_clear_explicit(&m->lock, memory_order_release);
}
}

View File

@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright (C) 2013-2024 OpenMV, LLC.
* Copyright (C) 2013-2025 OpenMV, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -26,19 +26,27 @@
#ifndef __MUTEX_H__
#define __MUTEX_H__
#include <stdint.h>
#define MUTEX_TID_IDE (1 << 0)
#define MUTEX_TID_OMV (1 << 1)
#include <stdbool.h>
#include <stddef.h>
#include <stdatomic.h>
// Conflicts with picosdk
#define mutex_t omv_mutex_t
typedef enum {
MUTEX_TID_IDE = 1,
MUTEX_TID_OMV = 2
} mutex_tid_t;
typedef volatile struct {
uint32_t tid;
uint32_t lock;
uint32_t last_tid;
} omv_mutex_t;
atomic_size_t tid;
atomic_flag lock;
} mutex_t;
void mutex_init0(omv_mutex_t *mutex);
void mutex_lock(omv_mutex_t *mutex, uint32_t tid);
int mutex_try_lock(omv_mutex_t *mutex, uint32_t tid);
int mutex_try_lock_alternate(omv_mutex_t *mutex, uint32_t tid);
int mutex_lock_timeout(omv_mutex_t *mutex, uint32_t tid, uint32_t timeout);
void mutex_unlock(omv_mutex_t *mutex, uint32_t tid);
#endif /* __MUTEX_H__ */
void mutex_init0(mutex_t *mutex);
void mutex_lock(mutex_t *mutex, size_t tid);
bool mutex_try_lock(mutex_t *mutex, size_t tid);
// Prevents a thread from locking twice in a row.
bool mutex_try_lock_fair(mutex_t *mutex, size_t tid);
void mutex_unlock(mutex_t *mutex, size_t tid);
#endif // __MUTEX_H__

View File

@ -173,7 +173,7 @@ void usbdbg_data_in(uint32_t size, usbdbg_write_callback_t write_callback) {
// Return 0 if FB is locked or not ready.
uint32_t buffer[3] = { 0 };
// Try to lock FB. If header size == 0 frame is not ready
if (mutex_try_lock_alternate(&JPEG_FB()->lock, MUTEX_TID_IDE)) {
if (mutex_try_lock_fair(&JPEG_FB()->lock, MUTEX_TID_IDE)) {
// If header size == 0 frame is not ready
if (JPEG_FB()->size == 0) {
// unlock FB
@ -249,7 +249,7 @@ void usbdbg_data_in(uint32_t size, usbdbg_write_callback_t write_callback) {
// Limit the frames sent over USB to 20Hz.
if (ticks_diff_ms(last_update_ms) > 50 &&
mutex_try_lock_alternate(&JPEG_FB()->lock, MUTEX_TID_IDE)) {
mutex_try_lock_fair(&JPEG_FB()->lock, MUTEX_TID_IDE)) {
// If header size == 0 frame is not ready
if (JPEG_FB()->size == 0) {
// unlock FB

View File

@ -248,7 +248,7 @@ void framebuffer_update_jpeg_buffer(image_t *src) {
}
// Lock the JPEG buffer.
if (!mutex_try_lock_alternate(&jpegbuffer.lock, MUTEX_TID_OMV)) {
if (!mutex_try_lock_fair(&jpegbuffer.lock, MUTEX_TID_OMV)) {
return;
}

View File

@ -27,9 +27,9 @@
#define __FRAMEBUFFER_H__
#include <stdint.h>
#include "imlib.h"
#include "mutex.h"
#include "omv_common.h"
#include "common/queue.h"
#include "common/mutex.h"
#ifndef FRAMEBUFFER_ALIGNMENT
#define FRAMEBUFFER_ALIGNMENT OMV_CACHE_LINE_SIZE
@ -122,7 +122,7 @@ typedef struct jpegbuffer {
int32_t enabled;
int32_t quality;
uint8_t *pixels;
omv_mutex_t lock;
mutex_t lock;
} jpegbuffer_t;
void framebuffer_init0();