Index: Lib/subprocess.py =================================================================== --- Lib/subprocess.py (revision 69127) +++ Lib/subprocess.py (working copy) @@ -951,18 +951,18 @@ self.wait() return (stdout, stderr) - def send_signal(self, sig): + def send_signal(self, sig, group=False): """Send a signal to the process """ if sig == signal.SIGTERM: - self.terminate() + self.terminate(group=group) else: raise ValueError("Only SIGTERM is supported on Windows") - def terminate(self): + def terminate(self, group=False): """Terminates the process """ - TerminateProcess(self._handle, 1) + TerminateProcess(self._handle, 1, group) kill = terminate @@ -1069,6 +1069,11 @@ if self.pid == 0: # Child try: + # If we're on unix, register the process in this process's + # subgroup. + if not mswindows: + os.setpgid(0, 0) + # Close parent's pipe ends if p2cwrite is not None: os.close(p2cwrite) @@ -1254,20 +1259,23 @@ self.wait() return (stdout, stderr) - def send_signal(self, sig): + def send_signal(self, sig, group=False): """Send a signal to the process """ - os.kill(self.pid, sig) + if group: + os.killpg(self.pid, sig) + else: + os.kill(self.pid, sig) - def terminate(self): + def terminate(self, group=False): """Terminate the process with SIGTERM """ - self.send_signal(signal.SIGTERM) + self.send_signal(signal.SIGTERM, group) - def kill(self): + def kill(self, group=False): """Kill the process with SIGKILL """ - self.send_signal(signal.SIGKILL) + self.send_signal(signal.SIGKILL, group) def _demo_posix(): Index: PC/_subprocess.c =================================================================== --- PC/_subprocess.c (revision 69127) +++ PC/_subprocess.c (working copy) @@ -452,11 +452,17 @@ HANDLE process; int exit_code; - if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:TerminateProcess", + int group = 0; + + if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i|i:TerminateProcess", &process, &exit_code)) return NULL; - result = TerminateProcess(process, exit_code); + if (group) { + result = TerminateJobObject(process, exit_code); + } else { + result = TerminateProcess(process, exit_code); + } if (! result) return PyErr_SetFromWindowsErr(GetLastError()); Index: Lib/test/test_subprocess.py =================================================================== --- Lib/test/test_subprocess.py (revision 69127) +++ Lib/test/test_subprocess.py (working copy) @@ -644,6 +644,13 @@ p.send_signal(signal.SIGINT) self.assertNotEqual(p.wait(), 0) + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.send_signal(signal.SIGINT, group=True) + self.assertNotEqual(p.wait(), 0) + def DISABLED_test_kill(self): p = subprocess.Popen([sys.executable, "-c", "input()"]) @@ -652,6 +659,13 @@ p.kill() self.assertEqual(p.wait(), -signal.SIGKILL) + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.kill(group=True) + self.assertEqual(p.wait(), -signal.SIGKILL) + def DISABLED_test_terminate(self): p = subprocess.Popen([sys.executable, "-c", "input()"]) @@ -660,6 +674,13 @@ p.terminate() self.assertEqual(p.wait(), -signal.SIGTERM) + p = subprocess.Popen([sys.executable, + "-c", "input()"]) + + self.assert_(p.poll() is None, p.poll()) + p.terminate(group=True) + self.assertEqual(p.wait(), -signal.SIGTERM) + # # Windows tests #