基质喷涂
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.

424 lines
11 KiB

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