Blame lib/gettimeofday.c

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