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);
}
#include <boost/shared_ptr.hpp>
#include <sys/socket.h>
+#include <chrono>
+
+using namespace std::chrono;
+
namespace isc {
namespace asiolink {
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.
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());
/// @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.
}
}
-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
}
/// @brief Poll IOService objects.
- void pollIOServices();
+ ///
+ /// @return The number of handlers that were executed.
+ size_t pollIOServices();
private:
#include <config.h>
#include <asiolink/io_service.h>
+#include <asiolink/interval_timer.h>
#include <gtest/gtest.h>
#include <functional>
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);
+}
+
}