Fix osal_task_handle_t declared as uintptr_t throws warning. Fix sub-tick delays and timeouts truncating to 0 ticks. Fix stk_*_create usage due to STK C API change. Remove dependence on tusb_config.h. Use non-recursive stk::sync::FastMutex.
diff --git a/src/osal/osal_stk.h b/src/osal/osal_stk.h index 659fd7a..60531d6 100644 --- a/src/osal/osal_stk.h +++ b/src/osal/osal_stk.h
@@ -13,7 +13,7 @@ * osal_freertos.h / osal_threadx.h / osal_rtx4.h ports. No companion .cpp file is needed and * this header stays includable from TinyUSB's plain-C translation units directly. * - * CFG_TUH_OSAL_STK_USE_CPP=1 - STK's native C++ API (stk::sync::Mutex/Semaphore/MessageQueue, + * CFG_TUH_OSAL_STK_USE_CPP=1 - STK's native C++ API (stk::sync::FastMutex/Semaphore/MessageQueue, * stk::hw::CriticalSection). STK's C++ API is not includable from plain C, so in this mode * every STK-touching function is only *declared* here (as extern "C") and *defined* in the * companion osal_stk.cpp, which must be added to the build and is compiled as C++. Pick this @@ -28,7 +28,7 @@ * object into that storage the first time it's created, and a static_assert there guards every * size guess - raise the matching *_STORAGE_WORDS macro below if one of those ever fires (e.g. * after an STK upgrade changes a class's layout). The C backend has no such concern: stk_c.h's - * own stk_sem_mem_t / stk_mutex_mem_t / stk_msgq_mem_t types are already correctly-sized POD + * own stk_sem_mem_t / stk_fastmutex_mem_t / stk_msgq_mem_t types are already correctly-sized POD * structs, so they're embedded directly - no size macros, no static_assert, no placement-new. * --------------------------------------------------------------------------- */ @@ -40,9 +40,7 @@ #include <stdbool.h> #include <stddef.h> -#include "tusb_config.h" - -#define CFG_TUH_OSAL_STK_VERSION (0x20260801) +#define CFG_TUH_OSAL_STK_VERSION (0x20261019) #ifndef CFG_TUH_OSAL_STK_USE_CPP #define CFG_TUH_OSAL_STK_USE_CPP (0) @@ -63,7 +61,7 @@ /* Underlying task-id type isn't part of this header's C-visible surface in either backend (it's * a plain STK type, not necessarily a pointer) - uintptr_t is wide enough to hold it regardless * of size; a static_assert (osal_stk.cpp, or stk_c.h's own stk_tid_t definition) guards the fit. */ -typedef uintptr_t osal_task_handle_t; +typedef void *osal_task_handle_t; //----------------------------------------------------------------------------+ // Spinlock API @@ -111,9 +109,10 @@ // MUTEX API //----------------------------------------------------------------------------+ -/* Sized to fit a placement-constructed stk::sync::Mutex - see the file-level note above. */ +/* Sized to fit a placement-constructed stk::sync::FastMutex (non-recursive) - see the file-level + * note above. Matches STK_FASTMUTEX_IMPL_SIZE of stk_c.h. */ #ifndef OSAL_STK_MUTEX_STORAGE_WORDS -#define OSAL_STK_MUTEX_STORAGE_WORDS (10U + (CFG_TUH_OSAL_STK_SYNC_DEBUG_NAMES ? 1U : 0U)) +#define OSAL_STK_MUTEX_STORAGE_WORDS (9U + (CFG_TUH_OSAL_STK_SYNC_DEBUG_NAMES ? 1U : 0U)) #endif typedef struct { @@ -199,8 +198,8 @@ //----------------------------------------------------------------------------+ typedef struct { - stk_mutex_mem_t mem; - stk_mutex_t *hdl; + stk_fastmutex_mem_t mem; + stk_fastmutex_t *hdl; } osal_mutex_def_t; typedef osal_mutex_def_t *osal_mutex_t; @@ -224,7 +223,41 @@ osal_queue_def_t _name = { .buf = (void *) _name##_buf, .depth = (_depth), .item_sz = sizeof(_type) } //----------------------------------------------------------------------------+ -// TASK API +// Helper API +//----------------------------------------------------------------------------+ + +/* OSAL_TIMEOUT_WAIT_FOREVER (UINT32_MAX) -> STK_WAIT_INFINITE; anything else -> STK ticks, + * via stk_ticks_from_ms_clamped_to_timeout() for overflow-safe conversion across tick rates + * (see stk_c.h). + * + * A non-zero msec always yields at least 1 tick: with a coarse tick (e.g. 10 ms) the ms->ticks + * conversion truncates sub-tick values to 0, and STK treats 0 as NO_WAIT / sleep(0) - which neither + * blocks nor yields. For osal_task_delay() that lets a higher-priority task starve the caller + * (e.g. the polling loop in tuh_control_xfer(), which only ever calls osal_task_delay(1)); for + * timed waits it would turn a short blocking timeout into a non-blocking poll. Only msec == 0 + * maps to 0 ticks. */ +static inline stk_timeout_t osal_stk_timeout_from_ms(uint32_t msec) +{ + stk_timeout_t ticks; + + if (msec == OSAL_TIMEOUT_WAIT_FOREVER) { + ticks = STK_WAIT_INFINITE; + } else { + const stk_timeout_t ms_clamped = + (msec > (uint32_t)INT32_MAX) ? (stk_timeout_t)INT32_MAX : (stk_timeout_t) msec; + + ticks = stk_ticks_from_ms_clamped_to_timeout(ms_clamped); + + if ((msec != 0U) && (ticks == 0)) { + ticks = 1; /* round sub-tick durations up to one full tick */ + } + } + + return ticks; +} + +//----------------------------------------------------------------------------+ +// Task API //----------------------------------------------------------------------------+ static inline osal_task_handle_t osal_task_get_current_handle(void) @@ -239,26 +272,14 @@ static inline void osal_task_delay(uint32_t msec) { - const stk_timeout_t ms_clamped = - (msec > (uint32_t)INT32_MAX) ? (stk_timeout_t)INT32_MAX : (stk_timeout_t)msec; - stk_sleep_ms(ms_clamped); -} - -//----------------------------------------------------------------------------+ -// Small helper -//----------------------------------------------------------------------------+ - -/* OSAL_TIMEOUT_WAIT_FOREVER (UINT32_MAX) -> STK_WAIT_INFINITE; anything else -> STK ticks, - * via stk_ticks_from_ms_clamped_to_timeout() for overflow-safe conversion across tick rates - * (see stk_c.h). */ -static inline stk_timeout_t osal_stk_timeout_from_ms(uint32_t msec) -{ - if (msec == OSAL_TIMEOUT_WAIT_FOREVER) { - return STK_WAIT_INFINITE; + if (msec == 0U) { + /* sleep(0) is a no-op in STK; yield instead. Note: in KERNEL_HRT mode stk_yield() signals + * job completion, so don't call this with 0 there. */ + stk_yield(); + } else { + /* Sleep in ticks (not stk_sleep_ms()): the ms variant truncates sub-tick delays to sleep(0). */ + stk_sleep(osal_stk_timeout_from_ms(msec)); } - const stk_timeout_t ms_clamped = - (msec > (uint32_t)INT32_MAX) ? (stk_timeout_t)INT32_MAX : (stk_timeout_t) msec; - return stk_ticks_from_ms_clamped_to_timeout(ms_clamped); } //----------------------------------------------------------------------------+ @@ -295,7 +316,7 @@ (void)in_isr; /* stk_critical_section_exit_ex() is safe from ISR context */ const stk_cs_session_t ses = - ((ctx != NULL) ? (stk_cs_session_t)(*ctx) : (stk_cs_session_t)STK_DEFAULT_CS_SESSION); + ((ctx != NULL) ? (stk_cs_session_t)(*ctx) : (stk_cs_session_t)STK_DEFAULT_CS_SESSION); stk_critical_section_exit_ex(ses); } @@ -307,7 +328,7 @@ { /* Always constructed at count 0 (not-yet-signaled), matching every other OSAL backend here. * max_count 0 means "use STK's default maximum" (65534) - see stk_sem_create() in stk_c.h. */ - semdef->hdl = stk_sem_create(&semdef->mem, (uint32_t)sizeof(semdef->mem), 0U, 0U); + semdef->hdl = stk_sem_create(&semdef->mem, 0U, 0U); return ((semdef->hdl != NULL) ? semdef : NULL); } @@ -339,29 +360,31 @@ } //----------------------------------------------------------------------------+ -// MUTEX API (STK's Mutex is already recursive; TinyUSB never relies on that, but it's harmless) +// Mutex API (backed by STK's FastMutex: non-recursive, TinyUSB does not need recursion. +// Locking a FastMutex the caller already owns is a contract violation that panics with +// KERNEL_PANIC_SYNC_DEADLOCK - including a NO_WAIT try-lock) //----------------------------------------------------------------------------+ static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) { - mdef->hdl = stk_mutex_create(&mdef->mem, (uint32_t)sizeof(mdef->mem)); + mdef->hdl = stk_fastmutex_create(&mdef->mem); return ((mdef->hdl != NULL) ? mdef : NULL); } static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) { - stk_mutex_destroy(mutex_hdl->hdl); + stk_fastmutex_destroy(mutex_hdl->hdl); return true; } static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) { - return stk_mutex_timed_lock(mutex_hdl->hdl, osal_stk_timeout_from_ms(msec)); + return stk_fastmutex_timed_lock(mutex_hdl->hdl, osal_stk_timeout_from_ms(msec)); } static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) { - stk_mutex_unlock(mutex_hdl->hdl); + stk_fastmutex_unlock(mutex_hdl->hdl); return true; } @@ -371,7 +394,7 @@ static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) { - qdef->hdl = stk_msgq_create(&qdef->mem, (uint32_t)sizeof(qdef->mem), + qdef->hdl = stk_msgq_create(&qdef->mem, (uint8_t *)qdef->buf, (uint32_t)(qdef->depth * qdef->item_sz), (size_t)qdef->depth, (size_t)qdef->item_sz);