Blame src/microhttpd/mhd_mono_clock.c

Packit 875988
/*
Packit 875988
  This file is part of libmicrohttpd
Packit 875988
  Copyright (C) 2015 Karlson2k (Evgeny Grin)
Packit 875988
Packit 875988
  This library is free software; you can redistribute it and/or
Packit 875988
  modify it under the terms of the GNU Lesser General Public
Packit 875988
  License as published by the Free Software Foundation; either
Packit 875988
  version 2.1 of the License, or (at your option) any later version.
Packit 875988
Packit 875988
  This library is distributed in the hope that it will be useful,
Packit 875988
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 875988
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 875988
  Lesser General Public License for more details.
Packit 875988
Packit 875988
  You should have received a copy of the GNU Lesser General Public
Packit 875988
  License along with this library; if not, write to the Free Software
Packit 875988
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 875988
*/
Packit 875988
Packit 875988
/**
Packit 875988
 * @file microhttpd/mhd_mono_clock.h
Packit 875988
 * @brief  internal monotonic clock functions implementations
Packit 875988
 * @author Karlson2k (Evgeny Grin)
Packit 875988
 */
Packit 875988
Packit 875988
#include "mhd_mono_clock.h"
Packit 875988
Packit 875988
#if defined(_WIN32) && ! defined(__CYGWIN__) && defined(HAVE_CLOCK_GETTIME)
Packit 875988
/* Prefer native clock source over wrappers */
Packit 875988
#undef HAVE_CLOCK_GETTIME
Packit 875988
#endif /* _WIN32 && ! __CYGWIN__ && HAVE_CLOCK_GETTIME */
Packit 875988
Packit 875988
#ifdef HAVE_CLOCK_GETTIME
Packit 875988
#include <time.h>
Packit 875988
#endif /* HAVE_CLOCK_GETTIME */
Packit 875988
Packit 875988
#ifdef HAVE_GETHRTIME
Packit 875988
#ifdef HAVE_SYS_TIME_H
Packit 875988
/* Solaris defines gethrtime() in sys/time.h */
Packit 875988
#include <sys/time.h>
Packit 875988
#endif /* HAVE_SYS_TIME_H */
Packit 875988
#ifdef HAVE_TIME_H
Packit 875988
/* HP-UX defines gethrtime() in time.h */
Packit 875988
#include <time.h>
Packit 875988
#endif /* HAVE_TIME_H */
Packit 875988
#endif /* HAVE_GETHRTIME */
Packit 875988
Packit 875988
#ifdef HAVE_CLOCK_GET_TIME
Packit 875988
#include <mach/mach.h>
Packit 875988
/* for host_get_clock_service(), mach_host_self(), mach_task_self() */
Packit 875988
#include <mach/clock.h>
Packit 875988
/* for clock_get_time() */
Packit 875988
Packit 875988
#define _MHD_INVALID_CLOCK_SERV ((clock_serv_t) -2)
Packit 875988
Packit 875988
static clock_serv_t mono_clock_service = _MHD_INVALID_CLOCK_SERV;
Packit 875988
#endif /* HAVE_CLOCK_GET_TIME */
Packit 875988
Packit 875988
#ifdef _WIN32
Packit 875988
#ifndef WIN32_LEAN_AND_MEAN
Packit 875988
/* Do not include unneeded parts of W32 headers. */
Packit 875988
#define WIN32_LEAN_AND_MEAN 1
Packit 875988
#endif /* !WIN32_LEAN_AND_MEAN */
Packit 875988
#include <windows.h>
Packit 875988
#include <stdint.h>
Packit 875988
#endif /* _WIN32 */
Packit 875988
Packit 875988
#ifdef HAVE_CLOCK_GETTIME
Packit 875988
#ifdef CLOCK_REALTIME
Packit 875988
#define _MHD_UNWANTED_CLOCK CLOCK_REALTIME
Packit 875988
#else  /* !CLOCK_REALTIME */
Packit 875988
#define _MHD_UNWANTED_CLOCK ((clockid_t) -2)
Packit 875988
#endif /* !CLOCK_REALTIME */
Packit 875988
Packit 875988
static clockid_t mono_clock_id = _MHD_UNWANTED_CLOCK;
Packit 875988
#endif /* HAVE_CLOCK_GETTIME */
Packit 875988
Packit 875988
/* sync clocks; reduce chance of value wrap */
Packit 875988
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GET_TIME) || defined(HAVE_GETHRTIME)
Packit 875988
static time_t mono_clock_start;
Packit 875988
#endif /* HAVE_CLOCK_GETTIME || HAVE_CLOCK_GET_TIME || HAVE_GETHRTIME */
Packit 875988
static time_t sys_clock_start;
Packit 875988
#ifdef HAVE_GETHRTIME
Packit 875988
static hrtime_t hrtime_start;
Packit 875988
#endif /* HAVE_GETHRTIME */
Packit 875988
#ifdef _WIN32
Packit 875988
#if _WIN32_WINNT >= 0x0600
Packit 875988
static uint64_t tick_start;
Packit 875988
#else  /* _WIN32_WINNT < 0x0600 */
Packit 875988
static int64_t perf_freq;
Packit 875988
static int64_t perf_start;
Packit 875988
#endif /* _WIN32_WINNT < 0x0600 */
Packit 875988
#endif /* _WIN32 */
Packit 875988
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Type of monotonic clock source
Packit 875988
 */
