Blame gnulib/tests/nanosleep.c

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