summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2018-12-08 12:50:37 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2018-12-08 12:50:37 +0100
commitd4e2feddfb104d29e9b92043247b4e06b18312a4 (patch)
tree87324f1ef6d004d64c1b5feea99a28e473c5ff6b
parent10f780b7c2c0bb63417360891662680a39465140 (diff)
downloadpsutil-thread-safety-2.tar.gz
#1111 try to make Process.oneshot() thread safethread-safety-2
-rw-r--r--psutil/__init__.py69
1 files 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