changeset 218:65b5c9390010

With _unix, Escape presses now cancel test data unarchiving
author Oleg Oshmyan <chortos@inbox.lv>
date Mon, 22 Aug 2011 22:34:09 +0300
parents ce1285728952
children 7827e63cd148
files upreckon/_unixmodule.cpp upreckon/exceptions.py upreckon/testcases.py upreckon/unix.py
diffstat 4 files changed, 40 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/upreckon/_unixmodule.cpp	Sun Aug 21 01:24:29 2011 +0300
+++ b/upreckon/_unixmodule.cpp	Mon Aug 22 22:34:09 2011 +0300
@@ -2,7 +2,6 @@
 
 #include <Python.h>
 #include <structmember.h>
-#include <stdio.h>
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -155,6 +154,9 @@
 #ifdef HAVE_TERMIOS_H
 static bool catch_escape = false;
 static struct termios orig_termios;
+#ifdef O_ASYNC
+static int orig_stdout_fl;
+#endif
 #endif
 
 typedef struct
@@ -405,6 +407,10 @@
 #endif
 #endif
 		
+#if defined HAVE_TERMIOS_H && defined O_ASYNC
+		signal(SIGIO, SIG_DFL);
+#endif
+		
 		if (c2ppipe[1] < 3)
 		{
 			int newfd;
@@ -1275,6 +1281,9 @@
 #ifdef HAVE_TERMIOS_H
 	if (catch_escape)
 	{
+#ifdef O_ASYNC
+		signal(SIGIO, SIG_DFL);
+#endif
 		char c;
 		while (read(0, &c, 1) == -1 && errno == EINTR)
 		{
@@ -1309,6 +1318,9 @@
 static void restore_termios(void)
 {
 	tcsetattr(0, TCSAFLUSH, &orig_termios);
+#ifdef O_ASYNC
+	fcntl(0, F_SETFL, orig_stdout_fl);
+#endif
 #ifdef USE_WAKEUP_FD
 	close_intpipe();
 #endif
@@ -1443,6 +1455,10 @@
 		if (!Py_AtExit(restore_termios) && !tcsetattr(0, TCSAFLUSH, &new_termios))
 		{
 			catch_escape = true;
+#ifdef O_ASYNC
+			orig_stdout_fl = fcntl(0, F_GETFL);
+			fcntl(0, F_SETFL, orig_stdout_fl | O_ASYNC);
+#endif
 		}
 	}
 #ifdef USE_WAKEUP_FD
--- a/upreckon/exceptions.py	Sun Aug 21 01:24:29 2011 +0300
+++ b/upreckon/exceptions.py	Mon Aug 22 22:34:09 2011 +0300
@@ -13,7 +13,7 @@
 class CPUTimeLimitExceeded(TimeLimitExceeded): __slots__ = ()
 class WallTimeLimitExceeded(TimeLimitExceeded): __slots__ = ()
 class MemoryLimitExceeded(TestCaseNotPassed): __slots__ = ()
-class CanceledByUser(TestCaseNotPassed): __slots__ = ()
+class CanceledByUser(BaseException): __slots__ = ()
 
 class WrongAnswer(TestCaseNotPassed):
 	__slots__ = 'comment'
--- a/upreckon/testcases.py	Sun Aug 21 01:24:29 2011 +0300
+++ b/upreckon/testcases.py	Mon Aug 22 22:34:09 2011 +0300
@@ -19,6 +19,8 @@
 	def __enter__(self): pass
 	def __exit__(self, exc_type, exc_value, traceback): pass
 signal_ignorer = DummySignalIgnorer()
+def install_escape_handler(): pass
+def remove_escape_handler(): pass
 
 try:
 	from .win32 import *
@@ -121,8 +123,10 @@
 		case.files_to_delete = []
 		case.time_limit_string = case.wall_time_limit_string
 		try:
+			install_escape_handler()
 			return case.test(callback)
 		finally:
+			remove_escape_handler()
 			now = clock()
 			if getattr(case, 'time_started', None) is None:
 				case.time_started = case.time_stopped = now
--- a/upreckon/unix.py	Sun Aug 21 01:24:29 2011 +0300
+++ b/upreckon/unix.py	Mon Aug 22 22:34:09 2011 +0300
@@ -308,3 +308,21 @@
 			tty.setcbreak(sys.stdin.fileno())
 			def pause():
 				sys.stdin.read(1)
+else:
+	try:
+		from signal import signal, SIGIO, SIG_DFL
+		from select import select
+	except ImportError:
+		pass
+	else:
+		def sigio_handler(signum, frame):
+			if select((sys.stdin,), (), (), 0)[0]:
+				if os.read(sys.stdin.fileno(), 1) == '\33'.encode('ascii'):
+					remove_escape_handler()
+					raise CanceledByUser
+		def install_escape_handler():
+			signal(SIGIO, sigio_handler)
+			sigio_handler(SIGIO, None)
+		def remove_escape_handler():
+			signal(SIGIO, SIG_DFL)
+		__all__ += 'install_escape_handler', 'remove_escape_handler'