diff -r 2a18f6b85da2 Lib/test/eintrdata/eintr_tester.py --- a/Lib/test/eintrdata/eintr_tester.py Sun Apr 12 18:47:56 2015 -0400 +++ b/Lib/test/eintrdata/eintr_tester.py Mon Apr 13 21:18:36 2015 -0400 @@ -13,13 +13,16 @@ import select import signal import socket +import sys +import threading import time import unittest from test import support -@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") +@unittest.skipUnless(hasattr(signal, "setitimer") or sys.platform == "win32", + "requires setitimer() on non-win32 platforms") class EINTRBaseTest(unittest.TestCase): """ Base class for EINTR tests. """ @@ -28,23 +31,51 @@ # signal delivery periodicity signal_period = 0.1 # default sleep time for tests - should obviously have: - # sleep_time > signal_period - sleep_time = 0.2 + # sleep_time > signal_period; for win32, should be > .2 + sleep_time = 0.5 + # signal number used to interrupt + signal_num = (signal.SIGINT if sys.platform == 'win32' else signal.SIGALRM) + + # Windows requires a thread to generate the signals + if sys.platform == 'win32': + _generate_thread_active = False + _generate_thread = None + @classmethod + def _generate_ctrl_c_events(cls): + + cls._generate_thread_active = True + while cls._generate_thread_active: + time.sleep(cls.signal_period) + # Calls GenerateConsoleCtrlEvent + os.kill(0, signal.CTRL_C_EVENT) @classmethod def setUpClass(cls): - cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None) - signal.setitimer(signal.ITIMER_REAL, cls.signal_delay, - cls.signal_period) + cls.orig_handler = signal.signal(cls.signal_num, lambda *args: None) + + if sys.platform == 'win32': + cls._generate_thread = threading.Thread(target=cls._generate_ctrl_c_events) + cls._generate_thread.start() + while not cls._generate_thread_active: + time.sleep(0.01) + else: + signal.setitimer(signal.ITIMER_REAL, cls.signal_delay, + cls.signal_period) @classmethod def stop_alarm(cls): - signal.setitimer(signal.ITIMER_REAL, 0, 0) + if sys.platform == 'win32': + if cls._generate_thread is not None: + cls._generate_thread_active = False + cls._generate_thread.join() + cls._generate_thread = None + else: + signal.setitimer(signal.ITIMER_REAL, 0, 0) @classmethod def tearDownClass(cls): cls.stop_alarm() - signal.signal(signal.SIGALRM, cls.orig_handler) + signal.signal(cls.signal_num, cls.orig_handler) @classmethod def _sleep(cls): @@ -257,7 +288,8 @@ lambda path: os.close(os.open(path, os.O_WRONLY))) -@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") +@unittest.skipUnless(hasattr(signal, "setitimer") or sys.platform == 'win32', + "requires setitimer() on non-win32 platforms") class TimeEINTRTest(EINTRBaseTest): """ EINTR tests for the time module. """ diff -r 2a18f6b85da2 Lib/test/script_helper.py --- a/Lib/test/script_helper.py Sun Apr 12 18:47:56 2015 -0400 +++ b/Lib/test/script_helper.py Mon Apr 13 21:18:36 2015 -0400 @@ -51,7 +51,7 @@ # Executing the interpreter in a subprocess -def _assert_python(expected_success, *args, **env_vars): +def _assert_python(expected_success, *args, creationflags=None, **env_vars): env_required = interpreter_requires_environment() if '__isolated' in env_vars: isolated = env_vars.pop('__isolated') @@ -65,6 +65,7 @@ elif not env_vars and not env_required: # ignore Python environment variables cmd_line.append('-E') + # Need to preserve the original environment, for in-place testing of # shared library builds. env = os.environ.copy() @@ -76,7 +77,7 @@ cmd_line.extend(args) p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=env) + env=env, creationflags=creationflags) try: out, err = p.communicate() finally: @@ -111,7 +112,7 @@ err)) return rc, out, err -def assert_python_ok(*args, **env_vars): +def assert_python_ok(*args, creationflags=None, **env_vars): """ Assert that running the interpreter with `args` and optional environment variables `env_vars` succeeds (rc == 0) and return a (return code, stdout, @@ -122,7 +123,7 @@ Python is started in isolated mode (command line option -I), except if the __isolated keyword is set to False. """ - return _assert_python(True, *args, **env_vars) + return _assert_python(True, *args, creationflags=creationflags, **env_vars) def assert_python_failure(*args, **env_vars): """ diff -r 2a18f6b85da2 Lib/test/test_eintr.py --- a/Lib/test/test_eintr.py Sun Apr 12 18:47:56 2015 -0400 +++ b/Lib/test/test_eintr.py Mon Apr 13 21:18:36 2015 -0400 @@ -1,19 +1,24 @@ import os import signal +import subprocess +import sys import unittest from test import script_helper, support -@unittest.skipUnless(os.name == "posix", "only supported on Unix") class EINTRTests(unittest.TestCase): - @unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") + @unittest.skipUnless(hasattr(signal, "setitimer") or sys.platform == 'win32', + "requires setitimer() on non-win32 platforms") def test_all(self): # Run the tester in a sub-process, to make sure there is only one # thread (for reliable signal delivery). tester = support.findfile("eintr_tester.py", subdir="eintrdata") - script_helper.assert_python_ok(tester) + if sys.platform == 'win32': + script_helper.assert_python_ok(tester, creationflags=subprocess.CREATE_NEW_CONSOLE) + else: + script_helper.assert_python_ok(tester) if __name__ == "__main__":