Skip to content

Commit ba75af7

Browse files
vmsppitrou
authored andcommitted
bpo-30794: added kill() method to multiprocessing.Process (#2528)
* bpo-30794: added kill() method to multiprocessing.Process * Added entries to documentation and NEWS * Refactored test_terminate and test_kill * Fix SIGTERM and SIGKILL being used on Windows for the tests * Added "versionadded" marker to the documentation * Fix trailing whitespace in doc
1 parent f474c5a commit ba75af7

6 files changed

Lines changed: 40 additions & 9 deletions

File tree

Doc/library/multiprocessing.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,12 @@ The :mod:`multiprocessing` package mostly replicates the API of the
598598
acquired a lock or semaphore etc. then terminating it is liable to
599599
cause other processes to deadlock.
600600

601+
.. method:: kill()
602+
603+
Same as :meth:`terminate()` but using the ``SIGKILL`` signal on Unix.
604+
605+
.. versionadded:: 3.7
606+
601607
.. method:: close()
602608

603609
Close the :class:`Process` object, releasing all resources associated

Lib/multiprocessing/popen_fork.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,22 @@ def wait(self, timeout=None):
4949
return self.poll(os.WNOHANG if timeout == 0.0 else 0)
5050
return self.returncode
5151

52-
def terminate(self):
52+
def _send_signal(self, sig):
5353
if self.returncode is None:
5454
try:
55-
os.kill(self.pid, signal.SIGTERM)
55+
os.kill(self.pid, sig)
5656
except ProcessLookupError:
5757
pass
5858
except OSError:
5959
if self.wait(timeout=0.1) is None:
6060
raise
6161

62+
def terminate(self):
63+
self._send_signal(signal.SIGTERM)
64+
65+
def kill(self):
66+
self._send_signal(signal.SIGKILL)
67+
6268
def _launch(self, process_obj):
6369
code = 1
6470
parent_r, child_w = os.pipe()

Lib/multiprocessing/popen_spawn_win32.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,7 @@ def terminate(self):
9797
if self.wait(timeout=1.0) is None:
9898
raise
9999

100+
kill = terminate
101+
100102
def close(self):
101103
self.finalizer()

Lib/multiprocessing/process.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ def terminate(self):
122122
self._check_closed()
123123
self._popen.terminate()
124124

125+
def kill(self):
126+
'''
127+
Terminate process; sends SIGKILL signal or uses TerminateProcess()
128+
'''
129+
self._check_closed()
130+
self._popen.kill()
131+
125132
def join(self, timeout=None):
126133
'''
127134
Wait until child process terminates

Lib/test/_test_multiprocessing.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,18 +277,18 @@ def test_process(self):
277277
self.assertNotIn(p, self.active_children())
278278

279279
@classmethod
280-
def _test_terminate(cls):
280+
def _sleep_some(cls):
281281
time.sleep(100)
282282

283283
@classmethod
284284
def _test_sleep(cls, delay):
285285
time.sleep(delay)
286286

287-
def test_terminate(self):
287+
def _kill_process(self, meth):
288288
if self.TYPE == 'threads':
289289
self.skipTest('test not appropriate for {}'.format(self.TYPE))
290290

291-
p = self.Process(target=self._test_terminate)
291+
p = self.Process(target=self._sleep_some)
292292
p.daemon = True
293293
p.start()
294294

@@ -309,7 +309,7 @@ def test_terminate(self):
309309
# XXX maybe terminating too soon causes the problems on Gentoo...
310310
time.sleep(1)
311311

312-
p.terminate()
312+
meth(p)
313313

314314
if hasattr(signal, 'alarm'):
315315
# On the Gentoo buildbot waitpid() often seems to block forever.
@@ -333,9 +333,17 @@ def handler(*args):
333333

334334
p.join()
335335

336-
# sometimes get p.exitcode == 0 on Windows ...
336+
return p.exitcode
337+
338+
def test_terminate(self):
339+
exitcode = self._kill_process(multiprocessing.Process.terminate)
340+
if os.name != 'nt':
341+
self.assertEqual(exitcode, -signal.SIGTERM)
342+
343+
def test_kill(self):
344+
exitcode = self._kill_process(multiprocessing.Process.kill)
337345
if os.name != 'nt':
338-
self.assertEqual(p.exitcode, -signal.SIGTERM)
346+
self.assertEqual(exitcode, -signal.SIGKILL)
339347

340348
def test_cpu_count(self):
341349
try:
@@ -462,7 +470,7 @@ def test_many_processes(self):
462470
for p in procs:
463471
self.assertEqual(p.exitcode, 0)
464472

465-
procs = [self.Process(target=self._test_terminate)
473+
procs = [self.Process(target=self._sleep_some)
466474
for i in range(N)]
467475
for p in procs:
468476
p.start()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added multiprocessing.Process.kill method to terminate using the SIGKILL
2+
signal on Unix.

0 commit comments

Comments
 (0)