]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4049] Preliminary commit
authorThomas Markwalder <tmark@isc.org>
Thu, 7 Aug 2025 13:39:08 +0000 (09:39 -0400)
committerThomas Markwalder <tmark@isc.org>
Thu, 14 Aug 2025 13:15:52 +0000 (13:15 +0000)
/src/bin/d2/d2_process.cc
    D2Process::runIO() - use new IOService::runOneFor()

/src/lib/asiolink/io_service.*
    IOServcie::runOneFor() - new func

/src/lib/asiolink/io_service_mgr.*
    IOServiceMgr::pollIOServices() - return count of
    handlers executed

/src/lib/asiolink/tests/io_service_unittest.cc
    TEST(IOService, runOneFor) - new test

src/bin/d2/d2_process.cc
src/lib/asiolink/io_service.cc
src/lib/asiolink/io_service.h
src/lib/asiolink/io_service_mgr.cc
src/lib/asiolink/io_service_mgr.h
src/lib/asiolink/tests/io_service_unittest.cc

index 7db49a34741e664bfe72c3bc010e6f5b386635c6..1236cff62656a0f8fd09c317b65c9c3c2ea10dc0 100644 (file)
@@ -150,18 +150,27 @@ D2Process::run() {
 
 size_t
 D2Process::runIO() {
-    // Handle events registered by hooks using external IOService objects.
-    IOServiceMgr::instance().pollIOServices();
-    // We want to block until at least one handler is called.
-    // Poll runs all that are ready. If none are ready it returns immediately
-    // with a count of zero.
-    size_t cnt = getIOService()->poll();
+    // We want to process all ready handlers on both the managed IOServices
+    // and the main IOservice.  If no handlers were executed on any of the
+    // IOServices will wait on the main IOService until at least one handler
+    // executes or we time out.
+    size_t cnt = IOServiceMgr::instance().pollIOServices();
+    cnt += getIOService()->poll();
     if (!cnt) {
-        // Poll ran no handlers either none are ready or the service has been
-        // stopped.  Either way, call runOne to wait for a IO event. If the
-        // service is stopped it will return immediately with a cnt of zero.
-        cnt = getIOService()->runOne();
+        // Polling ran no handlers so either none are ready or the service has been
+        // stopped.  Either way, call runOneFor() to wait for a IO event on the
+        // main service. If the service is stopped it will return immediately
+        //  with a cnt of zero and timed_out set to false.
+        bool timed_out;
+        /// @todo TKM wait time should probably be configurable.
+        /// Currently microseconds, should be milliseconds?
+        cnt = getIOService()->runOneFor(100 * 1000, timed_out);
+        if (timed_out) {
+            // Return 1 so caller knows the service has not stopped.
+            return (1);
+        }
     }
+
     return (cnt);
 }
 
index a3f7739ea14d9cb05b05908051f5e4ee642f8024..cb63b57b32f5c9f7291adc35eb17347fc362a707 100644 (file)
 #include <boost/shared_ptr.hpp>
 #include <sys/socket.h>
 
+#include <chrono>
+
+using namespace std::chrono;
+
 namespace isc {
 namespace asiolink {
 
@@ -56,6 +60,26 @@ public:
         return (static_cast<size_t>(io_service_.run_one()));
     };
 
+    /// @brief Run the underlying event loop for a single event or until
+    /// a wait time expires.
+    ///
+    /// This method returns control to the caller as soon as the
+    /// first handler has completed or the wait time elapses. If the
+    /// number of handlers executed is zero and timed_out is set to
+    /// false this indicates that the IOService was stopped.
+    ///
+    /// @param wait_time_usecs wait time in microseconds
+    /// @param[out] time_out set to true if th wait time expired
+    /// without any handlers executing.
+    /// timed_out parameter will be set true if the wait time elapsed
+    ///
+    /// @return The number of handlers that were executed.
+    size_t runOneFor(size_t wait_time_usecs, bool& timed_out) {
+        size_t cnt = io_service_.run_one_for(microseconds(wait_time_usecs));
+        timed_out = (!cnt && !io_service_.stopped());
+        return (cnt);
+    };
+
     /// @brief Run the underlying event loop for a ready events.
     ///
     /// This method executes handlers for all ready events and returns.
@@ -139,6 +163,11 @@ IOService::runOne() {
     return (io_impl_->runOne());
 }
 
+size_t
+IOService::runOneFor(size_t wait_time_usecs, bool& timed_out) {
+    return (io_impl_->runOneFor(wait_time_usecs, timed_out));
+};
+
 size_t
 IOService::poll() {
     return (io_impl_->poll());
index 5318b7a0bc262e7d66c816d40b62a3108fdc172b..5d60dbb2eaef85202ff669af51c7c1fe978a4c56 100644 (file)
@@ -61,6 +61,22 @@ public:
     /// @return The number of handlers that were executed.
     size_t runOne();
 
+    /// @brief Run the underlying event loop for a single event or until
+    /// a wait time expires.
+    ///
+    /// This method returns control to the caller as soon as the
+    /// first handler has completed or the wait time elapses. If the
+    /// number of handlers executed is zero and timed_out is set to
+    /// false this indicates that the IOService was stopped.
+    ///
+    /// @param wait_time_usecs wait time in microseconds
+    /// @param[out] time_out set to true if th wait time expired
+    /// without any handlers executing.
+    /// timed_out parameter will be set true if the wait time elapsed
+    ///
+    /// @return The number of handlers that were executed.
+    size_t runOneFor(size_t wait_time_usecs, bool& timed_out);
+
     /// @brief Run the underlying event loop for a ready events.
     ///
     /// This method executes handlers for all ready events and returns.
index 480a132e9a977336980ce52018e9955ca8f7e72c..0bd8ff66aa984e585687297eb9f771bebcfa91df 100644 (file)
@@ -35,11 +35,14 @@ IOServiceMgr::unregisterIOService(IOServicePtr io_service) {
     }
 }
 
-void
+size_t
 IOServiceMgr::pollIOServices() {
+    size_t cnt = 0;
     for (auto& io_service : io_services_) {
-        io_service->poll();
+        cnt += io_service->poll();
     }
+
+    return (cnt);
 }
 
 } // namespace asiolink
index 3c47d73e48eaebf36bc8034f30891518c5bb18b9..ef820ca2c6848dde89349383320f5f8723e36652 100644 (file)
@@ -62,7 +62,9 @@ public:
     }
 
     /// @brief Poll IOService objects.
