1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 Implementation of time related WIN API functions.
21 #include "pal/palinternal.h"
22 #include "pal/dbgmsg.h"
31 #if HAVE_MACH_ABSOLUTE_TIME
32 #include <mach/mach_time.h>
33 static mach_timebase_info_data_t s_TimebaseInfo;
36 using namespace CorUnix;
38 SET_DEFAULT_DEBUG_CHANNEL(MISC);
44 Initialize all Time-related stuff related
49 TRUE if Time support initialization succeeded
52 BOOL TIMEInitialize(void)
54 #if HAVE_MACH_ABSOLUTE_TIME
55 kern_return_t machRet;
56 if ((machRet = mach_timebase_info(&s_TimebaseInfo)) != KERN_SUCCESS)
58 ASSERT("mach_timebase_info() failed: %s\n", mach_error_string(machRet));
71 The GetSystemTime function retrieves the current system date and
72 time. The system time is expressed in Coordinated Universal Time
78 [out] Pointer to a SYSTEMTIME structure to receive the current system date and time.
82 This function does not return a value.
88 OUT LPSYSTEMTIME lpSystemTime)
93 #endif /* HAVE_GMTIME_R */
95 struct timeval timeval;
98 PERF_ENTRY(GetSystemTime);
99 ENTRY("GetSystemTime (lpSystemTime=%p)\n", lpSystemTime);
103 /* We can't get millisecond resolution from time(), so we get it from
105 timeofday_retval = gettimeofday(&timeval,NULL);
109 if (gmtime_r(&tt, utPtr) == NULL)
110 #else /* HAVE_GMTIME_R */
111 if ((utPtr = gmtime(&tt)) == NULL)
112 #endif /* HAVE_GMTIME_R */
114 ASSERT("gmtime() failed; errno is %d (%s)\n", errno, strerror(errno));
118 lpSystemTime->wYear = 1900 + utPtr->tm_year;
119 lpSystemTime->wMonth = utPtr->tm_mon + 1;
120 lpSystemTime->wDayOfWeek = utPtr->tm_wday;
121 lpSystemTime->wDay = utPtr->tm_mday;
122 lpSystemTime->wHour = utPtr->tm_hour;
123 lpSystemTime->wMinute = utPtr->tm_min;
124 lpSystemTime->wSecond = utPtr->tm_sec;
126 if(-1 == timeofday_retval)
128 ASSERT("gettimeofday() failed; errno is %d (%s)\n",
129 errno, strerror(errno));
130 lpSystemTime->wMilliseconds = 0;
137 lpSystemTime->wMilliseconds = timeval.tv_usec/tccMillieSecondsToMicroSeconds;
139 old_seconds = utPtr->tm_sec;
140 new_seconds = timeval.tv_sec%60;
142 /* just in case we reached the next second in the interval between
143 time() and gettimeofday() */
144 if( old_seconds!=new_seconds )
146 TRACE("crossed seconds boundary; setting milliseconds to 999\n");
147 lpSystemTime->wMilliseconds = 999;
151 LOGEXIT("GetSystemTime returns void\n");
152 PERF_EXIT(GetSystemTime);
159 The GetTickCount function retrieves the number of milliseconds that
160 have elapsed since the system was started. It is limited to the
161 resolution of the system timer. To obtain the system timer resolution,
162 use the GetSystemTimeAdjustment function.
166 This function has no parameters.
170 The return value is the number of milliseconds that have elapsed since
171 the system was started.
173 In the ROTOR implementation the return value is the elapsed time since
174 the start of the epoch.
183 PERF_ENTRY(GetTickCount);
184 ENTRY("GetTickCount ()\n");
186 // Get the 64-bit count from GetTickCount64 and truncate the results.
187 retval = (DWORD) GetTickCount64();
189 LOGEXIT("GetTickCount returns DWORD %u\n", retval);
190 PERF_EXIT(GetTickCount);
196 QueryPerformanceCounter(
197 OUT LARGE_INTEGER *lpPerformanceCount
202 PERF_ENTRY(QueryPerformanceCounter);
203 ENTRY("QueryPerformanceCounter()\n");
205 #if HAVE_MACH_ABSOLUTE_TIME
207 lpPerformanceCount->QuadPart = (LONGLONG)mach_absolute_time();
209 #elif HAVE_CLOCK_MONOTONIC
212 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
214 ASSERT("clock_gettime(CLOCK_MONOTONIC) failed; errno is %d (%s)\n", errno, strerror(errno));
218 lpPerformanceCount->QuadPart =
219 (LONGLONG)ts.tv_sec * (LONGLONG)tccSecondsToNanoSeconds + (LONGLONG)ts.tv_nsec;
223 lpPerformanceCount->QuadPart = (LONGLONG)gethrtime();
225 #elif HAVE_READ_REAL_TIME
228 read_real_time(&tb, TIMEBASE_SZ);
229 if (time_base_to_time(&tb, TIMEBASE_SZ) != 0)
231 ASSERT("time_base_to_time() failed; errno is %d (%s)\n", errno, strerror(errno));
235 lpPerformanceCount->QuadPart =
236 (LONGLONG)tb.tb_high * (LONGLONG)tccSecondsToNanoSeconds + (LONGLONG)tb.tb_low;
241 if (gettimeofday(&tv, NULL) == -1)
243 ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno));
247 lpPerformanceCount->QuadPart =
248 (LONGLONG)tv.tv_sec * (LONGLONG)tccSecondsToMicroSeconds + (LONGLONG)tv.tv_usec;
250 #endif // HAVE_CLOCK_MONOTONIC
253 LOGEXIT("QueryPerformanceCounter\n");
254 PERF_EXIT(QueryPerformanceCounter);
260 QueryPerformanceFrequency(
261 OUT LARGE_INTEGER *lpFrequency
265 PERF_ENTRY(QueryPerformanceFrequency);
266 ENTRY("QueryPerformanceFrequency()\n");
267 #if HAVE_MACH_ABSOLUTE_TIME
268 // use denom == 0 to indicate that s_TimebaseInfo is uninitialised.
269 if (s_TimebaseInfo.denom == 0)
271 ASSERT("s_TimebaseInfo is uninitialized.\n");
276 lpFrequency->QuadPart = (LONGLONG)tccSecondsToNanoSeconds * ((LONGLONG)s_TimebaseInfo.denom / (LONGLONG)s_TimebaseInfo.numer);
278 #elif HAVE_GETHRTIME || HAVE_READ_REAL_TIME || HAVE_CLOCK_MONOTONIC
279 lpFrequency->QuadPart = (LONGLONG)tccSecondsToNanoSeconds;
281 lpFrequency->QuadPart = (LONGLONG)tccSecondsToMicroSeconds;
282 #endif // HAVE_MACH_ABSOLUTE_TIME
283 LOGEXIT("QueryPerformanceFrequency\n");
284 PERF_EXIT(QueryPerformanceFrequency);
292 Puts the execution time (in nanoseconds) for the thread pointed to by ThreadHandle, into the unsigned long
293 pointed to by CycleTime. ThreadHandle must refer to the current thread. Returns TRUE on success, FALSE on
299 QueryThreadCycleTime(
300 IN HANDLE ThreadHandle,
301 OUT PULONG64 CycleTime
306 FILETIME kernelTime, userTime;
309 if(!GetThreadTimesInternal(ThreadHandle, &kernelTime, &userTime))
311 ASSERT("Could not get cycle time for current thread");
316 calcTime = ((ULONG64)kernelTime.dwHighDateTime << 32);
317 calcTime += (ULONG64)kernelTime.dwLowDateTime;
318 calcTime += ((ULONG64)userTime.dwHighDateTime << 32);
319 calcTime += (ULONG64)userTime.dwLowDateTime;
320 *CycleTime = calcTime;
330 Returns a 64-bit tick count with a millisecond resolution. It tries its best
331 to return monotonically increasing counts and avoid being affected by changes
332 to the system clock (either due to drift or due to explicit changes to system
339 ULONGLONG retval = 0;
341 #if HAVE_MACH_ABSOLUTE_TIME
343 // use denom == 0 to indicate that s_TimebaseInfo is uninitialised.
344 if (s_TimebaseInfo.denom == 0)
346 ASSERT("s_TimebaseInfo is uninitialized.\n");
349 retval = (mach_absolute_time() * s_TimebaseInfo.numer / s_TimebaseInfo.denom) / tccMillieSecondsToNanoSeconds;
351 #elif HAVE_CLOCK_MONOTONIC_COARSE || HAVE_CLOCK_MONOTONIC
353 clockid_t clockType =
354 #if HAVE_CLOCK_MONOTONIC_COARSE
355 CLOCK_MONOTONIC_COARSE; // good enough resolution, fastest speed
360 if (clock_gettime(clockType, &ts) != 0)
362 ASSERT("clock_gettime(CLOCK_MONOTONIC*) failed; errno is %d (%s)\n", errno, strerror(errno));
365 retval = (ts.tv_sec * tccSecondsToMillieSeconds)+(ts.tv_nsec / tccMillieSecondsToNanoSeconds);
369 retval = (ULONGLONG)(gethrtime() / tccMillieSecondsToNanoSeconds);
371 #elif HAVE_READ_REAL_TIME
374 read_real_time(&tb, TIMEBASE_SZ);
375 if (time_base_to_time(&tb, TIMEBASE_SZ) != 0)
377 ASSERT("time_base_to_time() failed; errno is %d (%s)\n", errno, strerror(errno));
380 retval = (tb.tb_high * tccSecondsToMillieSeconds)+(tb.tb_low / tccMillieSecondsToNanoSeconds);
385 if (gettimeofday(&tv, NULL) == -1)
387 ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno));
390 retval = (tv.tv_sec * tccSecondsToMillieSeconds) + (tv.tv_usec / tccMillieSecondsToMicroSeconds);
392 #endif // HAVE_CLOCK_MONOTONIC
401 Sleeps for the time specified in timeInNs.
402 Returns 0 on successful completion of the operation.
415 req.tv_nsec = timeInNs;
419 // Sleep for the requested time.
420 result = nanosleep(&req, &rem);
422 // Save the remaining time (used if the loop runs another iteration).
425 while(result == -1 && errno == EINTR);