From f242af54901846bb719b7bcc17d2f37e73c39205 Mon Sep 17 00:00:00 2001 From: Canlin Zhang <212407314+canlin-zhang@users.noreply.github.com> Date: Mon, 16 Mar 2026 18:55:21 +0000 Subject: [PATCH] Add per-allocator mutex for transfer_all/transfer_free Each PoolAllocator now has its own std::mutex (transfer_mutex). transfer_all and transfer_free lock only the destination's mutex, since the source is assumed to be accessed only by its owning thread. This avoids deadlocks (only one mutex locked at a time) while protecting the destination when multiple threads transfer concurrently. Also fix lcov coverage mismatch error with gcov-13 templates by adding --ignore-errors mismatch to the coverage capture command. Co-Authored-By: Claude Opus 4.6 (1M context) --- CMakeLists.txt | 2 +- include/pool_allocator/pool_allocator.h | 15 +++++++++++++-- include/pool_allocator/pool_allocator.tcc | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8807f73..f6e065c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ if(ENABLE_COVERAGE) add_custom_target(coverage COMMAND ${CMAKE_COMMAND} --build . --target all COMMAND ctest --output-on-failure - COMMAND ${LCOV_EXEC} --capture --directory ${CMAKE_BINARY_DIR} --output-file coverage.info --ignore-errors gcov,gcov + COMMAND ${LCOV_EXEC} --capture --directory ${CMAKE_BINARY_DIR} --output-file coverage.info --ignore-errors gcov,gcov --ignore-errors mismatch,mismatch COMMAND ${LCOV_EXEC} --remove coverage.info '/usr/*' --output-file coverage.filtered.info COMMAND ${GENHTML_EXEC} coverage.filtered.info --output-directory coverage-report WORKING_DIRECTORY ${CMAKE_BINARY_DIR} diff --git a/include/pool_allocator/pool_allocator.h b/include/pool_allocator/pool_allocator.h index bcb4384..16fc972 100644 --- a/include/pool_allocator/pool_allocator.h +++ b/include/pool_allocator/pool_allocator.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -253,9 +254,14 @@ class PoolAllocator : public pool_allocator_detail::ObjectOpsMixin& from); - // Transfer all memory blocks and free slots from another allocator + + // Transfer all memory blocks and free slots from another allocator. + // Locks this allocator's mutex (destination). The caller must be the owning + // thread of `from` (source) — no lock is taken on the source. void transfer_all(PoolAllocator& from); private: @@ -265,6 +271,11 @@ class PoolAllocator : public pool_allocator_detail::ObjectOpsMixin::transfer_all(PoolAllocator& from) { assert(&from != this && "Cannot import directly from self"); + std::lock_guard lock(transfer_mutex); allocator.transfer_all(from.allocator); } @@ -345,6 +346,7 @@ void PoolAllocator::transfer_free(PoolAllocator& from) { assert(&from != this && "Cannot import directly from self"); + std::lock_guard lock(transfer_mutex); allocator.transfer_free(from.allocator); }