Blame gnulib/nanosleep.c

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