summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2018-12-08 12:32:31 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2018-12-08 12:32:31 +0100
commit5398c48047d424af97644879fb4eaa7aad432f58 (patch)
tree5d889fa8571be69449a296d65e1c82c40d78fb87
parentc0f6b1d6514bad029995305e68dd127206e82864 (diff)
downloadpsutil-5398c48047d424af97644879fb4eaa7aad432f58.tar.gz
#1111 make Process.oneshot() thread-safe
-rw-r--r--HISTORY.rst1
-rw-r--r--psutil/__init__.py69
2 files changed, 37 insertions, 33 deletions
diff --git a/HISTORY.rst b/HISTORY.rst
index 7a26f50e..e66f5b49 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -13,6 +13,7 @@ XXXX-XX-XX
**Bug fixes**
+- 1111_: Process.oneshot() is now thread safe.
- 1354_: [Linux] disk_io_counters() fails on Linux kernel 4.18+.
- 1368_: [Windows] fix psutil.Process().ionice(...) mismatch. (patch by
EccoTheFlintstone)
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