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

Side by Side Diff: Python/pytime.c

Issue 22043: Use a monotonic clock to compute timeouts
Patch Set: Created 5 years, 2 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') | « Modules/timemodule.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
5
6 #if defined(__APPLE__)
7 #include <mach/mach_time.h> /* mach_absolute_time(), mach_timebase_info() */
8 #endif
9
10 #ifdef MS_WINDOWS
11 static OSVERSIONINFOEX winver;
4 #endif 12 #endif
5 13
6 static int 14 static int
7 pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info, int raise) 15 pygettimeofday(_PyTime_timeval *tp, _Py_clock_info_t *info, int raise)
8 { 16 {
9 #ifdef MS_WINDOWS 17 #ifdef MS_WINDOWS
10 FILETIME system_time; 18 FILETIME system_time;
11 ULARGE_INTEGER large; 19 ULARGE_INTEGER large;
12 ULONGLONG microseconds; 20 ULONGLONG microseconds;
13 21
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 assert(0); 111 assert(0);
104 tp->tv_sec = 0; 112 tp->tv_sec = 0;
105 tp->tv_usec = 0; 113 tp->tv_usec = 0;
106 } 114 }
107 } 115 }
108 116
109 int 117 int
110 _PyTime_gettimeofday_info(_PyTime_timeval *tp, _Py_clock_info_t *info) 118 _PyTime_gettimeofday_info(_PyTime_timeval *tp, _Py_clock_info_t *info)
111 { 119 {
112 return pygettimeofday(tp, info, 1); 120 return pygettimeofday(tp, info, 1);
121 }
122
123 static int
124 pymonotonic(_PyTime_timeval *tp, _Py_clock_info_t *info, int raise)
125 {
126 #if defined(MS_WINDOWS)
127 static ULONGLONG (*GetTickCount64) (void) = NULL;
128 static ULONGLONG (CALLBACK *Py_GetTickCount64)(void);
129 static int has_getickcount64 = -1;
AntoinePitrou 2014/08/31 02:24:18 You should fix the typo in the variable name.
haypo 2014/08/31 15:02:33 Oh, I just moved the code from timemodule.c. But o
130 ULONGLONG result;
131
132 assert(info == NULL || raise);
133
134 if (has_getickcount64 == -1) {
135 /* GetTickCount64() was added to Windows Vista */
136 if (winver.dwMajorVersion >= 6) {
137 HINSTANCE hKernel32;
138 hKernel32 = GetModuleHandleW(L"KERNEL32");
139 *(FARPROC*)&Py_GetTickCount64 = GetProcAddress(hKernel32,
140 "GetTickCount64");
141 has_getickcount64 = (Py_GetTickCount64 != NULL);
AntoinePitrou 2014/08/31 02:24:18 Is it expected to fail?
haypo 2014/08/31 15:02:33 MSDN documentation says that GetTickCount64() is a
142 }
143 else
144 has_getickcount64 = 0;
145 }
146
147 if (has_getickcount64) {
148 result = Py_GetTickCount64();
149 }
150 else {
151 static DWORD last_ticks = 0;
152 static DWORD n_overflow = 0;
153 DWORD ticks;
154
155 ticks = GetTickCount();
156 if (ticks < last_ticks)
157 n_overflow++;
158 last_ticks = ticks;
159
160 result = (ULONGLONG)n_overflow << 32;
161 result += ticks;
162 }
163
164 tp->tv_sec = result / 1000;
165 tp->tv_usec = (result % 1000) * 1000;
166
167 if (info) {
168 DWORD timeAdjustment, timeIncrement;
169 BOOL isTimeAdjustmentDisabled, ok;
170 if (has_getickcount64)
171 info->implementation = "GetTickCount64()";
172 else
173 info->implementation = "GetTickCount()";
174 info->monotonic = 1;
175 ok = GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
176 &isTimeAdjustmentDisabled);
177 if (!ok) {
178 PyErr_SetFromWindowsErr(0);
179 return -1;
180 }
181 info->resolution = timeIncrement * 1e-7;
182 info->adjustable = 0;
183 }
184 return 0;
185
186 #elif defined(__APPLE__)
187 static mach_timebase_info_data_t timebase;
188 uint64_t time;
189
190 if (timebase.denom == 0) {
191 /* According to the Technical Q&A QA1398, mach_timebase_info() cannot
192 fail: https://developer.apple.com/library/mac/#qa/qa1398/ */
193 (void)mach_timebase_info(&timebase);
194 }
195
196 time = mach_absolute_time();
197
198 /* nanoseconds => microseconds */
199 time /= 1000;
200 /* apply timebase factor */
201 time *= timebase.numer;
202 time /= timebase.denom;
203 tp->tv_sec = time / (1000 * 1000);
204 tp->tv_usec = time % (1000 * 1000);
205
206 if (info) {
207 info->implementation = "mach_absolute_time()";
208 info->resolution = (double)timebase.numer / timebase.denom * 1e-9;
209 info->monotonic = 1;
210 info->adjustable = 0;
211 }
212 return 0;
213
214 #else
215 struct timespec ts;
216 #ifdef CLOCK_HIGHRES
217 const clockid_t clk_id = CLOCK_HIGHRES;
218 const char *implementation = "clock_gettime(CLOCK_HIGHRES)";
219 #else
220 const clockid_t clk_id = CLOCK_MONOTONIC;
221 const char *implementation = "clock_gettime(CLOCK_MONOTONIC)";
222 #endif
223
224 assert(info == NULL || raise);
225
226 if (clock_gettime(clk_id, &ts) != 0) {
227 if (raise) {
228 PyErr_SetFromErrno(PyExc_OSError);
229 return -1;
230 }
231 tp->tv_sec = 0;
232 tp->tv_usec = 0;
233 return -1;
AntoinePitrou 2014/08/31 02:24:18 The doc in pytime.h says that "the function never
haypo 2014/08/31 15:02:33 _PyTime_monotonic() never fails, _PyTime_monotonic
234 }
235
236 if (info) {
237 struct timespec res;
238 info->monotonic = 1;
239 info->implementation = implementation;
240 info->adjustable = 0;
241 if (clock_getres(clk_id, &res) != 0) {
242 PyErr_SetFromErrno(PyExc_OSError);
243 return -1;
244 }
245 info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
246 }
247 tp->tv_sec = ts.tv_sec;
248 tp->tv_usec = ts.tv_nsec / 1000;
249 return 0;
250 #endif
251 }
252
253 void
254 _PyTime_monotonic(_PyTime_timeval *tp)
255 {
256 if (pymonotonic(tp, NULL, 0) < 0) {
257 /* cannot happen, _PyTime_Init() checks that pygettimeofday() works */
AntoinePitrou 2014/08/31 02:24:18 s/pygettimeofday/pymonotonic/
258 assert(0);
259 tp->tv_sec = 0;
260 tp->tv_usec = 0;
261 }
262 }
263
264 int
265 _PyTime_monotonic_info(_PyTime_timeval *tp, _Py_clock_info_t *info)
266 {
267 return pymonotonic(tp, info, 1);
113 } 268 }
114 269
115 static void 270 static void
116 error_time_t_overflow(void) 271 error_time_t_overflow(void)
117 { 272 {
118 PyErr_SetString(PyExc_OverflowError, 273 PyErr_SetString(PyExc_OverflowError,
119 "timestamp out of range for platform time_t"); 274 "timestamp out of range for platform time_t");
120 } 275 }
121 276
122 time_t 277 time_t
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec, 396 _PyTime_ObjectToTimeval(PyObject *obj, time_t *sec, long *usec,
242 _PyTime_round_t round) 397 _PyTime_round_t round)
243 { 398 {
244 return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round); 399 return _PyTime_ObjectToDenominator(obj, sec, usec, 1e6, round);
245 } 400 }
246 401
247 int 402 int
248 _PyTime_Init(void) 403 _PyTime_Init(void)
249 { 404 {
250 _PyTime_timeval tv; 405 _PyTime_timeval tv;
406
407 #ifdef MS_WINDOWS
408 winver.dwOSVersionInfoSize = sizeof(winver);
409 if (!GetVersionEx((OSVERSIONINFO*)&winver)) {
410 PyErr_SetFromWindowsErr(0);
411 return -1;
412 }
413 #endif
414
251 /* ensure that the system clock works */ 415 /* ensure that the system clock works */
252 if (_PyTime_gettimeofday_info(&tv, NULL) < 0) 416 if (_PyTime_gettimeofday_info(&tv, NULL) < 0)
253 return -1; 417 return -1;
418
419 /* ensure that the operating system provides a monotonic clock */
420 if (_PyTime_monotonic_info(&tv, NULL) < 0)
421 return -1;
254 return 0; 422 return 0;
255 } 423 }
OLDNEW
« Modules/timemodule.c ('K') | « Modules/timemodule.c ('k') | no next file » | no next file with comments »

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