This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

GCC 12.2 libc_nano exporting retargetable locking functions and data

Hi,

While upgrading a project from the 11.2 to 12.2 releases of the GNU ARM Embedded toolchain, I'm encountering a problem:


[344/346] cmd.exe /C "cd . && C:\tools\jetbrains\apps\CLion\ch-0\223.8617.54\bin\cmake\win\x64\bin\cmake.exe -E rm -f ext\soup\hal\libstm32h7_hal_resmgr.a && C:\PROGRA~2\ARMGNU~1\12DBAB~1.2RE\bin\ARM-NO~2.EXE qc ext\soup\hal\libstm32h7_hal_resmgr.a  ext/soup/hal/CMakeFiles/stm32h7_hal_resmgr.dir/STM32CubeH7/Utilities/ResourcesManager/res_mgr.c.obj && C:\PROGRA~2\ARMGNU~1\12DBAB~1.2RE\bin\AR17F9~1.EXE ext\soup\hal\libstm32h7_hal_resmgr.a && cd ."
[345/346] cmd.exe /C "cd . && C:\PROGRA~2\ARMGNU~1\12DBAB~1.2RE\bin\AR19DD~1.EXE -O0 -g3 -DDEBUG -TC:/src/h7-eval/CM4/STM32H757XIHX_FLASH.ld -Wl,--cref -Wl,--print-memory-usage -Wl,-Map=C:/src/cmake-build-h7m4-debug-gnu-arm-113/h7-eval/CM4/h7-eval-m4.map -mthumb -mcpu=cortex-m4 -mabi=aapcs --specs=nano.specs -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -static -Wl,--start-group -lc -lm -Wl,--end-group h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/Common/Src/system_stm32h7xx_dualcore_boot_cm4_cm7.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/adc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/crc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/cryp.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/dcmi.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/dma2d.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/eth.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/fmc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/gpio.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/hash.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/i2c.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/main.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/resmgr_utility.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/rng.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/spi.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/stm32h7xx_hal_msp.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/stm32h7xx_it.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/syscalls.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/sysmem.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/tim.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/usart.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Startup/startup_stm32h757xihx.s.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/ThreadX/tx_initialize_low_level.S.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/ThreadX/stm32h7xx_hal_timebase_tim.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/__/ext/soup/threadx/threadx/utility/execution_profile_kit/tx_execution_profile.c.obj -o h7-eval\CM4\h7-eval-m4.elf  ext/soup/hal/libstm32h7_hal.a  ext/soup/hal/libstm32h7_hal_resmgr.a  ext/soup/threadx/threadx/libthreadx.a  ext/soup/hal/libstm32h7_hal.a && cd ."
FAILED: h7-eval/CM4/h7-eval-m4.elf 
cmd.exe /C "cd . && C:\PROGRA~2\ARMGNU~1\12DBAB~1.2RE\bin\AR19DD~1.EXE -O0 -g3 -DDEBUG -TC:/src/h7-eval/CM4/STM32H757XIHX_FLASH.ld -Wl,--cref -Wl,--print-memory-usage -Wl,-Map=C:/src/cmake-build-h7m4-debug-gnu-arm-113/h7-eval/CM4/h7-eval-m4.map -mthumb -mcpu=cortex-m4 -mabi=aapcs --specs=nano.specs -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -static -Wl,--start-group -lc -lm -Wl,--end-group h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/Common/Src/system_stm32h7xx_dualcore_boot_cm4_cm7.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/adc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/crc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/cryp.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/dcmi.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/dma2d.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/eth.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/fmc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/gpio.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/hash.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/i2c.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/main.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/resmgr_utility.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/rng.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/spi.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/stm32h7xx_hal_msp.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/stm32h7xx_it.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/syscalls.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/sysmem.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/tim.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/usart.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Startup/startup_stm32h757xihx.s.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/ThreadX/tx_initialize_low_level.S.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/ThreadX/stm32h7xx_hal_timebase_tim.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/__/ext/soup/threadx/threadx/utility/execution_profile_kit/tx_execution_profile.c.obj -o h7-eval\CM4\h7-eval-m4.elf  ext/soup/hal/libstm32h7_hal.a  ext/soup/hal/libstm32h7_hal_resmgr.a  ext/soup/threadx/threadx/libthreadx.a  ext/soup/hal/libstm32h7_hal.a && cd ."
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:84: multiple definition of `__lock___sfp_recursive_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___sfp_recursive_mutex+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:87: multiple definition of `__lock___atexit_recursive_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___atexit_recursive_mutex+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:90: multiple definition of `__lock___at_quick_exit_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___at_quick_exit_mutex+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:93: multiple definition of `__lock___malloc_recursive_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___malloc_recursive_mutex+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:96: multiple definition of `__lock___env_recursive_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___env_recursive_mutex+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:99: multiple definition of `__lock___tz_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___tz_mutex+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:102: multiple definition of `__lock___dd_hash_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___dd_hash_mutex+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:105: multiple definition of `__lock___arc4random_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___arc4random_mutex+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_init':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:114: multiple definition of `__retarget_lock_init'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_init+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_init_recursive':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:123: multiple definition of `__retarget_lock_init_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_init_recursive+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_close':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:146: multiple definition of `__retarget_lock_close'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_close+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_close_recursive':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:155: multiple definition of `__retarget_lock_close_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_close_recursive+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_acquire':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:164: multiple definition of `__retarget_lock_acquire'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_acquire+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_acquire_recursive':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:174: multiple definition of `__retarget_lock_acquire_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_acquire_recursive+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_try_acquire':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:185: multiple definition of `__retarget_lock_try_acquire'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_try_acquire+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_try_acquire_recursive':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:196: multiple definition of `__retarget_lock_try_acquire_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_try_acquire_recursive+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_release':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:206: multiple definition of `__retarget_lock_release'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_release+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_release_recursive':
C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:216: multiple definition of `__retarget_lock_release_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_release_recursive+0x0): first defined here
c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: warning: h7-eval\CM4\h7-eval-m4.elf has a LOAD segment with RWX permissions
Memory region         Used Size  Region Size  %age Used
           FLASH:       53940 B         1 MB      5.14%
             RAM:          7 KB       288 KB      2.43%
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

This is due to the version of libc_nano included with the 12.2 release including the retargetable locking functions (the stubs?).  Is this a mistake?  They aren't weak so can't be overridden by the project to provide its own locking implementation.

libc_a-lock.o:
00000000 B __lock___arc4random_mutex
00000000 B __lock___atexit_recursive_mutex
00000000 B __lock___at_quick_exit_mutex
00000000 B __lock___dd_hash_mutex
00000000 B __lock___env_recursive_mutex
00000000 B __lock___malloc_recursive_mutex
00000000 B __lock___sfp_recursive_mutex
00000000 B __lock___tz_mutex
00000001 T __retarget_lock_acquire
00000001 T __retarget_lock_acquire_recursive
00000001 T __retarget_lock_close
00000001 T __retarget_lock_close_recursive
00000001 T __retarget_lock_init
00000001 T __retarget_lock_init_recursive
00000001 T __retarget_lock_release
00000001 T __retarget_lock_release_recursive
00000001 T __retarget_lock_try_acquire
00000001 T __retarget_lock_try_acquire_recursive

These symbols were not exported by the 11.2 build.  They conflict with the newlib_lock_glue.c generated by STM32CubeMX for STM32 projects (in this case, an H7 project).  I thought these retargetable locking functions were supposed to be implemented by the user, and that a default implementation was not possible for a bare metal application.  What is the intention for projects to do to work with GCC 12.2 newlib_nano?

Parents
  • /**
      ******************************************************************************
      * @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) 2022 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 <cmsis_compiler.h>
    
    /* 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 <newlib.h>
    #include <stdatomic.h>
    #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 <errno.h>
    #include <stdlib.h>
    #include <sys/lock.h>
    
    /* Private macros ------------------------------------------------------------*/
    /** See struct __lock definition */
    #define STM32_LOCK_PARAMETER(lock) (&(lock)->lock_data)
    
    /* Private variables ---------------------------------------------------------*/
    struct __lock
    {
      LockingData_t lock_data; /**< The STM32 lock instance */
    };
    
    /** 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> */
    struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    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 <reent.h>
    
    /* 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 <tt>-fno-threadsafe-statics</tt> 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 ---------------------------------------------------------*/
    
    /**
      * @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__ */
    
    /**
      ******************************************************************************
      * @file      stm32_lock.h
      * @author    STMicroelectronics
      * @brief     STMicroelectronics lock mechanisms
      *
      * @details
      * This implementation supports the following strategies for handling
      * thread-safe locks. The strategy can be explicitly selected by
      * defining <tt>\STM32_THREAD_SAFE_STRATEGY = \<number></tt> in the project.
      * Please look at the '<toolchain/library>_lock_glue.c' file for more details.
      *
      * 1. User defined thread-safe implementation.
      *    User defined solution for handling thread-safety.
      *    <br>
      *    <b>NOTE:</b> The stubs in stm32_lock_user.h needs to be implemented to gain
      *    thread-safety.
      *
      * 2. [<b>DEFAULT</b>] Allow lock usage from interrupts.
      *    This implementation will ensure thread-safety by disabling all interrupts
      *    during e.g. calls to malloc.
      *    <br>
      *    <b>NOTE:</b> Disabling all interrupts creates interrupt latency which
      *    might not be desired for this application!
      *
      * 3. Deny lock usage from interrupts.
      *    This implementation assumes single thread of execution.
      *    <br>
      *    <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop
      *    if used in interrupt context.
      *
      * 4. Allow lock usage from interrupts. Implemented using FreeRTOS locks.
      *    This implementation will ensure thread-safety by entering RTOS ISR capable
      *    critical sections during e.g. calls to malloc.
      *    By default this implementation supports 2 levels of recursive locking.
      *    Adding additional levels requires 4 bytes per lock per level of RAM.
      *    <br>
      *    <b>NOTE:</b> Interrupts with high priority are not disabled. This implies
      *    that the lock is not thread-safe from high priority interrupts!
      *
      * 5. Deny lock usage from interrupts. Implemented using FreeRTOS locks.
      *    This implementation will ensure thread-safety by suspending all tasks
      *    during e.g. calls to malloc.
      *    <br>
      *    <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop
      *    if used in interrupt context.
      *
      ******************************************************************************
      * @attention
      *
      * Copyright (c) 2022 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.
      *
      ******************************************************************************
      */
    
    #ifndef __STM32_LOCK_H__
    #define __STM32_LOCK_H__
    
    /* Includes ------------------------------------------------------------------*/
    #include <stdint.h>
    #include <stddef.h>
    #include <cmsis_compiler.h>
    
    #ifndef STM32_THREAD_SAFE_STRATEGY
    #define STM32_THREAD_SAFE_STRATEGY 2 /**< Assume strategy 2 if not specified */
    #endif /* STM32_THREAD_SAFE_STRATEGY */
    
    #ifdef __cplusplus
    extern "C" {
    #endif /* __cplusplus */
    
    /* Function prototypes -------------------------------------------------------*/
    void Error_Handler(void);
    
    /* Public macros -------------------------------------------------------------*/
    /** Blocks execution */
    #define STM32_LOCK_BLOCK()                      \
      do                                            \
      {                                             \
        __disable_irq();                            \
        Error_Handler();                            \
        while (1);                                  \
      } while (0)
    
    /** Blocks execution if argument is NULL */
    #define STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(x)    \
      do                                            \
      {                                             \
        if ((x) == NULL)                            \
        {                                           \
          STM32_LOCK_BLOCK();                       \
        }                                           \
      } while (0)
    
    /** Blocks execution if in interrupt context */
    #define STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT() \
      do                                            \
      {                                             \
        if (__get_IPSR())                           \
        {                                           \
          STM32_LOCK_BLOCK();                       \
        }                                           \
      } while (0)
    
    /** Hide unused parameter warning from compiler */
    #define STM32_LOCK_UNUSED(var) (void)var
    
    /** Size of array */
    #define STM32_LOCK_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
    
    #if STM32_THREAD_SAFE_STRATEGY == 1
    /*
     * User defined thread-safe implementation.
     */
    
    /* Includes ----------------------------------------------------------------*/
    /** STM32 lock API version */
    #define STM32_LOCK_API 1
    #include "stm32_lock_user.h"
    #undef STM32_LOCK_API
    
    #elif STM32_THREAD_SAFE_STRATEGY == 2
    /*
     * Allow lock usage from interrupts.
     */
    
    /* Private defines ---------------------------------------------------------*/
    /** Initialize members in instance of <code>LockingData_t</code> structure */
    #define LOCKING_DATA_INIT { 0, 0 }
    
    /* Private typedef ---------------------------------------------------------*/
    typedef struct
    {
      uint8_t flag; /**< Backup of PRIMASK.PM at nesting level 0 */
      uint8_t counter; /**< Nesting level */
    } LockingData_t;
    
    /* Private functions -------------------------------------------------------*/
    
    /**
      * @brief Initialize STM32 lock
      * @param lock The lock to init
      */
    static inline void stm32_lock_init(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      lock->flag = 0;
      lock->counter = 0;
    }
    
    /**
      * @brief Acquire STM32 lock
      * @param lock The lock to acquire
      */
    static inline void stm32_lock_acquire(LockingData_t *lock)
    {
      uint8_t flag = (uint8_t)(__get_PRIMASK() & 0x1); /* PRIMASK.PM */
      __disable_irq();
      __DSB();
      __ISB();
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      if (lock->counter == 0)
      {
        lock->flag = flag;
      }
      else if (lock->counter == UINT8_MAX)
      {
        STM32_LOCK_BLOCK();
      }
      lock->counter++;
    }
    
    /**
      * @brief Release STM32 lock
      * @param lock The lock to release
      */
    static inline void stm32_lock_release(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      if (lock->counter == 0)
      {
        STM32_LOCK_BLOCK();
      }
      lock->counter--;
      if (lock->counter == 0 && lock->flag == 0)
      {
        __enable_irq();
      }
    }
    
    #elif STM32_THREAD_SAFE_STRATEGY == 3
    /*
     * Deny lock usage from interrupts.
     */
    
    /* Private defines ---------------------------------------------------------*/
    /** Initialize members in instance of <code>LockingData_t</code> structure */
    #define LOCKING_DATA_INIT 0
    
    /* Private typedef ---------------------------------------------------------*/
    typedef uint8_t LockingData_t;  /**< Unused */
    
    /* Private functions -------------------------------------------------------*/
    
    /**
      * @brief Initialize STM32 lock
      * @param lock The lock to init
      */
    static inline void stm32_lock_init(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
    }
    
    /**
      * @brief Acquire STM32 lock
      * @param lock The lock to acquire
      */
    static inline void stm32_lock_acquire(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
    }
    
    /**
      * @brief Release ST lock
      * @param lock The lock to release
      */
    static inline void stm32_lock_release(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
    }
    
    #elif STM32_THREAD_SAFE_STRATEGY == 4
    /*
     * Allow lock usage from interrupts. Implemented using FreeRTOS locks.
     */
    
    /* Includes ----------------------------------------------------------------*/
    #include <FreeRTOS.h>
    #include <task.h>
    
    #if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0
    #warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe
    #endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */
    
    /* Private defines ---------------------------------------------------------*/
    /** Initialize members in instance of <code>LockingData_t</code> structure */
    #define LOCKING_DATA_INIT { {0, 0}, 0 }
    #define STM32_LOCK_MAX_NESTED_LEVELS 2 /**< Max nesting level of interrupts */
    typedef struct
    {
      uint32_t basepri[STM32_LOCK_MAX_NESTED_LEVELS];
      uint8_t nesting_level;
    } LockingData_t;
    
    /* Private macros ----------------------------------------------------------*/
    /** Blocks execution if reached max nesting level */
    #define STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock)                   \
      do                                                                  \
      {                                                                   \
        if (lock->nesting_level >= STM32_LOCK_ARRAY_SIZE(lock->basepri))  \
        {                                                                 \
          STM32_LOCK_BLOCK();                                             \
        }                                                                 \
      } while (0)
    
    /* Private functions -------------------------------------------------------*/
    
    /**
      * @brief Initialize STM32 lock
      * @param lock The lock to init
      */
    static inline void stm32_lock_init(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      for (size_t i = 0; i < STM32_LOCK_ARRAY_SIZE(lock->basepri); i++)
      {
        lock->basepri[i] = 0;
      }
      lock->nesting_level = 0;
    }
    
    /**
      * @brief Acquire STM32 lock
      * @param lock The lock to acquire
      */
    static inline void stm32_lock_acquire(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock);
      lock->basepri[lock->nesting_level++] = taskENTER_CRITICAL_FROM_ISR();
    }
    
    /**
      * @brief Release STM32 lock
      * @param lock The lock to release
      */
    static inline void stm32_lock_release(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      lock->nesting_level--;
      STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock);
      taskEXIT_CRITICAL_FROM_ISR(lock->basepri[lock->nesting_level]);
    }
    
    #undef STM32_LOCK_ASSERT_VALID_NESTING_LEVEL
    #undef STM32_LOCK_MAX_NESTED_LEVELS
    
    #elif STM32_THREAD_SAFE_STRATEGY == 5
    /*
     * Deny lock usage from interrupts. Implemented using FreeRTOS locks.
     */
    
    /* Includes ----------------------------------------------------------------*/
    #include <FreeRTOS.h>
    #include <task.h>
    #if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0
    #warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe
    #endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */
    
    /* Private defines ---------------------------------------------------------*/
    /** Initialize members in instance of <code>LockingData_t</code> structure */
    #define LOCKING_DATA_INIT 0
    
    /* Private typedef ---------------------------------------------------------*/
    typedef uint8_t LockingData_t;  /**< Unused */
    
    /* Private functions -------------------------------------------------------*/
    
    /**
      * @brief Initialize STM32 lock
      * @param lock The lock to init
      */
    static inline void stm32_lock_init(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
    }
    
    /**
      * @brief Acquire STM32 lock
      * @param lock The lock to acquire
      */
    static inline void stm32_lock_acquire(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
      vTaskSuspendAll();
    }
    
    /**
      * @brief Release STM32 lock
      * @param lock The lock to release
      */
    static inline void stm32_lock_release(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
      xTaskResumeAll();
    }
    
    #else
    #error Invalid STM32_THREAD_SAFE_STRATEGY specified
    #endif /* STM32_THREAD_SAFE_STRATEGY */
    
    #ifdef __cplusplus
    } /* extern "C" */
    #endif /* __cplusplus */
    
    #endif /* __STM32_LOCK_H__ */
    

    I have attached the autogenerated files containing the libc locking glue code.  I can certainly update these if there are partial definitions which result in the doubly-defined symbol error.  However, the code generator which emits these might also need updating to match.  Are these what you would expect for a custom implementation of the locking interface?

    Thanks,

    Roger

Reply
  • /**
      ******************************************************************************
      * @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) 2022 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 <cmsis_compiler.h>
    
    /* 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 <newlib.h>
    #include <stdatomic.h>
    #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 <errno.h>
    #include <stdlib.h>
    #include <sys/lock.h>
    
    /* Private macros ------------------------------------------------------------*/
    /** See struct __lock definition */
    #define STM32_LOCK_PARAMETER(lock) (&(lock)->lock_data)
    
    /* Private variables ---------------------------------------------------------*/
    struct __lock
    {
      LockingData_t lock_data; /**< The STM32 lock instance */
    };
    
    /** 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> */
    struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT };
    
    /** 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> */
    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 <reent.h>
    
    /* 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 <tt>-fno-threadsafe-statics</tt> 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 ---------------------------------------------------------*/
    
    /**
      * @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__ */
    
    /**
      ******************************************************************************
      * @file      stm32_lock.h
      * @author    STMicroelectronics
      * @brief     STMicroelectronics lock mechanisms
      *
      * @details
      * This implementation supports the following strategies for handling
      * thread-safe locks. The strategy can be explicitly selected by
      * defining <tt>\STM32_THREAD_SAFE_STRATEGY = \<number></tt> in the project.
      * Please look at the '<toolchain/library>_lock_glue.c' file for more details.
      *
      * 1. User defined thread-safe implementation.
      *    User defined solution for handling thread-safety.
      *    <br>
      *    <b>NOTE:</b> The stubs in stm32_lock_user.h needs to be implemented to gain
      *    thread-safety.
      *
      * 2. [<b>DEFAULT</b>] Allow lock usage from interrupts.
      *    This implementation will ensure thread-safety by disabling all interrupts
      *    during e.g. calls to malloc.
      *    <br>
      *    <b>NOTE:</b> Disabling all interrupts creates interrupt latency which
      *    might not be desired for this application!
      *
      * 3. Deny lock usage from interrupts.
      *    This implementation assumes single thread of execution.
      *    <br>
      *    <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop
      *    if used in interrupt context.
      *
      * 4. Allow lock usage from interrupts. Implemented using FreeRTOS locks.
      *    This implementation will ensure thread-safety by entering RTOS ISR capable
      *    critical sections during e.g. calls to malloc.
      *    By default this implementation supports 2 levels of recursive locking.
      *    Adding additional levels requires 4 bytes per lock per level of RAM.
      *    <br>
      *    <b>NOTE:</b> Interrupts with high priority are not disabled. This implies
      *    that the lock is not thread-safe from high priority interrupts!
      *
      * 5. Deny lock usage from interrupts. Implemented using FreeRTOS locks.
      *    This implementation will ensure thread-safety by suspending all tasks
      *    during e.g. calls to malloc.
      *    <br>
      *    <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop
      *    if used in interrupt context.
      *
      ******************************************************************************
      * @attention
      *
      * Copyright (c) 2022 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.
      *
      ******************************************************************************
      */
    
    #ifndef __STM32_LOCK_H__
    #define __STM32_LOCK_H__
    
    /* Includes ------------------------------------------------------------------*/
    #include <stdint.h>
    #include <stddef.h>
    #include <cmsis_compiler.h>
    
    #ifndef STM32_THREAD_SAFE_STRATEGY
    #define STM32_THREAD_SAFE_STRATEGY 2 /**< Assume strategy 2 if not specified */
    #endif /* STM32_THREAD_SAFE_STRATEGY */
    
    #ifdef __cplusplus
    extern "C" {
    #endif /* __cplusplus */
    
    /* Function prototypes -------------------------------------------------------*/
    void Error_Handler(void);
    
    /* Public macros -------------------------------------------------------------*/
    /** Blocks execution */
    #define STM32_LOCK_BLOCK()                      \
      do                                            \
      {                                             \
        __disable_irq();                            \
        Error_Handler();                            \
        while (1);                                  \
      } while (0)
    
    /** Blocks execution if argument is NULL */
    #define STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(x)    \
      do                                            \
      {                                             \
        if ((x) == NULL)                            \
        {                                           \
          STM32_LOCK_BLOCK();                       \
        }                                           \
      } while (0)
    
    /** Blocks execution if in interrupt context */
    #define STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT() \
      do                                            \
      {                                             \
        if (__get_IPSR())                           \
        {                                           \
          STM32_LOCK_BLOCK();                       \
        }                                           \
      } while (0)
    
    /** Hide unused parameter warning from compiler */
    #define STM32_LOCK_UNUSED(var) (void)var
    
    /** Size of array */
    #define STM32_LOCK_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
    
    #if STM32_THREAD_SAFE_STRATEGY == 1
    /*
     * User defined thread-safe implementation.
     */
    
    /* Includes ----------------------------------------------------------------*/
    /** STM32 lock API version */
    #define STM32_LOCK_API 1
    #include "stm32_lock_user.h"
    #undef STM32_LOCK_API
    
    #elif STM32_THREAD_SAFE_STRATEGY == 2
    /*
     * Allow lock usage from interrupts.
     */
    
    /* Private defines ---------------------------------------------------------*/
    /** Initialize members in instance of <code>LockingData_t</code> structure */
    #define LOCKING_DATA_INIT { 0, 0 }
    
    /* Private typedef ---------------------------------------------------------*/
    typedef struct
    {
      uint8_t flag; /**< Backup of PRIMASK.PM at nesting level 0 */
      uint8_t counter; /**< Nesting level */
    } LockingData_t;
    
    /* Private functions -------------------------------------------------------*/
    
    /**
      * @brief Initialize STM32 lock
      * @param lock The lock to init
      */
    static inline void stm32_lock_init(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      lock->flag = 0;
      lock->counter = 0;
    }
    
    /**
      * @brief Acquire STM32 lock
      * @param lock The lock to acquire
      */
    static inline void stm32_lock_acquire(LockingData_t *lock)
    {
      uint8_t flag = (uint8_t)(__get_PRIMASK() & 0x1); /* PRIMASK.PM */
      __disable_irq();
      __DSB();
      __ISB();
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      if (lock->counter == 0)
      {
        lock->flag = flag;
      }
      else if (lock->counter == UINT8_MAX)
      {
        STM32_LOCK_BLOCK();
      }
      lock->counter++;
    }
    
    /**
      * @brief Release STM32 lock
      * @param lock The lock to release
      */
    static inline void stm32_lock_release(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      if (lock->counter == 0)
      {
        STM32_LOCK_BLOCK();
      }
      lock->counter--;
      if (lock->counter == 0 && lock->flag == 0)
      {
        __enable_irq();
      }
    }
    
    #elif STM32_THREAD_SAFE_STRATEGY == 3
    /*
     * Deny lock usage from interrupts.
     */
    
    /* Private defines ---------------------------------------------------------*/
    /** Initialize members in instance of <code>LockingData_t</code> structure */
    #define LOCKING_DATA_INIT 0
    
    /* Private typedef ---------------------------------------------------------*/
    typedef uint8_t LockingData_t;  /**< Unused */
    
    /* Private functions -------------------------------------------------------*/
    
    /**
      * @brief Initialize STM32 lock
      * @param lock The lock to init
      */
    static inline void stm32_lock_init(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
    }
    
    /**
      * @brief Acquire STM32 lock
      * @param lock The lock to acquire
      */
    static inline void stm32_lock_acquire(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
    }
    
    /**
      * @brief Release ST lock
      * @param lock The lock to release
      */
    static inline void stm32_lock_release(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
    }
    
    #elif STM32_THREAD_SAFE_STRATEGY == 4
    /*
     * Allow lock usage from interrupts. Implemented using FreeRTOS locks.
     */
    
    /* Includes ----------------------------------------------------------------*/
    #include <FreeRTOS.h>
    #include <task.h>
    
    #if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0
    #warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe
    #endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */
    
    /* Private defines ---------------------------------------------------------*/
    /** Initialize members in instance of <code>LockingData_t</code> structure */
    #define LOCKING_DATA_INIT { {0, 0}, 0 }
    #define STM32_LOCK_MAX_NESTED_LEVELS 2 /**< Max nesting level of interrupts */
    typedef struct
    {
      uint32_t basepri[STM32_LOCK_MAX_NESTED_LEVELS];
      uint8_t nesting_level;
    } LockingData_t;
    
    /* Private macros ----------------------------------------------------------*/
    /** Blocks execution if reached max nesting level */
    #define STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock)                   \
      do                                                                  \
      {                                                                   \
        if (lock->nesting_level >= STM32_LOCK_ARRAY_SIZE(lock->basepri))  \
        {                                                                 \
          STM32_LOCK_BLOCK();                                             \
        }                                                                 \
      } while (0)
    
    /* Private functions -------------------------------------------------------*/
    
    /**
      * @brief Initialize STM32 lock
      * @param lock The lock to init
      */
    static inline void stm32_lock_init(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      for (size_t i = 0; i < STM32_LOCK_ARRAY_SIZE(lock->basepri); i++)
      {
        lock->basepri[i] = 0;
      }
      lock->nesting_level = 0;
    }
    
    /**
      * @brief Acquire STM32 lock
      * @param lock The lock to acquire
      */
    static inline void stm32_lock_acquire(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock);
      lock->basepri[lock->nesting_level++] = taskENTER_CRITICAL_FROM_ISR();
    }
    
    /**
      * @brief Release STM32 lock
      * @param lock The lock to release
      */
    static inline void stm32_lock_release(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      lock->nesting_level--;
      STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock);
      taskEXIT_CRITICAL_FROM_ISR(lock->basepri[lock->nesting_level]);
    }
    
    #undef STM32_LOCK_ASSERT_VALID_NESTING_LEVEL
    #undef STM32_LOCK_MAX_NESTED_LEVELS
    
    #elif STM32_THREAD_SAFE_STRATEGY == 5
    /*
     * Deny lock usage from interrupts. Implemented using FreeRTOS locks.
     */
    
    /* Includes ----------------------------------------------------------------*/
    #include <FreeRTOS.h>
    #include <task.h>
    #if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0
    #warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe
    #endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */
    
    /* Private defines ---------------------------------------------------------*/
    /** Initialize members in instance of <code>LockingData_t</code> structure */
    #define LOCKING_DATA_INIT 0
    
    /* Private typedef ---------------------------------------------------------*/
    typedef uint8_t LockingData_t;  /**< Unused */
    
    /* Private functions -------------------------------------------------------*/
    
    /**
      * @brief Initialize STM32 lock
      * @param lock The lock to init
      */
    static inline void stm32_lock_init(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
    }
    
    /**
      * @brief Acquire STM32 lock
      * @param lock The lock to acquire
      */
    static inline void stm32_lock_acquire(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
      vTaskSuspendAll();
    }
    
    /**
      * @brief Release STM32 lock
      * @param lock The lock to release
      */
    static inline void stm32_lock_release(LockingData_t *lock)
    {
      STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
      STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT();
      xTaskResumeAll();
    }
    
    #else
    #error Invalid STM32_THREAD_SAFE_STRATEGY specified
    #endif /* STM32_THREAD_SAFE_STRATEGY */
    
    #ifdef __cplusplus
    } /* extern "C" */
    #endif /* __cplusplus */
    
    #endif /* __STM32_LOCK_H__ */
    

    I have attached the autogenerated files containing the libc locking glue code.  I can certainly update these if there are partial definitions which result in the doubly-defined symbol error.  However, the code generator which emits these might also need updating to match.  Are these what you would expect for a custom implementation of the locking interface?

    Thanks,

    Roger

Children
No data