openMSX
Timer.cc
Go to the documentation of this file.
1 #include "Timer.hh"
2 #include "systemfuncs.hh"
3 #if HAVE_CLOCK_GETTIME
4 #include <ctime>
5 #endif
6 #if HAVE_USLEEP
7 #include <unistdp.hh>
8 #endif
9 #if defined _WIN32
10 #include <windows.h>
11 #endif
12 #include <SDL.h>
13 #include <cassert>
14 
15 namespace openmsx {
16 namespace Timer {
17 
18 static inline uint64_t getSDLTicks()
19 {
20  return static_cast<uint64_t>(SDL_GetTicks()) * 1000;
21 }
22 
23 uint64_t getTime()
24 {
25  static uint64_t lastTime = 0;
26  uint64_t now;
27 /* QueryPerformanceCounter() has problems on modern CPUs,
28  * - on dual core CPUs time can ge backwards (a bit) when your process
29  * get scheduled on the other core
30  * - the resolution of the timer can vary on CPUs that can change its
31  * clock frequency (for power managment)
32 ##if defined _WIN32
33  static LONGLONG hfFrequency = 0;
34 
35  LARGE_INTEGER li;
36  if (!hfFrequency) {
37  if (QueryPerformanceFrequency(&li)) {
38  hfFrequency = li.QuadPart;
39  } else {
40  return getSDLTicks();
41  }
42  }
43  QueryPerformanceCounter(&li);
44 
45  // Assumes that the timer never wraps. The mask is just to
46  // ensure that the multiplication doesn't wrap.
47  now = (li.QuadPart & (int64_t(-1) >> 20)) * 1000000 / hfFrequency;
48 */
49 #if HAVE_CLOCK_GETTIME && defined(_POSIX_MONOTONIC_CLOCK)
50  // Note: in the past we used the more portable gettimeofday() function,
51  // but the result of that function is not always monotonic.
52  timespec ts;
53  int result = clock_gettime(CLOCK_MONOTONIC, &ts);
54  assert(result == 0); (void)result;
55  now = static_cast<uint64_t>(ts.tv_sec) * 1000000 +
56  static_cast<uint64_t>(ts.tv_nsec) / 1000;
57 #else
58  now = getSDLTicks();
59 #endif
60  if (now < lastTime) {
61  // This shouldn't happen, time should never go backwards.
62  // Though there appears to be a bug in some Linux kernels
63  // so that occasionally clock_gettime(CLOCK_MONOTONIC) _does_
64  // go back in time slightly. When that happens we return the
65  // last time again.
66  return lastTime;
67  }
68  lastTime = now;
69  return now;
70 }
71 
72 /*#if defined _WIN32
73 static void CALLBACK timerCallback(unsigned int,
74  unsigned int,
75  unsigned long eventHandle,
76  unsigned long,
77  unsigned long)
78 {
79  SetEvent((HANDLE)eventHandle);
80 }
81 #endif*/
82 
83 void sleep(uint64_t us)
84 {
85 /*#if defined _WIN32
86  us /= 1000;
87  if (us > 0) {
88  static HANDLE timerEvent = nullptr;
89  if (!timerEvent) {
90  timerEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
91  }
92  UINT id = timeSetEvent(us, 1, timerCallback, (DWORD)timerEvent,
93  TIME_ONESHOT);
94  WaitForSingleObject(timerEvent, INFINITE);
95  timeKillEvent(id);
96  }
97 */
98 #if HAVE_USLEEP
99  usleep(us);
100 #else
101  SDL_Delay(unsigned(us / 1000));
102 #endif
103 }
104 
105 } // namespace Timer
106 } // namespace openmsx