1/* Provide gettimeofday for systems that don't have it or for which it's broken. 2 3 Copyright (C) 2001-2003, 2005-2007, 2009-2020 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3, or (at your option) 8 any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <https://www.gnu.org/licenses/>. */ 17 18/* written by Jim Meyering */ 19 20#include <config.h> 21 22/* Specification. */ 23#include <sys/time.h> 24 25#include <time.h> 26 27#if defined _WIN32 && ! defined __CYGWIN__ 28# define WINDOWS_NATIVE 29# include <windows.h> 30#endif 31 32#include "localtime-buffer.h" 33 34#ifdef WINDOWS_NATIVE 35 36/* Don't assume that UNICODE is not defined. */ 37# undef LoadLibrary 38# define LoadLibrary LoadLibraryA 39 40# if !(_WIN32_WINNT >= _WIN32_WINNT_WIN8) 41 42/* Avoid warnings from gcc -Wcast-function-type. */ 43# define GetProcAddress \ 44 (void *) GetProcAddress 45 46/* GetSystemTimePreciseAsFileTime was introduced only in Windows 8. */ 47typedef void (WINAPI * GetSystemTimePreciseAsFileTimeFuncType) (FILETIME *lpTime); 48static GetSystemTimePreciseAsFileTimeFuncType GetSystemTimePreciseAsFileTimeFunc = NULL; 49static BOOL initialized = FALSE; 50 51static void 52initialize (void) 53{ 54 HMODULE kernel32 = LoadLibrary ("kernel32.dll"); 55 if (kernel32 != NULL) 56 { 57 GetSystemTimePreciseAsFileTimeFunc = 58 (GetSystemTimePreciseAsFileTimeFuncType) GetProcAddress (kernel32, "GetSystemTimePreciseAsFileTime"); 59 } 60 initialized = TRUE; 61} 62 63# else 64 65# define GetSystemTimePreciseAsFileTimeFunc GetSystemTimePreciseAsFileTime 66 67# endif 68 69#endif 70 71/* This is a wrapper for gettimeofday. It is used only on systems 72 that lack this function, or whose implementation of this function 73 causes problems. 74 Work around the bug in some systems whereby gettimeofday clobbers 75 the static buffer that localtime uses for its return value. The 76 gettimeofday function from Mac OS X 10.0.4 (i.e., Darwin 1.3.7) has 77 this problem. */ 78 79int 80gettimeofday (struct timeval *restrict tv, void *restrict tz) 81{ 82#undef gettimeofday 83#ifdef WINDOWS_NATIVE 84 85 /* On native Windows, there are two ways to get the current time: 86 GetSystemTimeAsFileTime 87 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime> 88 or 89 GetSystemTimePreciseAsFileTime 90 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime>. 91 GetSystemTimeAsFileTime produces values that jump by increments of 92 15.627 milliseconds (!) on average. 93 Whereas GetSystemTimePreciseAsFileTime values usually jump by 1 or 2 94 microseconds. 95 More discussion on this topic: 96 <http://www.windowstimestamp.com/description>. */ 97 FILETIME current_time; 98 99# if !(_WIN32_WINNT >= _WIN32_WINNT_WIN8) 100 if (!initialized) 101 initialize (); 102# endif 103 if (GetSystemTimePreciseAsFileTimeFunc != NULL) 104 GetSystemTimePreciseAsFileTimeFunc (¤t_time); 105 else 106 GetSystemTimeAsFileTime (¤t_time); 107 108 /* Convert from FILETIME to 'struct timeval'. */ 109 /* FILETIME: <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */ 110 ULONGLONG since_1601 = 111 ((ULONGLONG) current_time.dwHighDateTime << 32) 112 | (ULONGLONG) current_time.dwLowDateTime; 113 /* Between 1601-01-01 and 1970-01-01 there were 280 normal years and 89 leap 114 years, in total 134774 days. */ 115 ULONGLONG since_1970 = 116 since_1601 - (ULONGLONG) 134774 * (ULONGLONG) 86400 * (ULONGLONG) 10000000; 117 ULONGLONG microseconds_since_1970 = since_1970 / (ULONGLONG) 10; 118 tv->tv_sec = microseconds_since_1970 / (ULONGLONG) 1000000; 119 tv->tv_usec = microseconds_since_1970 % (ULONGLONG) 1000000; 120 121 return 0; 122 123#else 124 125# if HAVE_GETTIMEOFDAY 126# if GETTIMEOFDAY_CLOBBERS_LOCALTIME 127 /* Save and restore the contents of the buffer used for localtime's 128 result around the call to gettimeofday. */ 129 struct tm save = *localtime_buffer_addr; 130# endif 131 132# if defined timeval /* 'struct timeval' overridden by gnulib? */ 133# undef timeval 134 struct timeval otv; 135 int result = gettimeofday (&otv, (struct timezone *) tz); 136 if (result == 0) 137 { 138 tv->tv_sec = otv.tv_sec; 139 tv->tv_usec = otv.tv_usec; 140 } 141# else 142 int result = gettimeofday (tv, (struct timezone *) tz); 143# endif 144 145# if GETTIMEOFDAY_CLOBBERS_LOCALTIME 146 *localtime_buffer_addr = save; 147# endif 148 149 return result; 150 151# else 152 153# if !defined OK_TO_USE_1S_CLOCK 154# error "Only 1-second nominal clock resolution found. Is that intended?" \ 155 "If so, compile with the -DOK_TO_USE_1S_CLOCK option." 156# endif 157 tv->tv_sec = time (NULL); 158 tv->tv_usec = 0; 159 160 return 0; 161 162# endif 163#endif 164} 165