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

Side by Side Diff: Python/pytime.c

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

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