(root)/
findutils-4.9.0/
gnulib-tests/
nanosleep.c
       1  /* Provide a replacement for the POSIX nanosleep function.
       2  
       3     Copyright (C) 1999-2000, 2002, 2004-2022 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  #include "sig-handler.h"
      27  #include "verify.h"
      28  
      29  #include <stdbool.h>
      30  #include <stdio.h>
      31  #include <sys/types.h>
      32  #include <sys/select.h>
      33  #include <signal.h>
      34  
      35  #include <sys/time.h>
      36  #include <errno.h>
      37  
      38  #include <unistd.h>
      39  
      40  
      41  enum { BILLION = 1000 * 1000 * 1000 };
      42  
      43  #if HAVE_BUG_BIG_NANOSLEEP
      44  
      45  int
      46  nanosleep (const struct timespec *requested_delay,
      47             struct timespec *remaining_delay)
      48  # undef nanosleep
      49  {
      50    /* nanosleep mishandles large sleeps due to internal overflow problems.
      51       The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which
      52       can't sleep more than 24.85 days (2^31 milliseconds).  Similarly,
      53       cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds).
      54       Solve this by breaking the sleep up into smaller chunks.  */
      55  
      56    if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
      57      {
      58        errno = EINVAL;
      59        return -1;
      60      }
      61  
      62    {
      63      /* Verify that time_t is large enough.  */
      64      verify (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60);
      65      const time_t limit = 24 * 24 * 60 * 60;
      66      time_t seconds = requested_delay->tv_sec;
      67      struct timespec intermediate;
      68      intermediate.tv_nsec = requested_delay->tv_nsec;
      69  
      70      while (limit < seconds)
      71        {
      72          int result;
      73          intermediate.tv_sec = limit;
      74          result = nanosleep (&intermediate, remaining_delay);
      75          seconds -= limit;
      76          if (result)
      77            {
      78              if (remaining_delay)
      79                remaining_delay->tv_sec += seconds;
      80              return result;
      81            }
      82          intermediate.tv_nsec = 0;
      83        }
      84      intermediate.tv_sec = seconds;
      85      return nanosleep (&intermediate, remaining_delay);
      86    }
      87  }
      88  
      89  #elif defined _WIN32 && ! defined __CYGWIN__
      90  /* Native Windows platforms.  */
      91  
      92  # define WIN32_LEAN_AND_MEAN
      93  # include <windows.h>
      94  
      95  /* The Windows API function Sleep() has a resolution of about 15 ms and takes
      96     at least 5 ms to execute.  We use this function for longer time periods.
      97     Additionally, we use busy-looping over short time periods, to get a
      98     resolution of about 0.01 ms.  In order to measure such short timespans,
      99     we use the QueryPerformanceCounter() function.  */
     100  
     101  int
     102  nanosleep (const struct timespec *requested_delay,
     103             struct timespec *remaining_delay)
     104  {
     105    static bool initialized;
     106    /* Number of performance counter increments per nanosecond,
     107       or zero if it could not be determined.  */
     108    static double ticks_per_nanosecond;
     109  
     110    if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
     111      {
     112        errno = EINVAL;
     113        return -1;
     114      }
     115  
     116    /* For requested delays of one second or more, 15ms resolution is
     117       sufficient.  */
     118    if (requested_delay->tv_sec == 0)
     119      {
     120        if (!initialized)
     121          {
     122            /* Initialize ticks_per_nanosecond.  */
     123            LARGE_INTEGER ticks_per_second;
     124  
     125            if (QueryPerformanceFrequency (&ticks_per_second))
     126              ticks_per_nanosecond =
     127                (double) ticks_per_second.QuadPart / 1000000000.0;
     128  
     129            initialized = true;
     130          }
     131        if (ticks_per_nanosecond)
     132          {
     133            /* QueryPerformanceFrequency worked.  We can use
     134               QueryPerformanceCounter.  Use a combination of Sleep and
     135               busy-looping.  */
     136            /* Number of milliseconds to pass to the Sleep function.
     137               Since Sleep can take up to 8 ms less or 8 ms more than requested
     138               (or maybe more if the system is loaded), we subtract 10 ms.  */
     139            int sleep_millis = (int) requested_delay->tv_nsec / 1000000 - 10;
     140            /* Determine how many ticks to delay.  */
     141            LONGLONG wait_ticks = requested_delay->tv_nsec * ticks_per_nanosecond;
     142            /* Start.  */
     143            LARGE_INTEGER counter_before;
     144            if (QueryPerformanceCounter (&counter_before))
     145              {
     146                /* Wait until the performance counter has reached this value.
     147                   We don't need to worry about overflow, because the performance
     148                   counter is reset at reboot, and with a frequency of 3.6E6
     149                   ticks per second 63 bits suffice for over 80000 years.  */
     150                LONGLONG wait_until = counter_before.QuadPart + wait_ticks;
     151                /* Use Sleep for the longest part.  */
     152                if (sleep_millis > 0)
     153                  Sleep (sleep_millis);
     154                /* Busy-loop for the rest.  */
     155                for (;;)
     156                  {
     157                    LARGE_INTEGER counter_after;
     158                    if (!QueryPerformanceCounter (&counter_after))
     159                      /* QueryPerformanceCounter failed, but succeeded earlier.
     160                         Should not happen.  */
     161                      break;
     162                    if (counter_after.QuadPart >= wait_until)
     163                      /* The requested time has elapsed.  */
     164                      break;
     165                  }
     166                goto done;
     167              }
     168          }
     169      }
     170    /* Implementation for long delays and as fallback.  */
     171    Sleep (requested_delay->tv_sec * 1000 + requested_delay->tv_nsec / 1000000);
     172  
     173   done:
     174    /* Sleep is not interruptible.  So there is no remaining delay.  */
     175    if (remaining_delay != NULL)
     176      {
     177        remaining_delay->tv_sec = 0;
     178        remaining_delay->tv_nsec = 0;
     179      }
     180    return 0;
     181  }
     182  
     183  #else
     184  /* Unix platforms lacking nanosleep. */
     185  
     186  /* Some systems (MSDOS) don't have SIGCONT.
     187     Using SIGTERM here turns the signal-handling code below
     188     into a no-op on such systems. */
     189  # ifndef SIGCONT
     190  #  define SIGCONT SIGTERM
     191  # endif
     192  
     193  static sig_atomic_t volatile suspended;
     194  
     195  /* Handle SIGCONT. */
     196  
     197  static _GL_ASYNC_SAFE void
     198  sighandler (int sig)
     199  {
     200    suspended = 1;
     201  }
     202  
     203  /* Suspend execution for at least *TS_DELAY seconds.  */
     204  
     205  static int
     206  my_usleep (const struct timespec *ts_delay)
     207  {
     208    struct timeval tv_delay;
     209    tv_delay.tv_sec = ts_delay->tv_sec;
     210    tv_delay.tv_usec = (ts_delay->tv_nsec + 999) / 1000;
     211    if (tv_delay.tv_usec == 1000000)
     212      {
     213        if (tv_delay.tv_sec == TYPE_MAXIMUM (time_t))
     214          tv_delay.tv_usec = 1000000 - 1; /* close enough */
     215        else
     216          {
     217            tv_delay.tv_sec++;
     218            tv_delay.tv_usec = 0;
     219          }
     220      }
     221    return select (0, NULL, NULL, NULL, &tv_delay);
     222  }
     223  
     224  /* Suspend execution for at least *REQUESTED_DELAY seconds.  The
     225     *REMAINING_DELAY part isn't implemented yet.  */
     226  
     227  int
     228  nanosleep (const struct timespec *requested_delay,
     229             struct timespec *remaining_delay)
     230  {
     231    static bool initialized;
     232  
     233    if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
     234      {
     235        errno = EINVAL;
     236        return -1;
     237      }
     238  
     239    /* set up sig handler */
     240    if (! initialized)
     241      {
     242        struct sigaction oldact;
     243  
     244        sigaction (SIGCONT, NULL, &oldact);
     245        if (get_handler (&oldact) != SIG_IGN)
     246          {
     247            struct sigaction newact;
     248  
     249            newact.sa_handler = sighandler;
     250            sigemptyset (&newact.sa_mask);
     251            newact.sa_flags = 0;
     252            sigaction (SIGCONT, &newact, NULL);
     253          }
     254        initialized = true;
     255      }
     256  
     257    suspended = 0;
     258  
     259    if (my_usleep (requested_delay) == -1)
     260      {
     261        if (suspended)
     262          {
     263            /* Calculate time remaining.  */
     264            /* FIXME: the code in sleep doesn't use this, so there's no
     265               rush to implement it.  */
     266  
     267            errno = EINTR;
     268          }
     269        return -1;
     270      }
     271  
     272    /* FIXME: Restore sig handler?  */
     273  
     274    return 0;
     275  }
     276  #endif