//============================================================================= /** * @file Reactor_Timer_Test.cpp * * This is a simple test that illustrates the timer mechanism of * the reactor. Scheduling timers, resetting timer intervals, * handling expired timers and cancelling scheduled timers are * all exercised in this test. * * @author Prashant Jain and Douglas C. Schmidt */ //============================================================================= #include "test_config.h" #include "ace/Timer_Queue.h" #include "ace/Reactor.h" #include "ace/High_Res_Timer.h" #include "ace/Trace.h" #include "ace/Recursive_Thread_Mutex.h" #include "ace/Log_Msg.h" #include "ace/Timer_Heap.h" #include "ace/Auto_Ptr.h" static int done = 0; static int the_count = 0; static int odd = 0; class Time_Handler : public ACE_Event_Handler { public: /// Default constructor Time_Handler (); /// Handle the timeout. int handle_timeout (const ACE_Time_Value &tv, const void *arg) override; /// Called when is removed. int handle_close (ACE_HANDLE handle, ACE_Reactor_Mask close_mask) override; /// Return our timer id. long timer_id () const; /// Set our timer id; void timer_id (long); private: /// Stores the id of this timer. long timer_id_; }; Time_Handler::Time_Handler () : timer_id_ (-1) { // Nothing } int Time_Handler::handle_close (ACE_HANDLE handle, ACE_Reactor_Mask close_mask) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("[%x] handle = %d, close_mask = %d, timer id = %d\n"), this, handle, close_mask, this->timer_id ())); return 0; } int Time_Handler::handle_timeout (const ACE_Time_Value &tv, const void *arg) { long current_count = static_cast (reinterpret_cast (arg)); if (current_count >= 0) ACE_TEST_ASSERT (current_count == the_count); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("[%x] Timer id %d with count #%d|%d timed out at %d!\n"), this, this->timer_id (), the_count, current_count, tv.sec ())); if (current_count == long (ACE_MAX_TIMERS - 1)) done = 1; else if (the_count == long (ACE_MAX_TIMERS - 1)) { done = 1; return -1; } else if (current_count == -1) { int result = ACE_Reactor::instance ()->reset_timer_interval (this->timer_id (), std::chrono::seconds {the_count + 1}); if (result == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("Error resetting timer interval\n"))); } the_count += (1 + odd); return 0; } long Time_Handler::timer_id () const { return this->timer_id_; } void Time_Handler::timer_id (long t) { this->timer_id_ = t; } static void test_registering_all_handlers () { ACE_Trace t (ACE_TEXT ("test_registering_all_handler"), __LINE__, ACE_TEXT_CHAR_TO_TCHAR (__FILE__)); Time_Handler rt[ACE_MAX_TIMERS]; long t_id[ACE_MAX_TIMERS]; for (size_t i = 0; i < ACE_MAX_TIMERS; i++) { t_id[i] = ACE_Reactor::instance ()->schedule_timer (&rt[i], (const void *) i, std::chrono::seconds {2 * i + 1}); ACE_TEST_ASSERT (t_id[i] != -1); rt[i].timer_id (t_id[i]); } while (!done) ACE_Reactor::instance ()->handle_events (); } static void test_registering_one_handler () { ACE_Trace t (ACE_TEXT ("test_registering_one_handler"), __LINE__, ACE_TEXT_CHAR_TO_TCHAR (__FILE__)); Time_Handler rt[ACE_MAX_TIMERS]; long t_id[ACE_MAX_TIMERS]; done = 0; the_count = 0; for (size_t i = 0; i < ACE_MAX_TIMERS; i++) { t_id[i] = ACE_Reactor::instance ()->schedule_timer (&rt[0], (const void *) i, ACE_Time_Value (2 * i + 1)); ACE_TEST_ASSERT (t_id[i] != -1); } while (!done) ACE_Reactor::instance ()->handle_events (); } static void test_canceling_odd_timers () { ACE_Trace t (ACE_TEXT ("test_canceling_odd_timers"), __LINE__, ACE_TEXT_CHAR_TO_TCHAR (__FILE__)); Time_Handler rt[ACE_MAX_TIMERS]; long t_id[ACE_MAX_TIMERS]; done = 0; the_count = 1; odd = 1; for (size_t i = 0; i < ACE_MAX_TIMERS; i++) { t_id[i] = ACE_Reactor::instance ()->schedule_timer (&rt[i], (const void *) i, ACE_Time_Value (2 * i + 1)); ACE_TEST_ASSERT (t_id[i] != -1); rt[i].timer_id (t_id[i]); } for (size_t j = 0; (u_long) j < ACE_MAX_TIMERS; j++) // Cancel handlers with odd numbered timer ids. if (ACE_ODD (rt[j].timer_id ())) { int result = ACE_Reactor::instance ()->cancel_timer (rt[j].timer_id ()); if (result == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("Error cancelling timer\n"))); } while (!done) ACE_Reactor::instance ()->handle_events (); } static void test_resetting_timer_intervals () { ACE_Trace t (ACE_TEXT ("test_resetting_timer_intervals"), __LINE__, ACE_TEXT_CHAR_TO_TCHAR (__FILE__)); Time_Handler rt; long t_id; done = 0; the_count = 0; odd = 0; t_id = ACE_Reactor::instance ()->schedule_timer (&rt, (const void *) -1, ACE_Time_Value (1), // Start off by making this an interval timer. ACE_Time_Value (1)); ACE_TEST_ASSERT (t_id != -1); rt.timer_id (t_id); while (!done) ACE_Reactor::instance ()->handle_events (); } // If any command line arg is given, run the test with high res timer // queue. Else run it normally. int run_main (int argc, ACE_TCHAR *[]) { ACE_START_TEST (ACE_TEXT ("Reactor_Timer_Test")); if (argc > 1) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Running with high-res timer queue\n"))); ACE_Reactor *r = ACE_Reactor::instance (); (void) ACE_High_Res_Timer::global_scale_factor (); // Change the source of time in the Reactor to the // high-resolution timer. Why does this test require such // precision for a 1 second timer is beyond me ... I think it // is a cut&paste error. // // The use of auto_ptr<> is optional, ACE uses dangerous memory // management idioms everywhere, I thought I could demonstrate how // to do it right in at least one test. Notice the lack of // ACE_NEW_RETURN, that monstrosity has no business in proper C++ // code ... std::unique_ptr tq( new ACE_Timer_Heap_Variable_Time_Source); // ... notice how the policy is in the derived timer queue type. // The abstract timer queue does not have a time policy ... tq->set_time_policy(&ACE_High_Res_Timer::gettimeofday_hr); // ... and then the timer queue is replaced. Strangely, the // Reactor does *not* copy the timers, it just deletes the // existing timer queue .... r->timer_queue(tq.get()); // ... the Reactor has assumed ownership, release the // auto_ptr<> ... tq.release(); } // Register all different handlers, i.e., one per timer. test_registering_all_handlers (); // Now try multiple timers for ONE event handler (should produce the // same result). test_registering_one_handler (); // Try canceling handlers with odd numbered timer ids. test_canceling_odd_timers (); // Make sure works. test_resetting_timer_intervals (); ACE_END_TEST; return 0; }