diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2019-02-26 15:35:41 +0100 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2019-02-26 15:35:41 +0100 |
commit | f240d984c8428dfad417ef516b837e1e7bb2769f (patch) | |
tree | 6c6a3c13a44fc1cd722a4366566d895214145872 | |
parent | 96091c266e9ab09995ad027c069cb8ade771e6c7 (diff) | |
download | psutil-f240d984c8428dfad417ef516b837e1e7bb2769f.tar.gz |
#1433, #1379: fix parents() method (infinite loop)
-rw-r--r-- | psutil/__init__.py | 27 | ||||
-rwxr-xr-x | psutil/tests/test_posix.py | 2 |
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): |