]> granicus.if.org Git - python/commitdiff
bpo-30794: added kill() method to multiprocessing.Process (#2528)
authorVitor Pereira <vmsousapereira@gmail.com>
Tue, 18 Jul 2017 15:34:23 +0000 (16:34 +0100)
committerAntoine Pitrou <pitrou@free.fr>
Tue, 18 Jul 2017 15:34:23 +0000 (17:34 +0200)
* 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

Doc/library/multiprocessing.rst
Lib/multiprocessing/popen_fork.py
Lib/multiprocessing/popen_spawn_win32.py
Lib/multiprocessing/process.py
Lib/test/_test_multiprocessing.py
Misc/NEWS.d/next/Library/2017-07-04-22-00-20.bpo-30794.qFwozm.rst [new file with mode: 0644]

index 5265639edb975d10735484918093bb52c4d7dc4a..9318a750919b67f9c7da299ed5577134fa52efe9 100644 (file)
@@ -598,6 +598,12 @@ The :mod:`multiprocessing` package mostly replicates the API of the
          acquired a lock or semaphore etc. then terminating it is liable to
          cause other processes to deadlock.
 
+   .. method:: kill()
+
+      Same as :meth:`terminate()` but using the ``SIGKILL`` signal on Unix.
+
+      .. versionadded:: 3.7
+
    .. method:: close()
 
       Close the :class:`Process` object, releasing all resources associated
index 5af9d919e4987ed87451af0c5eb21685ef018403..44ce9a9e79b0500599082e38862bccdb426407d3 100644 (file)
@@ -49,16 +49,22 @@ class Popen(object):
             return self.poll(os.WNOHANG if timeout == 0.0 else 0)
         return self.returncode
 
-    def terminate(self):
+    def _send_signal(self, sig):
         if self.returncode is None:
             try:
-                os.kill(self.pid, signal.SIGTERM)
+                os.kill(self.pid, sig)
             except ProcessLookupError:
                 pass
             except OSError:
                 if self.wait(timeout=0.1) is None:
                     raise
 
+    def terminate(self):
+        self._send_signal(signal.SIGTERM)
+
+    def kill(self):
+        self._send_signal(signal.SIGKILL)
+
     def _launch(self, process_obj):
         code = 1
         parent_r, child_w = os.pipe()
index ecb86e96ba43649e6e3fef500057c7b6c3b9040e..3e42e9c3387413a7afc70f19ee7dc55352ee22b2 100644 (file)
@@ -97,5 +97,7 @@ class Popen(object):
                 if self.wait(timeout=1.0) is None:
                     raise
 
+    kill = terminate
+
     def close(self):
         self.finalizer()
index fde97b7a67e4c8d8370dc341f6e1b300e01da383..ce4ce43cfca6fbd75d144f9cad2e3a31ea0516df 100644 (file)
@@ -122,6 +122,13 @@ class BaseProcess(object):
         self._check_closed()
         self._popen.terminate()
 
+    def kill(self):
+        '''
+        Terminate process; sends SIGKILL signal or uses TerminateProcess()
+        '''
+        self._check_closed()
+        self._popen.kill()
+
     def join(self, timeout=None):
         '''
         Wait until child process terminates
index d83b5a7b8dc4d3fe9d1f7237bd8f1a2023527244..0515730d14a853f7b2d5d058cd3b40d306c56c0f 100644 (file)
@@ -277,18 +277,18 @@ class _TestProcess(BaseTestCase):
         self.assertNotIn(p, self.active_children())
 
     @classmethod
-    def _test_terminate(cls):
+    def _sleep_some(cls):
         time.sleep(100)
 
     @classmethod
     def _test_sleep(cls, delay):
         time.sleep(delay)
 
-    def test_terminate(self):
+    def _kill_process(self, meth):
         if self.TYPE == 'threads':
             self.skipTest('test not appropriate for {}'.format(self.TYPE))
 
-        p = self.Process(target=self._test_terminate)
+        p = self.Process(target=self._sleep_some)
         p.daemon = True
         p.start()
 
@@ -309,7 +309,7 @@ class _TestProcess(BaseTestCase):
         # XXX maybe terminating too soon causes the problems on Gentoo...
         time.sleep(1)
 
-        p.terminate()
+        meth(p)
 
         if hasattr(signal, 'alarm'):
             # On the Gentoo buildbot waitpid() often seems to block forever.
@@ -333,9 +333,17 @@ class _TestProcess(BaseTestCase):
 
         p.join()
 
-        # sometimes get p.exitcode == 0 on Windows ...
+        return p.exitcode
+
+    def test_terminate(self):
+        exitcode = self._kill_process(multiprocessing.Process.terminate)
+        if os.name != 'nt':
+            self.assertEqual(exitcode, -signal.SIGTERM)
+
+    def test_kill(self):
+        exitcode = self._kill_process(multiprocessing.Process.kill)
         if os.name != 'nt':
-            self.assertEqual(p.exitcode, -signal.SIGTERM)
+            self.assertEqual(exitcode, -signal.SIGKILL)
 
     def test_cpu_count(self):
         try:
@@ -462,7 +470,7 @@ class _TestProcess(BaseTestCase):
         for p in procs:
             self.assertEqual(p.exitcode, 0)
 
-        procs = [self.Process(target=self._test_terminate)
+        procs = [self.Process(target=self._sleep_some)
                  for i in range(N)]
         for p in procs:
             p.start()
diff --git a/Misc/NEWS.d/next/Library/2017-07-04-22-00-20.bpo-30794.qFwozm.rst b/Misc/NEWS.d/next/Library/2017-07-04-22-00-20.bpo-30794.qFwozm.rst
new file mode 100644 (file)
index 0000000..d960bd3
--- /dev/null
@@ -0,0 +1,2 @@
+Added multiprocessing.Process.kill method to terminate using the SIGKILL
+signal on Unix.