Blame gnulib/lib/gettimeofday.c

Packit 06dd63
/* Provide gettimeofday for systems that don't have it or for which it's broken.
Packit 06dd63
Packit 06dd63
   Copyright (C) 2001-2003, 2005-2007, 2009-2019 Free Software Foundation, Inc.
Packit 06dd63
Packit 06dd63
   This program is free software; you can redistribute it and/or modify
Packit 06dd63
   it under the terms of the GNU Lesser General Public License as published by
Packit 06dd63
   the Free Software Foundation; either version 2.1, or (at your option)
Packit 06dd63
   any later version.
Packit 06dd63
Packit 06dd63
   This program is distributed in the hope that it will be useful,
Packit 06dd63
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 06dd63
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 06dd63
   GNU Lesser General Public License for more details.
Packit 06dd63
Packit 06dd63
   You should have received a copy of the GNU Lesser General Public License
Packit 06dd63
   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
Packit 06dd63
Packit 06dd63
/* written by Jim Meyering */
Packit 06dd63
Packit 06dd63
#include <config.h>
Packit 06dd63
Packit 06dd63
/* Specification.  */
Packit 06dd63
#include <sys/time.h>
Packit 06dd63
Packit 06dd63
#include <time.h>
Packit 06dd63
Packit 06dd63
#if defined _WIN32 && ! defined __CYGWIN__
Packit 06dd63
# define WINDOWS_NATIVE
Packit 06dd63
# include <windows.h>
Packit 06dd63
#endif
Packit 06dd63
Packit 06dd63
#include "localtime-buffer.h"
Packit 06dd63
Packit 06dd63
#ifdef WINDOWS_NATIVE
Packit 06dd63
Packit 06dd63
/* Avoid warnings from gcc -Wcast-function-type.  */
Packit 06dd63
# define GetProcAddress \
Packit 06dd63
   (void *) GetProcAddress
Packit 06dd63
Packit 06dd63
/* GetSystemTimePreciseAsFileTime was introduced only in Windows 8.  */
Packit 06dd63
typedef void (WINAPI * GetSystemTimePreciseAsFileTimeFuncType) (FILETIME *lpTime);
Packit 06dd63
static GetSystemTimePreciseAsFileTimeFuncType GetSystemTimePreciseAsFileTimeFunc = NULL;
Packit 06dd63
static BOOL initialized = FALSE;
Packit 06dd63
Packit 06dd63
static void
Packit 06dd63
initialize (void)
Packit 06dd63
{
Packit 06dd63
  HMODULE kernel32 = LoadLibrary ("kernel32.dll");
Packit 06dd63
  if (kernel32 != NULL)
Packit 06dd63
    {
Packit 06dd63
      GetSystemTimePreciseAsFileTimeFunc =
Packit 06dd63
        (GetSystemTimePreciseAsFileTimeFuncType) GetProcAddress (kernel32, "GetSystemTimePreciseAsFileTime");
Packit 06dd63
    }
Packit 06dd63
  initialized = TRUE;
Packit 06dd63
}
Packit 06dd63
Packit 06dd63
#endif
Packit 06dd63
Packit 06dd63
/* This is a wrapper for gettimeofday.  It is used only on systems
Packit 06dd63
   that lack this function, or whose implementation of this function
Packit 06dd63
   causes problems.
Packit 06dd63
   Work around the bug in some systems whereby gettimeofday clobbers
Packit 06dd63
   the static buffer that localtime uses for its return value.  The
Packit 06dd63
   gettimeofday function from Mac OS X 10.0.4 (i.e., Darwin 1.3.7) has
Packit 06dd63
   this problem.  */
