1 /* Assist in file system timestamp tests.
2 Copyright (C) 2009-2013 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 <http://www.gnu.org/licenses/>. */
17 /* Written by Eric Blake <ebb9@byu.net>, 2009. */
24 /* Return A - B, in ns.
25 Return 0 if the true result would be negative.
26 Return INT_MAX if the true result would be greater than INT_MAX. */
28 diff_timespec (struct timespec a, struct timespec b)
35 if (! (bs < as || (bs == as && bns < ans)))
37 if (as - bs <= INT_MAX / 1000000000)
39 int sdiff = (as - bs) * 1000000000;
40 int usdiff = ans - bns;
41 if (usdiff < INT_MAX - sdiff)
42 return sdiff + usdiff;
48 get_stat (int fd, struct stat *st, int do_write)
51 ASSERT (write (fd, "\n", 1) == 1);
52 ASSERT (fstat (fd, st) == 0);
55 /* Given a file whose descriptor is FD, see whether delaying by DELAY
56 nanoseconds causes a change in a file's time stamp. *ST is the
57 file's status, recently gotten. Update *ST to reflect the latest
58 status gotten. If successful, return the needed delay, in
59 nanoseconds as determined by the observed time stamps; this may be
60 greater than DELAY if we crossed a quantization boundary. If
61 unsuccessful, return 0. */
63 nap_works (int fd, int delay, struct stat *st)
65 struct stat old_st = *st;
66 struct timespec delay_spec;
68 delay_spec.tv_sec = delay / 1000000000;
69 delay_spec.tv_nsec = delay % 1000000000;
70 ASSERT (nanosleep (&delay_spec, 0) == 0);
73 /* Return the greater of the ctime and the mtime differences, or
74 zero if it cannot be determined, or INT_MAX if either overflows. */
75 cdiff = diff_timespec (get_stat_ctime (st), get_stat_ctime (&old_st));
78 mdiff = diff_timespec (get_stat_mtime (st), get_stat_mtime (&old_st));
80 return cdiff < mdiff ? mdiff : cdiff;
88 /* Try a 1-ns sleep first, for speed. If that doesn't work, try 100
89 ns, 1 microsecond, 1 ms, etc. xfs has a quantization of about 10
90 milliseconds, even though it has a granularity of 1 nanosecond,
91 and NTFS has a default quantization of 15.25 milliseconds, even
92 though it has a granularity of 100 nanoseconds, so 15.25 ms is a
93 good quantization to try. If that doesn't work, try 1 second.
94 The worst case is 2 seconds, needed for FAT. */
95 static int const delaytab[] = {1, 1000, 1000000, 15250000, 1000000000 };
96 int fd = creat (BASE "tmp", 0600);
98 int delay = 2000000000;
101 get_stat (fd, &st, 0);
102 for (i = 0; i < sizeof delaytab / sizeof delaytab[0]; i++)
104 int d = nap_works (fd, delaytab[i], &st);
111 ASSERT (close (fd) == 0);
112 ASSERT (unlink (BASE "tmp") == 0);
116 /* Sleep long enough to notice a timestamp difference on the file
117 system in the current directory. Assumes that BASE is defined,
118 and requires that the test module depends on nanosleep. */
122 static struct timespec delay;
123 if (!delay.tv_sec && !delay.tv_nsec)
125 int d = guess_delay ();
127 /* Multiply by 1.125 (rounding up), to avoid problems if the
128 file system's clock is a bit slower than nanosleep's.
129 Ceiling it at INT_MAX, though. */
130 int delta = (d >> 3) + ((d & 7) != 0);
131 d = delta < INT_MAX - d ? d + delta : INT_MAX;
132 delay.tv_sec = d / 1000000000;
133 delay.tv_nsec = d % 1000000000;
135 ASSERT (nanosleep (&delay, 0) == 0);
138 #endif /* GLTEST_NAP_H */