-    void pollIOServices();
+    ///
+    /// @return The number of handlers that were executed.
+    size_t pollIOServices();
 
 private:
 
index 4defa1de58b18196d6a5d9ac38950a40d20c6ef0..dc1ab5fd9773f90cb0e424117cd7cf8ea1eefc77 100644 (file)
@@ -7,6 +7,7 @@
 #include <config.h>
 
 #include <asiolink/io_service.h>
+#include <asiolink/interval_timer.h>
 
 #include <gtest/gtest.h>
 #include <functional>
@@ -45,4 +46,35 @@ TEST(IOService, post) {
     EXPECT_EQ(3, called[2]);
 }
 
+// Check the runOneFor() operates correctly.
+TEST(IOService, runOneFor) {
+    IOServicePtr io_service(new IOService());
+
+    // Setup up a timer to expire in 200 ms.
+    IntervalTimer timer(io_service);
+    size_t wait_ms = 200; 
+    bool timer_fired = false;
+    timer.setup([&timer_fired] { timer_fired = true; }, 
+                wait_ms, IntervalTimer::ONE_SHOT);
+
+    size_t time_outs = 0;
+    while (timer_fired == false && time_outs < 5) { 
+        // Call runOneFor() with 1/4 of the timer duration.
+        bool timed_out = false;
+        auto cnt = io_service->runOneFor(50 * 1000, timed_out);
+        if (cnt || timer_fired) {
+            ASSERT_FALSE(timed_out);
+        } else {
+            ASSERT_TRUE(timed_out);
+            ++time_outs;
+        }
+    }
+
+    // Should have had at least two time outs.
+    EXPECT_GE(time_outs, 2);
+
+    // Timer should have fired.
+    EXPECT_EQ(timer_fired, 1);
+}
+
 }