Blame gl/tests/nanosleep.c

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