Overview

Purpose

The Thread Safe LibC utility provides the locking hooks required to make the C library (libc) thread‑safe on STM32 targets. It supplies toolchain‑specific glue for newlib (GCC), ARMlibc (ARMCC), and IAR DLib, while allowing each project to select an appropriate locking strategy for its execution model (bare‑metal or FreeRTOS, with configurable permission or restriction of lock usage in ISRs).

Key Features

The main features are:

  • Configurable locking strategies via preprocessor macros: bare‑metal allow/deny, FreeRTOS allow/deny, or user‑defined locks.

  • Multi-toolchain C library integration: ready‑to‑use glue layers for newlib, ARMlibc, and IAR DLib, providing thread‑safe hooks for malloc/free, the C runtime environment, timezone handling, file I/O locking, and C++ static initialization guards.

  • FreeRTOS integration using taskENTER_CRITICAL / taskENTER_CRITICAL_FROM_ISR with bounded nesting.

  • Minimal footprint.

Architecture

The following diagram illustrates the software components involved in the Thread Safe LibC utility. It shows the interactions between the user application, the C library runtime (newlib, ARMlibc, IAR DLib), the Thread Safe LibC utility, and the STM32 target platform.

@startuml Thread_Safe_LibC_architecture
top to bottom direction
skinparam linetype ortho
<style>
componentDiagram {
   arrow {
      FontSize 8
   }
}
</style>

title Thread Safe LibC Architecture Overview

package "Application" {
  component APP as "User Application"
}

package "C Library (libc)" {
  component CRT as "Toolchain runtime\n(newlib / ARMlibc / IAR DLib)"
}

package "Thread Safe LibC Utility" {
  component LOCK_API as "Libc lock Callbacks invoked by libc for Thread Safe LibC initialization"
  component LOCK_BACK as "Configurable locking layer project-selected strategy (bare‑metal / FreeRTOS / custom)"
}

package "System" {
  [STM32 MCU] as HW
  [CMSIS-Core] as CMSIS6CORE
}

APP --> CRT : standard C/C++ calls
CRT --> LOCK_API : libc synchronization callbacks
LOCK_API --> LOCK_BACK : map callbacks to locking layer
LOCK_BACK --> CMSIS6CORE : uses CMSIS core services
CMSIS6CORE --> HW : Device/core access

@enduml

Component Structure

  • Core lock primitives (stm32_lock.h): Defines the configurable lock API (stm32_lock_init, stm32_lock_acquire, stm32_lock_release) and selects the lock strategy (user-defined, bare-metal, or FreeRTOS; allowing or denying lock usage in interrupt context) based on compile‑time macros.

  • Toolchain glue:

    • GCC/newlib (GCC/newlib_lock_glue.c): Implements the newlib lock interface for GCC to protect selected C library functions and provides the __cxa_guard_* hooks for thread-safe one-time initialization of local static objects in C++.

    • ARMCC/ARMlibc (ARM/armlib_lock_glue.c): Provides the ARM C library mutex implementation based on a fixed pool of statically allocated locks and routes _mutex_* operations through the STM32 lock API.

    • IAR/DLib (IAR/dlib_lock_glue.c): Implements the IAR DLib lock interface for system, file, and C++ dynamic locks and performs early thread‑safety initialization before main.

    • All these toolchain-specific lock implementations rely on the common stm32_lock primitives selected by the STM32 thread-safety strategy.

  • User template (stm32_lock_user.h): Provides a template for defining a custom LockingData_t type and implementing stm32_lock_init, stm32_lock_acquire, and stm32_lock_release when STM32_THREAD_SAFE_USER_LOCKS is selected, enabling projects to plug in their own thread‑safety mechanism.

Modules and Files

The following diagram illustrates the Thread Safe LibC module and its associated files.

@startuml Thread_Safe_LibC_modules
skinparam componentStyle rectangle
skinparam ArrowColor #2A4B8D
skinparam ArrowFontSize 10
skinparam RectangleBackgroundColor #FFFFFF
skinparam RectangleBorderColor #2A4B8D
skinparam Shadowing false
skinparam linetype ortho

title Thread Safe LibC Modules Overview

top to bottom direction

' Application
package "Application" {
  component APP as "User Application"
}

' Thread Safe LibC module
package "Thread Safe LibC" {

  ' Anchor component used as a visual entry point
  component TSL_ENTRY as "Thread Safe LibC\n(entry point)" #FFFFFF

  package "Toolchain glue" {
    component GCC_GLUE as "GCC/newlib_lock_glue.c"
    component ARM_GLUE as "ARM/armlib_lock_glue.c"
    component IAR_GLUE as "IAR/dlib_lock_glue.c"
  }

  package "Core lock primitives" {
    component LOCK_H as "stm32_lock.h"
    component USER_H as "stm32_lock_user.h\n(optional)" #F9F7D1
  }
}

' Application uses the module via its entry point
APP --> TSL_ENTRY : uses libc /\nThread Safe LibC init

' Entry point connected to glue layer (toolchain-specific)
TSL_ENTRY --> GCC_GLUE : GCC / newlib
TSL_ENTRY --> ARM_GLUE : ARMCC / ARMlibc
TSL_ENTRY --> IAR_GLUE : IAR / DLib

' Glue files include core lock header
GCC_GLUE --> LOCK_H : include
ARM_GLUE --> LOCK_H : include
IAR_GLUE --> LOCK_H : include

USER_H --> LOCK_H : include

note right of USER_H
Used when
STM32_THREAD_SAFE_USER_LOCKS
is selected
end note

@enduml

Configuration table

The following table lists the configuration defines for the Thread Safe LibC module:

Config Defines

Where

Description

STM32_THREAD_SAFE_USER_LOCKS

Preprocessor environment

Enables a user-defined locking implementation ( stm32_lock_user.h)

STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS

Preprocessor environment

Enables the bare-metal strategy that allows lock usage from interrupts

STM32_THREAD_SAFE_BAREMETAL_DENY_LOCKS

Preprocessor environment

Enables the bare-metal strategy that denies lock usage from interrupts

STM32_THREAD_SAFE_FREERTOS_ALLOW_LOCKS

Preprocessor environment

Enables the FreeRTOS-based strategy that allows lock usage from tasks and ISRs

STM32_THREAD_SAFE_FREERTOS_DENY_LOCKS

Preprocessor environment

Enables the FreeRTOS-based strategy that denies lock usage from tasks and ISRs

STM32_THREAD_SAFE_STRATEGY

Preprocessor environment

Legacy selector: values 1..5 to choose one of the strategies above (1 = user, 2 = bare‑metal allow, 3 = bare‑metal deny, 4 = FreeRTOS allow, 5 = FreeRTOS deny)