diff --git a/src/cmake/compiler-features/check-compiler-support.cmake b/src/cmake/compiler-features/check-compiler-support.cmake index 7f5f9a3a5..6e41490b7 100644 --- a/src/cmake/compiler-features/check-compiler-support.cmake +++ b/src/cmake/compiler-features/check-compiler-support.cmake @@ -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>? try_compile(STD_MAKE_UNIQUE_FOUND "${CMAKE_BINARY_DIR}/boost-fallback-compile-tests" diff --git a/src/main/cpp/loggingevent.cpp b/src/main/cpp/loggingevent.cpp index a0f25c5e6..a1d8c0325 100644 --- a/src/main/cpp/loggingevent.cpp +++ b/src/main/cpp/loggingevent.cpp @@ -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; - static std::list thread_id_map; - static std::mutex mutex; - std::lock_guard 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() ) { @@ -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"); @@ -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; diff --git a/src/main/cpp/messagebuffer.cpp b/src/main/cpp/messagebuffer.cpp index 461e9a9cc..d0da76cb8 100644 --- a/src/main/cpp/messagebuffer.cpp +++ b/src/main/cpp/messagebuffer.cpp @@ -42,7 +42,7 @@ struct StringOrStream {} ~StringOrStream() { -#if !LOG4CXX_HAS_THREAD_LOCAL +#if !LOG4CXX_HAS_THREAD_LOCAL && !APR_HAS_THREADS delete stream; #endif } @@ -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 initialState; +#if LOG4CXX_HAS_THREAD_LOCAL thread_local static std::basic_ostringstream sStream; +#else + auto& sStream = ThreadSpecificData::getStringStream(); +#endif this->stream = &sStream; this->stream->clear(); this->stream->precision(initialState.precision()); diff --git a/src/main/cpp/threadspecificdata.cpp b/src/main/cpp/threadspecificdata.cpp index 105db6646..b70575c09 100644 --- a/src/main/cpp/threadspecificdata.cpp +++ b/src/main/cpp/threadspecificdata.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ +#include #include #include #include @@ -23,13 +24,24 @@ #define LOG4CXX 1 #endif #include +#include 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_stringstream; +#endif +#if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR + std::basic_stringstream wchar_stringstream; +#endif +#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR + std::basic_stringstream unichar_stringstream; +#endif }; ThreadSpecificData::ThreadSpecificData() @@ -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; + static std::list thread_id_map; + static std::mutex mutex; + std::lock_guard 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& ThreadSpecificData::getStream(logchar&) +{ + if (auto data = getCurrentData()) + return data->m_priv->logchar_stringstream; + static std::basic_stringstream ss; + return ss; +} +#endif + +#if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR +std::basic_stringstream& ThreadSpecificData::getStream(wchar_t&) +{ + if (auto data = getCurrentData()) + return data->m_priv->wchar_stringstream; + static std::basic_stringstream ss; + return ss; +} +#endif + +#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR +std::basic_stringstream& ThreadSpecificData::getStream(UniChar&) +{ + if (auto data = getCurrentData()) + return data->m_priv->unichar_stringstream; + static std::basic_stringstream ss; + return ss; +} +#endif + ThreadSpecificData& ThreadSpecificData::getDataNoThreads() { static WideLife noThreadData; @@ -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; @@ -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; } @@ -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(); @@ -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; } diff --git a/src/main/include/log4cxx/helpers/threadspecificdata.h b/src/main/include/log4cxx/helpers/threadspecificdata.h index 82795179e..7a19aeb46 100644 --- a/src/main/include/log4cxx/helpers/threadspecificdata.h +++ b/src/main/include/log4cxx/helpers/threadspecificdata.h @@ -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 + static std::basic_stringstream& 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& getStream(logchar&); +#endif +#if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR + static std::basic_stringstream& getStream(wchar_t&); +#endif +#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR + static std::basic_stringstream& getStream(UniChar&); +#endif LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(ThreadSpecificDataPrivate, m_priv) }; diff --git a/src/test/cpp/asyncappendertestcase.cpp b/src/test/cpp/asyncappendertestcase.cpp index 6a960c57f..33b2f3717 100644 --- a/src/test/cpp/asyncappendertestcase.cpp +++ b/src/test/cpp/asyncappendertestcase.cpp @@ -17,9 +17,6 @@ #include "logunit.h" -#define LOG4CXX_TEST 1 -#include - #include #include #include @@ -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 } }); }