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