Packit 875988
enum _MHD_mono_clock_source
Packit 875988
{
Packit 875988
  /**
Packit 875988
   * No monotonic clock
Packit 875988
   */
Packit 875988
  _MHD_CLOCK_NO_SOURCE = 0,
Packit 875988
Packit 875988
  /**
Packit 875988
   * clock_gettime() with specific clock
Packit 875988
   */
Packit 875988
  _MHD_CLOCK_GETTIME,
Packit 875988
Packit 875988
  /**
Packit 875988
   * clock_get_time() with specific clock service
Packit 875988
   */
Packit 875988
  _MHD_CLOCK_GET_TIME,
Packit 875988
Packit 875988
  /**
Packit 875988
   * gethrtime() / 1000000000
Packit 875988
   */
Packit 875988
  _MHD_CLOCK_GETHRTIME,
Packit 875988
Packit 875988
  /**
Packit 875988
   * GetTickCount64() / 1000
Packit 875988
   */
Packit 875988
  _MHD_CLOCK_GETTICKCOUNT64,
Packit 875988
Packit 875988
   /**
Packit 875988
    * QueryPerformanceCounter() / QueryPerformanceFrequency()
Packit 875988
    */
Packit 875988
  _MHD_CLOCK_PERFCOUNTER
Packit 875988
};
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Initialise monotonic seconds counter.
Packit 875988
 */
