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 (&current_time);
105  else
106    GetSystemTimeAsFileTime (&current_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