Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(98489)

Side by Side Diff: Python/pytime.c

Issue 22043: Use a monotonic clock to compute timeouts
Patch Set: Created 5 years, 3 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« Modules/timemodule.c ('K') | « Python/pythonrun.c ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #include "Python.h" 1 #include "Python.h"
2 #ifdef MS_WINDOWS 2 #ifdef MS_WINDOWS
3 #include <windows.h> 3 #include <windows.h>
4 #endif 4 #endif
5 5
6 #if defined(__APPLE__) && defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME) 6 #if defined(__APPLE__) && defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME)
7 /* 7 /*
8 * _PyTime_gettimeofday falls back to ftime when getttimeofday fails because t he latter 8 * pygettimeofday() falls back to ftime when getttimeofday fails because the
9 * might fail on some platforms. This fallback is unwanted on MacOSX because 9 * latter might fail on some platforms. This fallback is unwanted on MacOSX
10 * that makes it impossible to use a binary build on OSX 10.4 on earlier 10 * because that makes it impossible to use a binary build on OSX 10.4 on
11 * releases of the OS. Therefore claim we don't support ftime. 11 * earlier releases of the OS. Therefore claim we don't support ftime.
12 */ 12 */
13 # undef HAVE_FTIME 13 # undef HAVE_FTIME
14 #endif 14 #endif
15 15
16 #if defined(HAVE_FTIME) && !defined(MS_WINDOWS) 16 #if defined(HAVE_FTIME) && !defined(MS_WINDOWS)
17 #include <sys/timeb.h> 17 #include <sys/timeb.h>
18 extern int ftime(struct timeb *); 18 extern int ftime(struct timeb *);
19 #endif 19 #endif
20 20
21 #if SIZEOF_TIME_T == 8 && defined(HAVE_LONG_LONG)
22 # define TIME_T_MAX ((PY_LONG_LONG)0x7ffffffffffff)
Charles-François Natali 2014/07/31 19:50:26 I don't understand those values. Should it be UINT
haypo 2014/08/01 01:44:20 Done.
23 #elif SIZEOF_TIME_T == 8 && SIZEOF_LONG == 8
24 # define TIME_T_MAX 0x7ffffffffffffL
25 #elif SIZEOF_TIME_T == 4
26 # define TIME_T_MAX 0x7fffffff
27 #else
28 # error "unsupported size of time_t"
29 #endif
30
31 /* one second in milliseconds (ms, 10^-3) */
32 #define SEC_IN_MILLISECONDS (1000UL)
Charles-François Natali 2014/07/31 19:50:26 Why use the complete name for the denominator and
haypo 2014/08/01 01:44:20 Done.
33
34 /* one second in microseconds (us, 10^-6) */
35 #define SEC_IN_MICROSECONDS (1000000UL)
36
37 /* one second in nanoseconds (ns, 10^-9) */
38 #define SEC_IN_NANOSECONDS (1000000000UL)
39
40 /* one millisecond (ms, 10^-3) in nanoseconds (ns, 10^-9) */
41 #define MS_IN_NANOSECONDS (1000000UL)
42
43 /* one microsecond (us, 10^-6) in nanoseconds (ns, 10^-9) */
44 #define US_IN_NANOSECONDS (1000UL)
45
21 static void 46 static void
22 pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info) 47 error_time_t_overflow(void)
48 {
49 PyErr_SetString(PyExc_OverflowError,
50 "timestamp out of range for platform time_t");
51 }
52
53 static int
54 _PyTime_DoubleToDenominator(double d, time_t *sec, long *numerator,
55 double denominator, _PyTime_round_t round,
56 int raise)
57 {
58 double intpart, err;
59 /* volatile avoids unsafe optimization on float enabled by gcc -O3 */
60 volatile double floatpart;
61
62 assert(0 < denominator && denominator < 1.0);
63
64 floatpart = modf(d, &intpart);
65 if (floatpart < 0) {
66 floatpart = 1.0 + floatpart;
67 intpart -= 1.0;
68 }
69
70 floatpart *= denominator;
71 if (round == _PyTime_ROUND_UP) {
72 if (intpart >= 0) {
73 floatpart = ceil(floatpart);
74 if (floatpart >= denominator) {
75 floatpart -= denominator;
76 intpart += 1.0;
77 }
78 }
79 else {
80 floatpart = floor(floatpart);
81 }
82 }
83
84 *sec = (time_t)intpart;
85 err = intpart - (double)*sec;
86 if (err <= -1.0 || err >= 1.0) {
87 if (raise)
88 error_time_t_overflow();
89 return -1;
90 }
91
92 *numerator = (long)floatpart;
93 return 0;
94 }
95
96 static int
97 _PyTimeSpec_set_overflow(_PyTimeSpec *ts)
98 {
99 ts->tv_sec = TIME_T_MAX;
100 ts->tv_nsec = 999999999;
101 return -1;
102 }
103
104 static int
105 _PyTimeSpec_add(_PyTimeSpec *ts, time_t secs, long ns)
106 {
107 assert(ns < SEC_IN_NANOSECONDS);
108
109 if (ts->tv_sec > TIME_T_MAX - secs)
110 goto overflow;
111 ts->tv_sec += secs;
112
113 ts->tv_nsec += ns;
114 while (ts->tv_nsec >= SEC_IN_NANOSECONDS) {
115 ts->tv_nsec -= SEC_IN_NANOSECONDS;
116 if (ts->tv_sec == TIME_T_MAX)
117 goto overflow;
118 ts->tv_sec++;
119 }
120 return 0;
121
122 overflow:
123 return _PyTimeSpec_set_overflow(ts);
124 }
125
126
127 int
128 _PyTimeSpec_add_sec(_PyTimeSpec *ts, double seconds)
129 {
130 time_t secs;
131 long ns;
132
133 if (_PyTime_DoubleToDenominator(seconds, &secs,
134 &ns, 1e-9, _PyTime_ROUND_UP, 0) < 0)
135 return _PyTimeSpec_set_overflow(ts);
136
137 return _PyTimeSpec_add(ts, secs, ns);
138 }
139
140 int
141 _PyTimeSpec_add_us(_PyTimeSpec *ts,
142 _PyTime_unit_t microseconds)
143 {
144 _PyTime_unit_t secs, us;
145
146 us = microseconds % SEC_IN_MICROSECONDS;
147 secs = microseconds / SEC_IN_MICROSECONDS;
148 if (secs > TIME_T_MAX)
149 return _PyTimeSpec_set_overflow(ts);
150
151 return _PyTimeSpec_add(ts, (time_t)secs, us * US_IN_NANOSECONDS);
152 }
153
154 double
155 _PyTimeSpec_interval_sec(_PyTimeSpec *start, _PyTimeSpec *end)
156 {
157 double dt;
158 dt = end->tv_sec - start->tv_sec;
159 dt += (end->tv_nsec - start->tv_nsec) * 1e-9;
160 return dt;
161 }
162
163 _PyTime_unit_t
164 _PyTimeSpec_interval_us(_PyTimeSpec *start, _PyTimeSpec *end)
165 {
166 _PyTime_unit_t us;
167 time_t secs;
168
169 us = (end->tv_nsec - start->tv_nsec) / US_IN_NANOSECONDS;
170 secs = (end->tv_sec - start->tv_sec);
171 if (secs > (_PyTime_UNIT_MAX - us) * SEC_IN_MICROSECONDS)
172 goto overflow;
173 us += secs * SEC_IN_MICROSECONDS;
174 return us;
175
176 overflow:
177 return _PyTime_UNIT_MAX;
178 }
179
180 static int
181 pygettimeofday(_PyTimeSpec *ts, _Py_clock_info_t *info, int raise)
23 { 182 {
24 #ifdef MS_WINDOWS 183 #ifdef MS_WINDOWS
25 FILETIME system_time; 184 FILETIME system_time;
26 ULARGE_INTEGER large; 185 ULARGE_INTEGER large;
27 ULONGLONG microseconds; 186 ULONGLONG nanoseconds;
28 187
29 GetSystemTimeAsFileTime(&system_time); 188 GetSystemTimeAsFileTime(&system_time);
30 large.u.LowPart = system_time.dwLowDateTime; 189 large.u.LowPart = system_time.dwLowDateTime;
31 large.u.HighPart = system_time.dwHighDateTime; 190 large.u.HighPart = system_time.dwHighDateTime;
32 /* 11,644,473,600,000,000: number of microseconds between 191 /* 11,644,473,600,000,000,000: number of nanoseconds between
33 the 1st january 1601 and the 1st january 1970 (369 years + 89 leap 192 the 1st january 1601 and the 1st january 1970 (369 years + 89 leap
34 days). */ 193 days). */
35 microseconds = large.QuadPart / 10 - 11644473600000000; 194 nanoseconds = large.QuadPart * 100 - 11644473600000000000;
36 tp->tv_sec = microseconds / 1000000; 195 ts->tv_sec = nanoseconds / SEC_IN_NANOSECONDS;
37 tp->tv_usec = microseconds % 1000000; 196 ts->tv_nsec = nanoseconds % SEC_IN_NANOSECONDS;
38 if (info) { 197 if (info) {
39 DWORD timeAdjustment, timeIncrement; 198 DWORD timeAdjustment, timeIncrement;
40 BOOL isTimeAdjustmentDisabled; 199 BOOL isTimeAdjustmentDisabled;
41 200
42 info->implementation = "GetSystemTimeAsFileTime()"; 201 info->implementation = "GetSystemTimeAsFileTime()";
43 info->monotonic = 0; 202 info->monotonic = 0;
44 (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, 203 (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
45 &isTimeAdjustmentDisabled); 204 &isTimeAdjustmentDisabled);
46 info->resolution = timeIncrement * 1e-7; 205 info->resolution = timeIncrement * 1e-7;
47 info->adjustable = 1; 206 info->adjustable = 1;
48 } 207 }
208 return 0;
49 #else 209 #else
50 /* There are three ways to get the time: 210 /* There are four ways to get the time:
51 (1) gettimeofday() -- resolution in microseconds 211 (1) gettimeofday() -- resolution in microseconds
52 (2) ftime() -- resolution in milliseconds 212 (2) ftime() -- resolution in milliseconds
53 (3) time() -- resolution in seconds 213 (3) time() -- resolution in seconds
54 In all cases the return value in a timeval struct. 214 In all cases the return value in a timeval struct.
55 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may 215 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
56 fail, so we fall back on ftime() or time(). 216 fail, so we fall back on ftime() or time().
57 Note: clock resolution does not imply clock accuracy! */ 217 Note: clock resolution does not imply clock accuracy! */
58 218
219 #if defined(HAVE_GETTIMEOFDAY) || defined(HAVE_FTIME)
220 int err;
221 #endif
59 #ifdef HAVE_GETTIMEOFDAY 222 #ifdef HAVE_GETTIMEOFDAY
60 int err; 223 struct timeval tv;
224 #endif
225 #ifdef HAVE_FTIME
226 struct timeb tb;
227 #endif
228
229 /* test gettimeofday() */
230 #ifdef HAVE_GETTIMEOFDAY
61 #ifdef GETTIMEOFDAY_NO_TZ 231 #ifdef GETTIMEOFDAY_NO_TZ
62 err = gettimeofday(tp); 232 err = gettimeofday(&tv);
63 #else 233 #else
64 err = gettimeofday(tp, (struct timezone *)NULL); 234 err = gettimeofday(&tv, (struct timezone *)NULL);
65 #endif 235 #endif
66 if (err == 0) { 236 if (err && raise) {
237 PyErr_SetFromErrno(PyExc_OSError);
238 goto error;
239 }
240 if (!err) {
241 ts->tv_sec = tv.tv_sec;
242 ts->tv_nsec = tv.tv_usec * US_IN_NANOSECONDS;
67 if (info) { 243 if (info) {
68 info->implementation = "gettimeofday()"; 244 info->implementation = "gettimeofday()";
69 info->resolution = 1e-6; 245 info->resolution = 1e-6;
70 info->monotonic = 0; 246 info->monotonic = 0;
71 info->adjustable = 1; 247 info->adjustable = 1;
72 } 248 }
73 return; 249 return 0;
74 } 250 }
75 #endif /* HAVE_GETTIMEOFDAY */ 251 #endif /* HAVE_GETTIMEOFDAY */
76 252
77 #if defined(HAVE_FTIME) 253 /* test ftime() */
78 { 254 #ifdef HAVE_FTIME
79 struct timeb t; 255 err = ftime(&tb);
80 ftime(&t); 256 if (err && raise) {
81 tp->tv_sec = t.time; 257 PyErr_SetFromErrno(PyExc_OSError);
82 tp->tv_usec = t.millitm * 1000; 258 goto error;
259 }
260 if (!err) {
261 ts->tv_sec = tb.time;
262 ts->tv_nsec = tb.millitm * MS_IN_NANOSECONDS;
83 if (info) { 263 if (info) {
84 info->implementation = "ftime()"; 264 info->implementation = "ftime()";
85 info->resolution = 1e-3; 265 info->resolution = 1e-3;
86 info->monotonic = 0; 266 info->monotonic = 0;
87 info->adjustable = 1; 267 info->adjustable = 1;
88 } 268 }
269 return 0;
89 } 270 }
90 #else /* !HAVE_FTIME */ 271 #endif /* !HAVE_FTIME */
91 tp->tv_sec = time(NULL); 272
92 tp->tv_usec = 0; 273 errno = 0;
274 ts->tv_sec = time(NULL);
275 if (ts->tv_sec == (time_t)-1 && errno != 0) {
276 if (raise)
277 PyErr_SetFromErrno(PyExc_OSError);
278 goto error;
279 }
280 ts->tv_nsec = 0;
93 if (info) { 281 if (info) {
94 info->implementation = "time()"; 282 info->implementation = "time()";
95 info->resolution = 1.0; 283 info->resolution = 1.0;
96 info->monotonic = 0; 284 info->monotonic = 0;
97 info->adjustable = 1; 285 info->adjustable = 1;
98 } 286 }
99 #endif /* !HAVE_FTIME */ 287 return 0;
288
289 error:
290 ts->tv_sec = 0;
291 ts->tv_nsec = 0;
292 return -1;
100 293
101 #endif /* MS_WINDOWS */ 294 #endif /* MS_WINDOWS */
102 } 295 }
103 296
104 void 297 void
105 _PyTime_gettimeofday(_PyTime_timeval *tp) 298 _PyTimeSpec_get_time(_PyTimeSpec *tp)
106 { 299 {
107 pygettimeofday(tp, NULL); 300 /* _PyTimeSpec_Init() checked that the system clock works. */
301 (void)pygettimeofday(tp, NULL, 0);
108 } 302 }
109 303
110 void 304 int
111 _PyTime_gettimeofday_info(_PyTime_timeval *tp, _Py_clock_info_t *info) 305 _PyTimeSpec_get_time_info(_PyTimeSpec *tp, _Py_clock_info_t *info)
112 { 306 {
113 pygettimeofday(tp, info); 307 /* _PyTimeSpec_Init() checked that the system clock works. */
114 } 308 return pygettimeofday(tp, info, 1);
115
116 static void
117 error_time_t_overflow(void)
118 {
119 PyErr_SetString(PyExc_OverflowError,
120 "timestamp out of range for platform time_t");
121 } 309 }
122 310
123 time_t 311 time_t
124 _PyLong_AsTime_t(PyObject *obj) 312 _PyLong_AsTime_t(PyObject *obj)
125 { 313 {
126 #if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG 314 #if defined(HAVE_LONG_LONG) && SIZEOF_TIME_T == SIZEOF_LONG_LONG
127 PY_LONG_LONG val; 315 PY_LONG_LONG val;
128 val = PyLong_AsLongLong(obj); 316 val = PyLong_AsLongLong(obj);
129 #else 317 #else
130 long val; 318 long val;
(...skipping 18 matching lines...) Expand all
149 return PyLong_FromLong((long)t); 337 return PyLong_FromLong((long)t);
150 #endif 338 #endif
151 } 339 }
152 340
153 static int 341 static int
154 _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator, 342 _PyTime_ObjectToDenominator(PyObject *obj, time_t *sec, long *numerator,
155 double denominator, _PyTime_round_t round) 343 double denominator, _PyTime_round_t round)
156 { 344 {
157 assert(denominator <= LONG_MAX); 345 assert(denominator <= LONG_MAX);
158 if (PyFloat_Check(obj)) { 346 if (PyFloat_Check(obj)) {
159 double d, intpart, err; 347 double d = PyFloat_AsDouble(obj);
160 /* volatile avoids unsafe optimization on float enabled by gcc -O3 */ 348 return _PyTime_DoubleToDenominator(d, sec, numerator,
161 volatile double floatpart; 349 denominator, round, 1);
162
163 d = PyFloat_AsDouble(obj);
164 floatpart = modf(d, &intpart);
165 if (floatpart < 0) {
166 floatpart = 1.0 + floatpart;
167 intpart -= 1.0;
168 }
169
170 floatpart *= denominator;
171 if (round == _PyTime_ROUND_UP) {
172 if (intpart >= 0) {
173 floatpart = ceil(floatpart);
174 if (floatpart >= denominator) {
175 floatpart = 0.0;
176 intpart += 1.0;
177 }
178 }
179 else {
180 floatpart = floor(floatpart);
181 }
182 }
183
184 *sec = (time_t)intpart;
185 err = intpart - (double)*sec;
186 if (err <= -1.0 || err >= 1.0) {
187 error_time_t_overflow();
188 return -1;
189 }
190
191 *numerator = (long)floatpart;
192 return 0;
193 } 350 }
194 else { 351 else {
195 *sec = _PyLong_AsTime_t(obj); 352 *sec = _PyLong_AsTime_t(obj);
196 if (*sec == (time_t)-1 && PyErr_Occurred()) 353 if (*sec == (time_t)-1 && PyErr_Occurred())
197 return -1; 354 return -1;
198 *numerator = 0; 355 *numerator = 0;
199 return 0; 356 return 0;
200 } 357 }
201 } 358 }
202 359
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 return _PyTime_ObjectToDenominator(obj, sec, nsec, 1e9, round); 395 return _PyTime_ObjectToDenominator(obj, sec, nsec, 1e9, round);
239 } 396 }
240 397
241 int 398 int
242 _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec, 399 _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec,
243 _PyTime_round_t round) 400 _PyTime_round_t round)
244 { 401 {
245 return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round); 402 return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round);
246 } 403 }
247 404
248 void 405 int
249 _PyTime_Init() 406 _PyTimeSpec_Init(void)
250 { 407 {
251 /* Do nothing. Needed to force linking. */ 408 _PyTimeSpec ts;
409 /* ensure that the system clock works */
410 if (_PyTimeSpec_get_time_info(&ts, NULL) < 0)
411 return -1;
412 return 0;
252 } 413 }
OLDNEW
« Modules/timemodule.c ('K') | « Python/pythonrun.c ('k') | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+