This is an automated email from the ASF dual-hosted git repository.

swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


The following commit(s) were added to refs/heads/master by this push:
     new f02e9185 Ensure a change to the shared ThreadUtility isActive flag is 
visible (#694)
f02e9185 is described below

commit f02e918533259b4be514ac0ead61fa0feb461d06
Author: Stephen Webb <[email protected]>
AuthorDate: Tue Jun 2 11:10:52 2026 +1000

    Ensure a change to the shared ThreadUtility isActive flag is visible (#694)
    
    * Reduce flakiness of tests that exit without calling LogManager::shutdown
    
    * Pass LOG4CXX_DEBUG environment var to child test processes
---
 .github/workflows/log4cxx-macos.yml              |  5 +++++
 src/main/cpp/threadutility.cpp                   | 28 ++++++++++++++++--------
 src/test/cpp/CMakeLists.txt                      |  5 ++++-
 src/test/cpp/fileappendertest.cpp                |  5 ++++-
 src/test/cpp/helpers/filewatchdogtest.cpp        | 11 ++++++++++
 src/test/cpp/helpers/threadutilitytestcase.cpp   |  6 +++++
 src/test/cpp/net/telnetappendertestcase.cpp      |  2 +-
 src/test/cpp/rolling/multiprocessrollingtest.cpp |  2 +-
 8 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/log4cxx-macos.yml 
b/.github/workflows/log4cxx-macos.yml
index 79f426a5..02918093 100644
--- a/.github/workflows/log4cxx-macos.yml
+++ b/.github/workflows/log4cxx-macos.yml
@@ -34,6 +34,7 @@ jobs:
             multiprocess: ON
             cfstring: OFF
             next_abi: OFF
+            exitevents: OFF
           - name: osx-15-clang
             os: macos-15
             cxx: clang++
@@ -42,6 +43,7 @@ jobs:
             multiprocess: OFF
             cfstring: ON
             next_abi: OFF
+            exitevents: OFF
           - name: osx-26-clang
             os: macos-26
             cxx: clang++
@@ -50,6 +52,7 @@ jobs:
             multiprocess: OFF
             cfstring: ON
             next_abi: ON
+            exitevents: ON
           - name: osx-g++
             os: macos-latest
             cxx: g++-14
@@ -58,6 +61,7 @@ jobs:
             multiprocess: OFF
             cfstring: ON
             next_abi: OFF
+            exitevents: OFF
 
     steps:
     - uses: actions/checkout@v4
@@ -87,6 +91,7 @@ jobs:
           -DLOG4CXX_ENABLE_ODBC=${{ matrix.odbc }} \
           -DLOG4CXX_MULTIPROCESS_ROLLING_FILE_APPENDER=${{ matrix.multiprocess 
}} \
           -DLOG4CXX_CFSTRING=${{ matrix.cfstring }} \
+          -DLOG4CXX_EVENTS_AT_EXIT=${{ matrix.exitevents }} \
           -DLOG4CXX_BUILD_NEXT_ABI=${{ matrix.next_abi }} \
           -DCMAKE_BUILD_TYPE=Debug \
           ..
diff --git a/src/main/cpp/threadutility.cpp b/src/main/cpp/threadutility.cpp
index 0ffcc140..cfe07507 100644
--- a/src/main/cpp/threadutility.cpp
+++ b/src/main/cpp/threadutility.cpp
@@ -83,18 +83,20 @@ struct ThreadUtility::priv_data
        std::atomic<bool>         terminated{ false };
        int                       retryCount{ 2 };
        Period                    maxDelay{ 0 };
-       bool                      threadIsActive{ false };
+       std::atomic<bool>         threadIsActive{ false };
+       LoggerPtr                 log;
 
        void doPeriodicTasks();
 
        void setTerminated()
        {
-               std::lock_guard<std::mutex> lock(interrupt_mutex);
+               std::lock_guard<std::recursive_mutex> lock(job_mutex);
                terminated.store(true);
        }
 
        void stopThread()
        {
+               LOGLOG_DEBUG(log, "stopThread");
                setTerminated();
                interrupt.notify_all();
                if (thread.joinable())
@@ -267,6 +269,9 @@ ThreadStartPost ThreadUtility::postStartFunction()
  */
 void ThreadUtility::addPeriodicTask(const LogString& name, 
std::function<void()> f, const Period& delay)
 {
+       if (!m_priv->log)
+               m_priv->log = Logger::getLogger("ThreadUtility");
+       LOGLOG_DEBUG(m_priv->log, LOG4CXX_STR("addPeriodicTask: ") << name);
        std::lock_guard<std::recursive_mutex> lock(m_priv->job_mutex);
        if (m_priv->maxDelay < delay)
                m_priv->maxDelay = delay;
@@ -274,14 +279,20 @@ void ThreadUtility::addPeriodicTask(const LogString& 
name, std::function<void()>
        m_priv->jobs.push_back( priv_data::NamedPeriodicFunction{name, delay, 
currentTime + delay, f, 0, false} );
 
        // Restart thread if it has stopped.
-       if (!m_priv->threadIsActive && m_priv->thread.joinable())
+       if (!m_priv->threadIsActive.load() && m_priv->thread.joinable())
                m_priv->thread.join();
 
        if (!m_priv->thread.joinable())
        {
                m_priv->terminated.store(false);
-               m_priv->threadIsActive = true;
-               m_priv->thread = createThread(LOG4CXX_STR("log4cxx"), 
std::bind(&priv_data::doPeriodicTasks, m_priv.get()));
+               m_priv->threadIsActive.store(true);
+               m_priv->thread = createThread(LOG4CXX_STR("log4cxx"), [this]()
+                       {
+                               LOGLOG_DEBUG(m_priv->log, "doPeriodicTasks: " 
<< "started");
+                               m_priv->doPeriodicTasks();
+                               LOGLOG_DEBUG(m_priv->log, "doPeriodicTasks: " 
<< "stopped");
+                               m_priv->threadIsActive.store(false);
+                       });
        }
        else
                m_priv->interrupt.notify_one();
@@ -305,6 +316,7 @@ bool ThreadUtility::hasPeriodicTask(const LogString& name)
  */
 void ThreadUtility::removeAllPeriodicTasks()
 {
+       LOGLOG_DEBUG(m_priv->log, "removeAllPeriodicTasks");
        {
                std::lock_guard<std::recursive_mutex> lock(m_priv->job_mutex);
                while (!m_priv->jobs.empty())
@@ -325,6 +337,7 @@ void ThreadUtility::removePeriodicTask(const LogString& 
name)
                );
        if (m_priv->jobs.end() != pItem)
        {
+               LOGLOG_DEBUG(m_priv->log, LOG4CXX_STR("removePeriodicTask: ") 
<< name);
                pItem->removed = true;
                m_priv->interrupt.notify_one();
        }
@@ -399,18 +412,15 @@ void ThreadUtility::priv_data::doPeriodicTasks()
                                );
                        if (this->jobs.end() == pItem)
                                break;
+                       LOGLOG_DEBUG(this->log, LOG4CXX_STR("doPeriodicTasks: 
erase ") << pItem->name);
                        this->jobs.erase(pItem);
                        if (this->jobs.empty())
-                       {
-                               this->threadIsActive = false;
                                return;
-                       }
                }
 
                std::unique_lock<std::mutex> lock(this->interrupt_mutex);
                this->interrupt.wait_until(lock, nextOperationTime);
        }
-    this->threadIsActive = false;
 }
 
 } //namespace helpers
diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt
index f20a84f8..28ebd7cf 100644
--- a/src/test/cpp/CMakeLists.txt
+++ b/src/test/cpp/CMakeLists.txt
@@ -124,7 +124,10 @@ else()
   set(TEST_COMPILE_DEFINITIONS _DEBUG)
 endif()
 if(LOG4CXX_TEST_ONLY_BUILD)
-  list(APPEND TEST_COMPILE_DEFINITIONS 
"ENABLE_FAILING_APPENDER_SIMULATION_TESTING=1")
+  list(APPEND TEST_COMPILE_DEFINITIONS
+      "ENABLE_FAILING_APPENDER_SIMULATION_TESTING=1"
+      "LOGLOG_THRESHOLD=1"
+  )
 endif()
 
 get_filename_component(UNIT_TEST_WORKING_DIR ../resources ABSOLUTE)
diff --git a/src/test/cpp/fileappendertest.cpp 
b/src/test/cpp/fileappendertest.cpp
index 1c874b46..c91a7009 100644
--- a/src/test/cpp/fileappendertest.cpp
+++ b/src/test/cpp/fileappendertest.cpp
@@ -159,6 +159,7 @@ public:
        {
                int requiredMsgCount = 100;
                auto logger = getLogger(LOG4CXX_STR("100message"));
+               LOGLOG_DEBUG(logger, "writeFinalBufferOutput: " << 
"configuing");
 
                // Set up a new file
                LogString dir{ LOG4CXX_STR("output/newdir") };
@@ -174,10 +175,12 @@ public:
                logger->setAdditivity(false);
                logger->addAppender(writer);
 
+               LOGLOG_DEBUG(logger, "writeFinalBufferOutput: " << "started");
                for ( int x = 0; x < requiredMsgCount; x++ )
                {
                        LOG4CXX_INFO( logger, "This is test message " << x );
                }
+               LOGLOG_DEBUG(logger, "writeFinalBufferOutput: " << "stopped");
        }
 
        void checkFinalBufferOutput()
@@ -247,7 +250,7 @@ private:
                {
                        LOGUNIT_FAIL("apr_procattr_create");
                }
-               if (apr_procattr_cmdtype_set(*attr, APR_PROGRAM) != APR_SUCCESS)
+               if (apr_procattr_cmdtype_set(*attr, APR_PROGRAM_ENV) != 
APR_SUCCESS)
                {
                        LOGUNIT_FAIL("apr_procattr_cmdtype_set");
                }
diff --git a/src/test/cpp/helpers/filewatchdogtest.cpp 
b/src/test/cpp/helpers/filewatchdogtest.cpp
index 67cae709..fea3d3c7 100644
--- a/src/test/cpp/helpers/filewatchdogtest.cpp
+++ b/src/test/cpp/helpers/filewatchdogtest.cpp
@@ -16,6 +16,7 @@
  */
 #include <log4cxx/helpers/pool.h>
 #include <log4cxx/helpers/filewatchdog.h>
+#include <log4cxx/helpers/loglog.h>
 #include "../logunit.h"
 #include "apr_time.h"
 
@@ -32,6 +33,14 @@ LOGUNIT_CLASS(FileWatchdogTest)
        LOGUNIT_TEST_SUITE(FileWatchdogTest);
        LOGUNIT_TEST(testShutdownDelay);
        LOGUNIT_TEST_SUITE_END();
+#ifdef _DEBUG
+       struct Fixture
+       {
+               Fixture() {
+                       LogLog::setInternalDebugging(true);
+               }
+       } suiteFixture;
+#endif
 
 private:
        class MockWatchdog : public FileWatchdog
@@ -63,6 +72,8 @@ public:
                }
                apr_time_t delta = apr_time_now() - start;
                LOGUNIT_ASSERT(delta < 30000000);
+               // wait 50 ms for periodic task thread to exit
+               apr_sleep(50000);
        }
 
 };
