summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2019-02-26 15:35:41 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2019-02-26 15:35:41 +0100
commitf240d984c8428dfad417ef516b837e1e7bb2769f (patch)
tree6c6a3c13a44fc1cd722a4366566d895214145872
parent96091c266e9ab09995ad027c069cb8ade771e6c7 (diff)
downloadpsutil-f240d984c8428dfad417ef516b837e1e7bb2769f.tar.gz
#1433, #1379: fix parents() method (infinite loop)
-rw-r--r--psutil/__init__.py27
-rwxr-xr-xpsutil/tests/test_posix.py2
2 files changed, 24 insertions, 5 deletions
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 70efc5af..2916764a 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -45,6 +45,7 @@ from ._common import memoize_when_activated
from ._common import wrap_numbers as _wrap_numbers
from ._compat import long
from ._compat import PY3 as _PY3
+from ._compat import lru_cache
from ._common import STATUS_DEAD
from ._common import STATUS_DISK_SLEEP
@@ -396,6 +397,11 @@ def _pprint_secs(secs):
return datetime.datetime.fromtimestamp(secs).strftime(fmt)
+@lru_cache()
+def _first_pid():
+ return sorted(pids())[0]
+
+
# =====================================================================
# --- Process class
# =====================================================================
@@ -660,11 +666,24 @@ class Process(object):
"""Return the parents of this process as a list of Process
instances. If no parents are known return an empty list.
"""
+ first_pid = _first_pid()
parents = []
proc = self.parent()
- while proc is not None:
- parents.append(proc)
- proc = proc.parent()
+ while True:
+ if proc is None:
+ break
+ elif proc.pid == first_pid:
+ # Needed because on certain systems such as macOS
+ # Process(0).ppid() returns 0.
+ parents.append(proc)
+ break
+ else:
+ par = proc.parent()
+ if par is None:
+ break
+ assert par.pid <= proc.pid, (par.pid, proc.pid)
+ parents.append(proc)
+ proc = par
return parents
def is_running(self):
@@ -2475,7 +2494,7 @@ def test(): # pragma: no cover
p.info['name'].strip() or '?'))
-del memoize, memoize_when_activated, division, deprecated_method
+del memoize, memoize_when_activated, division, deprecated_method, lru_cache
if sys.version_info[0] < 3:
del num, x
diff --git a/psutil/tests/test_posix.py b/psutil/tests/test_posix.py
index 5a8fdc17..955a4834 100755
--- a/psutil/tests/test_posix.py
+++ b/psutil/tests/test_posix.py
@@ -288,7 +288,7 @@ class TestProcess(unittest.TestCase):
failures = []
ignored_names = ['terminate', 'kill', 'suspend', 'resume', 'nice',
'send_signal', 'wait', 'children', 'as_dict',
- 'memory_info_ex']
+ 'memory_info_ex', 'parent', 'parents']
if LINUX and get_kernel_version() < (2, 6, 36):
ignored_names.append('rlimit')
if LINUX and get_kernel_version() < (2, 6, 23):