diff --git a/common/mutex.c b/common/mutex.c index e528a8d54..aed3238ff 100644 --- a/common/mutex.c +++ b/common/mutex.c @@ -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); -} - -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(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 (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; +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 0; + return false; } -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); } } diff --git a/common/mutex.h b/common/mutex.h index f9f555709..29e88445f 100644 --- a/common/mutex.h +++ b/common/mutex.h @@ -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 -#define MUTEX_TID_IDE (1 << 0) -#define MUTEX_TID_OMV (1 << 1) +#include +#include +#include + +// 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__ diff --git a/common/usbdbg.c b/common/usbdbg.c index bc779b9eb..607ad19ae 100644 --- a/common/usbdbg.c +++ b/common/usbdbg.c @@ -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 diff --git a/lib/imlib/framebuffer.c b/lib/imlib/framebuffer.c index 45629c151..6932dfd89 100644 --- a/lib/imlib/framebuffer.c +++ b/lib/imlib/framebuffer.c @@ -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; } diff --git a/lib/imlib/framebuffer.h b/lib/imlib/framebuffer.h index cb5bfcffe..1b60b0f6b 100644 --- a/lib/imlib/framebuffer.h +++ b/lib/imlib/framebuffer.h @@ -27,9 +27,9 @@ #define __FRAMEBUFFER_H__ #include #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();