From: Marcin Siodelski Date: Fri, 18 Sep 2015 11:03:05 +0000 (+0200) Subject: [4047] Instance of the TimerMgr is now shared pointer. X-Git-Tag: trac4045_base~6^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c99f6c0233a1da74aefc27fb569d24432248c12d;p=thirdparty%2Fkea.git [4047] Instance of the TimerMgr is now shared pointer. --- diff --git a/src/lib/dhcpsrv/tests/timer_mgr_unittest.cc b/src/lib/dhcpsrv/tests/timer_mgr_unittest.cc index 1a2478c021..569a1f7765 100644 --- a/src/lib/dhcpsrv/tests/timer_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/timer_mgr_unittest.cc @@ -113,27 +113,27 @@ TimerMgrTest::SetUp() { calls_count_.clear(); timeout_ = false; // Make sure there are no dangling threads. - TimerMgr::instance().stopThread(); + TimerMgr::instance()->stopThread(); } void TimerMgrTest::TearDown() { // Make sure there are no dangling threads. - TimerMgr::instance().stopThread(); + TimerMgr::instance()->stopThread(); // Remove all timers. - TimerMgr::instance().unregisterTimers(); + TimerMgr::instance()->unregisterTimers(); } void TimerMgrTest::registerTimer(const std::string& timer_name, const long timer_interval, const IntervalTimer::Mode& timer_mode) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Register the timer with the generic callback that counts the // number of callback invocations. ASSERT_NO_THROW( - timer_mgr.registerTimer(timer_name, makeCallback(timer_name), timer_interval, - timer_mode) + timer_mgr->registerTimer(timer_name, makeCallback(timer_name), timer_interval, + timer_mode) ); calls_count_[timer_name] = 0; @@ -151,7 +151,7 @@ TimerMgrTest::doWait(const long timeout, const bool call_receive) { while (!timeout_) { if (call_receive) { // Block for one 1 millisecond. - IfaceMgr::instance().receive6(0, 1000); + IfaceMgr::instancePtr()->receive6(0, 1000); } // Run ready handlers from the local IO service to execute // the timeout callback if necessary. @@ -168,7 +168,7 @@ TimerMgrTest::timerCallback(const std::string& timer_name) { // The timer installed is the ONE_SHOT timer, so we have // to reschedule the timer. - TimerMgr::instance().setup(timer_name); + TimerMgr::instance()->setup(timer_name); } void @@ -200,52 +200,52 @@ TimerMgrTest::timeoutCallback() { // parameters are specified when registering a timer, or when // the registration can't be made. TEST_F(TimerMgrTest, registerTimer) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Empty timer name is not allowed. - ASSERT_THROW(timer_mgr.registerTimer("", makeCallback("timer1"), 1, - IntervalTimer::ONE_SHOT), + ASSERT_THROW(timer_mgr->registerTimer("", makeCallback("timer1"), 1, + IntervalTimer::ONE_SHOT), BadValue); // Add a timer with a correct name. - ASSERT_NO_THROW(timer_mgr.registerTimer("timer2", makeCallback("timer2"), 1, - IntervalTimer::ONE_SHOT)); + ASSERT_NO_THROW(timer_mgr->registerTimer("timer2", makeCallback("timer2"), 1, + IntervalTimer::ONE_SHOT)); // Adding the timer with the same name as the existing timer is not // allowed. - ASSERT_THROW(timer_mgr.registerTimer("timer2", makeCallback("timer2"), 1, - IntervalTimer::ONE_SHOT), + ASSERT_THROW(timer_mgr->registerTimer("timer2", makeCallback("timer2"), 1, + IntervalTimer::ONE_SHOT), BadValue); // Start worker thread. - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->startThread()); // Can't register the timer when the thread is running. - ASSERT_THROW(timer_mgr.registerTimer("timer1", makeCallback("timer1"), 1, - IntervalTimer::ONE_SHOT), + ASSERT_THROW(timer_mgr->registerTimer("timer1", makeCallback("timer1"), 1, + IntervalTimer::ONE_SHOT), InvalidOperation); // Stop the thread and retry. - ASSERT_NO_THROW(timer_mgr.stopThread()); - EXPECT_NO_THROW(timer_mgr.registerTimer("timer1", makeCallback("timer1"), 1, - IntervalTimer::ONE_SHOT)); + ASSERT_NO_THROW(timer_mgr->stopThread()); + EXPECT_NO_THROW(timer_mgr->registerTimer("timer1", makeCallback("timer1"), 1, + IntervalTimer::ONE_SHOT)); } // This test verifies that it is possible to unregister a timer from // the TimerMgr. TEST_F(TimerMgrTest, unregisterTimer) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Register a timer and start it. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1)); - ASSERT_NO_THROW(timer_mgr.setup("timer1")); - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->setup("timer1")); + ASSERT_NO_THROW(timer_mgr->startThread()); // Wait for the timer to execute several times. doWait(100); // Stop the thread but execute pending callbacks. - ASSERT_NO_THROW(timer_mgr.stopThread(true)); + ASSERT_NO_THROW(timer_mgr->stopThread(true)); // Remember how many times the timer's callback was executed. const unsigned int calls_count = calls_count_["timer1"]; @@ -253,15 +253,15 @@ TEST_F(TimerMgrTest, unregisterTimer) { // Check that an attempt to unregister a non-existing timer would // result in exeception. - EXPECT_THROW(timer_mgr.unregisterTimer("timer2"), BadValue); + EXPECT_THROW(timer_mgr->unregisterTimer("timer2"), BadValue); // Now unregister the correct one. - ASSERT_NO_THROW(timer_mgr.unregisterTimer("timer1")); + ASSERT_NO_THROW(timer_mgr->unregisterTimer("timer1")); // Start the thread again and wait another 100ms. - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->startThread()); doWait(100); - ASSERT_NO_THROW(timer_mgr.stopThread(true)); + ASSERT_NO_THROW(timer_mgr->stopThread(true)); // The number of calls for the timer1 shouldn't change as the // timer had been unregistered. @@ -275,7 +275,7 @@ TEST_F(TimerMgrTest, unregisterTimer) { /// solve the problem. See ticket #4009. Until this ticket is /// implemented, the test should remain disabled. TEST_F(TimerMgrTest, unregisterTimers) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Register 10 timers. for (int i = 1; i <= 20; ++i) { @@ -284,15 +284,15 @@ TEST_F(TimerMgrTest, unregisterTimers) { ASSERT_NO_FATAL_FAILURE(registerTimer(s.str(), 1)) << "fatal failure occurred while registering " << s.str(); - ASSERT_NO_THROW(timer_mgr.setup(s.str())) + ASSERT_NO_THROW(timer_mgr->setup(s.str())) << "exception thrown while calling setup() for the " << s.str(); } // Start worker thread and wait for 500ms. - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->startThread()); doWait(500); - ASSERT_NO_THROW(timer_mgr.stopThread(true)); + ASSERT_NO_THROW(timer_mgr->stopThread(true)); // Make sure that all timers have been executed at least once. for (CallsCount::iterator it = calls_count_.begin(); @@ -308,12 +308,12 @@ TEST_F(TimerMgrTest, unregisterTimers) { CallsCount calls_count(calls_count_); // Let's unregister all timers. - ASSERT_NO_THROW(timer_mgr.unregisterTimers()); + ASSERT_NO_THROW(timer_mgr->unregisterTimers()); // Start worker thread again and wait for 500ms. - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->startThread()); doWait(500); - ASSERT_NO_THROW(timer_mgr.stopThread(true)); + ASSERT_NO_THROW(timer_mgr->stopThread(true)); // The calls counter shouldn't change because there are // no timers registered. @@ -323,16 +323,16 @@ TEST_F(TimerMgrTest, unregisterTimers) { // This test checks that it is not possible to unregister timers // while the thread is running. TEST_F(TimerMgrTest, unregisterTimerWhileRunning) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Register two timers. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1)); ASSERT_NO_FATAL_FAILURE(registerTimer("timer2", 1)); // Start the thread and make sure we can't unregister them. - ASSERT_NO_THROW(timer_mgr.startThread()); - EXPECT_THROW(timer_mgr.unregisterTimer("timer1"), InvalidOperation); - EXPECT_THROW(timer_mgr.unregisterTimers(), InvalidOperation); + ASSERT_NO_THROW(timer_mgr->startThread()); + EXPECT_THROW(timer_mgr->unregisterTimer("timer1"), InvalidOperation); + EXPECT_THROW(timer_mgr->unregisterTimers(), InvalidOperation); // No need to stop the thread as it will be stopped by the // test fixture destructor. @@ -340,39 +340,42 @@ TEST_F(TimerMgrTest, unregisterTimerWhileRunning) { // This test verifies that the timer execution can be cancelled. TEST_F(TimerMgrTest, cancel) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Register timer. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1)); - // We can start the worker thread before we even kick in the timers. - ASSERT_NO_THROW(timer_mgr.startThread()); - // Kick in the timer and wait for 500ms. - ASSERT_NO_THROW(timer_mgr.setup("timer1")); + ASSERT_NO_THROW(timer_mgr->setup("timer1")); + ASSERT_NO_THROW(timer_mgr->startThread()); doWait(500); + ASSERT_NO_THROW(timer_mgr->stopThread()); // Cancelling non-existing timer should fail. - EXPECT_THROW(timer_mgr.cancel("timer2"), BadValue); + EXPECT_THROW(timer_mgr->cancel("timer2"), BadValue); // Cancelling the good one should pass, even when the worker // thread is running. - ASSERT_NO_THROW(timer_mgr.cancel("timer1")); + ASSERT_NO_THROW(timer_mgr->cancel("timer1")); // Remember how many calls have been invoked and wait for // another 500ms. unsigned int calls_count = calls_count_["timer1"]; + + ASSERT_NO_THROW(timer_mgr->startThread()); doWait(500); + // Stop thread before we setup again. + ASSERT_NO_THROW(timer_mgr->stopThread()); // The number of calls shouldn't change because the timer had been // cancelled. ASSERT_EQ(calls_count, calls_count_["timer1"]); - TimerMgr::instance().stopThread(); - // Setup the timer again. - ASSERT_NO_THROW(timer_mgr.setup("timer1")); - TimerMgr::instance().startThread(); + ASSERT_NO_THROW(timer_mgr->setup("timer1")); + + // Restart the thread. + ASSERT_NO_THROW(timer_mgr->startThread()); doWait(500); // New calls should be recorded. @@ -382,7 +385,7 @@ TEST_F(TimerMgrTest, cancel) { // This test verifies that the callbacks for the scheduled timers are // actually called. TEST_F(TimerMgrTest, scheduleTimers) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Register two timers: 'timer1' and 'timer2'. The first timer will // be executed at the 1ms interval. The second one at the 5ms @@ -391,12 +394,12 @@ TEST_F(TimerMgrTest, scheduleTimers) { ASSERT_NO_FATAL_FAILURE(registerTimer("timer2", 5)); // We can start the worker thread before we even kick in the timers. - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->startThread()); // Kick in the timers. The timers have been registered so there // should be no exception. - ASSERT_NO_THROW(timer_mgr.setup("timer1")); - ASSERT_NO_THROW(timer_mgr.setup("timer2")); + ASSERT_NO_THROW(timer_mgr->setup("timer1")); + ASSERT_NO_THROW(timer_mgr->setup("timer2")); // Run IfaceMgr::receive6() in the loop for 500ms. This function // will read data from the watch sockets created when the timers @@ -408,7 +411,7 @@ TEST_F(TimerMgrTest, scheduleTimers) { // Stop the worker thread, which would halt the execution of // the timers. - timer_mgr.stopThread(true); + ASSERT_NO_THROW(timer_mgr->stopThread(true)); // We have been running the timer for 500ms at the interval of // 1 ms. The maximum number of callbacks is 500. However, the @@ -430,10 +433,10 @@ TEST_F(TimerMgrTest, scheduleTimers) { unsigned int calls_count_timer2 = calls_count_["timer2"]; // Unregister the 'timer1'. - ASSERT_NO_THROW(timer_mgr.unregisterTimer("timer1")); + ASSERT_NO_THROW(timer_mgr->unregisterTimer("timer1")); // Restart the thread. - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->startThread()); // Wait another 500ms. The 'timer1' was unregistered so it // should not make any more calls. The 'timer2' should still @@ -449,16 +452,14 @@ TEST_F(TimerMgrTest, scheduleTimers) { // This test verifies that it is possible to force that the pending // timer callbacks are executed when the worker thread is stopped. TEST_F(TimerMgrTest, stopThreadWithRunningHandlers) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Register 'timer1'. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1)); - // We can start the worker thread before we even kick in the timers. - ASSERT_NO_THROW(timer_mgr.startThread()); - // Kick in the timer. - ASSERT_NO_THROW(timer_mgr.setup("timer1")); + ASSERT_NO_THROW(timer_mgr->setup("timer1")); + ASSERT_NO_THROW(timer_mgr->startThread()); // Run the thread for 100ms. This should run some timers. The 'false' // value indicates that the IfaceMgr::receive6 is not called, so the @@ -469,13 +470,13 @@ TEST_F(TimerMgrTest, stopThreadWithRunningHandlers) { EXPECT_EQ(0, calls_count_["timer1"]); // Stop the worker thread without completing pending callbacks. - ASSERT_NO_THROW(timer_mgr.stopThread(false)); + ASSERT_NO_THROW(timer_mgr->stopThread(false)); // There should be still not be any calls registered. EXPECT_EQ(0, calls_count_["timer1"]); // We can restart the worker thread before we even kick in the timers. - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->startThread()); // Run the thread for 100ms. This should run some timers. The 'false' // value indicates that the IfaceMgr::receive6 is not called, so the @@ -486,7 +487,7 @@ TEST_F(TimerMgrTest, stopThreadWithRunningHandlers) { EXPECT_EQ(0, calls_count_["timer1"]); // Stop the worker thread with completing pending callbacks. - ASSERT_NO_THROW(timer_mgr.stopThread(true)); + ASSERT_NO_THROW(timer_mgr->stopThread(true)); // There should be one call registered. EXPECT_EQ(1, calls_count_["timer1"]); @@ -495,22 +496,22 @@ TEST_F(TimerMgrTest, stopThreadWithRunningHandlers) { // This test verifies that exceptions emitted from the callback would // be handled by the TimerMgr. TEST_F(TimerMgrTest, callbackWithException) { - TimerMgr& timer_mgr = TimerMgr::instance(); + const TimerMgrPtr& timer_mgr = TimerMgr::instance(); // Create timer which will trigger callback generating exception. ASSERT_NO_THROW( - timer_mgr.registerTimer("timer1", makeCallbackWithException(), 1, - IntervalTimer::ONE_SHOT) + timer_mgr->registerTimer("timer1", makeCallbackWithException(), 1, + IntervalTimer::ONE_SHOT) ); // Setup the timer. - ASSERT_NO_THROW(timer_mgr.setup("timer1")); + ASSERT_NO_THROW(timer_mgr->setup("timer1")); // Start thread. We hope that exception will be caught by the @c TimerMgr // and will not kill the process. - ASSERT_NO_THROW(timer_mgr.startThread()); + ASSERT_NO_THROW(timer_mgr->startThread()); doWait(500); - ASSERT_NO_THROW(timer_mgr.stopThread(true)); + ASSERT_NO_THROW(timer_mgr->stopThread(true)); } } // end of anonymous namespace diff --git a/src/lib/dhcpsrv/timer_mgr.cc b/src/lib/dhcpsrv/timer_mgr.cc index e4135e58f3..34e7f536e9 100644 --- a/src/lib/dhcpsrv/timer_mgr.cc +++ b/src/lib/dhcpsrv/timer_mgr.cc @@ -603,9 +603,9 @@ TimerMgrImpl::signalSocketClearing() { cond_var_.signal(); } -TimerMgr& +const TimerMgrPtr& TimerMgr::instance() { - static TimerMgr timer_mgr; + static TimerMgrPtr timer_mgr(new TimerMgr()); return (timer_mgr); } diff --git a/src/lib/dhcpsrv/timer_mgr.h b/src/lib/dhcpsrv/timer_mgr.h index d4a29f4388..2c22b03eea 100644 --- a/src/lib/dhcpsrv/timer_mgr.h +++ b/src/lib/dhcpsrv/timer_mgr.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include namespace isc { @@ -26,6 +26,12 @@ namespace dhcp { /// @brief Forward declaration of the @c TimerMgr implementation. class TimerMgrImpl; +/// @brief Forward declaration of the @c TimerMgr. +class TimerMgr; + +/// @brief Type definition of the shared pointer to @c TimerMgr. +typedef boost::shared_ptr TimerMgrPtr; + /// @brief Manages a pool of asynchronous interval timers for DHCP server. /// /// This class holds a pool of asynchronous interval timers which are @@ -97,8 +103,14 @@ class TimerMgrImpl; class TimerMgr : public boost::noncopyable { public: - /// @brief Returns sole instance of the @c TimerMgr singleton. - static TimerMgr& instance(); + /// @brief Returns pointer to the sole instance of the @c TimerMgr. + static const TimerMgrPtr& instance(); + + /// @brief Destructor. + /// + /// Stops the worker thread if it is running and unregisteres any + /// registered timers. + ~TimerMgr(); /// @name Registering, unregistering and scheduling the timers. //@{ @@ -218,9 +230,6 @@ public: private: - /// @name Constructor and destructor. - //@{ - /// /// @brief Private default constructor. /// /// The @c TimerMgr is a singleton class which instance must be created @@ -228,14 +237,6 @@ private: /// construction via @c TimerMgr::instance. TimerMgr(); - /// @brief Private destructor. - /// - /// Stops the worker thread if it is running and unregisteres any - /// registered timers. - ~TimerMgr(); - - //@} - /// @brief Pointer to @c TimerMgr implementation. TimerMgrImpl* impl_;