(root)/
grep-3.11/
gnulib-tests/
nanosleep.c
       1  /* Provide a replacement for the POSIX nanosleep function.
       2  
       3     Copyright (C) 1999-2000, 2002, 2004-2023 Free Software Foundation, Inc.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     License, or (at your option) any later version.
       9  
      10     This file is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* written by Jim Meyering
      19     and Bruno Haible for the native Windows part */
      20  
      21  #include <config.h>
      22  
      23  #include <time.h>
      24  
      25  #include "intprops.h"
      26  
      27  #include <stdio.h>
      28  #include <sys/types.h>
      29  #include <sys/select.h>
      30  #include <signal.h>
      31  
      32  #include <errno.h>
      33  
      34  #include <unistd.h>
      35  
      36  
      37  enum { BILLION = 1000 * 1000 * 1000 };
      38  
      39  #if HAVE_BUG_BIG_NANOSLEEP
      40  
      41  int
      42  nanosleep (const struct timespec *requested_delay,
      43             struct timespec *remaining_delay)
      44  # undef nanosleep
      45  {
      46    /* nanosleep mishandles large sleeps due to internal overflow problems.
      47       The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which
      48       can't sleep more than 24.85 days (2^31 milliseconds).  Similarly,
      49       cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds).
      50       Solve this by breaking the sleep up into smaller chunks.  */
      51  
      52    if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
      53      {
      54        errno = EINVAL;
      55        return -1;
      56      }
      57  
      58    {
      59      /* Verify that time_t is large enough.  */
      60      static_assert (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60);
      61      const time_t limit = 24 * 24 * 60 * 60;
      62      time_t seconds = requested_delay->tv_sec;
      63      struct timespec intermediate;
      64      intermediate.tv_nsec = requested_delay->tv_nsec;
      65  
      66      while (limit < seconds)
      67        {
      68          int result;
      69          intermediate.tv_sec = limit;
      70          result = nanosleep (&intermediate, remaining_delay);
      71          seconds -= limit;
      72          if (result)
      73            {
      74              if (remaining_delay)
      75                remaining_delay->tv_sec += seconds;
      76              return result;
      77            }
      78          intermediate.tv_nsec = 0;
      79        }
      80      intermediate.tv_sec = seconds;
      81      return nanosleep (&intermediate, remaining_delay);
      82    }
      83  }
      84  
      85  #elif defined _WIN32 && ! defined __CYGWIN__
      86  /* Native Windows platforms.  */
      87  
      88  # define WIN32_LEAN_AND_MEAN
      89  # include <windows.h>
      90  
      91  /* The Windows API function Sleep() has a resolution of about 15 ms and takes
      92     at least 5 ms to execute.  We use this function for longer time periods.
      93     Additionally, we use busy-looping over short time periods, to get a
      94     resolution of about 0.01 ms.  In order to measure such short timespans,
      95     we use the QueryPerformanceCounter() function.  */
      96  
      97  int
      98  nanosleep (const struct timespec *requested_delay,
      99             struct timespec *remaining_delay)
     100  {
     101    static bool initialized;
     102    /* Number of performance counter increments per nanosecond,
     103       or zero if it could not be determined.  */
     104    static double ticks_per_nanosecond;
     105  
     106    if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
     107      {
     108        errno = EINVAL;
     109        return -1;
     110      }
     111  
     112    /* For requested delays of one second or more, 15ms resolution is
     113       sufficient.  */
     114    if (requested_delay->tv_sec == 0)
     115      {
     116        if (!initialized)
     117          {
     118            /* Initialize ticks_per_nanosecond.  */
     119            LARGE_INTEGER ticks_per_second;
     120  
     121            if (QueryPerformanceFrequency (&ticks_per_second))
     122              ticks_per_nanosecond =
     123                (double) ticks_per_second.QuadPart / 1000000000.0;
     124  
     125            initialized = true;
     126          }
     127        if (ticks_per_nanosecond)
     128          {
     129            /* QueryPerformanceFrequency worked.  We can use
     130               QueryPerformanceCounter.  Use a combination of Sleep and
     131               busy-looping.  */
     132            /* Number of milliseconds to pass to the Sleep function.
     133               Since Sleep can take up to 8 ms less or 8 ms more than requested
     134               (or maybe more if the system is loaded), we subtract 10 ms.  */
     135            int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10;
     136            /* Determine how many ticks to delay.  */
     137            LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond;
     138            /* Start.  */
     139            LARGE_INTEGER counter_before;
     140            if (QueryPerformanceCounter (&counter_before))
     141              {
     142                /* Wait until the performance counter has reached this value.
     143                   We don't need to worry about overflow, because the performance
     144                   counter is reset at reboot, and with a frequency of 3.6E6
     145                   ticks per second 63 bits suffice for over 80000 years.  */
     146                LONGLONG wait_until = counter_before.QuadPart + wait_ticks;
     147                /* Use Sleep for the longest part.  */
     148                if (sleep_millis > 0)
     149                  Sleep (sleep_millis);
     150                /* Busy-loop for the rest.  */
     151                for (;;)
     152                  {
     153                    LARGE_INTEGER counter_after;
     154                    if (!QueryPerformanceCounter (&counter_after))
     155                      /* QueryPerformanceCounter failed, but succeeded earlier.
     156                         Should not happen.  */
     157                      break;
     158                    if (counter_after.QuadPart >= wait_until)
     159                      /* The requested time has elapsed.  */
     160                      break;
     161                  }
     162                goto done;
     163              }
     164          }
     165      }
     166    /* Implementation for long delays and as fallback.  */
     167    Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000);
     168  
     169   done:
     170    /* Sleep is not interruptible.  So there is no remaining delay.  */
     171    if (remaining_delay != NULL)
     172      {
     173        remaining_delay->tv_sec = 0;
     174        remaining_delay->tv_nsec = 0;
     175      }
     176    return 0;
     177  }
     178  
     179  #else
     180  /* Other platforms lacking nanosleep.
     181     It's not clear whether these are still practical porting targets.
     182     For now, just fall back on pselect.  */
     183  
     184  /* Suspend execution for at least *REQUESTED_DELAY seconds.  The
     185     *REMAINING_DELAY part isn't implemented yet.  */
     186  
     187  int
     188  nanosleep (const struct timespec *requested_delay,
     189             struct timespec *remaining_delay)
     190  {
     191    return pselect (0, NULL, NULL, NULL, requested_delay, NULL);
     192  }
     193  #endif