source: trunk/src/sed/gnulib-tests/nap.h@ 3669

Last change on this file since 3669 was 3611, checked in by bird, 10 months ago

vendor/sed/current: GNU sed 4.9 (sed-4.9.tar.xz sha256:6e226b732e1cd739464ad6862bd1a1aba42d7982922da7a53519631d24975181)

File size: 4.3 KB
Line 
1/* Assist in file system timestamp tests.
2 Copyright (C) 2009-2022 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
24# include <stdckdint.h>
25
26/* Avoid a conflict with a function called nap() on UnixWare. */
27# if defined _SCO_DS || (defined __SCO_VERSION__ || defined __sysv5__) /* OpenServer, UnixWare */
28# include <unistd.h>
29# undef nap
30# define nap gl_nap
31# endif
32
33/* Name of the witness file. */
34#define TEMPFILE BASE "nap.tmp"
35
36/* File descriptor used for the witness file. */
37static int nap_fd = -1;
38
39/* Return A - B, in ns.
40 Return 0 if the true result would be negative.
41 Return INT_MAX if the true result would be greater than INT_MAX. */
42static int
43diff_timespec (struct timespec a, struct timespec b)
44{
45 time_t as = a.tv_sec;
46 time_t bs = b.tv_sec;
47 int ans = a.tv_nsec;
48 int bns = b.tv_nsec;
49 int sdiff;
50
51 ASSERT (0 <= ans && ans < 2000000000);
52 ASSERT (0 <= bns && bns < 2000000000);
53
54 if (! (bs < as || (bs == as && bns < ans)))
55 return 0;
56
57 if (ckd_sub (&sdiff, as, bs)
58 || ckd_mul (&sdiff, sdiff, 1000000000)
59 || ckd_add (&sdiff, sdiff, ans - bns))
60 return INT_MAX;
61
62 return sdiff;
63}
64
65/* If DO_WRITE, bump the modification time of the file designated by NAP_FD.
66 Then fetch the new STAT information of NAP_FD. */
67static void
68nap_get_stat (struct stat *st, int do_write)
69{
70 if (do_write)
71 {
72 ASSERT (write (nap_fd, "\n", 1) == 1);
73#if defined _WIN32 || defined __CYGWIN__
74 /* On Windows, the modification times are not changed until NAP_FD
75 is closed. See
76 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-writefile> */
77 close (nap_fd);
78 nap_fd = open (TEMPFILE, O_RDWR, 0600);
79 ASSERT (nap_fd != -1);
80 lseek (nap_fd, 0, SEEK_END);
81#endif
82 }
83 ASSERT (fstat (nap_fd, st) == 0);
84}
85
86/* Given a file whose descriptor is FD, see whether delaying by DELAY
87 nanoseconds causes a change in a file's mtime.
88 OLD_ST is the file's status, recently gotten. */
89static bool
90nap_works (int delay, struct stat old_st)
91{
92 struct stat st;
93 struct timespec delay_spec;
94 delay_spec.tv_sec = delay / 1000000000;
95 delay_spec.tv_nsec = delay % 1000000000;
96 ASSERT (nanosleep (&delay_spec, 0) == 0);
97 nap_get_stat (&st, 1);
98
99 if (diff_timespec (get_stat_mtime (&st), get_stat_mtime (&old_st)))
100 return true;
101
102 return false;
103}
104
105static void
106clear_temp_file (void)
107{
108 if (0 <= nap_fd)
109 {
110 ASSERT (close (nap_fd) != -1);
111 ASSERT (unlink (TEMPFILE) != -1);
112 }
113}
114
115/* Sleep long enough to notice a timestamp difference on the file
116 system in the current directory. Use an adaptive approach, trying
117 to find the smallest delay which works on the current file system
118 to make the timestamp difference appear. Assert a maximum delay of
119 ~2 seconds, more precisely sum(2^n) from 0 to 30 = 2^31 - 1 = 2.1s.
120 Assumes that BASE is defined, and requires that the test module
121 depends on nanosleep. */
122static void
123nap (void)
124{
125 struct stat old_st;
126 static int delay = 1;
127
128 if (-1 == nap_fd)
129 {
130 atexit (clear_temp_file);
131 ASSERT ((nap_fd = creat (TEMPFILE, 0600)) != -1);
132 nap_get_stat (&old_st, 0);
133 }
134 else
135 {
136 ASSERT (0 <= nap_fd);
137 nap_get_stat (&old_st, 1);
138 }
139
140 if (1 < delay)
141 delay = delay / 2; /* Try half of the previous delay. */
142 ASSERT (0 < delay);
143
144 for (;;)
145 {
146 if (nap_works (delay, old_st))
147 return;
148 if (delay <= (2147483647 - 1) / 2)
149 {
150 delay = delay * 2 + 1;
151 continue;
152 }
153 else
154 break;
155 }
156
157 /* Bummer: even the highest nap delay didn't work. */
158 ASSERT (0);
159}
160
161#endif /* GLTEST_NAP_H */
Note: See TracBrowser for help on using the repository browser.