]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Use a condition variable to signal the checker thread.
authorMiod Vallat <miod.vallat@powerdns.com>
Thu, 6 Nov 2025 07:10:58 +0000 (08:10 +0100)
committerMiod Vallat <miod.vallat@powerdns.com>
Wed, 18 Mar 2026 08:29:05 +0000 (09:29 +0100)
Signed-off-by: Miod Vallat <miod.vallat@powerdns.com>
pdns/lua-record.cc

index 76e616e56e8cdd45139a35b78f83d0bbfd2c327b..a33174bed2f473475c2cfaa5fbf9d4dcb815a439 100644 (file)
@@ -1,17 +1,19 @@
-#include <boost/format/format_fwd.hpp>
+#include <algorithm>
+#include <condition_variable>
+#include <future>
+#include <random>
 #include <stdexcept>
 #include <thread>
-#include <future>
+#include <tuple>
+#include <utility>
+#include <variant>
 #include <boost/format.hpp>
+#include <boost/format/format_fwd.hpp>
 #include <boost/uuid/string_generator.hpp>
 #include <boost/algorithm/string/erase.hpp>
-#include <utility>
-#include <algorithm>
-#include <random>
+
 #include "misc.hh"
 #include "qtype.hh"
-#include <tuple>
-#include <variant>
 #include "version.hh"
 #include "ext/luawrapper/include/LuaContext.hpp"
 #include "lock.hh"
@@ -245,13 +247,13 @@ private:
       std::chrono::system_clock::time_point checkStart = std::chrono::system_clock::now();
       std::vector<std::future<void>> results;
       std::vector<CheckDesc> toDelete;
-      time_t interval{g_luaHealthChecksInterval};
       {
         // make sure there's no insertion
         auto statuses = d_statuses.read_lock();
         for (auto& it: *statuses) {
           auto& desc = it.first;
           auto& state = it.second;
+          time_t interval{g_luaHealthChecksInterval};
           time_t checkInterval{0};
           auto lastAccess = std::chrono::system_clock::from_time_t(state->lastAccess);
 
@@ -301,10 +303,15 @@ private:
       // set thread name again, in case std::async surprised us by doing work in this thread
       setThreadName("pdns/luaupcheck");
 
-      // Only sleep for 1 second here, even if the health check interval is
-      // larger, in case we get new entries to process in d_statuses in the
-      // meantime.
-      std::this_thread::sleep_for(std::chrono::seconds(1));
+      // Wait for at most one complete check interval, but allow an earlier
+      // wakeup in case more work is being put in d_statuses.
+      {
+        std::unique_lock<std::mutex> lock(d_mutex);
+        auto sleepTime = std::chrono::seconds(g_luaHealthChecksInterval) - (std::chrono::system_clock::now() - checkStart);
+        if (sleepTime > std::chrono::seconds::zero()) {
+          d_condvar.wait_until(lock, std::chrono::system_clock::now() + sleepTime);
+        }
+      }
     }
   }
 
@@ -314,6 +321,9 @@ private:
   std::unique_ptr<std::thread> d_checkerThread;
   std::atomic_flag d_checkerThreadStarted;
 
+  std::mutex d_mutex; // used with the condition variable below
+  std::condition_variable d_condvar;
+
   void setStatus(const CheckDesc& cd, bool status)
   {
     auto statuses = d_statuses.write_lock();
@@ -387,10 +397,14 @@ int IsUpOracle::isUp(const CheckDesc& cd)
       (*statuses)[cd] = std::make_unique<CheckState>(now);
     }
   }
-  // Now that we have given it work to do, make sure the checker thread runs.
+  // Now that we have given it work to do, make sure the checker thread runs,
+  // and notify it if it had already been running.
   if (!d_checkerThreadStarted.test_and_set()) {
     d_checkerThread = std::make_unique<std::thread>([this] { return checkThread(); });
   }
+  else {
+    d_condvar.notify_all();
+  }
   // If explicitly asked to fail on incomplete checks, report this (as
   // a negative value).
   static const std::string foic{"failOnIncompleteCheck"};