LCOV - code coverage report
Current view: top level - lib - xnanosleep.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 16 24 66.7 %
Date: 2018-01-30 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /* xnanosleep.c -- a more convenient interface to nanosleep
       2             : 
       3             :    Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software
       4             :    Foundation, Inc.
       5             : 
       6             :    This program is free software: you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      18             : 
      19             : /* Mostly written (for sleep.c) by Paul Eggert.
      20             :    Factored out (creating this file) by Jim Meyering.  */
      21             : 
      22             : #include <config.h>
      23             : 
      24             : #include "xnanosleep.h"
      25             : 
      26             : #include <limits.h>
      27             : #include <stdbool.h>
      28             : #include <stdio.h>
      29             : #include <assert.h>
      30             : #include <errno.h>
      31             : #include <sys/types.h>
      32             : #include <time.h>
      33             : 
      34             : #include "intprops.h"
      35             : 
      36             : #ifndef TIME_T_MAX
      37             : # define TIME_T_MAX TYPE_MAXIMUM (time_t)
      38             : #endif
      39             : 
      40             : /* Sleep until the time (call it WAKE_UP_TIME) specified as
      41             :    SECONDS seconds after the time this function is called.
      42             :    SECONDS must be non-negative.  If SECONDS is so large that
      43             :    it is not representable as a `struct timespec', then use
      44             :    the maximum value for that interval.  Return -1 on failure
      45             :    (setting errno), 0 on success.  */
      46             : 
      47             : int
      48           1 : xnanosleep (double seconds)
      49             : {
      50             :   enum { BILLION = 1000000000 };
      51             : 
      52             :   /* For overflow checking, use naive comparison if possible, widening
      53             :      to long double if double is not wide enough.  Otherwise, use <=,
      54             :      not <, to avoid problems when TIME_T_MAX is less than SECONDS but
      55             :      compares equal to SECONDS after loss of precision when coercing
      56             :      from time_t to long double.  This mishandles near-maximal values
      57             :      in some rare (perhaps theoretical) cases but that is better than
      58             :      undefined behavior.  */
      59           1 :   bool overflow = ((time_t) ((double) TIME_T_MAX / 2) == TIME_T_MAX / 2
      60             :                    ? TIME_T_MAX < seconds
      61             :                    : (time_t) ((long double) TIME_T_MAX / 2) == TIME_T_MAX / 2
      62           1 :                    ? TIME_T_MAX < (long double) seconds
      63             :                    : TIME_T_MAX <= (long double) seconds);
      64             : 
      65             :   struct timespec ts_sleep;
      66             : 
      67           1 :   assert (0 <= seconds);
      68             : 
      69             :   /* Separate whole seconds from nanoseconds.  */
      70           1 :   if (! overflow)
      71             :     {
      72           1 :       time_t floor_seconds = seconds;
      73           1 :       double ns = BILLION * (seconds - floor_seconds);
      74           1 :       ts_sleep.tv_sec = floor_seconds;
      75             : 
      76             :       /* Round up to the next whole number, if necessary, so that we
      77             :          always sleep for at least the requested amount of time.  Assuming
      78             :          the default rounding mode, we don't have to worry about the
      79             :          rounding error when computing 'ns' above, since the error won't
      80             :          cause 'ns' to drop below an integer boundary.  */
      81           1 :       ts_sleep.tv_nsec = ns;
      82           1 :       ts_sleep.tv_nsec += (ts_sleep.tv_nsec < ns);
      83             : 
      84             :       /* Normalize the interval length.  nanosleep requires this.  */
      85           1 :       if (BILLION <= ts_sleep.tv_nsec)
      86             :         {
      87           0 :           if (ts_sleep.tv_sec == TIME_T_MAX)
      88           0 :             overflow = true;
      89             :           else
      90             :             {
      91           0 :               ts_sleep.tv_sec++;
      92           0 :               ts_sleep.tv_nsec -= BILLION;
      93             :             }
      94             :         }
      95             :     }
      96             : 
      97             :   for (;;)
      98             :     {
      99           1 :       if (overflow)
     100             :         {
     101           0 :           ts_sleep.tv_sec = TIME_T_MAX;
     102           0 :           ts_sleep.tv_nsec = BILLION - 1;
     103             :         }
     104             : 
     105             :       /* Linux-2.6.8.1's nanosleep returns -1, but doesn't set errno
     106             :          when resumed after being suspended.  Earlier versions would
     107             :          set errno to EINTR.  nanosleep from linux-2.6.10, as well as
     108             :          implementations by (all?) other vendors, doesn't return -1
     109             :          in that case;  either it continues sleeping (if time remains)
     110             :          or it returns zero (if the wake-up time has passed).  */
     111           1 :       errno = 0;
     112           1 :       if (nanosleep (&ts_sleep, NULL) == 0)
     113           1 :         break;
     114           0 :       if (errno != EINTR && errno != 0)
     115           0 :         return -1;
     116             :     }
     117             : 
     118           1 :   return 0;
     119             : }

Generated by: LCOV version 1.10