summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2020-05-25 00:15:41 +0200
committerGitHub <noreply@github.com>2020-05-25 00:15:41 +0200
commitc74ece234cf810796aa096e0880646879c758ae9 (patch)
tree353922c72bd13d5966c65a90b4aced627597b586
parentbd4d2bf420e1dfa3298143daebd485b97335b256 (diff)
downloadpsutil-c74ece234cf810796aa096e0880646879c758ae9.tar.gz
[macOS] Fix zombie leak detection on (#1766)
-rwxr-xr-x.ci/travis/install.sh12
-rw-r--r--HISTORY.rst1
-rw-r--r--psutil/_psbsd.py12
-rw-r--r--psutil/_psosx.py13
-rw-r--r--psutil/tests/__init__.py3
-rwxr-xr-xpsutil/tests/test_connections.py3
-rwxr-xr-xpsutil/tests/test_contracts.py3
7 files changed, 38 insertions, 9 deletions
diff --git a/.ci/travis/install.sh b/.ci/travis/install.sh
index f06e43d5..16bd5c0c 100755
--- a/.ci/travis/install.sh
+++ b/.ci/travis/install.sh
@@ -24,13 +24,21 @@ if [[ "$(uname -s)" == 'Darwin' ]]; then
pyenv install 3.6.6
pyenv virtualenv 3.6.6 psutil
;;
+ py37)
+ pyenv install 3.7.6
+ pyenv virtualenv 3.7.6 psutil
+ ;;
+ py38)
+ pyenv install 3.8.2
+ pyenv virtualenv 3.8.2 psutil
+ ;;
esac
pyenv rehash
pyenv activate psutil
fi
if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]] || [[ $PYVER == 'py27' ]]; then
- pip install -U ipaddress mock
+ pip install -U ipaddress mock unittest2
fi
-pip install -U coverage coveralls flake8 setuptools concurrencytest
+pip install -U coverage coveralls flake8 setuptools
diff --git a/HISTORY.rst b/HISTORY.rst
index 3bae76b4..3cb021a1 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -31,6 +31,7 @@ XXXX-XX-XX
- 1726_: [Linux] cpu_freq() parsing should use spaces instead of tabs on ia64.
(patch by Michał Górny)
- 1760_: [Linux] Process.rlimit() does not handle long long type properly.
+- 1766_: [macOS] NoSuchProcess may be raised instead of ZombieProcess.
5.7.0
=====
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index 49ad1e99..d53eb042 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -551,10 +551,10 @@ def wrap_exceptions(fun):
try:
return fun(self, *args, **kwargs)
except ProcessLookupError:
- if not pid_exists(self.pid):
- raise NoSuchProcess(self.pid, self._name)
- else:
+ if is_zombie(self.pid):
raise ZombieProcess(self.pid, self._name, self._ppid)
+ else:
+ raise NoSuchProcess(self.pid, self._name)
except PermissionError:
raise AccessDenied(self.pid, self._name)
except OSError:
@@ -576,10 +576,10 @@ def wrap_exceptions_procfs(inst):
# ENOENT (no such file or directory) gets raised on open().
# ESRCH (no such process) can get raised on read() if
# process is gone in meantime.
- if not pid_exists(inst.pid):
- raise NoSuchProcess(inst.pid, inst._name)
- else:
+ if is_zombie(inst.pid):
raise ZombieProcess(inst.pid, inst._name, inst._ppid)
+ else:
+ raise NoSuchProcess(inst.pid, inst._name)
except PermissionError:
raise AccessDenied(inst.pid, inst._name)
diff --git a/psutil/_psosx.py b/psutil/_psosx.py
index e4296495..2feff932 100644
--- a/psutil/_psosx.py
+++ b/psutil/_psosx.py
@@ -324,6 +324,14 @@ def pids():
pid_exists = _psposix.pid_exists
+def is_zombie(pid):
+ try:
+ st = cext.proc_kinfo_oneshot(pid)[kinfo_proc_map['status']]
+ return st == cext.SZOMB
+ except Exception:
+ return False
+
+
def wrap_exceptions(fun):
"""Decorator which translates bare OSError exceptions into
NoSuchProcess and AccessDenied.
@@ -333,7 +341,10 @@ def wrap_exceptions(fun):
try:
return fun(self, *args, **kwargs)
except ProcessLookupError:
- raise NoSuchProcess(self.pid, self._name)
+ if is_zombie(self.pid):
+ raise ZombieProcess(self.pid, self._name, self._ppid)
+ else:
+ raise NoSuchProcess(self.pid, self._name)
except PermissionError:
raise AccessDenied(self.pid, self._name)
except cext.ZombieProcessError:
diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py
index 6a119bf5..aac7614f 100644
--- a/psutil/tests/__init__.py
+++ b/psutil/tests/__init__.py
@@ -499,6 +499,9 @@ def terminate(proc_or_pid, sig=signal.SIGTERM, wait_timeout=GLOBAL_TIMEOUT):
pass
def sendsig(proc, sig):
+ # XXX: otherwise the build hangs for some reason.
+ if MACOS and GITHUB_WHEELS:
+ sig = signal.SIGKILL
# If the process received SIGSTOP, SIGCONT is necessary first,
# otherwise SIGTERM won't work.
if POSIX and sig != signal.SIGKILL:
diff --git a/psutil/tests/test_connections.py b/psutil/tests/test_connections.py
index 8a9a6eb4..1a9b32f7 100755
--- a/psutil/tests/test_connections.py
+++ b/psutil/tests/test_connections.py
@@ -38,6 +38,7 @@ from psutil.tests import enum
from psutil.tests import get_free_port
from psutil.tests import HAS_CONNECTIONS_UNIX
from psutil.tests import PsutilTestCase
+from psutil.tests import reap_children
from psutil.tests import serialrun
from psutil.tests import skip_on_access_denied
from psutil.tests import SKIP_SYSCONS
@@ -392,6 +393,8 @@ class TestFilters(_ConnTestCase):
@skip_on_access_denied(only_if=MACOS)
def test_combos(self):
+ reap_children()
+
def check_conn(proc, conn, family, type, laddr, raddr, status, kinds):
all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4",
"tcp6", "udp", "udp4", "udp6")
diff --git a/psutil/tests/test_contracts.py b/psutil/tests/test_contracts.py
index 35ab61e0..51bbb9f0 100755
--- a/psutil/tests/test_contracts.py
+++ b/psutil/tests/test_contracts.py
@@ -34,6 +34,7 @@ from psutil._compat import long
from psutil._compat import range
from psutil.tests import create_sockets
from psutil.tests import enum
+from psutil.tests import GITHUB_WHEELS
from psutil.tests import HAS_CPU_FREQ
from psutil.tests import HAS_NET_IO_COUNTERS
from psutil.tests import HAS_SENSORS_FANS
@@ -85,6 +86,7 @@ class TestAvailConstantsAPIs(PsutilTestCase):
ae(hasattr(psutil, "IOPRIO_LOW"), WINDOWS)
ae(hasattr(psutil, "IOPRIO_VERYLOW"), WINDOWS)
+ @unittest.skipIf(GITHUB_WHEELS, "not exposed via GITHUB_WHEELS")
def test_linux_rlimit(self):
ae = self.assertEqual
ae(hasattr(psutil, "RLIM_INFINITY"), LINUX)
@@ -149,6 +151,7 @@ class TestAvailProcessAPIs(PsutilTestCase):
def test_ionice(self):
self.assertEqual(hasattr(psutil.Process, "ionice"), LINUX or WINDOWS)
+ @unittest.skipIf(GITHUB_WHEELS, "not exposed via GITHUB_WHEELS")
def test_rlimit(self):
# requires Linux 2.6.36
self.assertEqual(hasattr(psutil.Process, "rlimit"), LINUX)