Skip to content

Commit

Permalink
giampaolo#1111 make Process.oneshot() thread-safe
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Dec 8, 2018
1 parent c0f6b1d commit 5398c48
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 33 deletions.
1 change: 1 addition & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
69 changes: 36 additions & 33 deletions psutil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import signal
import subprocess
import sys
import threading
import time
try:
import pwd
Expand Down Expand Up @@ -360,6 +361,7 @@ def _init(self, pid, _ignore_nsp=False):
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()
Expand Down Expand Up @@ -456,40 +458,41 @@ def oneshot(self):
...
>>>
"""
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
Expand Down

0 comments on commit 5398c48

Please sign in to comment.