Blame lib/gettimeofday.c

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