diff options
-rw-r--r-- | ACE/ChangeLog | 25 | ||||
-rw-r--r-- | ACE/ace/High_Res_Timer.cpp | 163 | ||||
-rw-r--r-- | ACE/ace/High_Res_Timer.h | 54 | ||||
-rw-r--r-- | ACE/ace/High_Res_Timer.inl | 65 | ||||
-rw-r--r-- | ACE/ace/Timer_Queue_Adapters.cpp | 76 | ||||
-rw-r--r-- | ACE/ace/Timer_Queue_Adapters.h | 8 | ||||
-rw-r--r-- | ACE/ace/Timer_Queue_Adapters.inl | 12 | ||||
-rw-r--r-- | ACE/tests/Thread_Timer_Queue_Adapter_Test.cpp | 297 | ||||
-rw-r--r-- | ACE/tests/tests.mpc | 7 |
9 files changed, 596 insertions, 111 deletions
diff --git a/ACE/ChangeLog b/ACE/ChangeLog index b2536ce3193..54c80f59808 100644 --- a/ACE/ChangeLog +++ b/ACE/ChangeLog @@ -1,3 +1,28 @@ +Mon Mar 15 07:58:54 UTC 2010 Johnny Willemsen <jwillemsen@remedy.nl> + + * ace/High_Res_Timer.cpp + * ace/High_Res_Timer.h + * ace/High_Res_Timer.inl + Use 64bit calculations to increase our precision. If you want to have the 32bit + calculations, add ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS as define. If + the scoreboard doesn't show any platforms requiring 32bit, we will remove that code + before the next micro release goes out + Thanks to Alon Diamant <diamant dot alon at gmail dot com> for supplying the patches. + This fixes bugzilla 3703. + + * ace/Timer_Queue_Adapters.cpp + * ace/Timer_Queue_Adapters.h + * ace/Timer_Queue_Adapters.inl + Make it possible to use a customer event handler in ACE_Thread_Timer_Queue_Adapter. + Thanks to Alon Diamant <diamant dot alon at gmail dot com> for supplying the patches. + This fixes bugzilla 3614 + + * tests/tests.mpc: + * tests/Thread_Timer_Queue_Adapter_Test.cpp: + New test for testing custom event handlers in ACE_Thread_Timer_Queue_Adapter. + Thanks to Alon Diamant <diamant dot alon at gmail dot com> for creating + this new test + Fri Mar 12 21:53:30 UTC 2010 Adam Mitz <mitza@ociweb.com> * bin/PerlACE/ProcessVX.pm: diff --git a/ACE/ace/High_Res_Timer.cpp b/ACE/ace/High_Res_Timer.cpp index 69099214051..4e9b0f523f0 100644 --- a/ACE/ace/High_Res_Timer.cpp +++ b/ACE/ace/High_Res_Timer.cpp @@ -43,11 +43,24 @@ ACE_END_VERSIONED_NAMESPACE_DECL ACE_BEGIN_VERSIONED_NAMESPACE_DECL - // Initialize the global_scale_factor_ to 1. The first - // ACE_High_Res_Timer instance construction will override this - // value. - /* static */ - ACE_UINT32 ACE_High_Res_Timer::global_scale_factor_ = 1u; +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + + // Initialize the global_scale_factor_ to 1. The first + // ACE_High_Res_Timer instance construction will override this + // value. + /* static */ + ACE_UINT32 ACE_High_Res_Timer::global_scale_factor_ = 1u; + +#else + + /// This a higher-precision version, specific for Windows systems + // Initialize the global_scale_factor_ to 1. The first + // ACE_High_Res_Timer instance construction will override this + // value. + /* static */ + ACE_UINT64 ACE_High_Res_Timer::global_scale_factor_ = 1u; + +#endif ACE_END_VERSIONED_NAMESPACE_DECL @@ -190,8 +203,18 @@ ACE_High_Res_Timer::get_cpuinfo (void) } #endif /* linux */ -ACE_UINT32 -ACE_High_Res_Timer::global_scale_factor (void) + +// Return value is based on required precision. +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + + ACE_UINT32 ACE_High_Res_Timer::global_scale_factor (void) + +#else + + // This a higher-precision version, specific for Windows systems + ACE_UINT64 ACE_High_Res_Timer::global_scale_factor (void) + +#endif { #if (defined (ACE_WIN32) || defined (ACE_HAS_POWERPC_TIMER) || \ defined (ACE_HAS_PENTIUM) || defined (ACE_HAS_ALPHA_TIMER)) && \ @@ -211,27 +234,50 @@ ACE_High_Res_Timer::global_scale_factor (void) if (ACE_High_Res_Timer::global_scale_factor_status_ == 0) { # if defined (ACE_WIN32) - LARGE_INTEGER freq; - if (::QueryPerformanceFrequency (&freq)) - { - // We have a high-res timer -# if defined (ACE_LACKS_LONGLONG_T) - ACE_UINT64 uint64_freq(freq.u.LowPart, (ACE_UINT32) freq.u.HighPart); - ACE_High_Res_Timer::global_scale_factor - (uint64_freq / (ACE_UINT32) ACE_ONE_SECOND_IN_USECS); -# else - ACE_High_Res_Timer::global_scale_factor - (static_cast<unsigned int> (freq.QuadPart / ACE_HR_SCALE_CONVERSION)); -# endif // (ACE_LACKS_LONGLONG_T) - - ACE_High_Res_Timer::global_scale_factor_status_ = 1; - } - else - // High-Res timers not supported - ACE_High_Res_Timer::global_scale_factor_status_ = -1; - - return ACE_High_Res_Timer::global_scale_factor_; +# if defined (ACE_LACKS_LONGLONG_T) || \ + defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + + + LARGE_INTEGER freq; + if (::QueryPerformanceFrequency (&freq)) + { + // We have a high-res timer +# if defined (ACE_LACKS_LONGLONG_T) + ACE_UINT64 uint64_freq(freq.u.LowPart, (ACE_UINT32) freq.u.HighPart); + ACE_High_Res_Timer::global_scale_factor + (uint64_freq / (ACE_UINT32) ACE_ONE_SECOND_IN_USECS); +# else + ACE_High_Res_Timer::global_scale_factor + (static_cast<unsigned int> (freq.QuadPart / ACE_HR_SCALE_CONVERSION)); +# endif // (ACE_LACKS_LONGLONG_T) + + ACE_High_Res_Timer::global_scale_factor_status_ = 1; + } + else + // High-Res timers not supported + ACE_High_Res_Timer::global_scale_factor_status_ = -1; + + return ACE_High_Res_Timer::global_scale_factor_; +# else // defined (ACE_LACKS_LONGLONG_T) || \ + // defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + + // This a higher-precision version, specific for Windows systems + LARGE_INTEGER freq; + if (::QueryPerformanceFrequency (&freq)) + { + ACE_High_Res_Timer::global_scale_factor(freq.QuadPart); + + ACE_High_Res_Timer::global_scale_factor_status_ = 1; + } + else + { + // High-Res timers not supported + ACE_High_Res_Timer::global_scale_factor_status_ = -1; + } + return ACE_High_Res_Timer::global_scale_factor_; + +# endif # elif defined (linux) ACE_High_Res_Timer::global_scale_factor (ACE_High_Res_Timer::get_cpuinfo ()); # endif /* ! ACE_WIN32 && ! (linux && __alpha__) */ @@ -267,7 +313,7 @@ ACE_UINT32 ACE_High_Res_Timer::calibrate (const ACE_UINT32 usec, const u_int iterations) { - const ACE_Time_Value sleep_time (0, usec); + ACE_Time_Value const sleep_time (0, usec); ACE_Stats delta_hrtime; // In units of 100 usec, to avoid overflow. ACE_Stats actual_sleeps; @@ -276,13 +322,10 @@ ACE_High_Res_Timer::calibrate (const ACE_UINT32 usec, i < iterations; ++i) { - ACE_Time_Value const actual_start = - ACE_OS::gettimeofday (); - ACE_hrtime_t const start = - ACE_OS::gethrtime (); + ACE_Time_Value const actual_start = ACE_OS::gettimeofday (); + ACE_hrtime_t const start = ACE_OS::gethrtime (); ACE_OS::sleep (sleep_time); - ACE_hrtime_t const stop = - ACE_OS::gethrtime (); + ACE_hrtime_t const stop = ACE_OS::gethrtime (); ACE_Time_Value const actual_delta = ACE_OS::gettimeofday () - actual_start; @@ -403,26 +446,46 @@ ACE_High_Res_Timer::elapsed_time_incr (ACE_Time_Value &tv) const void ACE_High_Res_Timer::elapsed_time (ACE_hrtime_t &nanoseconds) const { - // Please do _not_ rearrange this equation. It is carefully - // designed and tested to avoid overflow on machines that don't have - // native 64-bit ints. In particular, division can be a problem. - // For more background on this, please see bugzilla #1024. - nanoseconds = ACE_High_Res_Timer::elapsed_hrtime (this->end_, this->start_) - * (1024000u / ACE_High_Res_Timer::global_scale_factor ()); - // Caution - Borland has a problem with >>=, so resist the temptation. - nanoseconds = nanoseconds >> 10; - // Right shift is implemented for non native 64-bit ints - // operator/ only for a 32 bit result ! +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + + // Please do _not_ rearrange this equation. It is carefully + // designed and tested to avoid overflow on machines that don't have + // native 64-bit ints. In particular, division can be a problem. + // For more background on this, please see bugzilla #1024. + nanoseconds = ACE_High_Res_Timer::elapsed_hrtime (this->end_, this->start_) + * (1024000u / ACE_High_Res_Timer::global_scale_factor ()); + // Caution - Borland has a problem with >>=, so resist the temptation. + nanoseconds = nanoseconds >> 10; + // Right shift is implemented for non native 64-bit ints + // operator/ only for a 32 bit result ! +#else + + // This a higher-precision version, specific for Windows systems + nanoseconds = + (ACE_High_Res_Timer::elapsed_hrtime (this->end_, this->start_) * ACE_HR_SCALE_CONVERSION * 1000u) / + ACE_High_Res_Timer::global_scale_factor (); + +#endif } void ACE_High_Res_Timer::elapsed_time_incr (ACE_hrtime_t &nanoseconds) const { - // Same as above. - nanoseconds = this->total_ +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + + // Same as above. + nanoseconds = this->total_ * (1024000u / ACE_High_Res_Timer::global_scale_factor ()); - // Caution - Borland has a problem with >>=, so resist the temptation. - nanoseconds = nanoseconds >> 10; + // Caution - Borland has a problem with >>=, so resist the temptation. + nanoseconds = nanoseconds >> 10; +#else + + // This a higher-precision version, specific for Windows systems + nanoseconds = + this->total_ * 1000000000u / + ACE_High_Res_Timer::global_scale_factor (); + +#endif } void @@ -480,9 +543,9 @@ ACE_High_Res_Timer::print_total (const ACE_TCHAR *str, // Separate to seconds and nanoseconds. u_long total_secs = - (u_long) (total_nanoseconds / (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS); + static_cast<u_long> (total_nanoseconds / (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS); ACE_UINT32 extra_nsecs = - (ACE_UINT32) (total_nanoseconds % (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS); + static_cast<ACE_UINT32> (total_nanoseconds % (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS); ACE_TCHAR buf[100]; if (count > 1) diff --git a/ACE/ace/High_Res_Timer.h b/ACE/ace/High_Res_Timer.h index 2bb9730280a..f0eff73296c 100644 --- a/ACE/ace/High_Res_Timer.h +++ b/ACE/ace/High_Res_Timer.h @@ -24,6 +24,30 @@ #include "ace/OS_NS_time.h" #include "ace/Time_Value.h" +/// 2009-06-03, Alon Diamant <diamant.alon@gmail.com> +/// +/// On Windows, the high-resolution timer calculations were done +/// using 32-bit integers. Since the timer actually uses 64-bit +/// integers for its frequency and counter values, the values +/// had to be divided - resulting in a loss of precision that +/// is in the range of a hundreth of a percent. On my system, +/// I experienced a lack of precision of up to 0.007% - which +/// translates to a 1 second loss of precision every 4 hours. +/// +/// I changed the high-resolution timer class to add support for +/// native 64-bit calculations - which are supported by a vast +/// majority of Windows machines nowadays. The loss of precision +/// that resulted from the 32-bit arithmetic is therefore gone. +/// +/// Define ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS +/// in config.h to disable this feature and use the old 32-bit +/// timer calculations. +/// +/// Note that this flag is only allowed on Windows systems. +#if !defined (ACE_WIN32) +#undef ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS +#endif + ACE_BEGIN_VERSIONED_NAMESPACE_DECL /** @@ -102,6 +126,8 @@ class ACE_Export ACE_High_Res_Timer public: // = Initialization method. +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + /** * global_scale_factor_ is set to @a gsf. All High_Res_Timers use * global_scale_factor_. This allows applications to set the scale @@ -119,6 +145,22 @@ public: /// Returns the global_scale_factor. static ACE_UINT32 global_scale_factor (void); + +#else + + /** + * global_scale_factor_ is set to @a gsf. All High_Res_Timers use + * global_scale_factor_. This allows applications to set the scale + * factor just once for all High_Res_Timers. + * This a higher-precision version, specific for Windows systems + * with 64-bit support. + */ + static void global_scale_factor (ACE_UINT64 gsf); + + /// Returns the global_scale_factor. + static ACE_UINT64 global_scale_factor (void); + +#endif #ifndef ACE_HR_SCALE_CONVERSION # define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_USECS) @@ -287,9 +329,21 @@ private: /// Start time of incremental timing. ACE_hrtime_t start_incr_; +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + /// Converts ticks to microseconds. That is, ticks / /// global_scale_factor_ == microseconds. static ACE_UINT32 global_scale_factor_; + +#else + + /// This a higher-precision version, specific for Windows systems + + /// Converts ticks to microseconds. That is, ticks / + /// global_scale_factor_ == microseconds. + static ACE_UINT64 global_scale_factor_; + +#endif /** * Indicates the status of the global scale factor, diff --git a/ACE/ace/High_Res_Timer.inl b/ACE/ace/High_Res_Timer.inl index 56df6e1f04b..a568d971eda 100644 --- a/ACE/ace/High_Res_Timer.inl +++ b/ACE/ace/High_Res_Timer.inl @@ -21,21 +21,37 @@ ACE_INLINE void ACE_High_Res_Timer::hrtime_to_tv (ACE_Time_Value &tv, const ACE_hrtime_t hrt) { - // The following are based on the units of global_scale_factor_ - // being 1/microsecond. Therefore, dividing by it converts - // clock ticks to microseconds. - tv.sec ((long) (hrt / (ACE_UINT32) ACE_HR_SCALE_CONVERSION / +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + + // The following are based on the units of global_scale_factor_ + // being 1/microsecond. Therefore, dividing by it converts + // clock ticks to microseconds. + tv.sec ((long) (hrt / (ACE_UINT32) ACE_HR_SCALE_CONVERSION / global_scale_factor ())); - // Calculate usec in a manner that's compatible with ACE_U_LongLong. - // hrt = (tv.sec * ACE_ONE_SECOND_IN_USECS + tv.usec) * global_scale_factor_ - // tv.usec = hrt / global_scale_factor_ - tv.sec * ACE_ONE_SECOND_IN_USECS - // That first term will be lossy, so factor out global_scale_factor_: - // tv.usec = (hrt - tv.sec * ACE_ONE_SECOND_IN_USECS * global_scale_factor_)/ - // global_scale_factor - ACE_hrtime_t tmp = tv.sec (); - tmp *= ((ACE_UINT32) ACE_HR_SCALE_CONVERSION * global_scale_factor ()); - tv.usec ((long) ((hrt - tmp) / global_scale_factor ())); + // Calculate usec in a manner that's compatible with ACE_U_LongLong. + // hrt = (tv.sec * ACE_ONE_SECOND_IN_USECS + tv.usec) * global_scale_factor_ + // tv.usec = hrt / global_scale_factor_ - tv.sec * ACE_ONE_SECOND_IN_USECS + // That first term will be lossy, so factor out global_scale_factor_: + // tv.usec = (hrt - tv.sec * ACE_ONE_SECOND_IN_USECS * global_scale_factor_)/ + // global_scale_factor + ACE_hrtime_t tmp = tv.sec (); + tmp *= ((ACE_UINT32) ACE_HR_SCALE_CONVERSION * global_scale_factor ()); + tv.usec ((long) ((hrt - tmp) / global_scale_factor ())); +#else + + // This a higher-precision version, specific for Windows systems + // The following are based on the units of global_scale_factor_ + // being 1/microsecond. Therefore, dividing by it converts + // clock ticks to microseconds. + tv.sec ((long) (hrt / global_scale_factor () )); + + // Calculate usec + ACE_hrtime_t tmp = tv.sec (); + tmp *= global_scale_factor (); + tv.usec ((long) ((hrt - tmp) * ACE_HR_SCALE_CONVERSION / global_scale_factor ())); + +#endif } @@ -139,15 +155,38 @@ ACE_High_Res_Timer::stop_incr (const ACE_OS::ACE_HRTimer_Op op) ACE_INLINE void ACE_High_Res_Timer::elapsed_microseconds (ACE_hrtime_t &usecs) const { + +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + ACE_hrtime_t elapsed = ACE_High_Res_Timer::elapsed_hrtime (this->end_, this->start_); usecs = (ACE_hrtime_t) (elapsed / global_scale_factor ()); + +#else + + usecs = (ACE_High_Res_Timer::elapsed_hrtime (this->end_, this->start_) * + ACE_HR_SCALE_CONVERSION) / + global_scale_factor (); + +#endif } +#if defined (ACE_USE_WINDOWS_32BIT_HIGH_RES_TIMER_CALCULATIONS) + ACE_INLINE void ACE_High_Res_Timer::global_scale_factor (ACE_UINT32 gsf) { global_scale_factor_ = gsf; } +#else + +ACE_INLINE void +ACE_High_Res_Timer::global_scale_factor (ACE_UINT64 gsf) +{ + global_scale_factor_ = gsf; +} + +#endif + ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/ace/Timer_Queue_Adapters.cpp b/ACE/ace/Timer_Queue_Adapters.cpp index 0c4fc51b573..1c04fd6eed2 100644 --- a/ACE/ace/Timer_Queue_Adapters.cpp +++ b/ACE/ace/Timer_Queue_Adapters.cpp @@ -23,14 +23,14 @@ ACE_BEGIN_VERSIONED_NAMESPACE_DECL -template <class TQ> TQ & -ACE_Async_Timer_Queue_Adapter<TQ>::timer_queue (void) +template <class TQ, class TYPE> TQ & +ACE_Async_Timer_Queue_Adapter<TQ, TYPE>::timer_queue (void) { return this->timer_queue_; } -template <class TQ> int -ACE_Async_Timer_Queue_Adapter<TQ>::cancel (long timer_id, +template <class TQ, class TYPE> int +ACE_Async_Timer_Queue_Adapter<TQ, TYPE>::cancel (long timer_id, const void **act) { // Block designated signals. @@ -40,8 +40,8 @@ ACE_Async_Timer_Queue_Adapter<TQ>::cancel (long timer_id, return this->timer_queue_.cancel (timer_id, act); } -template <class TQ> int -ACE_Async_Timer_Queue_Adapter<TQ>::expire (void) +template <class TQ, class TYPE> int +ACE_Async_Timer_Queue_Adapter<TQ, TYPE>::expire (void) { // Block designated signals. ACE_Sig_Guard sg (&this->mask_); @@ -50,8 +50,8 @@ ACE_Async_Timer_Queue_Adapter<TQ>::expire (void) return this->timer_queue_.expire (); } -template <class TQ> int -ACE_Async_Timer_Queue_Adapter<TQ>::schedule_ualarm (void) +template <class TQ, class TYPE> int +ACE_Async_Timer_Queue_Adapter<TQ, TYPE>::schedule_ualarm (void) { ACE_Time_Value tv = this->timer_queue_.earliest_time () - this->timer_queue_.gettimeofday (); @@ -68,8 +68,8 @@ ACE_Async_Timer_Queue_Adapter<TQ>::schedule_ualarm (void) return 0; } -template <class TQ> long -ACE_Async_Timer_Queue_Adapter<TQ>::schedule (ACE_Event_Handler *eh, +template <class TQ, class TYPE> long +ACE_Async_Timer_Queue_Adapter<TQ, TYPE>::schedule (TYPE eh, const void *act, const ACE_Time_Value &future_time, const ACE_Time_Value &interval) @@ -96,8 +96,8 @@ ACE_Async_Timer_Queue_Adapter<TQ>::schedule (ACE_Event_Handler *eh, return tid; } -template <class TQ> -ACE_Async_Timer_Queue_Adapter<TQ>::ACE_Async_Timer_Queue_Adapter (ACE_Sig_Set *mask) +template <class TQ, class TYPE> +ACE_Async_Timer_Queue_Adapter<TQ, TYPE>::ACE_Async_Timer_Queue_Adapter (ACE_Sig_Set *mask) // If <mask> == 0, block *all* signals when the SIGARLM handler is // running, else just block those in the mask. : mask_ (mask) @@ -120,8 +120,8 @@ ACE_Async_Timer_Queue_Adapter<TQ>::ACE_Async_Timer_Queue_Adapter (ACE_Sig_Set *m // list. It gets invoked asynchronously when the SIGALRM signal // occurs. -template <class TQ> int -ACE_Async_Timer_Queue_Adapter<TQ>::handle_signal (int signum, +template <class TQ, class TYPE> int +ACE_Async_Timer_Queue_Adapter<TQ, TYPE>::handle_signal (int signum, siginfo_t *, ucontext_t *) { @@ -154,8 +154,8 @@ ACE_Async_Timer_Queue_Adapter<TQ>::handle_signal (int signum, } } -template<class TQ> -ACE_Thread_Timer_Queue_Adapter<TQ>::ACE_Thread_Timer_Queue_Adapter (ACE_Thread_Manager *tm, +template<class TQ, class TYPE> +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::ACE_Thread_Timer_Queue_Adapter (ACE_Thread_Manager *tm, TQ* timer_queue) : ACE_Task_Base (tm), timer_queue_(timer_queue), @@ -172,8 +172,8 @@ ACE_Thread_Timer_Queue_Adapter<TQ>::ACE_Thread_Timer_Queue_Adapter (ACE_Thread_M } } -template<class TQ> -ACE_Thread_Timer_Queue_Adapter<TQ>::~ACE_Thread_Timer_Queue_Adapter (void) +template<class TQ, class TYPE> +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::~ACE_Thread_Timer_Queue_Adapter (void) { if (this->delete_timer_queue_) { @@ -183,39 +183,39 @@ ACE_Thread_Timer_Queue_Adapter<TQ>::~ACE_Thread_Timer_Queue_Adapter (void) } } -template<class TQ> ACE_SYNCH_RECURSIVE_MUTEX & -ACE_Thread_Timer_Queue_Adapter<TQ>::mutex (void) +template<class TQ, class TYPE> ACE_SYNCH_RECURSIVE_MUTEX & +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::mutex (void) { return this->mutex_; } -template<class TQ> long -ACE_Thread_Timer_Queue_Adapter<TQ>::schedule - (ACE_Event_Handler* handler, +template<class TQ, class TYPE> long +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::schedule + (TYPE handler, const void *act, const ACE_Time_Value &future_time, const ACE_Time_Value &interval) { ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, guard, this->mutex_, -1); - long const result = this->timer_queue_->schedule (handler, act, future_time, interval); + long result = this->timer_queue_->schedule (handler, act, future_time, interval); this->condition_.signal (); return result; } -template<class TQ> int -ACE_Thread_Timer_Queue_Adapter<TQ>::cancel (long timer_id, +template<class TQ, class TYPE> int +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::cancel (long timer_id, const void **act) { ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, guard, this->mutex_, -1); - int const result = this->timer_queue_->cancel (timer_id, act); + int result = this->timer_queue_->cancel (timer_id, act); condition_.signal (); return result; } -template<class TQ> void -ACE_Thread_Timer_Queue_Adapter<TQ>::deactivate (void) +template<class TQ, class TYPE> void +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::deactivate (void) { ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, guard, this->mutex_); @@ -223,8 +223,8 @@ ACE_Thread_Timer_Queue_Adapter<TQ>::deactivate (void) this->condition_.signal (); } -template<class TQ> int -ACE_Thread_Timer_Queue_Adapter<TQ>::svc (void) +template<class TQ, class TYPE> int +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::svc (void) { ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, guard, this->mutex_, -1); @@ -290,8 +290,8 @@ ACE_Thread_Timer_Queue_Adapter<TQ>::svc (void) return 0; } -template<class TQ> int -ACE_Thread_Timer_Queue_Adapter<TQ>::activate (long flags, +template<class TQ, class TYPE> int +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::activate (long flags, int , int , long priority, @@ -320,14 +320,14 @@ ACE_Thread_Timer_Queue_Adapter<TQ>::activate (long flags, // or cancelling timers on platforms where the timer queue mutex is not // recursive. -template<class TQ> int -ACE_Thread_Timer_Queue_Adapter<TQ>::enqueue_command (ACE_Command_Base *cmd, +template<class TQ, class TYPE> int +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::enqueue_command (ACE_Command_Base *cmd, COMMAND_ENQUEUE_POSITION pos) { // Serialize access to the command queue. ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard, this->command_mutex_, -1); - if (pos == ACE_Thread_Timer_Queue_Adapter<TQ>::TAIL) + if (pos == ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::TAIL) return command_queue_.enqueue_tail (cmd); else return command_queue_.enqueue_head (cmd); @@ -336,8 +336,8 @@ ACE_Thread_Timer_Queue_Adapter<TQ>::enqueue_command (ACE_Command_Base *cmd, // Dispatches all command objects enqueued in the most recent event // handler context. -template<class TQ> int -ACE_Thread_Timer_Queue_Adapter<TQ>::dispatch_commands (void) +template<class TQ, class TYPE> int +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::dispatch_commands (void) { // Serialize access to the command queue. ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard, this->command_mutex_, -1); diff --git a/ACE/ace/Timer_Queue_Adapters.h b/ACE/ace/Timer_Queue_Adapters.h index 08ea47075f3..4611239fb02 100644 --- a/ACE/ace/Timer_Queue_Adapters.h +++ b/ACE/ace/Timer_Queue_Adapters.h @@ -49,7 +49,7 @@ class ACE_Sig_Set; * * @todo This adapter does not automatically reschedule repeating timers. */ -template <class TQ> +template <class TQ, class TYPE = ACE_Event_Handler*> class ACE_Async_Timer_Queue_Adapter : public ACE_Event_Handler { public: @@ -70,7 +70,7 @@ public: * calling expire(). Note that interval timers are not implemented * yet. */ - long schedule (ACE_Event_Handler *type, + long schedule (TYPE type, const void *act, const ACE_Time_Value &future_time, const ACE_Time_Value &interval = ACE_Time_Value::zero); @@ -119,7 +119,7 @@ private: * use. * */ -template <class TQ> +template <class TQ, class TYPE = ACE_Event_Handler*> class ACE_Thread_Timer_Queue_Adapter : public ACE_Task_Base { public: @@ -145,7 +145,7 @@ public: /// Schedule the timer according to the semantics of the <TQ>; wakes /// up the dispatching thread. - long schedule (ACE_Event_Handler *handler, + long schedule (TYPE handler, const void *act, const ACE_Time_Value &future_time, const ACE_Time_Value &interval = ACE_Time_Value::zero); diff --git a/ACE/ace/Timer_Queue_Adapters.inl b/ACE/ace/Timer_Queue_Adapters.inl index 3252b186e07..16901a15bd6 100644 --- a/ACE/ace/Timer_Queue_Adapters.inl +++ b/ACE/ace/Timer_Queue_Adapters.inl @@ -4,14 +4,14 @@ ACE_BEGIN_VERSIONED_NAMESPACE_DECL -template<class TQ> ACE_INLINE TQ * -ACE_Thread_Timer_Queue_Adapter<TQ>::timer_queue (void) const +template<class TQ, class TYPE> ACE_INLINE TQ * +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::timer_queue (void) const { return this->timer_queue_; } -template<class TQ> ACE_INLINE int -ACE_Thread_Timer_Queue_Adapter<TQ>::timer_queue (TQ *tq) +template<class TQ, class TYPE> ACE_INLINE int +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::timer_queue (TQ *tq) { if (this->delete_timer_queue_) delete this->timer_queue_; @@ -20,8 +20,8 @@ ACE_Thread_Timer_Queue_Adapter<TQ>::timer_queue (TQ *tq) return 0; } -template<class TQ> ACE_INLINE ACE_thread_t -ACE_Thread_Timer_Queue_Adapter<TQ>::thr_id (void) const +template<class TQ, class TYPE> ACE_INLINE ACE_thread_t +ACE_Thread_Timer_Queue_Adapter<TQ, TYPE>::thr_id (void) const { return this->thr_id_; } diff --git a/ACE/tests/Thread_Timer_Queue_Adapter_Test.cpp b/ACE/tests/Thread_Timer_Queue_Adapter_Test.cpp new file mode 100644 index 00000000000..88fefc75387 --- /dev/null +++ b/ACE/tests/Thread_Timer_Queue_Adapter_Test.cpp @@ -0,0 +1,297 @@ +//============================================================================= +/** + * @file Thread_Timer_Queue_Adapter_Test.cpp + * + * @author Alon Diamant <diamant.alon@gmail.com> + * + * 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 "test_config.h" + +/// 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: + + typedef ACE_Timer_Queue_T<ICustomEventHandler*, + CCustomEventHandlerUpcall, + ACE_Null_Mutex> TTimerQueue; + + /// 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(ACE_TEXT ("timeout")); + + return (*p_Handler)(const_cast<void*> (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(ACE_TEXT ("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(ACE_TEXT ("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(int* p_iCallCount) + : m_p_iCallCount(p_iCallCount) + { + ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Initializing test event handler.\n"))); + } + + /// Default destructor. + /// + /// @return + virtual ~CTestEventHandler() + { + ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Destroying test event handler.\n"))); + } + + /// Main functor method. + /// + /// @return int + /// @param p_vParameter + virtual int operator() (void* p_vParameter) + { + int iParameter = (int) 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: + + int* m_p_iCallCount; + ACE_Thread_Mutex m_Mutex; +}; + +// Used for the actual timer queue thread adapter +typedef ACE_Timer_Wheel_T <ICustomEventHandler*, + CCustomEventHandlerUpcall, + ACE_Null_Mutex> TTimerWheel; +typedef ACE_Timer_Wheel_Iterator_T <ICustomEventHandler*, + CCustomEventHandlerUpcall, + ACE_Null_Mutex> TTimerWheelIterator; +typedef ACE_Thread_Timer_Queue_Adapter<TTimerWheel, + ICustomEventHandler*> TTimerWheelThreadAdapter; + +int +run_main (int, ACE_TCHAR *[]) +{ + ACE_START_TEST (ACE_TEXT ("Thread_Timer_Queue_Adapter_Test")); + + // Start the thread adapter + TTimerWheelThreadAdapter TimerWheelThreadAdapter; + TimerWheelThreadAdapter.activate(); + + // Single timer + { + // Create a test event handler + int iCallCount = 0; + CTestEventHandler* p_TestEventHandler = NULL; + 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_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 + int iCallCount = 0; + CTestEventHandler* p_TestEventHandler = NULL; + 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_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 + int iCallCount = 0; + CTestEventHandler* p_TestEventHandler = NULL; + 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_ASSERT(iCallCount == 3); + + // Cancel the repeating timer + TimerWheelThreadAdapter.cancel(lTimerHandle); + + ACE_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 + int iCallCount = 0; + CTestEventHandler* p_TestEventHandler = NULL; + 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_ASSERT(iCallCount == 3); + + delete p_TestEventHandler; + + ACE_DEBUG((LM_DEBUG, ACE_TEXT("%I(%t) Success in Multiple timers test.\n"))); + } + + ACE_END_TEST; + + return 0; +} diff --git a/ACE/tests/tests.mpc b/ACE/tests/tests.mpc index 8ee44a1a028..d2eaafb48f0 100644 --- a/ACE/tests/tests.mpc +++ b/ACE/tests/tests.mpc @@ -1393,6 +1393,13 @@ project(Thread Pool Test) : acetest { } } +project(Thread_Timer_Queue_Adapter_Test) : acetest { + exename = Thread_Timer_Queue_Adapter_Test + Source_Files { + Thread_Timer_Queue_Adapter_Test.cpp + } +} + project(Thread Creation Threshold Test) : acetest { exename = Thread_Creation_Threshold_Test Source_Files { |