Blame gnulib-tests/nanosleep.c

Packit 33f14e
/* Provide a replacement for the POSIX nanosleep function.
Packit 33f14e
Packit 33f14e
   Copyright (C) 1999-2000, 2002, 2004-2017 Free Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   This program is free software: you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3 of the License, or
Packit 33f14e
   (at your option) any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License
Packit 33f14e
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
/* written by Jim Meyering
Packit 33f14e
   and Bruno Haible for the native Windows part */
Packit 33f14e
Packit 33f14e
#include <config.h>
Packit 33f14e
Packit 33f14e
#include <time.h>
Packit 33f14e
Packit 33f14e
#include "intprops.h"
Packit 33f14e
#include "sig-handler.h"
Packit 33f14e
#include "verify.h"
Packit 33f14e
Packit 33f14e
#include <stdbool.h>
Packit 33f14e
#include <stdio.h>
Packit 33f14e
#include <sys/types.h>
Packit 33f14e
#include <sys/select.h>
Packit 33f14e
#include <signal.h>
Packit 33f14e
Packit 33f14e
#include <sys/time.h>
Packit 33f14e
#include <errno.h>
Packit 33f14e
Packit 33f14e
#include <unistd.h>
Packit 33f14e
Packit 33f14e
Packit 33f14e
enum { BILLION = 1000 * 1000 * 1000 };
Packit 33f14e
Packit 33f14e
#if HAVE_BUG_BIG_NANOSLEEP
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
nanosleep (const struct timespec *requested_delay,
Packit 33f14e
           struct timespec *remaining_delay)
