Mercurial > hg > octave-lojdl > gnulib-hg
comparison tests/nap.h @ 17388:3c592b4deb04
utimensat-tests, etc.: try to fix some races
Problem reported by Bernhard Voelker in
<http://lists.gnu.org/archive/html/bug-gnulib/2013-04/msg00071.html>.
I don't know whether this patch fixes that race condition, but it
fixes *some* race conditions, so it should be a win.
* modules/chown-tests (Depends-on):
* modules/fchownat-tests (Depends-on):
* modules/fdutimensat-tests (Depends-on):
* modules/futimens-tests (Depends-on):
* modules/lchown-tests (Depends-on):
* modules/stat-time-tests (Depends-on):
* modules/utimens-tests (Depends-on):
* modules/utimensat-tests (Depends-on):
Depend on nanosleep, not usleep.
* modules/chown-tests (test_chown_LDADD):
* modules/lchown-tests (test_lchown_LDADD):
* modules/stat-time-tests (test_stat_time_LDADD):
New macro.
* modules/fchownat-tests (test_fchownat_LDADD):
* modules/fdutimensat-tests (test_fdutimensat_LDADD):
* modules/futimens-tests (test_futimens_LDADD):
* modules/utimens-tests (test_utimens_LDADD):
* modules/utimensat-tests (test_utimensat_LDADD):
Add $(LIB_NANOSLEEP).
* modules/stat-time-tests (Files): Add tests/nap.h.
* tests/nap.h: Include <limits.h>, for INT_MAX.
(lt_mtime): Remove.
(diff_timespec): New function.
(get_stat): Rename from get_mtime. All callers changed.
(nap_works): Determine the needed delay by inspecting the
file system's timestamp jumps; this should be more reliable.
Look at both mtime and ctime, and take the maximum of the two jumps.
(nap_works, guess_delay):
Return a nanosecond cound, not a microsecond count.
All callers changed.
(nap_works, nap): Use nanosleep, not usleep. Check for nanosleep
failure.
(nap): Multiply the guess by 1.125, to accommodate the case where
the file system's clock is a bit slower than nanosleep's clock.
* tests/test-stat-time.c (BASE): New macro.
Include nap.h.
(nap): Remove; nap.h now defines this. This removes a duplicate
implementation of 'nap'.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Tue, 30 Apr 2013 23:14:19 -0700 |
parents | e542fd46ad6f |
children | afd09cd62311 |
comparison
equal
deleted
inserted
replaced
17387:5f320210ead1 | 17388:3c592b4deb04 |
---|---|
17 /* Written by Eric Blake <ebb9@byu.net>, 2009. */ | 17 /* Written by Eric Blake <ebb9@byu.net>, 2009. */ |
18 | 18 |
19 #ifndef GLTEST_NAP_H | 19 #ifndef GLTEST_NAP_H |
20 # define GLTEST_NAP_H | 20 # define GLTEST_NAP_H |
21 | 21 |
22 # include <limits.h> | |
23 | |
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. */ | |
22 static int | 27 static int |
23 lt_mtime (struct stat const *a, struct stat const *b) | 28 diff_timespec (struct timespec a, struct timespec b) |
24 { | 29 { |
25 time_t as = a->st_mtime; | 30 time_t as = a.tv_sec; |
26 time_t bs = b->st_mtime; | 31 time_t bs = b.tv_sec; |
27 int ans = get_stat_mtime_ns (a); | 32 int ans = a.tv_nsec; |
28 int bns = get_stat_mtime_ns (b); | 33 int bns = b.tv_nsec; |
29 | 34 |
30 return as < bs || (as == bs && ans < bns); | 35 if (! (bs < as || (bs == as && bns < ans))) |
36 return 0; | |
37 if (as - bs <= INT_MAX / 1000000000) | |
38 { | |
39 int sdiff = (as - bs) * 1000000000; | |
40 int usdiff = ans - bns; | |
41 if (usdiff < INT_MAX - sdiff) | |
42 return sdiff + usdiff; | |
43 } | |
44 return INT_MAX; | |
31 } | 45 } |
32 | 46 |
33 static void | 47 static void |
34 get_mtime (int fd, struct stat *st, int do_write) | 48 get_stat (int fd, struct stat *st, int do_write) |
35 { | 49 { |
36 if (do_write) | 50 if (do_write) |
37 ASSERT (write (fd, "\n", 1) == 1); | 51 ASSERT (write (fd, "\n", 1) == 1); |
38 ASSERT (fstat (fd, st) == 0); | 52 ASSERT (fstat (fd, st) == 0); |
39 } | 53 } |
40 | 54 |
41 /* Given a file whose descriptor is FD, see whether delaying by DELAY | 55 /* Given a file whose descriptor is FD, see whether delaying by DELAY |
42 microseconds causes a change in a file's time stamp. If the time | 56 nanoseconds causes a change in a file's time stamp. *ST is the |
43 stamps differ, repeat the test one more time, in case we crossed a | 57 file's status, recently gotten. Update *ST to reflect the latest |
44 quantization boundary on a file system with lower resolution. *ST | 58 status gotten. If successful, return the needed delay, in |
45 is the file's status, recently gotten. Update *ST to reflect the | 59 nanoseconds as determined by the observed time stamps; this may be |
46 latest status gotten. */ | 60 greater than DELAY if we crossed a quantization boundary. If |
61 unsuccessful, return 0. */ | |
47 static int | 62 static int |
48 nap_works (int fd, int delay, struct stat *st) | 63 nap_works (int fd, int delay, struct stat *st) |
49 { | 64 { |
50 struct stat old_st; | 65 struct stat old_st = *st; |
51 old_st = *st; | 66 struct timespec delay_spec; |
52 usleep (delay); | 67 int cdiff, mdiff; |
53 get_mtime (fd, st, 1); | 68 delay_spec.tv_sec = delay / 1000000000; |
54 if (! lt_mtime (&old_st, st)) | 69 delay_spec.tv_nsec = delay % 1000000000; |
55 return 0; | 70 ASSERT (nanosleep (&delay_spec, 0) == 0); |
56 old_st = *st; | 71 get_stat (fd, st, 1); |
57 usleep (delay); | 72 |
58 get_mtime (fd, st, 1); | 73 /* Return the greater of the ctime and the mtime differences, or |
59 return lt_mtime (&old_st, st); | 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)); | |
76 if (cdiff != 0) | |
77 { | |
78 mdiff = diff_timespec (get_stat_mtime (st), get_stat_mtime (&old_st)); | |
79 if (mdiff != 0) | |
80 return cdiff < mdiff ? mdiff : cdiff; | |
81 } | |
82 return 0; | |
60 } | 83 } |
61 | 84 |
62 static int | 85 static int |
63 guess_delay (void) | 86 guess_delay (void) |
64 { | 87 { |
65 /* Try a 1-microsecond sleep first, for speed. If that doesn't | 88 /* Try a 1-ns sleep first, for speed. If that doesn't work, try 100 |
66 work, try a 1 ms sleep; that should work with ext. If it doesn't | 89 ns, 1 microsecond, 1 ms, etc. xfs has a quantization of about 10 |
67 work, try a 20 ms sleep. xfs has a quantization of about 10 | |
68 milliseconds, even though it has a granularity of 1 nanosecond, | 90 milliseconds, even though it has a granularity of 1 nanosecond, |
69 and NTFS has a default quantization of 15.25 milliseconds, even | 91 and NTFS has a default quantization of 15.25 milliseconds, even |
70 though it has a granularity of 100 nanoseconds, so 20 ms is a | 92 though it has a granularity of 100 nanoseconds, so 15.25 ms is a |
71 good quantization to try. If that doesn't work, try 1 second. | 93 good quantization to try. If that doesn't work, try 1 second. |
72 The worst case is 2 seconds, needed for FAT. */ | 94 The worst case is 2 seconds, needed for FAT. */ |
73 static int const delaytab[] = {1, 1000, 20000, 1000000 }; | 95 static int const delaytab[] = {1, 1000, 1000000, 15250000, 1000000000 }; |
74 int fd = creat (BASE "tmp", 0600); | 96 int fd = creat (BASE "tmp", 0600); |
75 int i; | 97 int i; |
76 int delay = 2000000; | 98 int delay = 2000000000; |
77 struct stat st; | 99 struct stat st; |
78 ASSERT (0 <= fd); | 100 ASSERT (0 <= fd); |
79 get_mtime (fd, &st, 0); | 101 get_stat (fd, &st, 0); |
80 for (i = 0; i < sizeof delaytab / sizeof delaytab[0]; i++) | 102 for (i = 0; i < sizeof delaytab / sizeof delaytab[0]; i++) |
81 if (nap_works (fd, delaytab[i], &st)) | 103 { |
82 { | 104 int d = nap_works (fd, delaytab[i], &st); |
83 delay = delaytab[i]; | 105 if (d != 0) |
84 break; | 106 { |
85 } | 107 delay = d; |
108 break; | |
109 } | |
110 } | |
86 ASSERT (close (fd) == 0); | 111 ASSERT (close (fd) == 0); |
87 ASSERT (unlink (BASE "tmp") == 0); | 112 ASSERT (unlink (BASE "tmp") == 0); |
88 return delay; | 113 return delay; |
89 } | 114 } |
90 | 115 |
91 /* Sleep long enough to notice a timestamp difference on the file | 116 /* Sleep long enough to notice a timestamp difference on the file |
92 system in the current directory. Assumes that BASE is defined, | 117 system in the current directory. Assumes that BASE is defined, |
93 and requires that the test module depends on usleep. */ | 118 and requires that the test module depends on nanosleep. */ |
94 static void | 119 static void |
95 nap (void) | 120 nap (void) |
96 { | 121 { |
97 static int delay; | 122 static struct timespec delay; |
98 if (!delay) | 123 if (!delay.tv_sec && !delay.tv_nsec) |
99 delay = guess_delay (); | 124 { |
100 usleep (delay); | 125 int d = guess_delay (); |
126 | |
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; | |
134 } | |
135 ASSERT (nanosleep (&delay, 0) == 0); | |
101 } | 136 } |
102 | 137 |
103 #endif /* GLTEST_NAP_H */ | 138 #endif /* GLTEST_NAP_H */ |