summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2017-01-10 14:59:20 +0100
committerGiampaolo Rodola <g.rodola@gmail.com>2017-01-10 14:59:20 +0100
commit12a2a793f45a445275ec667feb701692621a875f (patch)
tree35daa0f9eadf7c062c30f2a1da35dfa5ab5b11ed
parentc5cc270ed2b8953de81a4f4a29ce48808b9abafb (diff)
parent6e60cc93c68f243dcaf3c895fcd8a9fabcedba4b (diff)
downloadpsutil-12a2a793f45a445275ec667feb701692621a875f.tar.gz
Merge branch 'master' into 941-cpu-freq
-rw-r--r--DEVGUIDE.rst6
-rw-r--r--HISTORY.rst16
-rw-r--r--INSTALL.rst2
-rw-r--r--MANIFEST.in15
-rw-r--r--Makefile10
-rw-r--r--README.rst2
-rw-r--r--docs/_themes/pydoctheme/static/pydoctheme.css10
-rw-r--r--docs/conf.py2
-rw-r--r--docs/index.rst314
-rw-r--r--psutil/__init__.py27
-rw-r--r--psutil/_psbsd.py22
-rw-r--r--psutil/_pslinux.py28
-rw-r--r--psutil/_psutil_bsd.c105
-rw-r--r--psutil/_psutil_posix.c63
-rw-r--r--psutil/arch/bsd/netbsd.c4
-rw-r--r--psutil/tests/__init__.py4
-rwxr-xr-xpsutil/tests/test_linux.py19
-rwxr-xr-xpsutil/tests/test_process.py13
-rwxr-xr-xsetup.py46
19 files changed, 434 insertions, 274 deletions
diff --git a/DEVGUIDE.rst b/DEVGUIDE.rst
index 95bea79a..93dfa690 100644
--- a/DEVGUIDE.rst
+++ b/DEVGUIDE.rst
@@ -1,6 +1,6 @@
-=====
-Setup
-=====
+=======================
+Setup and running tests
+=======================
If you plan on hacking on psutil this is what you're supposed to do first:
diff --git a/HISTORY.rst b/HISTORY.rst
index f93e0974..92413ec1 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,10 +1,22 @@
*Bug tracker at https://github.com/giampaolo/psutil/issues*
-5.0.1
+5.0.2
=====
*XXXX-XX-XX*
+**Bug fixes**
+
+- 687_: [Linux] pid_exists() no longer returns True if passed a process thread
+ ID.
+- 948_: cannot install psutil with PYTHONOPTIMIZE=2.
+
+
+5.0.1
+=====
+
+*2016-12-21*
+
**Enhancements**
- 939_: tar.gz distribution went from 1.8M to 258K.
@@ -13,10 +25,12 @@
**Bug fixes**
+- 609_: [SunOS] psutil does not compile on Solaris 10.
- 936_: [Windows] fix compilation error on VS 2013 (patch by Max Bélanger).
- 940_: [Linux] cpu_percent() and cpu_times_percent() was calculated
incorrectly as "iowait", "guest" and "guest_nice" times were not properly
taken into account.
+- 944_: [OpenBSD] psutil.pids() was omitting PID 0.
5.0.0
diff --git a/INSTALL.rst b/INSTALL.rst
index b1b40d68..fcbc3736 100644
--- a/INSTALL.rst
+++ b/INSTALL.rst
@@ -62,7 +62,7 @@ versions.
OSX
===
-Install `XcodeTools <https://developer.apple.com/downloads/?name=Xcode>`__
+Install `Xcode <https://developer.apple.com/downloads/?name=Xcode>`__
first, then:
::
diff --git a/MANIFEST.in b/MANIFEST.in
index 94532292..b0c15645 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,7 +1,18 @@
+include *.bat
include *.rst
+include .coveragerc
include CREDITS*
+include IDEAS
include INSTALL*
include LICENSE*
-include make.bar
+include HISTORY*
include Makefile
-recursive-include psutil *.py *.c *.h
+include tox.ini
+
+recursive-include psutil *.py *.c *.h *.rst
+recursive-include scripts *.py
+recursive-include README*
+
+recursive-include docs *.conf *.rst *.js *.html *.css *.py *.bat *Makefile* README*
+recursive-exclude docs/_build *
+recursive-exclude .ci *
diff --git a/Makefile b/Makefile
index c91d3b96..9224a0bb 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,7 @@ ARGS =
# List of nice-to-have dev libs.
DEPS = argparse \
+ check-manifest \
coverage \
flake8 \
futures \
@@ -171,6 +172,9 @@ pyflakes:
flake8:
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8
+check-manifest:
+ $(PYTHON) -m check_manifest -v $(ARGS)
+
# ===================================================================
# GIT
# ===================================================================
@@ -249,3 +253,9 @@ bench-oneshot: install
# same as above but using perf module (supposed to be more precise)
bench-oneshot-2: install
$(PYTHON) scripts/internal/bench_oneshot_2.py
+
+# generate a doc.zip file and manually upload it to PYPI.
+doc:
+ cd docs && make html && cd _build/html/ && zip doc.zip -r .
+ mv docs/_build/html/doc.zip .
+ echo "done; now manually upload doc.zip from here: https://pypi.python.org/pypi?:action=pkg_edit&name=psutil"
diff --git a/README.rst b/README.rst
index 91d41cdb..d413f1e8 100644
--- a/README.rst
+++ b/README.rst
@@ -71,7 +71,7 @@ Projects using psutil
=====================
At the time of writing there are over
-`4000 projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
+`4200 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
on github which depend from psutil.
Here's some I find particularly interesting:
diff --git a/docs/_themes/pydoctheme/static/pydoctheme.css b/docs/_themes/pydoctheme/static/pydoctheme.css
index 4196e558..c6f19ab7 100644
--- a/docs/_themes/pydoctheme/static/pydoctheme.css
+++ b/docs/_themes/pydoctheme/static/pydoctheme.css
@@ -185,3 +185,13 @@ div.body h3 {
div.body h2 {
padding-left:10px;
}
+
+.data {
+ margin-top: 4px !important;
+ margin-bottom: 4px !important;
+}
+
+.data dd {
+ margin-top: 0px !important;
+ margin-bottom: 0px !important;
+}
diff --git a/docs/conf.py b/docs/conf.py
index 2267b5d1..f0a206db 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -46,7 +46,7 @@ needs_sphinx = '1.0'
# ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.coverage',
- 'sphinx.ext.pngmath',
+ 'sphinx.ext.imgmath',
'sphinx.ext.viewcode',
'sphinx.ext.intersphinx']
diff --git a/docs/index.rst b/docs/index.rst
index bd2773da..022c6a6b 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -156,13 +156,14 @@ CPU
in Python 3.4).
If *logical* is ``False`` return the number of physical cores only (hyper
thread CPUs are excluded). Return ``None`` if undetermined.
+ On OpenBSD and NetBSD ``psutil.cpu_count(logical=False)`` always return
+ ``None``. Example on a system having 2 physical hyper-thread CPU cores:
>>> import psutil
>>> psutil.cpu_count()
4
>>> psutil.cpu_count(logical=False)
2
- >>>
.. function:: cpu_stats()
@@ -453,7 +454,7 @@ Network
else ``None``. On some platforms (e.g. Linux) the availability of this
field changes depending on process privileges (root is needed).
- The *kind* parameter is a string which filters for connections that fit the
+ The *kind* parameter is a string which filters for connections matching the
following criteria:
.. table::
@@ -461,27 +462,27 @@ Network
+----------------+-----------------------------------------------------+
| **Kind value** | **Connections using** |
+================+=====================================================+
- | "inet" | IPv4 and IPv6 |
+ | ``"inet"`` | IPv4 and IPv6 |
+----------------+-----------------------------------------------------+
- | "inet4" | IPv4 |
+ | ``"inet4"`` | IPv4 |
+----------------+-----------------------------------------------------+
- | "inet6" | IPv6 |
+ | ``"inet6"`` | IPv6 |
+----------------+-----------------------------------------------------+
- | "tcp" | TCP |
+ | ``"tcp"`` | TCP |
+----------------+-----------------------------------------------------+
- | "tcp4" | TCP over IPv4 |
+ | ``"tcp4"`` | TCP over IPv4 |
+----------------+-----------------------------------------------------+
- | "tcp6" | TCP over IPv6 |
+ | ``"tcp6"`` | TCP over IPv6 |
+----------------+-----------------------------------------------------+
- | "udp" | UDP |
+ | ``"udp"`` | UDP |
+----------------+-----------------------------------------------------+
- | "udp4" | UDP over IPv4 |
+ | ``"udp4"`` | UDP over IPv4 |
+----------------+-----------------------------------------------------+
- | "udp6" | UDP over IPv6 |
+ | ``"udp6"`` | UDP over IPv6 |
+----------------+-----------------------------------------------------+
- | "unix" | UNIX socket (both UDP and TCP protocols) |
+ | ``"unix"`` | UNIX socket (both UDP and TCP protocols) |
+----------------+-----------------------------------------------------+
- | "all" | the sum of all the possible families and protocols |
+ | ``"all"`` | the sum of all the possible families and protocols |
+----------------+-----------------------------------------------------+
On OSX this function requires root privileges.
@@ -632,12 +633,16 @@ Functions
.. function:: pids()
Return a list of current running PIDs. To iterate over all processes
- :func:`process_iter()` should be preferred.
+ and avoid race conditions :func:`process_iter()` should be preferred.
+
+ >>> import psutil
+ >>> psutil.pids()
+ [1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, ..., 32498]
.. function:: pid_exists(pid)
Check whether the given PID exists in the current process list. This is
- faster than doing ``"pid in psutil.pids()"`` and should be preferred.
+ faster than doing ``pid in psutil.pids()`` and should be preferred.
.. function:: process_iter()
@@ -678,18 +683,18 @@ Functions
- give them some time to terminate
- send SIGKILL to those ones which are still alive
- Example::
+ Example which terminates and waits all the children of this process::
import psutil
def on_terminate(proc):
print("process {} terminated with exit code {}".format(proc, proc.returncode))
- procs = [...] # a list of Process instances
+ procs = psutil.Process().children()
for p in procs:
p.terminate()
- gone, alive = psutil.wait_procs(procs, timeout=3, callback=on_terminate)
- for p in alive:
+ gone, still_alive = psutil.wait_procs(procs, timeout=3, callback=on_terminate)
+ for p in still_alive:
p.kill()
Exceptions
@@ -702,8 +707,8 @@ Exceptions
.. class:: NoSuchProcess(pid, name=None, msg=None)
Raised by :class:`Process` class methods when no process with the given
- pid* is found in the current process list or when a process no longer
- exists. "name" is the name the process had before disappearing
+ *pid* is found in the current process list or when a process no longer
+ exists. *name* is the name the process had before disappearing
and gets set only if :meth:`Process.name()` was previously called.
.. class:: ZombieProcess(pid, name=None, ppid=None, msg=None)
@@ -733,10 +738,12 @@ Process class
.. class:: Process(pid=None)
- Represents an OS process with the given *pid*. If *pid* is omitted current
- process *pid* (`os.getpid() <http://docs.python.org/library/os.html#os.getpid>`__)
- is used.
+ Represents an OS process with the given *pid*.
+ If *pid* is omitted current process *pid*
+ (`os.getpid() <http://docs.python.org/library/os.html#os.getpid>`__) is used.
Raise :class:`NoSuchProcess` if *pid* does not exist.
+ On Linux *pid* can also refer to a thread ID (the *id* field returned by
+ :meth:`threads` method).
When accessing methods of this class always be prepared to catch
:class:`NoSuchProcess`, :class:`ZombieProcess` and :class:`AccessDenied`
exceptions.
@@ -858,7 +865,7 @@ Process class
.. method:: ppid()
- The process parent pid. On Windows the return value is cached after first
+ The process parent PID. On Windows the return value is cached after first
call. Not on POSIX because
`ppid may change <https://github.com/giampaolo/psutil/issues/321>`__
if process becomes a zombie.
@@ -875,16 +882,28 @@ Process class
On some systems this may also be an empty string.
The return value is cached after first call.
+ >>> import psutil
+ >>> psutil.Process().exe()
+ '/usr/bin/python2.7'
+
.. method:: cmdline()
- The command line this process has been called with. The return value is not
- cached because the cmdline of a process may change.
+ The command line this process has been called with as a list of strings.
+ The return value is not cached because the cmdline of a process may change.
+
+ >>> import psutil
+ >>> psutil.Process().cmdline()
+ ['python', 'manage.py', 'runserver']
.. method:: environ()
The environment variables of the process as a dict. Note: this might not
reflect changes made after the process started.
+ >>> import psutil
+ >>> psutil.Process().environ()
+ {'LC_NUMERIC': 'it_IT.UTF-8', 'QT_QPA_PLATFORMTHEME': 'appmenu-qt5', 'IM_CONFIG_PHASE': '1', 'XDG_GREETER_DATA_DIR': '/var/lib/lightdm-data/giampaolo', 'GNOME_DESKTOP_SESSION_ID': 'this-is-deprecated', 'XDG_CURRENT_DESKTOP': 'Unity', 'UPSTART_EVENTS': 'started starting', 'GNOME_KEYRING_PID': '', 'XDG_VTNR': '7', 'QT_IM_MODULE': 'ibus', 'LOGNAME': 'giampaolo', 'USER': 'giampaolo', 'PATH': '/home/giampaolo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/giampaolo/svn/sysconf/bin', 'LC_PAPER': 'it_IT.UTF-8', 'GNOME_KEYRING_CONTROL': '', 'GTK_IM_MODULE': 'ibus', 'DISPLAY': ':0', 'LANG': 'en_US.UTF-8', 'LESS_TERMCAP_se': '\x1b[0m', 'TERM': 'xterm-256color', 'SHELL': '/bin/bash', 'XDG_SESSION_PATH': '/org/freedesktop/DisplayManager/Session0', 'XAUTHORITY': '/home/giampaolo/.Xauthority', 'LANGUAGE': 'en_US', 'COMPIZ_CONFIG_PROFILE': 'ubuntu', 'LC_MONETARY': 'it_IT.UTF-8', 'QT_LINUX_ACCESSIBILITY_ALWAYS_ON': '1', 'LESS_TERMCAP_me': '\x1b[0m', 'LESS_TERMCAP_md': '\x1b[01;38;5;74m', 'LESS_TERMCAP_mb': '\x1b[01;31m', 'HISTSIZE': '100000', 'UPSTART_INSTANCE': '', 'CLUTTER_IM_MODULE': 'xim', 'WINDOWID': '58786407', 'EDITOR': 'vim', 'SESSIONTYPE': 'gnome-session', 'XMODIFIERS': '@im=ibus', 'GPG_AGENT_INFO': '/home/giampaolo/.gnupg/S.gpg-agent:0:1', 'HOME': '/home/giampaolo', 'HISTFILESIZE': '100000', 'QT4_IM_MODULE': 'xim', 'GTK2_MODULES': 'overlay-scrollbar', 'XDG_SESSION_DESKTOP': 'ubuntu', 'SHLVL': '1', 'XDG_RUNTIME_DIR': '/run/user/1000', 'INSTANCE': 'Unity', 'LC_ADDRESS': 'it_IT.UTF-8', 'SSH_AUTH_SOCK': '/run/user/1000/keyring/ssh', 'VTE_VERSION': '4205', 'GDMSESSION': 'ubuntu', 'MANDATORY_PATH': '/usr/share/gconf/ubuntu.mandatory.path', 'VISUAL': 'vim', 'DESKTOP_SESSION': 'ubuntu', 'QT_ACCESSIBILITY': '1', 'XDG_SEAT_PATH': '/org/freedesktop/DisplayManager/Seat0', 'LESSCLOSE': '/usr/bin/lesspipe %s %s', 'LESSOPEN': '| /usr/bin/lesspipe %s', 'XDG_SESSION_ID': 'c2', 'DBUS_SESSION_BUS_ADDRESS': 'unix:abstract=/tmp/dbus-9GAJpvnt8r', '_': '/usr/bin/python', 'DEFAULTS_PATH': '/usr/share/gconf/ubuntu.default.path', 'LC_IDENTIFICATION': 'it_IT.UTF-8', 'LESS_TERMCAP_ue': '\x1b[0m', 'UPSTART_SESSION': 'unix:abstract=/com/ubuntu/upstart-session/1000/1294', 'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg', 'GTK_MODULES': 'gail:atk-bridge:unity-gtk-module', 'XDG_SESSION_TYPE': 'x11', 'PYTHONSTARTUP': '/home/giampaolo/.pythonstart', 'LC_NAME': 'it_IT.UTF-8', 'OLDPWD': '/home/giampaolo/svn/curio_giampaolo/tests', 'GDM_LANG': 'en_US', 'LC_TELEPHONE': 'it_IT.UTF-8', 'HISTCONTROL': 'ignoredups:erasedups', 'LC_MEASUREMENT': 'it_IT.UTF-8', 'PWD': '/home/giampaolo/svn/curio_giampaolo', 'JOB': 'gnome-session', 'LESS_TERMCAP_us': '\x1b[04;38;5;146m', 'UPSTART_JOB': 'unity-settings-daemon', 'LC_TIME': 'it_IT.UTF-8', 'LESS_TERMCAP_so': '\x1b[38;5;246m', 'PAGER': 'less', 'XDG_DATA_DIRS': '/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop', 'XDG_SEAT': 'seat0'}
+
Availability: Linux, OSX, Windows
.. versionadded:: 4.0.0
@@ -1100,7 +1119,7 @@ Process class
Return threads opened by process as a list of namedtuples including thread
id and thread CPU times (user/system). On OpenBSD this method requires
- root access.
+ root privileges.
.. method:: cpu_times()
@@ -1118,9 +1137,9 @@ Process class
.. method:: cpu_percent(interval=None)
- Return a float representing the process CPU utilization as a percentage.
- The returned value refers to the utilization of a single CPU, i.e. it is
- not evenly split between the number of available CPU cores.
+ Return a float representing the process CPU utilization as a percentage
+ which can also be ``> 100.0`` in case of a process running multiple threads
+ on different CPUs.
When *interval* is > ``0.0`` compares process times to system CPU times
elapsed before and after the interval (blocking). When interval is ``0.0``
or ``None`` compares process times to system CPU times elapsed since last
@@ -1132,30 +1151,28 @@ Process class
>>> import psutil
>>> p = psutil.Process()
- >>>
>>> # blocking
>>> p.cpu_percent(interval=1)
2.0
>>> # non-blocking (percentage since last call)
>>> p.cpu_percent(interval=None)
2.9
- >>>
.. note::
- a percentage > 100 is legitimate as it can result from a process with
- multiple threads running on different CPU cores.
+ the returned value can be > 100.0 in case of a process running multiple
+ threads on different CPU cores.
.. note::
- the returned value is explicitly **not** split evenly between all CPUs
- cores (differently from :func:`psutil.cpu_percent()`).
- This means that a busy loop process running on a system with 2 CPU
- cores will be reported as having 100% CPU utilization instead of 50%.
- This was done in order to be consistent with UNIX's "top" utility
+ the returned value is explicitly *not* split evenly between all available
+ CPUs (differently from :func:`psutil.cpu_percent()`).
+ This means that a busy loop process running on a system with 2 logical
+ CPUs will be reported as having 100% CPU utilization instead of 50%.
+ This was done in order to be consistent with ``top`` UNIX utility
and also to make it easier to identify processes hogging CPU resources
- (independently from the number of CPU cores).
- It must be noted that in the example above taskmgr.exe on Windows will
- report 50% usage instead.
- To emulate Windows's taskmgr.exe behavior you can do:
+ independently from the number of CPUs.
+ It must be noted that ``taskmgr.exe`` on Windows does not behave like
+ this (it would report 50% usage instead).
+ To emulate Windows ``taskmgr.exe`` behavior you can do:
``p.cpu_percent() / psutil.cpu_count()``.
.. warning::
@@ -1291,8 +1308,8 @@ Process class
some platform (Linux, OSX, Windows), also provides additional metrics
(USS, PSS and swap).
The additional metrics provide a better representation of "effective"
- process memory consumption (in case of USS) as explained in detail
- `here <http://grodola.blogspot.com/2016/02/psutil-4-real-process-memory-and-environ.html>`__.
+ process memory consumption (in case of USS) as explained in detail in this
+ `blog post <http://grodola.blogspot.com/2016/02/psutil-4-real-process-memory-and-environ.html>`__.
It does so by passing through the whole process address.
As such it usually requires higher user privileges than
:meth:`memory_info` and is considerably slower.
@@ -1390,7 +1407,13 @@ Process class
pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
...]
- >>>
+ >>> p.memory_maps(grouped=False)
+ [pmmap_ext(addr='00400000-006ea000', perms='r-xp', path='/usr/bin/python2.7', rss=2293760, size=3055616, pss=1157120, shared_clean=2273280, shared_dirty=0, private_clean=20480, private_dirty=0, referenced=2293760, anonymous=0, swap=0),
+ pmmap_ext(addr='008e9000-008eb000', perms='r--p', path='/usr/bin/python2.7', rss=8192, size=8192, pss=6144, shared_clean=4096, shared_dirty=0, private_clean=0, private_dirty=4096, referenced=8192, anonymous=4096, swap=0),
+ pmmap_ext(addr='008eb000-00962000', perms='rw-p', path='/usr/bin/python2.7', rss=417792, size=487424, pss=317440, shared_clean=200704, shared_dirty=0, private_clean=16384, private_dirty=200704, referenced=417792, anonymous=200704, swap=0),
+ pmmap_ext(addr='00962000-00985000', perms='rw-p', path='[anon]', rss=139264, size=143360, pss=139264, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=139264, referenced=139264, anonymous=139264, swap=0),
+ pmmap_ext(addr='02829000-02ccf000', perms='rw-p', path='[heap]', rss=4743168, size=4874240, pss=4743168, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=4743168, referenced=4718592, anonymous=4743168, swap=0),
+ ...]
Availability: All platforms except OpenBSD and NetBSD.
@@ -1399,7 +1422,7 @@ Process class
Return the children of this process as a list of :Class:`Process` objects,
preemptively checking whether PID has been reused. If recursive is `True`
return all the parent descendants.
- Example assuming *A == this process*:
+ Pseudo code example assuming *A == this process*:
::
A ─┐
@@ -1442,8 +1465,7 @@ Process class
>>> f = open('file.ext', 'w')
>>> p = psutil.Process()
>>> p.open_files()
- [popenfile(path='/home/giampaolo/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
- popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
+ [popenfile(path='/home/giampaolo/svn/psutil/file.ext', fd=3, position=0, mode='w', flags=32769)]
.. warning::
on Windows this is not fully reliable as due to some limitations of the
@@ -1502,27 +1524,27 @@ Process class
+----------------+-----------------------------------------------------+
| **Kind value** | **Connections using** |
+================+=====================================================+
- | "inet" | IPv4 and IPv6 |
+ | ``"inet"`` | IPv4 and IPv6 |
+----------------+-----------------------------------------------------+
- | "inet4" | IPv4 |
+ | ``"inet4"`` | IPv4 |
+----------------+-----------------------------------------------------+
- | "inet6" | IPv6 |
+ | ``"inet6"`` | IPv6 |
+----------------+-----------------------------------------------------+
- | "tcp" | TCP |
+ | ``"tcp"`` | TCP |
+----------------+-----------------------------------------------------+
- | "tcp4" | TCP over IPv4 |
+ | ``"tcp4"`` | TCP over IPv4 |
+----------------+-----------------------------------------------------+
- | "tcp6" | TCP over IPv6 |
+ | ``"tcp6"`` | TCP over IPv6 |
+----------------+-----------------------------------------------------+
- | "udp" | UDP |
+ | ``"udp"`` | UDP |
+----------------+-----------------------------------------------------+
- | "udp4" | UDP over IPv4 |
+ | ``"udp4"`` | UDP over IPv4 |
+----------------+-----------------------------------------------------+
- | "udp6" | UDP over IPv6 |
+ | ``"udp6"`` | UDP over IPv6 |
+----------------+-----------------------------------------------------+
- | "unix" | UNIX socket (both UDP and TCP protocols) |
+ | ``"unix"`` | UNIX socket (both UDP and TCP protocols) |
+----------------+-----------------------------------------------------+
- | "all" | the sum of all the possible families and protocols |
+ | ``"all"`` | the sum of all the possible families and protocols |
+----------------+-----------------------------------------------------+
Example:
@@ -1602,6 +1624,10 @@ Process class
either return immediately or raise :class:`TimeoutExpired`.
To wait for multiple processes use :func:`psutil.wait_procs()`.
+ >>> import psutil
+ >>> p = psutil.Process(9891)
+ >>> p.terminate()
+ >>> p.wait()
Popen class
-----------
@@ -1756,14 +1782,14 @@ Constants
.. _const-oses:
.. data:: POSIX
- WINDOWS
- LINUX
- OSX
- FREEBSD
- NETBSD
- OPENBSD
- BSD
- SUNOS
+.. data:: WINDOWS
+.. data:: LINUX
+.. data:: OSX
+.. data:: FREEBSD
+.. data:: NETBSD
+.. data:: OPENBSD
+.. data:: BSD
+.. data:: SUNOS
``bool`` constants which define what platform you're on. E.g. if on Windows,
*WINDOWS* constant will be ``True``, all others will be ``False``.
@@ -1784,18 +1810,18 @@ Constants
.. _const-pstatus:
.. data:: STATUS_RUNNING
- STATUS_SLEEPING
- STATUS_DISK_SLEEP
- STATUS_STOPPED
- STATUS_TRACING_STOP
- STATUS_ZOMBIE
- STATUS_DEAD
- STATUS_WAKE_KILL
- STATUS_WAKING
- STATUS_IDLE (OSX, FreeBSD)
- STATUS_LOCKED (FreeBSD)
- STATUS_WAITING (FreeBSD)
- STATUS_SUSPENDED (NetBSD)
+.. data:: STATUS_SLEEPING
+.. data:: STATUS_DISK_SLEEP
+.. data:: STATUS_STOPPED
+.. data:: STATUS_TRACING_STOP
+.. data:: STATUS_ZOMBIE
+.. data:: STATUS_DEAD
+.. data:: STATUS_WAKE_KILL
+.. data:: STATUS_WAKING
+.. data:: STATUS_IDLE (OSX, FreeBSD)
+.. data:: STATUS_LOCKED (FreeBSD)
+.. data:: STATUS_WAITING (FreeBSD)
+.. data:: STATUS_SUSPENDED (NetBSD)
A set of strings representing the status of a process.
Returned by :meth:`psutil.Process.status()`.
@@ -1804,31 +1830,31 @@ Constants
.. _const-conn:
.. data:: CONN_ESTABLISHED
- CONN_SYN_SENT
- CONN_SYN_RECV
- CONN_FIN_WAIT1
- CONN_FIN_WAIT2
- CONN_TIME_WAIT
- CONN_CLOSE
- CONN_CLOSE_WAIT
- CONN_LAST_ACK
- CONN_LISTEN
- CONN_CLOSING
- CONN_NONE
- CONN_DELETE_TCB (Windows)
- CONN_IDLE (Solaris)
- CONN_BOUND (Solaris)
+.. data:: CONN_SYN_SENT
+.. data:: CONN_SYN_RECV
+.. data:: CONN_FIN_WAIT1
+.. data:: CONN_FIN_WAIT2
+.. data:: CONN_TIME_WAIT
+.. data:: CONN_CLOSE
+.. data:: CONN_CLOSE_WAIT
+.. data:: CONN_LAST_ACK
+.. data:: CONN_LISTEN
+.. data:: CONN_CLOSING
+.. data:: CONN_NONE
+.. data:: CONN_DELETE_TCB (Windows)
+.. data:: CONN_IDLE (Solaris)
+.. data:: CONN_BOUND (Solaris)
A set of strings representing the status of a TCP connection.
Returned by :meth:`psutil.Process.connections()` (`status` field).
.. _const-prio:
.. data:: ABOVE_NORMAL_PRIORITY_CLASS
- BELOW_NORMAL_PRIORITY_CLASS
- HIGH_PRIORITY_CLASS
- IDLE_PRIORITY_CLASS
- NORMAL_PRIORITY_CLASS
- REALTIME_PRIORITY_CLASS
+.. data:: BELOW_NORMAL_PRIORITY_CLASS
+.. data:: HIGH_PRIORITY_CLASS
+.. data:: IDLE_PRIORITY_CLASS
+.. data:: NORMAL_PRIORITY_CLASS
+.. data:: REALTIME_PRIORITY_CLASS
A set of integers representing the priority of a process on Windows (see
`MSDN documentation <http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx>`__).
@@ -1844,9 +1870,9 @@ Constants
.. _const-ioprio:
.. data:: IOPRIO_CLASS_NONE
- IOPRIO_CLASS_RT
- IOPRIO_CLASS_BE
- IOPRIO_CLASS_IDLE
+.. data:: IOPRIO_CLASS_RT
+.. data:: IOPRIO_CLASS_BE
+.. data:: IOPRIO_CLASS_IDLE
A set of integers representing the I/O priority of a process on Linux. They
can be used in conjunction with :meth:`psutil.Process.ionice()` to get or set
@@ -1872,22 +1898,22 @@ Constants
.. _const-rlimit:
.. data:: RLIM_INFINITY
- RLIMIT_AS
- RLIMIT_CORE
- RLIMIT_CPU
- RLIMIT_DATA
- RLIMIT_FSIZE
- RLIMIT_LOCKS
- RLIMIT_MEMLOCK
- RLIMIT_MSGQUEUE
- RLIMIT_NICE
- RLIMIT_NOFILE
- RLIMIT_NPROC
- RLIMIT_RSS
- RLIMIT_RTPRIO
- RLIMIT_RTTIME
- RLIMIT_SIGPENDING
- RLIMIT_STACK
+.. data:: RLIMIT_AS
+.. data:: RLIMIT_CORE
+.. data:: RLIMIT_CPU
+.. data:: RLIMIT_DATA
+.. data:: RLIMIT_FSIZE
+.. data:: RLIMIT_LOCKS
+.. data:: RLIMIT_MEMLOCK
+.. data:: RLIMIT_MSGQUEUE
+.. data:: RLIMIT_NICE
+.. data:: RLIMIT_NOFILE
+.. data:: RLIMIT_NPROC
+.. data:: RLIMIT_RSS
+.. data:: RLIMIT_RTPRIO
+.. data:: RLIMIT_RTTIME
+.. data:: RLIMIT_SIGPENDING
+.. data:: RLIMIT_STACK
Constants used for getting and setting process resource limits to be used in
conjunction with :meth:`psutil.Process.rlimit()`. See
@@ -1905,8 +1931,8 @@ Constants
.. _const-duplex:
.. data:: NIC_DUPLEX_FULL
- NIC_DUPLEX_HALF
- NIC_DUPLEX_UNKNOWN
+.. data:: NIC_DUPLEX_HALF
+.. data:: NIC_DUPLEX_UNKNOWN
Constants which identifies whether a NIC (network interface card) has full or
half mode speed. NIC_DUPLEX_FULL means the NIC is able to send and receive
@@ -1925,6 +1951,36 @@ Constants
>>> if psutil.version_info >= (4, 5):
... pass
+Q&A
+===
+
+* Q: What Windows versions are supported?
+* A: From Windows **Vista** onwards, both 32 and 64 bit versions.
+ Latest binary (wheel / exe) release which supports Windows **2000**, **XP**
+ and **2003 server** is
+ `psutil 3.4.2 <https://pypi.python.org/pypi?name=psutil&version=3.4.2&:action=files>`__.
+ On such old systems psutil is no longer tested or maintained, but it can
+ still be compiled from sources (you'll need `Visual Studio <(https://github.com/giampaolo/psutil/blob/master/INSTALL.rst#windows>`__)
+ and it should "work" (more or less).
+
+----
+
+* Q: What SunOS versions are supported?
+* A: From Solaris 10 onwards.
+
+----
+
+* Q: Why do I get :class:`AccessDenied` for certain processes?
+* A: This may happen when you query processess owned by another user,
+ especially on `OSX <https://github.com/giampaolo/psutil/issues/883>`__ and
+ Windows.
+ Unfortunately there's not much you can do about this except running the
+ Python process with higher privileges.
+ On Unix you may run the the Python process as root or use the SUID bit
+ (this is the trick used by tools such as ``ps`` and ``netstat``).
+ On Windows you may run the Python process as NT AUTHORITY\\SYSTEM or install
+ the Python script as a Windows service (this is the trick used by tools
+ such as ProcessHacker).
Development guide
=================
@@ -1933,23 +1989,11 @@ If you plan on hacking on psutil (e.g. want to add a new feature or fix a bug)
take a look at the
`development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_.
-
-Q&A
-===
-
-* Q: What Windows versions are supported?
-* A: From Windows **Vista** onwards. Latest binary (wheel / exe) release
- supporting Windows **2000**, **XP** and **2003 server** which can installed
- via pip without a compiler being installed is
- `psutil 3.4.2 <https://pypi.python.org/pypi?name=psutil&version=3.4.2&:action=files>`__.
- More recent psutil versions may still be compiled from sources and work
- (more or less) but they are no longer being tested or maintained.
-
-
Timeline
========
-- 2016-11-06: `5.5.0 <https://pypi.python.org/pypi?name=psutil&version=5.5.0&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#550>`__
+- 2016-12-21: `5.0.1 <https://pypi.python.org/pypi?name=psutil&version=5.0.1&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#550>`__
+- 2016-11-06: `5.0.0 <https://pypi.python.org/pypi?name=psutil&version=5.0.0&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#550>`__
- 2016-10-26: `4.4.2 <https://pypi.python.org/pypi?name=psutil&version=4.4.2&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#442>`__
- 2016-10-25: `4.4.1 <https://pypi.python.org/pypi?name=psutil&version=4.4.1&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#441>`__
- 2016-10-23: `4.4.0 <https://pypi.python.org/pypi?name=psutil&version=4.4.0&:action=files>`__ - `what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#440>`__
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 6994c476..94ace42a 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -143,8 +143,8 @@ elif SUNOS:
from ._pssunos import CONN_BOUND # NOQA
from ._pssunos import CONN_IDLE # NOQA
- # This is public API and it will be retrieved from _pssunos.py
- # via sys.modules.
+ # This is public writable API which is read from _pslinux.py and
+ # _pssunos.py via sys.modules.
PROCFS_PATH = "/proc"
else: # pragma: no cover
@@ -189,7 +189,7 @@ __all__ = [
]
__all__.extend(_psplatform.__extra__all__)
__author__ = "Giampaolo Rodola'"
-__version__ = "5.0.1"
+__version__ = "5.0.2"
version_info = tuple([int(num) for num in __version__.split('.')])
AF_LINK = _psplatform.AF_LINK
_TOTAL_PHYMEM = None
@@ -222,6 +222,7 @@ if (int(__version__.replace('.', '')) !=
# --- exceptions
# =====================================================================
+
class Error(Exception):
"""Base exception class. All other psutil exceptions inherit
from this one.
@@ -453,6 +454,11 @@ class Process(object):
self._hash = hash(self._ident)
return self._hash
+ @property
+ def pid(self):
+ """The process PID."""
+ return self._pid
+
# --- utility methods
@contextlib.contextmanager
@@ -601,11 +607,6 @@ class Process(object):
# --- actual API
- @property
- def pid(self):
- """The process PID."""
- return self._pid
-
@memoize_when_activated
def ppid(self):
"""The process parent PID.
@@ -981,6 +982,14 @@ class Process(object):
In this case is recommended for accuracy that this function
be called with at least 0.1 seconds between calls.
+ A value > 100.0 can be returned in case of processes running
+ multiple threads on different CPU cores.
+
+ The returned value is explicitly *not* split evenly between
+ all available logical CPUs. This means that a busy loop process
+ running on a system with 2 logical CPUs will be reported as
+ having 100% CPU utilization instead of 50%.
+
Examples:
>>> import psutil
@@ -1186,6 +1195,8 @@ class Process(object):
"""
return self._proc.connections(kind)
+ # --- signals
+
if POSIX:
def _send_signal(self, sig):
assert not self.pid < 0, self.pid
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index a3301504..acf6c7c3 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -17,6 +17,7 @@ from . import _psutil_bsd as cext
from . import _psutil_posix as cext_posix
from ._common import conn_tmap
from ._common import FREEBSD
+from ._common import memoize
from ._common import memoize_when_activated
from ._common import NETBSD
from ._common import OPENBSD
@@ -420,7 +421,26 @@ def users():
# =====================================================================
-pids = cext.pids
+@memoize
+def _pid_0_exists():
+ try:
+ Process(0).name()
+ except NoSuchProcess:
+ return False
+ except AccessDenied:
+ return True
+ else:
+ return True
+
+
+def pids():
+ ret = cext.pids()
+ if OPENBSD and (0 not in ret) and _pid_0_exists():
+ # On OpenBSD the kernel does not return PID 0 (neither does
+ # ps) but it's actually querable (Process(0) will succeed).
+ ret.insert(0, 0)
+ return ret
+
if OPENBSD or NETBSD:
def pid_exists(pid):
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index e073b06e..9154896a 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -1105,8 +1105,32 @@ def pids():
def pid_exists(pid):
- """Check For the existence of a unix pid."""
- return _psposix.pid_exists(pid)
+ """Check for the existence of a unix PID."""
+ if not _psposix.pid_exists(pid):
+ return False
+ else:
+ # Linux's apparently does not distinguish between PIDs and TIDs
+ # (thread IDs).
+ # listdir("/proc") won't show any TID (only PIDs) but
+ # os.stat("/proc/{tid}") will succeed if {tid} exists.
+ # os.kill() can also be passed a TID. This is quite confusing.
+ # In here we want to enforce this distinction and support PIDs
+ # only, see:
+ # https://github.com/giampaolo/psutil/issues/687
+ try:
+ # Note: already checked that this is faster than using a
+ # regular expr. Also (a lot) faster than doing
+ # 'return pid in pids()'
+ with open_binary("%s/%s/status" % (get_procfs_path(), pid)) as f:
+ for line in f:
+ if line.startswith(b"Tgid:"):
+ tgid = int(line.split()[1])
+ # If tgid and pid are the same then we're
+ # dealing with a process PID.
+ return tgid == pid
+ raise ValueError("'Tgid' line not found")
+ except (EnvironmentError, ValueError):
+ return pid in pids()
def wrap_exceptions(fun):
diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c
index 33448ccf..afe3834e 100644
--- a/psutil/_psutil_bsd.c
+++ b/psutil/_psutil_bsd.c
@@ -15,8 +15,8 @@
* - psutil.Process.memory_maps()
*/
-#if defined(__NetBSD__)
-#define _KMEMUSER
+#if defined(PSUTIL_NETBSD)
+ #define _KMEMUSER
#endif
#include <Python.h>
@@ -61,17 +61,10 @@
#include "_psutil_common.h"
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
#include "arch/bsd/freebsd.h"
#include "arch/bsd/freebsd_socks.h"
-#elif __OpenBSD__
- #include "arch/bsd/openbsd.h"
-#elif __NetBSD__
- #include "arch/bsd/netbsd.h"
- #include "arch/bsd/netbsd_socks.h"
-#endif
-#ifdef __FreeBSD__
#include <net/if_media.h>
#include <devstat.h> // get io counters
#include <libutil.h> // process open files, shared libs (kinfo_getvmmap)
@@ -80,37 +73,39 @@
#else
#include <utmpx.h>
#endif
-#endif
+#elif PSUTIL_OPENBSD
+ #include "arch/bsd/openbsd.h"
-#ifdef __OpenBSD__
#include <utmp.h>
#include <sys/vnode.h> // for VREG
#define _KERNEL // for DTYPE_VNODE
#include <sys/file.h>
#undef _KERNEL
#include <sys/sched.h> // for CPUSTATES & CP_*
-#endif
+#elif PSUTIL_NETBSD
+ #include "arch/bsd/netbsd.h"
+ #include "arch/bsd/netbsd_socks.h"
-#if defined(__NetBSD__)
#include <utmpx.h>
#include <sys/vnode.h> // for VREG
#include <sys/sched.h> // for CPUSTATES & CP_*
#ifndef DTYPE_VNODE
- #define DTYPE_VNODE 1
+ #define DTYPE_VNODE 1
#endif
#endif
+
// convert a timeval struct to a double
#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
// convert a bintime struct to milliseconds
#define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * \
(uint32_t) (bt.frac >> 32) ) >> 32 ) / 1000000)
#endif
-#if defined(__OpenBSD__) || defined (__NetBSD__)
+#if defined(PSUTIL_OPENBSD) || defined (PSUTIL_NETBSD)
#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0)
#endif
@@ -146,9 +141,9 @@ psutil_pids(PyObject *self, PyObject *args) {
if (num_processes > 0) {
orig_address = proclist; // save so we can free it after we're done
for (idx = 0; idx < num_processes; idx++) {
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
py_pid = Py_BuildValue("i", proclist->ki_pid);
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
py_pid = Py_BuildValue("i", proclist->p_pid);
#endif
if (!py_pid)
@@ -215,9 +210,9 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
return NULL;
// Process
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
sprintf(str, "%s", kp.ki_comm);
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
sprintf(str, "%s", kp.p_comm);
#endif
#if PY_MAJOR_VERSION >= 3
@@ -233,7 +228,7 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
}
// Calculate memory.
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
rss = (long)kp.ki_rssize * pagesize;
vms = (long)kp.ki_size;
memtext = (long)kp.ki_tsize * pagesize;
@@ -241,12 +236,12 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
memstack = (long)kp.ki_ssize * pagesize;
#else
rss = (long)kp.p_vm_rssize * pagesize;
- #ifdef __OpenBSD__
+ #ifdef PSUTIL_OPENBSD
// VMS, this is how ps determines it on OpenBSD:
// http://anoncvs.spacehopper.org/openbsd-src/tree/bin/ps/print.c#n461
// vms
vms = (long)(kp.p_vm_dsize + kp.p_vm_ssize + kp.p_vm_tsize) * pagesize;
- #elif __NetBSD__
+ #elif PSUTIL_NETBSD
// VMS, this is how top determines it on NetBSD:
// ftp://ftp.iij.ad.jp/pub/NetBSD/NetBSD-release-6/src/external/bsd/
// top/dist/machine/m_netbsd.c
@@ -260,7 +255,7 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
// Return a single big tuple with all process info.
py_retlist = Py_BuildValue(
"(lillllllidllllddddlllllO)",
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
//
(long)kp.ki_ppid, // (long) ppid
(int)kp.ki_stat, // (int) status
@@ -292,7 +287,7 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
memtext, // (long) mem text
memdata, // (long) mem data
memstack, // (long) mem stack
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
//
(long)kp.p_ppid, // (long) ppid
(int)kp.p_stat, // (int) status
@@ -352,9 +347,9 @@ psutil_proc_name(PyObject *self, PyObject *args) {
if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
sprintf(str, "%s", kp.ki_comm);
-#elif defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
sprintf(str, "%s", kp.p_comm);
#endif
@@ -412,7 +407,7 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) {
*/
static PyObject *
psutil_cpu_times(PyObject *self, PyObject *args) {
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
u_int64_t cpu_time[CPUSTATES];
#else
long cpu_time[CPUSTATES];
@@ -420,9 +415,9 @@ psutil_cpu_times(PyObject *self, PyObject *args) {
size_t size = sizeof(cpu_time);
int ret;
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
ret = sysctlbyname("kern.cp_time", &cpu_time, &size, NULL, 0);
-#elif __OpenBSD__
+#elif PSUTIL_OPENBSD
int mib[] = {CTL_KERN, KERN_CPTIME};
ret = sysctl(mib, 2, &cpu_time, &size, NULL, 0);
#endif
@@ -447,7 +442,7 @@ psutil_cpu_times(PyObject *self, PyObject *args) {
* utility has the same problem see:
* https://github.com/giampaolo/psutil/issues/595
*/
-#if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || __OpenBSD__ || defined(__NetBSD__)
+#if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
static PyObject *
psutil_proc_open_files(PyObject *self, PyObject *args) {
long pid;
@@ -474,17 +469,17 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
for (i = 0; i < cnt; i++) {
kif = &freep[i];
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
if ((kif->kf_type == KF_TYPE_VNODE) &&
(kif->kf_vnode_type == KF_VTYPE_VREG))
{
py_tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd);
-#elif defined(__OpenBSD__)
+#elif PSUTIL_OPENBSD
if ((kif->f_type == DTYPE_VNODE) &&
(kif->v_type == VREG))
{
py_tuple = Py_BuildValue("(si)", "", kif->fd_fd);
-#elif defined(__NetBSD__)
+#elif PSUTIL_NETBSD
if ((kif->ki_ftype == DTYPE_VNODE) &&
(kif->ki_vtype == VREG))
{
@@ -521,7 +516,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
long len;
uint64_t flags;
char opts[200];
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
struct statvfs *fs = NULL;
#else
struct statfs *fs = NULL;
@@ -534,7 +529,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
// get the number of mount points
Py_BEGIN_ALLOW_THREADS
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
num = getvfsstat(NULL, 0, MNT_NOWAIT);
#else
num = getfsstat(NULL, 0, MNT_NOWAIT);
@@ -553,7 +548,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
}
Py_BEGIN_ALLOW_THREADS
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
num = getvfsstat(fs, len, MNT_NOWAIT);
#else
num = getfsstat(fs, len, MNT_NOWAIT);
@@ -567,7 +562,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
for (i = 0; i < num; i++) {
py_tuple = NULL;
opts[0] = 0;
-#if defined(__NetBSD__)
+#ifdef PSUTIL_NETBSD
flags = fs[i].f_flag;
#else
flags = fs[i].f_flags;
@@ -590,7 +585,7 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
strlcat(opts, ",noatime", sizeof(opts));
if (flags & MNT_SOFTDEP)
strlcat(opts, ",softdep", sizeof(opts));
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
if (flags & MNT_UNION)
strlcat(opts, ",union", sizeof(opts));
if (flags & MNT_SUIDDIR)
@@ -611,24 +606,24 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
strlcat(opts, ",noclusterw", sizeof(opts));
if (flags & MNT_NFS4ACLS)
strlcat(opts, ",nfs4acls", sizeof(opts));
-#elif __NetBSD__
+#elif PSUTIL_NETBSD
if (flags & MNT_NODEV)
strlcat(opts, ",nodev", sizeof(opts));
if (flags & MNT_UNION)
strlcat(opts, ",union", sizeof(opts));
if (flags & MNT_NOCOREDUMP)
strlcat(opts, ",nocoredump", sizeof(opts));
-#if defined(MNT_RELATIME)
+#ifdef MNT_RELATIME
if (flags & MNT_RELATIME)
strlcat(opts, ",relatime", sizeof(opts));
#endif
if (flags & MNT_IGNORE)
strlcat(opts, ",ignore", sizeof(opts));
-#if defined(MNT_DISCARD)
+#ifdef MNT_DISCARD
if (flags & MNT_DISCARD)
strlcat(opts, ",discard", sizeof(opts));
#endif
-#if defined(MNT_EXTATTR)
+#ifdef MNT_EXTATTR
if (flags & MNT_EXTATTR)
strlcat(opts, ",extattr", sizeof(opts));
#endif
@@ -769,7 +764,7 @@ psutil_users(PyObject *self, PyObject *args) {
if (py_retlist == NULL)
return NULL;
-#if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || __OpenBSD__
+#if (defined(__FreeBSD_version) && (__FreeBSD_version < 900000)) || PSUTIL_OPENBSD
struct utmp ut;
FILE *fp;
@@ -849,7 +844,7 @@ PsutilMethods[] = {
"Return multiple info about a process"},
{"proc_name", psutil_proc_name, METH_VARARGS,
"Return process name"},
-#if !defined(__NetBSD__)
+#if !defined(PSUTIL_NETBSD)
{"proc_connections", psutil_proc_connections, METH_VARARGS,
"Return connections opened by process"},
#endif
@@ -857,25 +852,25 @@ PsutilMethods[] = {
"Return process cmdline as a list of cmdline arguments"},
{"proc_threads", psutil_proc_threads, METH_VARARGS,
"Return process threads"},
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD)
{"proc_cwd", psutil_proc_cwd, METH_VARARGS,
"Return process current working directory."},
#endif
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ || defined(__NetBSD__)
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
{"proc_num_fds", psutil_proc_num_fds, METH_VARARGS,
"Return the number of file descriptors opened by this process"},
#endif
-#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || __OpenBSD__ || defined(__NetBSD__)
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
{"proc_open_files", psutil_proc_open_files, METH_VARARGS,
"Return files opened by process as a list of (path, fd) tuples"},
#endif
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
{"proc_exe", psutil_proc_exe, METH_VARARGS,
"Return process pathname executable"},
{"proc_num_threads", psutil_proc_num_threads, METH_VARARGS,
"Return number of threads used by process"},
-#if defined(__FreeBSD__)
+#if defined(PSUTIL_FREEBSD)
{"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS,
"Return a list of tuples for every process's memory map"},
{"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS,
@@ -914,7 +909,7 @@ PsutilMethods[] = {
"Return currently connected users as a list of tuples"},
{"cpu_stats", psutil_cpu_stats, METH_VARARGS,
"Return CPU statistics"},
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_NETBSD)
{"net_connections", psutil_net_connections, METH_VARARGS,
"Return system-wide open connections."},
#endif
@@ -976,7 +971,7 @@ void init_psutil_bsd(void)
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
// process status constants
-#ifdef __FreeBSD__
+#ifdef PSUTIL_FREEBSD
PyModule_AddIntConstant(module, "SIDL", SIDL);
PyModule_AddIntConstant(module, "SRUN", SRUN);
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
@@ -984,7 +979,7 @@ void init_psutil_bsd(void)
PyModule_AddIntConstant(module, "SZOMB", SZOMB);
PyModule_AddIntConstant(module, "SWAIT", SWAIT);
PyModule_AddIntConstant(module, "SLOCK", SLOCK);
-#elif __OpenBSD__
+#elif PSUTIL_OPENBSD
PyModule_AddIntConstant(module, "SIDL", SIDL);
PyModule_AddIntConstant(module, "SRUN", SRUN);
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
@@ -992,7 +987,7 @@ void init_psutil_bsd(void)
PyModule_AddIntConstant(module, "SZOMB", SZOMB); // unused
PyModule_AddIntConstant(module, "SDEAD", SDEAD);
PyModule_AddIntConstant(module, "SONPROC", SONPROC);
-#elif defined(__NetBSD__)
+#elif defined(PSUTIL_NETBSD)
PyModule_AddIntConstant(module, "SIDL", LSIDL);
PyModule_AddIntConstant(module, "SRUN", LSRUN);
PyModule_AddIntConstant(module, "SSLEEP", LSSLEEP);
diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c
index 2d9630ac..7aa4b553 100644
--- a/psutil/_psutil_posix.c
+++ b/psutil/_psutil_posix.c
@@ -16,25 +16,21 @@
#include <net/if.h>
#ifdef PSUTIL_SUNOS10
-#include "arch/solaris/v10/ifaddrs.h"
+ #include "arch/solaris/v10/ifaddrs.h"
#else
-#include <ifaddrs.h>
+ #include <ifaddrs.h>
#endif
-#ifdef __linux
-#include <netdb.h>
-#include <linux/if_packet.h>
-#endif // end linux
-
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
-#include <netdb.h>
-#include <netinet/in.h>
-#include <net/if_dl.h>
-#endif
-
-#if defined(__sun)
-#include <netdb.h>
-#include <sys/sockio.h>
+#if defined(PSUTIL_LINUX)
+ #include <netdb.h>
+ #include <linux/if_packet.h>
+#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
+ #include <netdb.h>
+ #include <netinet/in.h>
+ #include <net/if_dl.h>
+#elif defined(PSUTIL_SUNOS)
+ #include <netdb.h>
+ #include <sys/sockio.h>
#endif
@@ -50,7 +46,7 @@ psutil_posix_getpriority(PyObject *self, PyObject *args) {
if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
-#if defined(__APPLE__)
+#ifdef PSUTIL_OSX
priority = getpriority(PRIO_PROCESS, (id_t)pid);
#else
priority = getpriority(PRIO_PROCESS, pid);
@@ -73,7 +69,7 @@ psutil_posix_setpriority(PyObject *self, PyObject *args) {
if (! PyArg_ParseTuple(args, "li", &pid, &priority))
return NULL;
-#if defined(__APPLE__)
+#ifdef PSUTIL_OSX
retval = setpriority(PRIO_PROCESS, (id_t)pid, priority);
#else
retval = setpriority(PRIO_PROCESS, pid, priority);
@@ -122,14 +118,13 @@ psutil_convert_ipaddr(struct sockaddr *addr, int family) {
return Py_BuildValue("s", buf);
}
}
-#ifdef __linux
+#ifdef PSUTIL_LINUX
else if (family == AF_PACKET) {
struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
len = lladdr->sll_halen;
data = (const char *)lladdr->sll_addr;
}
-#endif
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
+#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
else if (addr->sa_family == AF_LINK) {
// Note: prior to Python 3.4 socket module does not expose
// AF_LINK so we'll do.
@@ -264,8 +259,11 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) {
char *nic_name;
int sock = 0;
int ret;
- int mtu;
+#ifdef PSUTIL_SUNOS10
+ struct lifreq lifr;
+#else
struct ifreq ifr;
+#endif
if (! PyArg_ParseTuple(args, "s", &nic_name))
return NULL;
@@ -274,14 +272,22 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) {
if (sock == -1)
goto error;
+#ifdef PSUTIL_SUNOS10
+ strncpy(lifr.lifr_name, nic_name, sizeof(lifr.lifr_name));
+ ret = ioctl(sock, SIOCGIFMTU, &lifr);
+#else
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
ret = ioctl(sock, SIOCGIFMTU, &ifr);
+#endif
if (ret == -1)
goto error;
close(sock);
- mtu = ifr.ifr_mtu;
- return Py_BuildValue("i", mtu);
+#ifdef PSUTIL_SUNOS10
+ return Py_BuildValue("i", lifr.lifr_mtu);
+#else
+ return Py_BuildValue("i", ifr.ifr_mtu);
+#endif
error:
if (sock != 0)
@@ -332,7 +338,7 @@ error:
/*
* net_if_stats() OSX/BSD implementation.
*/
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
+#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
#include <sys/sockio.h>
#include <net/if_media.h>
@@ -369,7 +375,7 @@ int psutil_get_nic_speed(int ifm_active) {
case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber
case(IFM_1000_LX): // 1000baseLX - single-mode fiber
case(IFM_1000_CX): // 1000baseCX - 150ohm STP
-#if defined(IFM_1000_TX) && !defined(__OpenBSD__)
+#if defined(IFM_1000_TX) && !defined(PSUTIL_OPENBSD)
// FreeBSD 4 and others (but NOT OpenBSD) -> #define IFM_1000_T in net/if_media.h
case(IFM_1000_TX):
#endif
@@ -542,7 +548,7 @@ PsutilMethods[] = {
"Retrieve NIC MTU"},
{"net_if_flags", psutil_net_if_flags, METH_VARARGS,
"Retrieve NIC flags"},
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__)
+#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
{"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS,
"Return NIC stats."},
#endif
@@ -567,6 +573,7 @@ psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) {
return 0;
}
+
static int
psutil_posix_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
@@ -601,7 +608,7 @@ void init_psutil_posix(void)
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
#endif
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) || defined(__sun) || defined(__NetBSD__)
+#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS)
PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
#endif
diff --git a/psutil/arch/bsd/netbsd.c b/psutil/arch/bsd/netbsd.c
index 2cf2ef22..d5c3e3b9 100644
--- a/psutil/arch/bsd/netbsd.c
+++ b/psutil/arch/bsd/netbsd.c
@@ -7,8 +7,8 @@
* Platform-specific module methods for NetBSD.
*/
-#if defined(__NetBSD__)
-#define _KMEMUSER
+#if defined(PSUTIL_NETBSD)
+ #define _KMEMUSER
#endif
#include <Python.h>
diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py
index 883d9285..b119a788 100644
--- a/psutil/tests/__init__.py
+++ b/psutil/tests/__init__.py
@@ -506,6 +506,7 @@ def chdir(dirname):
def create_exe(outpath, c_code=None):
+ """Creates an executable file in the given location."""
assert not os.path.exists(outpath), outpath
if which("gcc"):
if c_code is None:
@@ -526,6 +527,9 @@ def create_exe(outpath, c_code=None):
safe_rmpath(f.name)
else:
# fallback - use python's executable
+ if c_code is not None:
+ raise ValueError(
+ "can't specify c_code arg as gcc is not installed")
shutil.copyfile(sys.executable, outpath)
if POSIX:
st = os.stat(outpath)
diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py
index 871cb74e..028a41d9 100755
--- a/psutil/tests/test_linux.py
+++ b/psutil/tests/test_linux.py
@@ -40,6 +40,7 @@ from psutil.tests import safe_rmpath
from psutil.tests import sh
from psutil.tests import skip_on_not_implemented
from psutil.tests import TESTFN
+from psutil.tests import ThreadTask
from psutil.tests import TRAVIS
from psutil.tests import unittest
from psutil.tests import which
@@ -1004,6 +1005,24 @@ class TestMisc(unittest.TestCase):
importlib.reload(psutil._pslinux)
importlib.reload(psutil)
+ def test_issue_687(self):
+ # In case of thread ID:
+ # - pid_exists() is supposed to return False
+ # - Process(tid) is supposed to work
+ # - pids() should not return the TID
+ # See: https://github.com/giampaolo/psutil/issues/687
+ t = ThreadTask()
+ t.start()
+ try:
+ p = psutil.Process()
+ tid = p.threads()[1].id
+ assert not psutil.pid_exists(tid), tid
+ pt = psutil.Process(tid)
+ pt.as_dict()
+ self.assertNotIn(tid, psutil.pids())
+ finally:
+ t.stop()
+
# =====================================================================
# test process
diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py
index b0176083..d25f4474 100755
--- a/psutil/tests/test_process.py
+++ b/psutil/tests/test_process.py
@@ -302,7 +302,7 @@ class TestProcess(unittest.TestCase):
@unittest.skipIf(TRAVIS, 'not reliable on TRAVIS')
def test_terminal(self):
terminal = psutil.Process().terminal()
- if sys.stdin.isatty():
+ if sys.stdin.isatty() or sys.stdout.isatty():
tty = os.path.realpath(sh('tty'))
self.assertEqual(terminal, tty)
else:
@@ -501,10 +501,8 @@ class TestProcess(unittest.TestCase):
try:
step2 = p.num_threads()
self.assertEqual(step2, step1 + 1)
- thread.stop()
finally:
- if thread._running:
- thread.stop()
+ thread.stop()
@unittest.skipUnless(WINDOWS, 'WINDOWS only')
def test_num_handles(self):
@@ -524,7 +522,6 @@ class TestProcess(unittest.TestCase):
thread = ThreadTask()
thread.start()
-
try:
step2 = p.threads()
self.assertEqual(len(step2), len(step1) + 1)
@@ -536,11 +533,8 @@ class TestProcess(unittest.TestCase):
self.assertEqual(athread.id, athread[0])
self.assertEqual(athread.user_time, athread[1])
self.assertEqual(athread.system_time, athread[2])
- # test num threads
- thread.stop()
finally:
- if thread._running:
- thread.stop()
+ thread.stop()
@retry_before_failing()
# see: https://travis-ci.org/giampaolo/psutil/jobs/111842553
@@ -845,6 +839,7 @@ class TestProcess(unittest.TestCase):
def test_cpu_affinity(self):
p = psutil.Process()
initial = p.cpu_affinity()
+ self.addCleanup(p.cpu_affinity, initial)
if hasattr(os, "sched_getaffinity"):
self.assertEqual(initial, list(os.sched_getaffinity(p.pid)))
self.assertEqual(len(initial), len(set(initial)))
diff --git a/setup.py b/setup.py
index 938cfef9..426b7eb7 100755
--- a/setup.py
+++ b/setup.py
@@ -85,18 +85,6 @@ def silenced_output(stream_name):
VERSION = get_version()
macros.append(('PSUTIL_VERSION', int(VERSION.replace('.', ''))))
-
-# POSIX
-if POSIX:
- posix_extension = Extension(
- 'psutil._psutil_posix',
- sources=['psutil/_psutil_posix.c'])
- if SUNOS:
- posix_extension.libraries.append('socket')
- if platform.release() == '5.10':
- posix_extension.sources.append('psutil/arch/solaris/v10/ifaddrs.c')
- posix_extension.define_macros.append(('PSUTIL_SUNOS10', 1))
-
# Windows
if WINDOWS:
def get_winver():
@@ -139,7 +127,6 @@ if WINDOWS:
# extra_compile_args=["/Z7"],
# extra_link_args=["/DEBUG"]
)
- extensions = [ext]
# OS X
elif OSX:
@@ -155,7 +142,6 @@ elif OSX:
extra_link_args=[
'-framework', 'CoreFoundation', '-framework', 'IOKit'
])
- extensions = [ext, posix_extension]
# FreeBSD
elif FREEBSD:
@@ -170,7 +156,6 @@ elif FREEBSD:
],
define_macros=macros,
libraries=["devstat"])
- extensions = [ext, posix_extension]
# OpenBSD
elif OPENBSD:
@@ -184,7 +169,6 @@ elif OPENBSD:
],
define_macros=macros,
libraries=["kvm"])
- extensions = [ext, posix_extension]
# NetBSD
elif NETBSD:
@@ -199,7 +183,6 @@ elif NETBSD:
],
define_macros=macros,
libraries=["kvm"])
- extensions = [ext, posix_extension]
# Linux
elif LINUX:
@@ -229,15 +212,15 @@ elif LINUX:
else:
return None
- macros.append(("PSUTIL_LINUX", 1))
ETHTOOL_MACRO = get_ethtool_macro()
+
+ macros.append(("PSUTIL_LINUX", 1))
if ETHTOOL_MACRO is not None:
macros.append(ETHTOOL_MACRO)
ext = Extension(
'psutil._psutil_linux',
sources=['psutil/_psutil_linux.c'],
define_macros=macros)
- extensions = [ext, posix_extension]
# Solaris
elif SUNOS:
@@ -247,17 +230,32 @@ elif SUNOS:
sources=['psutil/_psutil_sunos.c'],
define_macros=macros,
libraries=['kstat', 'nsl', 'socket'])
- extensions = [ext, posix_extension]
else:
sys.exit('platform %s is not supported' % sys.platform)
+# POSIX
+if POSIX:
+ posix_extension = Extension(
+ 'psutil._psutil_posix',
+ define_macros=macros,
+ sources=['psutil/_psutil_posix.c'])
+ if SUNOS:
+ posix_extension.libraries.append('socket')
+ if platform.release() == '5.10':
+ posix_extension.sources.append('psutil/arch/solaris/v10/ifaddrs.c')
+ posix_extension.define_macros.append(('PSUTIL_SUNOS10', 1))
+
+ extensions = [ext, posix_extension]
+else:
+ extensions = [ext]
+
def main():
- setup_args = dict(
+ setup(
name='psutil',
version=VERSION,
- description=__doc__.replace('\n', '').strip(),
+ description=__doc__ .replace('\n', '').strip() if __doc__ else '',
long_description=get_description(),
keywords=[
'ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice', 'tty',
@@ -271,6 +269,7 @@ def main():
platforms='Platform Independent',
license='BSD',
packages=['psutil', 'psutil.tests'],
+ ext_modules=extensions,
# see: python setup.py register --list-classifiers
classifiers=[
'Development Status :: 5 - Production/Stable',
@@ -317,9 +316,6 @@ def main():
'Topic :: Utilities',
],
)
- if extensions is not None:
- setup_args["ext_modules"] = extensions
- setup(**setup_args)
if __name__ == '__main__':