diff win32.py @ 82:06356af50bf9

Finished testcases reorganization and CPU time limit implementation We now have: * Win32-specific code in the win32 module (including bug fixes), * UNIX-specific and generic code in the unix module, * a much cleaner testcases module, * wait4-based resource limits working on Python 3 (this is a bug fix), * no warning/error reported on non-Win32 when -x is not passed but standard input does not come from a terminal, * the maxtime configuration variable replaced with two new variables named maxcputime and maxwalltime, * CPU time reported if it can be determined unless an error occurs sooner than it is determined (e. g. if the wall-clock time limit is exceeded), * memory limits enforced even if Upreckon's forking already breaks them, * CPU time limits and private virtual memory limits honoured on Win32, * CPU time limits honoured on UNIX(-like) platforms supporting wait4 or getrusage, * address space limits honoured on UNIX(-like) platforms supporting setrlimit with RLIMIT_AS/RLIMIT_VMEM, * resident set size limits honoured on UNIX(-like) platforms supporting wait4.
author Oleg Oshmyan <chortos@inbox.lv>
date Wed, 23 Feb 2011 23:35:27 +0000
parents 24752db487c5
children 741ae3391b61
line wrap: on
line diff
--- a/win32.py	Wed Feb 16 15:30:57 2011 +0000
+++ b/win32.py	Wed Feb 23 23:35:27 2011 +0000
@@ -1,19 +1,20 @@
-# Copyright (c) 2011 Chortos-2 <chortos@inbox.lv>
+# Copyright (c) 2010-2011 Chortos-2 <chortos@inbox.lv>
 
 from __future__ import division, with_statement
+import sys
 
 try:
 	from compat import *
-	from testcases import (TimeLimitExceeded, MemoryLimitExceeded,
-	                       CanceledByUser, CannotStartTestee)
+	import testcases  # mutual import
 except ImportError:
 	import __main__
 	__main__.import_error(sys.exc_info()[1])
 
-from __main__ import clock
 from ctypes import *
 from ctypes.wintypes import *
+from msvcrt import getch as pause
 from subprocess import Popen
+from __main__ import clock
 
 # Defaults that may be overwritten by values from _subprocess
 INFINITE = -1
@@ -42,7 +43,7 @@
 else:
 	ProcessTimes = namedtuple('ProcessTimes', 'kernel user')
 
-__all__ = 'call', 'kill', 'terminate'
+__all__ = 'call', 'kill', 'terminate', 'pause'
 
 
 # Automatically convert _subprocess handle objects into low-level HANDLEs
@@ -315,7 +316,7 @@
 	            ('PeakProcessMemoryUsed', SIZE_T),
 	            ('PeakJobMemoryUsed', SIZE_T))
 
-prototype = WINFUNCTYPE(BOOL, HANDLE, c_int, c_void_p, DWORD)
+prototype = WINFUNCTYPE(BOOL, Handle, c_int, c_void_p, DWORD)
 flags = (1, 'job'), (1, 'infoclass'), (1, 'info'), (1, 'infosize')
 try:
 	_setjobinfo = prototype(('SetInformationJobObject',windll.kernel32), flags)
@@ -327,7 +328,7 @@
 		if not result: raise WinError()
 	_setjobinfo.errcheck = errcheck
 	def SetInformationJobObject(job, infoclass, info):
-		return _setjobinfo(job, infoclass, info, sizeof(info))
+		return _setjobinfo(job, infoclass, byref(info), sizeof(info))
 
 (
 	JobObjectBasicAccountingInformation,
@@ -417,13 +418,6 @@
 	console_input = True
 	FlushConsoleInputBuffer(stdin)
 
-def kill(process):
-	try:
-		process.terminate()
-	except AttributeError:
-		TerminateProcess(process._handle)
-terminate = kill
-
 def call(*args, **kwargs):
 	case = kwargs.pop('case')
 	job = CreateJobObject(None)
@@ -443,14 +437,14 @@
 	try:
 		case.process = Popen(*args, **kwargs)
 	except OSError:
-		raise CannotStartTestee(sys.exc_info()[1])
+		raise testcases.CannotStartTestee(sys.exc_info()[1])
 	case.time_started = clock()
 	AssignProcessToJobObject(job, case.process._handle)
 	if not console_input:
 		if case.maxwalltime:
 			if (WaitForSingleObject(case.process._handle, case.maxwalltime) !=
 			    WAIT_OBJECT_0):
-				raise TimeLimitExceeded
+				raise testcases.WallTimeLimitExceeded
 		else:
 			case.process.wait()
 	else:
@@ -467,9 +461,9 @@
 						    ir.EventType == 1 and
 						    ir.Event.KeyEvent.bKeyDown and
 						    ir.Event.KeyEvent.wVirtualKeyCode == 27):
-							raise CanceledByUser
+							raise testcases.CanceledByUser
 				else:
-					raise TimeLimitExceeded
+					raise testcases.WallTimeLimitExceeded
 		else:
 			while case.process.poll() is None:
 				if (WaitForMultipleObjects(handles, False, INFINITE) ==
@@ -479,16 +473,24 @@
 					    ir.EventType == 1 and
 					    ir.Event.KeyEvent.bKeyDown and
 					    ir.Event.KeyEvent.wVirtualKeyCode == 27):
-						raise CanceledByUser
+						raise testcases.CanceledByUser
 	case.time_stopped = clock()
-	if case.maxcputime and GetProcessTimes:
+	if GetProcessTimes:
 		try:
 			times = GetProcessTimes(case.process._handle)
 		except WindowsError:
 			pass
 		else:
-			if times.kernel + times.user > case.maxcputime:
-				raise TimeLimitExceeded
+			time = times.kernel + times.user
+			case.time_stopped = time
+			case.time_started = 0
+			case.time_limit_string = case.cpu_time_limit_string
+			if case.maxcputime and time > case.maxcputime:
+				raise testcases.CPUTimeLimitExceeded
+	if case.maxcputime and case.process.returncode == 1816:
+		raise testcases.CPUTimeLimitExceeded
+	if case.maxmemory and case.process.returncode == -0x3ffffffb:
+		raise testcases.MemoryLimitExceeded
 	if case.maxmemory and GetProcessMemoryInfo:
 		try:
 			counters = GetProcessMemoryInfo(case.process._handle)
@@ -496,4 +498,12 @@
 			pass
 		else:
 			if counters.PeakPagefileUsage > case.maxmemory * 1048576:
-				raise MemoryLimitExceeded
\ No newline at end of file
+				raise testcases.MemoryLimitExceeded
+
+
+def kill(process):
+	try:
+		process.terminate()
+	except AttributeError:
+		TerminateProcess(process._handle)
+terminate = kill
\ No newline at end of file