Packit 875988
void
Packit 875988
MHD_monotonic_sec_counter_init (void)
Packit 875988
{
Packit 875988
#ifdef HAVE_CLOCK_GET_TIME
Packit 875988
  mach_timespec_t cur_time;
Packit 875988
#endif /* HAVE_CLOCK_GET_TIME */
Packit 875988
  enum _MHD_mono_clock_source mono_clock_source = _MHD_CLOCK_NO_SOURCE;
Packit 875988
#ifdef HAVE_CLOCK_GETTIME
Packit 875988
  struct timespec ts;
Packit 875988
Packit 875988
  mono_clock_id = _MHD_UNWANTED_CLOCK;
Packit 875988
#endif /* HAVE_CLOCK_GETTIME */
Packit 875988
#ifdef HAVE_CLOCK_GET_TIME
Packit 875988
  mono_clock_service = _MHD_INVALID_CLOCK_SERV;
Packit 875988
#endif /* HAVE_CLOCK_GET_TIME */
Packit 875988
Packit 875988
  /* just a little syntactic trick to get the
Packit 875988
     various following ifdef's to work out nicely */
Packit 875988
  if (0)
Packit 875988
    {
Packit 875988
    }
Packit 875988
  else
Packit 875988
#ifdef HAVE_CLOCK_GETTIME
Packit 875988
#ifdef CLOCK_MONOTONIC_COARSE
Packit 875988
  /* Linux-specific fast value-getting clock */
Packit 875988
  /* Can be affected by frequency adjustment and don't count time in suspend, */
Packit 875988
  /* but preferred since it's fast */
Packit 875988
  if (0 == clock_gettime (CLOCK_MONOTONIC_COARSE,
Packit 875988
                          &ts))
Packit 875988
    {
Packit 875988
      mono_clock_id = CLOCK_MONOTONIC_COARSE;
Packit 875988
      mono_clock_start = ts.tv_sec;
Packit 875988
      mono_clock_source = _MHD_CLOCK_GETTIME;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* CLOCK_MONOTONIC_COARSE */
Packit 875988
#ifdef CLOCK_MONOTONIC_FAST
Packit 875988
  /* FreeBSD/DragonFly fast value-getting clock */
Packit 875988
  /* Can be affected by frequency adjustment, but preferred since it's fast */
Packit 875988
  if (0 == clock_gettime (CLOCK_MONOTONIC_FAST,
Packit 875988
                          &ts))
Packit 875988
    {
Packit 875988
      mono_clock_id = CLOCK_MONOTONIC_FAST;
Packit 875988
      mono_clock_start = ts.tv_sec;
Packit 875988
      mono_clock_source = _MHD_CLOCK_GETTIME;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* CLOCK_MONOTONIC_COARSE */
Packit 875988
#ifdef CLOCK_MONOTONIC_RAW
Packit 875988
  /* Linux-specific clock */
Packit 875988
  /* Not affected by frequency adjustment, but don't count time in suspend */
Packit 875988
  if (0 == clock_gettime (CLOCK_MONOTONIC_RAW,
Packit 875988
                          &ts))
Packit 875988
    {
Packit 875988
      mono_clock_id = CLOCK_MONOTONIC_RAW;
Packit 875988
      mono_clock_start = ts.tv_sec;
Packit 875988
      mono_clock_source = _MHD_CLOCK_GETTIME;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* CLOCK_MONOTONIC_RAW */
Packit 875988
#ifdef CLOCK_BOOTTIME
Packit 875988
  /* Linux-specific clock */
Packit 875988
  /* Count time in suspend so it's real monotonic on Linux, */
Packit 875988
  /* but can be slower value-getting than other clocks */
Packit 875988
  if (0 == clock_gettime (CLOCK_BOOTTIME,
Packit 875988
                          &ts))
Packit 875988
    {
Packit 875988
      mono_clock_id = CLOCK_BOOTTIME;
Packit 875988
      mono_clock_start = ts.tv_sec;
Packit 875988
      mono_clock_source = _MHD_CLOCK_GETTIME;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* CLOCK_BOOTTIME */
Packit 875988
#ifdef CLOCK_MONOTONIC
Packit 875988
  /* Monotonic clock */
Packit 875988
  /* Widely supported, may be affected by frequency adjustment */
Packit 875988
  /* On Linux it's not truly monotonic as it doesn't count time in suspend */
Packit 875988
  if (0 == clock_gettime (CLOCK_MONOTONIC,
Packit 875988
                          &ts))
Packit 875988
    {
Packit 875988
      mono_clock_id = CLOCK_MONOTONIC;
Packit 875988
      mono_clock_start = ts.tv_sec;
Packit 875988
      mono_clock_source = _MHD_CLOCK_GETTIME;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* CLOCK_BOOTTIME */
Packit 875988
#endif /* HAVE_CLOCK_GETTIME */
Packit 875988
#ifdef HAVE_CLOCK_GET_TIME
Packit 875988
  /* Darwin-specific monotonic clock */
Packit 875988
  /* Should be monotonic as clock_set_time function always unconditionally */
Packit 875988
  /* failed on latest kernels */
Packit 875988
  if ( (KERN_SUCCESS == host_get_clock_service (mach_host_self(),
Packit 875988
                                                SYSTEM_CLOCK,
Packit 875988
                                                &mono_clock_service)) &&
Packit 875988
       (KERN_SUCCESS == clock_get_time (mono_clock_service,
Packit 875988
                                        &cur_time)) )
Packit 875988
    {
Packit 875988
      mono_clock_start = cur_time.tv_sec;
Packit 875988
      mono_clock_source = _MHD_CLOCK_GET_TIME;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* HAVE_CLOCK_GET_TIME */
Packit 875988
#ifdef _WIN32
Packit 875988
#if _WIN32_WINNT >= 0x0600
Packit 875988
  /* W32 Vista or later specific monotonic clock */
Packit 875988
  /* Available since Vista, ~15ms accuracy */
Packit 875988
  if (1)
Packit 875988
    {
Packit 875988
      tick_start = GetTickCount64 ();
Packit 875988
      mono_clock_source = _MHD_CLOCK_GETTICKCOUNT64;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#else  /* _WIN32_WINNT < 0x0600 */
Packit 875988
  /* W32 specific monotonic clock */
Packit 875988
  /* Available on Windows 2000 and later */
Packit 875988
  if (1)
Packit 875988
    {
Packit 875988
      LARGE_INTEGER freq;
Packit 875988
      LARGE_INTEGER perf_counter;
Packit 875988
Packit 875988
      QueryPerformanceFrequency (&freq); /* never fail on XP and later */
Packit 875988
      QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
Packit 875988
      perf_freq = freq.QuadPart;
Packit 875988
      perf_start = perf_counter.QuadPart;
Packit 875988
      mono_clock_source = _MHD_CLOCK_PERFCOUNTER;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* _WIN32_WINNT < 0x0600 */
Packit 875988
#endif /* _WIN32 */
Packit 875988
#ifdef HAVE_CLOCK_GETTIME
Packit 875988
#ifdef CLOCK_HIGHRES
Packit 875988
  /* Solaris-specific monotonic high-resolution clock */
Packit 875988
  /* Not preferred due to be potentially resource-hungry */
Packit 875988
  if (0 == clock_gettime (CLOCK_HIGHRES,
Packit 875988
                          &ts))
Packit 875988
    {
Packit 875988
      mono_clock_id = CLOCK_HIGHRES;
Packit 875988
      mono_clock_start = ts.tv_sec;
Packit 875988
      mono_clock_source = _MHD_CLOCK_GETTIME;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* CLOCK_HIGHRES */
Packit 875988
#endif /* HAVE_CLOCK_GETTIME */
Packit 875988
#ifdef HAVE_GETHRTIME
Packit 875988
  /* HP-UX and Solaris monotonic clock */
Packit 875988
  /* Not preferred due to be potentially resource-hungry */
Packit 875988
  if (1)
Packit 875988
    {
Packit 875988
      hrtime_start = gethrtime ();
Packit 875988
      mono_clock_source = _MHD_CLOCK_GETHRTIME;
Packit 875988
    }
Packit 875988
  else
Packit 875988
#endif /* HAVE_GETHRTIME */
Packit 875988
    {
Packit 875988
      /* no suitable clock source was found */
Packit 875988
      mono_clock_source = _MHD_CLOCK_NO_SOURCE;
Packit 875988
    }
Packit 875988
Packit 875988
#ifdef HAVE_CLOCK_GET_TIME
Packit 875988
  if ( (_MHD_CLOCK_GET_TIME != mono_clock_source) &&
Packit 875988
       (_MHD_INVALID_CLOCK_SERV != mono_clock_service) )
Packit 875988
    {
Packit 875988
      /* clock service was initialised but clock_get_time failed */
Packit 875988
      mach_port_deallocate (mach_task_self(),
Packit 875988
                            mono_clock_service);
Packit 875988
      mono_clock_service = _MHD_INVALID_CLOCK_SERV;
Packit 875988
    }
Packit 875988
#else
Packit 875988
  (void) mono_clock_source; /* avoid compiler warning */
Packit 875988
#endif /* HAVE_CLOCK_GET_TIME */
Packit 875988
Packit 875988
  sys_clock_start = time (NULL);
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Deinitialise monotonic seconds counter by freeing any allocated resources
Packit 875988
 */
Packit 875988
void
Packit 875988
MHD_monotonic_sec_counter_finish (void)
Packit 875988
{
Packit 875988
#ifdef HAVE_CLOCK_GET_TIME
Packit 875988
  if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
Packit 875988
    {
Packit 875988
      mach_port_deallocate (mach_task_self(),
Packit 875988
                            mono_clock_service);
Packit 875988
      mono_clock_service = _MHD_INVALID_CLOCK_SERV;
Packit 875988
    }
Packit 875988
#endif /* HAVE_CLOCK_GET_TIME */
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Monotonic seconds counter, useful for timeout calculation.
Packit 875988
 * Tries to be not affected by manually setting the system real time
Packit 875988
 * clock or adjustments by NTP synchronization.
Packit 875988
 *
Packit 875988
 * @return number of seconds from some fixed moment
Packit 875988
 */
Packit 875988
time_t
Packit 875988
MHD_monotonic_sec_counter (void)
Packit 875988
{
Packit 875988
#ifdef HAVE_CLOCK_GETTIME
Packit 875988
  struct timespec ts;
Packit 875988
Packit 875988
  if ( (_MHD_UNWANTED_CLOCK != mono_clock_id) &&
Packit 875988
       (0 == clock_gettime (mono_clock_id ,
Packit 875988
                            &ts)) )
Packit 875988
    return ts.tv_sec - mono_clock_start;
Packit 875988
#endif /* HAVE_CLOCK_GETTIME */
Packit 875988
#ifdef HAVE_CLOCK_GET_TIME
Packit 875988
  if (_MHD_INVALID_CLOCK_SERV != mono_clock_service)
Packit 875988
    {
Packit 875988
      mach_timespec_t cur_time;
Packit 875988
Packit 875988
      if (KERN_SUCCESS == clock_get_time(mono_clock_service,
Packit 875988
                                         &cur_time))
Packit 875988
        return cur_time.tv_sec - mono_clock_start;
Packit 875988
    }
Packit 875988
#endif /* HAVE_CLOCK_GET_TIME */
Packit 875988
#if defined(_WIN32)
Packit 875988
#if _WIN32_WINNT >= 0x0600
Packit 875988
  if (1)
Packit 875988
    return (time_t)(((uint64_t)(GetTickCount64() - tick_start)) / 1000);
Packit 875988
#else  /* _WIN32_WINNT < 0x0600 */
Packit 875988
  if (0 != perf_freq)
Packit 875988
    {
Packit 875988
      LARGE_INTEGER perf_counter;
Packit 875988
Packit 875988
      QueryPerformanceCounter (&perf_counter); /* never fail on XP and later */
Packit 875988
      return (time_t)(((uint64_t)(perf_counter.QuadPart - perf_start)) / perf_freq);
Packit 875988
    }
Packit 875988
#endif /* _WIN32_WINNT < 0x0600 */
Packit 875988
#endif /* _WIN32 */
Packit 875988
#ifdef HAVE_GETHRTIME
Packit 875988
  if (1)
Packit 875988
    return (time_t)(((uint64_t) (gethrtime () - hrtime_start)) / 1000000000);
Packit 875988
#endif /* HAVE_GETHRTIME */
Packit 875988
Packit 875988
  return time (NULL) - sys_clock_start;
Packit 875988
}