cyclonedds/src/ddsrt/src/time/windows/time.c
Jeroen Koekkoek cd6742ee12 Rearrange and fixup abstraction layer
- Replace os_result by dds_retcode_t and move DDS return code defines down.
  Eliminates the need to convert between different return code types.

- Move dds_time_t down and remove os_time.
  Eliminates the need to convert between different time representations and
  reduces code duplication.

- Remove use of Microsoft source-code annotation language (SAL).
  SAL annotations are Microsoft specific and not very well documented. This
  makes it very difficult for contributers to write.

- Rearrange the abstraction layer to be feature-based. The previous layout
  falsely assumed that the operating system dictates which implementation is
  best suited. For general purpose operating systems this is mostly true, but
  embedded targets require a slightly different approach and may not even offer
  all features. The new layout makes it possible to mix-and-match feature
  implementations and allows for features to not be implemented at all.

- Replace the os prefix by ddsrt to avoid name collisions.

- Remove various portions of unused and unwanted code.

- Export thread names on all supported platforms.

- Return native thread identifier on POSIX compatible platforms.

- Add timed wait for condition variables that takes an absolute time.

- Remove system abstraction for errno. The os_getErrno and os_setErrno were
  incorrect. Functions that might fail now simply return a DDS return code
  instead.

- Remove thread-specific memory abstraction. os_threadMemGet and accompanying
  functions were a mess and their use has been eliminated by other changes in
  this commit.

- Replace attribute (re)defines by ddsrt_ prefixed equivalents to avoid name
  collisions and problems with faulty __nonnull__ attributes.

Signed-off-by: Jeroen Koekkoek <jeroen@koekkoek.nl>
2019-03-22 15:19:09 +01:00

161 lines
5.7 KiB
C

/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
#include <assert.h>
#include <sys/timeb.h>
#include <time.h>
#include "dds/ddsrt/timeconv.h"
extern inline DWORD
ddsrt_duration_to_msecs_ceil(dds_duration_t reltime);
/* GetSystemTimePreciseAsFileTime was introduced with Windows 8, so
starting from _WIN32_WINNET = 0x0602. When building for an older
version we can still check dynamically. */
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0602
#define UseGetSystemTimePreciseAsFileTime
#else
static VOID (WINAPI *GetSystemTimeAsFileTimeFunc)(LPFILTETIME) = GetSystemTimeAsFileTime;
static HANDLE Kernel32ModuleHandle;
#endif
/* GetSystemTimeAsFileTime returns the number of 100ns intervals that have elapsed
* since January 1, 1601 (UTC). There are 11,644,473,600 seconds between 1601 and
* the Unix epoch (January 1, 1970 (UTC)), which is the reference that is used for
* dds_time.
*/
#define FILETIME_EPOCH_OFFSET_SECS (11644473600)
#define SECS_IN_100_NSECS (1000 * 1000 * 10)
dds_time_t dds_time(void)
{
FILETIME ft;
ULARGE_INTEGER ns100;
/* GetSystemTime(Precise)AsFileTime returns the number of 100-nanosecond
* intervals since January 1, 1601 (UTC).
* GetSystemTimeAsFileTime has a resolution of approximately the
* TimerResolution (~15.6ms) on Windows XP. On Windows 7 it appears to have
* sub-millisecond resolution. GetSystemTimePreciseAsFileTime (available on
* Windows 8) has sub-microsecond resolution.
*
* This call appears to be significantly (factor 8) cheaper than the
* QueryPerformanceCounter (on the systems performance was measured on).
*
* TODO: When the API is extended to support retrieval of clock-properties,
* then the actual resolution of this clock can be retrieved using the
* GetSystemTimeAdjustment.
*/
#ifdef UseGetSystemTimePreciseAsFileTime
GetSystemTimePreciseAsFileTime(&ft);
#else
GetSystemTimeAsFileTimeFunc(&ft);
#endif
ns100.LowPart = ft.dwLowDateTime;
ns100.HighPart = ft.dwHighDateTime;
ns100.QuadPart -= (FILETIME_EPOCH_OFFSET_SECS * SECS_IN_100_NSECS);
return (dds_time_t)(ns100.QuadPart * 100);
}
void ddsrt_time_init(void)
{
#ifndef UseGetSystemTimePreciseAsFileTime
/* Resolve the time-functions from the Kernel32-library. */
VOID (WINAPI *f) (LPFILTETIME);
/* This os_timeModuleInit is currently called from DllMain. This means
* we're not allowed to do LoadLibrary. One exception is "Kernel32.DLL",
* since that library is per definition loaded (LoadLibrary itself
* lives there). And since we're only resolving stuff, not actually
* invoking, this is considered safe.
*/
Kernel32ModuleHandle = LoadLibrary("Kernel32.DLL");
assert(Kernel32ModuleHandle);
f = GetProcAddress(Kernel32ModuleHandle, "GetSystemTimePreciseAsFileTime");
if (f != 0) {
GetSystemTimeAsFileTimeFunc = f;
}
#endif
}
void ddsrt_time_fini(void)
{
#ifndef UseGetSystemTimePreciseAsFileTime
if (Kernel32ModuleHandle) {
GetSystemTimeAsFileTimeFunc = GetSystemTimeAsFileTime;
FreeLibrary(Kernel32ModuleHandle);
Kernel32ModuleHandle = NULL;
}
#endif
}
dds_time_t ddsrt_time_monotonic(void)
{
ULONGLONG ubit;
(void)QueryUnbiasedInterruptTime(&ubit); /* 100ns ticks */
return (dds_time_t)(ubit * 100);
}
dds_time_t ddsrt_time_elapsed(void)
{
LARGE_INTEGER qpc;
static LONGLONG qpc_freq; /* Counts per nanosecond. */
/* The QueryPerformanceCounter has a bad reputation, since it didn't behave
* very well on older hardware. On recent OS's (Windows XP SP2 and later)
* things have become much better, especially when combined with new hard-
* ware.
*
* There is currently one bug which is not fixed, which may cause forward
* jumps. This is currently not really important, since a forward jump may
* be observed anyway due to the system going to standby. There is a work-
* around available (comparing the progress with the progress made by
* GetTickCount), but for now we live with a risk of a forward jump on buggy
* hardware. Since Microsoft does maintain a list of hardware which exhibits
* the behaviour, it is possible to only have the workaround in place only
* on the faulty hardware (see KB274323 for a list and more info).
*
* TODO: When the API is extended to support retrieval of clock-properties,
* then the discontinuous nature (when sleeping/hibernating) of this
* clock and the drift tendency should be reported. */
if (qpc_freq == 0){
/* This block is idempotent, so don't bother with synchronisation. */
LARGE_INTEGER frequency;
if (QueryPerformanceFrequency(&frequency)) {
/* Performance-counter frequency is in counts per second. */
qpc_freq = DDS_NSECS_IN_SEC / frequency.QuadPart;
}
/* Since Windows XP SP2 the QueryPerformanceCounter is abstracted,
* so QueryPerformanceFrequency is not expected to ever return 0.
* That't why there is no fall-back for the case when no
* QueryPerformanceCounter is available. */
}
assert(qpc_freq);
/* The QueryPerformanceCounter tends to drift quite a bit, so in order to
* accurately measure longer periods with it, there may be a need to sync
* the time progression to actual time progression. */
QueryPerformanceCounter(&qpc);
return (dds_time_t)(qpc.QuadPart * qpc_freq);
}
void dds_sleepfor(dds_duration_t reltime)
{
Sleep(ddsrt_duration_to_msecs_ceil(reltime));
}