From d4e2feddfb104d29e9b92043247b4e06b18312a4 Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Sat, 8 Dec 2018 12:50:37 +0100 Subject: #1111 try to make Process.oneshot() thread safe --- psutil/__init__.py | 69 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/psutil/__init__.py b/psutil/__init__.py index 5a5720d7..0eb19799 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -31,6 +31,7 @@ import os import signal import subprocess import sys +import threading import time try: import pwd @@ -360,6 +361,7 @@ class Process(object): self._proc = _psplatform.Process(pid) self._last_sys_cpu_times = None self._last_proc_cpu_times = None + self._lock = threading.RLock() # cache creation time for later use in is_running() method try: self.create_time() @@ -456,40 +458,41 @@ class Process(object): ... >>> """ - if self._oneshot_inctx: - # NOOP: this covers the use case where the user enters the - # context twice. Since as_dict() internally uses oneshot() - # I expect that the code below will be a pretty common - # "mistake" that the user will make, so let's guard - # against that: - # - # >>> with p.oneshot(): - # ... p.as_dict() - # ... - yield - else: - self._oneshot_inctx = True - try: - # cached in case cpu_percent() is used - self.cpu_times.cache_activate() - # cached in case memory_percent() is used - self.memory_info.cache_activate() - # cached in case parent() is used - self.ppid.cache_activate() - # cached in case username() is used - if POSIX: - self.uids.cache_activate() - # specific implementation cache - self._proc.oneshot_enter() + with self._lock: + if self._oneshot_inctx: + # NOOP: this covers the use case where the user enters the + # context twice. Since as_dict() internally uses oneshot() + # I expect that the code below will be a pretty common + # "mistake" that the user will make, so let's guard + # against that: + # + # >>> with p.oneshot(): + # ... p.as_dict() + # ... yield - finally: - self.cpu_times.cache_deactivate() - self.memory_info.cache_deactivate() - self.ppid.cache_deactivate() - if POSIX: - self.uids.cache_deactivate() - self._proc.oneshot_exit() - self._oneshot_inctx = False + else: + self._oneshot_inctx = True + try: + # cached in case cpu_percent() is used + self.cpu_times.cache_activate() + # cached in case memory_percent() is used + self.memory_info.cache_activate() + # cached in case parent() is used + self.ppid.cache_activate() + # cached in case username() is used + if POSIX: + self.uids.cache_activate() + # specific implementation cache + self._proc.oneshot_enter() + yield + finally: + self.cpu_times.cache_deactivate() + self.memory_info.cache_deactivate() + self.ppid.cache_deactivate() + if POSIX: + self.uids.cache_deactivate() + self._proc.oneshot_exit() + self._oneshot_inctx = False def as_dict(self, attrs=None, ad_value=None): """Utility method returning process information as a -- cgit v1.2.1