/** * @file Thread_Timer_Queue_Adapter_Test.cpp * * @author Alon Diamant * * This test verifies the functionality of the ACE_Timer_Queue_Thread_Adapter. * It also shows the usage of custom event handlers. */ //============================================================================= #include "ace/Timer_Wheel.h" #include "ace/Timer_Queue_Adapters.h" #include "ace/Truncate.h" #include "test_config.h" #if defined (ACE_HAS_THREADS) /// ICustomEventHandler /// /// Used to demonstrate the usage of custom event handlers. This is called by the /// timer queue thread adapter. class ICustomEventHandler { public: /// Default constructor. /// /// @return ICustomEventHandler() { } /// Default destructor. /// /// @return virtual ~ICustomEventHandler() { } /// Main functor method. /// /// @return int /// @param p_vParameter virtual int operator() (void* p_vParameter) = 0; }; /// CCustomEventHandlerUpcall /// /// Implements the Upcall interface used by the ACE_Timer_Queue, specifically for the /// ICustomEventHandler interface. class CCustomEventHandlerUpcall { public: using TTimerQueue = ACE_Timer_Queue_T; /// Default constructor CCustomEventHandlerUpcall() { } /// Destructor. ~CCustomEventHandlerUpcall() { } /// This method is called when the timer expires. int timeout (TTimerQueue&, ICustomEventHandler* p_Handler, const void* p_vParameter, int /*recurring_timer*/, const ACE_Time_Value& /*cur_time*/) { ACE_TRACE("timeout"); return (*p_Handler)(const_cast (p_vParameter)); } /// This method is called when a timer is registered. int registration(TTimerQueue&, ICustomEventHandler*, const void*) { return 0; } /// This method is called before the timer expires. int preinvoke(TTimerQueue&, ICustomEventHandler*, const void*, int, const ACE_Time_Value&, const void*&) { return 0; } /// This method is called after the timer expires. int postinvoke(TTimerQueue&, ICustomEventHandler*, const void*, int, const ACE_Time_Value&, const void*) { return 0; } /// This method is called when a handler is canceled int cancel_type(TTimerQueue&, ICustomEventHandler*, int, int&) { return 0; } /// This method is called when a timer is canceled int cancel_timer(TTimerQueue&, ICustomEventHandler* p_Handler, int, int) { ACE_TRACE("cancel_timer"); delete p_Handler; return 0; } /// This method is called when the timer queue is destroyed and /// the timer is still contained in it int deletion(TTimerQueue&, ICustomEventHandler* p_Handler, const void*) { ACE_TRACE("deletion"); delete p_Handler; return 0; } }; /// ICustomEventHandler /// /// Used to demonstrate the usage of custom event handlers. This is called by the /// timer queue thread adapter. class CTestEventHandler : public ICustomEventHandler { public: /// Default constructor. /// /// @return CTestEventHandler(long* p_iCallCount) : m_p_iCallCount(p_iCallCount) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Initializing test event handler.\n"))); } /// Default destructor. /// /// @return ~CTestEventHandler() override { ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Destroying test event handler.\n"))); } /// Main functor method. /// /// @return int /// @param p_vParameter int operator() (void* p_vParameter) override { long iParameter = ACE_Utils::truncate_cast ((intptr_t)p_vParameter); ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Incrementing test event handler call count by %d.\n"), iParameter)); m_Mutex.acquire(); *m_p_iCallCount += iParameter; m_Mutex.release(); // Success return 0; } private: long* m_p_iCallCount; ACE_Thread_Mutex m_Mutex; }; // Used for the actual timer queue thread adapter using TTimerWheel = ACE_Timer_Wheel_T; using TTimerWheelIterator = ACE_Timer_Wheel_Iterator_T; using TTimerWheelThreadAdapter = ACE_Thread_Timer_Queue_Adapter; #endif /* ACE_HAS_THREADS */ int run_main (int, ACE_TCHAR *[]) { ACE_START_TEST (ACE_TEXT ("Thread_Timer_Queue_Adapter_Test")); #if defined (ACE_HAS_THREADS) // Start the thread adapter TTimerWheelThreadAdapter TimerWheelThreadAdapter; TimerWheelThreadAdapter.activate(); // Single timer { // Create a test event handler long iCallCount = 0; CTestEventHandler* p_TestEventHandler = 0; ACE_NEW_RETURN(p_TestEventHandler, CTestEventHandler(&iCallCount), -1); ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Scheduling timer...\n"))); TimerWheelThreadAdapter.schedule(p_TestEventHandler, (void*) 1, ACE_OS::gettimeofday() + ACE_Time_Value(1, 0)); ACE_OS::sleep(ACE_Time_Value(1, 100 * 1000)); ACE_TEST_ASSERT(iCallCount == 1); delete p_TestEventHandler; ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Success in Single timer test.\n"))); } // Single timer with cancellation { // Create a test event handler long iCallCount = 0; CTestEventHandler* p_TestEventHandler = 0; ACE_NEW_RETURN(p_TestEventHandler, CTestEventHandler(&iCallCount), -1); ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Scheduling timer...\n"))); long lTimerHandle = TimerWheelThreadAdapter.schedule(p_TestEventHandler, (void*) 1, ACE_OS::gettimeofday() + ACE_Time_Value(1, 0)); // Cancel the repeating timer TimerWheelThreadAdapter.cancel(lTimerHandle); ACE_OS::sleep(ACE_Time_Value(1, 100 * 1000)); ACE_TEST_ASSERT(iCallCount == 0); // Test event handler was deleted by the timer. ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Success in Single timer with cancellation test.\n"))); } // Repeating timer with cancellation { // Create a test event handler long iCallCount = 0; CTestEventHandler* p_TestEventHandler = 0; ACE_NEW_RETURN(p_TestEventHandler, CTestEventHandler(&iCallCount), -1); ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Scheduling timer...\n"))); long lTimerHandle = TimerWheelThreadAdapter.schedule (p_TestEventHandler, (void*) 1, ACE_OS::gettimeofday() + ACE_Time_Value(1, 0), ACE_Time_Value(1, 0)); ACE_OS::sleep(ACE_Time_Value(3, 500 * 1000)); ACE_TEST_ASSERT(iCallCount == 3); // Cancel the repeating timer TimerWheelThreadAdapter.cancel(lTimerHandle); ACE_TEST_ASSERT(iCallCount == 3); ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Success in Repeating timer with cancellation test.\n"))); } // Multiple timers { // Create a test event handler long iCallCount = 0; CTestEventHandler* p_TestEventHandler = 0; ACE_NEW_RETURN(p_TestEventHandler, CTestEventHandler(&iCallCount), -1); ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Scheduling timer...\n"))); TimerWheelThreadAdapter.schedule (p_TestEventHandler, (void*) 1, ACE_OS::gettimeofday() + ACE_Time_Value(1, 0)); TimerWheelThreadAdapter.schedule (p_TestEventHandler, (void*) 1, ACE_OS::gettimeofday() + ACE_Time_Value(1, 0)); TimerWheelThreadAdapter.schedule (p_TestEventHandler, (void*) 1, ACE_OS::gettimeofday() + ACE_Time_Value(2, 0)); ACE_OS::sleep(ACE_Time_Value(3, 0)); ACE_TEST_ASSERT(iCallCount == 3); delete p_TestEventHandler; ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Success in Multiple timers test.\n"))); } #else ACE_ERROR ((LM_INFO, ACE_TEXT ("threads not supported on this platform\n"))); #endif /* ACE_HAS_THREADS */ ACE_END_TEST; return 0; }