Coverage Report

Created: 2025-10-12 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/rutil/Time.hxx
Line
Count
Source
1
#if !defined(RESIP_TIME_HXX)
2
#define RESIP_TIME_HXX
3
4
#include "rutil/Mutex.hxx"
5
#include <limits.h>
6
#include "rutil/ResipAssert.h"
7
8
namespace resip
9
{
10
11
void sleepMs(unsigned int ms);
12
void sleepSeconds(unsigned int seconds);
13
14
/** Clock used for timing in the Timer class and possibly other areas.  Depending on the OS and compile settings this clock
15
    may not be monotonic.  Define _RESIP_MONOTONIC_CLOCK to enable monotonic timers.
16
    The precision of this clock is available in microseconds, but the accuracy depends on other factors such as the OS and hardware.
17
    The time values returned by this class should be considered independent of any other clock time, 
18
    including the system time (ie OS date/time,uptime,epoch,etc).
19
20
    OS Specific notes:
21
22
    <b>Windows</b>
23
    
24
    When _RESIP_MONOTONIC_CLOCK is defined, timeGetTime() is currently used as the underyling time source.  
25
    The default resolution/accuracy of this timer on windows is usually the same as the system time clock.  
26
    To query resolution information use ResipClock::queryTimerInfo().  timeBeginPeriod() can be used to increase 
27
    the resolution of the timer and allow for up to 1ms accuracy.  This will improve the accuracy of SIP related
28
    timers governed by resip::Timer, but also has other OS wide implications, please refer to Microsoft's
29
    documenation on timeBeginPeriod() for more information.
30
31
    When _RESIP_MONOTONIC_CLOCK is not defined, ::GetSystemTime is used as the underlying time source.  This
32
    value can jump forward or backward (not monotonic) if the OS system time is adjusted.  The default 
33
    resolution of this timer is the current system clock interrupt time and cannot be set to a higher resolution.
34
    The resolution has been observed at approx 15ms on XP and 1ms on Vista.
35
   
36
   <b>POSIX</b>
37
38
    When _RESIP_MONOTONIC_CLOCK is defined, clock_gettime() is used with the CLOCK_MONOTONIC clock.
39
40
    When _RESIP_MONOTONIC_CLOCK is not defined, gettimeofday() is used as the underyling clock.
41
42
   <b>OS X</b>
43
44
    A monotonic clock is currently not implemented for OS X.  There appear to be a couple of choices.
45
      http://www.wand.net.nz/~smr26/wordpress/2009/01/19/monotonic-time-in-mac-os-x/
46
      http://www.meandmark.com/timing.pdf
47
      http://developer.apple.com/qa/qa2004/qa1398.html
48
49
50
51
    @see resiprocate.org devlist discussion "Timers: why system time?";
52
 */
53
class ResipClock
54
{
55
   public:
56
      ResipClock(void);
57
      ~ResipClock(void);
58
59
      /** Returns the current clock time in microseconds.
60
      */
61
      static uint64_t getTimeMicroSec()
62
9.16k
      {
63
9.16k
         return getSystemTime();
64
9.16k
      }
65
66
67
      /** Returns the current clock time in milliseconds.
68
      */
69
      static uint64_t getTimeMs()
70
0
      {
71
0
         return getSystemTime()/1000LL;
72
0
      }
73
74
      /** Returns the current clock time in seconds.
75
      */
76
      static uint64_t getTimeSecs()
77
0
      {
78
0
         return getSystemTime()/1000000LL;
79
0
      }
80
81
      /** Returns an absolute time in ms that is between 50% and 90% of
82
          passed in ms from now.
83
      */
84
      static uint64_t getRandomFutureTimeMs( uint64_t futureMs );
85
      /** Infinit time in future.
86
      */
87
      static uint64_t getForever();
88
89
      /** Some monotonic clock implementations may internally only return 32-bit values that will wrap.
90
        * @see Timer::getMaxSystemTimeWaitMs()
91
      */
92
      static unsigned getMaxSystemTimeWaitMs(void)
93
0
      {
94
0
         return mMaxSystemTimeWaitMs;
95
0
      }     
96
97
      /** Gets the current clock's minimum, maximum and current/actual timer resolution and returns if the
98
          clock is known to be monotonic.
99
          If min, max or actual return 0 then that information is not available.
100
          min max and actual are in units of microseconds.
101
        */
102
      static void queryTimerInfo(unsigned &minRes, unsigned &maxRes, unsigned &actualRes, bool &isMonotonic);
103
104
   private:
105
      /** Returns the current clock time in microseconds.  Does not guarantee that this is related to the actual
106
        * OS system time (eg epoch or other time).
107
        */
108
      static uint64_t getSystemTime();
109
110
      static unsigned mMaxSystemTimeWaitMs;
111
112
#ifdef WIN32
113
   private:
114
      /** Responsible for returning a 64-bit monotonic clock value for timing.  Currently implemented using
115
        * timeGetTime. Precision of this class is milliseconds,
116
        * accuracy is dependent on the windows timer resolution. Use timeBeginPeriod() to increase the resolution.
117
        */
118
      class WinMonoClock
119
      {
120
         public:
121
            WinMonoClock();        
122
123
            /** Returns a monotonic clock value in milliseconds.  Currently this is the system uptime as reported
124
              * by timeGetTime.
125
              */
126
            static uint64_t GetClock64(void)
127
            {
128
               return mGTC64();
129
            }                     
130
131
         private:
132
133
            static void Initialize(void);
134
            /** Definition of a function that has no parameters and returns a 64-bit unsigned integer.
135
            */
136
            typedef uint64_t (*PGTC64)(void);
137
138
            /** Get Tick Count wrapper for 32-bit version of ::timeGetTime that is nearly lockless and handles 32-bit wraparound.
139
              * _InterlockedExchange64 is used, which requires the CMPXCHG8B instruction.  This instruction is found
140
              * on pentium and later intel processors and K5 and later AMD processors.
141
            */
142
            class GTCInterlocked
143
            {
144
               public:
145
146
                  static uint64_t GTC64(void);
147
148
                  /** The maximum time that can elapse when using this class as the timer for resip stack processing.
149
                    @see resip::SipStack::getTimeTillNextProcessMS().
150
                  */
151
                  static uint32_t GetMaxWaitMs(void)
152
                  {
153
                     //Since the base time isn't updated on every call, need to ensure that it's updated once every 49.7 days.
154
                     //The base time will lag behind the current tick count, which means the lag time must be used
155
                     //to determine the max wait.
156
                     //Also need to add a cushion to this calculaton because ::timeGetTime may not be accurate to 1ms.
157
                     __int64 maxWait = (__int64)UINT_MAX - mBaseTimeUpdateInterval - mBaseTimeCushion;
158
                     if (maxWait <= 0)
159
                     {
160
                        resip_assert(0);
161
                        const_cast<uint32_t &>(mBaseTimeUpdateInterval) = 60000;
162
                        const_cast<uint32_t &>(mBaseTimeCushion) = 120000;
163
                        return UINT_MAX - mBaseTimeUpdateInterval - mBaseTimeCushion;
164
                     }
165
                     return static_cast<uint32_t>(maxWait);
166
                  }
167
168
               private:
169
                  /** Last stored time. Using InterlockedExchange (CMPXCHG8B) the alignment is not necessary, but it shouldn't hurt.
170
                      Align it on a cache line since it is rarely written and read often (to avoid false-sharing).
171
                  */
172
                  static _declspec(align(128)) volatile uint64_t mBaseTime;
173
                  /** Max elapsed time since last GTC64 call, in milliseconds, before writing mBaseTime.
174
                      Cannot exceed UINT_MAX - mBaseTimeCushion.
175
                  */
176
                  static const uint32_t mBaseTimeUpdateInterval = 60000;
177
                  static const uint32_t mBaseTimeCushion = 120000; //!< large cushion to be cautious
178
            };
179
180
            /** Get Tick Count wrapper for 32-bit version of ::timeGetTime that minimizes locking and handles 32-bit wraparound.
181
              * Issues a mutex lock only during a 2 minute window around the 49.7 day threshold.  The lock is issued for each call to
182
              * GTC64 during this window and durinng this window only.
183
              * Requires SipStack::getTimeTillNextProcessMS() to not return a value greater than 2 minutes.
184
            */
185
            class GTCLockDuringRange
186
            {
187
               public:
188
189
                  static uint64_t GTC64(void);
190
191
                  static uint32_t GetMaxWaitMs(void)
192
                  {
193
                     return 120000;
194
                  }
195
196
               private:
197
                  /** timeGetTime() returns DWORD - ms since system start
198
                    Therefore, the time will wrap around to zero if the system is run continuously for 49.7 days
199
                   if timer is called reasonable often we may manage wrap around by counter below
200
                   */
201
                  static uint32_t mWrapCounter;
202
203
                  /** Last obtained tick to detect the need to increment mWrapCounter
204
                  */
205
                  static DWORD mPrevTick;
206
207
                  /** we have to made it thread safe
208
                  */
209
                  static Mutex mWrapCounterMutex;
210
211
            };
212
213
            /** Get Tick Count wrapper for 32-bit version of ::timeGetTime that locks on a mutex on every call to GTC64()
214
                to safely handle 32-bit wraparound.
215
            */
216
            class GTCLock
217
            {
218
               public:
219
                  static uint64_t GTC64(void);
220
221
               private:
222
                  static ULARGE_INTEGER mBaseTime;
223
224
                  /** Primary lock that is executed on each call to GTC64().
225
                  */
226
                  static Mutex mMutex;
227
            };
228
229
            static PGTC64 mGTC64;
230
      };
231
#endif
232
};
233
234
235
}//namespace resip
236
237
#endif
238
/* ====================================================================
239
 * The Vovida Software License, Version 1.0
240
 *
241
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
242
 *
243
 * Redistribution and use in source and binary forms, with or without
244
 * modification, are permitted provided that the following conditions
245
 * are met:
246
 *
247
 * 1. Redistributions of source code must retain the above copyright
248
 *    notice, this list of conditions and the following disclaimer.
249
 *
250
 * 2. Redistributions in binary form must reproduce the above copyright
251
 *    notice, this list of conditions and the following disclaimer in
252
 *    the documentation and/or other materials provided with the
253
 *    distribution.
254
 *
255
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
256
 *    and "Vovida Open Communication Application Library (VOCAL)" must
257
 *    not be used to endorse or promote products derived from this
258
 *    software without prior written permission. For written
259
 *    permission, please contact vocal@vovida.org.
260
 *
261
 * 4. Products derived from this software may not be called "VOCAL", nor
262
 *    may "VOCAL" appear in their name, without prior written
263
 *    permission of Vovida Networks, Inc.
264
 *
265
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
266
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
267
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
268
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
269
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
270
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
271
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
272
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
273
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
274
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
276
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
277
 * DAMAGE.
278
 *
279
 * ====================================================================
280
 *
281
 * This software consists of voluntary contributions made by Vovida
282
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
283
 * Inc.  For more information on Vovida Networks, Inc., please see
284
 * <http://www.vovida.org/>.
285
 *
286
 * vi: set shiftwidth=3 expandtab:
287
 */