Make message macros (FAIL, WARN, INFO, etc) thread safe

This builds on the existing work to make assertion thread safe,
by adding an extra synchronization point in the holder of
`ReusableStringStream`'s stream instances, as those are used to
build the messages, and finishing the move of message scope holders
to be thread-local.
This commit is contained in:
Martin Hořeňovský
2025-08-23 00:15:53 +02:00
parent f4e05a67bb
commit 582200a1f8
7 changed files with 165 additions and 54 deletions

View File

@@ -7,6 +7,7 @@
// SPDX-License-Identifier: BSL-1.0
#include <catch2/internal/catch_reusable_string_stream.hpp>
#include <catch2/internal/catch_singletons.hpp>
#include <catch2/internal/catch_thread_support.hpp>
#include <catch2/internal/catch_unique_ptr.hpp>
#include <cstdio>
@@ -20,8 +21,10 @@ namespace Catch {
std::vector<Detail::unique_ptr<std::ostringstream>> m_streams;
std::vector<std::size_t> m_unused;
std::ostringstream m_referenceStream; // Used for copy state/ flags from
Detail::Mutex m_mutex;
auto add() -> std::size_t {
Detail::LockGuard _( m_mutex );
if( m_unused.empty() ) {
m_streams.push_back( Detail::make_unique<std::ostringstream>() );
return m_streams.size()-1;
@@ -33,9 +36,13 @@ namespace Catch {
}
}
void release( std::size_t index ) {
m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
m_unused.push_back(index);
void release( std::size_t index, std::ostream* originalPtr ) {
assert( originalPtr );
originalPtr->copyfmt( m_referenceStream ); // Restore initial flags and other state
Detail::LockGuard _( m_mutex );
assert( originalPtr == m_streams[index].get() && "Mismatch between release index and stream ptr" );
m_unused.push_back( index );
}
};
@@ -47,7 +54,7 @@ namespace Catch {
ReusableStringStream::~ReusableStringStream() {
static_cast<std::ostringstream*>( m_oss )->str("");
m_oss->clear();
Singleton<StringStreams>::getMutable().release( m_index );
Singleton<StringStreams>::getMutable().release( m_index, m_oss );
}
std::string ReusableStringStream::str() const {