summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ACE/ChangeLog25
-rw-r--r--ACE/ace/High_Res_Timer.cpp163
-rw-r--r--ACE/ace/High_Res_Timer.h54
-rw-r--r--ACE/ace/High_Res_Timer.inl65
-rw-r--r--ACE/ace/Timer_Queue_Adapters.cpp76
-rw-r--r--ACE/ace/Timer_Queue_Adapters.h8
-rw-r--r--ACE/ace/Timer_Queue_Adapters.inl12
-rw-r--r--ACE/tests/Thread_Timer_Queue_Adapter_Test.cpp297
-rw-r--r--ACE/tests/tests.mpc7
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 {