Mercurial > ~astiob > upreckon > hgweb
comparison upreckon/win32.py @ 146:d5b6708c1955
Distutils support, reorganization and cleaning up
* Removed command-line options -t and -u.
* Reorganized code:
o all modules are now in package upreckon;
o TestCaseNotPassed and its descendants now live in a separate
module exceptions;
o load_problem now lives in module problem.
* Commented out mentions of command-line option -c in --help.
* Added a distutils-based setup.py.
author | Oleg Oshmyan <chortos@inbox.lv> |
---|---|
date | Sat, 28 May 2011 14:24:25 +0100 |
parents | win32.py@98bccf81db4d |
children | aa343ff41c27 |
comparison
equal
deleted
inserted
replaced
145:d2c266c8d820 | 146:d5b6708c1955 |
---|---|
1 # Copyright (c) 2010-2011 Chortos-2 <chortos@inbox.lv> | |
2 | |
3 from __future__ import division, with_statement | |
4 | |
5 from .compat import * | |
6 from .exceptions import * | |
7 | |
8 from ctypes import * | |
9 from ctypes.wintypes import * | |
10 from msvcrt import getch as pause | |
11 from time import clock | |
12 import os, subprocess, sys, time | |
13 | |
14 try: | |
15 from _winreg import * | |
16 except ImportError: | |
17 from winreg import * | |
18 | |
19 # Defaults that may be overwritten by values from _subprocess | |
20 INFINITE = -1 | |
21 STD_INPUT_HANDLE = -10 | |
22 WAIT_OBJECT_0 = 0 | |
23 | |
24 try: | |
25 from _subprocess import * | |
26 except ImportError: | |
27 pass | |
28 | |
29 try: | |
30 from numbers import Integral | |
31 except ImportError: | |
32 Integral = int, long | |
33 | |
34 try: | |
35 from collections import namedtuple | |
36 except ImportError: | |
37 from operator import itemgetter | |
38 class ProcessTimes(tuple): | |
39 __slots__ = () | |
40 def __new__(cls, creation, exit, kernel, user): | |
41 return tuple.__new__(cls, (creation, exit, kernel, user)) | |
42 __getnewargs__ = lambda self: tuple(self) | |
43 creation, exit, kernel, user = map(property, map(itemgetter, range(4))) | |
44 else: | |
45 ProcessTimes = namedtuple('ProcessTimes', 'creation exit kernel user') | |
46 | |
47 __all__ = 'call', 'kill', 'pause', 'clock' | |
48 | |
49 | |
50 from functools import wraps | |
51 pathext = [''] + os.environ['PATHEXT'].split(';') | |
52 @wraps(subprocess.Popen) | |
53 def Popen(cmdline, *args, **kwargs): | |
54 try: | |
55 return subprocess.Popen(cmdline, *args, **kwargs) | |
56 except WindowsError: | |
57 for ext in pathext: | |
58 path = cmdline[0] + ext | |
59 newcmdline = type(cmdline)((path,)) + cmdline[1:] | |
60 try: | |
61 return subprocess.Popen(newcmdline, *args, **kwargs) | |
62 except WindowsError: | |
63 pass | |
64 for branch in HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE: | |
65 try: | |
66 path = (R'SOFTWARE\Microsoft\Windows\CurrentVersion' | |
67 R'\App Paths\%s%s' % (cmdline[0], ext)) | |
68 path = QueryValue(branch, path) | |
69 break | |
70 except WindowsError: | |
71 pass | |
72 else: | |
73 continue | |
74 if path[0] == '"' == path[-1]: | |
75 path = path[1:-1] | |
76 newcmdline = type(cmdline)((path,)) + cmdline[1:] | |
77 try: | |
78 return subprocess.Popen(newcmdline, *args, **kwargs) | |
79 except WindowsError: | |
80 pass | |
81 # I'd like to transparently re-raise the exception generated | |
82 # on the very first try, but syntax differences preclude me from | |
83 # doing so in Python 2 and it can't be done at all in Python 3 | |
84 raise | |
85 | |
86 | |
87 # Automatically convert _subprocess handle objects into low-level | |
88 # HANDLEs and replicate their functionality for our own use | |
89 try: | |
90 _subprocess_handle = type(GetCurrentProcess()) | |
91 except NameError: | |
92 _subprocess_handle = Integral | |
93 class Handle(object): | |
94 @staticmethod | |
95 def from_param(handle): | |
96 if isinstance(handle, (_subprocess_handle, Integral)): | |
97 return HANDLE(int(handle)) | |
98 elif isinstance(handle, Handle): | |
99 return HANDLE(handle.handle) | |
100 elif isinstance(handle, HANDLE): | |
101 return handle | |
102 else: | |
103 raise TypeError('cannot convert %s to a handle' % | |
104 type(handle).__name__) | |
105 | |
106 __slots__ = 'handle' | |
107 | |
108 def __init__(self, handle): | |
109 if isinstance(handle, Integral): | |
110 self.handle = handle | |
111 elif isinstance(handle, HANDLE): | |
112 self.handle = handle.value | |
113 elif isinstance(handle, Handle): | |
114 self.handle = handle.handle | |
115 elif isinstance(handle, _subprocess_handle): | |
116 handle = HANDLE(int(handle)) | |
117 flags = DWORD() | |
118 try: | |
119 if windll.kernel32.GetHandleInformation(handle, byref(flags)): | |
120 flags = flags.value | |
121 else: | |
122 flags = 0 | |
123 except AttributeError: | |
124 # Available on NT 3.51 and up, NT line only | |
125 flags = 0 | |
126 proc = HANDLE(int(GetCurrentProcess())) | |
127 handle = DuplicateHandle(proc, handle, proc, 0, flags & 1, 2) | |
128 self.handle = handle.Detach() | |
129 else: | |
130 raise TypeError("Handle() argument must be a handle, not '%s'" % | |
131 type(handle).__name__) | |
132 | |
133 def __int__(self): | |
134 return int(self.handle) | |
135 | |
136 def Detach(self): | |
137 handle = self.handle | |
138 self.handle = None | |
139 return handle | |
140 | |
141 # This is also __del__, so only locals are accessed | |
142 def Close(self, _CloseHandle=windll.kernel32.CloseHandle, _HANDLE=HANDLE): | |
143 if getattr(self, 'handle', None): | |
144 _CloseHandle(_HANDLE(self.handle)) | |
145 self.handle = None | |
146 __del__ = Close | |
147 | |
148 CHAR = c_char | |
149 INVALID_HANDLE_VALUE = HANDLE(-1).value | |
150 LPDWORD = POINTER(DWORD) | |
151 LPFILETIME = POINTER(FILETIME) | |
152 SIZE_T = ULONG_PTR = WPARAM | |
153 ULONGLONG = c_ulonglong | |
154 | |
155 try: | |
156 unicode | |
157 except NameError: | |
158 LPCTSTR = LPCWSTR | |
159 UNISUFFIX = 'W' | |
160 else: | |
161 LPCTSTR = LPCSTR | |
162 UNISUFFIX = 'A' | |
163 | |
164 | |
165 prototype = WINFUNCTYPE(BOOL, Handle, | |
166 LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME) | |
167 flags = ((1, 'process'), | |
168 (2, 'creation'), (2, 'exit'), (2, 'kernel'), (2, 'user')) | |
169 try: | |
170 GetProcessTimes = prototype(('GetProcessTimes', windll.kernel32), flags) | |
171 except AttributeError: | |
172 # Available on NT 3.5 and up, NT line only | |
173 GetProcessTimes = None | |
174 else: | |
175 def errcheck(result, func, args): | |
176 if not result: raise WinError() | |
177 times = ((t.dwHighDateTime << 32 | t.dwLowDateTime) / 10000000 | |
178 for t in args[1:]) | |
179 return ProcessTimes(*times) | |
180 GetProcessTimes.errcheck = errcheck | |
181 | |
182 | |
183 class PROCESS_MEMORY_COUNTERS(Structure): | |
184 _fields_ = (('cb', DWORD), | |
185 ('PageFaultCount', DWORD), | |
186 ('PeakWorkingSetSize', SIZE_T), | |
187 ('WorkingSetSize', SIZE_T), | |
188 ('QuotaPeakPagedPoolUsage', SIZE_T), | |
189 ('QuotaPagedPoolUsage', SIZE_T), | |
190 ('QuotaPeakNonPagedPoolUsage', SIZE_T), | |
191 ('QuotaNonPagedPoolUsage', SIZE_T), | |
192 ('PagefileUsage', SIZE_T), | |
193 ('PeakPagefileUsage', SIZE_T)) | |
194 | |
195 prototype = WINFUNCTYPE(BOOL, Handle, POINTER(PROCESS_MEMORY_COUNTERS), DWORD) | |
196 flags = ((1, 'process'), (2, 'counters'), | |
197 (5, 'cb', sizeof(PROCESS_MEMORY_COUNTERS))) | |
198 try: | |
199 GetProcessMemoryInfo = prototype(('GetProcessMemoryInfo', windll.psapi), | |
200 flags) | |
201 except AttributeError: | |
202 # Available on NT 4.0 and up, NT line only | |
203 GetProcessMemoryInfo = None | |
204 else: | |
205 def errcheck(result, func, args): | |
206 if not result: raise WinError() | |
207 return args | |
208 GetProcessMemoryInfo.errcheck = errcheck | |
209 | |
210 | |
211 class _uChar_union(Union): | |
212 _fields_ = (('UnicodeChar', WCHAR), | |
213 ('AsciiChar', CHAR)) | |
214 | |
215 class KEY_EVENT_RECORD(Structure): | |
216 _fields_ = (('bKeyDown', BOOL), | |
217 ('wRepeatCount', WORD), | |
218 ('wVirtualKeyCode', WORD), | |
219 ('wVirtualScanCode', WORD), | |
220 ('uChar', _uChar_union), | |
221 ('dwControlKeyState', DWORD)) | |
222 | |
223 RIGHT_ALT_PRESSED = 0x001 | |
224 LEFT_ALT_PRESSED = 0x002 | |
225 RIGHT_CTRL_PRESSED = 0x004 | |
226 LEFT_CTRL_PRESSED = 0x008 | |
227 SHIFT_PRESSED = 0x010 | |
228 NUMLOCK_ON = 0x020 | |
229 SCROLLLOCK_ON = 0x040 | |
230 CAPSLOCK_ON = 0x080 | |
231 ENHANCED_KEY = 0x100 | |
232 | |
233 class _Event_union(Union): | |
234 _fields_ = ('KeyEvent', KEY_EVENT_RECORD), | |
235 | |
236 class INPUT_RECORD(Structure): | |
237 _fields_ = (('EventType', WORD), | |
238 ('Event', _Event_union)) | |
239 | |
240 KEY_EVENT = 0x01 | |
241 MOUSE_EVENT = 0x02 | |
242 WINDOW_BUFFER_SIZE_EVENT = 0x04 | |
243 MENU_EVENT = 0x08 | |
244 FOCUS_EVENT = 0x10 | |
245 | |
246 prototype = WINFUNCTYPE(BOOL, Handle, POINTER(INPUT_RECORD), DWORD, LPDWORD) | |
247 flags = (1, 'input'), (2, 'buffer'), (5, 'length', 1), (2, 'number_read') | |
248 ReadConsoleInput = prototype(('ReadConsoleInputA', windll.kernel32), flags) | |
249 def errcheck(result, func, args): | |
250 if not result: raise WinError() | |
251 return args[1] if args[3] else None | |
252 ReadConsoleInput.errcheck = errcheck | |
253 | |
254 | |
255 prototype = WINFUNCTYPE(BOOL, Handle) | |
256 flags = (1, 'input'), | |
257 FlushConsoleInputBuffer = prototype(('FlushConsoleInputBuffer', | |
258 windll.kernel32), flags) | |
259 def errcheck(result, func, args): | |
260 if not result: raise WinError() | |
261 FlushConsoleInputBuffer.errcheck = errcheck | |
262 | |
263 | |
264 prototype = WINFUNCTYPE(BOOL, Handle, DWORD) | |
265 flags = (1, 'console'), (1, 'mode') | |
266 SetConsoleMode = prototype(('SetConsoleMode', windll.kernel32), flags) | |
267 def errcheck(result, func, args): | |
268 if not result: raise WinError() | |
269 SetConsoleMode.errcheck = errcheck | |
270 | |
271 ENABLE_PROCESSED_INPUT = 0x001 | |
272 ENABLE_LINE_INPUT = 0x002 | |
273 ENABLE_ECHO_INPUT = 0x004 | |
274 ENABLE_WINDOW_INPUT = 0x008 | |
275 ENABLE_MOUSE_INPUT = 0x010 | |
276 ENABLE_INSERT_MODE = 0x020 | |
277 ENABLE_QUICK_EDIT_MODE = 0x040 | |
278 ENABLE_EXTENDED_FLAGS = 0x080 | |
279 | |
280 ENABLE_PROCESSED_OUTPUT = 1 | |
281 ENABLE_WRAP_AT_EOL_OUTPUT = 2 | |
282 | |
283 | |
284 prototype = WINFUNCTYPE(HANDLE, c_void_p, LPCTSTR) | |
285 flags = (5, 'attributes'), (1, 'name') | |
286 try: | |
287 CreateJobObject = prototype(('CreateJobObject'+UNISUFFIX, windll.kernel32), | |
288 flags) | |
289 except AttributeError: | |
290 # Available on 2000 and up, NT line only | |
291 CreateJobObject = lambda name: None | |
292 else: | |
293 def errcheck(result, func, args): | |
294 if not result: raise WinError() | |
295 return Handle(result) | |
296 CreateJobObject.errcheck = errcheck | |
297 | |
298 | |
299 prototype = WINFUNCTYPE(BOOL, Handle, Handle) | |
300 flags = (1, 'job'), (1, 'handle') | |
301 try: | |
302 AssignProcessToJobObject = prototype(('AssignProcessToJobObject', | |
303 windll.kernel32), flags) | |
304 except AttributeError: | |
305 # Available on 2000 and up, NT line only | |
306 AssignProcessToJobObject = lambda job, handle: None | |
307 else: | |
308 def errcheck(result, func, args): | |
309 if not result: raise WinError() | |
310 AssignProcessToJobObject.errcheck = errcheck | |
311 | |
312 | |
313 class JOBOBJECT_BASIC_LIMIT_INFORMATION(Structure): | |
314 _fields_ = (('PerProcessUserTimeLimit', LARGE_INTEGER), | |
315 ('PerJobUserTimeLimit', LARGE_INTEGER), | |
316 ('LimitFlags', DWORD), | |
317 ('MinimumWorkingSetSize', SIZE_T), | |
318 ('MaximumWorkingSetSize', SIZE_T), | |
319 ('ActiveProcessLimit', DWORD), | |
320 ('Affinity', ULONG_PTR), | |
321 ('PriorityClass', DWORD), | |
322 ('SchedulingClass', DWORD)) | |
323 | |
324 JOB_OBJECT_LIMIT_WORKINGSET = 0x0001 | |
325 JOB_OBJECT_LIMIT_PROCESS_TIME = 0x0002 | |
326 JOB_OBJECT_LIMIT_JOB_TIME = 0x0004 | |
327 JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x0008 | |
328 JOB_OBJECT_LIMIT_AFFINITY = 0x0010 | |
329 JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x0020 | |
330 JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x0040 | |
331 JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x0080 | |
332 JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x0100 | |
333 JOB_OBJECT_LIMIT_JOB_MEMORY = 0x0200 | |
334 JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x0400 | |
335 JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x0800 | |
336 JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x1000 | |
337 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000 | |
338 JOB_OBJECT_LIMIT_SUBSET_AFFINITY = 0x4000 | |
339 | |
340 class IO_COUNTERS(Structure): | |
341 _fields_ = (('ReadOperationCount', ULONGLONG), | |
342 ('WriteOperationCount', ULONGLONG), | |
343 ('OtherOperationCount', ULONGLONG), | |
344 ('ReadTransferCount', ULONGLONG), | |
345 ('WriteTransferCount', ULONGLONG), | |
346 ('OtherTransferCount', ULONGLONG)) | |
347 | |
348 class JOBOBJECT_EXTENDED_LIMIT_INFORMATION(Structure): | |
349 _fields_ = (('BasicLimitInformation', JOBOBJECT_BASIC_LIMIT_INFORMATION), | |
350 ('IoInfo', IO_COUNTERS), | |
351 ('ProcessMemoryLimit', SIZE_T), | |
352 ('JobMemoryLimit', SIZE_T), | |
353 ('PeakProcessMemoryUsed', SIZE_T), | |
354 ('PeakJobMemoryUsed', SIZE_T)) | |
355 | |
356 prototype = WINFUNCTYPE(BOOL, Handle, c_int, c_void_p, DWORD) | |
357 flags = (1, 'job'), (1, 'infoclass'), (1, 'info'), (1, 'infosize') | |
358 try: | |
359 _setjobinfo = prototype(('SetInformationJobObject',windll.kernel32), flags) | |
360 except AttributeError: | |
361 # Available on 2000 and up, NT line only | |
362 SetInformationJobObject = lambda job, infoclass, info: None | |
363 else: | |
364 def errcheck(result, func, args): | |
365 if not result: raise WinError() | |
366 _setjobinfo.errcheck = errcheck | |
367 def SetInformationJobObject(job, infoclass, info): | |
368 return _setjobinfo(job, infoclass, byref(info), sizeof(info)) | |
369 | |
370 ( | |
371 JobObjectBasicAccountingInformation, | |
372 JobObjectBasicLimitInformation, | |
373 JobObjectBasicProcessIdList, | |
374 JobObjectBasicUIRestrictions, | |
375 JobObjectSecurityLimitInformation, | |
376 JobObjectEndOfJobTimeInformation, | |
377 JobObjectAssociateCompletionPortInformation, | |
378 JobObjectBasicAndIoAccountingInformation, | |
379 JobObjectExtendedLimitInformation, | |
380 JobObjectJobSetInformation, | |
381 MaxJobObjectInfoClass | |
382 ) = range(1, 12) | |
383 | |
384 | |
385 prototype = WINFUNCTYPE(DWORD, DWORD, POINTER(HANDLE), BOOL, DWORD) | |
386 flags = (1, 'count'), (1, 'handles'), (1, 'wait_all'), (1, 'milliseconds') | |
387 _wait_multiple = prototype(('WaitForMultipleObjects', windll.kernel32), flags) | |
388 def errcheck(result, func, args): | |
389 if result == WAIT_FAILED: raise WinError() | |
390 return args | |
391 _wait_multiple.errcheck = errcheck | |
392 def WaitForMultipleObjects(handles, wait_all, timeout): | |
393 n = len(handles) | |
394 handles = (Handle.from_param(handle) for handle in handles) | |
395 timeout = ceil(timeout * 1000) | |
396 return _wait_multiple(n, (HANDLE * n)(*handles), wait_all, timeout) | |
397 | |
398 # WAIT_OBJECT_0 defined at the top of the file | |
399 WAIT_ABANDONED_0 = 0x00000080 | |
400 WAIT_TIMEOUT = 0x00000102 | |
401 WAIT_FAILED = 0xFFFFFFFF | |
402 | |
403 | |
404 try: | |
405 _wait_single = WaitForSingleObject | |
406 except NameError: | |
407 prototype = WINFUNCTYPE(DWORD, Handle, DWORD) | |
408 flags = (1, 'handle'), (1, 'milliseconds') | |
409 _wait_single = prototype(('WaitForSingleObject', windll.kernel32), flags) | |
410 def errcheck(result, func, args): | |
411 if result == WAIT_FAILED: raise WinError() | |
412 return args | |
413 _wait_single.errcheck = errcheck | |
414 def WaitForSingleObject(handle, timeout): | |
415 return _wait_single(handle, ceil(timeout * 1000)) | |
416 | |
417 | |
418 try: | |
419 GetStdHandle | |
420 except NameError: | |
421 prototype = WINFUNCTYPE(HANDLE, DWORD) | |
422 flags = (1, 'which'), | |
423 GetStdHandle = prototype(('GetStdHandle', windll.kernel32), flags) | |
424 def errcheck(result, func, args): | |
425 if result == INVALID_HANDLE_VALUE: raise WinError() | |
426 return args if result else None | |
427 GetStdHandle.errcheck = errcheck | |
428 | |
429 | |
430 try: | |
431 TerminateProcess | |
432 except NameError: | |
433 prototype = WINFUNCTYPE(BOOL, Handle, UINT) | |
434 flags = (1, 'process'), (1, 'exitcode') | |
435 TerminateProcess = prototype(('TerminateProcess', windll.kernel32), flags) | |
436 def errcheck(result, func, args): | |
437 if not result: raise WinError() | |
438 TerminateProcess.errcheck = errcheck | |
439 | |
440 | |
441 # Do not show error messages due to errors in the program being tested | |
442 try: | |
443 errmode = windll.kernel32.GetErrorMode() | |
444 except AttributeError: | |
445 # GetErrorMode is available on Vista/2008 and up | |
446 errmode = windll.kernel32.SetErrorMode(0) | |
447 windll.kernel32.SetErrorMode(errmode | 0x8003) | |
448 | |
449 stdin = GetStdHandle(STD_INPUT_HANDLE) | |
450 try: | |
451 SetConsoleMode(stdin, ENABLE_PROCESSED_INPUT) | |
452 except WindowsError: | |
453 console_input = False | |
454 else: | |
455 console_input = True | |
456 FlushConsoleInputBuffer(stdin) | |
457 | |
458 def call(*args, **kwargs): | |
459 case = kwargs.pop('case') | |
460 job = CreateJobObject(None) | |
461 flags = 0 | |
462 if case.maxcputime: | |
463 flags |= JOB_OBJECT_LIMIT_PROCESS_TIME | |
464 if case.maxmemory: | |
465 flags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY | |
466 limits = JOBOBJECT_EXTENDED_LIMIT_INFORMATION( | |
467 JOBOBJECT_BASIC_LIMIT_INFORMATION( | |
468 PerProcessUserTimeLimit=ceil((case.maxcputime or 0)*10000000), | |
469 LimitFlags=flags, | |
470 ), | |
471 ProcessMemoryLimit=ceil((case.maxmemory or 0)*1048576), | |
472 ) | |
473 SetInformationJobObject(job, JobObjectExtendedLimitInformation, limits) | |
474 try: | |
475 case.process = Popen(*args, **kwargs) | |
476 except OSError: | |
477 raise CannotStartTestee(sys.exc_info()[1]) | |
478 case.time_started = clock() | |
479 AssignProcessToJobObject(job, case.process._handle) | |
480 if not console_input: | |
481 if case.maxwalltime: | |
482 if (WaitForSingleObject(case.process._handle, case.maxwalltime) != | |
483 WAIT_OBJECT_0): | |
484 raise WallTimeLimitExceeded | |
485 else: | |
486 case.process.wait() | |
487 else: | |
488 handles = case.process._handle, stdin | |
489 if case.maxwalltime: | |
490 time_end = case.time_started + case.maxwalltime | |
491 while case.process.poll() is None: | |
492 remaining = time_end - clock() | |
493 if remaining > 0: | |
494 if (WaitForMultipleObjects(handles, False, remaining) == | |
495 WAIT_OBJECT_0 + 1): | |
496 ir = ReadConsoleInput(stdin) | |
497 if (ir and | |
498 ir.EventType == KEY_EVENT and | |
499 ir.Event.KeyEvent.bKeyDown and | |
500 ir.Event.KeyEvent.wVirtualKeyCode == 27): | |
501 raise CanceledByUser | |
502 else: | |
503 raise WallTimeLimitExceeded | |
504 else: | |
505 while case.process.poll() is None: | |
506 if (WaitForMultipleObjects(handles, False, INFINITE) == | |
507 WAIT_OBJECT_0 + 1): | |
508 ir = ReadConsoleInput(stdin) | |
509 if (ir and | |
510 ir.EventType == KEY_EVENT and | |
511 ir.Event.KeyEvent.bKeyDown and | |
512 ir.Event.KeyEvent.wVirtualKeyCode == 27): | |
513 raise CanceledByUser | |
514 case.time_stopped = clock() | |
515 if GetProcessTimes: | |
516 try: | |
517 times = GetProcessTimes(case.process._handle) | |
518 except WindowsError: | |
519 pass | |
520 else: | |
521 if case.maxcputime or not case.maxwalltime: | |
522 cputime = times.kernel + times.user | |
523 case.time_stopped = cputime | |
524 case.time_started = 0 | |
525 case.time_limit_string = case.cpu_time_limit_string | |
526 if case.maxcputime and cputime > case.maxcputime: | |
527 raise CPUTimeLimitExceeded | |
528 else: | |
529 case.time_stopped = times.exit | |
530 case.time_started = times.creation | |
531 walltime = times.exit - times.creation | |
532 if case.maxwalltime and walltime > case.maxwalltime: | |
533 raise WallTimeLimitExceeded | |
534 if case.maxcputime and case.process.returncode == 1816: | |
535 raise CPUTimeLimitExceeded | |
536 if case.maxmemory and GetProcessMemoryInfo: | |
537 try: | |
538 counters = GetProcessMemoryInfo(case.process._handle) | |
539 except WindowsError: | |
540 pass | |
541 else: | |
542 if counters.PeakPagefileUsage > case.maxmemory * 1048576: | |
543 raise MemoryLimitExceeded | |
544 | |
545 | |
546 def kill(process): | |
547 # Give up after three attempts | |
548 for i in range(3): | |
549 try: | |
550 try: | |
551 process.terminate() | |
552 except AttributeError: | |
553 TerminateProcess(process._handle, 1) | |
554 except WindowsError: | |
555 time.sleep(0) | |
556 else: | |
557 break |