diff --git a/src/backend/main/main.c b/src/backend/main/main.c index c51b391199..73c30c5354 100644 --- a/src/backend/main/main.c +++ b/src/backend/main/main.c @@ -260,6 +260,12 @@ startup_hacks(const char *progname) /* In case of general protection fault, don't show GUI popup box */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + +#ifndef HAVE_GETTIMEOFDAY + /* Figure out which syscall to use to capture timestamp information */ + init_win32_gettimeofday(); +#endif + } #endif /* WIN32 */ diff --git a/src/include/port.h b/src/include/port.h index 94a0e2fe2b..58677ec6bd 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -328,6 +328,8 @@ extern FILE *pgwin32_popen(const char *command, const char *type); #ifndef HAVE_GETTIMEOFDAY /* Last parameter not used */ extern int gettimeofday(struct timeval * tp, struct timezone * tzp); +/* On windows we need to call some backend start setup for accurate timing */ +extern void init_win32_gettimeofday(void); #endif #else /* !WIN32 */ diff --git a/src/port/gettimeofday.c b/src/port/gettimeofday.c index ecc0b4dd70..eabf161e04 100644 --- a/src/port/gettimeofday.c +++ b/src/port/gettimeofday.c @@ -41,10 +41,59 @@ static const unsigned __int64 epoch = UINT64CONST(116444736000000000); #define FILETIME_UNITS_PER_SEC 10000000L #define FILETIME_UNITS_PER_USEC 10 +/* + * Both GetSystemTimeAsFileTime and GetSystemTimePreciseAsFileTime share a + * signature, so we can just store a pointer to whichever we find. This + * is the pointer's type. + */ +typedef VOID (WINAPI *PgGetSystemTimeFn)(LPFILETIME); + +/* Storage for the function we pick at runtime */ +static PgGetSystemTimeFn pg_get_system_time = NULL; + +/* + * During backend startup, determine if GetSystemTimePreciseAsFileTime is + * available and use it; if not, fall back to GetSystemTimeAsFileTime. + */ +void +init_win32_gettimeofday(void) +{ + /* + * Because it's guaranteed that kernel32.dll will be linked into our + * address space already, we don't need to LoadLibrary it and worry about + * closing it afterwards, so we're not using Pg's dlopen/dlsym() wrapper. + * + * We'll just look up the address of GetSystemTimePreciseAsFileTime if + * present. + * + * While we could look up the Windows version and skip this on Windows + * versions below Windows 8 / Windows Server 2012 there isn't much point, + * and determining the windows version is its self somewhat Windows version + * and development SDK specific... + */ + pg_get_system_time = (PgGetSystemTimeFn) GetProcAddress( + GetModuleHandle(TEXT("kernel32.dll")), + "GetSystemTimePreciseAsFileTime"); + if (pg_get_system_time == NULL) + { + /* + * The expected error from GetLastError() is ERROR_PROC_NOT_FOUND, if + * the function isn't present. No other error should occur. + * + * It's too early in startup to elog(...) if we get some unexpected + * error, and not serious enough to warrant a fprintf to stderr about + * it or save the error and report it later. So silently fall back to + * GetSystemTimeAsFileTime irrespective of why the failure occurred. + */ + pg_get_system_time = &GetSystemTimeAsFileTime; + } + +} + /* * timezone information is stored outside the kernel so tzp isn't used anymore. * - * Note: this function is not for Win32 high precision timing purpose. See + * Note: this function is not for Win32 high precision timing purposes. See * elapsed_time(). */ int @@ -53,7 +102,7 @@ gettimeofday(struct timeval * tp, struct timezone * tzp) FILETIME file_time; ULARGE_INTEGER ularge; - GetSystemTimeAsFileTime(&file_time); + (*pg_get_system_time)(&file_time); ularge.LowPart = file_time.dwLowDateTime; ularge.HighPart = file_time.dwHighDateTime;