Implement #1220212. Add os.kill support for Windows.

os.kill takes one of two newly added signals, CTRL_C_EVENT and
CTRL_BREAK_EVENT, or any integer value. The events are a special case
which work with subprocess console applications which implement a
special console control handler. Any other value but those two will
cause os.kill to use TerminateProcess, outright killing the process.

This change adds win_console_handler.py, which is a script to implement
SetConsoleCtrlHandler and applicable handler function, using ctypes.

subprocess also gets another attribute which is a necessary flag to
creationflags in Popen in order to send the CTRL events.
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index b4e39a4..11d9607 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -1719,7 +1719,14 @@
 
    Send signal *sig* to the process *pid*.  Constants for the specific signals
    available on the host platform are defined in the :mod:`signal` module.
-   Availability: Unix.
+
+   Windows: The :data:`signal.CTRL_C_EVENT` and
+   :data:`signal.CTRL_BREAK_EVENT` signals are special signals which can
+   only be sent to console processes which share a common console window,
+   e.g., some subprocesses. Any other value for *sig* will cause the process
+   to be unconditionally killed by the TerminateProcess API, and the exit code
+   will be set to *sig*. The Windows version of :func:`kill` additionally takes
+   process handles to be killed.
 
 
 .. function:: killpg(pgid, sig)
diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
index 84f08b3..300c717 100644
--- a/Doc/library/signal.rst
+++ b/Doc/library/signal.rst
@@ -75,6 +75,20 @@
    the system are defined by this module.
 
 
+.. data:: CTRL_C_EVENT
+
+   The signal corresponding to the CTRL+C keystroke event.
+
+   Availability: Windows.
+
+
+.. data:: CTRL_BREAK_EVENT
+
+   The signal corresponding to the CTRL+BREAK keystroke event.
+
+   Availability: Windows.
+
+
 .. data:: NSIG
 
    One more than the number of the highest signal number.
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index b557bcd..439a46d 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -320,8 +320,9 @@
 
    .. note::
 
-      On Windows only SIGTERM is supported so far. It's an alias for
-      :meth:`terminate`.
+      On Windows, SIGTERM is an alias for :meth:`terminate`. CTRL_C_EVENT and
+      CTRL_BREAK_EVENT can be sent to processes started with a `creationflags`
+      parameter which includes `CREATE_NEW_PROCESS_GROUP`.
 
    .. versionadded:: 2.6
 
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 59ed60c..e4c843d 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -990,6 +990,10 @@
             """
             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 4e21dd8..2fc0d07 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -7,6 +7,9 @@
 import unittest
 import warnings
 import sys
+import signal
+import subprocess
+import time
 from test import test_support
 
 warnings.filterwarnings("ignore", "tempnam", RuntimeWarning, __name__)
@@ -649,7 +652,6 @@
             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)'])
@@ -664,7 +666,6 @@
             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)'])
@@ -672,6 +673,63 @@
     class PosixUidGidTests(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.1)
+        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.1)
+        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():
     test_support.run_unittest(
         FileTests,
@@ -684,7 +742,8 @@
         URandomTests,
         Win32ErrorTests,
         TestInvalidFD,
-        PosixUidGidTests
+        PosixUidGidTests,
+        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..e4190d4
--- /dev/null
+++ b/Lib/test/win_console_handler.py
@@ -0,0 +1,42 @@
+"""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

+    input()

diff --git a/Lib/unittest/test/test_break.py b/Lib/unittest/test/test_break.py
index 1cd75b8..c1c5e6d 100644
--- a/Lib/unittest/test/test_break.py
+++ b/Lib/unittest/test/test_break.py
@@ -1,5 +1,6 @@
 import gc
 import os
+import sys
 import signal
 import weakref
 
@@ -10,6 +11,7 @@
 
 
 @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):
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 8fb7aaa..53eb237 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -4075,6 +4075,53 @@
 }
 #endif
 
+#ifdef MS_WINDOWS
+PyDoc_STRVAR(win32_kill__doc__,
+"kill(pid, sig)\n\n\
+Kill a process with a signal.");
+
+static PyObject *
+win32_kill(PyObject *self, PyObject *args)
+{
+	PyObject *result, handle_obj;
+	DWORD pid, sig, err;
+	HANDLE handle;
+
+	if (!PyArg_ParseTuple(args, "kk:kill", &pid, &sig))
+		return NULL;
+
+	/* Console processes which share a common console can be sent CTRL+C or
+	   CTRL+BREAK events, provided they handle said events. */
+	if (sig == CTRL_C_EVENT || sig == CTRL_BREAK_EVENT) {
+		if (GenerateConsoleCtrlEvent(sig, pid) == 0) {
+			err = GetLastError();
+			PyErr_SetFromWindowsErr(err);
+		}
+		else
+			Py_RETURN_NONE;
+	}
+
+	/* If the signal is outside of what GenerateConsoleCtrlEvent can use,
+	   attempt to open and terminate the process. */
+	handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+	if (handle == NULL) {
+		err = GetLastError();
+		return PyErr_SetFromWindowsErr(err);
+	}
+
+	if (TerminateProcess(handle, sig) == 0) {
+		err = GetLastError();
+		result = PyErr_SetFromWindowsErr(err);
+	} else {
+		Py_INCREF(Py_None);
+		result = Py_None;
+	}
+
+	CloseHandle(handle);
+	return result;
+}
+#endif /* MS_WINDOWS */
+
 #ifdef HAVE_PLOCK
 
 #ifdef HAVE_SYS_LOCK_H
@@ -8660,6 +8707,7 @@
 	{"popen3",	win32_popen3, METH_VARARGS},
 	{"popen4",	win32_popen4, METH_VARARGS},
 	{"startfile",	win32_startfile, METH_VARARGS, win32_startfile__doc__},
+	{"kill",    win32_kill, METH_VARARGS, win32_kill__doc__},
 #else
 #if defined(PYOS_OS2) && defined(PYCC_GCC)
 	{"popen2",	os2emx_popen2, METH_VARARGS},
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index cecb2be..bb7e4b0 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -7,6 +7,7 @@
 #include "intrcheck.h"
 
 #ifdef MS_WINDOWS
+#include <Windows.h>
 #ifdef HAVE_PROCESS_H
 #include <process.h>
 #endif
@@ -793,6 +794,18 @@
     	PyDict_SetItemString(d, "ItimerError", ItimerError);
 #endif
 
+#ifdef CTRL_C_EVENT
+    x = PyInt_FromLong(CTRL_C_EVENT);
+    PyDict_SetItemString(d, "CTRL_C_EVENT", x);
+    Py_DECREF(x);
+#endif
+
+#ifdef CTRL_BREAK_EVENT
+    x = PyInt_FromLong(CTRL_BREAK_EVENT);
+    PyDict_SetItemString(d, "CTRL_BREAK_EVENT", x);
+    Py_DECREF(x);
+#endif
+
         if (!PyErr_Occurred())
                 return;
 
diff --git a/PC/_subprocess.c b/PC/_subprocess.c
index bb240e1..b4680a7 100644
--- a/PC/_subprocess.c
+++ b/PC/_subprocess.c
@@ -586,4 +586,5 @@
 	defint(d, "INFINITE", INFINITE);
 	defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0);
 	defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE);
+	defint(d, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP);
 }