Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
11 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: qwiktime.cpp
  5. //
  6. // Description: Implementation of CAQQuickTime class
  7. //
  8. // Author: Mike Swafford (MikeSwa)
  9. //
  10. // History:
  11. // 7/9/98 - MikeSwa Created
  12. //
  13. // Copyright (C) 1998 Microsoft Corporation
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "aqprecmp.h"
  17. #include "qwiktime.h"
  18. //The basic premise is to use GetTickCount to get a reasonable accurate
  19. //time information in a DWORD. GetTickCount is only valid for 50 days, and
  20. //has an accuracy of 1 ms. 50 days is just not long enough.
  21. //MSchofie was kind enough to prepare the following table:
  22. //Bit shift Resolution (seconds) Uptime(years)
  23. //3 0.008 1.088824217
  24. //4 0.016 2.177648434
  25. //5 0.032 4.355296868
  26. //6 0.064 8.710593736
  27. //7 0.128 17.42118747
  28. //8 0.256 34.84237495
  29. //9 0.512 69.68474989
  30. //10 1.024 139.3694998
  31. //11 2.048 278.7389996
  32. //12 4.096 557.4779991
  33. //13 8.192 1114.955998
  34. //14 16.384 2229.911997
  35. //15 32.768 4459.823993
  36. //16 65.536 8919.647986
  37. //The initial implementation used 16 bits, which had an error of about 66
  38. //seconds, which drove our poor Y2K tester nuts. 8 bits (34 years uptime)
  39. //seems much more reasonable.
  40. //The system tick is shifted right INTERNAL_TIME_TICK_BITS and stored in
  41. //the least significant INTERNAL_TIME_TICK_BITS bits of the internal time.
  42. //The upper 32-INTERNAL_TIME_TICK_BITS bits
  43. //is used to count the number of times the count rolls over
  44. #define INTERNAL_TIME_TICK_BITS 8
  45. #define INTERNAL_TIME_TICK_MASK 0x00FFFFFF
  46. //Number where tick count has wrapped
  47. const LONGLONG INTERNAL_TIME_TICK_ROLLOVER_COUNT
  48. = (1 << (32-INTERNAL_TIME_TICK_BITS));
  49. const LONGLONG TICKS_PER_INTERNAL_TIME = (1 << INTERNAL_TIME_TICK_BITS);
  50. //conversion constants
  51. //There are 10^6 milliseconds per nanosecond (FILETIME is in 100 nanosecond counts)
  52. const LONGLONG FILETIMES_PER_TICK = 10000;
  53. const LONGLONG FILETIMES_PER_INTERNAL_TIME = (FILETIMES_PER_TICK*TICKS_PER_INTERNAL_TIME);
  54. const LONGLONG FILETIMES_PER_MINUTE = (FILETIMES_PER_TICK*1000*60);
  55. //---[ CAQQuickTime::CAQQuickTime ]--------------------------------------------
  56. //
  57. //
  58. // Description:
  59. // Default Constructor for CAQQuickTime. Will call GetSystemTime once to
  60. // get start up time... GetTickCount is used for all other calls.
  61. // Parameters:
  62. // -
  63. // Returns:
  64. //
  65. // History:
  66. // 7/9/98 - MikeSwa Created
  67. //
  68. //-----------------------------------------------------------------------------
  69. CAQQuickTime::CAQQuickTime()
  70. {
  71. DWORD dwTickCount = GetTickCount();
  72. LARGE_INTEGER *pLargeIntSystemStart = (LARGE_INTEGER *) &m_ftSystemStart;
  73. m_dwSignature = QUICK_TIME_SIG;
  74. //Get internal time and start file time
  75. GetSystemTimeAsFileTime(&m_ftSystemStart);
  76. //convert tick count to internal time
  77. m_dwLastInternalTime = dwTickCount >> INTERNAL_TIME_TICK_BITS;
  78. //adjust start time so that it is the time when the tick count was zero
  79. pLargeIntSystemStart->QuadPart -= (LONGLONG) dwTickCount * FILETIMES_PER_TICK;
  80. //Some asserts to validate constants
  81. _ASSERT(!(INTERNAL_TIME_TICK_ROLLOVER_COUNT & INTERNAL_TIME_TICK_MASK));
  82. _ASSERT((INTERNAL_TIME_TICK_ROLLOVER_COUNT >> 1) & INTERNAL_TIME_TICK_MASK);
  83. }
  84. //---[ CAQQuickTime::dwGetInternalTime ]---------------------------------------
  85. //
  86. //
  87. // Description:
  88. // Gets internal time using GetTickCount... and makes sure that when
  89. // GetTickCount wraps, the correct time is returned.
  90. // Parameters:
  91. // -
  92. // Returns:
  93. // DWORD internal time
  94. // History:
  95. // 7/9/98 - MikeSwa Created
  96. //
  97. //-----------------------------------------------------------------------------
  98. DWORD CAQQuickTime::dwGetInternalTime()
  99. {
  100. DWORD dwCurrentTick = GetTickCount();
  101. DWORD dwLastInternalTime = m_dwLastInternalTime;
  102. DWORD dwCurrentInternalTime;
  103. DWORD dwCheck;
  104. dwCurrentInternalTime = dwCurrentTick >> INTERNAL_TIME_TICK_BITS;
  105. _ASSERT(dwCurrentInternalTime == (INTERNAL_TIME_TICK_MASK & dwCurrentInternalTime));
  106. //see if rolled over our tick count
  107. while ((dwLastInternalTime & INTERNAL_TIME_TICK_MASK) > dwCurrentInternalTime)
  108. {
  109. dwLastInternalTime = m_dwLastInternalTime;
  110. //it is possible that we have rolled over the tick count
  111. //first make sure it is not just a thread-timing issue
  112. dwCurrentTick = GetTickCount();
  113. dwCurrentInternalTime = dwCurrentTick >> INTERNAL_TIME_TICK_BITS;
  114. if ((dwLastInternalTime & INTERNAL_TIME_TICK_MASK) > dwCurrentInternalTime)
  115. {
  116. dwCurrentInternalTime |= (~INTERNAL_TIME_TICK_MASK & dwLastInternalTime);
  117. dwCurrentInternalTime += INTERNAL_TIME_TICK_ROLLOVER_COUNT;
  118. //attempt interlocked exchange to update internal last internal time
  119. dwCheck = (DWORD) InterlockedCompareExchange((PLONG) &m_dwLastInternalTime,
  120. (LONG) dwCurrentInternalTime,
  121. (LONG) dwLastInternalTime);
  122. if (dwCheck == dwLastInternalTime) //exchange worked
  123. goto Exit;
  124. }
  125. }
  126. _ASSERT(dwCurrentInternalTime == (INTERNAL_TIME_TICK_MASK & dwCurrentInternalTime));
  127. dwCurrentInternalTime |= (~INTERNAL_TIME_TICK_MASK & m_dwLastInternalTime);
  128. Exit:
  129. return dwCurrentInternalTime;
  130. }
  131. //---[ CAQQuickTime::GetExpireTime ]-------------------------------------------
  132. //
  133. //
  134. // Description:
  135. // Get the expriation time for cMinutesExpireTime from now.
  136. // Parameters:
  137. // IN cMinutesExpireTime # of minutes in future to set time
  138. // IN OUT pftExpireTime Filetime to store new expire time
  139. // IN OUT pdwExpireContext If non-zero will use the same tick count
  140. // as previous calls (saves call to GetTickCount)
  141. // Returns:
  142. //
  143. // History:
  144. // 7/10/98 - MikeSwa Created
  145. //
  146. //-----------------------------------------------------------------------------
  147. void CAQQuickTime::GetExpireTime(
  148. IN DWORD cMinutesExpireTime,
  149. IN OUT FILETIME *pftExpireTime,
  150. IN OUT DWORD *pdwExpireContext)
  151. {
  152. TraceFunctEnterEx((LPARAM) this, "CAQQuickTime::GetExpireTime");
  153. _ASSERT(pftExpireTime);
  154. DWORD dwInternalTime = 0;
  155. LARGE_INTEGER *pLargeIntTime = (LARGE_INTEGER *) pftExpireTime;
  156. if (pdwExpireContext)
  157. dwInternalTime = *pdwExpireContext;
  158. if (!dwInternalTime)
  159. {
  160. dwInternalTime = dwGetInternalTime();
  161. //save internal time as context
  162. if (pdwExpireContext)
  163. *pdwExpireContext = dwInternalTime;
  164. }
  165. memcpy(pftExpireTime, &m_ftSystemStart, sizeof(FILETIME));
  166. //set to current time
  167. pLargeIntTime->QuadPart += (LONGLONG) dwInternalTime * FILETIMES_PER_INTERNAL_TIME;
  168. //set cMinutesExpireTime into the future
  169. pLargeIntTime->QuadPart += (LONGLONG) cMinutesExpireTime * FILETIMES_PER_MINUTE;
  170. DebugTrace((LPARAM) this, "INFO: Creating file time for %d minutes of 0x%08X %08X",
  171. cMinutesExpireTime, pLargeIntTime->HighPart, pLargeIntTime->LowPart);
  172. TraceFunctLeave();
  173. }
  174. //---[ CAQQuickTime::GetExpireTime ]-------------------------------------------
  175. //
  176. //
  177. // Description:
  178. // Get the expriation time for cMinutesExpireTime from ftStartTime
  179. // Parameters:
  180. // IN cMinutesExpireTime # of minutes in future to set time
  181. // IN OUT pftExpireTime Filetime to store new expire time
  182. // IN ftStartTime Time to add expire minutes to
  183. // Returns:
  184. //
  185. // History:
  186. // 5/16/2001 - dbraun created from GetExpireTime above
  187. //
  188. //-----------------------------------------------------------------------------
  189. void CAQQuickTime::GetExpireTime(
  190. IN FILETIME ftStartTime,
  191. IN DWORD cMinutesExpireTime,
  192. IN OUT FILETIME *pftExpireTime)
  193. {
  194. TraceFunctEnterEx((LPARAM) this, "CAQQuickTime::GetExpireTime");
  195. _ASSERT(pftExpireTime);
  196. LARGE_INTEGER *pLargeIntTime = (LARGE_INTEGER *) pftExpireTime;
  197. // Set to start time
  198. memcpy(pftExpireTime, &ftStartTime, sizeof(FILETIME));
  199. //set cMinutesExpireTime into the future
  200. pLargeIntTime->QuadPart += (LONGLONG) cMinutesExpireTime * FILETIMES_PER_MINUTE;
  201. DebugTrace((LPARAM) this, "INFO: Creating file time for %d minutes of 0x%08X %08X",
  202. cMinutesExpireTime, pLargeIntTime->HighPart, pLargeIntTime->LowPart);
  203. TraceFunctLeave();
  204. }
  205. //---[ CAQQuickTime::fInPast ]-------------------------------------------------
  206. //
  207. //
  208. // Description:
  209. // Determines if a given file time has already happened
  210. // Parameters:
  211. // IN pftExpireTime FILETIME with expiration
  212. // IN OUT pdwExpireContext If non-zero will use the same tick count
  213. // as previous calls (saves call to GetTickCount)
  214. // Returns:
  215. // TRUE if expire time is in the past
  216. // FALSE if expire time is in the future
  217. // History:
  218. // 7/11/98 - MikeSwa Created
  219. // Note:
  220. // You should NOT use the same context used to get the filetime, because
  221. // it will always return FALSE
  222. //
  223. //-----------------------------------------------------------------------------
  224. BOOL CAQQuickTime::fInPast(IN FILETIME *pftExpireTime,
  225. IN OUT DWORD *pdwExpireContext)
  226. {
  227. _ASSERT(pftExpireTime);
  228. DWORD dwInternalTime = 0;
  229. FILETIME ftCurrentTime = m_ftSystemStart;
  230. LARGE_INTEGER *pLargeIntCurrentTime = (LARGE_INTEGER *) &ftCurrentTime;
  231. LARGE_INTEGER *pLargeIntExpireTime = (LARGE_INTEGER *) pftExpireTime;
  232. BOOL fInPast = FALSE;
  233. if (pdwExpireContext)
  234. dwInternalTime = *pdwExpireContext;
  235. if (!dwInternalTime)
  236. {
  237. dwInternalTime = dwGetInternalTime();
  238. //save internal time as context
  239. if (pdwExpireContext)
  240. *pdwExpireContext = dwInternalTime;
  241. }
  242. //Get current time
  243. pLargeIntCurrentTime->QuadPart += (LONGLONG) dwInternalTime * FILETIMES_PER_INTERNAL_TIME;
  244. if (pLargeIntCurrentTime->QuadPart > pLargeIntExpireTime->QuadPart)
  245. fInPast = TRUE;
  246. return fInPast;
  247. }