summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorBrian Curtin <brian.curtin@gmail.com>2010-04-12 17:16:38 (GMT)
committerBrian Curtin <brian.curtin@gmail.com>2010-04-12 17:16:38 (GMT)
commiteb24d7498f3e34586fee24209f5630a58bb1a04b (patch)
tree2618500362c3b75e9ff541971954b57d14d66a86 /Lib
parentb2416e54b15d90b4a1bc917897912061830b42fc (diff)
downloadcpython-eb24d7498f3e34586fee24209f5630a58bb1a04b.zip
cpython-eb24d7498f3e34586fee24209f5630a58bb1a04b.tar.gz
cpython-eb24d7498f3e34586fee24209f5630a58bb1a04b.tar.bz2
Port #1220212 (os.kill for Win32) to py3k.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/subprocess.py4
-rw-r--r--Lib/test/test_os.py66
-rw-r--r--Lib/test/win_console_handler.py43
-rw-r--r--Lib/unittest/test/test_break.py2
4 files changed, 112 insertions, 3 deletions
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 89cf9bf..ec391cb 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -980,6 +980,10 @@ class Popen(object):
"""
if sig == signal.SIGTERM:
self.terminate()
+ elif sig == signal.CTRL_C_EVENT:
+ os.kill(self.pid, signal.CTRL_C_EVENT)
+ elif sig == signal.CTRL_BREAK_EVENT:
+ os.kill(self.pid, signal.CTRL_BREAK_EVENT)
else:
raise ValueError("Only SIGTERM is supported on Windows")
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 395402b..705bdc7 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -7,9 +7,13 @@ import errno
import unittest
import warnings
import sys
+import signal
+import subprocess
+import time
import shutil
from test import support
+
# Tests creating TESTFN
class FileTests(unittest.TestCase):
def setUp(self):
@@ -739,7 +743,6 @@ if sys.platform != 'win32':
def test_setreuid_neg1(self):
# Needs to accept -1. We run this in a subprocess to avoid
# altering the test runner's process state (issue8045).
- import subprocess
subprocess.check_call([
sys.executable, '-c',
'import os,sys;os.setreuid(-1,-1);sys.exit(0)'])
@@ -754,7 +757,6 @@ if sys.platform != 'win32':
def test_setregid_neg1(self):
# Needs to accept -1. We run this in a subprocess to avoid
# altering the test runner's process state (issue8045).
- import subprocess
subprocess.check_call([
sys.executable, '-c',
'import os,sys;os.setregid(-1,-1);sys.exit(0)'])
@@ -798,6 +800,63 @@ else:
class Pep383Tests(unittest.TestCase):
pass
+@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
+class Win32KillTests(unittest.TestCase):
+ def _kill(self, sig, *args):
+ # Send a subprocess a signal (or in some cases, just an int to be
+ # the return value)
+ proc = subprocess.Popen(*args)
+ os.kill(proc.pid, sig)
+ self.assertEqual(proc.wait(), sig)
+
+ def test_kill_sigterm(self):
+ # SIGTERM doesn't mean anything special, but make sure it works
+ self._kill(signal.SIGTERM, [sys.executable])
+
+ def test_kill_int(self):
+ # os.kill on Windows can take an int which gets set as the exit code
+ self._kill(100, [sys.executable])
+
+ def _kill_with_event(self, event, name):
+ # Run a script which has console control handling enabled.
+ proc = subprocess.Popen([sys.executable,
+ os.path.join(os.path.dirname(__file__),
+ "win_console_handler.py")],
+ creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
+ # Let the interpreter startup before we send signals. See #3137.
+ time.sleep(0.5)
+ os.kill(proc.pid, event)
+ # proc.send_signal(event) could also be done here.
+ # Allow time for the signal to be passed and the process to exit.
+ time.sleep(0.5)
+ if not proc.poll():
+ # Forcefully kill the process if we weren't able to signal it.
+ os.kill(proc.pid, signal.SIGINT)
+ self.fail("subprocess did not stop on {}".format(name))
+
+ @unittest.skip("subprocesses aren't inheriting CTRL+C property")
+ def test_CTRL_C_EVENT(self):
+ from ctypes import wintypes
+ import ctypes
+
+ # Make a NULL value by creating a pointer with no argument.
+ NULL = ctypes.POINTER(ctypes.c_int)()
+ SetConsoleCtrlHandler = ctypes.windll.kernel32.SetConsoleCtrlHandler
+ SetConsoleCtrlHandler.argtypes = (ctypes.POINTER(ctypes.c_int),
+ wintypes.BOOL)
+ SetConsoleCtrlHandler.restype = wintypes.BOOL
+
+ # Calling this with NULL and FALSE causes the calling process to
+ # handle CTRL+C, rather than ignore it. This property is inherited
+ # by subprocesses.
+ SetConsoleCtrlHandler(NULL, 0)
+
+ self._kill_with_event(signal.CTRL_C_EVENT, "CTRL_C_EVENT")
+
+ def test_CTRL_BREAK_EVENT(self):
+ self._kill_with_event(signal.CTRL_BREAK_EVENT, "CTRL_BREAK_EVENT")
+
+
def test_main():
support.run_unittest(
ArgTests,
@@ -812,7 +871,8 @@ def test_main():
Win32ErrorTests,
TestInvalidFD,
PosixUidGidTests,
- Pep383Tests
+ Pep383Tests,
+ Win32KillTests
)
if __name__ == "__main__":
diff --git a/Lib/test/win_console_handler.py b/Lib/test/win_console_handler.py
new file mode 100644
index 0000000..17bbe1a
--- /dev/null
+++ b/Lib/test/win_console_handler.py
@@ -0,0 +1,43 @@
+"""Script used to test os.kill on Windows, for issue #1220212
+
+This script is started as a subprocess in test_os and is used to test the
+CTRL_C_EVENT and CTRL_BREAK_EVENT signals, which requires a custom handler
+to be written into the kill target.
+
+See http://msdn.microsoft.com/en-us/library/ms685049%28v=VS.85%29.aspx for a
+similar example in C.
+"""
+
+from ctypes import wintypes
+import signal
+import ctypes
+
+# Function prototype for the handler function. Returns BOOL, takes a DWORD.
+HandlerRoutine = wintypes.WINFUNCTYPE(wintypes.BOOL, wintypes.DWORD)
+
+def _ctrl_handler(sig):
+ """Handle a sig event and return 0 to terminate the process"""
+ if sig == signal.CTRL_C_EVENT:
+ pass
+ elif sig == signal.CTRL_BREAK_EVENT:
+ pass
+ else:
+ print("UNKNOWN EVENT")
+ return 0
+
+ctrl_handler = HandlerRoutine(_ctrl_handler)
+
+
+SetConsoleCtrlHandler = ctypes.windll.kernel32.SetConsoleCtrlHandler
+SetConsoleCtrlHandler.argtypes = (HandlerRoutine, wintypes.BOOL)
+SetConsoleCtrlHandler.restype = wintypes.BOOL
+
+if __name__ == "__main__":
+ # Add our console control handling function with value 1
+ if not SetConsoleCtrlHandler(ctrl_handler, 1):
+ print("Unable to add SetConsoleCtrlHandler")
+ exit(-1)
+
+ # Do nothing but wait for the signal
+ while True:
+ pass
diff --git a/Lib/unittest/test/test_break.py b/Lib/unittest/test/test_break.py
index e3fae34..9108a2c 100644
--- a/Lib/unittest/test/test_break.py
+++ b/Lib/unittest/test/test_break.py
@@ -1,6 +1,7 @@
import gc
import io
import os
+import sys
import signal
import weakref
@@ -8,6 +9,7 @@ import unittest
@unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill")
+@unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows")
class TestBreak(unittest.TestCase):
def setUp(self):