Packit 33f14e
# undef nanosleep
Packit 33f14e
{
Packit 33f14e
  /* nanosleep mishandles large sleeps due to internal overflow problems.
Packit 33f14e
     The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which
Packit 33f14e
     can't sleep more than 24.85 days (2^31 milliseconds).  Similarly,
Packit 33f14e
     cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds).
Packit 33f14e
     Solve this by breaking the sleep up into smaller chunks.  */
Packit 33f14e
Packit 33f14e
  if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
Packit 33f14e
    {
Packit 33f14e
      errno = EINVAL;
Packit 33f14e
      return -1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  {
Packit 33f14e
    /* Verify that time_t is large enough.  */
Packit 33f14e
    verify (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60);
Packit 33f14e
    const time_t limit = 24 * 24 * 60 * 60;
Packit 33f14e
    time_t seconds = requested_delay->tv_sec;
Packit 33f14e
    struct timespec intermediate;
Packit 33f14e
    intermediate.tv_nsec = requested_delay->tv_nsec;
Packit 33f14e
Packit 33f14e
    while (limit < seconds)
Packit 33f14e
      {
Packit 33f14e
        int result;
Packit 33f14e
        intermediate.tv_sec = limit;
Packit 33f14e
        result = nanosleep (&intermediate, remaining_delay);
Packit 33f14e
        seconds -= limit;
Packit 33f14e
        if (result)
Packit 33f14e
          {
Packit 33f14e
            if (remaining_delay)
Packit 33f14e
              remaining_delay->tv_sec += seconds;
Packit 33f14e
            return result;
Packit 33f14e
          }
Packit 33f14e
        intermediate.tv_nsec = 0;
Packit 33f14e
      }
Packit 33f14e
    intermediate.tv_sec = seconds;
Packit 33f14e
    return nanosleep (&intermediate, remaining_delay);
Packit 33f14e
  }
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#elif (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
Packit 33f14e
/* Native Windows platforms.  */
Packit 33f14e
Packit 33f14e
# define WIN32_LEAN_AND_MEAN
Packit 33f14e
# include <windows.h>
Packit 33f14e
Packit 33f14e
/* The Windows API function Sleep() has a resolution of about 15 ms and takes
Packit 33f14e
   at least 5 ms to execute.  We use this function for longer time periods.
Packit 33f14e
   Additionally, we use busy-looping over short time periods, to get a
Packit 33f14e
   resolution of about 0.01 ms.  In order to measure such short timespans,
Packit 33f14e
   we use the QueryPerformanceCounter() function.  */
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
nanosleep (const struct timespec *requested_delay,
Packit 33f14e
           struct timespec *remaining_delay)
Packit 33f14e
{
Packit 33f14e
  static bool initialized;
Packit 33f14e
  /* Number of performance counter increments per nanosecond,
Packit 33f14e
     or zero if it could not be determined.  */
Packit 33f14e
  static double ticks_per_nanosecond;
Packit 33f14e
Packit 33f14e
  if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
Packit 33f14e
    {
Packit 33f14e
      errno = EINVAL;
Packit 33f14e
      return -1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* For requested delays of one second or more, 15ms resolution is
Packit 33f14e
     sufficient.  */
Packit 33f14e
  if (requested_delay->tv_sec == 0)
Packit 33f14e
    {
Packit 33f14e
      if (!initialized)
Packit 33f14e
        {
Packit 33f14e
          /* Initialize ticks_per_nanosecond.  */
Packit 33f14e
          LARGE_INTEGER ticks_per_second;
Packit 33f14e
Packit 33f14e
          if (QueryPerformanceFrequency (&ticks_per_second))
Packit 33f14e
            ticks_per_nanosecond =
Packit 33f14e
              (double) ticks_per_second.QuadPart / 1000000000.0;
Packit 33f14e
Packit 33f14e
          initialized = true;
Packit 33f14e
        }
Packit 33f14e
      if (ticks_per_nanosecond)
Packit 33f14e
        {
Packit 33f14e
          /* QueryPerformanceFrequency worked.  We can use
Packit 33f14e
             QueryPerformanceCounter.  Use a combination of Sleep and
Packit 33f14e
             busy-looping.  */
Packit 33f14e
          /* Number of milliseconds to pass to the Sleep function.
Packit 33f14e
             Since Sleep can take up to 8 ms less or 8 ms more than requested
Packit 33f14e
             (or maybe more if the system is loaded), we subtract 10 ms.  */
Packit 33f14e
          int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10;
Packit 33f14e
          /* Determine how many ticks to delay.  */
Packit 33f14e
          LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond;
Packit 33f14e
          /* Start.  */
Packit 33f14e
          LARGE_INTEGER counter_before;
Packit 33f14e
          if (QueryPerformanceCounter (&counter_before))
Packit 33f14e
            {
Packit 33f14e
              /* Wait until the performance counter has reached this value.
Packit 33f14e
                 We don't need to worry about overflow, because the performance
Packit 33f14e
                 counter is reset at reboot, and with a frequency of 3.6E6
Packit 33f14e
                 ticks per second 63 bits suffice for over 80000 years.  */
Packit 33f14e
              LONGLONG wait_until = counter_before.QuadPart + wait_ticks;
Packit 33f14e
              /* Use Sleep for the longest part.  */
Packit 33f14e
              if (sleep_millis > 0)
Packit 33f14e
                Sleep (sleep_millis);
Packit 33f14e
              /* Busy-loop for the rest.  */
Packit 33f14e
              for (;;)
Packit 33f14e
                {
Packit 33f14e
                  LARGE_INTEGER counter_after;
Packit 33f14e
                  if (!QueryPerformanceCounter (&counter_after))
Packit 33f14e
                    /* QueryPerformanceCounter failed, but succeeded earlier.
Packit 33f14e
                       Should not happen.  */
Packit 33f14e
                    break;
Packit 33f14e
                  if (counter_after.QuadPart >= wait_until)
Packit 33f14e
                    /* The requested time has elapsed.  */
Packit 33f14e
                    break;
Packit 33f14e
                }
Packit 33f14e
              goto done;
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
  /* Implementation for long delays and as fallback.  */
Packit 33f14e
  Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000);
Packit 33f14e
Packit 33f14e
 done:
Packit 33f14e
  /* Sleep is not interruptible.  So there is no remaining delay.  */
Packit 33f14e
  if (remaining_delay != NULL)
Packit 33f14e
    {
Packit 33f14e
      remaining_delay->tv_sec = 0;
Packit 33f14e
      remaining_delay->tv_nsec = 0;
Packit 33f14e
    }
Packit 33f14e
  return 0;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#else
Packit 33f14e
/* Unix platforms lacking nanosleep. */
Packit 33f14e
Packit 33f14e
/* Some systems (MSDOS) don't have SIGCONT.
Packit 33f14e
   Using SIGTERM here turns the signal-handling code below
Packit 33f14e
   into a no-op on such systems. */
Packit 33f14e
# ifndef SIGCONT
Packit 33f14e
#  define SIGCONT SIGTERM
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
static sig_atomic_t volatile suspended;
Packit 33f14e
Packit 33f14e
/* Handle SIGCONT. */
Packit 33f14e
Packit 33f14e
static void
Packit 33f14e
sighandler (int sig)
Packit 33f14e
{
Packit 33f14e
  suspended = 1;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Suspend execution for at least *TS_DELAY seconds.  */
Packit 33f14e
Packit 33f14e
static int
Packit 33f14e
my_usleep (const struct timespec *ts_delay)
Packit 33f14e
{
Packit 33f14e
  struct timeval tv_delay;
Packit 33f14e
  tv_delay.tv_sec = ts_delay->tv_sec;
Packit 33f14e
  tv_delay.tv_usec = (ts_delay->tv_nsec + 999) / 1000;
Packit 33f14e
  if (tv_delay.tv_usec == 1000000)
Packit 33f14e
    {
Packit 33f14e
      if (tv_delay.tv_sec == TYPE_MAXIMUM (time_t))
Packit 33f14e
        tv_delay.tv_usec = 1000000 - 1; /* close enough */
Packit 33f14e
      else
Packit 33f14e
        {
Packit 33f14e
          tv_delay.tv_sec++;
Packit 33f14e
          tv_delay.tv_usec = 0;
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
  return select (0, NULL, NULL, NULL, &tv_delay);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
/* Suspend execution for at least *REQUESTED_DELAY seconds.  The
Packit 33f14e
   *REMAINING_DELAY part isn't implemented yet.  */
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
nanosleep (const struct timespec *requested_delay,
Packit 33f14e
           struct timespec *remaining_delay)
Packit 33f14e
{
Packit 33f14e
  static bool initialized;
Packit 33f14e
Packit 33f14e
  if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
Packit 33f14e
    {
Packit 33f14e
      errno = EINVAL;
Packit 33f14e
      return -1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* set up sig handler */
Packit 33f14e
  if (! initialized)
Packit 33f14e
    {
Packit 33f14e
      struct sigaction oldact;
Packit 33f14e
Packit 33f14e
      sigaction (SIGCONT, NULL, &oldact);
Packit 33f14e
      if (get_handler (&oldact) != SIG_IGN)
Packit 33f14e
        {
Packit 33f14e
          struct sigaction newact;
Packit 33f14e
Packit 33f14e
          newact.sa_handler = sighandler;
Packit 33f14e
          sigemptyset (&newact.sa_mask);
Packit 33f14e
          newact.sa_flags = 0;
Packit 33f14e
          sigaction (SIGCONT, &newact, NULL);
Packit 33f14e
        }
Packit 33f14e
      initialized = true;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  suspended = 0;
Packit 33f14e
Packit 33f14e
  if (my_usleep (requested_delay) == -1)
Packit 33f14e
    {
Packit 33f14e
      if (suspended)
Packit 33f14e
        {
Packit 33f14e
          /* Calculate time remaining.  */
Packit 33f14e
          /* FIXME: the code in sleep doesn't use this, so there's no
Packit 33f14e
             rush to implement it.  */
Packit 33f14e
Packit 33f14e
          errno = EINTR;
Packit 33f14e
        }
Packit 33f14e
      return -1;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* FIXME: Restore sig handler?  */
Packit 33f14e
Packit 33f14e
  return 0;
Packit 33f14e
}
Packit 33f14e
#endif