Skip to content

Commit

Permalink
On MINGW use APR for thread_local data
Browse files Browse the repository at this point in the history
  • Loading branch information
stephen-webb committed Jul 20, 2024
1 parent 62d4cb1 commit b327e57
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 64 deletions.
7 changes: 6 additions & 1 deletion src/cmake/compiler-features/check-compiler-support.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
#

# Does the compiler support thread_local?
try_compile(HAS_THREAD_LOCAL "${CMAKE_BINARY_DIR}/Testing/thread-local-test"
if(MINGW)
# As at 2024-7-19 the msys2 ucrt-x86_64 runtime terminates with error c0000374 during thread local data cleanup
set(HAS_THREAD_LOCAL 0)
else()
try_compile(HAS_THREAD_LOCAL "${CMAKE_BINARY_DIR}/Testing/thread-local-test"
"${CMAKE_CURRENT_LIST_DIR}/test-thread-local.cpp"
CXX_STANDARD 11
)
endif()

# Does the standard library support std::make_unique<T>>?
try_compile(STD_MAKE_UNIQUE_FOUND "${CMAKE_BINARY_DIR}/boost-fallback-compile-tests"
Expand Down
26 changes: 4 additions & 22 deletions src/main/cpp/loggingevent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,29 +333,10 @@ LoggingEvent::KeySet LoggingEvent::getPropertyKeySet() const

const LogString& LoggingEvent::getCurrentThreadName()
{
#if LOG4CXX_HAS_PTHREAD_SELF && !(defined(_WIN32) && defined(_LIBCPP_VERSION))
using ThreadIdType = pthread_t;
ThreadIdType threadId = pthread_self();
#elif defined(_WIN32)
using ThreadIdType = DWORD;
ThreadIdType threadId = GetCurrentThreadId();
#else
using ThreadIdType = int;
ThreadIdType threadId = 0;
#endif

#if LOG4CXX_HAS_THREAD_LOCAL
thread_local LogString thread_id_string;
#else
using ListItem = std::pair<ThreadIdType, LogString>;
static std::list<ListItem> thread_id_map;
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
auto pThreadId = std::find_if(thread_id_map.begin(), thread_id_map.end()
, [threadId](const ListItem& item) { return threadId == item.first; });
if (thread_id_map.end() == pThreadId)
pThreadId = thread_id_map.insert(thread_id_map.begin(), ListItem(threadId, LogString()));
LogString& thread_id_string = pThreadId->second;
LogString& thread_id_string = ThreadSpecificData::getThreadIdString();
#endif
if ( !thread_id_string.empty() )
{
Expand All @@ -365,12 +346,13 @@ const LogString& LoggingEvent::getCurrentThreadName()
#if LOG4CXX_HAS_PTHREAD_SELF && !(defined(_WIN32) && defined(_LIBCPP_VERSION))
// pthread_t encoded in HEX takes needs as many characters
// as two times the size of the type, plus an additional null byte.
auto threadId = pthread_self();
char result[sizeof(pthread_t) * 3 + 10];
apr_snprintf(result, sizeof(result), LOG4CXX_APR_THREAD_FMTSPEC, (void*) &threadId);
thread_id_string = Transcoder::decode(result);
#elif defined(_WIN32)
char result[20];
apr_snprintf(result, sizeof(result), LOG4CXX_WIN32_THREAD_FMTSPEC, threadId);
apr_snprintf(result, sizeof(result), LOG4CXX_WIN32_THREAD_FMTSPEC, GetCurrentThreadId());
thread_id_string = Transcoder::decode(result);
#else
thread_id_string = LOG4CXX_STR("0x00000000");
Expand All @@ -383,7 +365,7 @@ const LogString& LoggingEvent::getCurrentThreadUserName()
#if LOG4CXX_HAS_THREAD_LOCAL
thread_local LogString thread_name;
#else
static LogString thread_name = LOG4CXX_STR("(noname)");
LogString& thread_name = ThreadSpecificData::getThreadName();
#endif
if( !thread_name.empty() ){
return thread_name;
Expand Down
8 changes: 6 additions & 2 deletions src/main/cpp/messagebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct StringOrStream
{}
~StringOrStream()
{
#if !LOG4CXX_HAS_THREAD_LOCAL
#if !LOG4CXX_HAS_THREAD_LOCAL && !APR_HAS_THREADS
delete stream;
#endif
}
Expand All @@ -53,9 +53,13 @@ struct StringOrStream
{
if (!this->stream)
{
#if LOG4CXX_HAS_THREAD_LOCAL
#if LOG4CXX_HAS_THREAD_LOCAL || APR_HAS_THREADS
const static std::basic_ostringstream<T> initialState;
#if LOG4CXX_HAS_THREAD_LOCAL
thread_local static std::basic_ostringstream<T> sStream;
#else
auto& sStream = ThreadSpecificData::getStringStream<T>();
#endif
this->stream = &sStream;
this->stream->clear();
this->stream->precision(initialState.precision());
Expand Down
115 changes: 87 additions & 28 deletions src/main/cpp/threadspecificdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/

#include <log4cxx/log4cxx.h>
#include <log4cxx/logstring.h>
#include <log4cxx/helpers/threadspecificdata.h>
#include <log4cxx/helpers/exception.h>
Expand All @@ -23,13 +24,24 @@
#define LOG4CXX 1
#endif
#include <log4cxx/helpers/aprinitializer.h>
#include <sstream>

using namespace LOG4CXX_NS;
using namespace LOG4CXX_NS::helpers;

struct ThreadSpecificData::ThreadSpecificDataPrivate{
LOG4CXX_NS::NDC::Stack ndcStack;
LOG4CXX_NS::MDC::Map mdcMap;
NDC::Stack ndcStack;
MDC::Map mdcMap;
LogString str[2];
#if !LOG4CXX_LOGCHAR_IS_UNICHAR && !LOG4CXX_LOGCHAR_IS_WCHAR
std::basic_stringstream<logchar> logchar_stringstream;
#endif
#if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR
std::basic_stringstream<wchar_t> wchar_stringstream;
#endif
#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR
std::basic_stringstream<UniChar> unichar_stringstream;
#endif
};

ThreadSpecificData::ThreadSpecificData()
Expand All @@ -42,16 +54,79 @@ ThreadSpecificData::~ThreadSpecificData()
}


LOG4CXX_NS::NDC::Stack& ThreadSpecificData::getStack()
NDC::Stack& ThreadSpecificData::getStack()
{
return m_priv->ndcStack;
}

LOG4CXX_NS::MDC::Map& ThreadSpecificData::getMap()
MDC::Map& ThreadSpecificData::getMap()
{
return m_priv->mdcMap;
}

LogString& ThreadSpecificData::getThreadIdString()
{
if (auto data = getCurrentData())
return data->m_priv->str[0];
#if LOG4CXX_HAS_PTHREAD_SELF && !(defined(_WIN32) && defined(_LIBCPP_VERSION))
using ThreadIdType = pthread_t;
ThreadIdType threadId = pthread_self();
#elif defined(_WIN32)
using ThreadIdType = DWORD;
ThreadIdType threadId = GetCurrentThreadId();
#else
using ThreadIdType = int;
ThreadIdType threadId = 0;
#endif
using ListItem = std::pair<ThreadIdType, LogString>;
static std::list<ListItem> thread_id_map;
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
auto pThreadId = std::find_if(thread_id_map.begin(), thread_id_map.end()
, [threadId](const ListItem& item) { return threadId == item.first; });
if (thread_id_map.end() == pThreadId)
pThreadId = thread_id_map.insert(thread_id_map.begin(), ListItem(threadId, LogString()));
return pThreadId->second;
}

LogString& ThreadSpecificData::getThreadName()
{
if (auto data = getCurrentData())
return data->m_priv->str[1];
static LogString thread_name = LOG4CXX_STR("(noname)");
return thread_name;
}

#if !LOG4CXX_LOGCHAR_IS_UNICHAR && !LOG4CXX_LOGCHAR_IS_WCHAR
std::basic_stringstream<logchar>& ThreadSpecificData::getStream(logchar&)
{
if (auto data = getCurrentData())
return data->m_priv->logchar_stringstream;
static std::basic_stringstream<logchar> ss;
return ss;
}
#endif

#if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR
std::basic_stringstream<wchar_t>& ThreadSpecificData::getStream(wchar_t&)
{
if (auto data = getCurrentData())
return data->m_priv->wchar_stringstream;
static std::basic_stringstream<wchar_t> ss;
return ss;
}
#endif

#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR
std::basic_stringstream<UniChar>& ThreadSpecificData::getStream(UniChar&)
{
if (auto data = getCurrentData())
return data->m_priv->unichar_stringstream;
static std::basic_stringstream<UniChar> ss;
return ss;
}
#endif

ThreadSpecificData& ThreadSpecificData::getDataNoThreads()
{
static WideLife<ThreadSpecificData> noThreadData;
Expand All @@ -63,6 +138,11 @@ ThreadSpecificData* ThreadSpecificData::getCurrentData()
#if APR_HAS_THREADS
void* pData = NULL;
apr_threadkey_private_get(&pData, APRInitializer::getTlsKey());
if (!pData)
{
pData = new ThreadSpecificData();
apr_threadkey_private_set(pData, APRInitializer::getTlsKey());
}
return (ThreadSpecificData*) pData;
#elif LOG4CXX_HAS_THREAD_LOCAL
thread_local ThreadSpecificData data;
Expand Down Expand Up @@ -97,14 +177,7 @@ void ThreadSpecificData::recycle()

void ThreadSpecificData::put(const LogString& key, const LogString& val)
{
ThreadSpecificData* data = getCurrentData();

if (data == 0)
{
data = createCurrentData();
}

if (data != 0)
if (auto data = getCurrentData())
{
data->getMap()[key] = val;
}
Expand All @@ -115,14 +188,7 @@ void ThreadSpecificData::put(const LogString& key, const LogString& val)

void ThreadSpecificData::push(const LogString& val)
{
ThreadSpecificData* data = getCurrentData();

if (data == 0)
{
data = createCurrentData();
}

if (data != 0)
if (auto data = getCurrentData())
{
NDC::Stack& stack = data->getStack();

Expand All @@ -142,14 +208,7 @@ void ThreadSpecificData::push(const LogString& val)

void ThreadSpecificData::inherit(const NDC::Stack& src)
{
ThreadSpecificData* data = getCurrentData();

if (data == 0)
{
data = createCurrentData();
}

if (data != 0)
if (auto data = getCurrentData())
{
data->getStack() = src;
}
Expand Down
20 changes: 18 additions & 2 deletions src/main/include/log4cxx/helpers/threadspecificdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,29 @@ class LOG4CXX_EXPORT ThreadSpecificData
static void push(const LogString& val);
static void inherit(const LOG4CXX_NS::NDC::Stack& stack);

LOG4CXX_NS::NDC::Stack& getStack();
LOG4CXX_NS::MDC::Map& getMap();
NDC::Stack& getStack();
MDC::Map& getMap();

template <typename T>
static std::basic_stringstream<T>& getStringStream()
{
return getStream(T());
}
static LogString& getThreadIdString();
static LogString& getThreadName();

private:
static ThreadSpecificData& getDataNoThreads();
static ThreadSpecificData* createCurrentData();
#if !LOG4CXX_LOGCHAR_IS_UNICHAR && !LOG4CXX_LOGCHAR_IS_WCHAR
static std::basic_stringstream<logchar>& getStream(logchar&);
#endif
#if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR
static std::basic_stringstream<wchar_t>& getStream(wchar_t&);
#endif
#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR
static std::basic_stringstream<UniChar>& getStream(UniChar&);
#endif
LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(ThreadSpecificDataPrivate, m_priv)
};

Expand Down
9 changes: 0 additions & 9 deletions src/test/cpp/asyncappendertestcase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@

#include "logunit.h"

#define LOG4CXX_TEST 1
#include <log4cxx/private/log4cxx_private.h>

#include <log4cxx/logger.h>
#include <log4cxx/logmanager.h>
#include <log4cxx/simplelayout.h>
Expand Down Expand Up @@ -253,13 +250,7 @@ class AsyncAppenderTestCase : public AppenderSkeletonTestCase
{
for (size_t i = 0; i < LEN; i++)
{
// As at 2024-7-19 the msys2 ucrt-x86_64 runtime terminates with error c0000374 during thread local data cleanup
// The call to debug() avoids the use of the thread_local data in MessageBuffer
#if LOG4CXX_HAS_THREAD_LOCAL && LOG4CXX_HAS_PTHREAD_SELF && !(defined(_WIN32) && defined(_LIBCPP_VERSION))
root->debug("message" + std::to_string(i));
#else
LOG4CXX_DEBUG(root, "message" << i);
#endif
}
});
}
Expand Down

0 comments on commit b327e57

Please sign in to comment.