+// sleep based timing loop.
+//
+// Calling sleep, even usleep() on linux is less accurate than
+// we like, but it does free up the cpu for other tasks during
+// the sleep so it is desirable. Because of the way sleep()
+// is implemented in consumer operating systems like windows
+// and linux, you almost always sleep a little longer than the
+// requested amount.
+//
+// To combat the problem of sleeping too long, we calculate the
+// desired wait time and shorten it by 2000us (2ms) to avoid
+// [hopefully] over-sleep'ing. The 2ms value was arrived at
+// via experimentation. We follow this up at the end with a
+// simple busy-wait loop to get the final pause timing exactly
+// right.
+//
+// Assuming we don't oversleep by more than 2000us, this
+// should be a reasonable compromise between sleep based
+// waiting, and busy waiting.
+//
+// Usually posix timer resolutions are low enough that we
+// could just leave this to the operating system today.
+// The day where the busy loop was introduced in flightgear,
+// the usual kernels still had just about 10ms (=HZ for
+// the timer tick) accuracy which is too bad to catch 60Hz...
+bool SGTimeStamp::sleepUntil(const SGTimeStamp& abstime)
+{
+#if defined(_POSIX_TIMERS) && (0 < _POSIX_TIMERS)
+ SGTimeStamp abstimeForSleep = abstime;
+
+ // Always undersleep by resolution of the clock
+ struct timespec ts;
+ if (-1 != clock_getres(getClockId(), &ts)) {
+ abstimeForSleep -= SGTimeStamp::fromSecNSec(ts.tv_sec, ts.tv_nsec);
+ } else {
+ abstimeForSleep -= SGTimeStamp::fromSecMSec(0, 2);
+ }
+
+ ts.tv_sec = abstimeForSleep._sec;
+ ts.tv_nsec = abstimeForSleep._nsec;
+ for (;;) {
+ int ret = clock_nanosleep(getClockId(), TIMER_ABSTIME, &ts, NULL);
+ if (-1 == ret && errno != EINTR)
+ return false;
+ if (ret == 0)
+ break;
+ }
+
+ // The busy loop for the rest
+ SGTimeStamp currentTime;
+ do {
+ currentTime.stamp();
+ } while (currentTime < abstime);
+
+ return true;
+
+#elif defined _WIN32
+
+ SGTimeStamp currentTime;
+ currentTime.stamp();
+ if (abstime <= currentTime)
+ return true;
+
+ SGTimeStamp abstimeForSleep = abstime - SGTimeStamp::fromSecMSec(0, 2);
+ for (;abstimeForSleep < currentTime;) {
+ SGTimeStamp timeDiff = abstimeForSleep - currentTime;
+ if (timeDiff < SGTimeStamp::fromSecMSec(0, 1))
+ break;
+ // Don't know, but may be win32 has something better today??
+ Sleep(static_cast<DWORD>(timeDiff.toMSecs()));
+
+ currentTime.stamp();
+ }
+
+ // Follow by a busy loop
+ while (currentTime < abstime) {
+ currentTime.stamp();
+ }
+
+ return true;
+