Skip to content
Browse files

Better handling of zombies in is_running()

  • Loading branch information...
1 parent 06acbf4 commit 2f495219b7d6d92e10a861d2a95cc10fe2a3483d @kumar303 committed
Showing with 44 additions and 13 deletions.
  1. +23 −5 desub/desub.py
  2. +1 −1 setup.py
  3. +20 −7 tests/test.py
View
28 desub/desub.py
@@ -5,7 +5,6 @@
import json
import os
import re
-import shutil
import signal
import subprocess
@@ -116,16 +115,35 @@ def __init__(self, cmd_args, **kw):
self.save_data()
def is_running(self):
- """True if the subprocess is running."""
+ """
+ True if the subprocess is running.
+
+ If it's a zombie then we call
+ :func:`desub.Desub.stop` to kill it with fire and return False.
+ """
pp = self.pid
if pp:
try:
proc = psutil.Process(pp)
- if str(proc.status) == 'running':
- return True
- else: # zombie script!
+
+ # Possible status:
+ # "STATUS_RUNNING", "STATUS_IDLE",
+ # "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
+ # "STATUS_STOPPED", "STATUS_TRACING_STOP",
+ # "STATUS_ZOMBIE", "STATUS_DEAD",
+ # "STATUS_WAKING", "STATUS_LOCKED",
+
+ if proc.status in (psutil.STATUS_STOPPED,
+ psutil.STATUS_DEAD,
+ psutil.STATUS_ZOMBIE):
+ # The PID is still in the process table so call stop to
+ # remove the PID.
self.stop()
return False
+ else:
+ # OK, it's running.
+ return True
+
except psutil.NoSuchProcess:
pass
return False
View
2 setup.py
@@ -8,7 +8,7 @@ def path(name):
setup(name='desub',
- version='1.0.2',
+ version='1.0.3',
description='Work with a detached subprocess.',
long_description=path('README.rst').read(),
author='Kumar McMillan',
View
27 tests/test.py
@@ -11,25 +11,37 @@
import desub
-class Test(unittest.TestCase):
+class Base(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.mkdtemp()
- self.proc = self.join()
+ self.proc = None
def tearDown(self):
- self.proc.stop()
+ if self.proc and self.proc.is_running():
+ try:
+ self.proc.stop(timeout=2)
+ except psutil.TimeoutExpired:
+ print ' ** could not stop pid %s' % self.proc.pid
shutil.rmtree(self.tmp)
- def join(self):
- return desub.join([sys.executable,
- self.cmd('loop.py')], root=self.tmp)
-
def cmd(self, name):
return os.path.join(os.path.dirname(__file__), 'cmd', name)
+ def join(self, cmd='loop.py'):
+ return desub.join([sys.executable,
+ self.cmd(cmd)], root=self.tmp)
+
+
+class TestLongRunningCmd(Base):
+
+ def setUp(self):
+ super(TestLongRunningCmd, self).setUp()
+ self.proc = self.join()
+
def test_start(self):
self.proc.start()
+ eq_(self.proc.is_running(), True)
pp = psutil.Process(self.proc.pid)
eq_(pp.status, 'running')
self.proc.stop()
@@ -41,6 +53,7 @@ def test_stop(self):
pid = self.proc.pid
self.proc.stop()
psutil.Process(pid)
+ eq_(self.proc.is_running(), False)
def test_stop_preserves_root(self):
self.proc.start()

0 comments on commit 2f49521

Please sign in to comment.
Something went wrong with that request. Please try again.