sys_ioctl: Simplify.
[gnulib.git] / tests / nap.h
blob5dd264f6df65f3445b7720de490bb9db6af8a1e1
1 /* Assist in file system timestamp tests.
2 Copyright (C) 2009-2020 Free Software Foundation, Inc.
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.
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.
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/>. */
17 /* Written by Eric Blake <ebb9@byu.net>, 2009. */
19 #ifndef GLTEST_NAP_H
20 # define GLTEST_NAP_H
22 # include <limits.h>
23 # include <stdbool.h>
25 # include <intprops.h>
27 /* Name of the witness file. */
28 #define TEMPFILE BASE "nap.tmp"
30 /* File descriptor used for the witness file. */
31 static int nap_fd = -1;
33 /* Return A - B, in ns.
34 Return 0 if the true result would be negative.
35 Return INT_MAX if the true result would be greater than INT_MAX. */
36 static int
37 diff_timespec (struct timespec a, struct timespec b)
39 time_t as = a.tv_sec;
40 time_t bs = b.tv_sec;
41 int ans = a.tv_nsec;
42 int bns = b.tv_nsec;
43 int sdiff;
45 ASSERT (0 <= ans && ans < 2000000000);
46 ASSERT (0 <= bns && bns < 2000000000);
48 if (! (bs < as || (bs == as && bns < ans)))
49 return 0;
51 if (INT_SUBTRACT_WRAPV (as, bs, &sdiff)
52 || INT_MULTIPLY_WRAPV (sdiff, 1000000000, &sdiff)
53 || INT_ADD_WRAPV (sdiff, ans - bns, &sdiff))
54 return INT_MAX;
56 return sdiff;
59 /* If DO_WRITE, bump the modification time of the file designated by NAP_FD.
60 Then fetch the new STAT information of NAP_FD. */
61 static void
62 nap_get_stat (struct stat *st, int do_write)
64 if (do_write)
66 ASSERT (write (nap_fd, "\n", 1) == 1);
67 #if defined _WIN32 || defined __CYGWIN__
68 /* On Windows, the modification times are not changed until NAP_FD
69 is closed. See
70 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-writefile> */
71 close (nap_fd);
72 nap_fd = open (TEMPFILE, O_RDWR, 0600);
73 ASSERT (nap_fd != -1);
74 lseek (nap_fd, 0, SEEK_END);
75 #endif
77 ASSERT (fstat (nap_fd, st) == 0);
80 /* Given a file whose descriptor is FD, see whether delaying by DELAY
81 nanoseconds causes a change in a file's mtime.
82 OLD_ST is the file's status, recently gotten. */
83 static bool
84 nap_works (int delay, struct stat old_st)
86 struct stat st;
87 struct timespec delay_spec;
88 delay_spec.tv_sec = delay / 1000000000;
89 delay_spec.tv_nsec = delay % 1000000000;
90 ASSERT (nanosleep (&delay_spec, 0) == 0);
91 nap_get_stat (&st, 1);
93 if (diff_timespec (get_stat_mtime (&st), get_stat_mtime (&old_st)))
94 return true;
96 return false;
99 static void
100 clear_temp_file (void)
102 if (0 <= nap_fd)
104 ASSERT (close (nap_fd) != -1);
105 ASSERT (unlink (TEMPFILE) != -1);
109 /* Sleep long enough to notice a timestamp difference on the file
110 system in the current directory. Use an adaptive approach, trying
111 to find the smallest delay which works on the current file system
112 to make the timestamp difference appear. Assert a maximum delay of
113 ~2 seconds, more precisely sum(2^n) from 0 to 30 = 2^31 - 1 = 2.1s.
114 Assumes that BASE is defined, and requires that the test module
115 depends on nanosleep. */
116 static void
117 nap (void)
119 struct stat old_st;
120 static int delay = 1;
122 if (-1 == nap_fd)
124 atexit (clear_temp_file);
125 ASSERT ((nap_fd = creat (TEMPFILE, 0600)) != -1);
126 nap_get_stat (&old_st, 0);
128 else
130 ASSERT (0 <= nap_fd);
131 nap_get_stat (&old_st, 1);
134 if (1 < delay)
135 delay = delay / 2; /* Try half of the previous delay. */
136 ASSERT (0 < delay);
138 for (;;)
140 if (nap_works (delay, old_st))
141 return;
142 if (delay <= (2147483647 - 1) / 2)
144 delay = delay * 2 + 1;
145 continue;
147 else
148 break;
151 /* Bummer: even the highest nap delay didn't work. */
152 ASSERT (0);
155 #endif /* GLTEST_NAP_H */