root/maint/gnulib/tests/nap.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. diff_timespec
  2. nap_get_stat
  3. nap_works
  4. clear_temp_file
  5. nap

   1 /* Assist in file system timestamp tests.
   2    Copyright (C) 2009-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3 of the License, or
   7    (at your option) any later version.
   8 
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Eric Blake <ebb9@byu.net>, 2009.  */
  18 
  19 #ifndef GLTEST_NAP_H
  20 # define GLTEST_NAP_H
  21 
  22 # include <limits.h>
  23 # include <stdbool.h>
  24 
  25 # include <intprops.h>
  26 
  27 /* Avoid a conflict with a function called nap() on UnixWare.  */
  28 # if defined _SCO_DS || (defined __SCO_VERSION__ || defined __sysv5__)  /* OpenServer, UnixWare */
  29 #  include <unistd.h>
  30 #  undef nap
  31 #  define nap gl_nap
  32 # endif
  33 
  34 /* Name of the witness file.  */
  35 #define TEMPFILE BASE "nap.tmp"
  36 
  37 /* File descriptor used for the witness file.  */
  38 static int nap_fd = -1;
  39 
  40 /* Return A - B, in ns.
  41    Return 0 if the true result would be negative.
  42    Return INT_MAX if the true result would be greater than INT_MAX.  */
  43 static int
  44 diff_timespec (struct timespec a, struct timespec b)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46   time_t as = a.tv_sec;
  47   time_t bs = b.tv_sec;
  48   int ans = a.tv_nsec;
  49   int bns = b.tv_nsec;
  50   int sdiff;
  51 
  52   ASSERT (0 <= ans && ans < 2000000000);
  53   ASSERT (0 <= bns && bns < 2000000000);
  54 
  55   if (! (bs < as || (bs == as && bns < ans)))
  56     return 0;
  57 
  58   if (INT_SUBTRACT_WRAPV (as, bs, &sdiff)
  59       || INT_MULTIPLY_WRAPV (sdiff, 1000000000, &sdiff)
  60       || INT_ADD_WRAPV (sdiff, ans - bns, &sdiff))
  61     return INT_MAX;
  62 
  63   return sdiff;
  64 }
  65 
  66 /* If DO_WRITE, bump the modification time of the file designated by NAP_FD.
  67    Then fetch the new STAT information of NAP_FD.  */
  68 static void
  69 nap_get_stat (struct stat *st, int do_write)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71   if (do_write)
  72     {
  73       ASSERT (write (nap_fd, "\n", 1) == 1);
  74 #if defined _WIN32 || defined __CYGWIN__
  75       /* On Windows, the modification times are not changed until NAP_FD
  76          is closed. See
  77          <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-writefile> */
  78       close (nap_fd);
  79       nap_fd = open (TEMPFILE, O_RDWR, 0600);
  80       ASSERT (nap_fd != -1);
  81       lseek (nap_fd, 0, SEEK_END);
  82 #endif
  83     }
  84   ASSERT (fstat (nap_fd, st) == 0);
  85 }
  86 
  87 /* Given a file whose descriptor is FD, see whether delaying by DELAY
  88    nanoseconds causes a change in a file's mtime.
  89    OLD_ST is the file's status, recently gotten.  */
  90 static bool
  91 nap_works (int delay, struct stat old_st)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93   struct stat st;
  94   struct timespec delay_spec;
  95   delay_spec.tv_sec = delay / 1000000000;
  96   delay_spec.tv_nsec = delay % 1000000000;
  97   ASSERT (nanosleep (&delay_spec, 0) == 0);
  98   nap_get_stat (&st, 1);
  99 
 100   if (diff_timespec (get_stat_mtime (&st), get_stat_mtime (&old_st)))
 101     return true;
 102 
 103   return false;
 104 }
 105 
 106 static void
 107 clear_temp_file (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 {
 109   if (0 <= nap_fd)
 110     {
 111       ASSERT (close (nap_fd) != -1);
 112       ASSERT (unlink (TEMPFILE) != -1);
 113     }
 114 }
 115 
 116 /* Sleep long enough to notice a timestamp difference on the file
 117    system in the current directory.  Use an adaptive approach, trying
 118    to find the smallest delay which works on the current file system
 119    to make the timestamp difference appear.  Assert a maximum delay of
 120    ~2 seconds, more precisely sum(2^n) from 0 to 30 = 2^31 - 1 = 2.1s.
 121    Assumes that BASE is defined, and requires that the test module
 122    depends on nanosleep.  */
 123 static void
 124 nap (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126   struct stat old_st;
 127   static int delay = 1;
 128 
 129   if (-1 == nap_fd)
 130     {
 131       atexit (clear_temp_file);
 132       ASSERT ((nap_fd = creat (TEMPFILE, 0600)) != -1);
 133       nap_get_stat (&old_st, 0);
 134     }
 135   else
 136     {
 137       ASSERT (0 <= nap_fd);
 138       nap_get_stat (&old_st, 1);
 139     }
 140 
 141   if (1 < delay)
 142     delay = delay / 2;  /* Try half of the previous delay.  */
 143   ASSERT (0 < delay);
 144 
 145   for (;;)
 146     {
 147       if (nap_works (delay, old_st))
 148         return;
 149       if (delay <= (2147483647 - 1) / 2)
 150         {
 151           delay = delay * 2 + 1;
 152           continue;
 153         }
 154       else
 155         break;
 156     }
 157 
 158   /* Bummer: even the highest nap delay didn't work. */
 159   ASSERT (0);
 160 }
 161 
 162 #endif /* GLTEST_NAP_H */

/* [previous][next][first][last][top][bottom][index][help] */