Packit 06dd63
Packit 06dd63
int
Packit 06dd63
gettimeofday (struct timeval *restrict tv, void *restrict tz)
Packit 06dd63
{
Packit 06dd63
#undef gettimeofday
Packit 06dd63
#ifdef WINDOWS_NATIVE
Packit 06dd63
Packit 06dd63
  /* On native Windows, there are two ways to get the current time:
Packit 06dd63
     GetSystemTimeAsFileTime
Packit 06dd63
     <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime>
Packit 06dd63
     or
Packit 06dd63
     GetSystemTimePreciseAsFileTime
Packit 06dd63
     <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime>.
Packit 06dd63
     GetSystemTimeAsFileTime produces values that jump by increments of
Packit 06dd63
     15.627 milliseconds (!) on average.
Packit 06dd63
     Whereas GetSystemTimePreciseAsFileTime values usually jump by 1 or 2
Packit 06dd63
     microseconds.
Packit 06dd63
     More discussion on this topic:
Packit 06dd63
     <http://www.windowstimestamp.com/description>.  */
Packit 06dd63
  FILETIME current_time;
Packit 06dd63
Packit 06dd63
  if (!initialized)
Packit 06dd63
    initialize ();
Packit 06dd63
  if (GetSystemTimePreciseAsFileTimeFunc != NULL)
Packit 06dd63
    GetSystemTimePreciseAsFileTimeFunc (&current_time);
Packit 06dd63
  else
Packit 06dd63
    GetSystemTimeAsFileTime (&current_time);
Packit 06dd63
Packit 06dd63
  /* Convert from FILETIME to 'struct timeval'.  */
Packit 06dd63
  /* FILETIME: <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */
Packit 06dd63
  ULONGLONG since_1601 =
Packit 06dd63
    ((ULONGLONG) current_time.dwHighDateTime << 32)
Packit 06dd63
    | (ULONGLONG) current_time.dwLowDateTime;
Packit 06dd63
  /* Between 1601-01-01 and 1970-01-01 there were 280 normal years and 89 leap
Packit 06dd63
     years, in total 134774 days.  */
Packit 06dd63
  ULONGLONG since_1970 =
Packit 06dd63
    since_1601 - (ULONGLONG) 134774 * (ULONGLONG) 86400 * (ULONGLONG) 10000000;
Packit 06dd63
  ULONGLONG microseconds_since_1970 = since_1970 / (ULONGLONG) 10;
Packit 06dd63
  tv->tv_sec = microseconds_since_1970 / (ULONGLONG) 1000000;
Packit 06dd63
  tv->tv_usec = microseconds_since_1970 % (ULONGLONG) 1000000;
Packit 06dd63
Packit 06dd63
  return 0;
Packit 06dd63
Packit 06dd63
#else
Packit 06dd63
Packit 06dd63
# if HAVE_GETTIMEOFDAY
Packit 06dd63
#  if GETTIMEOFDAY_CLOBBERS_LOCALTIME
Packit 06dd63
  /* Save and restore the contents of the buffer used for localtime's
Packit 06dd63
     result around the call to gettimeofday.  */
Packit 06dd63
  struct tm save = *localtime_buffer_addr;
Packit 06dd63
#  endif
Packit 06dd63
Packit 06dd63
#  if defined timeval /* 'struct timeval' overridden by gnulib?  */
Packit 06dd63
#   undef timeval
Packit 06dd63
  struct timeval otv;
Packit 06dd63
  int result = gettimeofday (&otv, (struct timezone *) tz);
Packit 06dd63
  if (result == 0)
Packit 06dd63
    {
Packit 06dd63
      tv->tv_sec = otv.tv_sec;
Packit 06dd63
      tv->tv_usec = otv.tv_usec;
Packit 06dd63
    }
Packit 06dd63
#  else
Packit 06dd63
  int result = gettimeofday (tv, (struct timezone *) tz);
Packit 06dd63
#  endif
Packit 06dd63
Packit 06dd63
#  if GETTIMEOFDAY_CLOBBERS_LOCALTIME
Packit 06dd63
  *localtime_buffer_addr = save;
Packit 06dd63
#  endif
Packit 06dd63
Packit 06dd63
  return result;
Packit 06dd63
Packit 06dd63
# else
Packit 06dd63
Packit 06dd63
#  if !defined OK_TO_USE_1S_CLOCK
Packit 06dd63
#   error "Only 1-second nominal clock resolution found.  Is that intended?" \
Packit 06dd63
          "If so, compile with the -DOK_TO_USE_1S_CLOCK option."
Packit 06dd63
#  endif
Packit 06dd63
  tv->tv_sec = time (NULL);
Packit 06dd63
  tv->tv_usec = 0;
Packit 06dd63
Packit 06dd63
  return 0;
Packit 06dd63
Packit 06dd63
# endif
Packit 06dd63
#endif
Packit 06dd63
}