diff options
Diffstat (limited to 'ACE/ace/Time_Value.cpp')
-rw-r--r-- | ACE/ace/Time_Value.cpp | 258 |
1 files changed, 171 insertions, 87 deletions
diff --git a/ACE/ace/Time_Value.cpp b/ACE/ace/Time_Value.cpp index 33ebdd8fa7f..0d582c18d95 100644 --- a/ACE/ace/Time_Value.cpp +++ b/ACE/ace/Time_Value.cpp @@ -1,9 +1,6 @@ -#include "ace/Time_Value.h" - -ACE_RCSID (ace, - Time_Value, - "$Id$") +// $Id$ +#include "ace/Time_Value.h" #if !defined (__ACE_INLINE__) #include "ace/Time_Value.inl" @@ -11,28 +8,33 @@ ACE_RCSID (ace, #include "ace/Numeric_Limits.h" #include "ace/If_Then_Else.h" +#include "ace/OS_NS_math.h" + +#ifdef ACE_HAS_CPP98_IOSTREAMS +#include <ostream> +#include <iomanip> +#endif /* ACE_HAS_CPP98_IOSTREAMS */ ACE_BEGIN_VERSIONED_NAMESPACE_DECL -// Static constant representing `zero-time'. -// Note: this object requires static construction. +/// Static constant representing `zero-time'. +/// Note: this object requires static construction. const ACE_Time_Value ACE_Time_Value::zero; -// Constant for maximum time representable. Note that this time -// is not intended for use with select () or other calls that may -// have *their own* implementation-specific maximum time representations. -// Its primary use is in time computations such as those used by the -// dynamic subpriority strategies in the ACE_Dynamic_Message_Queue class. -// Note: this object requires static construction. +/// Constant for maximum time representable. Note that this time +/// is not intended for use with select () or other calls that may +/// have *their own* implementation-specific maximum time representations. +/// Its primary use is in time computations such as those used by the +/// dynamic subpriority strategies in the ACE_Dynamic_Message_Queue class. +/// Note: this object requires static construction. const ACE_Time_Value ACE_Time_Value::max_time ( ACE_Numeric_Limits<time_t>::max (), ACE_ONE_SECOND_IN_USECS - 1); ACE_ALLOC_HOOK_DEFINE (ACE_Time_Value) -// Increment microseconds (the only reason this is here is to allow -// the use of ACE_Atomic_Op with ACE_Time_Value). - +/// Increment microseconds (the only reason this is here is to allow +/// the use of ACE_Atomic_Op with ACE_Time_Value). ACE_Time_Value ACE_Time_Value::operator ++ (int) { @@ -51,9 +53,8 @@ ACE_Time_Value::operator ++ (void) return *this; } -// Decrement microseconds (the only reason this is here is / to allow -// the use of ACE_Atomic_Op with ACE_Time_Value). - +/// Decrement microseconds (the only reason this is here is / to allow +/// the use of ACE_Atomic_Op with ACE_Time_Value). ACE_Time_Value ACE_Time_Value::operator -- (int) { @@ -73,13 +74,13 @@ ACE_Time_Value::operator -- (void) } #if defined (ACE_WIN32) -// Static constant to remove time skew between FILETIME and POSIX -// time. POSIX and Win32 use different epochs (Jan. 1, 1970 v.s. -// Jan. 1, 1601). The following constant defines the difference -// in 100ns ticks. -// -// In the beginning (Jan. 1, 1601), there was no time and no computer. -// And Bill said: "Let there be time," and there was time.... +/// Static constant to remove time skew between FILETIME and POSIX +/// time. POSIX and Win32 use different epochs (Jan. 1, 1970 v.s. +/// Jan. 1, 1601). The following constant defines the difference +/// in 100ns ticks. +/// +/// In the beginning (Jan. 1, 1601), there was no time and no computer. +/// And Bill said: "Let there be time," and there was time.... # if defined (ACE_LACKS_LONGLONG_T) const ACE_U_LongLong ACE_Time_Value::FILETIME_to_timval_skew = ACE_U_LongLong (0xd53e8000, 0x19db1de); @@ -88,8 +89,7 @@ const DWORDLONG ACE_Time_Value::FILETIME_to_timval_skew = ACE_INT64_LITERAL (0x19db1ded53e8000); # endif -// Initializes the ACE_Time_Value object from a Win32 FILETIME - +/// Initializes the ACE_Time_Value object from a Win32 FILETIME ACE_Time_Value::ACE_Time_Value (const FILETIME &file_time) { // // ACE_OS_TRACE ("ACE_Time_Value::ACE_Time_Value"); @@ -103,7 +103,7 @@ void ACE_Time_Value::set (const FILETIME &file_time) ACE_U_LongLong LL_100ns(file_time.dwLowDateTime, file_time.dwHighDateTime); LL_100ns -= ACE_Time_Value::FILETIME_to_timval_skew; // Convert 100ns units to seconds; - this->tv_.tv_sec = (long) (LL_100ns / ((double) (10000 * 1000))); + this->tv_.tv_sec = (time_t) (LL_100ns / ((double) (10000 * 1000))); // Convert remainder to microseconds; this->tv_.tv_usec = (suseconds_t)((LL_100ns % ((ACE_UINT32)(10000 * 1000))) / 10); #else @@ -115,15 +115,14 @@ void ACE_Time_Value::set (const FILETIME &file_time) _100ns.QuadPart -= ACE_Time_Value::FILETIME_to_timval_skew; // Convert 100ns units to seconds; - this->tv_.tv_sec = (long) (_100ns.QuadPart / (10000 * 1000)); + this->tv_.tv_sec = (time_t) (_100ns.QuadPart / (10000 * 1000)); // Convert remainder to microseconds; this->tv_.tv_usec = (suseconds_t) ((_100ns.QuadPart % (10000 * 1000)) / 10); #endif // ACE_LACKS_LONGLONG_T this->normalize (); } -// Returns the value of the object as a Win32 FILETIME. - +/// Returns the value of the object as a Win32 FILETIME. ACE_Time_Value::operator FILETIME () const { FILETIME file_time; @@ -155,19 +154,10 @@ ACE_Time_Value::operator FILETIME () const void ACE_Time_Value::dump (void) const { -#if defined (ACE_HAS_DUMP) - // ACE_OS_TRACE ("ACE_Time_Value::dump"); -#if 0 - ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntv_sec_ = %d"), this->tv_.tv_sec)); - ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntv_usec_ = %d\n"), this->tv_.tv_usec)); - ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); -#endif /* 0 */ -#endif /* ACE_HAS_DUMP */ } void -ACE_Time_Value::normalize (void) +ACE_Time_Value::normalize (bool saturate) { // // ACE_OS_TRACE ("ACE_Time_Value::normalize"); // From Hans Rohnert... @@ -176,23 +166,45 @@ ACE_Time_Value::normalize (void) { /*! \todo This loop needs some optimization. */ - do - { - ++this->tv_.tv_sec; - this->tv_.tv_usec -= ACE_ONE_SECOND_IN_USECS; - } - while (this->tv_.tv_usec >= ACE_ONE_SECOND_IN_USECS); + if (!saturate) // keep the conditionnal expression outside the while loop to minimize performance cost + do + { + ++this->tv_.tv_sec; + this->tv_.tv_usec -= ACE_ONE_SECOND_IN_USECS; + } + while (this->tv_.tv_usec >= ACE_ONE_SECOND_IN_USECS); + else + do + if (this->tv_.tv_sec < ACE_Numeric_Limits<time_t>::max()) + { + ++this->tv_.tv_sec; + this->tv_.tv_usec -= ACE_ONE_SECOND_IN_USECS; + } + else + this->tv_.tv_usec = ACE_ONE_SECOND_IN_USECS - 1; + while (this->tv_.tv_usec >= ACE_ONE_SECOND_IN_USECS); } else if (this->tv_.tv_usec <= -ACE_ONE_SECOND_IN_USECS) { /*! \todo This loop needs some optimization. */ - do - { - --this->tv_.tv_sec; - this->tv_.tv_usec += ACE_ONE_SECOND_IN_USECS; - } - while (this->tv_.tv_usec <= -ACE_ONE_SECOND_IN_USECS); + if (!saturate) + do + { + --this->tv_.tv_sec; + this->tv_.tv_usec += ACE_ONE_SECOND_IN_USECS; + } + while (this->tv_.tv_usec <= -ACE_ONE_SECOND_IN_USECS); + else + do + if (this->tv_.tv_sec > ACE_Numeric_Limits<time_t>::min()) + { + --this->tv_.tv_sec; + this->tv_.tv_usec += ACE_ONE_SECOND_IN_USECS; + } + else + this->tv_.tv_usec = -ACE_ONE_SECOND_IN_USECS + 1; + while (this->tv_.tv_usec <= -ACE_ONE_SECOND_IN_USECS); } if (this->tv_.tv_sec >= 1 && this->tv_.tv_usec < 0) @@ -200,65 +212,137 @@ ACE_Time_Value::normalize (void) --this->tv_.tv_sec; this->tv_.tv_usec += ACE_ONE_SECOND_IN_USECS; } -// tv_sec in qnxnto is unsigned -#if !defined ( __QNXNTO__) + // tv_sec in qnxnto is unsigned +#if !defined ( __QNX__) else if (this->tv_.tv_sec < 0 && this->tv_.tv_usec > 0) { ++this->tv_.tv_sec; this->tv_.tv_usec -= ACE_ONE_SECOND_IN_USECS; } -#endif /* __QNXNTO__ */ +#endif /* __QNX__ */ } ACE_Time_Value & ACE_Time_Value::operator *= (double d) { - // The floating type to be used in the computations. It should be - // large enough to hold a time_t. We actually want a floating type - // with enough digits in its mantissa to hold a time_t without - // losing precision. For example, if FLT_RADIX is 2 and - // LDBL_MANT_DIG is 64, a long double has a 64 bit wide mantissa, - // which would be sufficient to hold a 64 bit time_t value without - // losing precision. + // To work around the lack of precision of a long double to contain + // a 64-bits time_t + 6 digits after the decimal point for the usec part, + // we perform the multiplication of the 2 timeval parts separately. + // + // This extra precision step is adding a cost when transfering the + // seconds resulting from the usec multiplication. This operation + // correspond to the normalization process performed in normalize() + // but we must absolutly do it here because the usec multiplication + // result value could exceed what can be stored in a suseconds_t + // type variable. // - // For now we'll simply go with long double if it is larger than - // time_t. We're hosed if long double isn't large enough. + // Since this is a costly operation, we try to detect as soon as + // possible if we are having a saturation in order to abort the rest + // of the computation. typedef ACE::If_Then_Else<(sizeof (double) > sizeof (time_t)), - double, - long double>::result_type float_type; + double, + long double>::result_type float_type; - float_type time_total = - (this->sec () - + static_cast<float_type> (this->usec ()) / ACE_ONE_SECOND_IN_USECS) * d; + float_type sec_total = static_cast<float_type> (this->sec()); + sec_total *= d; // shall we saturate the result? static const float_type max_int = - ACE_Numeric_Limits<time_t>::max () + 0.999999; + ACE_Numeric_Limits<time_t>::max() + 0.999999; static const float_type min_int = - ACE_Numeric_Limits<time_t>::min () - 0.999999; + ACE_Numeric_Limits<time_t>::min() - 0.999999; - if (time_total > max_int) - time_total = max_int; - if (time_total < min_int) - time_total = min_int; + if (sec_total > max_int) + { + this->set(ACE_Numeric_Limits<time_t>::max(), ACE_ONE_SECOND_IN_USECS-1); + } + else if (sec_total < min_int) + { + this->set(ACE_Numeric_Limits<time_t>::min(), -ACE_ONE_SECOND_IN_USECS+1); + } + else + { + time_t time_sec = static_cast<time_t> (sec_total); - const time_t time_sec = static_cast<time_t> (time_total); + float_type usec_total = this->usec(); + usec_total *= d; - time_total -= time_sec; - time_total *= ACE_ONE_SECOND_IN_USECS; + // adding usec resulting from tv_sec mult + usec_total += (sec_total-time_sec) * ACE_ONE_SECOND_IN_USECS; - suseconds_t time_usec = static_cast<suseconds_t> (time_total); + // extract seconds component of the usec mult + sec_total = usec_total / ACE_ONE_SECOND_IN_USECS; + // keep remaining usec + if (sec_total > 0) + { + usec_total = (sec_total - ACE_OS::floor(sec_total)); + } + else + { + usec_total = (sec_total - ACE_OS::ceil(sec_total)); + } - // round up the result to save the last usec - if (time_usec > 0 && (time_total - time_usec) >= 0.5) - ++time_usec; - else if (time_usec < 0 && (time_total - time_usec) <= -0.5) - --time_usec; + sec_total -= usec_total; + usec_total *= ACE_ONE_SECOND_IN_USECS; - this->set (time_sec, time_usec); + // add the seconds component of the usec mult with the tv_sec mult prod. + sec_total += time_sec; + // recheck for saturation + if (sec_total > max_int) + { + this->set (ACE_Numeric_Limits<time_t>::max(), ACE_ONE_SECOND_IN_USECS - 1); + } + else if (sec_total < min_int) + { + this->set (ACE_Numeric_Limits<time_t>::min(), -ACE_ONE_SECOND_IN_USECS + 1); + } + else + { + time_sec = static_cast<time_t> (sec_total); + suseconds_t time_usec = static_cast<suseconds_t> (usec_total); + + // round up the result to save the last usec + if (time_usec > 0 && (usec_total - time_usec) >= 0.5) + { + ++time_usec; + } + else if (time_usec < 0 && (usec_total - time_usec) <= -0.5) + { + --time_usec; + } + + this->set (time_sec, time_usec); + } + } return *this; } +#ifdef ACE_HAS_CPP98_IOSTREAMS +ostream &operator<<(ostream &o, const ACE_Time_Value &v) +{ + char oldFiller = o.fill (); + o.fill ('0'); + const timeval *tv = v; + if (tv->tv_sec) + { + o << tv->tv_sec; + if (tv->tv_usec) + o << '.' << std::setw (6) << ACE_STD_NAMESPACE::abs (tv->tv_usec); + } + else if (tv->tv_usec < 0) + o << "-0." << std::setw (6) << - tv->tv_usec; + else + { + o << '0'; + if (tv->tv_usec > 0) + o << '.'<< std::setw (6) << tv->tv_usec; + } + + o.fill (oldFiller); + return o; +} +#endif /* ACE_HAS_CPP98_IOSTREAMS */ + ACE_END_VERSIONED_NAMESPACE_DECL |