diff --git a/src/test/cpp/helpers/threadutilitytestcase.cpp 
b/src/test/cpp/helpers/threadutilitytestcase.cpp
index 8c10fecb..d89d2a3b 100644
--- a/src/test/cpp/helpers/threadutilitytestcase.cpp
+++ b/src/test/cpp/helpers/threadutilitytestcase.cpp
@@ -22,6 +22,10 @@
 #include <log4cxx/patternlayout.h>
 #include <log4cxx/fileappender.h>
 #include <log4cxx/logmanager.h>
+#if !defined(LOG4CXX)
+       #define LOG4CXX 1
+#endif
+#include <log4cxx/private/log4cxx_private.h>
 #include <atomic>
 #include <chrono>
 
@@ -147,6 +151,8 @@ public:
                }
                thrUtil->removePeriodicTask(secondTask);
                LOGUNIT_ASSERT(0 < secondRuns.load());
+               // wait 30 ms for periodic task thread to exit
+               std::this_thread::sleep_for(std::chrono::milliseconds(30));
        }
 
        void testThreadNameLogging()
diff --git a/src/test/cpp/net/telnetappendertestcase.cpp 
b/src/test/cpp/net/telnetappendertestcase.cpp
index 270465df..52f70464 100644
--- a/src/test/cpp/net/telnetappendertestcase.cpp
+++ b/src/test/cpp/net/telnetappendertestcase.cpp
@@ -189,7 +189,7 @@ private:
                {
                        LOGUNIT_FAIL("apr_procattr_create");
                }
-               if (apr_procattr_cmdtype_set(*attr, APR_PROGRAM) != APR_SUCCESS)
+               if (apr_procattr_cmdtype_set(*attr, APR_PROGRAM_ENV) != 
APR_SUCCESS)
                {
                        LOGUNIT_FAIL("apr_procattr_cmdtype_set");
                }
diff --git a/src/test/cpp/rolling/multiprocessrollingtest.cpp 
b/src/test/cpp/rolling/multiprocessrollingtest.cpp
index 98e754d8..e1afa777 100644
--- a/src/test/cpp/rolling/multiprocessrollingtest.cpp
+++ b/src/test/cpp/rolling/multiprocessrollingtest.cpp
@@ -329,7 +329,7 @@ private:
                {
                        LOGUNIT_FAIL("apr_procattr_create");
                }
-               if (apr_procattr_cmdtype_set(*attr, APR_PROGRAM) != APR_SUCCESS)
+               if (apr_procattr_cmdtype_set(*attr, APR_PROGRAM_ENV) != 
APR_SUCCESS)
                {
                        LOGUNIT_FAIL("apr_procattr_cmdtype_set");
                }

Reply via email to