From 70cead28d73ab37739c6c07f4d7de0ed32c89e7e Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Mon, 15 Jun 2026 10:37:01 +0200 Subject: [PATCH] Re-add newlib lock glue to Src --- Core/Src/ThreadSafe/newlib_lock_glue.c | 435 +++++++++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 Core/Src/ThreadSafe/newlib_lock_glue.c diff --git a/Core/Src/ThreadSafe/newlib_lock_glue.c b/Core/Src/ThreadSafe/newlib_lock_glue.c new file mode 100644 index 0000000..744d87e --- /dev/null +++ b/Core/Src/ThreadSafe/newlib_lock_glue.c @@ -0,0 +1,435 @@ +/** + ****************************************************************************** + * @file newlib_lock_glue.c + * @author STMicroelectronics + * @brief Implementation of newlib lock interface + * + * @details This file implements locking glue necessary to protect C library + * functions and initialization of local static objects in C++. + * Lock strategies are defined in stm32_lock.h that implements + * different level of thread-safety. + * + * For more information about which C functions need which of these + * low level functions, please consult the newlib libc manual, + * see https://sourceware.org/newlib/libc.html + * + * For more information about the one-time construction API for C++, + * see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +#if !defined (__GNUC__) || defined (__CC_ARM) +#error "newlib_lock_glue.c" should be used with GNU Compilers only +#endif /* !defined (__GNUC__) || defined (__CC_ARM) */ + +/* Includes ------------------------------------------------------------------*/ +#include + +/* Private functions prototypes ----------------------------------------------*/ +__WEAK void Error_Handler(void); +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief Global Error_Handler + */ +__WEAK void Error_Handler(void) +{ + /* Not used if it exists in project */ + while (1); +} + +#ifdef __SINGLE_THREAD__ +#warning C library is in single-threaded mode. Please take care when using C library functions in threaded contexts +#else + +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include "stm32_lock.h" + +/** + * @defgroup _newlib_lock_functions newlib library locks + * @see https://sourceware.org/newlib/libc.html + * @{ + */ + +#if __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) +#include +#include +#include + +/* Private macros ------------------------------------------------------------*/ +/** See struct __lock definition */ +#define STM32_LOCK_PARAMETER(lock) (&(lock)->lock_data) + +/* shared variables for bare metal allow lock ------------------------------------------------------*/ +#if defined(STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS) && (STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS != 0) +uint32_t gflag = 0; +uint32_t call_counter = 0; +#endif /* defined(STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS) && (STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS != 0) */ + +/* Private variables ---------------------------------------------------------*/ +struct __lock +{ + LockingData_t lock_data; /**< The STM32 lock instance */ +}; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT }; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT }; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT }; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT }; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT }; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT }; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT }; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT }; + +/** Implementing mutex from newlib/libc/misc/lock.c */ +struct __lock __lock___arc4random_mutex = { LOCKING_DATA_INIT }; + +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief Initialize lock + * @param lock The lock + */ +void __retarget_lock_init(_LOCK_T *lock) +{ + __retarget_lock_init_recursive(lock); +} + +/** + * @brief Initialize recursive lock + * @param lock The lock + */ +void __retarget_lock_init_recursive(_LOCK_T *lock) +{ + if (lock == NULL) + { + errno = EINVAL; + return; + } + + *lock = (_LOCK_T)malloc(sizeof(struct __lock)); + if (*lock != NULL) + { + stm32_lock_init(STM32_LOCK_PARAMETER(*lock)); + return; + } + + /* Unable to allocate memory */ + STM32_LOCK_BLOCK(); +} + +/** + * @brief Close lock + * @param lock The lock + */ +void __retarget_lock_close(_LOCK_T lock) +{ + __retarget_lock_close_recursive(lock); +} + +/** + * @brief Close recursive lock + * @param lock The lock + */ +void __retarget_lock_close_recursive(_LOCK_T lock) +{ + free(lock); +} + +/** + * @brief Acquire lock + * @param lock The lock + */ +void __retarget_lock_acquire(_LOCK_T lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + stm32_lock_acquire(STM32_LOCK_PARAMETER(lock)); +} + +/** + * @brief Acquire recursive lock + * @param lock The lock + */ +void __retarget_lock_acquire_recursive(_LOCK_T lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + stm32_lock_acquire(STM32_LOCK_PARAMETER(lock)); +} + +/** + * @brief Try acquire lock + * @param lock The lock + * @return 0 always + */ +int __retarget_lock_try_acquire(_LOCK_T lock) +{ + __retarget_lock_acquire(lock); + return 0; +} + +/** + * @brief Try acquire recursive lock + * @param lock The lock + * @return 0 always + */ +int __retarget_lock_try_acquire_recursive(_LOCK_T lock) +{ + __retarget_lock_acquire_recursive(lock); + return 0; +} + +/** + * @brief Release lock + * @param lock The lock + */ +void __retarget_lock_release(_LOCK_T lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + stm32_lock_release(STM32_LOCK_PARAMETER(lock)); +} + +/** + * @brief Release recursive lock + * @param lock The lock + */ +void __retarget_lock_release_recursive(_LOCK_T lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + stm32_lock_release(STM32_LOCK_PARAMETER(lock)); +} + +#else +#warning This makes malloc, env, and TZ calls thread-safe, not the entire newlib + +/* Includes ------------------------------------------------------------------*/ +#include + +/* Private variables ---------------------------------------------------------*/ +/** Mutex used in __malloc_lock and __malloc_unlock */ +static LockingData_t __lock___malloc_recursive_mutex = LOCKING_DATA_INIT; + +/** Mutex used in __env_lock and __env_unlock */ +static LockingData_t __lock___env_recursive_mutex = LOCKING_DATA_INIT; + +/** Mutex used in __tz_lock and __tz_unlock */ +static LockingData_t __lock___tz_mutex = LOCKING_DATA_INIT; + +/* Private functions ---------------------------------------------------------*/ + +#if __STD_C + +/** + * @brief Acquire malloc lock + * @param reent The reentrance struct + */ +void __malloc_lock(struct _reent *reent) +{ + STM32_LOCK_UNUSED(reent); + stm32_lock_acquire(&__lock___malloc_recursive_mutex); +} + +/** + * @brief Release malloc lock + * @param reent The reentrance struct + */ +void __malloc_unlock(struct _reent *reent) +{ + STM32_LOCK_UNUSED(reent); + stm32_lock_release(&__lock___malloc_recursive_mutex); +} + +#else + +/** + * @brief Acquire malloc lock + */ +void __malloc_lock() +{ + stm32_lock_acquire(&__lock___malloc_recursive_mutex); +} + +/** + * @brief Release malloc lock + */ +void __malloc_unlock() +{ + stm32_lock_release(&__lock___malloc_recursive_mutex); +} +#endif /* __STD_C */ + +/** + * @brief Acquire env lock + * @param reent The reentrance struct + */ +void __env_lock(struct _reent *reent) +{ + STM32_LOCK_UNUSED(reent); + stm32_lock_acquire(&__lock___env_recursive_mutex); +} + +/** + * @brief Release env lock + * @param reent The reentrance struct + */ +void __env_unlock(struct _reent *reent) +{ + STM32_LOCK_UNUSED(reent); + stm32_lock_release(&__lock___env_recursive_mutex); +} + +/** + * @brief Acquire tz lock + */ +void __tz_lock() +{ + stm32_lock_acquire(&__lock___tz_mutex); +} + +/** + * @brief Release tz lock + */ +void __tz_unlock() +{ + stm32_lock_release(&__lock___tz_mutex); +} + +#endif /* __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) */ + +/** + * @} + */ + + +/** + * @defgroup __cxa_guard_ GNU C++ one-time construction API + * @see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor + * + * When building for C++, please make sure that -fno-threadsafe-statics is not passed to the compiler + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/** The guard object is created by the C++ compiler and is 32 bit for ARM EABI. */ +typedef struct +{ + atomic_uchar initialized; /**< Indicate if object is initialized */ + uint8_t acquired; /**< Ensure non-recursive lock */ + uint16_t unused; /**< Padding */ +} __attribute__((packed)) CxaGuardObject_t; + +/* Private variables ---------------------------------------------------------*/ +/** Mutex used in __cxa_guard_acquire, __cxa_guard_release and __cxa_guard_abort */ +static LockingData_t __cxa_guard_mutex = LOCKING_DATA_INIT; + +/* Private functions prototype ---------------------------------------------------------*/ +int __cxa_guard_acquire(CxaGuardObject_t *guard_object); +void __cxa_guard_abort(CxaGuardObject_t *guard_object); +void __cxa_guard_release(CxaGuardObject_t *guard_object); +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief Acquire __cxa_guard mutex + * @param guard_object Guard object + * @return 0 if object is initialized, else initialization of object required + */ +int __cxa_guard_acquire(CxaGuardObject_t *guard_object) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); + + if (atomic_load(&guard_object->initialized) == 0) + { + /* Object needs initialization, lock threading context */ + stm32_lock_acquire(&__cxa_guard_mutex); + if (atomic_load(&guard_object->initialized) == 0) + { + /* Object needs initialization */ + if (guard_object->acquired) + { + /* Object initialization already in progress */ + STM32_LOCK_BLOCK(); + } + + /* Lock acquired */ + guard_object->acquired = 1; + return 1; + } + else + { + /* Object initialized in another thread */ + stm32_lock_release(&__cxa_guard_mutex); + } + } + + /* Object already initialized */ + return 0; +} + +/** + * @brief Abort __cxa_guard mutex + * @param guard_object Guard object + */ +void __cxa_guard_abort(CxaGuardObject_t *guard_object) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); + + if (guard_object->acquired) + { + /* Release lock */ + guard_object->acquired = 0; + stm32_lock_release(&__cxa_guard_mutex); + } + else + { + /* Trying to release non-acquired lock */ + STM32_LOCK_BLOCK(); + } +} + +/** + * @brief Release __cxa_guard mutex + * @param guard_object Guard object + */ +void __cxa_guard_release(CxaGuardObject_t *guard_object) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); + + /* Object initialized */ + atomic_store(&guard_object->initialized, 1); + + /* Release lock */ + __cxa_guard_abort(guard_object); +} + +/** + * @} + */ + +#endif /* __SINGLE_THREAD__ */