feat(build): add CONFIG_COMPILER_CXX_ATOMIC_LOCK_POLICY option

libstdc++ selects between a lock-free and a mutex-based policy for
std::shared_ptr reference counting based on this macro. Enabling this
option forces the lock-free policy, which avoids pulling in the
mutex-based implementation and can reduce code size.

Note: the lock-free policy avoids embedding a mutex in each control
block, saving about 88 bytes per shared_ptr, and improves performance
by using atomic operations instead of mutex locking.

Note: this option changes the ABI of libstdc++ atomic/shared_ptr
helpers. It can be incompatible when linking against prebuilt
libraries that were compiled without it, leading to link errors or
undefined runtime behavior. Only enable it if all C++ objects and
libraries in the build use the same setting.
This commit is contained in:
Alexey Lapshin
2026-07-23 18:20:25 +07:00
parent 480d5f2559
commit b3ae652f21
16 changed files with 239 additions and 0 deletions
@@ -9,3 +9,10 @@ components/cxx/test_apps:
- cxx
- pthread
- freertos
components/cxx/test_apps/atomic_lock_policy:
enable:
- if: IDF_TARGET == "esp32c5"
disable:
- if: IDF_TARGET != "esp32c5"
reason: only built on ESP32-C5
@@ -0,0 +1,7 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.22)
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_cxx_atomic_lock_policy)
@@ -0,0 +1,12 @@
| Supported Targets | ESP32-C5 |
| ----------------- | -------- |
# C++ atomic lock policy test
Build-only app. Validates ``CONFIG_COMPILER_CXX_ATOMIC_LOCK_POLICY``: both
translation units use ``std::shared_ptr`` under the forced lock-free policy, and
the cxx post-build hook accepts the linked executable.
For the negative build-system check (mixed ``__gnu_cxx::_Lock_policy``), see
``tools/test_build_system/test_cxx_atomic_policy.py``, which builds this app with
``-DTEST_INVALID_LOCK_POLICIES=1``.
@@ -0,0 +1,12 @@
idf_component_register(SRCS "test_cxx_atomic_lock_policy.cpp"
"cxx_atomic_a.cpp"
"cxx_atomic_b.cpp")
# Default build: both TUs inherit CONFIG_COMPILER_CXX_ATOMIC_LOCK_POLICY.
# With -DTEST_INVALID_LOCK_POLICIES=1, undefine the macro for one TU so the
# linked image mixes __gnu_cxx::_Lock_policy instantiations; the cxx post-build
# hook (check_cxx_atomic_policy.cmake) must then fail the build.
if(TEST_INVALID_LOCK_POLICIES)
set_source_files_properties("cxx_atomic_b.cpp" PROPERTIES
COMPILE_OPTIONS "-U_GLIBCXX_HAVE_ATOMIC_LOCK_POLICY")
endif()
@@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <memory>
// Compiled with the project-wide atomic lock policy (CONFIG_COMPILER_CXX_ATOMIC_LOCK_POLICY).
// std::make_shared instantiates the __gnu_cxx::_Lock_policy-parameterized
// reference counting templates.
int cxx_atomic_use_a(void)
{
auto p = std::make_shared<int>(1);
return *p;
}
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <memory>
// By default compiled with the same project-wide atomic lock policy as
// cxx_atomic_a.cpp. When TEST_INVALID_LOCK_POLICIES is set, main/CMakeLists.txt
// adds -U_GLIBCXX_HAVE_ATOMIC_LOCK_POLICY so this TU instantiates a different
// __gnu_cxx::_Lock_policy.
int cxx_atomic_use_b(void)
{
auto p = std::make_shared<int>(2);
return *p;
}
@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
int cxx_atomic_use_a(void);
int cxx_atomic_use_b(void);
extern "C" void app_main(void)
{
// Reference both translation units so the linker keeps their
// _Lock_policy instantiations (needed for the invalid-policy build check).
volatile int r = cxx_atomic_use_a() + cxx_atomic_use_b();
printf("cxx atomic lock policy: %d\n", r);
}
@@ -0,0 +1 @@
CONFIG_COMPILER_CXX_ATOMIC_LOCK_POLICY=y