You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

423 lines
11 KiB

12 months ago
  1. /**
  2. ******************************************************************************
  3. * @file newlib_lock_glue.c
  4. * @author STMicroelectronics
  5. * @brief Implementation of newlib lock interface
  6. *
  7. * @details This file implements locking glue necessary to protect C library
  8. * functions and initialization of local static objects in C++.
  9. * Lock strategies are defined in stm32_lock.h that implements
  10. * different level of thread-safety.
  11. *
  12. * For more information about which C functions need which of these
  13. * low level functions, please consult the newlib libc manual,
  14. * see https://sourceware.org/newlib/libc.html
  15. *
  16. * For more information about the one-time construction API for C++,
  17. * see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor
  18. *
  19. ******************************************************************************
  20. * @attention
  21. *
  22. * Copyright (c) 2024 STMicroelectronics.
  23. * All rights reserved.
  24. *
  25. * This software is licensed under terms that can be found in the LICENSE file
  26. * in the root directory of this software component.
  27. * If no LICENSE file comes with this software, it is provided AS-IS.
  28. *
  29. ******************************************************************************
  30. */
  31. #if !defined (__GNUC__) || defined (__CC_ARM)
  32. #error "newlib_lock_glue.c" should be used with GNU Compilers only
  33. #endif /* !defined (__GNUC__) || defined (__CC_ARM) */
  34. /* Includes ------------------------------------------------------------------*/
  35. #include <cmsis_compiler.h>
  36. /* Private functions ---------------------------------------------------------*/
  37. /**
  38. * @brief Global Error_Handler
  39. */
  40. __WEAK void Error_Handler(void)
  41. {
  42. /* Not used if it exists in project */
  43. while (1);
  44. }
  45. #ifdef __SINGLE_THREAD__
  46. #warning C library is in single-threaded mode. Please take care when using C library functions in threaded contexts
  47. #else
  48. /* Includes ------------------------------------------------------------------*/
  49. #include <newlib.h>
  50. #include <stdatomic.h>
  51. #include "stm32_lock.h"
  52. /**
  53. * @defgroup _newlib_lock_functions newlib library locks
  54. * @see https://sourceware.org/newlib/libc.html
  55. * @{
  56. */
  57. #if __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING)
  58. #include <errno.h>
  59. #include <stdlib.h>
  60. #include <sys/lock.h>
  61. /* Private macros ------------------------------------------------------------*/
  62. /** See struct __lock definition */
  63. #define STM32_LOCK_PARAMETER(lock) (&(lock)->lock_data)
  64. /* Private variables ---------------------------------------------------------*/
  65. struct __lock
  66. {
  67. LockingData_t lock_data; /**< The STM32 lock instance */
  68. };
  69. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  70. struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT };
  71. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  72. struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT };
  73. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  74. struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT };
  75. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  76. struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT };
  77. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  78. struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT };
  79. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  80. struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT };
  81. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  82. struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT };
  83. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  84. struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT };
  85. /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
  86. struct __lock __lock___arc4random_mutex = { LOCKING_DATA_INIT };
  87. /* Private functions ---------------------------------------------------------*/
  88. /**
  89. * @brief Initialize lock
  90. * @param lock The lock
  91. */
  92. void __retarget_lock_init(_LOCK_T *lock)
  93. {
  94. __retarget_lock_init_recursive(lock);
  95. }
  96. /**
  97. * @brief Initialize recursive lock
  98. * @param lock The lock
  99. */
  100. void __retarget_lock_init_recursive(_LOCK_T *lock)
  101. {
  102. if (lock == NULL)
  103. {
  104. errno = EINVAL;
  105. return;
  106. }
  107. *lock = (_LOCK_T)malloc(sizeof(struct __lock));
  108. if (*lock != NULL)
  109. {
  110. stm32_lock_init(STM32_LOCK_PARAMETER(*lock));
  111. return;
  112. }
  113. /* Unable to allocate memory */
  114. STM32_LOCK_BLOCK();
  115. }
  116. /**
  117. * @brief Close lock
  118. * @param lock The lock
  119. */
  120. void __retarget_lock_close(_LOCK_T lock)
  121. {
  122. __retarget_lock_close_recursive(lock);
  123. }
  124. /**
  125. * @brief Close recursive lock
  126. * @param lock The lock
  127. */
  128. void __retarget_lock_close_recursive(_LOCK_T lock)
  129. {
  130. free(lock);
  131. }
  132. /**
  133. * @brief Acquire lock
  134. * @param lock The lock
  135. */
  136. void __retarget_lock_acquire(_LOCK_T lock)
  137. {
  138. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  139. stm32_lock_acquire(STM32_LOCK_PARAMETER(lock));
  140. }
  141. /**
  142. * @brief Acquire recursive lock
  143. * @param lock The lock
  144. */
  145. void __retarget_lock_acquire_recursive(_LOCK_T lock)
  146. {
  147. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  148. stm32_lock_acquire(STM32_LOCK_PARAMETER(lock));
  149. }
  150. /**
  151. * @brief Try acquire lock
  152. * @param lock The lock
  153. * @return 0 always
  154. */
  155. int __retarget_lock_try_acquire(_LOCK_T lock)
  156. {
  157. __retarget_lock_acquire(lock);
  158. return 0;
  159. }
  160. /**
  161. * @brief Try acquire recursive lock
  162. * @param lock The lock
  163. * @return 0 always
  164. */
  165. int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
  166. {
  167. __retarget_lock_acquire_recursive(lock);
  168. return 0;
  169. }
  170. /**
  171. * @brief Release lock
  172. * @param lock The lock
  173. */
  174. void __retarget_lock_release(_LOCK_T lock)
  175. {
  176. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  177. stm32_lock_release(STM32_LOCK_PARAMETER(lock));
  178. }
  179. /**
  180. * @brief Release recursive lock
  181. * @param lock The lock
  182. */
  183. void __retarget_lock_release_recursive(_LOCK_T lock)
  184. {
  185. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
  186. stm32_lock_release(STM32_LOCK_PARAMETER(lock));
  187. }
  188. #else
  189. #warning This makes malloc, env, and TZ calls thread-safe, not the entire newlib
  190. /* Includes ------------------------------------------------------------------*/
  191. #include <reent.h>
  192. /* Private variables ---------------------------------------------------------*/
  193. /** Mutex used in __malloc_lock and __malloc_unlock */
  194. static LockingData_t __lock___malloc_recursive_mutex = LOCKING_DATA_INIT;
  195. /** Mutex used in __env_lock and __env_unlock */
  196. static LockingData_t __lock___env_recursive_mutex = LOCKING_DATA_INIT;
  197. /** Mutex used in __tz_lock and __tz_unlock */
  198. static LockingData_t __lock___tz_mutex = LOCKING_DATA_INIT;
  199. /* Private functions ---------------------------------------------------------*/
  200. #if __STD_C
  201. /**
  202. * @brief Acquire malloc lock
  203. * @param reent The reentrance struct
  204. */
  205. void __malloc_lock(struct _reent *reent)
  206. {
  207. STM32_LOCK_UNUSED(reent);
  208. stm32_lock_acquire(&__lock___malloc_recursive_mutex);
  209. }
  210. /**
  211. * @brief Release malloc lock
  212. * @param reent The reentrance struct
  213. */
  214. void __malloc_unlock(struct _reent *reent)
  215. {
  216. STM32_LOCK_UNUSED(reent);
  217. stm32_lock_release(&__lock___malloc_recursive_mutex);
  218. }
  219. #else
  220. /**
  221. * @brief Acquire malloc lock
  222. */
  223. void __malloc_lock()
  224. {
  225. stm32_lock_acquire(&__lock___malloc_recursive_mutex);
  226. }
  227. /**
  228. * @brief Release malloc lock
  229. */
  230. void __malloc_unlock()
  231. {
  232. stm32_lock_release(&__lock___malloc_recursive_mutex);
  233. }
  234. #endif /* __STD_C */
  235. /**
  236. * @brief Acquire env lock
  237. * @param reent The reentrance struct
  238. */
  239. void __env_lock(struct _reent *reent)
  240. {
  241. STM32_LOCK_UNUSED(reent);
  242. stm32_lock_acquire(&__lock___env_recursive_mutex);
  243. }
  244. /**
  245. * @brief Release env lock
  246. * @param reent The reentrance struct
  247. */
  248. void __env_unlock(struct _reent *reent)
  249. {
  250. STM32_LOCK_UNUSED(reent);
  251. stm32_lock_release(&__lock___env_recursive_mutex);
  252. }
  253. /**
  254. * @brief Acquire tz lock
  255. */
  256. void __tz_lock()
  257. {
  258. stm32_lock_acquire(&__lock___tz_mutex);
  259. }
  260. /**
  261. * @brief Release tz lock
  262. */
  263. void __tz_unlock()
  264. {
  265. stm32_lock_release(&__lock___tz_mutex);
  266. }
  267. #endif /* __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) */
  268. /**
  269. * @}
  270. */
  271. /**
  272. * @defgroup __cxa_guard_ GNU C++ one-time construction API
  273. * @see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor
  274. *
  275. * When building for C++, please make sure that <tt>-fno-threadsafe-statics</tt> is not passed to the compiler
  276. * @{
  277. */
  278. /* Private typedef -----------------------------------------------------------*/
  279. /** The guard object is created by the C++ compiler and is 32 bit for ARM EABI. */
  280. typedef struct
  281. {
  282. atomic_uchar initialized; /**< Indicate if object is initialized */
  283. uint8_t acquired; /**< Ensure non-recursive lock */
  284. uint16_t unused; /**< Padding */
  285. } __attribute__((packed)) CxaGuardObject_t;
  286. /* Private variables ---------------------------------------------------------*/
  287. /** Mutex used in __cxa_guard_acquire, __cxa_guard_release and __cxa_guard_abort */
  288. static LockingData_t __cxa_guard_mutex = LOCKING_DATA_INIT;
  289. /* Private functions ---------------------------------------------------------*/
  290. /**
  291. * @brief Acquire __cxa_guard mutex
  292. * @param guard_object Guard object
  293. * @return 0 if object is initialized, else initialization of object required
  294. */
  295. int __cxa_guard_acquire(CxaGuardObject_t *guard_object)
  296. {
  297. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
  298. if (atomic_load(&guard_object->initialized) == 0)
  299. {
  300. /* Object needs initialization, lock threading context */
  301. stm32_lock_acquire(&__cxa_guard_mutex);
  302. if (atomic_load(&guard_object->initialized) == 0)
  303. {
  304. /* Object needs initialization */
  305. if (guard_object->acquired)
  306. {
  307. /* Object initialization already in progress */
  308. STM32_LOCK_BLOCK();
  309. }
  310. /* Lock acquired */
  311. guard_object->acquired = 1;
  312. return 1;
  313. }
  314. else
  315. {
  316. /* Object initialized in another thread */
  317. stm32_lock_release(&__cxa_guard_mutex);
  318. }
  319. }
  320. /* Object already initialized */
  321. return 0;
  322. }
  323. /**
  324. * @brief Abort __cxa_guard mutex
  325. * @param guard_object Guard object
  326. */
  327. void __cxa_guard_abort(CxaGuardObject_t *guard_object)
  328. {
  329. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
  330. if (guard_object->acquired)
  331. {
  332. /* Release lock */
  333. guard_object->acquired = 0;
  334. stm32_lock_release(&__cxa_guard_mutex);
  335. }
  336. else
  337. {
  338. /* Trying to release non-acquired lock */
  339. STM32_LOCK_BLOCK();
  340. }
  341. }
  342. /**
  343. * @brief Release __cxa_guard mutex
  344. * @param guard_object Guard object
  345. */
  346. void __cxa_guard_release(CxaGuardObject_t *guard_object)
  347. {
  348. STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
  349. /* Object initialized */
  350. atomic_store(&guard_object->initialized, 1);
  351. /* Release lock */
  352. __cxa_guard_abort(guard_object);
  353. }
  354. /**
  355. * @}
  356. */
  357. #endif /* __SINGLE_THREAD__ */