summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/README3
-rw-r--r--.ci/appveyor/README2
-rw-r--r--.ci/appveyor/install.ps185
-rw-r--r--.ci/appveyor/run_with_compiler.cmd47
-rw-r--r--.ci/travis/README2
-rwxr-xr-x.ci/travis/install.sh51
-rwxr-xr-x.ci/travis/run.sh18
-rw-r--r--.coveragerc21
-rwxr-xr-x.git-pre-commit47
-rw-r--r--.gitignore18
-rw-r--r--.travis.yml45
-rw-r--r--CREDITS59
-rw-r--r--DEVGUIDE.rst147
-rw-r--r--HISTORY.rst153
-rw-r--r--INSTALL.rst70
-rw-r--r--MANIFEST.in9
-rw-r--r--Makefile70
-rw-r--r--README.rst79
-rw-r--r--TODO52
-rw-r--r--appveyor.yml77
-rw-r--r--docs/index.rst234
-rwxr-xr-xexamples/ifconfig.py80
-rwxr-xr-xexamples/iotop.py15
-rwxr-xr-xexamples/nettop.py10
-rwxr-xr-xexamples/process_detail.py21
-rwxr-xr-x[-rw-r--r--]examples/ps.py0
-rwxr-xr-x[-rw-r--r--]examples/pstree.py2
-rwxr-xr-xexamples/top.py11
-rw-r--r--make.bat162
-rw-r--r--psutil/__init__.py686
-rw-r--r--psutil/_common.py114
-rw-r--r--psutil/_compat.py30
-rw-r--r--psutil/_psbsd.py89
-rw-r--r--psutil/_pslinux.py335
-rw-r--r--psutil/_psosx.py43
-rw-r--r--psutil/_psposix.py10
-rw-r--r--psutil/_pssunos.py56
-rw-r--r--psutil/_psutil_bsd.c809
-rw-r--r--psutil/_psutil_linux.c276
-rw-r--r--psutil/_psutil_linux.h1
-rw-r--r--psutil/_psutil_osx.c559
-rw-r--r--psutil/_psutil_posix.c449
-rw-r--r--psutil/_psutil_posix.h5
-rw-r--r--psutil/_psutil_sunos.c307
-rw-r--r--psutil/_psutil_sunos.h1
-rw-r--r--psutil/_psutil_windows.c1699
-rw-r--r--psutil/_psutil_windows.h10
-rw-r--r--psutil/_pswindows.py160
-rw-r--r--psutil/arch/bsd/process_info.c54
-rw-r--r--psutil/arch/bsd/process_info.h2
-rw-r--r--psutil/arch/osx/process_info.c81
-rw-r--r--psutil/arch/osx/process_info.h2
-rw-r--r--psutil/arch/windows/inet_ntop.c38
-rw-r--r--psutil/arch/windows/inet_ntop.h10
-rw-r--r--psutil/arch/windows/ntextapi.h99
-rw-r--r--psutil/arch/windows/process_handles.c771
-rw-r--r--psutil/arch/windows/process_handles.h101
-rw-r--r--psutil/arch/windows/process_info.c112
-rw-r--r--psutil/arch/windows/process_info.h11
-rw-r--r--psutil/arch/windows/security.c33
-rw-r--r--setup.py108
-rw-r--r--test/README15
-rw-r--r--test/README.rst21
-rw-r--r--test/__init__.py0
-rw-r--r--test/_bsd.py63
-rw-r--r--test/_linux.py307
-rw-r--r--test/_osx.py75
-rw-r--r--test/_posix.py36
-rw-r--r--test/_sunos.py10
-rw-r--r--test/_windows.py201
-rw-r--r--test/test_memory_leaks.py63
-rw-r--r--test/test_psutil.py1241
-rw-r--r--tox.ini22
73 files changed, 6845 insertions, 3860 deletions
diff --git a/.ci/README b/.ci/README
new file mode 100644
index 00000000..86b72afb
--- /dev/null
+++ b/.ci/README
@@ -0,0 +1,3 @@
+This directory contains support scripts for Travis and Appveyor continuous
+integration services.
+Travis is used to run tests on Linux and OSX, Appveyor runs tests on Windows.
diff --git a/.ci/appveyor/README b/.ci/appveyor/README
new file mode 100644
index 00000000..2e092a07
--- /dev/null
+++ b/.ci/appveyor/README
@@ -0,0 +1,2 @@
+This directory contains support files for appveyor, a continuous integration
+service which runs tests on Windows on every push.
diff --git a/.ci/appveyor/install.ps1 b/.ci/appveyor/install.ps1
new file mode 100644
index 00000000..3f056282
--- /dev/null
+++ b/.ci/appveyor/install.ps1
@@ -0,0 +1,85 @@
+# Sample script to install Python and pip under Windows
+# Authors: Olivier Grisel and Kyle Kastner
+# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
+
+$BASE_URL = "https://www.python.org/ftp/python/"
+$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
+$GET_PIP_PATH = "C:\get-pip.py"
+
+
+function DownloadPython ($python_version, $platform_suffix) {
+ $webclient = New-Object System.Net.WebClient
+ $filename = "python-" + $python_version + $platform_suffix + ".msi"
+ $url = $BASE_URL + $python_version + "/" + $filename
+
+ $basedir = $pwd.Path + "\"
+ $filepath = $basedir + $filename
+ if (Test-Path $filename) {
+ Write-Host "Reusing" $filepath
+ return $filepath
+ }
+
+ # Download and retry up to 5 times in case of network transient errors.
+ Write-Host "Downloading" $filename "from" $url
+ $retry_attempts = 3
+ for($i=0; $i -lt $retry_attempts; $i++){
+ try {
+ $webclient.DownloadFile($url, $filepath)
+ break
+ }
+ Catch [Exception]{
+ Start-Sleep 1
+ }
+ }
+ Write-Host "File saved at" $filepath
+ return $filepath
+}
+
+
+function InstallPython ($python_version, $architecture, $python_home) {
+ Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
+ if (Test-Path $python_home) {
+ Write-Host $python_home "already exists, skipping."
+ return $false
+ }
+ if ($architecture -eq "32") {
+ $platform_suffix = ""
+ } else {
+ $platform_suffix = ".amd64"
+ }
+ $filepath = DownloadPython $python_version $platform_suffix
+ Write-Host "Installing" $filepath "to" $python_home
+ $args = "/qn /i $filepath TARGETDIR=$python_home"
+ Write-Host "msiexec.exe" $args
+ Start-Process -FilePath "msiexec.exe" -ArgumentList $args -Wait -Passthru
+ Write-Host "Python $python_version ($architecture) installation complete"
+ return $true
+}
+
+
+function InstallPip ($python_home) {
+ $pip_path = $python_home + "/Scripts/pip.exe"
+ $python_path = $python_home + "/python.exe"
+ if (-not(Test-Path $pip_path)) {
+ Write-Host "Installing pip..."
+ $webclient = New-Object System.Net.WebClient
+ $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH)
+ Write-Host "Executing:" $python_path $GET_PIP_PATH
+ Start-Process -FilePath "$python_path" -ArgumentList "$GET_PIP_PATH" -Wait -Passthru
+ } else {
+ Write-Host "pip already installed."
+ }
+}
+
+function InstallPackage ($python_home, $pkg) {
+ $pip_path = $python_home + "/Scripts/pip.exe"
+ & $pip_path install $pkg
+}
+
+function main () {
+ InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
+ InstallPip $env:PYTHON
+ InstallPackage $env:PYTHON wheel
+}
+
+main
diff --git a/.ci/appveyor/run_with_compiler.cmd b/.ci/appveyor/run_with_compiler.cmd
new file mode 100644
index 00000000..3a472bc8
--- /dev/null
+++ b/.ci/appveyor/run_with_compiler.cmd
@@ -0,0 +1,47 @@
+:: To build extensions for 64 bit Python 3, we need to configure environment
+:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
+:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1)
+::
+:: To build extensions for 64 bit Python 2, we need to configure environment
+:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of:
+:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0)
+::
+:: 32 bit builds do not require specific environment configurations.
+::
+:: Note: this script needs to be run with the /E:ON and /V:ON flags for the
+:: cmd interpreter, at least for (SDK v7.0)
+::
+:: More details at:
+:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows
+:: http://stackoverflow.com/a/13751649/163740
+::
+:: Author: Olivier Grisel
+:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
+@ECHO OFF
+
+SET COMMAND_TO_RUN=%*
+SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows
+
+SET MAJOR_PYTHON_VERSION="%PYTHON_VERSION:~0,1%"
+IF %MAJOR_PYTHON_VERSION% == "2" (
+ SET WINDOWS_SDK_VERSION="v7.0"
+) ELSE IF %MAJOR_PYTHON_VERSION% == "3" (
+ SET WINDOWS_SDK_VERSION="v7.1"
+) ELSE (
+ ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%"
+ EXIT 1
+)
+
+IF "%PYTHON_ARCH%"=="64" (
+ ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture
+ SET DISTUTILS_USE_SDK=1
+ SET MSSdk=1
+ "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION%
+ "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release
+ ECHO Executing: %COMMAND_TO_RUN%
+ call %COMMAND_TO_RUN% || EXIT 1
+) ELSE (
+ ECHO Using default MSVC build environment for 32 bit architecture
+ ECHO Executing: %COMMAND_TO_RUN%
+ call %COMMAND_TO_RUN% || EXIT 1
+)
diff --git a/.ci/travis/README b/.ci/travis/README
new file mode 100644
index 00000000..d9d5f65a
--- /dev/null
+++ b/.ci/travis/README
@@ -0,0 +1,2 @@
+This directory contains support files for Travis, a continuous integration
+service which runs tests on Linux and Windows on every push.
diff --git a/.ci/travis/install.sh b/.ci/travis/install.sh
new file mode 100755
index 00000000..23d9ce04
--- /dev/null
+++ b/.ci/travis/install.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+ brew update || brew update
+ brew outdated pyenv || brew upgrade pyenv
+ brew install pyenv-virtualenv
+
+ if which pyenv > /dev/null; then
+ eval "$(pyenv init -)"
+ fi
+
+ case "${PYVER}" in
+ py26)
+ pyenv install 2.6.9
+ pyenv virtualenv 2.6.9 psutil
+ ;;
+ py27)
+ pyenv install 2.7.10
+ pyenv virtualenv 2.7.10 psutil
+ ;;
+ py32)
+ pyenv install 3.2.6
+ pyenv virtualenv 3.2.6 psutil
+ ;;
+ py33)
+ pyenv install 3.3.6
+ pyenv virtualenv 3.3.6 psutil
+ ;;
+ py34)
+ pyenv install 3.4.3
+ pyenv virtualenv 3.4.3 psutil
+ ;;
+ esac
+ pyenv rehash
+ pyenv activate psutil
+fi
+
+if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]] || [[ $PYVER == 'py26' ]]; then
+ pip install -U ipaddress unittest2 mock==1.0.1
+elif [[ $TRAVIS_PYTHON_VERSION == '2.7' ]] || [[ $PYVER == 'py27' ]]; then
+ pip install -U ipaddress mock
+elif [[ $TRAVIS_PYTHON_VERSION == '3.2' ]] || [[ $PYVER == 'py32' ]]; then
+ pip install -U ipaddress mock
+elif [[ $TRAVIS_PYTHON_VERSION == '3.3' ]] || [[ $PYVER == 'py33' ]]; then
+ pip install -U ipaddress
+fi
+
+pip install coverage coveralls flake8 pep8 \ No newline at end of file
diff --git a/.ci/travis/run.sh b/.ci/travis/run.sh
new file mode 100755
index 00000000..41167aa8
--- /dev/null
+++ b/.ci/travis/run.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+ if which pyenv > /dev/null; then
+ eval "$(pyenv init -)"
+ fi
+ pyenv activate psutil
+fi
+
+python setup.py build
+python setup.py install
+coverage run test/test_psutil.py --include="psutil/*" --omit="test/*,*setup*"
+python test/test_memory_leaks.py
+flake8
+pep8
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 00000000..f023909b
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,21 @@
+[report]
+
+include =
+ *psutil*
+
+omit =
+ test/*
+ *setup*
+ *_compat.py*
+
+exclude_lines =
+ pragma: no cover
+ if __name__ == .__main__.:
+ if sys.platform.startswith
+ if _WINDOWS:
+ import enum
+ if enum is not None:
+ if enum is None:
+ if has_enums:
+ enum.IntEnum
+ except ImportError:
diff --git a/.git-pre-commit b/.git-pre-commit
new file mode 100755
index 00000000..3a6161f4
--- /dev/null
+++ b/.git-pre-commit
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+# This gets executed on 'git commit' and rejects the commit in case the
+# submitted code does not pass validation.
+# Install it with "make install-git-hooks"
+
+import os
+import subprocess
+import sys
+
+
+def main():
+ out = subprocess.check_output("git diff --cached --name-only", shell=True)
+ files = [x for x in out.split('\n') if x.endswith('.py') and
+ os.path.exists(x)]
+
+ for path in files:
+ with open(path) as f:
+ data = f.read()
+
+ # pdb
+ if "pdb.set_trace" in data:
+ for lineno, line in enumerate(data.split('\n'), 1):
+ line = line.rstrip()
+ if "pdb.set_trace" in line:
+ print("%s: %s" % (lineno, line))
+ sys.exit(
+ "commit aborted: you forgot a pdb in your python code")
+
+ # bare except clause
+ if "except:" in data:
+ for lineno, line in enumerate(data.split('\n'), 1):
+ line = line.rstrip()
+ if "except:" in line and not line.endswith("# NOQA"):
+ print("%s: %s" % (lineno, line))
+ sys.exit("commit aborted: bare except clause")
+
+ # flake8
+ failed = False
+ for path in files:
+ ret = subprocess.call("flake8 %s" % path, shell=True)
+ if ret != 0:
+ failed = True
+ if failed:
+ sys.exit("commit aborted: python code is not flake8-compliant")
+
+main()
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..99d0d545
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+syntax: glob
+*.al
+*.bak
+*.egg-info
+*.la
+*.lo
+*.o
+*.orig
+*.pyc
+*.pyd
+*.rej
+*.so
+*.swp
+.cache/
+.idea/
+.tox/
+build/
+dist/
diff --git a/.travis.yml b/.travis.yml
index 2534164a..d883c653 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,21 +1,30 @@
+sudo: false
language: python
-python:
- - 2.6
- - 2.7
- - 3.2
- - 3.3
- - 3.4
- # - pypy
+matrix:
+ include:
+ - python: 2.6
+ - python: 2.7
+ - python: 3.2
+ - python: 3.3
+ - python: 3.4
+ - language: generic
+ os: osx
+ env: PYVER=py26
+ - language: generic
+ os: osx
+ env: PYVER=py27
+ - language: generic
+ os: osx
+ env: PYVER=py32
+ - language: generic
+ os: osx
+ env: PYVER=py33
+ - language: generic
+ os: osx
+ env: PYVER=py34
install:
- - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi
+ - ./.ci/travis/install.sh
script:
- - pip install flake8
- - python setup.py build
- - python setup.py install
- - python test/test_psutil.py
- - python test/test_memory_leaks.py
- - make flake8
-os:
- - linux
- - osx
-
+ - ./.ci/travis/run.sh
+after_success:
+ - coveralls # upload reports to coveralls.io
diff --git a/CREDITS b/CREDITS
index 896133cc..60faa749 100644
--- a/CREDITS
+++ b/CREDITS
@@ -29,6 +29,10 @@ E: jloden@gmail.com
D: original co-author, initial design/bootstrap and occasional bug fixes
W: http://www.jayloden.com
+N: Jeff Tang
+W: https://github.com/mrjefftang
+I: 340, 529, 616, 653, 654, 648, 641
+
N: Jeremy Whitlock
E: jcscoobyrs@gmail.com
D: great help with OSX C development.
@@ -253,10 +257,6 @@ N: msabramo
E: msabramo@gmail.com
I: 492
-N: Jeff Tang
-W: https://github.com/mrjefftang
-I: 340, 529
-
N: Yaolong Huang
E: airekans@gmail.com
W: http://airekans.github.io/
@@ -267,8 +267,9 @@ W: https://github.com/anders-chrigstrom
I: 496
N: spacewander
+W: https://github.com/spacewander
E: spacewanderlzx@gmail.com
-I: 561
+I: 561, 603
N: Sylvain Mouquet
E: sylvain.mouquet@gmail.com
@@ -276,3 +277,51 @@ I: 565
N: karthikrev
I: 568
+
+N: Bruno Binet
+E: bruno.binet@gmail.com
+I: 572
+
+N: Gabi Davar
+C: Israel
+W: https://github.com/mindw
+I: 578, 581, 587
+
+N: spacewanderlzx
+C: Guangzhou,China
+E: spacewanderlzx@gmail.com
+I: 555
+
+N: Fabian Groffen
+I: 611, 618
+
+N: desbma
+W: https://github.com/desbma
+C: France
+I: 628
+
+N: John Burnett
+W: http://www.johnburnett.com/
+C: Irvine, CA, US
+I: 614
+
+N: Árni Már Jónsson
+E: Reykjavik, Iceland
+E: https://github.com/arnimarj
+I: 634
+
+N: Bart van Kleef
+W: https://github.com/bkleef
+I: 664
+
+N: Steven Winfield
+W: https://github.com/stevenwinfield
+I: 672
+
+N: sk6249
+W: https://github.com/sk6249
+I: 670
+
+N: maozguttman
+W: https://github.com/maozguttman
+I: 659
diff --git a/DEVGUIDE.rst b/DEVGUIDE.rst
new file mode 100644
index 00000000..cfbc1789
--- /dev/null
+++ b/DEVGUIDE.rst
@@ -0,0 +1,147 @@
+=====
+Setup
+=====
+
+If you plan on hacking on psutil this is what you're supposed to do first:
+
+- git clone the repo: ``git clone git@github.com:giampaolo/psutil.git``.
+- take a look at `install instructions <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
+ and satisfy system dependencies first.
+- bear in mind that ``make`` (see `Makefile <https://github.com/giampaolo/psutil/blob/master/Makefile>`_)
+ is the designated tool to run tests, build etc. and that it is also available
+ on Windows (see `make.bat <https://github.com/giampaolo/psutil/blob/master/make.bat>`_).
+- (UNIX only) run ``make install-git-hooks``: this will reject your commit
+ if it's not PEP8 compliant.
+- run ``make setup-dev-env``: this will install test deps (e.g. mock lib)
+ and other useful tools (e.g. ipdb, flake8).
+- run ``make test`` to run tests.
+
+============
+Coding style
+============
+
+- python code strictly follows `PEP 8 <https://www.python.org/dev/peps/pep-0008/>`_
+ styling guides and this is enforced by ``make install-git-hooks``.
+- C code strictly follows `PEP 7 <https://www.python.org/dev/peps/pep-0007/>`_
+ styling guides.
+
+========
+Makefile
+========
+
+Some useful make commands:
+
+- ``make install``
+- ``make test``
+- ``make test-memleaks``
+- ``make coverage``
+- ``make flake8``
+
+====================
+Adding a new feature
+====================
+
+Usually the files involved when adding a new functionality are:
+
+.. code-block:: plain
+
+ psutil/__init__.py # main psutil namespace
+ psutil/_ps{platform}.py # python platform wrapper
+ psutil/_psutil_{platform}.c # C platform extension
+ psutil/_psutil_{platform}.h # C header file
+ test/test_psutil.py # main test suite
+ test/_{platform}.py # platform specific test suite
+
+Typical process occurring when adding a new functionality (API):
+
+- define the new function in ``psutil/__init__.py``.
+- write the platform specific implementation in ``psutil/_ps{platform}.py``
+ (e.g. ``psutil/_pslinux.py``).
+- if the change requires C code write the C implementation in
+ ``psutil/_psutil_{platform}.c`` (e.g. ``psutil/_psutil_linux.c``).
+- write a cross platform test in ``test/test_psutil.py``.
+- write a platform specific test in ``test/_{platform}.py``; platform specific
+ tests usually test psutil against system CLI tools.
+- update doc.
+- make a pull request.
+
+======================
+Continuous integration
+======================
+
+All of the services listed below are automatically run on ``git push``.
+
+Tests
+-----
+
+Tests are automatically run for every GIT push on **Linux**, **OSX** and
+**Windows** by using:
+
+- `Travis <https://travis-ci.org/giampaolo/psutil>`_ (Linux, OSX)
+- `Appveyor <https://ci.appveyor.com/project/giampaolo/psutil>`_ (Windows)
+
+Test files controlling these are
+`.travis.yml <https://github.com/giampaolo/psutil/blob/master/.travis.yml>`_
+and
+`appveyor.yml <https://github.com/giampaolo/psutil/blob/master/appveyor.yml>`_.
+Both services run psutil test suite against all supported python version
+(2.6 - 3.4).
+Two icons in the home page (README) always show the build status:
+
+.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master
+ :target: https://travis-ci.org/giampaolo/psutil
+ :alt: Linux tests (Travis)
+
+.. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true
+ :target: https://ci.appveyor.com/project/giampaolo/psutil
+ :alt: Windows tests (Appveyor)
+
+OSX, FreeBSD and Solaris are currently tested manually (sigh!).
+
+Test coverage
+-------------
+
+Test coverage is provided by `coveralls.io <https://coveralls.io/github/giampaolo/psutil>`_
+and it is controlled via `.travis.yml <https://github.com/giampaolo/psutil/blob/master/.travis.yml>`_.
+An icon in the home page (README) always shows the last coverage percentage:
+
+.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github
+ :target: https://coveralls.io/github/giampaolo/psutil?branch=master
+ :alt: Test coverage (coverall.io)
+
+Code quality
+------------
+
+Code quality is controlled by `scrutinizer-ci <https://scrutinizer-ci.com/g/giampaolo/psutil/>`_
+which provides a report signaling duplicated code and other amenities. It is
+controlled by `.scrutinizer.yml <https://github.com/giampaolo/psutil/blob/master/.scrutinizer.yml>`_.
+An icon in the home page always shows a code quality score:
+
+.. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg
+ :target: https://scrutinizer-ci.com/g/giampaolo/psutil/
+ :alt: Code quality (scrutinizer-ci.com)
+
+=============
+Documentation
+=============
+
+- doc source code is in `/docs <https://github.com/giampaolo/psutil/tree/master/docs>`_
+ directory.
+- it uses `RsT syntax <http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_
+ and it's built with `sphinx <http://sphinx-doc.org/>`_.
+- doc can be built with ``make setup-dev-env; cd docs; make html``.
+- public doc is hosted on http://pythonhosted.org/psutil/.
+- it is uploaded on every new release with ``make upload-doc``.
+
+=======================
+Releasing a new version
+=======================
+
+These are note for myself (Giampaolo):
+
+- make sure all tests pass and all builds are green.
+- upload source tarball on PYPI with ``make upload-src``.
+- upload exe and wheel files for windows on PYPI with ``make upload-all``.
+- upload updated doc on http://pythonhosted.org/psutil with ``make upload-doc``.
+- GIT tag the new release with ``make git-tag-release``.
+- post on psutil and python-announce mailing lists, twitter, g+, blog.
diff --git a/HISTORY.rst b/HISTORY.rst
index e053b8d5..76821e92 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,5 +1,158 @@
Bug tracker at https://github.com/giampaolo/psutil/issues
+3.2.1 - 2015-09-03
+==================
+
+**Bug fixes**
+
+- #677: [Linux] can't install psutil due to bug in setup.py.
+
+
+3.2.0 - 2015-09-02
+==================
+
+**Enhancements**
+
+- #644: [Windows] added support for CTRL_C_EVENT and CTRL_BREAK_EVENT signals
+ to use with Process.send_signal().
+- #648: CI test integration for OSX. (patch by Jeff Tang)
+- #663: [UNIX] net_if_addrs() now returns point-to-point (VPNs) addresses.
+- #655: [Windows] different issues regarding unicode handling were fixed. On
+ Python 2 all APIs returning a string will now return an encoded version of it
+ by using sys.getfilesystemencoding() codec. The APIs involved are:
+ - psutil.net_if_addrs()
+ - psutil.net_if_stats()
+ - psutil.net_io_counters()
+ - psutil.Process.cmdline()
+ - psutil.Process.name()
+ - psutil.Process.username()
+ - psutil.users()
+
+**Bug fixes**
+
+- #513: [Linux] fixed integer overflow for RLIM_INFINITY.
+- #641: [Windows] fixed many compilation warnings. (patch by Jeff Tang)
+- #652: [Windows] net_if_addrs() UnicodeDecodeError in case of non-ASCII NIC
+ names.
+- #655: [Windows] net_if_stats() UnicodeDecodeError in case of non-ASCII NIC
+ names.
+- #659: [Linux] compilation error on Suse 10. (patch by maozguttman)
+- #664: [Linux] compilation error on Alpine Linux. (patch by Bart van Kleef)
+- #670: [Windows] segfgault of net_if_addrs() in case of non-ASCII NIC names.
+ (patch by sk6249)
+- #672: [Windows] compilation fails if using Windows SDK v8.0. (patch by
+ Steven Winfield)
+- #675: [Linux] net_connections(); UnicodeDecodeError may occur when listing
+ UNIX sockets.
+
+
+3.1.1 - 2015-07-15
+==================
+
+**Bug fixes**
+
+- #603: [Linux] ionice_set value range is incorrect. (patch by spacewander)
+- #645: [Linux] psutil.cpu_times_percent() may produce negative results.
+- #656: 'from psutil import *' does not work.
+
+
+3.1.0 - 2015-07-15
+==================
+
+**Enhancements**
+
+- #534: [Linux] disk_partitions() added support for ZFS filesystems.
+- #646: continuous tests integration for Windows with
+ https://ci.appveyor.com/project/giampaolo/psutil.
+- #647: new dev guide:
+ https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst
+- #651: continuous code quality test integration with
+ https://scrutinizer-ci.com/g/giampaolo/psutil/
+
+**Bug fixes**
+
+- #340: [Windows] Process.open_files() no longer hangs. Instead it uses a
+ thred which times out and skips the file handle in case it's taking too long
+ to be retrieved. (patch by Jeff Tang, PR #597)
+- #627: [Windows] Process.name() no longer raises AccessDenied for pids owned
+ by another user.
+- #636: [Windows] Process.memory_info() raise AccessDenied.
+- #637: [UNIX] raise exception if trying to send signal to Process PID 0 as it
+ will affect os.getpid()'s process group instead of PID 0.
+- #639: [Linux] Process.cmdline() can be truncated.
+- #640: [Linux] *connections functions may swallow errors and return an
+ incomplete list of connnections.
+- #642: repr() of exceptions is incorrect.
+- #653: [Windows] Add inet_ntop function for Windows XP to support IPv6.
+- #641: [Windows] Replace deprecated string functions with safe equivalents.
+
+
+3.0.1 - 2015-06-18
+==================
+
+**Bug fixes**
+
+- #632: [Linux] better error message if cannot parse process UNIX connections.
+- #634: [Linux] Proces.cmdline() does not include empty string arguments.
+- #635: [UNIX] crash on module import if 'enum' package is installed on python
+ < 3.4.
+
+
+3.0.0 - 2015-06-13
+==================
+
+**Enhancements**
+
+- #250: new psutil.net_if_stats() returning NIC statistics (isup, duplex,
+ speed, MTU).
+- #376: new psutil.net_if_addrs() returning all NIC addresses a-la ifconfig.
+- #469: on Python >= 3.4 ``IOPRIO_CLASS_*`` and ``*_PRIORITY_CLASS`` constants
+ returned by psutil.Process' ionice() and nice() methods are enums instead of
+ plain integers.
+- #581: add .gitignore. (patch by Gabi Davar)
+- #582: connection constants returned by psutil.net_connections() and
+ psutil.Process.connections() were turned from int to enums on Python > 3.4.
+- #587: Move native extension into the package.
+- #589: Process.cpu_affinity() accepts any kind of iterable (set, tuple, ...),
+ not only lists.
+- #594: all deprecated APIs were removed.
+- #599: [Windows] process name() can now be determined for all processes even
+ when running as a limited user.
+- #602: pre-commit GIT hook.
+- #629: enhanced support for py.test and nose test discovery and tests run.
+- #616: [Windows] Add inet_ntop function for Windows XP.
+
+**Bug fixes**
+
+- #428: [all UNIXes except Linux] correct handling of zombie processes;
+ introduced new ZombieProcess exception class.
+- #512: [BSD] fix segfault in net_connections().
+- #555: [Linux] psutil.users() correctly handles ":0" as an alias for
+ "localhost"
+- #579: [Windows] Fixed open_files() for PID>64K.
+- #579: [Windows] fixed many compiler warnings.
+- #585: [FreeBSD] net_connections() may raise KeyError.
+- #586: [FreeBSD] cpu_affinity() segfaults on set in case an invalid CPU
+ number is provided.
+- #593: [FreeBSD] Process().memory_maps() segfaults.
+- #606: Process.parent() may swallow NoSuchProcess exceptions.
+- #611: [SunOS] net_io_counters has send and received swapped
+- #614: [Linux]: cpu_count(logical=False) return the number of physical CPUs
+ instead of physical cores.
+- #618: [SunOS] swap tests fail on Solaris when run as normal user
+- #628: [Linux] Process.name() truncates process name in case it contains
+ spaces or parentheses.
+
+
+2.2.1 - 2015-02-02
+==================
+
+**Bug fixes**
+
+- #496: [Linux] fix "ValueError: ambiguos inode with multiple PIDs references"
+ (patch by Bruno Binet)
+
+
2.2.0 - 2015-01-06
==================
diff --git a/INSTALL.rst b/INSTALL.rst
index bb30a06b..fdbc4d6d 100644
--- a/INSTALL.rst
+++ b/INSTALL.rst
@@ -4,12 +4,12 @@ Installing using pip on UNIX
The easiest way to install psutil on UNIX is by using pip (but first you might
need to install python header files; see later).
-First install pip:
+First install pip::
- $ wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
- python ez_setup.py
+ $ wget https://bootstrap.pypa.io/get-pip.py
+ $ python get-pip.py
-...then run:
+...then run::
$ pip install psutil
@@ -22,49 +22,27 @@ Installing on Windows
Just get the right installer for your Python version and architecture from:
https://pypi.python.org/pypi/psutil/#downloads
-
-
-==================================
-Compiling on Windows using mingw32
-==================================
-
-First install mingw (http://www.mingw.org/) then add mingw "bin" folder to
-environment PATH (NOTE: this assumes MinGW is installed in C:\MinGW):
-
- SET PATH=C:\MinGW\bin;%PATH%
-
-You can then compile psutil by running:
-
- setup.py build -c mingw32
-
-To compile and install:
-
- setup.py build -c mingw32 install
-
-You can also use make.bat which automatically sets the env variable for you:
-
- make.bat build
-
-FWIW I managed to compile psutil against all 32-bit Python versions but not
-64 bit.
+Since wheels installers are also available you may also use pip.
========================================
Compiling on Windows using Visual Studio
========================================
-To use Visual Studio to compile psutil you must have the same version of
-Visual Studio used to compile your installation of Python which is::
+In order to compile psutil on Windows you'll need Visual Studio (Mingw32 is
+no longer supported). You must have the same version of Visual Studio used to
+compile your installation of Python, that is::
- Python 2.6: VS 2008
- Python 2.7: VS 2008
- Python 3.3+: VS 2010
+* Python 2.6: VS 2008 (download it from `here <http://www.microsoft.com/en-us/download/details.aspx?id=44266>`_)
+* Python 2.7: VS 2008 (download it from `here <http://www.microsoft.com/en-us/download/details.aspx?id=44266>`_)
+* Python 3.3, 3.4: VS 2010 (you can download it from `MS website <http://www.visualstudio.com/downloads/download-visual-studio-vs#d-2010-express>`_)
+* Python 3.5: `VS 2015 UP <http://www.visualstudio.com/en-au/news/vs2015-preview-vs>`_
-...then run:
+...then run::
setup.py build
-...or:
+...or::
make.bat build
@@ -73,24 +51,20 @@ Windows SDK and .NET Framework 3.5 SP1 to be installed first.
Once you have those run vcvars64.bat, then compile:
http://stackoverflow.com/questions/11072521/
-If you do not have the right version of Visual Studio available then try using
-MinGW instead.
-
-
===================
Installing on Linux
===================
gcc is required and so the python headers. They can easily be installed by
-using the distro package manager. For example, on Debian amd Ubuntu:
+using the distro package manager. For example, on Debian and Ubuntu::
$ sudo apt-get install gcc python-dev
-...on Redhat and CentOS:
+...on Redhat and CentOS::
$ sudo yum install gcc python-devel
-Once done, you can build/install psutil with:
+Once done, you can build/install psutil with::
$ python setup.py install
@@ -102,11 +76,11 @@ Installing on OS X
OS X installation from source will require gcc which you can obtain as part of
the 'XcodeTools' installer from Apple. Then you can run the standard distutils
commands.
-To build only:
+To build only::
$ python setup.py build
-To install and build:
+To install and build::
$ python setup.py install
@@ -119,11 +93,11 @@ The same compiler used to install Python must be present on the system in order
to build modules using distutils. Assuming it is installed, you can build using
the standard distutils commands.
-Build only:
+Build only::
$ python setup.py build
-Install and build:
+Install and build::
$ python setup.py install
@@ -136,7 +110,7 @@ A makefile is available for both UNIX and Windows (make.bat). It provides
some automations for the tasks described above and might be preferred over
using setup.py. With it you can::
- $ make install # just install
+ $ make install # just install (in --user mode)
$ make uninstall # uninstall (needs pip)
$ make test # run tests
$ make clean # remove installation files
diff --git a/MANIFEST.in b/MANIFEST.in
index b275f613..a95f32f4 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,8 @@
+include .coveragerc
+include .git-pre-commit
+include .gitignore
include .travis.yml
+include appveyor.yml
include CREDITS
include HISTORY.rst
include INSTALL.rst
@@ -10,8 +14,9 @@ include README.rst
include setup.py
include TODO
include tox.ini
-recursive-include docs *
recursive-exclude docs/_build *
+recursive-include .ci/*
+recursive-include docs *
recursive-include examples *.py
recursive-include psutil *.py *.c *.h
-recursive-include test *.py README \ No newline at end of file
+recursive-include test *.py README*
diff --git a/Makefile b/Makefile
index 542cc251..153a0773 100644
--- a/Makefile
+++ b/Makefile
@@ -16,21 +16,51 @@ clean:
rm -f `find . -type f -name \*.bak`
rm -f `find . -type f -name \*.rej`
rm -rf `find . -type d -name __pycache__`
+ rm -rf *.core
rm -rf *.egg-info
rm -rf *\$testfile*
+ rm -rf .coverage
rm -rf .tox
rm -rf build
rm -rf dist
rm -rf docs/_build
+ rm -rf htmlcov
build: clean
$(PYTHON) setup.py build
+ @# copies *.so files in ./psutil directory in order to allow
+ @# "import psutil" when using the interactive interpreter from within
+ @# this directory.
+ $(PYTHON) setup.py build_ext -i
+
+# useful deps which are nice to have while developing / testing
+setup-dev-env: install-git-hooks
+ python -c "import urllib2, ssl; \
+ context = ssl._create_unverified_context() if hasattr(ssl, '_create_unverified_context') else None; \
+ kw = dict(context=context) if context else {}; \
+ r = urllib2.urlopen('https://bootstrap.pypa.io/get-pip.py', **kw); \
+ open('/tmp/get-pip.py', 'w').write(r.read());"
+ $(PYTHON) /tmp/get-pip.py --user
+ rm /tmp/get-pip.py
+ $(PYTHON) -m pip install --user --upgrade pip
+ $(PYTHON) -m pip install --user --upgrade \
+ coverage \
+ flake8 \
+ ipaddress \
+ ipdb \
+ mock==1.0.1 \
+ nose \
+ pep8 \
+ pyflakes \
+ sphinx \
+ sphinx-pypi-upload \
+ unittest2 \
install: build
- $(PYTHON) setup.py install --user; \
+ $(PYTHON) setup.py install --user
uninstall:
- cd ..; $(PYTHON) -m pip uninstall -y -v psutil; \
+ cd ..; $(PYTHON) -m pip uninstall -y -v psutil
test: install
$(PYTHON) $(TSCRIPT)
@@ -42,27 +72,36 @@ test-system: install
$(PYTHON) -m unittest -v test.test_psutil.TestSystemAPIs
test-memleaks: install
- $(PYTHON) -m unittest -v test.test_memory_leaks
+ $(PYTHON) test/test_memory_leaks.py
# Run a specific test by name; e.g. "make test-by-name disk_" will run
# all test methods containing "disk_" in their name.
# Requires "pip install nose".
-test-by-name:
- @$(PYTHON) -m nose test/test_psutil.py --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS))
+test-by-name: install
+ @$(PYTHON) -m nose test/test_psutil.py test/_* --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS))
+
+# Same as above but for test_memory_leaks.py script.
+test-memleaks-by-name: install
+ @$(PYTHON) -m nose test/test_memory_leaks.py --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS))
+
+coverage: install
+ # Note: coverage options are controlled by .coveragerc file
+ rm -rf .coverage htmlcov
+ $(PYTHON) -m coverage run $(TSCRIPT)
+ $(PYTHON) -m coverage report
+ @echo "writing results to htmlcov/index.html"
+ $(PYTHON) -m coverage html
+ $(PYTHON) -m webbrowser -t htmlcov/index.html
-# requires "pip install pep8"
pep8:
- @git ls-files | grep \\.py$ | xargs pep8
+ @git ls-files | grep \\.py$ | xargs $(PYTHON) -m pep8
-# requires "pip install pyflakes"
pyflakes:
@export PYFLAKES_NODOCTEST=1 && \
- git ls-files | grep \\.py$ | xargs pyflakes
+ git ls-files | grep \\.py$ | xargs $(PYTHON) -m pyflakes
-# requires "pip install flake8"
flake8:
- @git ls-files | grep \\.py$ | xargs flake8
-
+ @git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8
# Upload source tarball on https://pypi.python.org/pypi/psutil.
upload-src: clean
@@ -77,4 +116,9 @@ upload-doc:
# git-tag a new release
git-tag-release:
git tag -a release-`python -c "import setup; print(setup.get_version())"` -m `git rev-list HEAD --count`:`git rev-parse --short HEAD`
- echo "done; now run 'git push --follow-tags' to push the new tag on the remote repo"
+ git push --follow-tags
+
+# install GIT pre-commit hook
+install-git-hooks:
+ ln -sf ../../.git-pre-commit .git/hooks/pre-commit
+ chmod +x .git/hooks/pre-commit
diff --git a/README.rst b/README.rst
index 3a218705..6517810a 100644
--- a/README.rst
+++ b/README.rst
@@ -1,28 +1,46 @@
-.. image:: https://pypip.in/d/psutil/badge.png
- :target: https://crate.io/packages/psutil/
- :alt: Download this month
+.. image:: https://img.shields.io/pypi/dm/psutil.svg
+ :target: https://pypi.python.org/pypi/psutil#downloads
+ :alt: Downloads this month
-.. image:: https://pypip.in/v/psutil/badge.png
+.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master
+ :target: https://travis-ci.org/giampaolo/psutil
+ :alt: Linux tests (Travis)
+
+.. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true
+ :target: https://ci.appveyor.com/project/giampaolo/psutil
+ :alt: Windows tests (Appveyor)
+
+.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github
+ :target: https://coveralls.io/github/giampaolo/psutil?branch=master
+ :alt: Test coverage (coverall.io)
+
+.. image:: https://img.shields.io/pypi/v/psutil.svg
:target: https://pypi.python.org/pypi/psutil/
:alt: Latest version
-.. image:: https://pypip.in/license/psutil/badge.png
+.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
+ :target: https://github.com/giampaolo/psutil/
+ :alt: Github stars
+
+.. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg
+ :target: https://scrutinizer-ci.com/g/giampaolo/psutil/
+ :alt: Code quality (scrutinizer-ci.com)
+
+.. image:: https://img.shields.io/pypi/l/psutil.svg
:target: https://pypi.python.org/pypi/psutil/
:alt: License
-.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master
- :target: https://travis-ci.org/giampaolo/psutil
- :alt: Travis
-
===========
Quick links
===========
- `Home page <https://github.com/giampaolo/psutil>`_
- `Documentation <http://pythonhosted.org/psutil/>`_
+- `Installation <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
- `Forum <http://groups.google.com/group/psutil/topics>`_
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
+- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
=======
@@ -37,7 +55,7 @@ running processes**. It implements many functionalities offered by command line
tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice,
ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports
**Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and
-**64-bit** architectures, with Python versions from **2.6 to 3.4** (users of
+**64-bit** architectures, with Python versions from **2.6 to 3.5** (users of
Python 2.4 and 2.5 may use `2.1.3 <https://pypi.python.org/pypi?name=psutil&version=2.1.3&:action=files>`__ version).
`PyPy <http://pypy.org/>`__ is also known to work.
@@ -110,9 +128,9 @@ Memory
.. code-block:: python
>>> psutil.virtual_memory()
- svmem(total=8374149120L, available=2081050624L, percent=75.1, used=8074080256L, free=300068864L, active=3294920704, inactive=1361616896, buffers=529895424L, cached=1251086336)
+ svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336)
>>> psutil.swap_memory()
- sswap(total=2097147904L, used=296128512L, free=1801019392L, percent=14.1, sin=304193536, sout=677842944)
+ sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
>>>
Disks
@@ -141,11 +159,23 @@ Network
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
>>>
>>> psutil.net_connections()
- [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
- pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
- pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
- pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
+ [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
+ pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
+ pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
+ pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
...]
+ >>>
+ >>> psutil.net_if_addrs()
+ {'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
+ snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
+ snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
+ 'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
+ snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
+ snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
+ >>>
+ >>> psutil.net_if_stats()
+ {'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
+ 'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
Other system info
=================
@@ -228,10 +258,10 @@ Process management
[popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
>>>
>>> p.connections()
- [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
- pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
- pconn(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
- pconn(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
+ [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
+ pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
+ pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
+ pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
>>>
>>> p.num_threads()
4
@@ -252,7 +282,7 @@ Process management
>>>
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)
>>> p.ionice()
- pionice(ioclass=3, value=0)
+ pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
>>>
>>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only)
>>> p.rlimit(psutil.RLIMIT_NOFILE)
@@ -320,6 +350,13 @@ http://groups.google.com/group/psutil/
Timeline
========
+- 2015-09-03: `psutil-3.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.2.1.tar.gz>`_
+- 2015-09-02: `psutil-3.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.2.0.tar.gz>`_
+- 2015-07-15: `psutil-3.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.1.tar.gz>`_
+- 2015-07-15: `psutil-3.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.0.tar.gz>`_
+- 2015-06-18: `psutil-3.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.1.tar.gz>`_
+- 2015-06-13: `psutil-3.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.0.tar.gz>`_
+- 2015-02-02: `psutil-2.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.1.tar.gz>`_
- 2015-01-06: `psutil-2.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.0.tar.gz>`_
- 2014-09-26: `psutil-2.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.3.tar.gz>`_
- 2014-09-21: `psutil-2.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.2.tar.gz>`_
diff --git a/TODO b/TODO
index 9e0292e9..a5df809d 100644
--- a/TODO
+++ b/TODO
@@ -9,22 +9,29 @@ https://github.com/giampaolo/psutil/issues
HIGHER PRIORITY
===============
- * #250: net ifaces speed.
-
- * #376: ifconfig functionalities aka psutil.net_ifaces (could be merged
- with #250)
-
* OpenBSD support.
* #371: CPU temperature (apparently OSX and Linux only; on Linux it requires
lm-sensors lib).
- * #269: expose network ifaces RX/TW queues.
+ * #269: expose network ifaces RX/TW queues. This should probably go into
+ net_if_stats(). Figure out on what platforms this is supported:
+ Linux: yes
+ Others: ?
- * Process.threads(): thread names
+ * Process.threads(): thread names; patch for OSX available at:
+ https://code.google.com/p/plcrashreporter/issues/detail?id=65
* Asynchronous psutil.Popen (see http://bugs.python.org/issue1191964)
+ * (Windows) fall back on using WMIC for Process methods returning AccessDenied
+
+ * #613: thread names.
+
+ * #604: emulate os.getloadavg() on Windows
+
+ * #269: NIC rx/tx queue.
+
LOWER PRIORITY
==============
@@ -50,10 +57,7 @@ LOWER PRIORITY
* #357: what CPU a process is on.
- * thread names:
- * https://code.google.com/p/plcrashreporter/issues/detail?id=65
-
- * Doc / wiki which compares similarities between UNIX cli tools and psutil.
+ * Doc / wiki which compares similarities between UNIX cli tools and psutil.
Example:
df -a -> psutil.disk_partitions
lsof -> psutil.Process.open_files() and psutil.Process.open_connections()
@@ -65,7 +69,13 @@ LOWER PRIORITY
DEBATABLE
=========
- * support wheels? http://pythonwheels.com/
+ * psutil.proc_tree() something which obtains a {pid:ppid, ...} dict for
+ all running processes in one shot. This can be factored out from
+ Process.children() and exposed as a first class function.
+ PROS: on Windows we can take advantage of _psutil_windows.ppid_map()
+ which is faster than iterating over all pids and calling ppid().
+ CONS: examples/pstree.py shows this can be easily done in the user code
+ so maybe it's not worth the addition.
* advanced cmdline interface exposing the whole API and providing different
kind of outputs (e.g. pprinted, colorized, json).
@@ -86,10 +96,18 @@ DEBATABLE
Also, we can probably reimplement wait_pid() on POSIX which is currently
implemented as a busy-loop.
- * Certain systems (XXX figure out which ones exactly) provide CPU times about
- process children. On those systems Process.cpu_times() might return
- a (user, system, user_children, system_children) ntuple.
- Also, os.times() provides 'elapsed' times as well.
+ * Certain systems provide CPU times about process children. On those systems
+ Process.cpu_times() might return a (user, system, user_children,
+ system_children) ntuple.
+ * Linux: /proc/{PID}/stat
+ * Solaris: pr_cutime and pr_cstime
+ * FreeBSD: none
+ * OSX: none
+ * Windows: none
+
+ * ...also, os.times() provides 'elapsed' times as well.
+
+ * ...also Linux provides guest_time and cguest_time.
* Enrich exception classes hierarchy on Python >= 3.3 / post PEP-3151 so that:
- NoSuchProcess inherits from ProcessLookupError
@@ -146,4 +164,4 @@ Removals (will likely happen in 2.2):
REJECTED IDEAS
==============
-STUB \ No newline at end of file
+STUB
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 00000000..10080c79
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,77 @@
+environment:
+
+ global:
+ # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
+ # /E:ON and /V:ON options are not enabled in the batch script intepreter
+ # See: http://stackoverflow.com/a/13751649/163740
+ WITH_COMPILER: "cmd /E:ON /V:ON /C .\\.ci\\appveyor\\run_with_compiler.cmd"
+
+ matrix:
+ # Pre-installed Python versions, which Appveyor may upgrade to
+ # a later point release.
+
+ - PYTHON: "C:\\Python27"
+ PYTHON_VERSION: "2.7.x"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python33"
+ PYTHON_VERSION: "3.3.x"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python34"
+ PYTHON_VERSION: "3.4.x"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python27-x64"
+ PYTHON_VERSION: "2.7.x"
+ PYTHON_ARCH: "64"
+ WINDOWS_SDK_VERSION: "v7.0"
+
+ - PYTHON: "C:\\Python33-x64"
+ PYTHON_VERSION: "3.3.x"
+ PYTHON_ARCH: "64"
+ WINDOWS_SDK_VERSION: "v7.1"
+
+ - PYTHON: "C:\\Python34-x64"
+ PYTHON_VERSION: "3.4.x"
+ PYTHON_ARCH: "64"
+ WINDOWS_SDK_VERSION: "v7.1"
+
+ # Also build on a Python version not pre-installed by Appveyor.
+ # See: https://github.com/ogrisel/python-appveyor-demo/issues/10
+
+ # - PYTHON: "C:\\Python266"
+ # PYTHON_VERSION: "2.6.6"
+ # PYTHON_ARCH: "32"
+
+init:
+ - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%"
+
+install:
+ - "powershell .ci\\appveyor\\install.ps1"
+ # - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:/get-pip.py')
+ # - "%PYTHON%/python.exe C:/get-pip.py"
+ # - "%PYTHON%/python.exe -m pip install ..."
+ - "%WITH_COMPILER% %PYTHON%/python.exe setup.py build"
+ - "%WITH_COMPILER% %PYTHON%/python.exe setup.py build build_ext -i"
+ - "%WITH_COMPILER% %PYTHON%/python.exe setup.py install"
+ - "%WITH_COMPILER% %PYTHON%/Scripts/pip.exe install unittest2 ipaddress pypiwin32 wmi wheel --upgrade"
+ # 1.0.1 is the latest release supporting python 2.6
+ - "%WITH_COMPILER% %PYTHON%/Scripts/pip.exe install mock==1.0.1"
+
+build: off
+
+test_script:
+ - "%WITH_COMPILER% %PYTHON%/python test/test_psutil.py"
+
+after_test:
+ - "%WITH_COMPILER% %PYTHON%/python setup.py bdist_wheel"
+
+artifacts:
+ - path: dist\*
+
+# on_success:
+# - might want to upload the content of dist/*.whl to a public wheelhouse
+
+skip_commits:
+ message: skip-ci
diff --git a/docs/index.rst b/docs/index.rst
index e4c36afa..e8998390 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -18,8 +18,10 @@ Quick links
* `Home page <https://github.com/giampaolo/psutil>`__
* `Blog <http://grodola.blogspot.com/search/label/psutil>`__
-* `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`__
* `Forum <http://groups.google.com/group/psutil/topics>`__
+* `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`__
+* `Installation <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
+* `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
* `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`__
About
@@ -66,7 +68,7 @@ CPU
- **guest** *(Linux 2.6.24+)*
- **guest_nice** *(Linux 3.2.0+)*
- When *percpu* is ``True`` return a list of nameduples for each logical CPU
+ When *percpu* is ``True`` return a list of namedtuples for each logical CPU
on the system.
First element of the list refers to first CPU, second element to second CPU
and so on.
@@ -199,7 +201,7 @@ Memory
* **total**: total swap memory in bytes
* **used**: used swap memory in bytes
* **free**: free swap memory in bytes
- * **percent**: the percentage usage
+ * **percent**: the percentage usage calculated as ``(total - available) / total * 100``
* **sin**: the number of bytes the system has swapped in from disk
(cumulative)
* **sout**: the number of bytes the system has swapped out from disk
@@ -274,7 +276,7 @@ Disks
If *perdisk* is ``True`` return the same information for every physical disk
installed on the system as a dictionary with partition names as the keys and
- the namedutuple described above as the values.
+ the namedtuple described above as the values.
See `examples/iotop.py <https://github.com/giampaolo/psutil/blob/master/examples/iotop.py>`__
for an example application.
@@ -321,7 +323,7 @@ Network
.. function:: net_connections(kind='inet')
- Return system-wide socket connections as a list of namedutples.
+ Return system-wide socket connections as a list of namedtuples.
Every namedtuple provides 7 attributes:
- **fd**: the socket file descriptor, if retrievable, else ``-1``.
@@ -383,6 +385,7 @@ Network
| "all" | the sum of all the possible families and protocols |
+----------------+-----------------------------------------------------+
+ On OSX this function requires root privileges.
To get per-process connections use :meth:`Process.connections`.
Also, see
`netstat.py sample script <https://github.com/giampaolo/psutil/blob/master/examples/netstat.py>`__.
@@ -390,10 +393,10 @@ Network
>>> import psutil
>>> psutil.net_connections()
- [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
- pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
- pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
- pconn(fd=-1, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
+ [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
+ pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
+ pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
+ pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
...]
.. note:: (OSX) :class:`psutil.AccessDenied` is always raised unless running
@@ -402,6 +405,87 @@ Network
.. versionadded:: 2.1.0
+.. function:: net_if_addrs()
+
+ Return the addresses associated to each NIC (network interface card)
+ installed on the system as a dictionary whose keys are the NIC names and
+ value is a list of namedtuples for each address assigned to the NIC.
+ Each namedtuple includes 5 fields:
+
+ - **family**
+ - **address**
+ - **netmask**
+ - **broadcast**
+ - **ptp**
+
+ *family* can be either
+ `AF_INET <http://docs.python.org//library/socket.html#socket.AF_INET>`__,
+ `AF_INET6 <http://docs.python.org//library/socket.html#socket.AF_INET6>`__
+ or :const:`psutil.AF_LINK`, which refers to a MAC address.
+ *address* is the primary address and it is always set.
+ *netmask*, *broadcast* and *ptp* may be ``None``.
+ *ptp* stands for "point to point" and references the destination address on a
+ point to point interface (tipically a VPN).
+ *broadcast* and *ptp* are mutually exclusive.
+ *netmask*, *broadcast* and *ptp* are not supported on Windows and are set to
+ ``None``.
+
+ Example::
+
+ >>> import psutil
+ >>> psutil.net_if_addrs()
+ {'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
+ snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
+ snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
+ 'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
+ snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
+ snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
+ >>>
+
+ See also `examples/ifconfig.py <https://github.com/giampaolo/psutil/blob/master/examples/ifconfig.py>`__
+ for an example application.
+
+ .. note:: if you're interested in others families (e.g. AF_BLUETOOTH) you can
+ use the more powerful `netifaces <https://pypi.python.org/pypi/netifaces/>`__
+ extension.
+
+ .. note:: you can have more than one address of the same family associated
+ with each interface (that's why dict values are lists).
+
+ .. note:: *netmask*, *broadcast* and *ptp* are not supported on Windows and
+ are set to ``None``.
+
+ *New in 3.0.0*
+
+ *Changed in 3.2.0:* *ptp* field was added.
+
+.. function:: net_if_stats()
+
+ Return information about each NIC (network interface card) installed on the
+ system as a dictionary whose keys are the NIC names and value is a namedtuple
+ with the following fields:
+
+ - **isup**
+ - **duplex**
+ - **speed**
+ - **mtu**
+
+ *isup* is a boolean indicating whether the NIC is up and running, *duplex*
+ can be either :const:`NIC_DUPLEX_FULL`, :const:`NIC_DUPLEX_HALF` or
+ :const:`NIC_DUPLEX_UNKNOWN`, *speed* is the NIC speed expressed in mega bits
+ (MB), if it can't be determined (e.g. 'localhost') it will be set to ``0``,
+ *mtu* is the maximum transmission unit expressed in bytes.
+ See also `examples/ifconfig.py <https://github.com/giampaolo/psutil/blob/master/examples/ifconfig.py>`__
+ for an example application.
+ Example:
+
+ >>> import psutil
+ >>> psutil.net_if_stats()
+ {'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
+ 'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
+
+ *New in 3.0.0*
+
Other system info
-----------------
@@ -498,7 +582,7 @@ Functions
import psutil
def on_terminate(proc):
- print("process {} terminated".format(proc))
+ print("process {} terminated with exit code {}".format(proc, proc.returncode))
procs = [...] # a list of Process instances
for p in procs:
@@ -521,6 +605,18 @@ Exceptions
exists. "name" is the name the process had before disappearing
and gets set only if :meth:`Process.name()` was previosly called.
+.. class:: ZombieProcess(pid, name=None, ppid=None, msg=None)
+
+ This may be raised by :class:`Process` class methods when querying a zombie
+ process on UNIX (Windows doesn't have zombie processes). Depending on the
+ method called the OS may be able to succeed in retrieving the process
+ information or not.
+ Note: this is a subclass of :class:`NoSuchProcess` so if you're not
+ interested in retrieving zombies (e.g. when using :func:`process_iter()`)
+ you can ignore this exception and just catch :class:`NoSuchProcess`.
+
+ *New in 3.0.0*
+
.. class:: AccessDenied(pid=None, name=None, msg=None)
Raised by :class:`Process` class methods when permission to perform an
@@ -616,13 +712,17 @@ Process class
:class:`Process` class's attribute names (e.g. ``['cpu_times', 'name']``)
else all public (read only) attributes are assumed. *ad_value* is the
value which gets assigned to a dict key in case :class:`AccessDenied`
- exception is raised when retrieving that particular process information.
+ or :class:`ZombieProcess` exception is raised when retrieving that
+ particular process information.
>>> import psutil
>>> p = psutil.Process()
>>> p.as_dict(attrs=['pid', 'name', 'username'])
{'username': 'giampaolo', 'pid': 12366, 'name': 'python'}
+ .. versionchanged:: 3.0.0 *ad_value* is used also when incurring into
+ :class:`ZombieProcess` exception, not only :class:`AccessDenied`
+
.. method:: parent()
Utility method which returns the parent process as a :class:`Process`
@@ -646,7 +746,7 @@ Process class
.. method:: uids()
The **real**, **effective** and **saved** user ids of this process as a
- nameduple. This is the same as
+ namedtuple. This is the same as
`os.getresuid() <http://docs.python.org//library/os.html#os.getresuid>`__
but can be used for every process PID.
@@ -655,7 +755,7 @@ Process class
.. method:: gids()
The **real**, **effective** and **saved** group ids of this process as a
- nameduple. This is the same as
+ namedtuple. This is the same as
`os.getresgid() <http://docs.python.org//library/os.html#os.getresgid>`__
but can be used for every process PID.
@@ -682,6 +782,13 @@ Process class
10
>>>
+ Starting from `Python 3.3 <http://bugs.python.org/issue10784>`__ this
+ functionality is also available as
+ `os.getpriority() <http://docs.python.org/3/library/os.html#os.getpriority>`__
+ and
+ `os.setpriority() <http://docs.python.org/3/library/os.html#os.setpriority>`__
+ (UNIX only).
+
On Windows this is available as well by using
`GetPriorityClass <http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx>`__
and `SetPriorityClass <http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx>`__
@@ -692,12 +799,6 @@ Process class
>>> p.nice(psutil.HIGH_PRIORITY_CLASS)
- Starting from `Python 3.3 <http://bugs.python.org/issue10784>`__ this
- same functionality is available as
- `os.getpriority() <http://docs.python.org/3/library/os.html#os.getpriority>`__
- and
- `os.setpriority() <http://docs.python.org/3/library/os.html#os.setpriority>`__.
-
.. method:: ionice(ioclass=None, value=None)
Get or set
@@ -714,7 +815,7 @@ Process class
>>> p = psutil.Process()
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # set
>>> p.ionice() # get
- pionice(ioclass=3, value=0)
+ pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
>>>
On Windows only *ioclass* is used and it can be set to ``2`` (normal),
@@ -722,6 +823,10 @@ Process class
Availability: Linux and Windows > Vista
+ .. versionchanged:: 3.0.0 on >= Python 3.4 the returned ``ioclass``
+ constant is an `enum <https://docs.python.org/3/library/enum.html#module-enum>`__
+ instead of a plain integer.
+
.. method:: rlimit(resource, limits=None)
Get or set process resource limits (see
@@ -761,7 +866,7 @@ Process class
>>> p.io_counters()
pio(read_count=454556, write_count=3456, read_bytes=110592, write_bytes=0)
- Availability: all platforms except OSX
+ Availability: all platforms except OSX and Solaris
.. method:: num_ctx_switches()
@@ -836,7 +941,8 @@ Process class
`CPU affinity <http://www.linuxjournal.com/article/6799?page=0,0>`__.
CPU affinity consists in telling the OS to run a certain process on a
limited set of CPUs only. The number of eligible CPUs can be obtained with
- ``list(range(psutil.cpu_count()))``.
+ ``list(range(psutil.cpu_count()))``. On set raises ``ValueError`` in case
+ an invalid CPU number is specified.
>>> import psutil
>>> psutil.cpu_count()
@@ -911,7 +1017,7 @@ Process class
.. method:: memory_maps(grouped=True)
- Return process's mapped memory regions as a list of nameduples whose
+ Return process's mapped memory regions as a list of namedtuples whose
fields are variable depending on the platform. As such, portable
applications should rely on namedtuple's `path` and `rss` fields only.
This method is useful to obtain a detailed representation of process
@@ -966,15 +1072,31 @@ Process class
the absolute file name and the file descriptor number (on Windows this is
always ``-1``). Example:
- >>> import psutil
- >>> f = open('file.ext', 'w')
- >>> p = psutil.Process()
- >>> p.open_files()
- [popenfile(path='/home/giampaolo/svn/psutil/file.ext', fd=3)]
+ >>> import psutil
+ >>> f = open('file.ext', 'w')
+ >>> p = psutil.Process()
+ >>> p.open_files()
+ [popenfile(path='/home/giampaolo/svn/psutil/file.ext', fd=3)]
+
+ .. warning::
+ on Windows this is not fully reliable as due to some limitations of the
+ Windows API the underlying implementation may hang when retrieving
+ certain file handles.
+ In order to work around that psutil on Windows Vista (and higher) spawns
+ a thread and kills it if it's not responding after 100ms.
+ That implies that on Windows this method is not guaranteed to enumerate
+ all regular file handles (see full discusion
+ `here <https://github.com/giampaolo/psutil/pull/597>`_).
+
+ .. warning::
+ on FreeBSD this method can return files with a 'null' path (see
+ `issue 595 <https://github.com/giampaolo/psutil/pull/595>`_).
+
+ .. versionchanged:: 3.1.0 no longer hangs on Windows.
.. method:: connections(kind="inet")
- Return socket connections opened by process as a list of namedutples.
+ Return socket connections opened by process as a list of namedtuples.
To get system-wide connections use :func:`psutil.net_connections()`.
Every namedtuple provides 6 attributes:
@@ -1040,10 +1162,10 @@ Process class
>>> p.name()
'firefox'
>>> p.connections()
- [pconn(fd=115, family=2, type=1, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
- pconn(fd=117, family=2, type=1, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
- pconn(fd=119, family=2, type=1, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
- pconn(fd=123, family=2, type=1, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
+ [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
+ pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
+ pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
+ pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
.. method:: is_running()
@@ -1061,10 +1183,14 @@ Process class
Send a signal to process (see
`signal module <http://docs.python.org//library/signal.html>`__
constants) pre-emptively checking whether PID has been reused.
- This is the same as ``os.kill(pid, sig)``.
- On Windows only **SIGTERM** is valid and is treated as an alias for
+ On UNIX this is the same as ``os.kill(pid, sig)``.
+ On Windows only **SIGTERM**, **CTRL_C_EVENT** and **CTRL_BREAK_EVENT**
+ signals are supported and **SIGTERM** is treated as an alias for
:meth:`kill()`.
+ *Changed in 3.2.0:* support for CTRL_C_EVENT and CTRL_BREAK_EVENT signals
+ was added.
+
.. method:: suspend()
Suspend process execution with **SIGSTOP** signal pre-emptively checking
@@ -1133,7 +1259,7 @@ Popen class
:meth:`send_signal() <psutil.Process.send_signal()>`,
:meth:`terminate() <psutil.Process.terminate()>` and
:meth:`kill() <psutil.Process.kill()>`
- so that you don't accidentally terminate another process, fixing
+ so that you can't accidentally terminate another process, fixing
http://bugs.python.org/issue6973.
>>> import psutil
@@ -1205,6 +1331,10 @@ Constants
Availability: Windows
+ .. versionchanged:: 3.0.0 on Python >= 3.4 these constants are
+ `enums <https://docs.python.org/3/library/enum.html#module-enum>`__
+ instead of a plain integer.
+
.. _const-ioprio:
.. data:: IOPRIO_CLASS_NONE
IOPRIO_CLASS_RT
@@ -1228,6 +1358,10 @@ Constants
Availability: Linux
+ .. versionchanged:: 3.0.0 on Python >= 3.4 thse constants are
+ `enums <https://docs.python.org/3/library/enum.html#module-enum>`__
+ instead of a plain integer.
+
.. _const-rlimit:
.. data:: RLIMIT_INFINITY
RLIMIT_AS
@@ -1253,3 +1387,31 @@ Constants
`man prlimit <http://linux.die.net/man/2/prlimit>`__ for futher information.
Availability: Linux
+
+.. _const-aflink:
+.. data:: AF_LINK
+
+ Constant which identifies a MAC address associated with a network interface.
+ To be used in conjunction with :func:`psutil.net_if_addrs()`.
+
+ *New in 3.0.0*
+
+.. _const-duplex:
+.. data:: NIC_DUPLEX_FULL
+ NIC_DUPLEX_HALF
+ 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
+ data (files) simultaneously, NIC_DUPLEX_FULL means the NIC can either send or
+ receive data at a time.
+ To be used in conjunction with :func:`psutil.net_if_stats()`.
+
+ *New in 3.0.0*
+
+Development guide
+=================
+
+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>`_.
diff --git a/examples/ifconfig.py b/examples/ifconfig.py
new file mode 100755
index 00000000..1f1ee985
--- /dev/null
+++ b/examples/ifconfig.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+A clone of 'ifconfig' on UNIX.
+
+$ python examples/ifconfig.py
+lo (speed=0MB, duplex=?, mtu=65536, up=yes):
+ IPv4 address : 127.0.0.1
+ broadcast : 127.0.0.1
+ netmask : 255.0.0.0
+ IPv6 address : ::1
+ netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+ MAC address : 00:00:00:00:00:00
+ broadcast : 00:00:00:00:00:00
+
+wlan0 (speed=0MB, duplex=?, mtu=1500, up=yes):
+ IPv4 address : 10.0.3.1
+ broadcast : 10.0.3.255
+ netmask : 255.255.255.0
+ IPv6 address : fe80::3005:adff:fe31:8698
+ netmask : ffff:ffff:ffff:ffff::
+ MAC address : 32:05:ad:31:86:98
+ broadcast : ff:ff:ff:ff:ff:ff
+
+eth0 (speed=100MB, duplex=full, mtu=1500, up=yes):
+ IPv4 address : 192.168.1.2
+ broadcast : 192.168.1.255
+ netmask : 255.255.255.0
+ IPv6 address : fe80::c685:8ff:fe45:641
+ netmask : ffff:ffff:ffff:ffff::
+ MAC address : c4:85:08:45:06:41
+ broadcast : ff:ff:ff:ff:ff:ff
+"""
+
+from __future__ import print_function
+import socket
+
+import psutil
+
+
+af_map = {
+ socket.AF_INET: 'IPv4',
+ socket.AF_INET6: 'IPv6',
+ psutil.AF_LINK: 'MAC',
+}
+
+duplex_map = {
+ psutil.NIC_DUPLEX_FULL: "full",
+ psutil.NIC_DUPLEX_HALF: "half",
+ psutil.NIC_DUPLEX_UNKNOWN: "?",
+}
+
+
+def main():
+ stats = psutil.net_if_stats()
+ for nic, addrs in psutil.net_if_addrs().items():
+ if nic in stats:
+ print("%s (speed=%sMB, duplex=%s, mtu=%s, up=%s):" % (
+ nic, stats[nic].speed, duplex_map[stats[nic].duplex],
+ stats[nic].mtu, "yes" if stats[nic].isup else "no"))
+ else:
+ print("%s:" % (nic))
+ for addr in addrs:
+ print(" %-8s" % af_map.get(addr.family, addr.family), end="")
+ print(" address : %s" % addr.address)
+ if addr.broadcast:
+ print(" broadcast : %s" % addr.broadcast)
+ if addr.netmask:
+ print(" netmask : %s" % addr.netmask)
+ if addr.ptp:
+ print(" p2p : %s" % addr.ptp)
+ print("")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/examples/iotop.py b/examples/iotop.py
index a0986782..16ac7fbf 100755
--- a/examples/iotop.py
+++ b/examples/iotop.py
@@ -30,14 +30,15 @@ PID USER DISK READ DISK WRITE COMMAND
Author: Giampaolo Rodola' <g.rodola@gmail.com>
"""
-import os
+import atexit
+import time
import sys
-import psutil
-if not hasattr(psutil.Process, 'io_counters') or os.name != 'posix':
+try:
+ import curses
+except ImportError:
sys.exit('platform not supported')
-import time
-import curses
-import atexit
+
+import psutil
# --- curses stuff
@@ -116,7 +117,7 @@ def poll(interval):
if not p._cmdline:
p._cmdline = p.name()
p._username = p.username()
- except psutil.NoSuchProcess:
+ except (psutil.NoSuchProcess, psutil.ZombieProcess):
procs.remove(p)
disks_after = psutil.disk_io_counters()
diff --git a/examples/nettop.py b/examples/nettop.py
index 857285cf..7a8343ee 100755
--- a/examples/nettop.py
+++ b/examples/nettop.py
@@ -31,13 +31,13 @@ pkts-sent 0 0
pkts-recv 1214470 0
"""
-import sys
-import os
-if os.name != 'posix':
- sys.exit('platform not supported')
import atexit
-import curses
import time
+import sys
+try:
+ import curses
+except ImportError:
+ sys.exit('platform not supported')
import psutil
diff --git a/examples/process_detail.py b/examples/process_detail.py
index a55fc959..e20371ae 100755
--- a/examples/process_detail.py
+++ b/examples/process_detail.py
@@ -79,13 +79,19 @@ def run(pid):
parent = ''
except psutil.Error:
parent = ''
- started = datetime.datetime.fromtimestamp(
- pinfo['create_time']).strftime('%Y-%m-%d %H:%M')
+ if pinfo['create_time'] != ACCESS_DENIED:
+ started = datetime.datetime.fromtimestamp(
+ pinfo['create_time']).strftime('%Y-%m-%d %H:%M')
+ else:
+ started = ACCESS_DENIED
io = pinfo.get('io_counters', ACCESS_DENIED)
- mem = '%s%% (resident=%s, virtual=%s) ' % (
- round(pinfo['memory_percent'], 1),
- convert_bytes(pinfo['memory_info'].rss),
- convert_bytes(pinfo['memory_info'].vms))
+ if pinfo['memory_info'] != ACCESS_DENIED:
+ mem = '%s%% (resident=%s, virtual=%s) ' % (
+ round(pinfo['memory_percent'], 1),
+ convert_bytes(pinfo['memory_info'].rss),
+ convert_bytes(pinfo['memory_info'].vms))
+ else:
+ mem = ACCESS_DENIED
children = p.children()
print_('pid', pinfo['pid'])
@@ -101,8 +107,7 @@ def run(pid):
print_('gids', 'real=%s, effective=%s, saved=%s' % pinfo['gids'])
if POSIX:
print_('terminal', pinfo['terminal'] or '')
- if hasattr(p, 'getcwd'):
- print_('cwd', pinfo['cwd'])
+ print_('cwd', pinfo['cwd'])
print_('memory', mem)
print_('cpu', '%s%% (user=%s, system=%s)' % (
pinfo['cpu_percent'],
diff --git a/examples/ps.py b/examples/ps.py
index 2b67bd18..2b67bd18 100644..100755
--- a/examples/ps.py
+++ b/examples/ps.py
diff --git a/examples/pstree.py b/examples/pstree.py
index e435f09d..1bf8c9c0 100644..100755
--- a/examples/pstree.py
+++ b/examples/pstree.py
@@ -59,7 +59,7 @@ def main():
for p in psutil.process_iter():
try:
tree[p.ppid()].append(p.pid)
- except psutil.NoSuchProcess:
+ except (psutil.NoSuchProcess, psutil.ZombieProcess):
pass
# on systems supporting PID 0, PID 0's parent is usually 0
if 0 in tree and 0 in tree[0]:
diff --git a/examples/top.py b/examples/top.py
index a305297f..7aebef1d 100755
--- a/examples/top.py
+++ b/examples/top.py
@@ -34,14 +34,15 @@ PID USER NI VIRT RES CPU% MEM% TIME+ NAME
...
"""
+from datetime import datetime, timedelta
+import atexit
import os
+import time
import sys
-if os.name != 'posix':
+try:
+ import curses
+except ImportError:
sys.exit('platform not supported')
-import atexit
-import curses
-import time
-from datetime import datetime, timedelta
import psutil
diff --git a/make.bat b/make.bat
index 4520a989..56cdbfc4 100644
--- a/make.bat
+++ b/make.bat
@@ -13,9 +13,10 @@ rem ...therefore it might not work on your Windows installation.
rem
rem By default C:\Python27\python.exe is used.
rem To compile for a specific Python version run:
+rem set PYTHON=C:\Python34\python.exe & make.bat build
rem
-rem set PYTHON=C:\Python26\python.exe & make.bat build
-rem
+rem To use a different test script:
+rem set PYTHON=C:\Python34\python.exe & set TSCRIPT=foo.py & make.bat test
rem ==========================================================================
if "%PYTHON%" == "" (
@@ -25,8 +26,16 @@ if "%TSCRIPT%" == "" (
set TSCRIPT=test\test_psutil.py
)
-rem Needed to compile using Mingw.
-set PATH=C:\MinGW\bin;%PATH%
+set PYTHON26=C:\Python26\python.exe
+set PYTHON27=C:\Python27\python.exe
+set PYTHON33=C:\Python33\python.exe
+set PYTHON34=C:\Python34\python.exe
+set PYTHON26-64=C:\Python26-64\python.exe
+set PYTHON27-64=C:\Python27-64\python.exe
+set PYTHON33-64=C:\Python33-64\python.exe
+set PYTHON34-64=C:\Python34-64\python.exe
+
+set ALL_PYTHONS=%PYTHON26% %PYTHON27% %PYTHON33% %PYTHON34% %PYTHON26-64% %PYTHON27-64% %PYTHON33-64% %PYTHON34-64%
rem Needed to locate the .pypirc file and upload exes on PYPI.
set HOME=%USERPROFILE%
@@ -37,26 +46,25 @@ if "%1" == "help" (
:help
echo Run `make ^<target^>` where ^<target^> is one of:
echo build compile without installing
- echo build-exes create exe installers in dist directory
- echo build-wheels create wheel installers in dist directory
+ echo build-all build exes + wheels
echo clean clean build files
+ echo flake8 run flake8
echo install compile and install
- echo setup-env install pip, unittest2, wheels for all python versions
+ echo setup-dev-env install pip, pywin32, wheels, etc. for all python versions
echo test run tests
echo test-memleaks run memory leak tests
echo test-process run process related tests
echo test-system run system APIs related tests
echo uninstall uninstall
- echo upload-exes upload exe installers on pypi
- echo upload-wheels upload wheel installers on pypi
+ echo upload-all upload exes + wheels
goto :eof
)
if "%1" == "clean" (
- :clean
for /r %%R in (__pycache__) do if exist %%R (rmdir /S /Q %%R)
for /r %%R in (*.pyc) do if exist %%R (del /s %%R)
for /r %%R in (*.pyd) do if exist %%R (del /s %%R)
+ for /r %%R in (*.obj) do if exist %%R (del /s %%R)
for /r %%R in (*.orig) do if exist %%R (del /s %%R)
for /r %%R in (*.bak) do if exist %%R (del /s %%R)
for /r %%R in (*.rej) do if exist %%R (del /s %%R)
@@ -68,19 +76,25 @@ if "%1" == "clean" (
if "%1" == "build" (
:build
+ "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
%PYTHON% setup.py build
if %errorlevel% neq 0 goto :error
+ rem copies *.pyd files in ./psutil directory in order to allow
+ rem "import psutil" when using the interactive interpreter from
+ rem within this directory.
+ %PYTHON% setup.py build_ext -i
+ if %errorlevel% neq 0 goto :error
goto :eof
)
if "%1" == "install" (
:install
- %PYTHON% setup.py build install
+ call :build
+ %PYTHON% setup.py install
goto :eof
)
if "%1" == "uninstall" (
- :uninstall
for %%A in ("%PYTHON%") do (
set folder=%%~dpA
)
@@ -91,120 +105,98 @@ if "%1" == "uninstall" (
)
if "%1" == "test" (
- :test
call :install
%PYTHON% %TSCRIPT%
goto :eof
)
if "%1" == "test-process" (
- :test
call :install
%PYTHON% -m unittest -v test.test_psutil.TestProcess
goto :eof
)
if "%1" == "test-system" (
- :test
call :install
%PYTHON% -m unittest -v test.test_psutil.TestSystem
goto :eof
)
if "%1" == "test-memleaks" (
- :memtest
call :install
%PYTHON% test\test_memory_leaks.py
goto :eof
)
-if "%1" == "build-exes" (
- :build-exes
- rem "standard" 32 bit versions, using VS 2008 (2.6, 2.7) or VS 2010 (3.3+)
- C:\Python26\python.exe setup.py build bdist_wininst || goto :error
- C:\Python27\python.exe setup.py build bdist_wininst || goto :error
- C:\Python33\python.exe setup.py build bdist_wininst || goto :error
- C:\Python34\python.exe setup.py build bdist_wininst || goto :error
- rem 64 bit versions
- rem Python 2.7 + VS 2008 requires vcvars64.bat to be run first:
- rem http://stackoverflow.com/questions/11072521/
- rem Windows SDK and .NET Framework 3.5 SP1 also need to be installed (sigh)
+if "%1" == "build-all" (
+ :build-all
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
- C:\Python27-64\python.exe setup.py build bdist_wininst || goto :error
- C:\Python33-64\python.exe setup.py build bdist_wininst || goto :error
- C:\Python34-64\python.exe setup.py build bdist_wininst || goto :error
+ for %%P in (%ALL_PYTHONS%) do (
+ @echo ------------------------------------------------
+ @echo building exe for %%P
+ @echo ------------------------------------------------
+ %%P setup.py build bdist_wininst || goto :error
+ @echo ------------------------------------------------
+ @echo building wheel for %%P
+ @echo ------------------------------------------------
+ %%P setup.py build bdist_wheel || goto :error
+ )
echo OK
goto :eof
)
-if "%1" == "upload-exes" (
+if "%1" == "upload-all" (
:upload-exes
- rem "standard" 32 bit versions, using VS 2008 (2.6, 2.7) or VS 2010 (3.3+)
- C:\Python26\python.exe setup.py bdist_wininst upload || goto :error
- C:\Python27\python.exe setup.py bdist_wininst upload || goto :error
- C:\Python33\python.exe setup.py bdist_wininst upload || goto :error
- C:\Python34\python.exe setup.py bdist_wininst upload || goto :error
- rem 64 bit versions
- C:\Python27-64\python.exe setup.py build bdist_wininst upload || goto :error
- C:\Python33-64\python.exe setup.py build bdist_wininst upload || goto :error
- C:\Python34-64\python.exe setup.py build bdist_wininst upload || goto :error
+ "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
+ for %%P in (%ALL_PYTHONS%) do (
+ @echo ------------------------------------------------
+ @echo uploading exe for %%P
+ @echo ------------------------------------------------
+ %%P setup.py build bdist_wininst upload || goto :error
+ @echo ------------------------------------------------
+ @echo uploading wheel for %%P
+ @echo ------------------------------------------------
+ %%P setup.py build bdist_wheel upload || goto :error
+ )
echo OK
goto :eof
)
-if "%1" == "setup-env" (
+if "%1" == "setup-dev-env" (
:setup-env
- C:\python27\python.exe -c "import urllib2; url = urllib2.urlopen('https://raw.github.com/pypa/pip/master/contrib/get-pip.py'); data = url.read(); f = open('get-pip.py', 'w'); f.write(data)"
- C:\python26\python.exe get-pip.py & C:\python26\scripts\pip install unittest2 wheel --upgrade
- C:\python27\python.exe get-pip.py & C:\python27\scripts\pip install wheel --upgrade
- C:\python33\python.exe get-pip.py & C:\python33\scripts\pip install wheel --upgrade
- C:\python34\scripts\easy_install.exe wheel
- rem 64-bit versions
- C:\python27-64\python.exe get-pip.py & C:\python27-64\scripts\pip install wheel --upgrade
- C:\python33-64\python.exe get-pip.py & C:\python33-64\scripts\pip install wheel --upgrade
- C:\python34-64\scripts\easy_install.exe wheel
- goto :eof
-)
-
-if "%1" == "build-wheels" (
- :build-wheels
- C:\Python26\python.exe setup.py build bdist_wheel || goto :error
- C:\Python27\python.exe setup.py build bdist_wheel || goto :error
- C:\Python33\python.exe setup.py build bdist_wheel || goto :error
- C:\Python34\python.exe setup.py build bdist_wheel || goto :error
- rem 64 bit versions
- rem Python 2.7 + VS 2008 requires vcvars64.bat to be run first:
- rem http://stackoverflow.com/questions/11072521/
- rem Windows SDK and .NET Framework 3.5 SP1 also need to be installed (sigh)
- "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
- C:\Python27-64\python.exe setup.py build bdist_wheel || goto :error
- C:\Python33-64\python.exe setup.py build bdist_wheel || goto :error
- C:\Python34-64\python.exe setup.py build bdist_wheel || goto :error
- echo OK
+ @echo ------------------------------------------------
+ @echo downloading pip installer
+ @echo ------------------------------------------------
+ C:\python27\python.exe -c "import urllib2; r = urllib2.urlopen('https://raw.github.com/pypa/pip/master/contrib/get-pip.py'); open('get-pip.py', 'wb').write(r.read())"
+ for %%P in (%ALL_PYTHONS%) do (
+ @echo ------------------------------------------------
+ @echo installing pip for %%P
+ @echo ------------------------------------------------
+ %%P get-pip.py
+ )
+ for %%P in (%ALL_PYTHONS%) do (
+ @echo ------------------------------------------------
+ @echo installing deps for %%P
+ @echo ------------------------------------------------
+ rem mandatory / for unittests
+ %%P -m pip install unittest2 ipaddress mock wmi wheel pypiwin32 --upgrade
+ rem nice to have
+ %%P -m pip install ipdb pep8 pyflakes flake8 --upgrade
+ )
goto :eof
)
-if "%1" == "upload-wheels" (
- :build-wheels
- C:\Python26\python.exe setup.py build bdist_wheel upload || goto :error
- C:\Python27\python.exe setup.py build bdist_wheel upload || goto :error
- C:\Python33\python.exe setup.py build bdist_wheel upload || goto :error
- C:\Python34\python.exe setup.py build bdist_wheel upload || goto :error
- rem 64 bit versions
- rem Python 2.7 + VS 2008 requires vcvars64.bat to be run first:
- rem http://stackoverflow.com/questions/11072521/
- rem Windows SDK and .NET Framework 3.5 SP1 also need to be installed (sigh)
- "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
- C:\Python27-64\python.exe setup.py build bdist_wheel upload || goto :error
- C:\Python33-64\python.exe setup.py build bdist_wheel upload || goto :error
- C:\Python34-64\python.exe setup.py build bdist_wheel upload || goto :error
- echo OK
+if "%1" == "flake8" (
+ :flake8
+ %PYTHON% -c "from flake8.main import main; main()"
goto :eof
)
goto :help
:error
- echo last command exited with error code %errorlevel%
- exit /b %errorlevel%
+ @echo ------------------------------------------------
+ @echo last command exited with error code %errorlevel%
+ @echo ------------------------------------------------
+ @exit /b %errorlevel%
goto :eof
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 8d5ba5d6..4c71d02e 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -11,32 +11,6 @@ in Python.
from __future__ import division
-__author__ = "Giampaolo Rodola'"
-__version__ = "2.2.0"
-version_info = tuple([int(num) for num in __version__.split('.')])
-
-__all__ = [
- # exceptions
- "Error", "NoSuchProcess", "AccessDenied", "TimeoutExpired",
- # constants
- "version_info", "__version__",
- "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
- "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
- "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED",
- "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",
- # classes
- "Process", "Popen",
- # functions
- "pid_exists", "pids", "process_iter", "wait_procs", # proc
- "virtual_memory", "swap_memory", # memory
- "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu
- "net_io_counters", "net_connections", # network
- "disk_io_counters", "disk_partitions", "disk_usage", # disk
- "users", "boot_time", # others
-]
-
import collections
import errno
import functools
@@ -45,73 +19,70 @@ import signal
import subprocess
import sys
import time
-import warnings
try:
import pwd
except ImportError:
pwd = None
-from psutil._common import memoize
-from psutil._compat import callable, long
-from psutil._compat import PY3 as _PY3
-from psutil._common import (deprecated_method as _deprecated_method,
- deprecated as _deprecated,
- sdiskio as _nt_sys_diskio,
- snetio as _nt_sys_netio)
-
-from psutil._common import (STATUS_RUNNING, # NOQA
- STATUS_SLEEPING,
- STATUS_DISK_SLEEP,
- STATUS_STOPPED,
- STATUS_TRACING_STOP,
- STATUS_ZOMBIE,
- STATUS_DEAD,
- STATUS_WAKING,
- STATUS_LOCKED,
- STATUS_IDLE, # bsd
- STATUS_WAITING, # bsd
- STATUS_LOCKED) # bsd
-
-from psutil._common import (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)
+from . import _common
+from ._common import memoize
+from ._compat import callable, long
+from ._compat import PY3 as _PY3
+
+from ._common import (STATUS_RUNNING, # NOQA
+ STATUS_SLEEPING,
+ STATUS_DISK_SLEEP,
+ STATUS_STOPPED,
+ STATUS_TRACING_STOP,
+ STATUS_ZOMBIE,
+ STATUS_DEAD,
+ STATUS_WAKING,
+ STATUS_LOCKED,
+ STATUS_IDLE, # bsd
+ STATUS_WAITING) # bsd
+
+from ._common import (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)
+
+from ._common import (NIC_DUPLEX_FULL, # NOQA
+ NIC_DUPLEX_HALF,
+ NIC_DUPLEX_UNKNOWN)
if sys.platform.startswith("linux"):
- import psutil._pslinux as _psplatform
- from psutil._pslinux import (phymem_buffers, # NOQA
- cached_phymem)
-
- from psutil._pslinux import (IOPRIO_CLASS_NONE, # NOQA
- IOPRIO_CLASS_RT,
- IOPRIO_CLASS_BE,
- IOPRIO_CLASS_IDLE)
+ from . import _pslinux as _psplatform
+
+ from ._pslinux import (IOPRIO_CLASS_NONE, # NOQA
+ IOPRIO_CLASS_RT,
+ IOPRIO_CLASS_BE,
+ IOPRIO_CLASS_IDLE)
# Linux >= 2.6.36
if _psplatform.HAS_PRLIMIT:
- from _psutil_linux import (RLIM_INFINITY, # NOQA
- RLIMIT_AS,
- RLIMIT_CORE,
- RLIMIT_CPU,
- RLIMIT_DATA,
- RLIMIT_FSIZE,
- RLIMIT_LOCKS,
- RLIMIT_MEMLOCK,
- RLIMIT_NOFILE,
- RLIMIT_NPROC,
- RLIMIT_RSS,
- RLIMIT_STACK)
+ from ._psutil_linux import (RLIM_INFINITY, # NOQA
+ RLIMIT_AS,
+ RLIMIT_CORE,
+ RLIMIT_CPU,
+ RLIMIT_DATA,
+ RLIMIT_FSIZE,
+ RLIMIT_LOCKS,
+ RLIMIT_MEMLOCK,
+ RLIMIT_NOFILE,
+ RLIMIT_NPROC,
+ RLIMIT_RSS,
+ RLIMIT_STACK)
# Kinda ugly but considerably faster than using hasattr() and
# setattr() against the module object (we are at import time:
# speed matters).
- import _psutil_linux
+ from . import _psutil_linux
try:
RLIMIT_MSGQUEUE = _psutil_linux.RLIMIT_MSGQUEUE
except AttributeError:
@@ -135,32 +106,60 @@ if sys.platform.startswith("linux"):
del _psutil_linux
elif sys.platform.startswith("win32"):
- import psutil._pswindows as _psplatform
- from _psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS, # NOQA
- BELOW_NORMAL_PRIORITY_CLASS,
- HIGH_PRIORITY_CLASS,
- IDLE_PRIORITY_CLASS,
- NORMAL_PRIORITY_CLASS,
- REALTIME_PRIORITY_CLASS)
- from psutil._pswindows import CONN_DELETE_TCB # NOQA
+ from . import _pswindows as _psplatform
+ from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS, # NOQA
+ BELOW_NORMAL_PRIORITY_CLASS,
+ HIGH_PRIORITY_CLASS,
+ IDLE_PRIORITY_CLASS,
+ NORMAL_PRIORITY_CLASS,
+ REALTIME_PRIORITY_CLASS)
+ from ._pswindows import CONN_DELETE_TCB # NOQA
elif sys.platform.startswith("darwin"):
- import psutil._psosx as _psplatform
+ from . import _psosx as _psplatform
elif sys.platform.startswith("freebsd"):
- import psutil._psbsd as _psplatform
+ from . import _psbsd as _psplatform
elif sys.platform.startswith("sunos"):
- import psutil._pssunos as _psplatform
- from psutil._pssunos import (CONN_IDLE, # NOQA
- CONN_BOUND)
+ from . import _pssunos as _psplatform
+ from ._pssunos import (CONN_IDLE, # NOQA
+ CONN_BOUND)
-else:
+else: # pragma: no cover
raise NotImplementedError('platform %s is not supported' % sys.platform)
-__all__.extend(_psplatform.__extra__all__)
-
+__all__ = [
+ # exceptions
+ "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied",
+ "TimeoutExpired",
+ # constants
+ "version_info", "__version__",
+ "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
+ "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
+ "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED",
+ "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",
+ "AF_LINK",
+ "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN",
+ # classes
+ "Process", "Popen",
+ # functions
+ "pid_exists", "pids", "process_iter", "wait_procs", # proc
+ "virtual_memory", "swap_memory", # memory
+ "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu
+ "net_io_counters", "net_connections", "net_if_addrs", # network
+ "net_if_stats",
+ "disk_io_counters", "disk_partitions", "disk_usage", # disk
+ "users", "boot_time", # others
+]
+__all__.extend(_psplatform.__extra__all__)
+__author__ = "Giampaolo Rodola'"
+__version__ = "3.2.1"
+version_info = tuple([int(num) for num in __version__.split('.')])
+AF_LINK = _psplatform.AF_LINK
_TOTAL_PHYMEM = None
_POSIX = os.name == 'posix'
_WINDOWS = os.name == 'nt'
@@ -190,14 +189,24 @@ class Error(Exception):
from this one.
"""
+ def __init__(self, msg=""):
+ self.msg = msg
+
+ def __repr__(self):
+ ret = "%s.%s %s" % (self.__class__.__module__,
+ self.__class__.__name__, self.msg)
+ return ret.strip()
+
+ __str__ = __repr__
+
class NoSuchProcess(Error):
"""Exception raised when a process with a certain PID doesn't
- or no longer exists (zombie).
+ or no longer exists.
"""
def __init__(self, pid, name=None, msg=None):
- Error.__init__(self)
+ Error.__init__(self, msg)
self.pid = pid
self.name = name
self.msg = msg
@@ -208,15 +217,37 @@ class NoSuchProcess(Error):
details = "(pid=%s)" % self.pid
self.msg = "process no longer exists " + details
- def __str__(self):
- return self.msg
+
+class ZombieProcess(NoSuchProcess):
+ """Exception raised when querying a zombie process. This is
+ raised on OSX, BSD and Solaris only, and not always: depending
+ on the query the OS may be able to succeed anyway.
+ On Linux all zombie processes are querable (hence this is never
+ raised). Windows doesn't have zombie processes.
+ """
+
+ def __init__(self, pid, name=None, ppid=None, msg=None):
+ Error.__init__(self, msg)
+ self.pid = pid
+ self.ppid = ppid
+ self.name = name
+ self.msg = msg
+ if msg is None:
+ if name and ppid:
+ details = "(pid=%s, name=%s, ppid=%s)" % (
+ self.pid, repr(self.name), self.ppid)
+ elif name:
+ details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
+ else:
+ details = "(pid=%s)" % self.pid
+ self.msg = "process still exists but it's a zombie " + details
class AccessDenied(Error):
"""Exception raised when permission to perform an action is denied."""
def __init__(self, pid=None, name=None, msg=None):
- Error.__init__(self)
+ Error.__init__(self, msg)
self.pid = pid
self.name = name
self.msg = msg
@@ -228,9 +259,6 @@ class AccessDenied(Error):
else:
self.msg = ""
- def __str__(self):
- return self.msg
-
class TimeoutExpired(Error):
"""Raised on Process.wait(timeout) if timeout expires and process
@@ -238,21 +266,19 @@ class TimeoutExpired(Error):
"""
def __init__(self, seconds, pid=None, name=None):
- Error.__init__(self)
+ Error.__init__(self, "timeout after %s seconds" % seconds)
self.seconds = seconds
self.pid = pid
self.name = name
- self.msg = "timeout after %s seconds" % seconds
if (pid is not None) and (name is not None):
self.msg += " (pid=%s, name=%s)" % (pid, repr(name))
elif (pid is not None):
self.msg += " (pid=%s)" % self.pid
- def __str__(self):
- return self.msg
# push exception classes into platform specific module namespace
_psplatform.NoSuchProcess = NoSuchProcess
+_psplatform.ZombieProcess = ZombieProcess
_psplatform.AccessDenied = AccessDenied
_psplatform.TimeoutExpired = TimeoutExpired
@@ -261,6 +287,7 @@ _psplatform.TimeoutExpired = TimeoutExpired
# --- Process class
# =====================================================================
+
def _assert_pid_not_reused(fun):
"""Decorator which raises NoSuchProcess in case a process is no
longer running or its PID has been reused.
@@ -339,6 +366,11 @@ class Process(object):
# process creation time on all platforms even as a
# limited user
pass
+ except ZombieProcess:
+ # Let's consider a zombie process as legitimate as
+ # tehcnically it's still alive (it can be queried,
+ # although not always, and it's returned by pids()).
+ pass
except NoSuchProcess:
if not _ignore_nsp:
msg = 'no process found with pid %s' % pid
@@ -355,6 +387,8 @@ class Process(object):
try:
pid = self.pid
name = repr(self.name())
+ except ZombieProcess:
+ details = "(pid=%s (zombie))" % self.pid
except NoSuchProcess:
details = "(pid=%s (terminated))" % self.pid
except AccessDenied:
@@ -394,32 +428,17 @@ class Process(object):
only) attributes are assumed.
'ad_value' is the value which gets assigned in case
- AccessDenied exception is raised when retrieving that
- particular process information.
+ AccessDenied or ZombieProcess exception is raised when
+ retrieving that particular process information.
"""
excluded_names = set(
['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
'is_running', 'as_dict', 'parent', 'children', 'rlimit'])
retdict = dict()
- ls = set(attrs or [x for x in dir(self) if not x.startswith('get')])
+ ls = set(attrs or [x for x in dir(self)])
for name in ls:
if name.startswith('_'):
continue
- if name.startswith('set_'):
- continue
- if name.startswith('get_'):
- msg = "%s() is deprecated; use %s() instead" % (name, name[4:])
- warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
- name = name[4:]
- if name in ls:
- continue
- if name == 'getcwd':
- msg = "getcwd() is deprecated; use cwd() instead"
- warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
- name = 'cwd'
- if name in ls:
- continue
-
if name in excluded_names:
continue
try:
@@ -428,7 +447,7 @@ class Process(object):
ret = attr()
else:
ret = attr
- except AccessDenied:
+ except (AccessDenied, ZombieProcess):
ret = ad_value
except NotImplementedError:
# in case of not implemented functionality (may happen
@@ -447,9 +466,10 @@ class Process(object):
"""
ppid = self.ppid()
if ppid is not None:
+ ctime = self.create_time()
try:
parent = Process(ppid)
- if parent.create_time() <= self.create_time():
+ if parent.create_time() <= ctime:
return parent
# ...else ppid has been reused by another process
except NoSuchProcess:
@@ -465,8 +485,8 @@ class Process(object):
try:
# Checking if PID is alive is not enough as the PID might
# have been reused by another process: we also want to
- # check process identity.
- # Process identity / uniqueness over time is greanted by
+ # verify process identity.
+ # Process identity / uniqueness over time is guaranteed by
# (PID + creation time) and that is verified in __eq__.
return self == Process(self.pid)
except NoSuchProcess:
@@ -494,8 +514,7 @@ class Process(object):
if _POSIX:
return self._proc.ppid()
else:
- if self._ppid is None:
- self._ppid = self._proc.ppid()
+ self._ppid = self._ppid or self._proc.ppid()
return self._ppid
def name(self):
@@ -534,9 +553,9 @@ class Process(object):
# Attempt to guess only in case of an absolute path.
# It is not safe otherwise as the process might have
# changed cwd.
- if (os.path.isabs(exe)
- and os.path.isfile(exe)
- and os.access(exe, os.X_OK)):
+ if (os.path.isabs(exe) and
+ os.path.isfile(exe) and
+ os.access(exe, os.X_OK)):
return exe
if isinstance(fallback, AccessDenied):
raise fallback
@@ -565,7 +584,10 @@ class Process(object):
def status(self):
"""The process current status as a STATUS_* constant."""
- return self._proc.status()
+ try:
+ return self._proc.status()
+ except ZombieProcess:
+ return STATUS_ZOMBIE
def username(self):
"""The name of the user that owns the process.
@@ -662,7 +684,7 @@ class Process(object):
"""
if ioclass is None:
if value is not None:
- raise ValueError("'ioclass' must be specified")
+ raise ValueError("'ioclass' argument must be specified")
return self._proc.ionice_get()
else:
return self._proc.ionice_set(ioclass, value)
@@ -694,10 +716,13 @@ class Process(object):
want to set the affinity (e.g. [0, 1]).
(Windows, Linux and BSD only).
"""
+ # Automatically remove duplicates both on get and
+ # set (for get it's not really necessary, it's
+ # just for extra safety).
if cpus is None:
- return self._proc.cpu_affinity_get()
+ return list(set(self._proc.cpu_affinity_get()))
else:
- self._proc.cpu_affinity_set(cpus)
+ self._proc.cpu_affinity_set(list(set(cpus)))
if _WINDOWS:
@@ -769,7 +794,7 @@ class Process(object):
# (self) it means child's PID has been reused
if self.create_time() <= p.create_time():
ret.append(p)
- except NoSuchProcess:
+ except (NoSuchProcess, ZombieProcess):
pass
else:
# Windows only (faster)
@@ -781,7 +806,7 @@ class Process(object):
# (self) it means child's PID has been reused
if self.create_time() <= child.create_time():
ret.append(child)
- except NoSuchProcess:
+ except (NoSuchProcess, ZombieProcess):
pass
else:
# construct a dict where 'values' are all the processes
@@ -791,14 +816,14 @@ class Process(object):
for p in process_iter():
try:
table[p.ppid()].append(p)
- except NoSuchProcess:
+ except (NoSuchProcess, ZombieProcess):
pass
else:
for pid, ppid in ppid_map.items():
try:
p = Process(pid)
table[ppid].append(p)
- except NoSuchProcess:
+ except (NoSuchProcess, ZombieProcess):
pass
# At this point we have a mapping table where table[self.pid]
# are the current process' children.
@@ -811,7 +836,7 @@ class Process(object):
# if child happens to be older than its parent
# (self) it means child's PID has been reused
intime = self.create_time() <= child.create_time()
- except NoSuchProcess:
+ except (NoSuchProcess, ZombieProcess):
pass
else:
if intime:
@@ -850,9 +875,11 @@ class Process(object):
blocking = interval is not None and interval > 0.0
num_cpus = cpu_count()
if _POSIX:
- timer = lambda: _timer() * num_cpus
+ def timer():
+ return _timer() * num_cpus
else:
- timer = lambda: sum(cpu_times())
+ def timer():
+ return sum(cpu_times())
if blocking:
st1 = timer()
pt1 = self._proc.cpu_times()
@@ -927,7 +954,7 @@ class Process(object):
return 0.0
def memory_maps(self, grouped=True):
- """Return process' mapped memory regions as a list of nameduples
+ """Return process' mapped memory regions as a list of namedtuples
whose fields are variable depending on the platform.
If 'grouped' is True the mapped regions with the same 'path'
@@ -983,17 +1010,19 @@ class Process(object):
if _POSIX:
def _send_signal(self, sig):
- # XXX: according to "man 2 kill" PID 0 has a special
- # meaning as it refers to <<every process in the process
- # group of the calling process>>, so should we prevent
- # it here?
+ if self.pid == 0:
+ # see "man 2 kill"
+ raise ValueError(
+ "preventing sending signal to process with PID 0 as it "
+ "would affect every process in the process group of the "
+ "calling process (os.getpid()) instead of PID 0")
try:
os.kill(self.pid, sig)
except OSError as err:
if err.errno == errno.ESRCH:
self._gone = True
raise NoSuchProcess(self.pid, self._name)
- if err.errno == errno.EPERM:
+ if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._name)
raise
@@ -1009,8 +1038,14 @@ class Process(object):
else:
if sig == signal.SIGTERM:
self._proc.kill()
+ # py >= 2.7
+ elif sig in (getattr(signal, "CTRL_C_EVENT", object()),
+ getattr(signal, "CTRL_BREAK_EVENT", object())):
+ self._proc.send_signal(sig)
else:
- raise ValueError("only SIGTERM is supported on Windows")
+ raise ValueError(
+ "only SIGTERM, CTRL_C_EVENT and CTRL_BREAK_EVENT signals "
+ "are supported on Windows")
@_assert_pid_not_reused
def suspend(self):
@@ -1071,119 +1106,12 @@ class Process(object):
raise ValueError("timeout must be a positive integer")
return self._proc.wait(timeout)
- # --- deprecated APIs
-
- _locals = set(locals())
-
- @_deprecated_method(replacement='children')
- def get_children(self):
- pass
-
- @_deprecated_method(replacement='connections')
- def get_connections(self):
- pass
-
- if "cpu_affinity" in _locals:
- @_deprecated_method(replacement='cpu_affinity')
- def get_cpu_affinity(self):
- pass
-
- @_deprecated_method(replacement='cpu_affinity')
- def set_cpu_affinity(self, cpus):
- pass
-
- @_deprecated_method(replacement='cpu_percent')
- def get_cpu_percent(self):
- pass
-
- @_deprecated_method(replacement='cpu_times')
- def get_cpu_times(self):
- pass
-
- @_deprecated_method(replacement='cwd')
- def getcwd(self):
- pass
-
- @_deprecated_method(replacement='memory_info_ex')
- def get_ext_memory_info(self):
- pass
-
- if "io_counters" in _locals:
- @_deprecated_method(replacement='io_counters')
- def get_io_counters(self):
- pass
-
- if "ionice" in _locals:
- @_deprecated_method(replacement='ionice')
- def get_ionice(self):
- pass
-
- @_deprecated_method(replacement='ionice')
- def set_ionice(self, ioclass, value=None):
- pass
-
- @_deprecated_method(replacement='memory_info')
- def get_memory_info(self):
- pass
-
- @_deprecated_method(replacement='memory_maps')
- def get_memory_maps(self):
- pass
-
- @_deprecated_method(replacement='memory_percent')
- def get_memory_percent(self):
- pass
-
- @_deprecated_method(replacement='nice')
- def get_nice(self):
- pass
-
- @_deprecated_method(replacement='num_ctx_switches')
- def get_num_ctx_switches(self):
- pass
-
- if 'num_fds' in _locals:
- @_deprecated_method(replacement='num_fds')
- def get_num_fds(self):
- pass
-
- if 'num_handles' in _locals:
- @_deprecated_method(replacement='num_handles')
- def get_num_handles(self):
- pass
-
- @_deprecated_method(replacement='num_threads')
- def get_num_threads(self):
- pass
-
- @_deprecated_method(replacement='open_files')
- def get_open_files(self):
- pass
-
- if "rlimit" in _locals:
- @_deprecated_method(replacement='rlimit')
- def get_rlimit(self):
- pass
-
- @_deprecated_method(replacement='rlimit')
- def set_rlimit(self, resource, limits):
- pass
-
- @_deprecated_method(replacement='threads')
- def get_threads(self):
- pass
-
- @_deprecated_method(replacement='nice')
- def set_nice(self, value):
- pass
-
- del _locals
-
# =====================================================================
# --- Popen class
# =====================================================================
+
class Popen(Process):
"""A more convenient interface to stdlib subprocess module.
It starts a sub process and deals with it exactly as when using
@@ -1251,6 +1179,7 @@ class Popen(Process):
# --- system processes related functions
# =====================================================================
+
def pids():
"""Return a list of current running PIDs."""
return _psplatform.pids()
@@ -1324,7 +1253,10 @@ def process_iter():
# Process creation time can't be determined hence there's
# no way to tell whether the pid of the cached process
# has been reused. Just return the cached version.
- yield proc
+ if proc is None and pid in _pmap:
+ yield _pmap[pid]
+ else:
+ raise
def wait_procs(procs, timeout=None, callback=None):
@@ -1417,13 +1349,14 @@ def wait_procs(procs, timeout=None, callback=None):
# --- CPU related functions
# =====================================================================
+
@memoize
def cpu_count(logical=True):
"""Return the number of logical CPUs in the system (same as
os.cpu_count() in Python 3.4).
If logical is False return the number of physical cores only
- (hyper thread CPUs are excluded).
+ (e.g. hyper thread CPUs are excluded).
Return None if undetermined.
@@ -1453,7 +1386,7 @@ def cpu_times(percpu=False):
- guest (Linux >= 2.6.24)
- guest_nice (Linux >= 3.2.0)
- When percpu is True return a list of nameduples for each CPU.
+ When percpu is True return a list of namedtuples for each CPU.
First element of the list refers to first CPU, second element
to second CPU and so on.
The order of the list is consistent across calls.
@@ -1580,23 +1513,20 @@ def cpu_times_percent(interval=None, percpu=False):
except ZeroDivisionError:
field_perc = 0.0
field_perc = round(field_perc, 1)
- if _WINDOWS:
- # XXX
- # Work around:
- # https://github.com/giampaolo/psutil/issues/392
- # CPU times are always supposed to increase over time
- # or at least remain the same and that's because time
- # cannot go backwards.
- # Surprisingly sometimes this might not be the case on
- # Windows where 'system' CPU time can be smaller
- # compared to the previous call, resulting in corrupted
- # percentages (< 0 or > 100).
- # I really don't know what to do about that except
- # forcing the value to 0 or 100.
- if field_perc > 100.0:
- field_perc = 100.0
- elif field_perc < 0.0:
- field_perc = 0.0
+ # CPU times are always supposed to increase over time
+ # or at least remain the same and that's because time
+ # cannot go backwards.
+ # Surprisingly sometimes this might not be the case (at
+ # least on Windows and Linux), see:
+ # https://github.com/giampaolo/psutil/issues/392
+ # https://github.com/giampaolo/psutil/issues/645
+ # I really don't know what to do about that except
+ # forcing the value to 0 or 100.
+ if field_perc > 100.0:
+ field_perc = 100.0
+ # `<=` because `-0.0 == 0.0` evaluates to True
+ elif field_perc <= 0.0:
+ field_perc = 0.0
nums.append(field_perc)
return _psplatform.scputimes(*nums)
@@ -1627,6 +1557,7 @@ def cpu_times_percent(interval=None, percpu=False):
# --- system memory related functions
# =====================================================================
+
def virtual_memory():
"""Return statistics about system memory usage as a namedtuple
including the following fields, expressed in bytes:
@@ -1707,6 +1638,7 @@ def swap_memory():
# --- disks/paritions related functions
# =====================================================================
+
def disk_usage(path):
"""Return disk usage statistics about the given path as a namedtuple
including total, used and free space expressed in bytes plus the
@@ -1740,7 +1672,7 @@ def disk_io_counters(perdisk=False):
If perdisk is True return the same information for every
physical disk installed on the system as a dictionary
- with partition names as the keys and the namedutuple
+ with partition names as the keys and the namedtuple
described above as the values.
On recent Windows versions 'diskperf -y' command may need to be
@@ -1751,16 +1683,17 @@ def disk_io_counters(perdisk=False):
raise RuntimeError("couldn't find any physical disk")
if perdisk:
for disk, fields in rawdict.items():
- rawdict[disk] = _nt_sys_diskio(*fields)
+ rawdict[disk] = _common.sdiskio(*fields)
return rawdict
else:
- return _nt_sys_diskio(*[sum(x) for x in zip(*rawdict.values())])
+ return _common.sdiskio(*[sum(x) for x in zip(*rawdict.values())])
# =====================================================================
# --- network related functions
# =====================================================================
+
def net_io_counters(pernic=False):
"""Return network I/O statistics as a namedtuple including
the following fields:
@@ -1785,10 +1718,10 @@ def net_io_counters(pernic=False):
raise RuntimeError("couldn't find any network interface")
if pernic:
for nic, fields in rawdict.items():
- rawdict[nic] = _nt_sys_netio(*fields)
+ rawdict[nic] = _common.snetio(*fields)
return rawdict
else:
- return _nt_sys_netio(*[sum(x) for x in zip(*rawdict.values())])
+ return _common.snetio(*[sum(x) for x in zip(*rawdict.values())])
def net_connections(kind='inet'):
@@ -1811,19 +1744,80 @@ def net_connections(kind='inet'):
udp6 UDP over IPv6
unix UNIX socket (both UDP and TCP protocols)
all the sum of all the possible families and protocols
+
+ On OSX this function requires root privileges.
"""
return _psplatform.net_connections(kind)
+def net_if_addrs():
+ """Return the addresses associated to each NIC (network interface
+ card) installed on the system as a dictionary whose keys are the
+ NIC names and value is a list of namedtuples for each address
+ assigned to the NIC. Each namedtuple includes 5 fields:
+
+ - family
+ - address
+ - netmask
+ - broadcast
+ - ptp
+
+ 'family' can be either socket.AF_INET, socket.AF_INET6 or
+ psutil.AF_LINK, which refers to a MAC address.
+ 'address' is the primary address and it is always set.
+ 'netmask' and 'broadcast' and 'ptp' may be None.
+ 'ptp' stands for "point to point" and references the destination
+ address on a point to point interface (tipically a VPN).
+ 'broadcast' and 'ptp' are mutually exclusive.
+
+ Note: you can have more than one address of the same family
+ associated with each interface.
+ """
+ has_enums = sys.version_info >= (3, 4)
+ if has_enums:
+ import socket
+ rawlist = _psplatform.net_if_addrs()
+ rawlist.sort(key=lambda x: x[1]) # sort by family
+ ret = collections.defaultdict(list)
+ for name, fam, addr, mask, broadcast, ptp in rawlist:
+ if has_enums:
+ try:
+ fam = socket.AddressFamily(fam)
+ except ValueError:
+ if os.name == 'nt' and fam == -1:
+ fam = _psplatform.AF_LINK
+ elif (hasattr(_psplatform, "AF_LINK") and
+ _psplatform.AF_LINK == fam):
+ # Linux defines AF_LINK as an alias for AF_PACKET.
+ # We re-set the family here so that repr(family)
+ # will show AF_LINK rather than AF_PACKET
+ fam = _psplatform.AF_LINK
+ ret[name].append(_common.snic(fam, addr, mask, broadcast, ptp))
+ return dict(ret)
+
+
+def net_if_stats():
+ """Return information about each NIC (network interface card)
+ installed on the system as a dictionary whose keys are the
+ NIC names and value is a namedtuple with the following fields:
+
+ - isup: whether the interface is up (bool)
+ - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or
+ NIC_DUPLEX_UNKNOWN
+ - speed: the NIC speed expressed in mega bits (MB); if it can't
+ be determined (e.g. 'localhost') it will be set to 0.
+ - mtu: the maximum transmission unit expressed in bytes.
+ """
+ return _psplatform.net_if_stats()
+
+
# =====================================================================
# --- other system related functions
# =====================================================================
def boot_time():
- """Return the system boot time expressed in seconds since the epoch.
- This is also available as psutil.BOOT_TIME.
- """
+ """Return the system boot time expressed in seconds since the epoch."""
# Note: we are not caching this because it is subject to
# system clock updates.
return _psplatform.boot_time()
@@ -1842,70 +1836,7 @@ def users():
return _psplatform.users()
-# =====================================================================
-# --- deprecated functions
-# =====================================================================
-
-@_deprecated(replacement="psutil.pids()")
-def get_pid_list():
- return pids()
-
-
-@_deprecated(replacement="list(process_iter())")
-def get_process_list():
- return list(process_iter())
-
-
-@_deprecated(replacement="psutil.users()")
-def get_users():
- return users()
-
-
-@_deprecated(replacement="psutil.virtual_memory()")
-def phymem_usage():
- """Return the amount of total, used and free physical memory
- on the system in bytes plus the percentage usage.
- Deprecated; use psutil.virtual_memory() instead.
- """
- return virtual_memory()
-
-
-@_deprecated(replacement="psutil.swap_memory()")
-def virtmem_usage():
- return swap_memory()
-
-
-@_deprecated(replacement="psutil.phymem_usage().free")
-def avail_phymem():
- return phymem_usage().free
-
-
-@_deprecated(replacement="psutil.phymem_usage().used")
-def used_phymem():
- return phymem_usage().used
-
-
-@_deprecated(replacement="psutil.virtmem_usage().total")
-def total_virtmem():
- return virtmem_usage().total
-
-
-@_deprecated(replacement="psutil.virtmem_usage().used")
-def used_virtmem():
- return virtmem_usage().used
-
-
-@_deprecated(replacement="psutil.virtmem_usage().free")
-def avail_virtmem():
- return virtmem_usage().free
-
-
-@_deprecated(replacement="psutil.net_io_counters()")
-def network_io_counters(pernic=False):
- return net_io_counters(pernic)
-
-
-def test():
+def test(): # pragma: no cover
"""List info of all currently running processes emulating ps aux
output.
"""
@@ -1938,14 +1869,6 @@ def test():
time.localtime(sum(pinfo['cpu_times'])))
try:
user = p.username()
- except KeyError:
- if _POSIX:
- if pinfo['uids']:
- user = str(pinfo['uids'].real)
- else:
- user = ''
- else:
- raise
except Error:
user = ''
if _WINDOWS and '\\' in user:
@@ -1969,44 +1892,7 @@ def test():
pinfo['name'].strip() or '?'))
-def _replace_module():
- """Dirty hack to replace the module object in order to access
- deprecated module constants, see:
- http://www.dr-josiah.com/2013/12/properties-on-python-modules.html
- """
- class ModuleWrapper(object):
-
- def __repr__(self):
- return repr(self._module)
- __str__ = __repr__
-
- @property
- def NUM_CPUS(self):
- msg = "NUM_CPUS constant is deprecated; use cpu_count() instead"
- warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
- return cpu_count()
-
- @property
- def BOOT_TIME(self):
- msg = "BOOT_TIME constant is deprecated; use boot_time() instead"
- warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
- return boot_time()
-
- @property
- def TOTAL_PHYMEM(self):
- msg = "TOTAL_PHYMEM constant is deprecated; " \
- "use virtual_memory().total instead"
- warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
- return virtual_memory().total
-
- mod = ModuleWrapper()
- mod.__dict__ = globals()
- mod._module = sys.modules[__name__]
- sys.modules[__name__] = mod
-
-
-_replace_module()
-del memoize, division, _replace_module
+del memoize, division
if sys.version_info < (3, 0):
del num
diff --git a/psutil/_common.py b/psutil/_common.py
index 92d0fd0c..9f5c06f2 100644
--- a/psutil/_common.py
+++ b/psutil/_common.py
@@ -12,14 +12,19 @@ import functools
import os
import socket
import stat
-import warnings
+import sys
+from collections import namedtuple
+from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
try:
import threading
except ImportError:
import dummy_threading as threading
-from collections import namedtuple
-from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
+if sys.version_info >= (3, 4):
+ import enum
+else:
+ enum = None
+
# --- constants
@@ -52,6 +57,18 @@ CONN_LISTEN = "LISTEN"
CONN_CLOSING = "CLOSING"
CONN_NONE = "NONE"
+if enum is None:
+ NIC_DUPLEX_FULL = 2
+ NIC_DUPLEX_HALF = 1
+ NIC_DUPLEX_UNKNOWN = 0
+else:
+ class NicDuplex(enum.IntEnum):
+ NIC_DUPLEX_FULL = 2
+ NIC_DUPLEX_HALF = 1
+ NIC_DUPLEX_UNKNOWN = 0
+
+ globals().update(NicDuplex.__members__)
+
# --- functions
@@ -108,43 +125,6 @@ def memoize(fun):
return wrapper
-# http://code.activestate.com/recipes/577819-deprecated-decorator/
-def deprecated(replacement=None):
- """A decorator which can be used to mark functions as deprecated."""
- def outer(fun):
- msg = "psutil.%s is deprecated" % fun.__name__
- if replacement is not None:
- msg += "; use %s instead" % replacement
- if fun.__doc__ is None:
- fun.__doc__ = msg
-
- @functools.wraps(fun)
- def inner(*args, **kwargs):
- warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
- return fun(*args, **kwargs)
-
- return inner
- return outer
-
-
-def deprecated_method(replacement):
- """A decorator which can be used to mark a method as deprecated
- 'replcement' is the method name which will be called instead.
- """
- def outer(fun):
- msg = "%s() is deprecated; use %s() instead" % (
- fun.__name__, replacement)
- if fun.__doc__ is None:
- fun.__doc__ = msg
-
- @functools.wraps(fun)
- def inner(self, *args, **kwargs):
- warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
- return getattr(self, replacement)(*args, **kwargs)
- return inner
- return outer
-
-
def isfile_strict(path):
"""Same as os.path.isfile() but does not swallow EACCES / EPERM
exceptions, see:
@@ -160,6 +140,30 @@ def isfile_strict(path):
return stat.S_ISREG(st.st_mode)
+def sockfam_to_enum(num):
+ """Convert a numeric socket family value to an IntEnum member.
+ If it's not a known member, return the numeric value itself.
+ """
+ if enum is None:
+ return num
+ try:
+ return socket.AddressFamily(num)
+ except (ValueError, AttributeError):
+ return num
+
+
+def socktype_to_enum(num):
+ """Convert a numeric socket type value to an IntEnum member.
+ If it's not a known member, return the numeric value itself.
+ """
+ if enum is None:
+ return num
+ try:
+ return socket.AddressType(num)
+ except (ValueError, AttributeError):
+ return num
+
+
# --- Process.connections() 'kind' parameter mapping
conn_tmap = {
@@ -184,7 +188,7 @@ if AF_UNIX is not None:
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
})
-del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM, socket
+del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM
# --- namedtuples for psutil.* system-related functions
@@ -210,6 +214,10 @@ suser = namedtuple('suser', ['name', 'terminal', 'host', 'started'])
# psutil.net_connections()
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
'status', 'pid'])
+# psutil.net_if_addrs()
+snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast', 'ptp'])
+# psutil.net_if_stats()
+snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
# --- namedtuples for psutil.Process methods
@@ -233,24 +241,6 @@ pio = namedtuple('pio', ['read_count', 'write_count',
pionice = namedtuple('pionice', ['ioclass', 'value'])
# psutil.Process.ctx_switches()
pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary'])
-
-
-# --- misc
-
-# backward compatibility layer for Process.connections() ntuple
-class pconn(
- namedtuple('pconn',
- ['fd', 'family', 'type', 'laddr', 'raddr', 'status'])):
- __slots__ = ()
-
- @property
- def local_address(self):
- warnings.warn("'local_address' field is deprecated; use 'laddr'"
- "instead", category=DeprecationWarning, stacklevel=2)
- return self.laddr
-
- @property
- def remote_address(self):
- warnings.warn("'remote_address' field is deprecated; use 'raddr'"
- "instead", category=DeprecationWarning, stacklevel=2)
- return self.raddr
+# psutil.Process.connections()
+pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr',
+ 'status'])
diff --git a/psutil/_compat.py b/psutil/_compat.py
index 203408b8..5920c921 100644
--- a/psutil/_compat.py
+++ b/psutil/_compat.py
@@ -4,42 +4,28 @@
"""Module which provides compatibility with older Python versions."""
-__all__ = ["PY3", "int", "long", "xrange", "exec_", "callable", "lru_cache"]
-
import collections
import functools
import sys
-try:
- import __builtin__
-except ImportError:
- import builtins as __builtin__ # py3
+
+__all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"]
PY3 = sys.version_info[0] == 3
if PY3:
- int = int
long = int
xrange = range
unicode = str
- basestring = str
- exec_ = getattr(__builtin__, "exec")
+
+ def u(s):
+ return s
else:
- int = int
long = long
xrange = xrange
unicode = unicode
- basestring = basestring
-
- def exec_(code, globs=None, locs=None):
- if globs is None:
- frame = sys._getframe(1)
- globs = frame.f_globals
- if locs is None:
- locs = frame.f_locals
- del frame
- elif locs is None:
- locs = globs
- exec("""exec code in globs, locs""")
+
+ def u(s):
+ return unicode(s, "unicode_escape")
# removed in 3.0, reintroduced in 3.2
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index 39dfea36..e2cc6ba4 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -7,14 +7,15 @@
import errno
import functools
import os
-import sys
+import xml.etree.ElementTree as ET
from collections import namedtuple
-from psutil import _common
-from psutil import _psposix
-from psutil._common import conn_tmap, usage_percent
-import _psutil_bsd as cext
-import _psutil_posix
+from . import _common
+from . import _psposix
+from . import _psutil_bsd as cext
+from . import _psutil_posix as cext_posix
+from ._common import conn_tmap, usage_percent, sockfam_to_enum
+from ._common import socktype_to_enum
__extra__all__ = []
@@ -47,6 +48,7 @@ TCP_STATUSES = {
}
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
+AF_LINK = cext_posix.AF_LINK
# extend base mem ntuple with BSD-specific memory metrics
svmem = namedtuple(
@@ -62,6 +64,7 @@ pmmap_ext = namedtuple(
# set later from __init__.py
NoSuchProcess = None
+ZombieProcess = None
AccessDenied = None
TimeoutExpired = None
@@ -130,19 +133,25 @@ def cpu_count_physical():
# We may get None in case "sysctl kern.sched.topology_spec"
# is not supported on this BSD version, in which case we'll mimic
# os.cpu_count() and return None.
+ ret = None
s = cext.cpu_count_phys()
if s is not None:
# get rid of padding chars appended at the end of the string
index = s.rfind("</groups>")
if index != -1:
s = s[:index + 9]
- if sys.version_info >= (2, 5):
- import xml.etree.ElementTree as ET
- root = ET.fromstring(s)
- return len(root.findall('group/children/group/cpu')) or None
- else:
- s = s[s.find('<children>'):]
- return s.count("<cpu") or None
+ root = ET.fromstring(s)
+ try:
+ ret = len(root.findall('group/children/group/cpu')) or None
+ finally:
+ # needed otherwise it will memleak
+ root.clear()
+ if not ret:
+ # If logical CPUs are 1 it's obvious we'll have only 1
+ # physical CPU.
+ if cpu_count_logical() == 1:
+ return 1
+ return ret
def boot_time():
@@ -182,15 +191,36 @@ def net_connections(kind):
raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind]
- ret = []
+ ret = set()
rawlist = cext.net_connections()
for item in rawlist:
fd, fam, type, laddr, raddr, status, pid = item
# TODO: apply filter at C level
if fam in families and type in types:
- status = TCP_STATUSES[status]
+ try:
+ status = TCP_STATUSES[status]
+ except KeyError:
+ # XXX: Not sure why this happens. I saw this occurring
+ # with IPv6 sockets opened by 'vim'. Those sockets
+ # have a very short lifetime so maybe the kernel
+ # can't initialize their status?
+ status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
+ fam = sockfam_to_enum(fam)
+ type = socktype_to_enum(type)
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
- ret.append(nt)
+ ret.add(nt)
+ return list(ret)
+
+
+def net_if_stats():
+ """Get NIC stats (isup, duplex, speed, mtu)."""
+ names = net_io_counters().keys()
+ ret = {}
+ for name in names:
+ isup, duplex, speed, mtu = cext_posix.net_if_stats(name)
+ if hasattr(_common, 'NicDuplex'):
+ duplex = _common.NicDuplex(duplex)
+ ret[name] = _common.snicstats(isup, duplex, speed, mtu)
return ret
@@ -199,6 +229,7 @@ pid_exists = _psposix.pid_exists
disk_usage = _psposix.disk_usage
net_io_counters = cext.net_io_counters
disk_io_counters = cext.disk_io_counters
+net_if_addrs = cext_posix.net_if_addrs
def wrap_exceptions(fun):
@@ -211,10 +242,14 @@ def wrap_exceptions(fun):
return fun(self, *args, **kwargs)
except OSError as err:
# support for private module import
- if NoSuchProcess is None or AccessDenied is None:
+ if (NoSuchProcess is None or AccessDenied is None or
+ ZombieProcess is None):
raise
if err.errno == errno.ESRCH:
- raise NoSuchProcess(self.pid, self._name)
+ if not pid_exists(self.pid):
+ raise NoSuchProcess(self.pid, self._name)
+ else:
+ raise ZombieProcess(self.pid, self._name, self._ppid)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._name)
raise
@@ -224,11 +259,12 @@ def wrap_exceptions(fun):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name"]
+ __slots__ = ["pid", "_name", "_ppid"]
def __init__(self, pid):
self.pid = pid
self._name = None
+ self._ppid = None
@wrap_exceptions
def name(self):
@@ -310,6 +346,8 @@ class Process(object):
ret = []
for item in rawlist:
fd, fam, type, laddr, raddr, status = item
+ fam = sockfam_to_enum(fam)
+ type = socktype_to_enum(type)
status = TCP_STATUSES[status]
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
ret.append(nt)
@@ -327,11 +365,11 @@ class Process(object):
@wrap_exceptions
def nice_get(self):
- return _psutil_posix.getpriority(self.pid)
+ return cext_posix.getpriority(self.pid)
@wrap_exceptions
def nice_set(self, value):
- return _psutil_posix.setpriority(self.pid, value)
+ return cext_posix.setpriority(self.pid, value)
@wrap_exceptions
def status(self):
@@ -392,6 +430,14 @@ class Process(object):
@wrap_exceptions
def cpu_affinity_set(self, cpus):
+ # Pre-emptively check if CPUs are valid because the C
+ # function has a weird behavior in case of invalid CPUs,
+ # see: https://github.com/giampaolo/psutil/issues/586
+ allcpus = tuple(range(len(per_cpu_times())))
+ for cpu in cpus:
+ if cpu not in allcpus:
+ raise ValueError("invalid CPU #%i (choose between %s)"
+ % (cpu, allcpus))
try:
cext.proc_cpu_affinity_set(self.pid, cpus)
except OSError as err:
@@ -400,7 +446,6 @@ class Process(object):
# on because the set does not overlap with the thread's
# anonymous mask>>
if err.errno in (errno.EINVAL, errno.EDEADLK):
- allcpus = tuple(range(len(per_cpu_times())))
for cpu in cpus:
if cpu not in allcpus:
raise ValueError("invalid CPU #%i (choose between %s)"
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index 71ab8824..54a2f916 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -17,12 +17,18 @@ import sys
import warnings
from collections import namedtuple, defaultdict
-from psutil import _common
-from psutil import _psposix
-from psutil._common import (isfile_strict, usage_percent, deprecated)
-from psutil._compat import PY3
-import _psutil_linux as cext
-import _psutil_posix
+from . import _common
+from . import _psposix
+from . import _psutil_linux as cext
+from . import _psutil_posix as cext_posix
+from ._common import isfile_strict, usage_percent
+from ._common import NIC_DUPLEX_FULL, NIC_DUPLEX_HALF, NIC_DUPLEX_UNKNOWN
+from ._compat import PY3, long
+
+if sys.version_info >= (3, 4):
+ import enum
+else:
+ enum = None
__extra__all__ = [
@@ -32,10 +38,7 @@ __extra__all__ = [
# connection status constants
"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",
- # other
- "phymem_buffers", "cached_phymem"]
-
+ "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", ]
# --- constants
@@ -51,13 +54,29 @@ if HAS_PRLIMIT:
CLOCK_TICKS = os.sysconf("SC_CLK_TCK")
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
BOOT_TIME = None # set later
-DEFAULT_ENCODING = sys.getdefaultencoding()
+if PY3:
+ FS_ENCODING = sys.getfilesystemencoding()
+if enum is None:
+ AF_LINK = socket.AF_PACKET
+else:
+ AddressFamily = enum.IntEnum('AddressFamily',
+ {'AF_LINK': socket.AF_PACKET})
+ AF_LINK = AddressFamily.AF_LINK
# ioprio_* constants http://linux.die.net/man/2/ioprio_get
-IOPRIO_CLASS_NONE = 0
-IOPRIO_CLASS_RT = 1
-IOPRIO_CLASS_BE = 2
-IOPRIO_CLASS_IDLE = 3
+if enum is None:
+ IOPRIO_CLASS_NONE = 0
+ IOPRIO_CLASS_RT = 1
+ IOPRIO_CLASS_BE = 2
+ IOPRIO_CLASS_IDLE = 3
+else:
+ class IOPriority(enum.IntEnum):
+ IOPRIO_CLASS_NONE = 0
+ IOPRIO_CLASS_RT = 1
+ IOPRIO_CLASS_BE = 2
+ IOPRIO_CLASS_IDLE = 3
+
+ globals().update(IOPriority.__members__)
# taken from /fs/proc/array.c
PROC_STATUSES = {
@@ -90,10 +109,21 @@ TCP_STATUSES = {
# set later from __init__.py
NoSuchProcess = None
+ZombieProcess = None
AccessDenied = None
TimeoutExpired = None
+# --- utils
+
+def open_text(fname):
+ """On Python 3 opens a file in text mode by using fs encoding.
+ On Python 2 this is just an alias for open(name, 'rt').
+ """
+ kw = dict(encoding=FS_ENCODING) if PY3 else dict()
+ return open(fname, "rt", **kw)
+
+
# --- named tuples
def _get_cputimes_fields():
@@ -148,9 +178,9 @@ def virtual_memory():
active = int(line.split()[1]) * 1024
elif line.startswith(b"Inactive:"):
inactive = int(line.split()[1]) * 1024
- if (cached is not None
- and active is not None
- and inactive is not None):
+ if (cached is not None and
+ active is not None and
+ inactive is not None):
break
else:
# we might get here when dealing with exotic Linux flavors, see:
@@ -191,16 +221,6 @@ def swap_memory():
return _common.sswap(total, used, free, percent, sin, sout)
-@deprecated(replacement='psutil.virtual_memory().cached')
-def cached_phymem():
- return virtual_memory().cached
-
-
-@deprecated(replacement='psutil.virtual_memory().buffers')
-def phymem_buffers():
- return virtual_memory().buffers
-
-
# --- CPUs
def cpu_times():
@@ -252,7 +272,7 @@ def cpu_count_logical():
# try to parse /proc/stat as a last resort
if num == 0:
search = re.compile('cpu\d')
- with open('/proc/stat', 'rt') as f:
+ with open_text('/proc/stat') as f:
for line in f:
line = line.split(' ')[0]
if search.match(line):
@@ -265,14 +285,28 @@ def cpu_count_logical():
def cpu_count_physical():
- """Return the number of physical CPUs in the system."""
+ """Return the number of physical cores in the system."""
+ mapping = {}
+ current_info = {}
with open('/proc/cpuinfo', 'rb') as f:
- found = set()
for line in f:
- if line.lower().startswith(b'physical id'):
- found.add(line.strip())
+ line = line.strip().lower()
+ if not line:
+ # new section
+ if (b'physical id' in current_info and
+ b'cpu cores' in current_info):
+ mapping[current_info[b'physical id']] = \
+ current_info[b'cpu cores']
+ current_info = {}
+ else:
+ # ongoing section
+ if (line.startswith(b'physical id') or
+ line.startswith(b'cpu cores')):
+ key, value = line.split(b'\t:', 1)
+ current_info[key] = int(value)
+
# mimic os.cpu_count()
- return len(found) if found else None
+ return sum(mapping.values()) or None
# --- other system functions
@@ -288,7 +322,7 @@ def users():
# to use them in the future.
if not user_process:
continue
- if hostname == ':0.0':
+ if hostname == ':0.0' or hostname == ':0':
hostname = 'localhost'
nt = _common.suser(user, tty or None, hostname, tstamp)
retlist.append(nt)
@@ -304,7 +338,7 @@ def boot_time():
ret = float(line.strip().split()[1])
BOOT_TIME = ret
return ret
- raise RuntimeError("line 'btime' not found")
+ raise RuntimeError("line 'btime' not found in /proc/stat")
# --- processes
@@ -358,9 +392,17 @@ class Connections:
for fd in os.listdir("/proc/%s/fd" % pid):
try:
inode = os.readlink("/proc/%s/fd/%s" % (pid, fd))
- except OSError:
- # TODO: need comment here
- continue
+ except OSError as err:
+ # ENOENT == file which is gone in the meantime;
+ # os.stat('/proc/%s' % self.pid) will be done later
+ # to force NSP (if it's the case)
+ if err.errno in (errno.ENOENT, errno.ESRCH):
+ continue
+ elif err.errno == errno.EINVAL:
+ # not a link
+ continue
+ else:
+ raise
else:
if inode.startswith('socket:['):
# the process is using a socket
@@ -438,18 +480,23 @@ class Connections:
if file.endswith('6') and not os.path.exists(file):
# IPv6 not supported
return
- with open(file, 'rt') as f:
+ with open_text(file) as f:
f.readline() # skip the first line
for line in f:
- _, laddr, raddr, status, _, _, _, _, _, inode = \
- line.split()[:10]
+ try:
+ _, laddr, raddr, status, _, _, _, _, _, inode = \
+ line.split()[:10]
+ except ValueError:
+ raise RuntimeError(
+ "error while parsing %s; malformed line %r" % (
+ file, line))
if inode in inodes:
- # We assume inet sockets are unique, so we error
- # out if there are multiple references to the
- # same inode. We won't do this for UNIX sockets.
- if len(inodes[inode]) > 1 and family != socket.AF_UNIX:
- raise ValueError("ambiguos inode with multiple "
- "PIDs references")
+ # # We assume inet sockets are unique, so we error
+ # # out if there are multiple references to the
+ # # same inode. We won't do this for UNIX sockets.
+ # if len(inodes[inode]) > 1 and family != socket.AF_UNIX:
+ # raise ValueError("ambiguos inode with multiple "
+ # "PIDs references")
pid, fd = inodes[inode][0]
else:
pid, fd = None, -1
@@ -466,11 +513,18 @@ class Connections:
def process_unix(self, file, family, inodes, filter_pid=None):
"""Parse /proc/net/unix files."""
- with open(file, 'rt') as f:
+ # see: https://github.com/giampaolo/psutil/issues/675
+ kw = dict(encoding=FS_ENCODING, errors='replace') if PY3 else dict()
+ with open(file, 'rt', **kw) as f:
f.readline() # skip the first line
for line in f:
tokens = line.split()
- _, _, _, _, type_, _, inode = tokens[0:7]
+ try:
+ _, _, _, _, type_, _, inode = tokens[0:7]
+ except ValueError:
+ raise RuntimeError(
+ "error while parsing %s; malformed line %r" % (
+ file, line))
if inode in inodes:
# With UNIX sockets we can have a single inode
# referencing many file descriptors.
@@ -501,7 +555,7 @@ class Connections:
return []
else:
inodes = self.get_all_inodes()
- ret = []
+ ret = set()
for f, family, type_ in self.tmap[kind]:
if family in (socket.AF_INET, socket.AF_INET6):
ls = self.process_inet(
@@ -516,8 +570,8 @@ class Connections:
else:
conn = _common.sconn(fd, family, type_, laddr, raddr,
status, bound_pid)
- ret.append(conn)
- return ret
+ ret.add(conn)
+ return list(ret)
_connections = Connections()
@@ -532,7 +586,7 @@ def net_io_counters():
"""Return network I/O statistics for every network interface
installed on the system as a dict of raw tuples.
"""
- with open("/proc/net/dev", "rt") as f:
+ with open_text("/proc/net/dev") as f:
lines = f.readlines()
retdict = {}
for line in lines[2:]:
@@ -553,6 +607,23 @@ def net_io_counters():
return retdict
+def net_if_stats():
+ """Get NIC stats (isup, duplex, speed, mtu)."""
+ duplex_map = {cext.DUPLEX_FULL: NIC_DUPLEX_FULL,
+ cext.DUPLEX_HALF: NIC_DUPLEX_HALF,
+ cext.DUPLEX_UNKNOWN: NIC_DUPLEX_UNKNOWN}
+ names = net_io_counters().keys()
+ ret = {}
+ for name in names:
+ isup, duplex, speed, mtu = cext.net_if_stats(name)
+ duplex = duplex_map[duplex]
+ ret[name] = _common.snicstats(isup, duplex, speed, mtu)
+ return ret
+
+
+net_if_addrs = cext_posix.net_if_addrs
+
+
# --- disks
def disk_io_counters():
@@ -566,7 +637,7 @@ def disk_io_counters():
# determine partitions we want to look for
partitions = []
- with open("/proc/partitions", "rt") as f:
+ with open_text("/proc/partitions") as f:
lines = f.readlines()[2:]
for line in reversed(lines):
_, _, _, name = line.split()
@@ -583,7 +654,7 @@ def disk_io_counters():
partitions.append(name)
#
retdict = {}
- with open("/proc/diskstats", "rt") as f:
+ with open_text("/proc/diskstats") as f:
lines = f.readlines()
for line in lines:
# http://www.mjmwired.net/kernel/Documentation/iostats.txt
@@ -607,12 +678,18 @@ def disk_io_counters():
def disk_partitions(all=False):
- """Return mounted disk partitions as a list of nameduples"""
- phydevs = []
- with open("/proc/filesystems", "r") as f:
+ """Return mounted disk partitions as a list of namedtuples"""
+ fstypes = set()
+ with open_text("/proc/filesystems") as f:
for line in f:
+ line = line.strip()
if not line.startswith("nodev"):
- phydevs.append(line.strip())
+ fstypes.add(line.strip())
+ else:
+ # ignore all lines starting with "nodev" except "nodev zfs"
+ fstype = line.split("\t")[1]
+ if fstype == "zfs":
+ fstypes.add("zfs")
retlist = []
partitions = cext.disk_partitions()
@@ -621,7 +698,7 @@ def disk_partitions(all=False):
if device == 'none':
device = ''
if not all:
- if device == '' or fstype not in phydevs:
+ if device == '' or fstype not in fstypes:
continue
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
retlist.append(ntuple)
@@ -656,27 +733,41 @@ def wrap_exceptions(fun):
return wrapper
+def wrap_exceptions_w_zombie(fun):
+ """Same as above but also handles zombies."""
+ @functools.wraps(fun)
+ def wrapper(self, *args, **kwargs):
+ try:
+ return wrap_exceptions(fun)(self)
+ except NoSuchProcess:
+ if not pid_exists(self.pid):
+ raise
+ else:
+ raise ZombieProcess(self.pid, self._name, self._ppid)
+ return wrapper
+
+
class Process(object):
"""Linux process implementation."""
- __slots__ = ["pid", "_name"]
+ __slots__ = ["pid", "_name", "_ppid"]
def __init__(self, pid):
self.pid = pid
self._name = None
+ self._ppid = None
@wrap_exceptions
def name(self):
- fname = "/proc/%s/stat" % self.pid
- kw = dict(encoding=DEFAULT_ENCODING) if PY3 else dict()
- with open(fname, "rt", **kw) as f:
- # XXX - gets changed later and probably needs refactoring
- return f.read().split(' ')[1].replace('(', '').replace(')', '')
+ with open_text("/proc/%s/stat" % self.pid) as f:
+ data = f.read()
+ # XXX - gets changed later and probably needs refactoring
+ return data[data.find('(') + 1:data.rfind(')')]
def exe(self):
try:
exe = os.readlink("/proc/%s/exe" % self.pid)
- except (OSError, IOError) as err:
+ except OSError as err:
if err.errno in (errno.ENOENT, errno.ESRCH):
# no such file error; might be raised also if the
# path actually exists for system processes with
@@ -684,8 +775,10 @@ class Process(object):
if os.path.lexists("/proc/%s" % self.pid):
return ""
else:
- # ok, it is a process which has gone away
- raise NoSuchProcess(self.pid, self._name)
+ if not pid_exists(self.pid):
+ raise NoSuchProcess(self.pid, self._name)
+ else:
+ raise ZombieProcess(self.pid, self._name, self._ppid)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._name)
raise
@@ -702,10 +795,11 @@ class Process(object):
@wrap_exceptions
def cmdline(self):
- fname = "/proc/%s/cmdline" % self.pid
- kw = dict(encoding=DEFAULT_ENCODING) if PY3 else dict()
- with open(fname, "rt", **kw) as f:
- return [x for x in f.read().split('\x00') if x]
+ with open_text("/proc/%s/cmdline" % self.pid) as f:
+ data = f.read()
+ if data.endswith('\x00'):
+ data = data[:-1]
+ return [x for x in data.split('\x00')]
@wrap_exceptions
def terminal(self):
@@ -807,11 +901,11 @@ class Process(object):
@wrap_exceptions
def memory_maps(self):
- """Return process's mapped memory regions as a list of nameduples.
+ """Return process's mapped memory regions as a list of named tuples.
Fields are explained in 'man proc'; here is an updated (Apr 2012)
version: http://goo.gl/fmebo
"""
- with open("/proc/%s/smaps" % self.pid, "rt") as f:
+ with open_text("/proc/%s/smaps" % self.pid) as f:
first_line = f.readline()
current_block = [first_line]
@@ -870,7 +964,7 @@ class Process(object):
% self.pid
raise NotImplementedError(msg)
- @wrap_exceptions
+ @wrap_exceptions_w_zombie
def cwd(self):
# readlink() might return paths containing null bytes causing
# problems when used with other fs-related functions (os.*,
@@ -913,7 +1007,7 @@ class Process(object):
try:
with open(fname, 'rb') as f:
st = f.read().strip()
- except EnvironmentError as err:
+ except IOError as err:
if err.errno == errno.ENOENT:
# no such file or directory; it means thread
# disappeared on us
@@ -934,16 +1028,16 @@ class Process(object):
@wrap_exceptions
def nice_get(self):
- # with open('/proc/%s/stat' % self.pid, 'r') as f:
+ # with open_text('/proc/%s/stat' % self.pid) as f:
# data = f.read()
# return int(data.split()[18])
# Use C implementation
- return _psutil_posix.getpriority(self.pid)
+ return cext_posix.getpriority(self.pid)
@wrap_exceptions
def nice_set(self, value):
- return _psutil_posix.setpriority(self.pid, value)
+ return cext_posix.setpriority(self.pid, value)
@wrap_exceptions
def cpu_affinity_get(self):
@@ -968,48 +1062,70 @@ class Process(object):
@wrap_exceptions
def ionice_get(self):
ioclass, value = cext.proc_ioprio_get(self.pid)
+ if enum is not None:
+ ioclass = IOPriority(ioclass)
return _common.pionice(ioclass, value)
@wrap_exceptions
def ionice_set(self, ioclass, value):
+ if value is not None:
+ if not PY3 and not isinstance(value, (int, long)):
+ msg = "value argument is not an integer (gor %r)" % value
+ raise TypeError(msg)
+ if not 0 <= value <= 7:
+ raise ValueError(
+ "value argument range expected is between 0 and 7")
+
if ioclass in (IOPRIO_CLASS_NONE, None):
if value:
- msg = "can't specify value with IOPRIO_CLASS_NONE"
+ msg = "can't specify value with IOPRIO_CLASS_NONE " \
+ "(got %r)" % value
raise ValueError(msg)
ioclass = IOPRIO_CLASS_NONE
value = 0
- if ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE):
- if value is None:
- value = 4
elif ioclass == IOPRIO_CLASS_IDLE:
if value:
- msg = "can't specify value with IOPRIO_CLASS_IDLE"
+ msg = "can't specify value with IOPRIO_CLASS_IDLE " \
+ "(got %r)" % value
raise ValueError(msg)
value = 0
+ elif ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE):
+ if value is None:
+ # TODO: add comment explaining why this is 4 (?)
+ value = 4
else:
- value = 0
- if not 0 <= value <= 8:
- raise ValueError(
- "value argument range expected is between 0 and 8")
+ # otherwise we would get OSError(EVINAL)
+ raise ValueError("invalid ioclass argument %r" % ioclass)
+
return cext.proc_ioprio_set(self.pid, ioclass, value)
if HAS_PRLIMIT:
@wrap_exceptions
def rlimit(self, resource, limits=None):
- # if pid is 0 prlimit() applies to the calling process and
- # we don't want that
+ # If pid is 0 prlimit() applies to the calling process and
+ # we don't want that. We should never get here though as
+ # PID 0 is not supported on Linux.
if self.pid == 0:
raise ValueError("can't use prlimit() against PID 0 process")
- if limits is None:
- # get
- return cext.linux_prlimit(self.pid, resource)
- else:
- # set
- if len(limits) != 2:
- raise ValueError(
- "second argument must be a (soft, hard) tuple")
- soft, hard = limits
- cext.linux_prlimit(self.pid, resource, soft, hard)
+ try:
+ if limits is None:
+ # get
+ return cext.linux_prlimit(self.pid, resource)
+ else:
+ # set
+ if len(limits) != 2:
+ raise ValueError(
+ "second argument must be a (soft, hard) tuple, "
+ "got %s" % repr(limits))
+ soft, hard = limits
+ cext.linux_prlimit(self.pid, resource, soft, hard)
+ except OSError as err:
+ if err.errno == errno.ENOSYS and pid_exists(self.pid):
+ # I saw this happening on Travis:
+ # https://travis-ci.org/giampaolo/psutil/jobs/51368273
+ raise ZombieProcess(self.pid, self._name, self._ppid)
+ else:
+ raise
@wrap_exceptions
def status(self):
@@ -1068,27 +1184,30 @@ class Process(object):
@wrap_exceptions
def ppid(self):
- with open("/proc/%s/status" % self.pid, 'rb') as f:
+ fpath = "/proc/%s/status" % self.pid
+ with open(fpath, 'rb') as f:
for line in f:
if line.startswith(b"PPid:"):
# PPid: nnnn
return int(line.split()[1])
- raise NotImplementedError("line not found")
+ raise NotImplementedError("line 'PPid' not found in %s" % fpath)
@wrap_exceptions
def uids(self):
- with open("/proc/%s/status" % self.pid, 'rb') as f:
+ fpath = "/proc/%s/status" % self.pid
+ with open(fpath, 'rb') as f:
for line in f:
if line.startswith(b'Uid:'):
_, real, effective, saved, fs = line.split()
return _common.puids(int(real), int(effective), int(saved))
- raise NotImplementedError("line not found")
+ raise NotImplementedError("line 'Uid' not found in %s" % fpath)
@wrap_exceptions
def gids(self):
- with open("/proc/%s/status" % self.pid, 'rb') as f:
+ fpath = "/proc/%s/status" % self.pid
+ with open(fpath, 'rb') as f:
for line in f:
if line.startswith(b'Gid:'):
_, real, effective, saved, fs = line.split()
return _common.pgids(int(real), int(effective), int(saved))
- raise NotImplementedError("line not found")
+ raise NotImplementedError("line 'Gid' not found in %s" % fpath)
diff --git a/psutil/_psosx.py b/psutil/_psosx.py
index 733a1854..b44acb23 100644
--- a/psutil/_psosx.py
+++ b/psutil/_psosx.py
@@ -9,11 +9,12 @@ import functools
import os
from collections import namedtuple
-from psutil import _common
-from psutil import _psposix
-from psutil._common import conn_tmap, usage_percent, isfile_strict
-import _psutil_osx as cext
-import _psutil_posix
+from . import _common
+from . import _psposix
+from . import _psutil_osx as cext
+from . import _psutil_posix as cext_posix
+from ._common import conn_tmap, usage_percent, isfile_strict
+from ._common import sockfam_to_enum, socktype_to_enum
__extra__all__ = []
@@ -21,6 +22,7 @@ __extra__all__ = []
# --- constants
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
+AF_LINK = cext_posix.AF_LINK
# http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
TCP_STATUSES = {
@@ -63,6 +65,7 @@ pmmap_ext = namedtuple(
# set later from __init__.py
NoSuchProcess = None
+ZombieProcess = None
AccessDenied = None
TimeoutExpired = None
@@ -163,11 +166,24 @@ def net_connections(kind='inet'):
return ret
+def net_if_stats():
+ """Get NIC stats (isup, duplex, speed, mtu)."""
+ names = net_io_counters().keys()
+ ret = {}
+ for name in names:
+ isup, duplex, speed, mtu = cext_posix.net_if_stats(name)
+ if hasattr(_common, 'NicDuplex'):
+ duplex = _common.NicDuplex(duplex)
+ ret[name] = _common.snicstats(isup, duplex, speed, mtu)
+ return ret
+
+
pids = cext.pids
pid_exists = _psposix.pid_exists
disk_usage = _psposix.disk_usage
net_io_counters = cext.net_io_counters
disk_io_counters = cext.disk_io_counters
+net_if_addrs = cext_posix.net_if_addrs
def wrap_exceptions(fun):
@@ -180,10 +196,14 @@ def wrap_exceptions(fun):
return fun(self, *args, **kwargs)
except OSError as err:
# support for private module import
- if NoSuchProcess is None or AccessDenied is None:
+ if (NoSuchProcess is None or AccessDenied is None or
+ ZombieProcess is None):
raise
if err.errno == errno.ESRCH:
- raise NoSuchProcess(self.pid, self._name)
+ if not pid_exists(self.pid):
+ raise NoSuchProcess(self.pid, self._name)
+ else:
+ raise ZombieProcess(self.pid, self._name, self._ppid)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._name)
raise
@@ -193,11 +213,12 @@ def wrap_exceptions(fun):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name"]
+ __slots__ = ["pid", "_name", "_ppid"]
def __init__(self, pid):
self.pid = pid
self._name = None
+ self._ppid = None
@wrap_exceptions
def name(self):
@@ -290,6 +311,8 @@ class Process(object):
for item in rawlist:
fd, fam, type, laddr, raddr, status = item
status = TCP_STATUSES[status]
+ fam = sockfam_to_enum(fam)
+ type = socktype_to_enum(type)
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
ret.append(nt)
return ret
@@ -312,11 +335,11 @@ class Process(object):
@wrap_exceptions
def nice_get(self):
- return _psutil_posix.getpriority(self.pid)
+ return cext_posix.getpriority(self.pid)
@wrap_exceptions
def nice_set(self, value):
- return _psutil_posix.setpriority(self.pid, value)
+ return cext_posix.setpriority(self.pid, value)
@wrap_exceptions
def status(self):
diff --git a/psutil/_psposix.py b/psutil/_psposix.py
index 0da6a8ce..046a75f0 100644
--- a/psutil/_psposix.py
+++ b/psutil/_psposix.py
@@ -10,8 +10,8 @@ import os
import sys
import time
-from psutil._common import sdiskusage, usage_percent, memoize
-from psutil._compat import PY3, unicode
+from ._common import sdiskusage, usage_percent, memoize
+from ._compat import PY3, unicode
class TimeoutExpired(Exception):
@@ -66,10 +66,12 @@ def wait_pid(pid, timeout=None):
timer = getattr(time, 'monotonic', time.time)
if timeout is not None:
- waitcall = lambda: os.waitpid(pid, os.WNOHANG)
+ def waitcall():
+ return os.waitpid(pid, os.WNOHANG)
stop_at = timer() + timeout
else:
- waitcall = lambda: os.waitpid(pid, 0)
+ def waitcall():
+ return os.waitpid(pid, 0)
delay = 0.0001
while True:
diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py
index 1ee249e5..ae7d533b 100644
--- a/psutil/_pssunos.py
+++ b/psutil/_pssunos.py
@@ -11,17 +11,19 @@ import subprocess
import sys
from collections import namedtuple
-from psutil import _common
-from psutil import _psposix
-from psutil._common import usage_percent, isfile_strict
-from psutil._compat import PY3
-import _psutil_posix
-import _psutil_sunos as cext
+from . import _common
+from . import _psposix
+from . import _psutil_posix as cext_posix
+from . import _psutil_sunos as cext
+from ._common import isfile_strict, socktype_to_enum, sockfam_to_enum
+from ._common import usage_percent
+from ._compat import PY3
__extra__all__ = ["CONN_IDLE", "CONN_BOUND"]
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
+AF_LINK = cext_posix.AF_LINK
CONN_IDLE = "IDLE"
CONN_BOUND = "BOUND"
@@ -62,6 +64,7 @@ pmmap_ext = namedtuple(
# set later from __init__.py
NoSuchProcess = None
+ZombieProcess = None
AccessDenied = None
TimeoutExpired = None
@@ -70,6 +73,7 @@ TimeoutExpired = None
disk_io_counters = cext.disk_io_counters
net_io_counters = cext.net_io_counters
disk_usage = _psposix.disk_usage
+net_if_addrs = cext_posix.net_if_addrs
def virtual_memory():
@@ -90,7 +94,9 @@ def swap_memory():
# usr/src/cmd/swap/swap.c
# ...nevertheless I can't manage to obtain the same numbers as 'swap'
# cmdline utility, so let's parse its output (sigh!)
- p = subprocess.Popen(['swap', '-l', '-k'], stdout=subprocess.PIPE)
+ p = subprocess.Popen(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' %
+ os.environ['PATH'], 'swap', '-l', '-k'],
+ stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
if PY3:
stdout = stdout.decode(sys.stdout.encoding)
@@ -208,7 +214,7 @@ def net_connections(kind, _pid=-1):
% (kind, ', '.join([repr(x) for x in cmap])))
families, types = _common.conn_tmap[kind]
rawlist = cext.net_connections(_pid, families, types)
- ret = []
+ ret = set()
for item in rawlist:
fd, fam, type_, laddr, raddr, status, pid = item
if fam not in families:
@@ -216,11 +222,24 @@ def net_connections(kind, _pid=-1):
if type_ not in types:
continue
status = TCP_STATUSES[status]
+ fam = sockfam_to_enum(fam)
+ type_ = socktype_to_enum(type_)
if _pid == -1:
nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid)
else:
nt = _common.pconn(fd, fam, type_, laddr, raddr, status)
- ret.append(nt)
+ ret.add(nt)
+ return list(ret)
+
+
+def net_if_stats():
+ """Get NIC stats (isup, duplex, speed, mtu)."""
+ ret = cext.net_if_stats()
+ for name, items in ret.items():
+ isup, duplex, speed, mtu = items
+ if hasattr(_common, 'NicDuplex'):
+ duplex = _common.NicDuplex(duplex)
+ ret[name] = _common.snicstats(isup, duplex, speed, mtu)
return ret
@@ -233,13 +252,17 @@ def wrap_exceptions(fun):
return fun(self, *args, **kwargs)
except EnvironmentError as err:
# support for private module import
- if NoSuchProcess is None or AccessDenied is None:
+ if (NoSuchProcess is None or AccessDenied is None or
+ ZombieProcess is None):
raise
# ENOENT (no such file or directory) gets raised on open().
# ESRCH (no such process) can get raised on read() if
# process is gone in meantime.
if err.errno in (errno.ENOENT, errno.ESRCH):
- raise NoSuchProcess(self.pid, self._name)
+ if not pid_exists(self.pid):
+ raise NoSuchProcess(self.pid, self._name)
+ else:
+ raise ZombieProcess(self.pid, self._name, self._ppid)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._name)
raise
@@ -249,11 +272,12 @@ def wrap_exceptions(fun):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name"]
+ __slots__ = ["pid", "_name", "_ppid"]
def __init__(self, pid):
self.pid = pid
self._name = None
+ self._ppid = None
@wrap_exceptions
def name(self):
@@ -290,9 +314,11 @@ class Process(object):
# Note: tested on Solaris 11; on Open Solaris 5 everything is
# fine.
try:
- return _psutil_posix.getpriority(self.pid)
+ return cext_posix.getpriority(self.pid)
except EnvironmentError as err:
- if err.errno in (errno.ENOENT, errno.ESRCH):
+ # 48 is 'operation not supported' but errno does not expose
+ # it. It occurs for low system pids.
+ if err.errno in (errno.ENOENT, errno.ESRCH, 48):
if pid_exists(self.pid):
raise AccessDenied(self.pid, self._name)
raise
@@ -305,7 +331,7 @@ class Process(object):
# The process actually exists though, as it has a name,
# creation time, etc.
raise AccessDenied(self.pid, self._name)
- return _psutil_posix.setpriority(self.pid, value)
+ return cext_posix.setpriority(self.pid, value)
@wrap_exceptions
def ppid(self):
diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c
index 0128c8c8..16bb351f 100644
--- a/psutil/_psutil_bsd.c
+++ b/psutil/_psutil_bsd.c
@@ -28,6 +28,7 @@
#include <sys/socketvar.h> // for struct xsocket
#include <sys/un.h>
#include <sys/unpcb.h>
+#include <sys/sockio.h>
// for xinpcb struct
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -50,6 +51,7 @@
#include <net/if.h> // net io counters
#include <net/if_dl.h>
#include <net/route.h>
+#include <net/if_media.h>
#include <netinet/in.h> // process open files/connections
#include <sys/un.h>
@@ -67,8 +69,7 @@
* Utility function which fills a kinfo_proc struct based on process pid
*/
static int
-psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc)
-{
+psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) {
int mib[4];
size_t size;
mib[0] = CTL_KERN;
@@ -95,14 +96,12 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc)
/*
* Set exception to AccessDenied if pid exists else NoSuchProcess.
*/
-int
+void
psutil_raise_ad_or_nsp(long pid) {
- if (psutil_pid_exists(pid) == 0) {
+ if (psutil_pid_exists(pid) == 0)
NoSuchProcess();
- }
- else {
+ else
AccessDenied();
- }
}
@@ -110,18 +109,16 @@ psutil_raise_ad_or_nsp(long pid) {
* Return a Python list of all the PIDs running on the system.
*/
static PyObject *
-psutil_pids(PyObject *self, PyObject *args)
-{
+psutil_pids(PyObject *self, PyObject *args) {
kinfo_proc *proclist = NULL;
kinfo_proc *orig_address = NULL;
size_t num_processes;
size_t idx;
- PyObject *retlist = PyList_New(0);
- PyObject *pid = NULL;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_pid = NULL;
- if (retlist == NULL) {
+ if (py_retlist == NULL)
return NULL;
- }
if (psutil_get_proc_list(&proclist, &num_processes) != 0) {
PyErr_SetString(PyExc_RuntimeError,
"failed to retrieve process list.");
@@ -131,25 +128,24 @@ 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++) {
- pid = Py_BuildValue("i", proclist->ki_pid);
- if (!pid)
+ py_pid = Py_BuildValue("i", proclist->ki_pid);
+ if (!py_pid)
goto error;
- if (PyList_Append(retlist, pid))
+ if (PyList_Append(py_retlist, py_pid))
goto error;
- Py_DECREF(pid);
+ Py_DECREF(py_pid);
proclist++;
}
free(orig_address);
}
- return retlist;
+ return py_retlist;
error:
- Py_XDECREF(pid);
- Py_DECREF(retlist);
- if (orig_address != NULL) {
+ Py_XDECREF(py_pid);
+ Py_DECREF(py_retlist);
+ if (orig_address != NULL)
free(orig_address);
- }
return NULL;
}
@@ -159,8 +155,7 @@ error:
* seconds since the epoch.
*/
static PyObject *
-psutil_boot_time(PyObject *self, PyObject *args)
-{
+psutil_boot_time(PyObject *self, PyObject *args) {
// fetch sysctl "kern.boottime"
static int request[2] = { CTL_KERN, KERN_BOOTTIME };
struct timeval boottime;
@@ -178,16 +173,13 @@ psutil_boot_time(PyObject *self, PyObject *args)
* Return process name from kinfo_proc as a Python string.
*/
static PyObject *
-psutil_proc_name(PyObject *self, PyObject *args)
-{
+psutil_proc_name(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("s", kp.ki_comm);
}
@@ -198,17 +190,15 @@ psutil_proc_name(PyObject *self, PyObject *args)
* http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT
*/
static PyObject *
-psutil_proc_exe(PyObject *self, PyObject *args)
-{
+psutil_proc_exe(PyObject *self, PyObject *args) {
long pid;
char pathname[PATH_MAX];
int error;
int mib[4];
size_t size;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
@@ -222,12 +212,10 @@ psutil_proc_exe(PyObject *self, PyObject *args)
return NULL;
}
if (size == 0 || strlen(pathname) == 0) {
- if (psutil_pid_exists(pid) == 0) {
+ if (psutil_pid_exists(pid) == 0)
return NoSuchProcess();
- }
- else {
+ else
strcpy(pathname, "");
- }
}
return Py_BuildValue("s", pathname);
}
@@ -237,24 +225,21 @@ psutil_proc_exe(PyObject *self, PyObject *args)
* Return process cmdline as a Python list of cmdline arguments.
*/
static PyObject *
-psutil_proc_cmdline(PyObject *self, PyObject *args)
-{
+psutil_proc_cmdline(PyObject *self, PyObject *args) {
long pid;
- PyObject *arglist = NULL;
+ PyObject *py_retlist = NULL;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
// get the commandline, defined in arch/bsd/process_info.c
- arglist = psutil_get_arg_list(pid);
+ py_retlist = psutil_get_cmdline(pid);
- // psutil_get_arg_list() returns NULL only if psutil_cmd_args
+ // psutil_get_cmdline() returns NULL only if psutil_cmd_args
// failed with ESRCH (no process with that PID)
- if (NULL == arglist) {
+ if (NULL == py_retlist)
return PyErr_SetFromErrno(PyExc_OSError);
- }
- return Py_BuildValue("N", arglist);
+ return Py_BuildValue("N", py_retlist);
}
@@ -262,16 +247,13 @@ psutil_proc_cmdline(PyObject *self, PyObject *args)
* Return process parent pid from kinfo_proc as a Python integer.
*/
static PyObject *
-psutil_proc_ppid(PyObject *self, PyObject *args)
-{
+psutil_proc_ppid(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("l", (long)kp.ki_ppid);
}
@@ -280,16 +262,13 @@ psutil_proc_ppid(PyObject *self, PyObject *args)
* Return process status as a Python integer.
*/
static PyObject *
-psutil_proc_status(PyObject *self, PyObject *args)
-{
+psutil_proc_status(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("i", (int)kp.ki_stat);
}
@@ -299,16 +278,13 @@ psutil_proc_status(PyObject *self, PyObject *args)
* as a Python tuple.
*/
static PyObject *
-psutil_proc_uids(PyObject *self, PyObject *args)
-{
+psutil_proc_uids(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("lll",
(long)kp.ki_ruid,
(long)kp.ki_uid,
@@ -321,16 +297,13 @@ psutil_proc_uids(PyObject *self, PyObject *args)
* as a Python tuple.
*/
static PyObject *
-psutil_proc_gids(PyObject *self, PyObject *args)
-{
+psutil_proc_gids(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("lll",
(long)kp.ki_rgid,
(long)kp.ki_groups[0],
@@ -343,16 +316,13 @@ psutil_proc_gids(PyObject *self, PyObject *args)
* as a Python tuple.
*/
static PyObject *
-psutil_proc_tty_nr(PyObject *self, PyObject *args)
-{
+psutil_proc_tty_nr(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("i", kp.ki_tdev);
}
@@ -361,16 +331,13 @@ psutil_proc_tty_nr(PyObject *self, PyObject *args)
* Return the number of context switches performed by process as a tuple.
*/
static PyObject *
-psutil_proc_num_ctx_switches(PyObject *self, PyObject *args)
-{
+psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("(ll)",
kp.ki_rusage.ru_nvcsw,
kp.ki_rusage.ru_nivcsw);
@@ -381,16 +348,13 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args)
* Return number of threads used by process as a Python integer.
*/
static PyObject *
-psutil_proc_num_threads(PyObject *self, PyObject *args)
-{
+psutil_proc_num_threads(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("l", (long)kp.ki_numthreads);
}
@@ -403,8 +367,7 @@ psutil_proc_num_threads(PyObject *self, PyObject *args)
* procstat_threads.c?v=8-CURRENT
*/
static PyObject *
-psutil_proc_threads(PyObject *self, PyObject *args)
-{
+psutil_proc_threads(PyObject *self, PyObject *args) {
long pid;
int mib[4];
struct kinfo_proc *kip = NULL;
@@ -412,10 +375,10 @@ psutil_proc_threads(PyObject *self, PyObject *args)
int error;
unsigned int i;
size_t size;
- PyObject *retList = PyList_New(0);
- PyObject *pyTuple = NULL;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
- if (retList == NULL)
+ if (py_retlist == NULL)
return NULL;
if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
@@ -455,25 +418,24 @@ psutil_proc_threads(PyObject *self, PyObject *args)
for (i = 0; i < size / sizeof(*kipp); i++) {
kipp = &kip[i];
- pyTuple = Py_BuildValue("Idd",
- kipp->ki_tid,
- TV2DOUBLE(kipp->ki_rusage.ru_utime),
- TV2DOUBLE(kipp->ki_rusage.ru_stime));
- if (pyTuple == NULL)
+ py_tuple = Py_BuildValue("Idd",
+ kipp->ki_tid,
+ TV2DOUBLE(kipp->ki_rusage.ru_utime),
+ TV2DOUBLE(kipp->ki_rusage.ru_stime));
+ if (py_tuple == NULL)
goto error;
- if (PyList_Append(retList, pyTuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(pyTuple);
+ Py_DECREF(py_tuple);
}
free(kip);
- return retList;
+ return py_retlist;
error:
- Py_XDECREF(pyTuple);
- Py_DECREF(retList);
- if (kip != NULL) {
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
+ if (kip != NULL)
free(kip);
- }
return NULL;
}
@@ -482,17 +444,14 @@ error:
* Return a Python tuple (user_time, kernel_time)
*/
static PyObject *
-psutil_proc_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_times(PyObject *self, PyObject *args) {
long pid;
double user_t, sys_t;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
// convert from microseconds to seconds
user_t = TV2DOUBLE(kp.ki_rusage.ru_utime);
sys_t = TV2DOUBLE(kp.ki_rusage.ru_stime);
@@ -505,8 +464,7 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args)
* XXX this could be shared with OSX
*/
static PyObject *
-psutil_cpu_count_logical(PyObject *self, PyObject *args)
-{
+psutil_cpu_count_logical(PyObject *self, PyObject *args) {
int mib[2];
int ncpu;
size_t len;
@@ -515,13 +473,10 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args)
mib[1] = HW_NCPU;
len = sizeof(ncpu);
- if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
- // mimic os.cpu_count()
- Py_RETURN_NONE;
- }
- else {
+ if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1)
+ Py_RETURN_NONE; // mimic os.cpu_count()
+ else
return Py_BuildValue("i", ncpu);
- }
}
@@ -530,8 +485,7 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args)
* physical CPU cores in the system.
*/
static PyObject *
-psutil_cpu_count_phys(PyObject *self, PyObject *args)
-{
+psutil_cpu_count_phys(PyObject *self, PyObject *args) {
void *topology = NULL;
size_t size = 0;
PyObject *py_str;
@@ -564,16 +518,13 @@ error:
* seconds since the epoch.
*/
static PyObject *
-psutil_proc_create_time(PyObject *self, PyObject *args)
-{
+psutil_proc_create_time(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("d", TV2DOUBLE(kp.ki_start));
}
@@ -583,16 +534,13 @@ psutil_proc_create_time(PyObject *self, PyObject *args)
* seconds since the epoch.
*/
static PyObject *
-psutil_proc_io_counters(PyObject *self, PyObject *args)
-{
+psutil_proc_io_counters(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
// there's apparently no way to determine bytes count, hence return -1.
return Py_BuildValue("(llll)",
kp.ki_rusage.ru_inblock,
@@ -606,16 +554,13 @@ psutil_proc_io_counters(PyObject *self, PyObject *args)
* Return extended memory info for a process as a Python tuple.
*/
static PyObject *
-psutil_proc_memory_info(PyObject *self, PyObject *args)
-{
+psutil_proc_memory_info(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("(lllll)",
ptoa(kp.ki_rssize), // rss
(long)kp.ki_size, // vms
@@ -629,8 +574,7 @@ psutil_proc_memory_info(PyObject *self, PyObject *args)
* Return virtual memory usage statistics.
*/
static PyObject *
-psutil_virtual_mem(PyObject *self, PyObject *args)
-{
+psutil_virtual_mem(PyObject *self, PyObject *args) {
unsigned int total, active, inactive, wired, cached, free;
size_t size = sizeof(total);
struct vmtotal vm;
@@ -688,8 +632,7 @@ error:
* Return swap memory stats (see 'swapinfo' cmdline tool)
*/
static PyObject *
-psutil_swap_mem(PyObject *self, PyObject *args)
-{
+psutil_swap_mem(PyObject *self, PyObject *args) {
kvm_t *kd;
struct kvm_swap kvmsw[1];
unsigned int swapin, swapout, nodein, nodeout;
@@ -735,8 +678,7 @@ sbn_error:
* Return a Python tuple representing user, kernel and idle CPU times
*/
static PyObject *
-psutil_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_cpu_times(PyObject *self, PyObject *args) {
long cpu_time[CPUSTATES];
size_t size;
@@ -767,20 +709,22 @@ psutil_cpu_times(PyObject *self, PyObject *args)
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
/*
- * Return files opened by process as a list of (path, fd) tuples
+ * Return files opened by process as a list of (path, fd) tuples.
+ * TODO: this is broken as it may report empty paths. 'procstat'
+ * utility has the same problem see:
+ * https://github.com/giampaolo/psutil/issues/595
*/
static PyObject *
-psutil_proc_open_files(PyObject *self, PyObject *args)
-{
+psutil_proc_open_files(PyObject *self, PyObject *args) {
long pid;
int i, cnt;
struct kinfo_file *freep = NULL;
struct kinfo_file *kif;
struct kinfo_proc kipp;
- PyObject *retList = PyList_New(0);
- PyObject *tuple = NULL;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
- if (retList == NULL)
+ if (py_retlist == NULL)
return NULL;
if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
@@ -798,20 +742,20 @@ psutil_proc_open_files(PyObject *self, PyObject *args)
if ((kif->kf_type == KF_TYPE_VNODE) &&
(kif->kf_vnode_type == KF_VTYPE_VREG))
{
- tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd);
- if (tuple == NULL)
+ py_tuple = Py_BuildValue("(si)", kif->kf_path, kif->kf_fd);
+ if (py_tuple == NULL)
goto error;
- if (PyList_Append(retList, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
}
free(freep);
- return retList;
+ return py_retlist;
error:
- Py_XDECREF(tuple);
- Py_DECREF(retList);
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
if (freep != NULL)
free(freep);
return NULL;
@@ -822,8 +766,7 @@ error:
* Return files opened by process as a list of (path, fd) tuples
*/
static PyObject *
-psutil_proc_num_fds(PyObject *self, PyObject *args)
-{
+psutil_proc_num_fds(PyObject *self, PyObject *args) {
long pid;
int cnt;
@@ -850,13 +793,12 @@ psutil_proc_num_fds(PyObject *self, PyObject *args)
* Return process current working directory.
*/
static PyObject *
-psutil_proc_cwd(PyObject *self, PyObject *args)
-{
+psutil_proc_cwd(PyObject *self, PyObject *args) {
long pid;
- PyObject *path = NULL;
struct kinfo_file *freep = NULL;
struct kinfo_file *kif;
struct kinfo_proc kipp;
+ PyObject *py_path = NULL;
int i, cnt;
@@ -874,8 +816,8 @@ psutil_proc_cwd(PyObject *self, PyObject *args)
for (i = 0; i < cnt; i++) {
kif = &freep[i];
if (kif->kf_fd == KF_FD_TYPE_CWD) {
- path = Py_BuildValue("s", kif->kf_path);
- if (!path)
+ py_path = Py_BuildValue("s", kif->kf_path);
+ if (!py_path)
goto error;
break;
}
@@ -885,14 +827,13 @@ psutil_proc_cwd(PyObject *self, PyObject *args)
* (lsof can't do that it either). Since this happens even
* as root we return an empty string instead of AccessDenied.
*/
- if (path == NULL) {
- path = Py_BuildValue("s", "");
- }
+ if (py_path == NULL)
+ py_path = Py_BuildValue("s", "");
free(freep);
- return path;
+ return py_path;
error:
- Py_XDECREF(path);
+ Py_XDECREF(py_path);
if (freep != NULL)
free(freep);
return NULL;
@@ -901,11 +842,9 @@ error:
// The tcplist fetching and walking is borrowed from netstat/inet.c.
static char *
-psutil_fetch_tcplist(void)
-{
+psutil_fetch_tcplist(void) {
char *buf;
size_t len;
- int error;
for (;;) {
if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) {
@@ -927,38 +866,37 @@ psutil_fetch_tcplist(void)
}
static int
-psutil_sockaddr_port(int family, struct sockaddr_storage *ss)
-{
+psutil_sockaddr_port(int family, struct sockaddr_storage *ss) {
struct sockaddr_in6 *sin6;
struct sockaddr_in *sin;
if (family == AF_INET) {
sin = (struct sockaddr_in *)ss;
return (sin->sin_port);
- } else {
+ }
+ else {
sin6 = (struct sockaddr_in6 *)ss;
return (sin6->sin6_port);
}
}
static void *
-psutil_sockaddr_addr(int family, struct sockaddr_storage *ss)
-{
+psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) {
struct sockaddr_in6 *sin6;
struct sockaddr_in *sin;
if (family == AF_INET) {
sin = (struct sockaddr_in *)ss;
return (&sin->sin_addr);
- } else {
+ }
+ else {
sin6 = (struct sockaddr_in6 *)ss;
return (&sin6->sin6_addr);
}
}
static socklen_t
-psutil_sockaddr_addrlen(int family)
-{
+psutil_sockaddr_addrlen(int family) {
if (family == AF_INET)
return (sizeof(struct in_addr));
else
@@ -967,8 +905,7 @@ psutil_sockaddr_addrlen(int family)
static int
psutil_sockaddr_matches(int family, int port, void *pcb_addr,
- struct sockaddr_storage *ss)
-{
+ struct sockaddr_storage *ss) {
if (psutil_sockaddr_port(family, ss) != port)
return (0);
return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr,
@@ -976,8 +913,7 @@ psutil_sockaddr_matches(int family, int port, void *pcb_addr,
}
static struct tcpcb *
-psutil_search_tcplist(char *buf, struct kinfo_file *kif)
-{
+psutil_search_tcplist(char *buf, struct kinfo_file *kif) {
struct tcpcb *tp;
struct inpcb *inp;
struct xinpgen *xig, *oxig;
@@ -1029,8 +965,7 @@ static int PSUTIL_CONN_NONE = 128;
* Return connections opened by process.
*/
static PyObject *
-psutil_proc_connections(PyObject *self, PyObject *args)
-{
+psutil_proc_connections(PyObject *self, PyObject *args) {
long pid;
int i, cnt;
@@ -1039,22 +974,20 @@ psutil_proc_connections(PyObject *self, PyObject *args)
char *tcplist = NULL;
struct tcpcb *tcp;
- PyObject *retList = PyList_New(0);
- PyObject *tuple = NULL;
- PyObject *laddr = NULL;
- PyObject *raddr = NULL;
- PyObject *af_filter = NULL;
- PyObject *type_filter = NULL;
- PyObject *_family = NULL;
- PyObject *_type = NULL;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
+ PyObject *py_laddr = NULL;
+ PyObject *py_raddr = NULL;
+ PyObject *py_af_filter = NULL;
+ PyObject *py_type_filter = NULL;
+ PyObject *py_family = NULL;
+ PyObject *py_type = NULL;
- if (retList == NULL) {
+ if (py_retlist == NULL)
return NULL;
- }
- if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) {
+ if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
goto error;
- }
- if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
+ if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
goto error;
}
@@ -1076,27 +1009,23 @@ psutil_proc_connections(PyObject *self, PyObject *args)
char lip[200], rip[200];
char path[PATH_MAX];
int inseq;
- tuple = NULL;
- laddr = NULL;
- raddr = NULL;
+ py_tuple = NULL;
+ py_laddr = NULL;
+ py_raddr = NULL;
kif = &freep[i];
- if (kif->kf_type == KF_TYPE_SOCKET)
- {
+ if (kif->kf_type == KF_TYPE_SOCKET) {
// apply filters
- _family = PyLong_FromLong((long)kif->kf_sock_domain);
- inseq = PySequence_Contains(af_filter, _family);
- Py_DECREF(_family);
- if (inseq == 0) {
+ py_family = PyLong_FromLong((long)kif->kf_sock_domain);
+ inseq = PySequence_Contains(py_af_filter, py_family);
+ Py_DECREF(py_family);
+ if (inseq == 0)
continue;
- }
- _type = PyLong_FromLong((long)kif->kf_sock_type);
- inseq = PySequence_Contains(type_filter, _type);
- Py_DECREF(_type);
- if (inseq == 0) {
+ py_type = PyLong_FromLong((long)kif->kf_sock_type);
+ inseq = PySequence_Contains(py_type_filter, py_type);
+ Py_DECREF(py_type);
+ if (inseq == 0)
continue;
- }
-
// IPv4 / IPv6 socket
if ((kif->kf_sock_domain == AF_INET) ||
(kif->kf_sock_domain == AF_INET6)) {
@@ -1127,29 +1056,29 @@ psutil_proc_connections(PyObject *self, PyObject *args)
&kif->kf_sa_peer));
// construct python tuple/list
- laddr = Py_BuildValue("(si)", lip, lport);
- if (!laddr)
+ py_laddr = Py_BuildValue("(si)", lip, lport);
+ if (!py_laddr)
goto error;
- if (rport != 0) {
- raddr = Py_BuildValue("(si)", rip, rport);
- }
- else {
- raddr = Py_BuildValue("()");
- }
- if (!raddr)
+ if (rport != 0)
+ py_raddr = Py_BuildValue("(si)", rip, rport);
+ else
+ py_raddr = Py_BuildValue("()");
+ if (!py_raddr)
goto error;
- tuple = Py_BuildValue("(iiiNNi)",
- kif->kf_fd,
- kif->kf_sock_domain,
- kif->kf_sock_type,
- laddr,
- raddr,
- state);
- if (!tuple)
+ py_tuple = Py_BuildValue(
+ "(iiiNNi)",
+ kif->kf_fd,
+ kif->kf_sock_domain,
+ kif->kf_sock_type,
+ py_laddr,
+ py_raddr,
+ state
+ );
+ if (!py_tuple)
goto error;
- if (PyList_Append(retList, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
// UNIX socket
else if (kif->kf_sock_domain == AF_UNIX) {
@@ -1158,34 +1087,36 @@ psutil_proc_connections(PyObject *self, PyObject *args)
sun = (struct sockaddr_un *)&kif->kf_sa_local;
snprintf(
path, sizeof(path), "%.*s",
- (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
+ (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
sun->sun_path);
- tuple = Py_BuildValue("(iiisOi)",
- kif->kf_fd,
- kif->kf_sock_domain,
- kif->kf_sock_type,
- path,
- Py_None,
- PSUTIL_CONN_NONE);
- if (!tuple)
+ py_tuple = Py_BuildValue(
+ "(iiisOi)",
+ kif->kf_fd,
+ kif->kf_sock_domain,
+ kif->kf_sock_type,
+ path,
+ Py_None,
+ PSUTIL_CONN_NONE
+ );
+ if (!py_tuple)
goto error;
- if (PyList_Append(retList, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
Py_INCREF(Py_None);
}
}
}
free(freep);
free(tcplist);
- return retList;
+ return py_retlist;
error:
- Py_XDECREF(tuple);
- Py_XDECREF(laddr);
- Py_XDECREF(raddr);
- Py_DECREF(retList);
+ Py_XDECREF(py_tuple);
+ Py_XDECREF(py_laddr);
+ Py_XDECREF(py_raddr);
+ Py_DECREF(py_retlist);
if (freep != NULL)
free(freep);
if (tcplist != NULL)
@@ -1198,8 +1129,7 @@ error:
* Return a Python list of tuple representing per-cpu times
*/
static PyObject *
-psutil_per_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_per_cpu_times(PyObject *self, PyObject *args) {
static int maxcpus;
int mib[2];
int ncpu;
@@ -1277,30 +1207,26 @@ void remove_spaces(char *str) {
* 'procstat' cmdline utility has been used as an example.
*/
static PyObject *
-psutil_proc_memory_maps(PyObject *self, PyObject *args)
-{
+psutil_proc_memory_maps(PyObject *self, PyObject *args) {
long pid;
int ptrwidth;
int i, cnt;
- char addr[30];
+ char addr[1000];
char perms[4];
const char *path;
struct kinfo_proc kp;
struct kinfo_vmentry *freep = NULL;
struct kinfo_vmentry *kve;
ptrwidth = 2 * sizeof(void *);
- PyObject *pytuple = NULL;
- PyObject *retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
+ PyObject *py_retlist = PyList_New(0);
- if (retlist == NULL) {
+ if (py_retlist == NULL)
return NULL;
- }
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
- }
- if (psutil_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_kinfo_proc(pid, &kp) == -1)
goto error;
- }
freep = kinfo_getvmmap(pid, &cnt);
if (freep == NULL) {
@@ -1308,7 +1234,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
goto error;
}
for (i = 0; i < cnt; i++) {
- pytuple = NULL;
+ py_tuple = NULL;
kve = &freep[i];
addr[0] = '\0';
perms[0] = '\0';
@@ -1324,43 +1250,43 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
if (strlen(kve->kve_path) == 0) {
switch (kve->kve_type) {
- case KVME_TYPE_NONE:
- path = "[none]";
- break;
- case KVME_TYPE_DEFAULT:
- path = "[default]";
- break;
- case KVME_TYPE_VNODE:
- path = "[vnode]";
- break;
- case KVME_TYPE_SWAP:
- path = "[swap]";
- break;
- case KVME_TYPE_DEVICE:
- path = "[device]";
- break;
- case KVME_TYPE_PHYS:
- path = "[phys]";
- break;
- case KVME_TYPE_DEAD:
- path = "[dead]";
- break;
- case KVME_TYPE_SG:
- path = "[sg]";
- break;
- case KVME_TYPE_UNKNOWN:
- path = "[unknown]";
- break;
- default:
- path = "[?]";
- break;
+ case KVME_TYPE_NONE:
+ path = "[none]";
+ break;
+ case KVME_TYPE_DEFAULT:
+ path = "[default]";
+ break;
+ case KVME_TYPE_VNODE:
+ path = "[vnode]";
+ break;
+ case KVME_TYPE_SWAP:
+ path = "[swap]";
+ break;
+ case KVME_TYPE_DEVICE:
+ path = "[device]";
+ break;
+ case KVME_TYPE_PHYS:
+ path = "[phys]";
+ break;
+ case KVME_TYPE_DEAD:
+ path = "[dead]";
+ break;
+ case KVME_TYPE_SG:
+ path = "[sg]";
+ break;
+ case KVME_TYPE_UNKNOWN:
+ path = "[unknown]";
+ break;
+ default:
+ path = "[?]";
+ break;
}
}
else {
path = kve->kve_path;
}
- pytuple = Py_BuildValue("sssiiii",
+ py_tuple = Py_BuildValue("sssiiii",
addr, // "start-end" address
perms, // "rwx" permissions
path, // path
@@ -1368,18 +1294,18 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
kve->kve_private_resident, // private
kve->kve_ref_count, // ref count
kve->kve_shadow_count); // shadow count
- if (!pytuple)
+ if (!py_tuple)
goto error;
- if (PyList_Append(retlist, pytuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(pytuple);
+ Py_DECREF(py_tuple);
}
free(freep);
- return retlist;
+ return py_retlist;
error:
- Py_XDECREF(pytuple);
- Py_DECREF(retlist);
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
if (freep != NULL)
free(freep);
return NULL;
@@ -1392,8 +1318,7 @@ error:
* for all partitions mounted on the system.
*/
static PyObject *
-psutil_disk_partitions(PyObject *self, PyObject *args)
-{
+psutil_disk_partitions(PyObject *self, PyObject *args) {
int num;
int i;
long len;
@@ -1499,17 +1424,16 @@ error:
* Return a Python list of named tuples with overall network I/O information
*/
static PyObject *
-psutil_net_io_counters(PyObject *self, PyObject *args)
-{
+psutil_net_io_counters(PyObject *self, PyObject *args) {
char *buf = NULL, *lim, *next;
struct if_msghdr *ifm;
int mib[6];
size_t len;
PyObject *py_retdict = PyDict_New();
PyObject *py_ifc_info = NULL;
+
if (py_retdict == NULL)
return NULL;
-
mib[0] = CTL_NET; // networking subsystem
mib[1] = PF_ROUTE; // type of information
mib[2] = 0; // protocol (IPPROTO_xxx)
@@ -1551,9 +1475,8 @@ psutil_net_io_counters(PyObject *self, PyObject *args)
// http://lists.freebsd.org/pipermail/freebsd-current/
// 2011-October/028752.html
// 'ifconfig -a' doesn't show them, nor do we.
- if (strncmp(ifc_name, "usbus", 5) == 0) {
+ if (strncmp(ifc_name, "usbus", 5) == 0)
continue;
- }
py_ifc_info = Py_BuildValue("(kkkkkkki)",
if2m->ifm_data.ifi_obytes,
@@ -1591,16 +1514,15 @@ error:
* Return a Python dict of tuples for disk I/O information
*/
static PyObject *
-psutil_disk_io_counters(PyObject *self, PyObject *args)
-{
+psutil_disk_io_counters(PyObject *self, PyObject *args) {
int i;
struct statinfo stats;
PyObject *py_retdict = PyDict_New();
PyObject *py_disk_info = NULL;
+
if (py_retdict == NULL)
return NULL;
-
if (devstat_checkversion(NULL) < 0) {
PyErr_Format(PyExc_RuntimeError, "devstat_checkversion() failed");
goto error;
@@ -1644,9 +1566,8 @@ psutil_disk_io_counters(PyObject *self, PyObject *args)
Py_DECREF(py_disk_info);
}
- if (stats.dinfo->mem_ptr) {
+ if (stats.dinfo->mem_ptr)
free(stats.dinfo->mem_ptr);
- }
free(stats.dinfo);
return py_retdict;
@@ -1663,12 +1584,11 @@ error:
* Return currently connected users as a list of tuples.
*/
static PyObject *
-psutil_users(PyObject *self, PyObject *args)
-{
- PyObject *ret_list = PyList_New(0);
- PyObject *tuple = NULL;
+psutil_users(PyObject *self, PyObject *args) {
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
- if (ret_list == NULL)
+ if (py_retlist == NULL)
return NULL;
#if __FreeBSD_version < 900000
@@ -1684,21 +1604,21 @@ psutil_users(PyObject *self, PyObject *args)
while (fread(&ut, sizeof(ut), 1, fp) == 1) {
if (*ut.ut_name == '\0')
continue;
- tuple = Py_BuildValue(
+ py_tuple = Py_BuildValue(
"(sssf)",
ut.ut_name, // username
ut.ut_line, // tty
ut.ut_host, // hostname
(float)ut.ut_time); // start time
- if (!tuple) {
+ if (!py_tuple) {
fclose(fp);
goto error;
}
- if (PyList_Append(ret_list, tuple)) {
+ if (PyList_Append(py_retlist, py_tuple)) {
fclose(fp);
goto error;
}
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
fclose(fp);
@@ -1708,7 +1628,7 @@ psutil_users(PyObject *self, PyObject *args)
while ((utx = getutxent()) != NULL) {
if (utx->ut_type != USER_PROCESS)
continue;
- tuple = Py_BuildValue(
+ py_tuple = Py_BuildValue(
"(sssf)",
utx->ut_user, // username
utx->ut_line, // tty
@@ -1716,24 +1636,24 @@ psutil_users(PyObject *self, PyObject *args)
(float)utx->ut_tv.tv_sec // start time
);
- if (!tuple) {
+ if (!py_tuple) {
endutxent();
goto error;
}
- if (PyList_Append(ret_list, tuple)) {
+ if (PyList_Append(py_retlist, py_tuple)) {
endutxent();
goto error;
}
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
endutxent();
#endif
- return ret_list;
+ return py_retlist;
error:
- Py_XDECREF(tuple);
- Py_DECREF(ret_list);
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
return NULL;
}
@@ -1748,8 +1668,7 @@ static struct xfile *psutil_xfiles;
static int psutil_nxfiles;
int
-psutil_populate_xfiles()
-{
+psutil_populate_xfiles() {
size_t len;
if ((psutil_xfiles = malloc(len = sizeof *psutil_xfiles)) == NULL) {
@@ -1776,48 +1695,49 @@ psutil_populate_xfiles()
}
int
-psutil_get_pid_from_sock(int sock_hash)
-{
+psutil_get_pid_from_sock(int sock_hash) {
struct xfile *xf;
int hash, n;
for (xf = psutil_xfiles, n = 0; n < psutil_nxfiles; ++n, ++xf) {
if (xf->xf_data == NULL)
continue;
hash = (int)((uintptr_t)xf->xf_data % HASHSIZE);
- if (sock_hash == hash) {
+ if (sock_hash == hash)
return xf->xf_pid;
- }
}
return -1;
}
-int psutil_gather_inet(int proto, PyObject *py_retlist)
-{
+// Reference:
+// https://gitorious.org/freebsd/freebsd/source/
+// f1d6f4778d2044502209708bc167c05f9aa48615:usr.bin/sockstat/sockstat.c
+int psutil_gather_inet(int proto, PyObject *py_retlist) {
struct xinpgen *xig, *exig;
struct xinpcb *xip;
struct xtcpcb *xtp;
struct inpcb *inp;
struct xsocket *so;
- struct sock *sock;
- const char *varname;
+ const char *varname = NULL;
size_t len, bufsize;
void *buf;
- int hash, retry, vflag, type;
+ int hash;
+ int retry;
+ int type;
- PyObject *tuple = NULL;
- PyObject *laddr = NULL;
- PyObject *raddr = NULL;
+ PyObject *py_tuple = NULL;
+ PyObject *py_laddr = NULL;
+ PyObject *py_raddr = NULL;
switch (proto) {
- case IPPROTO_TCP:
- varname = "net.inet.tcp.pcblist";
- type = SOCK_STREAM;
- break;
- case IPPROTO_UDP:
- varname = "net.inet.udp.pcblist";
- type = SOCK_DGRAM;
- break;
+ case IPPROTO_TCP:
+ varname = "net.inet.tcp.pcblist";
+ type = SOCK_STREAM;
+ break;
+ case IPPROTO_UDP:
+ varname = "net.inet.udp.pcblist";
+ type = SOCK_DGRAM;
+ break;
}
buf = NULL;
@@ -1826,10 +1746,8 @@ int psutil_gather_inet(int proto, PyObject *py_retlist)
do {
for (;;) {
buf = realloc(buf, bufsize);
- if (buf == NULL) {
- // XXX
- continue;
- }
+ if (buf == NULL)
+ continue; // XXX
len = bufsize;
if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
break;
@@ -1849,33 +1767,41 @@ int psutil_gather_inet(int proto, PyObject *py_retlist)
for (;;) {
+ int lport, rport, pid, status, family;
+
xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
if (xig >= exig)
break;
switch (proto) {
- case IPPROTO_TCP:
- xtp = (struct xtcpcb *)xig;
- if (xtp->xt_len != sizeof *xtp) {
- PyErr_Format(PyExc_RuntimeError, "struct xtcpcb size mismatch");
- goto error;
- }
- break;
- case IPPROTO_UDP:
- xip = (struct xinpcb *)xig;
- if (xip->xi_len != sizeof *xip) {
- PyErr_Format(PyExc_RuntimeError, "struct xinpcb size mismatch");
+ case IPPROTO_TCP:
+ xtp = (struct xtcpcb *)xig;
+ if (xtp->xt_len != sizeof *xtp) {
+ PyErr_Format(PyExc_RuntimeError,
+ "struct xtcpcb size mismatch");
+ goto error;
+ }
+ inp = &xtp->xt_inp;
+ so = &xtp->xt_socket;
+ status = xtp->xt_tp.t_state;
+ break;
+ case IPPROTO_UDP:
+ xip = (struct xinpcb *)xig;
+ if (xip->xi_len != sizeof *xip) {
+ PyErr_Format(PyExc_RuntimeError,
+ "struct xinpcb size mismatch");
+ goto error;
+ }
+ inp = &xip->xi_inp;
+ so = &xip->xi_socket;
+ status = PSUTIL_CONN_NONE;
+ break;
+ default:
+ PyErr_Format(PyExc_RuntimeError, "invalid proto");
goto error;
- }
- inp = &xip->xi_inp;
- so = &xip->xi_socket;
- break;
}
- inp = &xtp->xt_inp;
- so = &xtp->xt_socket;
char lip[200], rip[200];
- int family, lport, rport, pid, status;
hash = (int)((uintptr_t)so->xso_so % HASHSIZE);
pid = psutil_get_pid_from_sock(hash);
@@ -1883,7 +1809,6 @@ int psutil_gather_inet(int proto, PyObject *py_retlist)
continue;
lport = ntohs(inp->inp_lport);
rport = ntohs(inp->inp_fport);
- status = xtp->xt_tp.t_state;
if (inp->inp_vflag & INP_IPV4) {
family = AF_INET;
@@ -1897,64 +1822,63 @@ int psutil_gather_inet(int proto, PyObject *py_retlist)
}
// construct python tuple/list
- laddr = Py_BuildValue("(si)", lip, lport);
- if (!laddr)
+ py_laddr = Py_BuildValue("(si)", lip, lport);
+ if (!py_laddr)
goto error;
- if (rport != 0) {
- raddr = Py_BuildValue("(si)", rip, rport);
- }
- else {
- raddr = Py_BuildValue("()");
- }
- if (!raddr)
+ if (rport != 0)
+ py_raddr = Py_BuildValue("(si)", rip, rport);
+ else
+ py_raddr = Py_BuildValue("()");
+ if (!py_raddr)
goto error;
- tuple = Py_BuildValue("(iiiNNii)", -1, family, type, laddr, raddr,
- status, pid);
- if (!tuple)
+ py_tuple = Py_BuildValue("(iiiNNii)", -1, family, type, py_laddr,
+ py_raddr, status, pid);
+ if (!py_tuple)
goto error;
- if (PyList_Append(py_retlist, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
- }
+ Py_DECREF(py_tuple);
+ }
free(buf);
return 1;
error:
- Py_XDECREF(tuple);
- Py_XDECREF(laddr);
- Py_XDECREF(raddr);
+ Py_XDECREF(py_tuple);
+ Py_XDECREF(py_laddr);
+ Py_XDECREF(py_raddr);
free(buf);
return 0;
}
-int psutil_gather_unix(int proto, PyObject *py_retlist)
-{
+int psutil_gather_unix(int proto, PyObject *py_retlist) {
struct xunpgen *xug, *exug;
struct xunpcb *xup;
- struct sock *sock;
- const char *varname, *protoname;
- size_t len, bufsize;
+ const char *varname = NULL;
+ const char *protoname = NULL;
+ size_t len;
+ size_t bufsize;
void *buf;
- int hash, retry;
- int family, lport, rport, pid;
+ int hash;
+ int retry;
+ int pid;
struct sockaddr_un *sun;
char path[PATH_MAX];
- PyObject *tuple = NULL;
- PyObject *laddr = NULL;
- PyObject *raddr = NULL;
+ PyObject *py_tuple = NULL;
+ PyObject *py_laddr = NULL;
+ PyObject *py_raddr = NULL;
switch (proto) {
- case SOCK_STREAM:
- varname = "net.local.stream.pcblist";
- protoname = "stream";
- break;
- case SOCK_DGRAM:
- varname = "net.local.dgram.pcblist";
- protoname = "dgram";
- break;
+ case SOCK_STREAM:
+ varname = "net.local.stream.pcblist";
+ protoname = "stream";
+ break;
+ case SOCK_DGRAM:
+ varname = "net.local.dgram.pcblist";
+ protoname = "dgram";
+ break;
}
buf = NULL;
@@ -1991,9 +1915,8 @@ int psutil_gather_unix(int proto, PyObject *py_retlist)
if (xug >= exug)
break;
xup = (struct xunpcb *)xug;
- if (xup->xu_len != sizeof *xup) {
+ if (xup->xu_len != sizeof *xup)
goto error;
- }
hash = (int)((uintptr_t) xup->xu_socket.xso_so % HASHSIZE);
pid = psutil_get_pid_from_sock(hash);
@@ -2002,16 +1925,16 @@ int psutil_gather_unix(int proto, PyObject *py_retlist)
sun = (struct sockaddr_un *)&xup->xu_addr;
snprintf(path, sizeof(path), "%.*s",
- (sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
+ (int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
sun->sun_path);
- tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path, Py_None,
- PSUTIL_CONN_NONE, pid);
- if (!tuple)
+ py_tuple = Py_BuildValue("(iiisOii)", -1, AF_UNIX, proto, path,
+ Py_None, PSUTIL_CONN_NONE, pid);
+ if (!py_tuple)
goto error;
- if (PyList_Append(py_retlist, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
Py_INCREF(Py_None);
}
@@ -2019,9 +1942,9 @@ int psutil_gather_unix(int proto, PyObject *py_retlist)
return 1;
error:
- Py_XDECREF(tuple);
- Py_XDECREF(laddr);
- Py_XDECREF(raddr);
+ Py_XDECREF(py_tuple);
+ Py_XDECREF(py_laddr);
+ Py_XDECREF(py_raddr);
free(buf);
return 0;
}
@@ -2031,15 +1954,13 @@ error:
* Return system-wide open connections.
*/
static PyObject*
-psutil_net_connections(PyObject* self, PyObject* args)
-{
- PyObject *af_filter = NULL;
- PyObject *type_filter = NULL;
+psutil_net_connections(PyObject* self, PyObject* args) {
PyObject *py_retlist = PyList_New(0);
+ if (py_retlist == NULL)
+ return NULL;
if (psutil_populate_xfiles() != 1)
goto error;
-
if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0)
goto error;
if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0)
@@ -2064,8 +1985,7 @@ error:
* Reference: http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c
*/
static PyObject*
-psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args)
-{
+psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args) {
long pid;
int ret;
int i;
@@ -2073,10 +1993,8 @@ psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args)
PyObject* py_retlist;
PyObject* py_cpu_num;
- if (!PyArg_ParseTuple(args, "i", &pid)) {
+ if (!PyArg_ParseTuple(args, "i", &pid))
return NULL;
- }
-
ret = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid,
sizeof(mask), &mask);
if (ret != 0) {
@@ -2112,8 +2030,7 @@ error:
* Reference: http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c
*/
static PyObject *
-psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
long pid;
int i;
int seq_len;
@@ -2122,14 +2039,12 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
PyObject *py_cpu_set;
PyObject *py_cpu_seq = NULL;
- if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) {
- goto error;
- }
+ if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set))
+ return NULL;
py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer");
- if (!py_cpu_seq) {
- goto error;
- }
+ if (!py_cpu_seq)
+ return NULL;
seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq);
// calculate the mask
@@ -2141,9 +2056,8 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
#else
long value = PyInt_AsLong(item);
#endif
- if (value == -1 && PyErr_Occurred()) {
+ if (value == -1 && PyErr_Occurred())
goto error;
- }
CPU_SET(value, &cpu_set);
}
@@ -2169,8 +2083,8 @@ error:
* define the psutil C module methods and initialize the module.
*/
static PyMethodDef
-PsutilMethods[] =
-{
+PsutilMethods[] = {
+
// --- per-process functions
{"proc_name", psutil_proc_name, METH_VARARGS,
@@ -2332,9 +2246,8 @@ void init_psutil_bsd(void)
PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
- if (module == NULL) {
+ if (module == NULL)
INITERROR;
- }
#if PY_MAJOR_VERSION >= 3
return module;
#endif
diff --git a/psutil/_psutil_linux.c b/psutil/_psutil_linux.c
index 98255445..b582a870 100644
--- a/psutil/_psutil_linux.c
+++ b/psutil/_psutil_linux.c
@@ -19,6 +19,20 @@
#include <linux/version.h>
#include <sys/syscall.h>
#include <sys/sysinfo.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+
+// see: https://github.com/giampaolo/psutil/issues/659
+#ifdef PSUTIL_ETHTOOL_MISSING_TYPES
+ #include <linux/types.h>
+ typedef __u64 u64;
+ typedef __u32 u32;
+ typedef __u16 u16;
+ typedef __u8 u8;
+#endif
+#include <linux/ethtool.h>
#include "_psutil_linux.h"
@@ -46,15 +60,19 @@ enum {
IOPRIO_WHO_PROCESS = 1,
};
+// May happen on old RedHat versions, see:
+// https://github.com/giampaolo/psutil/issues/607
+#ifndef DUPLEX_UNKNOWN
+ #define DUPLEX_UNKNOWN 0xff
+#endif
+
static inline int
-ioprio_get(int which, int who)
-{
+ioprio_get(int which, int who) {
return syscall(__NR_ioprio_get, which, who);
}
static inline int
-ioprio_set(int which, int who, int ioprio)
-{
+ioprio_set(int which, int who, int ioprio) {
return syscall(__NR_ioprio_set, which, who, ioprio);
}
@@ -70,17 +88,14 @@ ioprio_set(int which, int who, int ioprio)
* Return a (ioclass, iodata) Python tuple representing process I/O priority.
*/
static PyObject *
-psutil_proc_ioprio_get(PyObject *self, PyObject *args)
-{
+psutil_proc_ioprio_get(PyObject *self, PyObject *args) {
long pid;
int ioprio, ioclass, iodata;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
- if (ioprio == -1) {
+ if (ioprio == -1)
return PyErr_SetFromErrno(PyExc_OSError);
- }
ioclass = IOPRIO_PRIO_CLASS(ioprio);
iodata = IOPRIO_PRIO_DATA(ioprio);
return Py_BuildValue("ii", ioclass, iodata);
@@ -93,20 +108,17 @@ psutil_proc_ioprio_get(PyObject *self, PyObject *args)
* or 0. iodata goes from 0 to 7 depending on ioclass specified.
*/
static PyObject *
-psutil_proc_ioprio_set(PyObject *self, PyObject *args)
-{
+psutil_proc_ioprio_set(PyObject *self, PyObject *args) {
long pid;
int ioprio, ioclass, iodata;
int retval;
- if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata)) {
+ if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata))
return NULL;
- }
ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
- if (retval == -1) {
+ if (retval == -1)
return PyErr_SetFromErrno(PyExc_OSError);
- }
Py_RETURN_NONE;
}
#endif
@@ -119,21 +131,19 @@ psutil_proc_ioprio_set(PyObject *self, PyObject *args)
* 'soft' and 'hard' args must be provided.
*/
static PyObject *
-psutil_linux_prlimit(PyObject *self, PyObject *args)
-{
+psutil_linux_prlimit(PyObject *self, PyObject *args) {
long pid;
int ret, resource;
struct rlimit old, new;
struct rlimit *newp = NULL;
- PyObject *soft = NULL;
- PyObject *hard = NULL;
+ PyObject *py_soft = NULL;
+ PyObject *py_hard = NULL;
- if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &soft, &hard)) {
+ if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &py_soft, &py_hard))
return NULL;
- }
// get
- if (soft == NULL && hard == NULL) {
+ if (py_soft == NULL && py_hard == NULL) {
ret = prlimit(pid, resource, NULL, &old);
if (ret == -1)
return PyErr_SetFromErrno(PyExc_OSError);
@@ -150,17 +160,17 @@ psutil_linux_prlimit(PyObject *self, PyObject *args)
// set
else {
#if defined(PSUTIL_HAVE_LARGEFILE_SUPPORT)
- new.rlim_cur = PyLong_AsLongLong(soft);
+ new.rlim_cur = PyLong_AsLongLong(py_soft);
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
- new.rlim_max = PyLong_AsLongLong(hard);
+ new.rlim_max = PyLong_AsLongLong(py_hard);
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
#else
- new.rlim_cur = PyLong_AsLong(soft);
+ new.rlim_cur = PyLong_AsLong(py_soft);
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
- new.rlim_max = PyLong_AsLong(hard);
+ new.rlim_max = PyLong_AsLong(py_hard);
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
return NULL;
#endif
@@ -179,8 +189,7 @@ psutil_linux_prlimit(PyObject *self, PyObject *args)
* mount point and filesystem type
*/
static PyObject *
-psutil_disk_partitions(PyObject *self, PyObject *args)
-{
+psutil_disk_partitions(PyObject *self, PyObject *args) {
FILE *file = NULL;
struct mntent *entry;
PyObject *py_retlist = PyList_New(0);
@@ -230,13 +239,11 @@ error:
* A wrapper around sysinfo(), return system memory usage statistics.
*/
static PyObject *
-psutil_linux_sysinfo(PyObject *self, PyObject *args)
-{
+psutil_linux_sysinfo(PyObject *self, PyObject *args) {
struct sysinfo info;
- if (sysinfo(&info) != 0) {
- return PyErr_SetFromErrno(PyExc_OSError);
- }
+ if (sysinfo(&info) != 0)
+ return PyErr_SetFromErrno(PyExc_OSError);
// note: boot time might also be determined from here
return Py_BuildValue(
"(KKKKKK)",
@@ -258,18 +265,15 @@ psutil_linux_sysinfo(PyObject *self, PyObject *args)
#ifdef CPU_ALLOC
static PyObject *
-psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
int cpu, ncpus, count, cpucount_s;
long pid;
size_t setsize;
cpu_set_t *mask = NULL;
- PyObject *res = NULL;
+ PyObject *py_list = NULL;
- if (!PyArg_ParseTuple(args, "i", &pid)) {
+ if (!PyArg_ParseTuple(args, "i", &pid))
return NULL;
- }
-
ncpus = NCPUS_START;
while (1) {
setsize = CPU_ALLOC_SIZE(ncpus);
@@ -289,8 +293,8 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
ncpus = ncpus * 2;
}
- res = PyList_New(0);
- if (res == NULL)
+ py_list = PyList_New(0);
+ if (py_list == NULL)
goto error;
cpucount_s = CPU_COUNT_S(setsize, mask);
@@ -301,23 +305,23 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
#else
PyObject *cpu_num = PyInt_FromLong(cpu);
#endif
- --count;
if (cpu_num == NULL)
goto error;
- if (PyList_Append(res, cpu_num)) {
+ if (PyList_Append(py_list, cpu_num)) {
Py_DECREF(cpu_num);
goto error;
}
Py_DECREF(cpu_num);
+ --count;
}
}
CPU_FREE(mask);
- return res;
+ return py_list;
error:
if (mask)
CPU_FREE(mask);
- Py_XDECREF(res);
+ Py_XDECREF(py_list);
return NULL;
}
#else
@@ -327,25 +331,23 @@ error:
* Alternative implementation in case CPU_ALLOC is not defined.
*/
static PyObject *
-psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
cpu_set_t cpuset;
unsigned int len = sizeof(cpu_set_t);
long pid;
int i;
- PyObject* py_retlist;
- PyObject *py_cpu_num;
+ PyObject* py_retlist = NULL;
+ PyObject *py_cpu_num = NULL;
- if (!PyArg_ParseTuple(args, "i", &pid)) {
+ if (!PyArg_ParseTuple(args, "i", &pid))
return NULL;
- }
-
CPU_ZERO(&cpuset);
- if (sched_getaffinity(pid, len, &cpuset) < 0) {
+ if (sched_getaffinity(pid, len, &cpuset) < 0)
return PyErr_SetFromErrno(PyExc_OSError);
- }
py_retlist = PyList_New(0);
+ if (py_retlist == NULL)
+ goto error;
for (i = 0; i < CPU_SETSIZE; ++i) {
if (CPU_ISSET(i, &cpuset)) {
py_cpu_num = Py_BuildValue("i", i);
@@ -353,6 +355,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
goto error;
if (PyList_Append(py_retlist, py_cpu_num))
goto error;
+ Py_DECREF(py_cpu_num);
}
}
@@ -369,8 +372,7 @@ error:
* Set process CPU affinity; expects a bitmask
*/
static PyObject *
-psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
cpu_set_t cpu_set;
size_t len;
long pid;
@@ -378,9 +380,8 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
PyObject *py_cpu_set;
PyObject *py_cpu_seq = NULL;
- if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set)) {
- goto error;
- }
+ if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set))
+ return NULL;
if (!PySequence_Check(py_cpu_set)) {
PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s",
@@ -389,9 +390,8 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
}
py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer");
- if (!py_cpu_seq) {
+ if (!py_cpu_seq)
goto error;
- }
seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq);
CPU_ZERO(&cpu_set);
for (i = 0; i < seq_len; i++) {
@@ -401,9 +401,8 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
#else
long value = PyInt_AsLong(item);
#endif
- if (value == -1 && PyErr_Occurred()) {
+ if (value == -1 && PyErr_Occurred())
goto error;
- }
CPU_SET(value, &cpu_set);
}
@@ -417,10 +416,8 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
Py_RETURN_NONE;
error:
- if (py_cpu_seq != NULL) {
+ if (py_cpu_seq != NULL)
Py_DECREF(py_cpu_seq);
- }
-
return NULL;
}
@@ -429,55 +426,134 @@ error:
* Return currently connected users as a list of tuples.
*/
static PyObject *
-psutil_users(PyObject *self, PyObject *args)
-{
- PyObject *ret_list = PyList_New(0);
- PyObject *tuple = NULL;
- PyObject *user_proc = NULL;
+psutil_users(PyObject *self, PyObject *args) {
struct utmp *ut;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
+ PyObject *py_user_proc = NULL;
- if (ret_list == NULL)
+ if (py_retlist == NULL)
return NULL;
setutent();
while (NULL != (ut = getutent())) {
- tuple = NULL;
- user_proc = NULL;
+ py_tuple = NULL;
+ py_user_proc = NULL;
if (ut->ut_type == USER_PROCESS)
- user_proc = Py_True;
+ py_user_proc = Py_True;
else
- user_proc = Py_False;
- tuple = Py_BuildValue(
+ py_user_proc = Py_False;
+ py_tuple = Py_BuildValue(
"(sssfO)",
ut->ut_user, // username
ut->ut_line, // tty
ut->ut_host, // hostname
(float)ut->ut_tv.tv_sec, // tstamp
- user_proc // (bool) user process
+ py_user_proc // (bool) user process
);
- if (! tuple)
+ if (! py_tuple)
goto error;
- if (PyList_Append(ret_list, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
endutent();
- return ret_list;
+ return py_retlist;
error:
- Py_XDECREF(tuple);
- Py_XDECREF(user_proc);
- Py_DECREF(ret_list);
+ Py_XDECREF(py_tuple);
+ Py_XDECREF(py_user_proc);
+ Py_DECREF(py_retlist);
endutent();
return NULL;
}
/*
+ * Return stats about a particular network
+ * interface. References:
+ * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py
+ * http://www.i-scream.org/libstatgrab/
+ */
+static PyObject*
+psutil_net_if_stats(PyObject* self, PyObject* args) {
+ char *nic_name;
+ int sock = 0;
+ int ret;
+ int duplex;
+ int speed;
+ int mtu;
+ struct ifreq ifr;
+ struct ethtool_cmd ethcmd;
+ PyObject *py_is_up = NULL;
+ PyObject *py_retlist = NULL;
+
+ if (! PyArg_ParseTuple(args, "s", &nic_name))
+ return NULL;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == -1)
+ goto error;
+ strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
+
+ // is up?
+ ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+ if (ret == -1)
+ goto error;
+ if ((ifr.ifr_flags & IFF_UP) != 0)
+ py_is_up = Py_True;
+ else
+ py_is_up = Py_False;
+ Py_INCREF(py_is_up);
+
+ // MTU
+ ret = ioctl(sock, SIOCGIFMTU, &ifr);
+ if (ret == -1)
+ goto error;
+ mtu = ifr.ifr_mtu;
+
+ // duplex and speed
+ memset(&ethcmd, 0, sizeof ethcmd);
+ ethcmd.cmd = ETHTOOL_GSET;
+ ifr.ifr_data = (void *)&ethcmd;
+ ret = ioctl(sock, SIOCETHTOOL, &ifr);
+
+ if (ret != -1) {
+ duplex = ethcmd.duplex;
+ speed = ethcmd.speed;
+ }
+ else {
+ if (errno == EOPNOTSUPP) {
+ // we typically get here in case of wi-fi cards
+ duplex = DUPLEX_UNKNOWN;
+ speed = 0;
+ }
+ else {
+ goto error;
+ }
+ }
+
+ close(sock);
+ py_retlist = Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu);
+ if (!py_retlist)
+ goto error;
+ Py_DECREF(py_is_up);
+ return py_retlist;
+
+error:
+ Py_XDECREF(py_is_up);
+ if (sock != 0)
+ close(sock);
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+}
+
+
+/*
* Define the psutil C module methods and initialize the module.
*/
static PyMethodDef
-PsutilMethods[] =
-{
+PsutilMethods[] = {
+
// --- per-process functions
#if PSUTIL_HAVE_IOPRIO
@@ -498,6 +574,8 @@ PsutilMethods[] =
"device, mount point and filesystem type"},
{"users", psutil_users, METH_VARARGS,
"Return currently connected users as a list of tuples"},
+ {"net_if_stats", psutil_net_if_stats, METH_VARARGS,
+ "Return NIC stats (isup, duplex, speed, mtu)"},
// --- linux specific
@@ -559,16 +637,15 @@ PyMODINIT_FUNC PyInit__psutil_linux(void)
void init_psutil_linux(void)
#endif
{
+ PyObject *v;
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
#endif
-
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
#if PSUTIL_HAVE_PRLIMIT
- PyModule_AddIntConstant(module, "RLIM_INFINITY", RLIM_INFINITY);
PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS);
PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE);
PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU);
@@ -580,6 +657,19 @@ void init_psutil_linux(void)
PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC);
PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS);
PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK);
+
+#if defined(HAVE_LONG_LONG)
+ if (sizeof(RLIM_INFINITY) > sizeof(long)) {
+ v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY);
+ } else
+#endif
+ {
+ v = PyLong_FromLong((long) RLIM_INFINITY);
+ }
+ if (v) {
+ PyModule_AddObject(module, "RLIM_INFINITY", v);
+ }
+
#ifdef RLIMIT_MSGQUEUE
PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE);
#endif
@@ -596,10 +686,12 @@ void init_psutil_linux(void)
PyModule_AddIntConstant(module, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING);
#endif
#endif
+ PyModule_AddIntConstant(module, "DUPLEX_HALF", DUPLEX_HALF);
+ PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL);
+ PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN);
- if (module == NULL) {
+ if (module == NULL)
INITERROR;
- }
#if PY_MAJOR_VERSION >= 3
return module;
#endif
diff --git a/psutil/_psutil_linux.h b/psutil/_psutil_linux.h
index 04ffec3d..ec6a3387 100644
--- a/psutil/_psutil_linux.h
+++ b/psutil/_psutil_linux.h
@@ -18,3 +18,4 @@ static PyObject* psutil_proc_ioprio_get(PyObject* self, PyObject* args);
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
static PyObject* psutil_linux_sysinfo(PyObject* self, PyObject* args);
static PyObject* psutil_users(PyObject* self, PyObject* args);
+static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c
index 2f1dd3f6..53ad668d 100644
--- a/psutil/_psutil_osx.c
+++ b/psutil/_psutil_osx.c
@@ -48,8 +48,7 @@
* A wrapper around host_statistics() invoked with HOST_VM_INFO.
*/
int
-psutil_sys_vminfo(vm_statistics_data_t *vmstat)
-{
+psutil_sys_vminfo(vm_statistics_data_t *vmstat) {
kern_return_t ret;
mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t);
mach_port_t mport = mach_host_self();
@@ -69,16 +68,15 @@ psutil_sys_vminfo(vm_statistics_data_t *vmstat)
* Return a Python list of all the PIDs running on the system.
*/
static PyObject *
-psutil_pids(PyObject *self, PyObject *args)
-{
+psutil_pids(PyObject *self, PyObject *args) {
kinfo_proc *proclist = NULL;
kinfo_proc *orig_address = NULL;
size_t num_processes;
size_t idx;
- PyObject *pid = NULL;
- PyObject *retlist = PyList_New(0);
+ PyObject *py_pid = NULL;
+ PyObject *py_retlist = PyList_New(0);
- if (retlist == NULL)
+ if (py_retlist == NULL)
return NULL;
if (psutil_get_proc_list(&proclist, &num_processes) != 0) {
@@ -91,21 +89,21 @@ psutil_pids(PyObject *self, PyObject *args)
// save the address of proclist so we can free it later
orig_address = proclist;
for (idx = 0; idx < num_processes; idx++) {
- pid = Py_BuildValue("i", proclist->kp_proc.p_pid);
- if (!pid)
+ py_pid = Py_BuildValue("i", proclist->kp_proc.p_pid);
+ if (! py_pid)
goto error;
- if (PyList_Append(retlist, pid))
+ if (PyList_Append(py_retlist, py_pid))
goto error;
- Py_DECREF(pid);
+ Py_DECREF(py_pid);
proclist++;
}
free(orig_address);
}
- return retlist;
+ return py_retlist;
error:
- Py_XDECREF(pid);
- Py_DECREF(retlist);
+ Py_XDECREF(py_pid);
+ Py_DECREF(py_retlist);
if (orig_address != NULL)
free(orig_address);
return NULL;
@@ -116,16 +114,13 @@ error:
* Return process name from kinfo_proc as a Python string.
*/
static PyObject *
-psutil_proc_name(PyObject *self, PyObject *args)
-{
+psutil_proc_name(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_get_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_get_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("s", kp.kp_proc.p_comm);
}
@@ -134,14 +129,12 @@ psutil_proc_name(PyObject *self, PyObject *args)
* Return process current working directory.
*/
static PyObject *
-psutil_proc_cwd(PyObject *self, PyObject *args)
-{
+psutil_proc_cwd(PyObject *self, PyObject *args) {
long pid;
struct proc_vnodepathinfo pathinfo;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
if (! psutil_proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, &pathinfo,
sizeof(pathinfo)))
@@ -156,23 +149,19 @@ psutil_proc_cwd(PyObject *self, PyObject *args)
* Return path of the process executable.
*/
static PyObject *
-psutil_proc_exe(PyObject *self, PyObject *args)
-{
+psutil_proc_exe(PyObject *self, PyObject *args) {
long pid;
char buf[PATH_MAX];
int ret;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
ret = proc_pidpath(pid, &buf, sizeof(buf));
if (ret == 0) {
- if (! psutil_pid_exists(pid)) {
+ if (! psutil_pid_exists(pid))
return NoSuchProcess();
- }
- else {
+ else
return AccessDenied();
- }
}
return Py_BuildValue("s", buf);
}
@@ -182,18 +171,16 @@ psutil_proc_exe(PyObject *self, PyObject *args)
* Return process cmdline as a Python list of cmdline arguments.
*/
static PyObject *
-psutil_proc_cmdline(PyObject *self, PyObject *args)
-{
+psutil_proc_cmdline(PyObject *self, PyObject *args) {
long pid;
- PyObject *arglist = NULL;
+ PyObject *py_retlist = NULL;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
// get the commandline, defined in arch/osx/process_info.c
- arglist = psutil_get_arg_list(pid);
- return arglist;
+ py_retlist = psutil_get_cmdline(pid);
+ return py_retlist;
}
@@ -201,16 +188,13 @@ psutil_proc_cmdline(PyObject *self, PyObject *args)
* Return process parent pid from kinfo_proc as a Python integer.
*/
static PyObject *
-psutil_proc_ppid(PyObject *self, PyObject *args)
-{
+psutil_proc_ppid(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_get_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_get_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("l", (long)kp.kp_eproc.e_ppid);
}
@@ -219,16 +203,13 @@ psutil_proc_ppid(PyObject *self, PyObject *args)
* Return process real uid from kinfo_proc as a Python integer.
*/
static PyObject *
-psutil_proc_uids(PyObject *self, PyObject *args)
-{
+psutil_proc_uids(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_get_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_get_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("lll",
(long)kp.kp_eproc.e_pcred.p_ruid,
(long)kp.kp_eproc.e_ucred.cr_uid,
@@ -240,16 +221,13 @@ psutil_proc_uids(PyObject *self, PyObject *args)
* Return process real group id from ki_comm as a Python integer.
*/
static PyObject *
-psutil_proc_gids(PyObject *self, PyObject *args)
-{
+psutil_proc_gids(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_get_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_get_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("lll",
(long)kp.kp_eproc.e_pcred.p_rgid,
(long)kp.kp_eproc.e_ucred.cr_groups[0],
@@ -261,16 +239,13 @@ psutil_proc_gids(PyObject *self, PyObject *args)
* Return process controlling terminal number as an integer.
*/
static PyObject *
-psutil_proc_tty_nr(PyObject *self, PyObject *args)
-{
+psutil_proc_tty_nr(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_get_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_get_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("i", kp.kp_eproc.e_tdev);
}
@@ -280,8 +255,7 @@ psutil_proc_tty_nr(PyObject *self, PyObject *args)
* 'procstat' cmdline utility has been used as an example.
*/
static PyObject *
-psutil_proc_memory_maps(PyObject *self, PyObject *args)
-{
+psutil_proc_memory_maps(PyObject *self, PyObject *args) {
char buf[PATH_MAX];
char addr_str[34];
char perms[8];
@@ -299,9 +273,8 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
if (py_list == NULL)
return NULL;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
- }
err = task_for_pid(mach_task_self(), pid, &task);
@@ -324,11 +297,8 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
err = vm_region_recurse_64(task, &address, &size, &depth,
(vm_region_info_64_t)&info, &count);
-
- if (err == KERN_INVALID_ADDRESS) {
+ if (err == KERN_INVALID_ADDRESS)
break;
- }
-
if (info.is_submap) {
depth++;
}
@@ -356,32 +326,30 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
if (strlen(buf) == 0) {
switch (info.share_mode) {
- /*
- case SM_LARGE_PAGE:
- // Treat SM_LARGE_PAGE the same as SM_PRIVATE
- // since they are not shareable and are wired.
- */
- case SM_COW:
- strcpy(buf, "[cow]");
- break;
- case SM_PRIVATE:
- strcpy(buf, "[prv]");
- break;
- case SM_EMPTY:
- strcpy(buf, "[nul]");
- break;
- case SM_SHARED:
- case SM_TRUESHARED:
- strcpy(buf, "[shm]");
- break;
- case SM_PRIVATE_ALIASED:
- strcpy(buf, "[ali]");
- break;
- case SM_SHARED_ALIASED:
- strcpy(buf, "[s/a]");
- break;
- default:
- strcpy(buf, "[???]");
+ // case SM_LARGE_PAGE:
+ // Treat SM_LARGE_PAGE the same as SM_PRIVATE
+ // since they are not shareable and are wired.
+ case SM_COW:
+ strcpy(buf, "[cow]");
+ break;
+ case SM_PRIVATE:
+ strcpy(buf, "[prv]");
+ break;
+ case SM_EMPTY:
+ strcpy(buf, "[nul]");
+ break;
+ case SM_SHARED:
+ case SM_TRUESHARED:
+ strcpy(buf, "[shm]");
+ break;
+ case SM_PRIVATE_ALIASED:
+ strcpy(buf, "[ali]");
+ break;
+ case SM_SHARED_ALIASED:
+ strcpy(buf, "[s/a]");
+ break;
+ default:
+ strcpy(buf, "[???]");
}
}
@@ -427,23 +395,27 @@ error:
* XXX this could be shared with BSD.
*/
static PyObject *
-psutil_cpu_count_logical(PyObject *self, PyObject *args)
-{
+psutil_cpu_count_logical(PyObject *self, PyObject *args) {
+ /*
int mib[2];
int ncpu;
size_t len;
-
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(ncpu);
- if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
- // mimic os.cpu_count()
- Py_RETURN_NONE;
- }
- else {
+ if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1)
+ Py_RETURN_NONE; // mimic os.cpu_count()
+ else
return Py_BuildValue("i", ncpu);
- }
+ */
+ int num;
+ size_t size = sizeof(int);
+
+ if (sysctlbyname("hw.logicalcpu", &num, &size, NULL, 2))
+ Py_RETURN_NONE; // mimic os.cpu_count()
+ else
+ return Py_BuildValue("i", num);
}
@@ -451,15 +423,14 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args)
* Return the number of physical CPUs in the system.
*/
static PyObject *
-psutil_cpu_count_phys(PyObject *self, PyObject *args)
-{
+psutil_cpu_count_phys(PyObject *self, PyObject *args) {
int num;
size_t size = sizeof(int);
- if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0)) {
- // mimic os.cpu_count()
- Py_RETURN_NONE;
- }
- return Py_BuildValue("i", num);
+
+ if (sysctlbyname("hw.physicalcpu", &num, &size, NULL, 0))
+ Py_RETURN_NONE; // mimic os.cpu_count()
+ else
+ return Py_BuildValue("i", num);
}
@@ -469,16 +440,14 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args)
* Return a Python tuple (user_time, kernel_time)
*/
static PyObject *
-psutil_proc_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_times(PyObject *self, PyObject *args) {
long pid;
struct proc_taskinfo pti;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) {
+ if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti)))
return NULL;
- }
return Py_BuildValue("(dd)",
(float)pti.pti_total_user / 1000000000.0,
(float)pti.pti_total_system / 1000000000.0);
@@ -490,16 +459,13 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args)
* seconds since the epoch.
*/
static PyObject *
-psutil_proc_create_time(PyObject *self, PyObject *args)
-{
+psutil_proc_create_time(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_get_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_get_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("d", TV2DOUBLE(kp.kp_proc.p_starttime));
}
@@ -508,17 +474,14 @@ psutil_proc_create_time(PyObject *self, PyObject *args)
* Return extended memory info about a process.
*/
static PyObject *
-psutil_proc_memory_info(PyObject *self, PyObject *args)
-{
+psutil_proc_memory_info(PyObject *self, PyObject *args) {
long pid;
struct proc_taskinfo pti;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) {
+ if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti)))
return NULL;
- }
-
// Note: determining other memory stats on OSX is a mess:
// http://www.opensource.apple.com/source/top/top-67/libtop.c?txt
// I just give up...
@@ -538,16 +501,14 @@ psutil_proc_memory_info(PyObject *self, PyObject *args)
* Return number of threads used by process as a Python integer.
*/
static PyObject *
-psutil_proc_num_threads(PyObject *self, PyObject *args)
-{
+psutil_proc_num_threads(PyObject *self, PyObject *args) {
long pid;
struct proc_taskinfo pti;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) {
+ if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti)))
return NULL;
- }
return Py_BuildValue("k", pti.pti_threadnum);
}
@@ -556,16 +517,14 @@ psutil_proc_num_threads(PyObject *self, PyObject *args)
* Return the number of context switches performed by process.
*/
static PyObject *
-psutil_proc_num_ctx_switches(PyObject *self, PyObject *args)
-{
+psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) {
long pid;
struct proc_taskinfo pti;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti))) {
+ if (! psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, &pti, sizeof(pti)))
return NULL;
- }
// unvoluntary value seems not to be available;
// pti.pti_csw probably refers to the sum of the two (getrusage()
// numbers seems to confirm this theory).
@@ -577,18 +536,18 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args)
* Return system virtual memory stats
*/
static PyObject *
-psutil_virtual_mem(PyObject *self, PyObject *args)
-{
+psutil_virtual_mem(PyObject *self, PyObject *args) {
int mib[2];
uint64_t total;
size_t len = sizeof(total);
vm_statistics_data_t vm;
int pagesize = getpagesize();
-
// physical mem
mib[0] = CTL_HW;
mib[1] = HW_MEMSIZE;
+
+ // This is also available as sysctlbyname("hw.memsize").
if (sysctl(mib, 2, &total, &len, NULL, 0)) {
if (errno != 0)
PyErr_SetFromErrno(PyExc_OSError);
@@ -598,9 +557,8 @@ psutil_virtual_mem(PyObject *self, PyObject *args)
}
// vm
- if (!psutil_sys_vminfo(&vm)) {
+ if (!psutil_sys_vminfo(&vm))
return NULL;
- }
return Py_BuildValue(
"KKKKK",
@@ -617,8 +575,7 @@ psutil_virtual_mem(PyObject *self, PyObject *args)
* Return stats about swap memory.
*/
static PyObject *
-psutil_swap_mem(PyObject *self, PyObject *args)
-{
+psutil_swap_mem(PyObject *self, PyObject *args) {
int mib[2];
size_t size;
struct xsw_usage totals;
@@ -635,9 +592,8 @@ psutil_swap_mem(PyObject *self, PyObject *args)
PyErr_Format(PyExc_RuntimeError, "sysctl(VM_SWAPUSAGE) failed");
return NULL;
}
- if (!psutil_sys_vminfo(&vmstat)) {
+ if (!psutil_sys_vminfo(&vmstat))
return NULL;
- }
return Py_BuildValue(
"LLLKK",
@@ -653,8 +609,7 @@ psutil_swap_mem(PyObject *self, PyObject *args)
* Return a Python tuple representing user, kernel and idle CPU times
*/
static PyObject *
-psutil_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_cpu_times(PyObject *self, PyObject *args) {
mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
kern_return_t error;
host_cpu_load_info_data_t r_load;
@@ -662,11 +617,10 @@ psutil_cpu_times(PyObject *self, PyObject *args)
mach_port_t host_port = mach_host_self();
error = host_statistics(host_port, HOST_CPU_LOAD_INFO,
(host_info_t)&r_load, &count);
- if (error != KERN_SUCCESS) {
+ if (error != KERN_SUCCESS)
return PyErr_Format(PyExc_RuntimeError,
"Error in host_statistics(): %s",
mach_error_string(error));
- }
mach_port_deallocate(mach_task_self(), host_port);
return Py_BuildValue(
@@ -683,8 +637,7 @@ psutil_cpu_times(PyObject *self, PyObject *args)
* Return a Python list of tuple representing per-cpu times
*/
static PyObject *
-psutil_per_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_per_cpu_times(PyObject *self, PyObject *args) {
natural_t cpu_count;
processor_info_array_t info_array;
mach_msg_type_number_t info_count;
@@ -726,9 +679,8 @@ psutil_per_cpu_times(PyObject *self, PyObject *args)
ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array,
info_count * sizeof(int));
- if (ret != KERN_SUCCESS) {
+ if (ret != KERN_SUCCESS)
PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2);
- }
return py_retlist;
error:
@@ -737,9 +689,8 @@ error:
if (cpu_load_info != NULL) {
ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array,
info_count * sizeof(int));
- if (ret != KERN_SUCCESS) {
+ if (ret != KERN_SUCCESS)
PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2);
- }
}
return NULL;
}
@@ -750,8 +701,7 @@ error:
* seconds since the epoch.
*/
static PyObject *
-psutil_boot_time(PyObject *self, PyObject *args)
-{
+psutil_boot_time(PyObject *self, PyObject *args) {
// fetch sysctl "kern.boottime"
static int request[2] = { CTL_KERN, KERN_BOOTTIME };
struct timeval result;
@@ -772,8 +722,7 @@ psutil_boot_time(PyObject *self, PyObject *args)
* for all partitions mounted on the system.
*/
static PyObject *
-psutil_disk_partitions(PyObject *self, PyObject *args)
-{
+psutil_disk_partitions(PyObject *self, PyObject *args) {
int num;
int i;
long len;
@@ -894,16 +843,13 @@ error:
* Return process status as a Python integer.
*/
static PyObject *
-psutil_proc_status(PyObject *self, PyObject *args)
-{
+psutil_proc_status(PyObject *self, PyObject *args) {
long pid;
struct kinfo_proc kp;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (psutil_get_kinfo_proc(pid, &kp) == -1) {
+ if (psutil_get_kinfo_proc(pid, &kp) == -1)
return NULL;
- }
return Py_BuildValue("i", (int)kp.kp_proc.p_stat);
}
@@ -912,8 +858,7 @@ psutil_proc_status(PyObject *self, PyObject *args)
* Return process threads
*/
static PyObject *
-psutil_proc_threads(PyObject *self, PyObject *args)
-{
+psutil_proc_threads(PyObject *self, PyObject *args) {
long pid;
int err, j, ret;
kern_return_t kr;
@@ -925,26 +870,23 @@ psutil_proc_threads(PyObject *self, PyObject *args)
thread_basic_info_t basic_info_th;
mach_msg_type_number_t thread_count, thread_info_count;
- PyObject *retList = PyList_New(0);
- PyObject *pyTuple = NULL;
+ PyObject *py_tuple = NULL;
+ PyObject *py_retlist = PyList_New(0);
- if (retList == NULL)
+ if (py_retlist == NULL)
return NULL;
// the argument passed should be a process id
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
- }
// task_for_pid() requires special privileges
err = task_for_pid(mach_task_self(), pid, &task);
if (err != KERN_SUCCESS) {
- if (! psutil_pid_exists(pid)) {
+ if (! psutil_pid_exists(pid))
NoSuchProcess();
- }
- else {
+ else
AccessDenied();
- }
goto error;
}
@@ -971,7 +913,7 @@ psutil_proc_threads(PyObject *self, PyObject *args)
}
for (j = 0; j < thread_count; j++) {
- pyTuple = NULL;
+ py_tuple = NULL;
thread_info_count = THREAD_INFO_MAX;
kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
(thread_info_t)thinfo_basic, &thread_info_count);
@@ -982,40 +924,38 @@ psutil_proc_threads(PyObject *self, PyObject *args)
}
basic_info_th = (thread_basic_info_t)thinfo_basic;
- pyTuple = Py_BuildValue(
+ py_tuple = Py_BuildValue(
"Iff",
j + 1,
(float)basic_info_th->user_time.microseconds / 1000000.0,
(float)basic_info_th->system_time.microseconds / 1000000.0
);
- if (!pyTuple)
+ if (!py_tuple)
goto error;
- if (PyList_Append(retList, pyTuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(pyTuple);
+ Py_DECREF(py_tuple);
}
ret = vm_deallocate(task, (vm_address_t)thread_list,
thread_count * sizeof(int));
- if (ret != KERN_SUCCESS) {
+ if (ret != KERN_SUCCESS)
PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2);
- }
mach_port_deallocate(mach_task_self(), task);
- return retList;
+ return py_retlist;
error:
if (task != MACH_PORT_NULL)
mach_port_deallocate(mach_task_self(), task);
- Py_XDECREF(pyTuple);
- Py_DECREF(retList);
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
if (thread_list != NULL) {
ret = vm_deallocate(task, (vm_address_t)thread_list,
thread_count * sizeof(int));
- if (ret != KERN_SUCCESS) {
+ if (ret != KERN_SUCCESS)
PyErr_WarnEx(PyExc_RuntimeWarning, "vm_deallocate() failed", 2);
- }
}
return NULL;
}
@@ -1028,8 +968,7 @@ error:
* - /usr/include/sys/proc_info.h
*/
static PyObject *
-psutil_proc_open_files(PyObject *self, PyObject *args)
-{
+psutil_proc_open_files(PyObject *self, PyObject *args) {
long pid;
int pidinfo_result;
int iterations;
@@ -1040,15 +979,14 @@ psutil_proc_open_files(PyObject *self, PyObject *args)
struct proc_fdinfo *fdp_pointer;
struct vnode_fdinfowithpath vi;
- PyObject *retList = PyList_New(0);
- PyObject *tuple = NULL;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
- if (retList == NULL)
+ if (py_retlist == NULL)
return NULL;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
- }
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (pidinfo_result <= 0) {
@@ -1075,7 +1013,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args)
iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
for (i = 0; i < iterations; i++) {
- tuple = NULL;
+ py_tuple = NULL;
fdp_pointer = &fds_pointer[i];
if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE)
@@ -1107,37 +1045,33 @@ psutil_proc_open_files(PyObject *self, PyObject *args)
// --- /errors checking
// --- construct python list
- tuple = Py_BuildValue("(si)",
- vi.pvip.vip_path,
- (int)fdp_pointer->proc_fd);
- if (!tuple)
+ py_tuple = Py_BuildValue(
+ "(si)",
+ vi.pvip.vip_path,
+ (int)fdp_pointer->proc_fd);
+ if (!py_tuple)
goto error;
- if (PyList_Append(retList, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
// --- /construct python list
}
}
free(fds_pointer);
- return retList;
+ return py_retlist;
error:
- Py_XDECREF(tuple);
- Py_DECREF(retList);
- if (fds_pointer != NULL) {
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
+ if (fds_pointer != NULL)
free(fds_pointer);
- }
- if (errno != 0) {
+ if (errno != 0)
return PyErr_SetFromErrno(PyExc_OSError);
- }
- else if (! psutil_pid_exists(pid)) {
+ else if (! psutil_pid_exists(pid))
return NoSuchProcess();
- }
- else {
- // exception has already been set earlier
- return NULL;
- }
+ else
+ return NULL; // exception has already been set earlier
}
@@ -1151,8 +1085,7 @@ static int PSUTIL_CONN_NONE = 128;
* - /usr/include/sys/proc_info.h
*/
static PyObject *
-psutil_proc_connections(PyObject *self, PyObject *args)
-{
+psutil_proc_connections(PyObject *self, PyObject *args) {
long pid;
int pidinfo_result;
int iterations;
@@ -1163,33 +1096,29 @@ psutil_proc_connections(PyObject *self, PyObject *args)
struct proc_fdinfo *fdp_pointer;
struct socket_fdinfo si;
- PyObject *retList = PyList_New(0);
- PyObject *tuple = NULL;
- PyObject *laddr = NULL;
- PyObject *raddr = NULL;
- PyObject *af_filter = NULL;
- PyObject *type_filter = NULL;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
+ PyObject *py_laddr = NULL;
+ PyObject *py_raddr = NULL;
+ PyObject *py_af_filter = NULL;
+ PyObject *py_type_filter = NULL;
- if (retList == NULL)
+ if (py_retlist == NULL)
return NULL;
- if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) {
+ if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
goto error;
- }
- if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
+ if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
goto error;
}
- if (pid == 0) {
- return retList;
- }
-
+ if (pid == 0)
+ return py_retlist;
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
- if (pidinfo_result <= 0) {
+ if (pidinfo_result <= 0)
goto error;
- }
fds_pointer = malloc(pidinfo_result);
if (fds_pointer == NULL) {
@@ -1199,16 +1128,14 @@ psutil_proc_connections(PyObject *self, PyObject *args)
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
pidinfo_result);
- if (pidinfo_result <= 0) {
+ if (pidinfo_result <= 0)
goto error;
- }
-
iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
for (i = 0; i < iterations; i++) {
- tuple = NULL;
- laddr = NULL;
- raddr = NULL;
+ py_tuple = NULL;
+ py_laddr = NULL;
+ py_raddr = NULL;
errno = 0;
fdp_pointer = &fds_pointer[i];
@@ -1223,14 +1150,12 @@ psutil_proc_connections(PyObject *self, PyObject *args)
// let's assume socket has been closed
continue;
}
- if (errno != 0) {
+ if (errno != 0)
PyErr_SetFromErrno(PyExc_OSError);
- }
- else {
+ else
PyErr_Format(
PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
- }
goto error;
}
if (nb < sizeof(si)) {
@@ -1245,26 +1170,24 @@ psutil_proc_connections(PyObject *self, PyObject *args)
int fd, family, type, lport, rport, state;
char lip[200], rip[200];
int inseq;
- PyObject *_family;
- PyObject *_type;
+ PyObject *py_family;
+ PyObject *py_type;
fd = (int)fdp_pointer->proc_fd;
family = si.psi.soi_family;
type = si.psi.soi_type;
// apply filters
- _family = PyLong_FromLong((long)family);
- inseq = PySequence_Contains(af_filter, _family);
- Py_DECREF(_family);
- if (inseq == 0) {
+ py_family = PyLong_FromLong((long)family);
+ inseq = PySequence_Contains(py_af_filter, py_family);
+ Py_DECREF(py_family);
+ if (inseq == 0)
continue;
- }
- _type = PyLong_FromLong((long)type);
- inseq = PySequence_Contains(type_filter, _type);
- Py_DECREF(_type);
- if (inseq == 0) {
+ py_type = PyLong_FromLong((long)type);
+ inseq = PySequence_Contains(py_type_filter, py_type);
+ Py_DECREF(py_type);
+ if (inseq == 0)
continue;
- }
if (errno != 0) {
PyErr_SetFromErrno(PyExc_OSError);
@@ -1303,73 +1226,65 @@ psutil_proc_connections(PyObject *self, PyObject *args)
lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
- if (type == SOCK_STREAM) {
+ if (type == SOCK_STREAM)
state = (int)si.psi.soi_proto.pri_tcp.tcpsi_state;
- }
- else {
+ else
state = PSUTIL_CONN_NONE;
- }
- laddr = Py_BuildValue("(si)", lip, lport);
- if (!laddr)
+ py_laddr = Py_BuildValue("(si)", lip, lport);
+ if (!py_laddr)
goto error;
- if (rport != 0) {
- raddr = Py_BuildValue("(si)", rip, rport);
- }
- else {
- raddr = Py_BuildValue("()");
- }
- if (!raddr)
+ if (rport != 0)
+ py_raddr = Py_BuildValue("(si)", rip, rport);
+ else
+ py_raddr = Py_BuildValue("()");
+ if (!py_raddr)
goto error;
// construct the python list
- tuple = Py_BuildValue("(iiiNNi)", fd, family, type, laddr,
- raddr, state);
- if (!tuple)
+ py_tuple = Py_BuildValue(
+ "(iiiNNi)", fd, family, type, py_laddr, py_raddr, state);
+ if (!py_tuple)
goto error;
- if (PyList_Append(retList, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
else if (family == AF_UNIX) {
// construct the python list
- tuple = Py_BuildValue(
+ py_tuple = Py_BuildValue(
"(iiissi)",
fd, family, type,
si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path,
si.psi.soi_proto.pri_un.unsi_caddr.ua_sun.sun_path,
PSUTIL_CONN_NONE);
- if (!tuple)
+ if (!py_tuple)
goto error;
- if (PyList_Append(retList, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
}
}
free(fds_pointer);
- return retList;
+ return py_retlist;
error:
- Py_XDECREF(tuple);
- Py_XDECREF(laddr);
- Py_XDECREF(raddr);
- Py_DECREF(retList);
+ Py_XDECREF(py_tuple);
+ Py_XDECREF(py_laddr);
+ Py_XDECREF(py_raddr);
+ Py_DECREF(py_retlist);
- if (fds_pointer != NULL) {
+ if (fds_pointer != NULL)
free(fds_pointer);
- }
- if (errno != 0) {
+ if (errno != 0)
return PyErr_SetFromErrno(PyExc_OSError);
- }
- else if (! psutil_pid_exists(pid) ) {
+ else if (! psutil_pid_exists(pid))
return NoSuchProcess();
- }
- else {
+ else
return PyErr_Format(PyExc_RuntimeError,
"proc_pidinfo(PROC_PIDLISTFDS) failed");
- }
}
@@ -1377,26 +1292,22 @@ error:
* Return number of file descriptors opened by process.
*/
static PyObject *
-psutil_proc_num_fds(PyObject *self, PyObject *args)
-{
+psutil_proc_num_fds(PyObject *self, PyObject *args) {
long pid;
int pidinfo_result;
int num;
struct proc_fdinfo *fds_pointer;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
- if (pidinfo_result <= 0) {
+ if (pidinfo_result <= 0)
return PyErr_SetFromErrno(PyExc_OSError);
- }
fds_pointer = malloc(pidinfo_result);
- if (fds_pointer == NULL) {
+ if (fds_pointer == NULL)
return PyErr_NoMemory();
- }
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
pidinfo_result);
if (pidinfo_result <= 0) {
@@ -1414,8 +1325,7 @@ psutil_proc_num_fds(PyObject *self, PyObject *args)
* Return a Python list of named tuples with overall network I/O information
*/
static PyObject *
-psutil_net_io_counters(PyObject *self, PyObject *args)
-{
+psutil_net_io_counters(PyObject *self, PyObject *args) {
char *buf = NULL, *lim, *next;
struct if_msghdr *ifm;
int mib[6];
@@ -1502,8 +1412,7 @@ error:
* Return a Python dict of tuples for disk I/O information
*/
static PyObject *
-psutil_disk_io_counters(PyObject *self, PyObject *args)
-{
+psutil_disk_io_counters(PyObject *self, PyObject *args) {
CFDictionaryRef parent_dict;
CFDictionaryRef props_dict;
CFDictionaryRef stats_dict;
@@ -1677,41 +1586,40 @@ error:
* Return currently connected users as a list of tuples.
*/
static PyObject *
-psutil_users(PyObject *self, PyObject *args)
-{
+psutil_users(PyObject *self, PyObject *args) {
struct utmpx *utx;
- PyObject *ret_list = PyList_New(0);
- PyObject *tuple = NULL;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
- if (ret_list == NULL)
+ if (py_retlist == NULL)
return NULL;
while ((utx = getutxent()) != NULL) {
if (utx->ut_type != USER_PROCESS)
continue;
- tuple = Py_BuildValue(
+ py_tuple = Py_BuildValue(
"(sssf)",
utx->ut_user, // username
utx->ut_line, // tty
utx->ut_host, // hostname
(float)utx->ut_tv.tv_sec // start time
);
- if (!tuple) {
+ if (!py_tuple) {
endutxent();
goto error;
}
- if (PyList_Append(ret_list, tuple)) {
+ if (PyList_Append(py_retlist, py_tuple)) {
endutxent();
goto error;
}
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
endutxent();
- return ret_list;
+ return py_retlist;
error:
- Py_XDECREF(tuple);
- Py_DECREF(ret_list);
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
return NULL;
}
@@ -1720,8 +1628,8 @@ error:
* define the psutil C module methods and initialize the module.
*/
static PyMethodDef
-PsutilMethods[] =
-{
+PsutilMethods[] = {
+
// --- per-process functions
{"proc_name", psutil_proc_name, METH_VARARGS,
@@ -1871,9 +1779,8 @@ init_psutil_osx(void)
PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
- if (module == NULL) {
+ if (module == NULL)
INITERROR;
- }
#if PY_MAJOR_VERSION >= 3
return module;
#endif
diff --git a/psutil/_psutil_posix.c b/psutil/_psutil_posix.c
index d020837c..241b9d59 100644
--- a/psutil/_psutil_posix.c
+++ b/psutil/_psutil_posix.c
@@ -10,6 +10,26 @@
#include <errno.h>
#include <stdlib.h>
#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+
+#ifdef __linux
+#include <netdb.h>
+#include <linux/if_packet.h>
+#endif // end linux
+
+#if defined(__FreeBSD__) || defined(__APPLE__)
+#include <netdb.h>
+#include <netinet/in.h>
+#include <net/if_dl.h>
+#endif
+
+#if defined(__sun)
+#include <netdb.h>
+#endif
#include "_psutil_posix.h"
@@ -18,18 +38,16 @@
* Given a PID return process priority as a Python integer.
*/
static PyObject *
-psutil_posix_getpriority(PyObject *self, PyObject *args)
-{
+psutil_posix_getpriority(PyObject *self, PyObject *args) {
long pid;
int priority;
errno = 0;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
priority = getpriority(PRIO_PROCESS, pid);
- if (errno != 0) {
+ if (errno != 0)
return PyErr_SetFromErrno(PyExc_OSError);
- }
return Py_BuildValue("i", priority);
}
@@ -38,32 +56,427 @@ psutil_posix_getpriority(PyObject *self, PyObject *args)
* Given a PID and a value change process priority.
*/
static PyObject *
-psutil_posix_setpriority(PyObject *self, PyObject *args)
-{
+psutil_posix_setpriority(PyObject *self, PyObject *args) {
long pid;
int priority;
int retval;
- if (! PyArg_ParseTuple(args, "li", &pid, &priority)) {
+
+ if (! PyArg_ParseTuple(args, "li", &pid, &priority))
return NULL;
- }
retval = setpriority(PRIO_PROCESS, pid, priority);
- if (retval == -1) {
+ if (retval == -1)
return PyErr_SetFromErrno(PyExc_OSError);
- }
Py_RETURN_NONE;
}
/*
+ * Translate a sockaddr struct into a Python string.
+ * Return None if address family is not AF_INET* or AF_PACKET.
+ */
+static PyObject *
+psutil_convert_ipaddr(struct sockaddr *addr, int family) {
+ char buf[NI_MAXHOST];
+ int err;
+ int addrlen;
+ int n;
+ size_t len;
+ const char *data;
+ char *ptr;
+
+ if (addr == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else if (family == AF_INET || family == AF_INET6) {
+ if (family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else
+ addrlen = sizeof(struct sockaddr_in6);
+ err = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
+ NI_NUMERICHOST);
+ if (err != 0) {
+ // XXX we get here on FreeBSD when processing 'lo' / AF_INET6
+ // broadcast. Not sure what to do other than returning None.
+ // ifconfig does not show anything BTW.
+ //PyErr_Format(PyExc_RuntimeError, gai_strerror(err));
+ //return NULL;
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else {
+ return Py_BuildValue("s", buf);
+ }
+ }
+#ifdef __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(__APPLE__)
+ else if (addr->sa_family == AF_LINK) {
+ // Note: prior to Python 3.4 socket module does not expose
+ // AF_LINK so we'll do.
+ struct sockaddr_dl *dladdr = (struct sockaddr_dl *)addr;
+ len = dladdr->sdl_alen;
+ data = LLADDR(dladdr);
+ }
+#endif
+ else {
+ // unknown family
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ // AF_PACKET or AF_LINK
+ if (len > 0) {
+ ptr = buf;
+ for (n = 0; n < len; ++n) {
+ sprintf(ptr, "%02x:", data[n] & 0xff);
+ ptr += 3;
+ }
+ *--ptr = '\0';
+ return Py_BuildValue("s", buf);
+ }
+ else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+
+/*
+ * Return NICs information a-la ifconfig as a list of tuples.
+ * TODO: on Solaris we won't get any MAC address.
+ */
+static PyObject*
+psutil_net_if_addrs(PyObject* self, PyObject* args) {
+ struct ifaddrs *ifaddr, *ifa;
+ int family;
+
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
+ PyObject *py_address = NULL;
+ PyObject *py_netmask = NULL;
+ PyObject *py_broadcast = NULL;
+ PyObject *py_ptp = NULL;
+
+ if (py_retlist == NULL)
+ return NULL;
+ if (getifaddrs(&ifaddr) == -1) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ goto error;
+ }
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
+ family = ifa->ifa_addr->sa_family;
+ py_address = psutil_convert_ipaddr(ifa->ifa_addr, family);
+ // If the primary address can't be determined just skip it.
+ // I've never seen this happen on Linux but I did on FreeBSD.
+ if (py_address == Py_None)
+ continue;
+ if (py_address == NULL)
+ goto error;
+ py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family);
+ if (py_netmask == NULL)
+ goto error;
+
+ if (ifa->ifa_flags & IFF_BROADCAST) {
+ py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family);
+ Py_INCREF(Py_None);
+ py_ptp = Py_None;
+ }
+ else if (ifa->ifa_flags & IFF_POINTOPOINT) {
+ py_ptp = psutil_convert_ipaddr(ifa->ifa_dstaddr, family);
+ Py_INCREF(Py_None);
+ py_broadcast = Py_None;
+ }
+ else {
+ Py_INCREF(Py_None);
+ Py_INCREF(Py_None);
+ py_broadcast = Py_None;
+ py_ptp = Py_None;
+ }
+
+ if ((py_broadcast == NULL) || (py_ptp == NULL))
+ goto error;
+ py_tuple = Py_BuildValue(
+ "(siOOOO)",
+ ifa->ifa_name,
+ family,
+ py_address,
+ py_netmask,
+ py_broadcast,
+ py_ptp
+ );
+
+ if (! py_tuple)
+ goto error;
+ if (PyList_Append(py_retlist, py_tuple))
+ goto error;
+ Py_DECREF(py_tuple);
+ Py_DECREF(py_address);
+ Py_DECREF(py_netmask);
+ Py_DECREF(py_broadcast);
+ Py_DECREF(py_ptp);
+ }
+
+ freeifaddrs(ifaddr);
+ return py_retlist;
+
+error:
+ if (ifaddr != NULL)
+ freeifaddrs(ifaddr);
+ Py_DECREF(py_retlist);
+ Py_XDECREF(py_tuple);
+ Py_XDECREF(py_address);
+ Py_XDECREF(py_netmask);
+ Py_XDECREF(py_broadcast);
+ Py_XDECREF(py_ptp);
+ return NULL;
+}
+
+
+/*
+ * net_if_stats() implementation. This is here because it is common
+ * to both OSX and FreeBSD and I didn't know where else to put it.
+ */
+#if defined(__FreeBSD__) || defined(__APPLE__)
+
+#include <sys/sockio.h>
+#include <net/if_media.h>
+#include <net/if.h>
+
+int psutil_get_nic_speed(int ifm_active) {
+ // Determine NIC speed. Taken from:
+ // http://www.i-scream.org/libstatgrab/
+ // Assuming only ETHER devices
+ switch(IFM_TYPE(ifm_active)) {
+ case IFM_ETHER:
+ switch(IFM_SUBTYPE(ifm_active)) {
+#if defined(IFM_HPNA_1) && ((!defined(IFM_10G_LR)) \
+ || (IFM_10G_LR != IFM_HPNA_1))
+ // HomePNA 1.0 (1Mb/s)
+ case(IFM_HPNA_1):
+ return 1;
+#endif
+ // 10 Mbit
+ case(IFM_10_T): // 10BaseT - RJ45
+ case(IFM_10_2): // 10Base2 - Thinnet
+ case(IFM_10_5): // 10Base5 - AUI
+ case(IFM_10_STP): // 10BaseT over shielded TP
+ case(IFM_10_FL): // 10baseFL - Fiber
+ return 10;
+ // 100 Mbit
+ case(IFM_100_TX): // 100BaseTX - RJ45
+ case(IFM_100_FX): // 100BaseFX - Fiber
+ case(IFM_100_T4): // 100BaseT4 - 4 pair cat 3
+ case(IFM_100_VG): // 100VG-AnyLAN
+ case(IFM_100_T2): // 100BaseT2
+ return 100;
+ // 1000 Mbit
+ 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)
+ // FreeBSD 4 and others (but NOT OpenBSD)?
+ case(IFM_1000_TX):
+#endif
+#ifdef IFM_1000_FX
+ case(IFM_1000_FX):
+#endif
+#ifdef IFM_1000_T
+ case(IFM_1000_T):
+#endif
+ return 1000;
+#if defined(IFM_10G_SR) || defined(IFM_10G_LR) || defined(IFM_10G_CX4) \
+ || defined(IFM_10G_T)
+#ifdef IFM_10G_SR
+ case(IFM_10G_SR):
+#endif
+#ifdef IFM_10G_LR
+ case(IFM_10G_LR):
+#endif
+#ifdef IFM_10G_CX4
+ case(IFM_10G_CX4):
+#endif
+#ifdef IFM_10G_TWINAX
+ case(IFM_10G_TWINAX):
+#endif
+#ifdef IFM_10G_TWINAX_LONG
+ case(IFM_10G_TWINAX_LONG):
+#endif
+#ifdef IFM_10G_T
+ case(IFM_10G_T):
+#endif
+ return 10000;
+#endif
+#if defined(IFM_2500_SX)
+#ifdef IFM_2500_SX
+ case(IFM_2500_SX):
+#endif
+ return 2500;
+#endif // any 2.5GBit stuff...
+ // We don't know what it is
+ default:
+ return 0;
+ }
+ break;
+
+#ifdef IFM_TOKEN
+ case IFM_TOKEN:
+ switch(IFM_SUBTYPE(ifm_active)) {
+ case IFM_TOK_STP4: // Shielded twisted pair 4m - DB9
+ case IFM_TOK_UTP4: // Unshielded twisted pair 4m - RJ45
+ return 4;
+ case IFM_TOK_STP16: // Shielded twisted pair 16m - DB9
+ case IFM_TOK_UTP16: // Unshielded twisted pair 16m - RJ45
+ return 16;
+#if defined(IFM_TOK_STP100) || defined(IFM_TOK_UTP100)
+#ifdef IFM_TOK_STP100
+ case IFM_TOK_STP100: // Shielded twisted pair 100m - DB9
+#endif
+#ifdef IFM_TOK_UTP100
+ case IFM_TOK_UTP100: // Unshielded twisted pair 100m - RJ45
+#endif
+ return 100;
+#endif
+ // We don't know what it is
+ default:
+ return 0;
+ }
+ break;
+#endif
+
+#ifdef IFM_FDDI
+ case IFM_FDDI:
+ switch(IFM_SUBTYPE(ifm_active)) {
+ // We don't know what it is
+ default:
+ return 0;
+ }
+ break;
+#endif
+ case IFM_IEEE80211:
+ switch(IFM_SUBTYPE(ifm_active)) {
+ case IFM_IEEE80211_FH1: // Frequency Hopping 1Mbps
+ case IFM_IEEE80211_DS1: // Direct Sequence 1Mbps
+ return 1;
+ case IFM_IEEE80211_FH2: // Frequency Hopping 2Mbps
+ case IFM_IEEE80211_DS2: // Direct Sequence 2Mbps
+ return 2;
+ case IFM_IEEE80211_DS5: // Direct Sequence 5Mbps
+ return 5;
+ case IFM_IEEE80211_DS11: // Direct Sequence 11Mbps
+ return 11;
+ case IFM_IEEE80211_DS22: // Direct Sequence 22Mbps
+ return 22;
+ // We don't know what it is
+ default:
+ return 0;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+}
+
+
+/*
+ * Return stats about a particular network interface.
+ * References:
+ * http://www.i-scream.org/libstatgrab/
+ */
+static PyObject *
+psutil_net_if_stats(PyObject *self, PyObject *args) {
+ char *nic_name;
+ int sock = 0;
+ int ret;
+ int duplex;
+ int speed;
+ int mtu;
+ struct ifreq ifr;
+ struct ifmediareq ifmed;
+
+ PyObject *py_is_up = NULL;
+
+ if (! PyArg_ParseTuple(args, "s", &nic_name))
+ return NULL;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == -1)
+ goto error;
+ strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
+
+ // is up?
+ ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+ if (ret == -1)
+ goto error;
+ if ((ifr.ifr_flags & IFF_UP) != 0)
+ py_is_up = Py_True;
+ else
+ py_is_up = Py_False;
+ Py_INCREF(py_is_up);
+
+ // MTU
+ ret = ioctl(sock, SIOCGIFMTU, &ifr);
+ if (ret == -1)
+ goto error;
+ mtu = ifr.ifr_mtu;
+
+ // speed / duplex
+ memset(&ifmed, 0, sizeof(struct ifmediareq));
+ strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name));
+ ret = ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed);
+ if (ret == -1) {
+ speed = 0;
+ duplex = 0;
+ }
+ else {
+ speed = psutil_get_nic_speed(ifmed.ifm_active);
+ if ((ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active)
+ duplex = 2;
+ else if ((ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active)
+ duplex = 1;
+ else
+ duplex = 0;
+ }
+
+ close(sock);
+ Py_DECREF(py_is_up);
+
+ return Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu);
+
+error:
+ Py_XDECREF(py_is_up);
+ if (sock != 0)
+ close(sock);
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+}
+#endif // net_if_stats() implementation
+
+
+/*
* define the psutil C module methods and initialize the module.
*/
static PyMethodDef
-PsutilMethods[] =
-{
+PsutilMethods[] = {
{"getpriority", psutil_posix_getpriority, METH_VARARGS,
"Return process priority"},
{"setpriority", psutil_posix_setpriority, METH_VARARGS,
"Set process priority"},
+ {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS,
+ "Retrieve NICs information"},
+#if defined(__FreeBSD__) || defined(__APPLE__)
+ {"net_if_stats", psutil_net_if_stats, METH_VARARGS,
+ "Return NIC stats."},
+#endif
{NULL, NULL, 0, NULL}
};
@@ -118,9 +531,13 @@ void init_psutil_posix(void)
#else
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
#endif
- if (module == NULL) {
+
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__sun)
+ PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
+#endif
+
+ if (module == NULL)
INITERROR;
- }
#if PY_MAJOR_VERSION >= 3
return module;
#endif
diff --git a/psutil/_psutil_posix.h b/psutil/_psutil_posix.h
index 5a4681d1..bbe6fc5a 100644
--- a/psutil/_psutil_posix.h
+++ b/psutil/_psutil_posix.h
@@ -6,5 +6,10 @@
#include <Python.h>
+static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args);
static PyObject* psutil_posix_getpriority(PyObject* self, PyObject* args);
static PyObject* psutil_posix_setpriority(PyObject* self, PyObject* args);
+
+#if defined(__FreeBSD__) || defined(__APPLE__)
+static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
+#endif
diff --git a/psutil/_psutil_sunos.c b/psutil/_psutil_sunos.c
index 32108e09..0611e014 100644
--- a/psutil/_psutil_sunos.c
+++ b/psutil/_psutil_sunos.c
@@ -30,6 +30,8 @@
#include <sys/mntent.h> // for MNTTAB
#include <sys/mnttab.h>
#include <sys/procfs.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
#include <fcntl.h>
#include <utmpx.h>
#include <kstat.h>
@@ -38,6 +40,7 @@
#include <stropts.h>
#include <inet/tcp.h>
#include <arpa/inet.h>
+#include <net/if.h>
#include "_psutil_sunos.h"
@@ -48,8 +51,7 @@
* Read a file content and fills a C structure with it.
*/
int
-psutil_file_to_struct(char *path, void *fstruct, size_t size)
-{
+psutil_file_to_struct(char *path, void *fstruct, size_t size) {
int fd;
size_t nbytes;
fd = open(path, O_RDONLY);
@@ -78,8 +80,7 @@ psutil_file_to_struct(char *path, void *fstruct, size_t size)
* as a Python tuple.
*/
static PyObject *
-psutil_proc_basic_info(PyObject *self, PyObject *args)
-{
+psutil_proc_basic_info(PyObject *self, PyObject *args) {
int pid;
char path[100];
psinfo_t info;
@@ -106,8 +107,7 @@ psutil_proc_basic_info(PyObject *self, PyObject *args)
* Return process name and args as a Python tuple.
*/
static PyObject *
-psutil_proc_name_and_args(PyObject *self, PyObject *args)
-{
+psutil_proc_name_and_args(PyObject *self, PyObject *args) {
int pid;
char path[100];
psinfo_t info;
@@ -125,8 +125,7 @@ psutil_proc_name_and_args(PyObject *self, PyObject *args)
* Return process user and system CPU times as a Python tuple.
*/
static PyObject *
-psutil_proc_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_times(PyObject *self, PyObject *args) {
int pid;
char path[100];
pstatus_t info;
@@ -147,8 +146,7 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args)
* Return process uids/gids as a Python tuple.
*/
static PyObject *
-psutil_proc_cred(PyObject *self, PyObject *args)
-{
+psutil_proc_cred(PyObject *self, PyObject *args) {
int pid;
char path[100];
prcred_t info;
@@ -168,8 +166,7 @@ psutil_proc_cred(PyObject *self, PyObject *args)
* Return process uids/gids as a Python tuple.
*/
static PyObject *
-psutil_proc_num_ctx_switches(PyObject *self, PyObject *args)
-{
+psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) {
int pid;
char path[100];
prusage_t info;
@@ -195,19 +192,16 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args)
* ...they should be meaningless anyway.
*
static PyObject*
-proc_io_counters(PyObject* self, PyObject* args)
-{
+proc_io_counters(PyObject* self, PyObject* args) {
int pid;
char path[100];
prusage_t info;
- if (! PyArg_ParseTuple(args, "i", &pid)) {
+ if (! PyArg_ParseTuple(args, "i", &pid))
return NULL;
- }
sprintf(path, "/proc/%i/usage", pid);
- if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) {
+ if (! psutil_file_to_struct(path, (void *)&info, sizeof(info)))
return NULL;
- }
// On Solaris we only have 'pr_ioch' which accounts for bytes read
// *and* written.
@@ -227,8 +221,7 @@ proc_io_counters(PyObject* self, PyObject* args)
* Return information about a given process thread.
*/
static PyObject *
-psutil_proc_query_thread(PyObject *self, PyObject *args)
-{
+psutil_proc_query_thread(PyObject *self, PyObject *args) {
int pid, tid;
char path[100];
lwpstatus_t info;
@@ -248,8 +241,7 @@ psutil_proc_query_thread(PyObject *self, PyObject *args)
* Return information about system virtual memory.
*/
static PyObject *
-psutil_swap_mem(PyObject *self, PyObject *args)
-{
+psutil_swap_mem(PyObject *self, PyObject *args) {
// XXX (arghhh!)
// total/free swap mem: commented out as for some reason I can't
// manage to get the same results shown by "swap -l", despite the
@@ -315,9 +307,8 @@ psutil_swap_mem(PyObject *self, PyObject *args)
uint_t sout = 0;
kc = kstat_open();
- if (kc == NULL) {
+ if (kc == NULL)
return PyErr_SetFromErrno(PyExc_OSError);;
- }
k = kc->kc_chain;
while (k != NULL) {
@@ -345,41 +336,40 @@ psutil_swap_mem(PyObject *self, PyObject *args)
* Return users currently connected on the system.
*/
static PyObject *
-psutil_users(PyObject *self, PyObject *args)
-{
+psutil_users(PyObject *self, PyObject *args) {
struct utmpx *ut;
- PyObject *ret_list = PyList_New(0);
- PyObject *tuple = NULL;
- PyObject *user_proc = NULL;
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
+ PyObject *py_user_proc = NULL;
- if (ret_list == NULL)
+ if (py_retlist == NULL)
return NULL;
while (NULL != (ut = getutxent())) {
if (ut->ut_type == USER_PROCESS)
- user_proc = Py_True;
+ py_user_proc = Py_True;
else
- user_proc = Py_False;
- tuple = Py_BuildValue(
+ py_user_proc = Py_False;
+ py_tuple = Py_BuildValue(
"(sssfO)",
ut->ut_user, // username
ut->ut_line, // tty
ut->ut_host, // hostname
(float)ut->ut_tv.tv_sec, // tstamp
- user_proc); // (bool) user process
- if (tuple == NULL)
+ py_user_proc); // (bool) user process
+ if (py_tuple == NULL)
goto error;
- if (PyList_Append(ret_list, tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(tuple);
+ Py_DECREF(py_tuple);
}
endutent();
- return ret_list;
+ return py_retlist;
error:
- Py_XDECREF(tuple);
- Py_DECREF(ret_list);
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
if (ut != NULL)
endutent();
return NULL;
@@ -391,8 +381,7 @@ error:
* mount point and filesystem type.
*/
static PyObject *
-psutil_disk_partitions(PyObject *self, PyObject *args)
-{
+psutil_disk_partitions(PyObject *self, PyObject *args) {
FILE *file;
struct mnttab mt;
PyObject *py_retlist = PyList_New(0);
@@ -437,13 +426,10 @@ error:
* Return system-wide CPU times.
*/
static PyObject *
-psutil_per_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_per_cpu_times(PyObject *self, PyObject *args) {
kstat_ctl_t *kc;
kstat_t *ksp;
cpu_stat_t cs;
- int numcpus;
- int i;
PyObject *py_retlist = PyList_New(0);
PyObject *py_cputime = NULL;
@@ -492,8 +478,7 @@ error:
* Return disk IO statistics.
*/
static PyObject *
-psutil_disk_io_counters(PyObject *self, PyObject *args)
-{
+psutil_disk_io_counters(PyObject *self, PyObject *args) {
kstat_ctl_t *kc;
kstat_t *ksp;
kstat_io_t kio;
@@ -551,8 +536,7 @@ error:
* Return process memory mappings.
*/
static PyObject *
-psutil_proc_memory_maps(PyObject *self, PyObject *args)
-{
+psutil_proc_memory_maps(PyObject *self, PyObject *args) {
int pid;
int fd = -1;
char path[100];
@@ -568,20 +552,17 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
uintptr_t pr_addr_sz;
uintptr_t stk_base_sz, brk_base_sz;
- PyObject *pytuple = NULL;
+ PyObject *py_tuple = NULL;
PyObject *py_retlist = PyList_New(0);
- if (py_retlist == NULL) {
+ if (py_retlist == NULL)
return NULL;
- }
- if (! PyArg_ParseTuple(args, "i", &pid)) {
+ if (! PyArg_ParseTuple(args, "i", &pid))
goto error;
- }
sprintf(path, "/proc/%i/status", pid);
- if (! psutil_file_to_struct(path, (void *)&status, sizeof(status))) {
+ if (! psutil_file_to_struct(path, (void *)&status, sizeof(status)))
goto error;
- }
sprintf(path, "/proc/%i/xmap", pid);
if (stat(path, &st) == -1) {
@@ -652,19 +633,20 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
}
}
- pytuple = Py_BuildValue("iisslll",
- p->pr_vaddr,
- pr_addr_sz,
- perms,
- name,
- (long)p->pr_rss * p->pr_pagesize,
- (long)p->pr_anon * p->pr_pagesize,
- (long)p->pr_locked * p->pr_pagesize);
- if (!pytuple)
+ py_tuple = Py_BuildValue(
+ "iisslll",
+ p->pr_vaddr,
+ pr_addr_sz,
+ perms,
+ name,
+ (long)p->pr_rss * p->pr_pagesize,
+ (long)p->pr_anon * p->pr_pagesize,
+ (long)p->pr_locked * p->pr_pagesize);
+ if (!py_tuple)
goto error;
- if (PyList_Append(py_retlist, pytuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(pytuple);
+ Py_DECREF(py_tuple);
// increment pointer
p += 1;
@@ -677,7 +659,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
error:
if (fd != -1)
close(fd);
- Py_XDECREF(pytuple);
+ Py_XDECREF(py_tuple);
Py_DECREF(py_retlist);
if (xmap != NULL)
free(xmap);
@@ -689,8 +671,7 @@ error:
* Return a list of tuples for network I/O statistics.
*/
static PyObject *
-psutil_net_io_counters(PyObject *self, PyObject *args)
-{
+psutil_net_io_counters(PyObject *self, PyObject *args) {
kstat_ctl_t *kc = NULL;
kstat_t *ksp;
kstat_named_t *rbytes, *wbytes, *rpkts, *wpkts, *ierrs, *oerrs;
@@ -717,9 +698,8 @@ psutil_net_io_counters(PyObject *self, PyObject *args)
(strcmp(ksp->ks_module, "lo") != 0)) {
goto skip;
*/
- if ((strcmp(ksp->ks_module, "link") != 0)) {
+ if ((strcmp(ksp->ks_module, "link") != 0))
goto next;
- }
if (kstat_read(kc, ksp, NULL) == -1) {
errno = 0;
@@ -742,18 +722,18 @@ psutil_net_io_counters(PyObject *self, PyObject *args)
#if defined(_INT64_TYPE)
py_ifc_info = Py_BuildValue("(KKKKkkii)",
- rbytes->value.ui64,
wbytes->value.ui64,
- rpkts->value.ui64,
+ rbytes->value.ui64,
wpkts->value.ui64,
+ rpkts->value.ui64,
ierrs->value.ui32,
oerrs->value.ui32,
#else
py_ifc_info = Py_BuildValue("(kkkkkkii)",
- rbytes->value.ui32,
wbytes->value.ui32,
- rpkts->value.ui32,
+ rbytes->value.ui32,
wpkts->value.ui32,
+ rpkts->value.ui32,
ierrs->value.ui32,
oerrs->value.ui32,
#endif
@@ -802,10 +782,9 @@ static int PSUTIL_CONN_NONE = 128;
* cmd-inet/usr.bin/netstat/netstat.c
*/
static PyObject *
-psutil_net_connections(PyObject *self, PyObject *args)
-{
+psutil_net_connections(PyObject *self, PyObject *args) {
long pid;
- int sd = NULL;
+ int sd = 0;
mib2_tcpConnEntry_t *tp = NULL;
mib2_udpEntry_t *ude;
#if defined(AF_INET6)
@@ -817,6 +796,7 @@ psutil_net_connections(PyObject *self, PyObject *args)
char lip[200], rip[200];
int lport, rport;
int processed_pid;
+ int databuf_init = 0;
struct strbuf ctlbuf, databuf;
struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
@@ -827,14 +807,14 @@ psutil_net_connections(PyObject *self, PyObject *args)
PyObject *py_tuple = NULL;
PyObject *py_laddr = NULL;
PyObject *py_raddr = NULL;
- PyObject *af_filter = NULL;
- PyObject *type_filter = NULL;
+ PyObject *py_af_filter = NULL;
+ PyObject *py_type_filter = NULL;
if (py_retlist == NULL)
return NULL;
- if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter))
+ if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
goto error;
- if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
+ if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
goto error;
}
@@ -917,6 +897,7 @@ psutil_net_connections(PyObject *self, PyObject *args)
PyErr_NoMemory();
goto error;
}
+ databuf_init = 1;
flags = 0;
getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags);
@@ -943,9 +924,8 @@ psutil_net_connections(PyObject *self, PyObject *args)
py_laddr = Py_BuildValue("(si)", lip, lport);
if (!py_laddr)
goto error;
- if (rport != 0) {
+ if (rport != 0)
py_raddr = Py_BuildValue("(si)", rip, rport);
- }
else {
py_raddr = Py_BuildValue("()");
}
@@ -957,9 +937,8 @@ psutil_net_connections(PyObject *self, PyObject *args)
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_STREAM,
py_laddr, py_raddr, state,
processed_pid);
- if (!py_tuple) {
+ if (!py_tuple)
goto error;
- }
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
@@ -986,12 +965,10 @@ psutil_net_connections(PyObject *self, PyObject *args)
py_laddr = Py_BuildValue("(si)", lip, lport);
if (!py_laddr)
goto error;
- if (rport != 0) {
+ if (rport != 0)
py_raddr = Py_BuildValue("(si)", rip, rport);
- }
- else {
+ else
py_raddr = Py_BuildValue("()");
- }
if (!py_raddr)
goto error;
state = tp6->tcp6ConnEntryInfo.ce_state;
@@ -999,9 +976,8 @@ psutil_net_connections(PyObject *self, PyObject *args)
// add item
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_STREAM,
py_laddr, py_raddr, state, processed_pid);
- if (!py_tuple) {
+ if (!py_tuple)
goto error;
- }
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
@@ -1034,9 +1010,8 @@ psutil_net_connections(PyObject *self, PyObject *args)
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET, SOCK_DGRAM,
py_laddr, py_raddr, PSUTIL_CONN_NONE,
processed_pid);
- if (!py_tuple) {
+ if (!py_tuple)
goto error;
- }
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
@@ -1044,7 +1019,9 @@ psutil_net_connections(PyObject *self, PyObject *args)
}
#if defined(AF_INET6)
// UDPv6
- else if (mibhdr->level == MIB2_UDP6 || mibhdr->level == MIB2_UDP6_ENTRY) {
+ else if (mibhdr->level == MIB2_UDP6 ||
+ mibhdr->level == MIB2_UDP6_ENTRY)
+ {
ude6 = (mib2_udp6Entry_t *)databuf.buf;
num_ent = mibhdr->len / sizeof(mib2_udp6Entry_t);
for (i = 0; i < num_ent; i++, ude6++) {
@@ -1062,9 +1039,8 @@ psutil_net_connections(PyObject *self, PyObject *args)
py_tuple = Py_BuildValue("(iiiNNiI)", -1, AF_INET6, SOCK_DGRAM,
py_laddr, py_raddr, PSUTIL_CONN_NONE,
processed_pid);
- if (!py_tuple) {
+ if (!py_tuple)
goto error;
- }
if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
@@ -1082,16 +1058,16 @@ error:
Py_XDECREF(py_laddr);
Py_XDECREF(py_raddr);
Py_DECREF(py_retlist);
- // TODO : free databuf
- if (sd != NULL)
+ if (databuf_init == 1)
+ free(databuf.buf);
+ if (sd != 0)
close(sd);
return NULL;
}
static PyObject *
-psutil_boot_time(PyObject *self, PyObject *args)
-{
+psutil_boot_time(PyObject *self, PyObject *args) {
float boot_time = 0.0;
struct utmpx *ut;
@@ -1116,8 +1092,7 @@ psutil_boot_time(PyObject *self, PyObject *args)
* Return the number of physical CPU cores on the system.
*/
static PyObject *
-psutil_cpu_count_phys(PyObject *self, PyObject *args)
-{
+psutil_cpu_count_phys(PyObject *self, PyObject *args) {
kstat_ctl_t *kc;
kstat_t *ksp;
int ncpus = 0;
@@ -1132,7 +1107,7 @@ psutil_cpu_count_phys(PyObject *self, PyObject *args)
for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
if (strcmp(ksp->ks_module, "cpu_info") != 0)
continue;
- if (kstat_read(kc, ksp, NULL) == NULL)
+ if (kstat_read(kc, ksp, NULL) == -1)
goto error;
ncpus += 1;
}
@@ -1152,11 +1127,120 @@ error:
/*
+ * Return stats about a particular network
+ * interface. References:
+ * https://github.com/dpaleino/wicd/blob/master/wicd/backends/be-ioctl.py
+ * http://www.i-scream.org/libstatgrab/
+ */
+static PyObject*
+psutil_net_if_stats(PyObject* self, PyObject* args) {
+ kstat_ctl_t *kc = NULL;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+ int ret;
+ int sock = 0;
+ int duplex;
+ int speed;
+
+ PyObject *py_retdict = PyDict_New();
+ PyObject *py_ifc_info = NULL;
+ PyObject *py_is_up = NULL;
+
+ if (py_retdict == NULL)
+ return NULL;
+ kc = kstat_open();
+ if (kc == NULL)
+ goto error;
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == -1)
+ goto error;
+
+ for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
+ if (strcmp(ksp->ks_class, "net") == 0) {
+ struct ifreq ifr;
+
+ kstat_read(kc, ksp, NULL);
+ if (ksp->ks_type != KSTAT_TYPE_NAMED)
+ continue;
+ if (strcmp(ksp->ks_class, "net") != 0)
+ continue;
+
+ strncpy(ifr.ifr_name, ksp->ks_name, sizeof(ifr.ifr_name));
+ ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+ if (ret == -1)
+ continue; // not a network interface
+
+ // is up?
+ if ((ifr.ifr_flags & IFF_UP) != 0) {
+ if ((knp = kstat_data_lookup(ksp, "link_up")) != NULL) {
+ if (knp->value.ui32 != 0u)
+ py_is_up = Py_True;
+ else
+ py_is_up = Py_False;
+ }
+ else {
+ py_is_up = Py_True;
+ }
+ }
+ else {
+ py_is_up = Py_False;
+ }
+ Py_INCREF(py_is_up);
+
+ // duplex
+ duplex = 0; // unknown
+ if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) {
+ if (knp->value.ui32 == 1)
+ duplex = 1; // half
+ else if (knp->value.ui32 == 2)
+ duplex = 2; // full
+ }
+
+ // speed
+ if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL)
+ // expressed in bits per sec, we want mega bits per sec
+ speed = (int)knp->value.ui64 / 1000000;
+ else
+ speed = 0;
+
+ // mtu
+ ret = ioctl(sock, SIOCGIFMTU, &ifr);
+ if (ret == -1)
+ goto error;
+
+ py_ifc_info = Py_BuildValue("(Oiii)", py_is_up, duplex, speed,
+ ifr.ifr_mtu);
+ if (!py_ifc_info)
+ goto error;
+ if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info))
+ goto error;
+ Py_DECREF(py_ifc_info);
+ }
+ }
+
+ close(sock);
+ kstat_close(kc);
+ return py_retdict;
+
+error:
+ Py_XDECREF(py_is_up);
+ Py_XDECREF(py_ifc_info);
+ Py_DECREF(py_retdict);
+ if (sock != 0)
+ close(sock);
+ if (kc != NULL)
+ kstat_close(kc);
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+}
+
+
+/*
* define the psutil C module methods and initialize the module.
*/
static PyMethodDef
-PsutilMethods[] =
-{
+PsutilMethods[] = {
+
// --- process-related functions
{"proc_basic_info", psutil_proc_basic_info, METH_VARARGS,
"Return process ppid, rss, vms, ctime, nice, nthreads, status and tty"},
@@ -1192,8 +1276,10 @@ PsutilMethods[] =
"Return the number of physical CPUs on the system."},
{"net_connections", psutil_net_connections, METH_VARARGS,
"Return TCP and UDP syste-wide open connections."},
+ {"net_if_stats", psutil_net_if_stats, METH_VARARGS,
+ "Return NIC stats (isup, duplex, speed, mtu)"},
-{NULL, NULL, 0, NULL}
+ {NULL, NULL, 0, NULL}
};
@@ -1277,9 +1363,8 @@ void init_psutil_sunos(void)
PyModule_AddIntConstant(module, "TCPS_BOUND", TCPS_BOUND);
PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
- if (module == NULL) {
+ if (module == NULL)
INITERROR;
- }
#if PY_MAJOR_VERSION >= 3
return module;
#endif
diff --git a/psutil/_psutil_sunos.h b/psutil/_psutil_sunos.h
index 414a7d80..f93dbfe0 100644
--- a/psutil/_psutil_sunos.h
+++ b/psutil/_psutil_sunos.h
@@ -25,3 +25,4 @@ static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
static PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
static PyObject* psutil_users(PyObject* self, PyObject* args);
static PyObject* psutil_net_connections(PyObject* self, PyObject* args);
+static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index 1d0e3278..32f00b67 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -20,6 +20,7 @@
#include <winsock2.h>
#include <iphlpapi.h>
#include <wtsapi32.h>
+#include <ws2tcpip.h>
// Link with Iphlpapi.lib
#pragma comment(lib, "IPHLPAPI.lib")
@@ -30,18 +31,163 @@
#include "arch/windows/process_info.h"
#include "arch/windows/process_handles.h"
#include "arch/windows/ntextapi.h"
+#include "arch/windows/inet_ntop.h"
#ifdef __MINGW32__
#include "arch/windows/glpi.h"
#endif
+
+/*
+ * ============================================================================
+ * Utilities
+ * ============================================================================
+ */
+
+ // a flag for connections without an actual status
+static int PSUTIL_CONN_NONE = 128;
+
+#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+#define LO_T ((float)1e-7)
+#define HI_T (LO_T*4294967296.0)
+#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff)
+#ifndef AF_INET6
+#define AF_INET6 23
+#endif
+#define _psutil_conn_decref_objs() \
+ Py_DECREF(_AF_INET); \
+ Py_DECREF(_AF_INET6);\
+ Py_DECREF(_SOCK_STREAM);\
+ Py_DECREF(_SOCK_DGRAM);
+
+typedef BOOL (WINAPI *LPFN_GLPI)
+ (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
+
+// fix for mingw32, see
+// https://github.com/giampaolo/psutil/issues/351#c2
+typedef struct _DISK_PERFORMANCE_WIN_2008 {
+ LARGE_INTEGER BytesRead;
+ LARGE_INTEGER BytesWritten;
+ LARGE_INTEGER ReadTime;
+ LARGE_INTEGER WriteTime;
+ LARGE_INTEGER IdleTime;
+ DWORD ReadCount;
+ DWORD WriteCount;
+ DWORD QueueDepth;
+ DWORD SplitCount;
+ LARGE_INTEGER QueryTime;
+ DWORD StorageDeviceNumber;
+ WCHAR StorageManagerName[8];
+} DISK_PERFORMANCE_WIN_2008;
+
+// --- network connections mingw32 support
+#ifndef _IPRTRMIB_H
+typedef struct _MIB_TCP6ROW_OWNER_PID {
+ UCHAR ucLocalAddr[16];
+ DWORD dwLocalScopeId;
+ DWORD dwLocalPort;
+ UCHAR ucRemoteAddr[16];
+ DWORD dwRemoteScopeId;
+ DWORD dwRemotePort;
+ DWORD dwState;
+ DWORD dwOwningPid;
+} MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID;
+
+typedef struct _MIB_TCP6TABLE_OWNER_PID {
+ DWORD dwNumEntries;
+ MIB_TCP6ROW_OWNER_PID table[ANY_SIZE];
+} MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID;
+#endif
+
+#ifndef __IPHLPAPI_H__
+typedef struct in6_addr {
+ union {
+ UCHAR Byte[16];
+ USHORT Word[8];
+ } u;
+} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR;
+
+typedef enum _UDP_TABLE_CLASS {
+ UDP_TABLE_BASIC,
+ UDP_TABLE_OWNER_PID,
+ UDP_TABLE_OWNER_MODULE
+} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS;
+
+typedef struct _MIB_UDPROW_OWNER_PID {
+ DWORD dwLocalAddr;
+ DWORD dwLocalPort;
+ DWORD dwOwningPid;
+} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID;
+
+typedef struct _MIB_UDPTABLE_OWNER_PID {
+ DWORD dwNumEntries;
+ MIB_UDPROW_OWNER_PID table[ANY_SIZE];
+} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID;
+#endif
+
+typedef struct _MIB_UDP6ROW_OWNER_PID {
+ UCHAR ucLocalAddr[16];
+ DWORD dwLocalScopeId;
+ DWORD dwLocalPort;
+ DWORD dwOwningPid;
+} MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID;
+
+typedef struct _MIB_UDP6TABLE_OWNER_PID {
+ DWORD dwNumEntries;
+ MIB_UDP6ROW_OWNER_PID table[ANY_SIZE];
+} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID;
+
+PIP_ADAPTER_ADDRESSES
+psutil_get_nic_addresses() {
+ // allocate a 15 KB buffer to start with
+ int outBufLen = 15000;
+ DWORD dwRetVal = 0;
+ ULONG attempts = 0;
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+
+ do {
+ pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
+ if (pAddresses == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ dwRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses,
+ &outBufLen);
+ if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
+ free(pAddresses);
+ pAddresses = NULL;
+ }
+ else {
+ break;
+ }
+
+ attempts++;
+ } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3));
+
+ if (dwRetVal != NO_ERROR) {
+ PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed.");
+ return NULL;
+ }
+
+ return pAddresses;
+}
+
+
+/*
+ * ============================================================================
+ * Public Python API
+ * ============================================================================
+ */
+
+
/*
* Return a Python float representing the system uptime expressed in seconds
* since the epoch.
*/
static PyObject *
-psutil_boot_time(PyObject *self, PyObject *args)
-{
+psutil_boot_time(PyObject *self, PyObject *args) {
double uptime;
time_t pt;
FILETIME fileTime;
@@ -77,19 +223,16 @@ psutil_boot_time(PyObject *self, PyObject *args)
* Return 1 if PID exists in the current process list, else 0.
*/
static PyObject *
-psutil_pid_exists(PyObject *self, PyObject *args)
-{
+psutil_pid_exists(PyObject *self, PyObject *args) {
long pid;
int status;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
status = psutil_pid_is_running(pid);
- if (-1 == status) {
+ if (-1 == status)
return NULL; // exception raised in psutil_pid_is_running()
- }
return PyBool_FromLong(status);
}
@@ -98,38 +241,35 @@ psutil_pid_exists(PyObject *self, PyObject *args)
* Return a Python list of all the PIDs running on the system.
*/
static PyObject *
-psutil_pids(PyObject *self, PyObject *args)
-{
+psutil_pids(PyObject *self, PyObject *args) {
DWORD *proclist = NULL;
DWORD numberOfReturnedPIDs;
DWORD i;
- PyObject *pid = NULL;
- PyObject *retlist = PyList_New(0);
+ PyObject *py_pid = NULL;
+ PyObject *py_retlist = PyList_New(0);
- if (retlist == NULL) {
+ if (py_retlist == NULL)
return NULL;
- }
proclist = psutil_get_pids(&numberOfReturnedPIDs);
- if (NULL == proclist) {
+ if (proclist == NULL)
goto error;
- }
for (i = 0; i < numberOfReturnedPIDs; i++) {
- pid = Py_BuildValue("I", proclist[i]);
- if (!pid)
+ py_pid = Py_BuildValue("I", proclist[i]);
+ if (!py_pid)
goto error;
- if (PyList_Append(retlist, pid))
+ if (PyList_Append(py_retlist, py_pid))
goto error;
- Py_DECREF(pid);
+ Py_DECREF(py_pid);
}
// free C array allocated for PIDs
free(proclist);
- return retlist;
+ return py_retlist;
error:
- Py_XDECREF(pid);
- Py_DECREF(retlist);
+ Py_XDECREF(py_pid);
+ Py_DECREF(py_retlist);
if (proclist != NULL)
free(proclist);
return NULL;
@@ -140,17 +280,14 @@ error:
* Kill a process given its PID.
*/
static PyObject *
-psutil_proc_kill(PyObject *self, PyObject *args)
-{
+psutil_proc_kill(PyObject *self, PyObject *args) {
HANDLE hProcess;
long pid;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (pid == 0) {
+ if (pid == 0)
return AccessDenied();
- }
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (hProcess == NULL) {
@@ -180,20 +317,17 @@ psutil_proc_kill(PyObject *self, PyObject *args)
* Wait for process to terminate and return its exit code.
*/
static PyObject *
-psutil_proc_wait(PyObject *self, PyObject *args)
-{
+psutil_proc_wait(PyObject *self, PyObject *args) {
HANDLE hProcess;
DWORD ExitCode;
DWORD retVal;
long pid;
long timeout;
- if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) {
+ if (! PyArg_ParseTuple(args, "ll", &pid, &timeout))
return NULL;
- }
- if (pid == 0) {
+ if (pid == 0)
return AccessDenied();
- }
hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
FALSE, pid);
@@ -242,21 +376,17 @@ psutil_proc_wait(PyObject *self, PyObject *args)
* Return a Python tuple (user_time, kernel_time)
*/
static PyObject *
-psutil_proc_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_times(PyObject *self, PyObject *args) {
long pid;
HANDLE hProcess;
FILETIME ftCreate, ftExit, ftKernel, ftUser;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
hProcess = psutil_handle_from_pid(pid);
- if (hProcess == NULL) {
+ if (hProcess == NULL)
return NULL;
- }
-
if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
CloseHandle(hProcess);
if (GetLastError() == ERROR_ACCESS_DENIED) {
@@ -292,38 +422,11 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args)
/*
- * Alternative implementation of the one above but bypasses ACCESS DENIED.
- */
-static PyObject *
-psutil_proc_cpu_times_2(PyObject *self, PyObject *args)
-{
- DWORD pid;
- PSYSTEM_PROCESS_INFORMATION process;
- PVOID buffer;
- double user, kernel;
-
- if (! PyArg_ParseTuple(args, "l", &pid)) {
- return NULL;
- }
- if (! psutil_get_proc_info(pid, &process, &buffer)) {
- return NULL;
- }
- user = (double)process->UserTime.HighPart * 429.4967296 + \
- (double)process->UserTime.LowPart * 1e-7;
- kernel = (double)process->KernelTime.HighPart * 429.4967296 + \
- (double)process->KernelTime.LowPart * 1e-7;
- free(buffer);
- return Py_BuildValue("(dd)", user, kernel);
-}
-
-
-/*
* Return a Python float indicating the process create time expressed in
* seconds since the epoch.
*/
static PyObject *
-psutil_proc_create_time(PyObject *self, PyObject *args)
-{
+psutil_proc_create_time(PyObject *self, PyObject *args) {
long pid;
long long unix_time;
DWORD exitCode;
@@ -331,20 +434,16 @@ psutil_proc_create_time(PyObject *self, PyObject *args)
BOOL ret;
FILETIME ftCreate, ftExit, ftKernel, ftUser;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
// special case for PIDs 0 and 4, return system boot time
- if (0 == pid || 4 == pid) {
+ if (0 == pid || 4 == pid)
return psutil_boot_time(NULL, NULL);
- }
hProcess = psutil_handle_from_pid(pid);
- if (hProcess == NULL) {
+ if (hProcess == NULL)
return NULL;
- }
-
if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
CloseHandle(hProcess);
if (GetLastError() == ERROR_ACCESS_DENIED) {
@@ -366,9 +465,8 @@ psutil_proc_create_time(PyObject *self, PyObject *args)
ret = GetExitCodeProcess(hProcess, &exitCode);
CloseHandle(hProcess);
if (ret != 0) {
- if (exitCode != STILL_ACTIVE) {
+ if (exitCode != STILL_ACTIVE)
return NoSuchProcess();
- }
}
else {
// Ignore access denied as it means the process is still alive.
@@ -391,69 +489,28 @@ psutil_proc_create_time(PyObject *self, PyObject *args)
}
-/*
- * Alternative implementation of the one above but bypasses ACCESS DENIED.
- */
-static PyObject *
-psutil_proc_create_time_2(PyObject *self, PyObject *args)
-{
- DWORD pid;
- PSYSTEM_PROCESS_INFORMATION process;
- PVOID buffer;
- long long unix_time;
-
- if (! PyArg_ParseTuple(args, "l", &pid)) {
- return NULL;
- }
- if (! psutil_get_proc_info(pid, &process, &buffer)) {
- return NULL;
- }
- // special case for PIDs 0 and 4, return system boot time
- if (0 == pid || 4 == pid) {
- return psutil_boot_time(NULL, NULL);
- }
- /*
- Convert the LARGE_INTEGER union to a Unix time.
- It's the best I could find by googling and borrowing code here and there.
- The time returned has a precision of 1 second.
- */
- unix_time = ((LONGLONG)process->CreateTime.HighPart) << 32;
- unix_time += process->CreateTime.LowPart - 116444736000000000LL;
- unix_time /= 10000000;
- free(buffer);
- return Py_BuildValue("d", (double)unix_time);
-}
-
/*
* Return the number of logical CPUs.
*/
static PyObject *
-psutil_cpu_count_logical(PyObject *self, PyObject *args)
-{
+psutil_cpu_count_logical(PyObject *self, PyObject *args) {
SYSTEM_INFO system_info;
system_info.dwNumberOfProcessors = 0;
GetSystemInfo(&system_info);
- if (system_info.dwNumberOfProcessors == 0) {
- // mimic os.cpu_count()
- Py_RETURN_NONE;
- }
- else {
+ if (system_info.dwNumberOfProcessors == 0)
+ Py_RETURN_NONE; // mimic os.cpu_count()
+ else
return Py_BuildValue("I", system_info.dwNumberOfProcessors);
- }
}
-typedef BOOL (WINAPI *LPFN_GLPI) (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,
- PDWORD);
-
/*
* Return the number of physical CPU cores.
*/
static PyObject *
-psutil_cpu_count_phys(PyObject *self, PyObject *args)
-{
+psutil_cpu_count_phys(PyObject *self, PyObject *args) {
LPFN_GLPI glpi;
DWORD rc;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
@@ -518,36 +575,32 @@ static PyObject *
psutil_proc_cmdline(PyObject *self, PyObject *args) {
long pid;
int pid_return;
- PyObject *arglist;
+ PyObject *py_retlist;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if ((pid == 0) || (pid == 4)) {
+ if ((pid == 0) || (pid == 4))
return Py_BuildValue("[]");
- }
pid_return = psutil_pid_is_running(pid);
- if (pid_return == 0) {
+ if (pid_return == 0)
return NoSuchProcess();
- }
- if (pid_return == -1) {
+ if (pid_return == -1)
return NULL;
- }
// XXX the assumptio below probably needs to go away
// May fail any of several ReadProcessMemory calls etc. and
// not indicate a real problem so we ignore any errors and
// just live without commandline.
- arglist = psutil_get_arg_list(pid);
- if ( NULL == arglist ) {
+ py_retlist = psutil_get_cmdline(pid);
+ if ( NULL == py_retlist ) {
// carry on anyway, clear any exceptions too
PyErr_Clear();
return Py_BuildValue("[]");
}
- return arglist;
+ return py_retlist;
}
@@ -559,15 +612,13 @@ psutil_proc_exe(PyObject *self, PyObject *args) {
long pid;
HANDLE hProcess;
wchar_t exe[MAX_PATH];
- if (! PyArg_ParseTuple(args, "l", &pid)) {
- return NULL;
- }
+ if (! PyArg_ParseTuple(args, "l", &pid))
+ return NULL;
hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_QUERY_INFORMATION);
- if (NULL == hProcess) {
+ if (NULL == hProcess)
return NULL;
- }
- if (GetProcessImageFileNameW(hProcess, &exe, MAX_PATH) == 0) {
+ if (GetProcessImageFileNameW(hProcess, exe, MAX_PATH) == 0) {
CloseHandle(hProcess);
PyErr_SetFromWindowsErr(0);
return NULL;
@@ -578,11 +629,52 @@ psutil_proc_exe(PyObject *self, PyObject *args) {
/*
+ * Return process base name.
+ * Note: psutil_proc_exe() is attempted first because it's faster
+ * but it raise AccessDenied for processes owned by other users
+ * in which case we fall back on using this.
+ */
+static PyObject *
+psutil_proc_name(PyObject *self, PyObject *args) {
+ long pid;
+ int ok;
+ PROCESSENTRY32W pentry;
+ HANDLE hSnapShot;
+
+ if (! PyArg_ParseTuple(args, "l", &pid))
+ return NULL;
+ hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid);
+ if (hSnapShot == INVALID_HANDLE_VALUE) {
+ PyErr_SetFromWindowsErr(0);
+ return NULL;
+ }
+ pentry.dwSize = sizeof(PROCESSENTRY32W);
+ ok = Process32FirstW(hSnapShot, &pentry);
+ if (! ok) {
+ CloseHandle(hSnapShot);
+ PyErr_SetFromWindowsErr(0);
+ return NULL;
+ }
+ while (ok) {
+ if (pentry.th32ProcessID == pid) {
+ CloseHandle(hSnapShot);
+ return PyUnicode_FromWideChar(
+ pentry.szExeFile, wcslen(pentry.szExeFile));
+ }
+ ok = Process32NextW(hSnapShot, &pentry);
+ }
+
+ CloseHandle(hSnapShot);
+ NoSuchProcess();
+ return NULL;
+}
+
+
+/*
* Return process memory information as a Python tuple.
*/
static PyObject *
-psutil_proc_memory_info(PyObject *self, PyObject *args)
-{
+psutil_proc_memory_info(PyObject *self, PyObject *args) {
HANDLE hProcess;
DWORD pid;
#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2
@@ -592,16 +684,15 @@ psutil_proc_memory_info(PyObject *self, PyObject *args)
#endif
SIZE_T private = 0;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
hProcess = psutil_handle_from_pid(pid);
- if (NULL == hProcess) {
+ if (NULL == hProcess)
return NULL;
- }
- if (! GetProcessMemoryInfo(hProcess, &cnt, sizeof(cnt)) ) {
+ if (! GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&cnt,
+ sizeof(cnt))) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
}
@@ -650,8 +741,7 @@ psutil_proc_memory_info(PyObject *self, PyObject *args)
* Alternative implementation of the one above but bypasses ACCESS DENIED.
*/
static PyObject *
-psutil_proc_memory_info_2(PyObject *self, PyObject *args)
-{
+psutil_proc_memory_info_2(PyObject *self, PyObject *args) {
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
@@ -664,12 +754,10 @@ psutil_proc_memory_info_2(PyObject *self, PyObject *args)
unsigned int m1, m2, m3, m4, m5, m6, m7, m8;
#endif
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (! psutil_get_proc_info(pid, &process, &buffer)) {
+ if (! psutil_get_proc_info(pid, &process, &buffer))
return NULL;
- }
#if (_WIN32_WINNT >= 0x0501) // Windows XP with SP2
private = process->PrivatePageCount;
@@ -707,15 +795,12 @@ psutil_proc_memory_info_2(PyObject *self, PyObject *args)
* in bytes.
*/
static PyObject *
-psutil_virtual_mem(PyObject *self, PyObject *args)
-{
+psutil_virtual_mem(PyObject *self, PyObject *args) {
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
- if (! GlobalMemoryStatusEx(&memInfo) ) {
+ if (! GlobalMemoryStatusEx(&memInfo))
return PyErr_SetFromWindowsErr(0);
- }
-
return Py_BuildValue("(LLLLLL)",
memInfo.ullTotalPhys, // total
memInfo.ullAvailPhys, // avail
@@ -726,24 +811,18 @@ psutil_virtual_mem(PyObject *self, PyObject *args)
}
-#define LO_T ((float)1e-7)
-#define HI_T (LO_T*4294967296.0)
-
-
/*
* Retrieves system CPU timing information as a (user, system, idle)
* tuple. On a multiprocessor system, the values returned are the
* sum of the designated times across all processors.
*/
static PyObject *
-psutil_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_cpu_times(PyObject *self, PyObject *args) {
float idle, kernel, user, system;
FILETIME idle_time, kernel_time, user_time;
- if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) {
+ if (!GetSystemTimes(&idle_time, &kernel_time, &user_time))
return PyErr_SetFromWindowsErr(0);
- }
idle = (float)((HI_T * idle_time.dwHighDateTime) + \
(LO_T * idle_time.dwLowDateTime));
@@ -764,8 +843,7 @@ psutil_cpu_times(PyObject *self, PyObject *args)
* Same as above but for all system CPUs.
*/
static PyObject *
-psutil_per_cpu_times(PyObject *self, PyObject *args)
-{
+psutil_per_cpu_times(PyObject *self, PyObject *args) {
float idle, kernel, user;
typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG);
NTQSI_PROC NtQuerySystemInformation;
@@ -773,10 +851,10 @@ psutil_per_cpu_times(PyObject *self, PyObject *args)
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
SYSTEM_INFO si;
UINT i;
- PyObject *arg = NULL;
- PyObject *retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
+ PyObject *py_retlist = PyList_New(0);
- if (retlist == NULL)
+ if (py_retlist == NULL)
return NULL;
// dynamic linking is mandatory to use NtQuerySystemInformation
@@ -786,8 +864,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args)
NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
hNtDll, "NtQuerySystemInformation");
- if (NtQuerySystemInformation != NULL)
- {
+ if (NtQuerySystemInformation != NULL) {
// retrives number of processors
GetSystemInfo(&si);
@@ -796,8 +873,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args)
sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \
malloc(si.dwNumberOfProcessors * \
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
- if (sppi != NULL)
- {
+ if (sppi != NULL) {
// gets cpu time informations
if (0 == NtQuerySystemInformation(
SystemProcessorPerformanceInformation,
@@ -811,7 +887,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args)
// processor value
idle = user = kernel = 0;
for (i = 0; i < si.dwNumberOfProcessors; i++) {
- arg = NULL;
+ py_tuple = NULL;
user = (float)((HI_T * sppi[i].UserTime.HighPart) +
(LO_T * sppi[i].UserTime.LowPart));
idle = (float)((HI_T * sppi[i].IdleTime.HighPart) +
@@ -821,19 +897,19 @@ psutil_per_cpu_times(PyObject *self, PyObject *args)
// kernel time includes idle time on windows
// we return only busy kernel time subtracting
// idle time from kernel time
- arg = Py_BuildValue("(ddd)",
+ py_tuple = Py_BuildValue("(ddd)",
user,
kernel - idle,
idle);
- if (!arg)
+ if (!py_tuple)
goto error;
- if (PyList_Append(retlist, arg))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(arg);
+ Py_DECREF(py_tuple);
}
free(sppi);
FreeLibrary(hNtDll);
- return retlist;
+ return py_retlist;
} // END NtQuerySystemInformation
} // END malloc SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
@@ -842,14 +918,12 @@ psutil_per_cpu_times(PyObject *self, PyObject *args)
goto error;
error:
- Py_XDECREF(arg);
- Py_DECREF(retlist);
- if (sppi) {
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
+ if (sppi)
free(sppi);
- }
- if (hNtDll) {
+ if (hNtDll)
FreeLibrary(hNtDll);
- }
PyErr_SetFromWindowsErr(0);
return NULL;
}
@@ -860,26 +934,21 @@ error:
*/
static PyObject *
-psutil_proc_cwd(PyObject *self, PyObject *args)
-{
+psutil_proc_cwd(PyObject *self, PyObject *args) {
long pid;
HANDLE processHandle = NULL;
PVOID pebAddress;
PVOID rtlUserProcParamsAddress;
UNICODE_STRING currentDirectory;
WCHAR *currentDirectoryContent = NULL;
- PyObject *returnPyObj = NULL;
- PyObject *cwd_from_wchar = NULL;
- PyObject *cwd = NULL;
+ PyObject *py_unicode = NULL;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
processHandle = psutil_handle_from_pid(pid);
- if (processHandle == NULL) {
+ if (processHandle == NULL)
return NULL;
- }
pebAddress = psutil_get_peb_address(processHandle);
@@ -953,36 +1022,17 @@ psutil_proc_cwd(PyObject *self, PyObject *args)
// currentDirectory.Length is in bytes
currentDirectoryContent[(currentDirectory.Length / sizeof(WCHAR))] = '\0';
- // convert wchar array to a Python unicode string, and then to UTF8
- cwd_from_wchar = PyUnicode_FromWideChar(currentDirectoryContent,
- wcslen(currentDirectoryContent));
- if (cwd_from_wchar == NULL)
- goto error;
-
-#if PY_MAJOR_VERSION >= 3
- cwd = PyUnicode_FromObject(cwd_from_wchar);
-#else
- cwd = PyUnicode_AsUTF8String(cwd_from_wchar);
-#endif
- if (cwd == NULL)
+ // convert wchar array to a Python unicode string
+ py_unicode = PyUnicode_FromWideChar(
+ currentDirectoryContent, wcslen(currentDirectoryContent));
+ if (py_unicode == NULL)
goto error;
-
- // decrement the reference count on our temp unicode str to avoid
- // mem leak
- returnPyObj = Py_BuildValue("N", cwd);
- if (!returnPyObj)
- goto error;
-
- Py_DECREF(cwd_from_wchar);
-
CloseHandle(processHandle);
free(currentDirectoryContent);
- return returnPyObj;
+ return py_unicode;
error:
- Py_XDECREF(cwd_from_wchar);
- Py_XDECREF(cwd);
- Py_XDECREF(returnPyObj);
+ Py_XDECREF(py_unicode);
if (currentDirectoryContent != NULL)
free(currentDirectoryContent);
if (processHandle != NULL)
@@ -995,8 +1045,7 @@ error:
* Resume or suspends a process
*/
int
-psutil_proc_suspend_or_resume(DWORD pid, int suspend)
-{
+psutil_proc_suspend_or_resume(DWORD pid, int suspend) {
// a huge thanks to http://www.codeproject.com/KB/threads/pausep.aspx
HANDLE hThreadSnap = NULL;
THREADENTRY32 te32 = {0};
@@ -1064,76 +1113,47 @@ psutil_proc_suspend_or_resume(DWORD pid, int suspend)
static PyObject *
-psutil_proc_suspend(PyObject *self, PyObject *args)
-{
+psutil_proc_suspend(PyObject *self, PyObject *args) {
long pid;
int suspend = 1;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
- return NULL;
- }
- if (! psutil_proc_suspend_or_resume(pid, suspend)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
+ return NULL;
+ if (! psutil_proc_suspend_or_resume(pid, suspend))
return NULL;
- }
Py_RETURN_NONE;
}
static PyObject *
-psutil_proc_resume(PyObject *self, PyObject *args)
-{
+psutil_proc_resume(PyObject *self, PyObject *args) {
long pid;
int suspend = 0;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
- return NULL;
- }
- if (! psutil_proc_suspend_or_resume(pid, suspend)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- Py_RETURN_NONE;
-}
-
-
-static PyObject *
-psutil_proc_num_threads(PyObject *self, PyObject *args)
-{
- DWORD pid;
- PSYSTEM_PROCESS_INFORMATION process;
- PVOID buffer;
- int num;
-
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! psutil_proc_suspend_or_resume(pid, suspend))
return NULL;
- }
- if (! psutil_get_proc_info(pid, &process, &buffer)) {
- return NULL;
- }
- num = (int)process->NumberOfThreads;
- free(buffer);
- return Py_BuildValue("i", num);
+ Py_RETURN_NONE;
}
static PyObject *
-psutil_proc_threads(PyObject *self, PyObject *args)
-{
+psutil_proc_threads(PyObject *self, PyObject *args) {
HANDLE hThread;
THREADENTRY32 te32 = {0};
long pid;
int pid_return;
int rc;
FILETIME ftDummy, ftKernel, ftUser;
- PyObject *retList = PyList_New(0);
- PyObject *pyTuple = NULL;
HANDLE hThreadSnap = NULL;
+ PyObject *py_tuple = NULL;
+ PyObject *py_retlist = PyList_New(0);
- if (retList == NULL) {
+ if (py_retlist == NULL)
return NULL;
- }
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
- }
if (pid == 0) {
// raise AD instead of returning 0 as procexp is able to
// retrieve useful information somehow
@@ -1146,9 +1166,8 @@ psutil_proc_threads(PyObject *self, PyObject *args)
NoSuchProcess();
goto error;
}
- if (pid_return == -1) {
+ if (pid_return == -1)
goto error;
- }
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE) {
@@ -1166,11 +1185,9 @@ psutil_proc_threads(PyObject *self, PyObject *args)
// Walk the thread snapshot to find all threads of the process.
// If the thread belongs to the process, increase the counter.
- do
- {
- if (te32.th32OwnerProcessID == pid)
- {
- pyTuple = NULL;
+ do {
+ if (te32.th32OwnerProcessID == pid) {
+ py_tuple = NULL;
hThread = NULL;
hThread = OpenThread(THREAD_QUERY_INFORMATION,
FALSE, te32.th32ThreadID);
@@ -1195,61 +1212,55 @@ psutil_proc_threads(PyObject *self, PyObject *args)
* process has executed in user/kernel mode I borrowed the code
* below from Python's Modules/posixmodule.c
*/
- pyTuple = Py_BuildValue(
+ py_tuple = Py_BuildValue(
"kdd",
te32.th32ThreadID,
(double)(ftUser.dwHighDateTime * 429.4967296 + \
ftUser.dwLowDateTime * 1e-7),
(double)(ftKernel.dwHighDateTime * 429.4967296 + \
ftKernel.dwLowDateTime * 1e-7));
- if (!pyTuple)
+ if (!py_tuple)
goto error;
- if (PyList_Append(retList, pyTuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
- Py_DECREF(pyTuple);
+ Py_DECREF(py_tuple);
CloseHandle(hThread);
}
} while (Thread32Next(hThreadSnap, &te32));
CloseHandle(hThreadSnap);
- return retList;
+ return py_retlist;
error:
- Py_XDECREF(pyTuple);
- Py_DECREF(retList);
+ Py_XDECREF(py_tuple);
+ Py_DECREF(py_retlist);
if (hThread != NULL)
CloseHandle(hThread);
- if (hThreadSnap != NULL) {
+ if (hThreadSnap != NULL)
CloseHandle(hThreadSnap);
- }
return NULL;
}
static PyObject *
-psutil_proc_open_files(PyObject *self, PyObject *args)
-{
+psutil_proc_open_files(PyObject *self, PyObject *args) {
long pid;
HANDLE processHandle;
DWORD access = PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
- PyObject *filesList;
+ PyObject *py_retlist;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
processHandle = psutil_handle_from_pid_waccess(pid, access);
- if (processHandle == NULL) {
+ if (processHandle == NULL)
return NULL;
- }
-
- filesList = psutil_get_open_files(pid, processHandle);
+ py_retlist = psutil_get_open_files(pid, processHandle);
CloseHandle(processHandle);
- if (filesList == NULL) {
+ if (py_retlist == NULL)
return PyErr_SetFromWindowsErr(0);
- }
- return filesList;
+ return py_retlist;
}
@@ -1259,23 +1270,20 @@ psutil_proc_open_files(PyObject *self, PyObject *args)
If no match is found return an empty string.
*/
static PyObject *
-psutil_win32_QueryDosDevice(PyObject *self, PyObject *args)
-{
+psutil_win32_QueryDosDevice(PyObject *self, PyObject *args) {
LPCTSTR lpDevicePath;
TCHAR d = TEXT('A');
TCHAR szBuff[5];
- if (!PyArg_ParseTuple(args, "s", &lpDevicePath)) {
+ if (!PyArg_ParseTuple(args, "s", &lpDevicePath))
return NULL;
- }
- while (d <= TEXT('Z'))
- {
+ while (d <= TEXT('Z')) {
TCHAR szDeviceName[3] = {d, TEXT(':'), TEXT('\0')};
TCHAR szTarget[512] = {0};
if (QueryDosDevice(szDeviceName, szTarget, 511) != 0) {
if (_tcscmp(lpDevicePath, szTarget) == 0) {
- _stprintf(szBuff, TEXT("%c:"), d);
+ _stprintf_s(szBuff, _countof(szBuff), TEXT("%c:"), d);
return Py_BuildValue("s", szBuff);
}
}
@@ -1289,8 +1297,7 @@ psutil_win32_QueryDosDevice(PyObject *self, PyObject *args)
* Return process username as a "DOMAIN//USERNAME" string.
*/
static PyObject *
-psutil_proc_username(PyObject *self, PyObject *args)
-{
+psutil_proc_username(PyObject *self, PyObject *args) {
long pid;
HANDLE processHandle;
HANDLE tokenHandle;
@@ -1302,17 +1309,15 @@ psutil_proc_username(PyObject *self, PyObject *args)
ULONG domainNameSize;
SID_NAME_USE nameUse;
PTSTR fullName;
- PyObject *returnObject;
+ PyObject *py_unicode;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
processHandle = psutil_handle_from_pid_waccess(
pid, PROCESS_QUERY_INFORMATION);
- if (processHandle == NULL) {
+ if (processHandle == NULL)
return NULL;
- }
if (!OpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)) {
CloseHandle(processHandle);
@@ -1325,9 +1330,8 @@ psutil_proc_username(PyObject *self, PyObject *args)
bufferSize = 0x100;
user = malloc(bufferSize);
- if (user == NULL) {
+ if (user == NULL)
return PyErr_NoMemory();
- }
if (!GetTokenInformation(tokenHandle, TokenUser, user, bufferSize,
&bufferSize))
@@ -1398,7 +1402,7 @@ psutil_proc_username(PyObject *self, PyObject *args)
memcpy(&fullName[domainNameSize + 1], name, nameSize);
fullName[domainNameSize + 1 + nameSize] = '\0';
- returnObject = PyUnicode_Decode(
+ py_unicode = PyUnicode_Decode(
fullName, _tcslen(fullName), Py_FileSystemDefaultEncoding, "replace");
free(fullName);
@@ -1406,104 +1410,17 @@ psutil_proc_username(PyObject *self, PyObject *args)
free(domainName);
free(user);
- return returnObject;
+ return py_unicode;
}
-// --- network connections mingw32 support
-
-#ifndef _IPRTRMIB_H
-typedef struct _MIB_TCP6ROW_OWNER_PID {
- UCHAR ucLocalAddr[16];
- DWORD dwLocalScopeId;
- DWORD dwLocalPort;
- UCHAR ucRemoteAddr[16];
- DWORD dwRemoteScopeId;
- DWORD dwRemotePort;
- DWORD dwState;
- DWORD dwOwningPid;
-} MIB_TCP6ROW_OWNER_PID, *PMIB_TCP6ROW_OWNER_PID;
-
-typedef struct _MIB_TCP6TABLE_OWNER_PID {
- DWORD dwNumEntries;
- MIB_TCP6ROW_OWNER_PID table[ANY_SIZE];
-} MIB_TCP6TABLE_OWNER_PID, *PMIB_TCP6TABLE_OWNER_PID;
-#endif
-
-#ifndef __IPHLPAPI_H__
-typedef struct in6_addr {
- union {
- UCHAR Byte[16];
- USHORT Word[8];
- } u;
-} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR;
-
-typedef enum _UDP_TABLE_CLASS {
- UDP_TABLE_BASIC,
- UDP_TABLE_OWNER_PID,
- UDP_TABLE_OWNER_MODULE
-} UDP_TABLE_CLASS, *PUDP_TABLE_CLASS;
-
-typedef struct _MIB_UDPROW_OWNER_PID {
- DWORD dwLocalAddr;
- DWORD dwLocalPort;
- DWORD dwOwningPid;
-} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID;
-
-typedef struct _MIB_UDPTABLE_OWNER_PID {
- DWORD dwNumEntries;
- MIB_UDPROW_OWNER_PID table[ANY_SIZE];
-} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID;
-#endif
-
-typedef struct _MIB_UDP6ROW_OWNER_PID {
- UCHAR ucLocalAddr[16];
- DWORD dwLocalScopeId;
- DWORD dwLocalPort;
- DWORD dwOwningPid;
-} MIB_UDP6ROW_OWNER_PID, *PMIB_UDP6ROW_OWNER_PID;
-
-typedef struct _MIB_UDP6TABLE_OWNER_PID {
- DWORD dwNumEntries;
- MIB_UDP6ROW_OWNER_PID table[ANY_SIZE];
-} MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID;
-
-
-#define BYTESWAP_USHORT(x) ((((USHORT)(x) << 8) | ((USHORT)(x) >> 8)) & 0xffff)
-
-#ifndef AF_INET6
-#define AF_INET6 23
-#endif
-
-#define _psutil_conn_decref_objs() \
- Py_DECREF(_AF_INET); \
- Py_DECREF(_AF_INET6);\
- Py_DECREF(_SOCK_STREAM);\
- Py_DECREF(_SOCK_DGRAM);
-
-// a signaler for connections without an actual status
-static int PSUTIL_CONN_NONE = 128;
-
-
/*
* Return a list of network connections opened by a process
*/
static PyObject *
-psutil_net_connections(PyObject *self, PyObject *args)
-{
+psutil_net_connections(PyObject *self, PyObject *args) {
static long null_address[4] = { 0, 0, 0, 0 };
-
unsigned long pid;
- PyObject *connectionsList;
- PyObject *connectionTuple = NULL;
- PyObject *af_filter = NULL;
- PyObject *type_filter = NULL;
-
- PyObject *_AF_INET = PyLong_FromLong((long)AF_INET);
- PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6);
- PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM);
- PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM);
-
typedef PSTR (NTAPI * _RtlIpv4AddressToStringA)(struct in_addr *, PSTR);
_RtlIpv4AddressToStringA rtlIpv4AddressToStringA;
typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(struct in6_addr *, PSTR);
@@ -1522,16 +1439,26 @@ psutil_net_connections(PyObject *self, PyObject *args)
PMIB_UDP6TABLE_OWNER_PID udp6Table;
ULONG i;
CHAR addressBufferLocal[65];
- PyObject *addressTupleLocal = NULL;
CHAR addressBufferRemote[65];
- PyObject *addressTupleRemote = NULL;
- if (! PyArg_ParseTuple(args, "lOO", &pid, &af_filter, &type_filter)) {
+ PyObject *py_retlist;
+ PyObject *py_conn_tuple = NULL;
+ PyObject *py_af_filter = NULL;
+ PyObject *py_type_filter = NULL;
+ PyObject *py_addr_tuple_local = NULL;
+ PyObject *py_addr_tuple_remote = NULL;
+ PyObject *_AF_INET = PyLong_FromLong((long)AF_INET);
+ PyObject *_AF_INET6 = PyLong_FromLong((long)AF_INET6);
+ PyObject *_SOCK_STREAM = PyLong_FromLong((long)SOCK_STREAM);
+ PyObject *_SOCK_DGRAM = PyLong_FromLong((long)SOCK_DGRAM);
+
+ if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
+ {
_psutil_conn_decref_objs();
return NULL;
}
- if (!PySequence_Check(af_filter) || !PySequence_Check(type_filter)) {
+ if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
_psutil_conn_decref_objs();
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
return NULL;
@@ -1572,21 +1499,21 @@ psutil_net_connections(PyObject *self, PyObject *args)
return NULL;
}
- connectionsList = PyList_New(0);
- if (connectionsList == NULL) {
+ py_retlist = PyList_New(0);
+ if (py_retlist == NULL) {
_psutil_conn_decref_objs();
return NULL;
}
// TCP IPv4
- if ((PySequence_Contains(af_filter, _AF_INET) == 1) &&
- (PySequence_Contains(type_filter, _SOCK_STREAM) == 1))
+ if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) &&
+ (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1))
{
table = NULL;
- connectionTuple = NULL;
- addressTupleLocal = NULL;
- addressTupleRemote = NULL;
+ py_conn_tuple = NULL;
+ py_addr_tuple_local = NULL;
+ py_addr_tuple_remote = NULL;
tableSize = 0;
getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET,
TCP_TABLE_OWNER_PID_ALL, 0);
@@ -1617,16 +1544,16 @@ psutil_net_connections(PyObject *self, PyObject *args)
addr.S_un.S_addr = tcp4Table->table[i].dwLocalAddr;
rtlIpv4AddressToStringA(&addr, addressBufferLocal);
- addressTupleLocal = Py_BuildValue(
+ py_addr_tuple_local = Py_BuildValue(
"(si)",
addressBufferLocal,
BYTESWAP_USHORT(tcp4Table->table[i].dwLocalPort));
}
else {
- addressTupleLocal = PyTuple_New(0);
+ py_addr_tuple_local = PyTuple_New(0);
}
- if (addressTupleLocal == NULL)
+ if (py_addr_tuple_local == NULL)
goto error;
// On Windows <= XP, remote addr is filled even if socket
@@ -1639,33 +1566,33 @@ psutil_net_connections(PyObject *self, PyObject *args)
addr.S_un.S_addr = tcp4Table->table[i].dwRemoteAddr;
rtlIpv4AddressToStringA(&addr, addressBufferRemote);
- addressTupleRemote = Py_BuildValue(
+ py_addr_tuple_remote = Py_BuildValue(
"(si)",
addressBufferRemote,
BYTESWAP_USHORT(tcp4Table->table[i].dwRemotePort));
}
else
{
- addressTupleRemote = PyTuple_New(0);
+ py_addr_tuple_remote = PyTuple_New(0);
}
- if (addressTupleRemote == NULL)
+ if (py_addr_tuple_remote == NULL)
goto error;
- connectionTuple = Py_BuildValue(
+ py_conn_tuple = Py_BuildValue(
"(iiiNNiI)",
-1,
AF_INET,
SOCK_STREAM,
- addressTupleLocal,
- addressTupleRemote,
+ py_addr_tuple_local,
+ py_addr_tuple_remote,
tcp4Table->table[i].dwState,
tcp4Table->table[i].dwOwningPid);
- if (!connectionTuple)
+ if (!py_conn_tuple)
goto error;
- if (PyList_Append(connectionsList, connectionTuple))
+ if (PyList_Append(py_retlist, py_conn_tuple))
goto error;
- Py_DECREF(connectionTuple);
+ Py_DECREF(py_conn_tuple);
}
}
@@ -1674,13 +1601,13 @@ psutil_net_connections(PyObject *self, PyObject *args)
// TCP IPv6
- if ((PySequence_Contains(af_filter, _AF_INET6) == 1) &&
- (PySequence_Contains(type_filter, _SOCK_STREAM) == 1))
+ if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) &&
+ (PySequence_Contains(py_type_filter, _SOCK_STREAM) == 1))
{
table = NULL;
- connectionTuple = NULL;
- addressTupleLocal = NULL;
- addressTupleRemote = NULL;
+ py_conn_tuple = NULL;
+ py_addr_tuple_local = NULL;
+ py_addr_tuple_remote = NULL;
tableSize = 0;
getExtendedTcpTable(NULL, &tableSize, FALSE, AF_INET6,
TCP_TABLE_OWNER_PID_ALL, 0);
@@ -1711,17 +1638,16 @@ psutil_net_connections(PyObject *self, PyObject *args)
memcpy(&addr, tcp6Table->table[i].ucLocalAddr, 16);
rtlIpv6AddressToStringA(&addr, addressBufferLocal);
- addressTupleLocal = Py_BuildValue(
+ py_addr_tuple_local = Py_BuildValue(
"(si)",
addressBufferLocal,
BYTESWAP_USHORT(tcp6Table->table[i].dwLocalPort));
}
- else
- {
- addressTupleLocal = PyTuple_New(0);
+ else {
+ py_addr_tuple_local = PyTuple_New(0);
}
- if (addressTupleLocal == NULL)
+ if (py_addr_tuple_local == NULL)
goto error;
// On Windows <= XP, remote addr is filled even if socket
@@ -1735,33 +1661,32 @@ psutil_net_connections(PyObject *self, PyObject *args)
memcpy(&addr, tcp6Table->table[i].ucRemoteAddr, 16);
rtlIpv6AddressToStringA(&addr, addressBufferRemote);
- addressTupleRemote = Py_BuildValue(
+ py_addr_tuple_remote = Py_BuildValue(
"(si)",
addressBufferRemote,
BYTESWAP_USHORT(tcp6Table->table[i].dwRemotePort));
}
- else
- {
- addressTupleRemote = PyTuple_New(0);
+ else {
+ py_addr_tuple_remote = PyTuple_New(0);
}
- if (addressTupleRemote == NULL)
+ if (py_addr_tuple_remote == NULL)
goto error;
- connectionTuple = Py_BuildValue(
+ py_conn_tuple = Py_BuildValue(
"(iiiNNiI)",
-1,
AF_INET6,
SOCK_STREAM,
- addressTupleLocal,
- addressTupleRemote,
+ py_addr_tuple_local,
+ py_addr_tuple_remote,
tcp6Table->table[i].dwState,
tcp6Table->table[i].dwOwningPid);
- if (!connectionTuple)
+ if (!py_conn_tuple)
goto error;
- if (PyList_Append(connectionsList, connectionTuple))
+ if (PyList_Append(py_retlist, py_conn_tuple))
goto error;
- Py_DECREF(connectionTuple);
+ Py_DECREF(py_conn_tuple);
}
}
@@ -1770,13 +1695,13 @@ psutil_net_connections(PyObject *self, PyObject *args)
// UDP IPv4
- if ((PySequence_Contains(af_filter, _AF_INET) == 1) &&
- (PySequence_Contains(type_filter, _SOCK_DGRAM) == 1))
+ if ((PySequence_Contains(py_af_filter, _AF_INET) == 1) &&
+ (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1))
{
table = NULL;
- connectionTuple = NULL;
- addressTupleLocal = NULL;
- addressTupleRemote = NULL;
+ py_conn_tuple = NULL;
+ py_addr_tuple_local = NULL;
+ py_addr_tuple_remote = NULL;
tableSize = 0;
getExtendedUdpTable(NULL, &tableSize, FALSE, AF_INET,
UDP_TABLE_OWNER_PID, 0);
@@ -1807,32 +1732,32 @@ psutil_net_connections(PyObject *self, PyObject *args)
addr.S_un.S_addr = udp4Table->table[i].dwLocalAddr;
rtlIpv4AddressToStringA(&addr, addressBufferLocal);
- addressTupleLocal = Py_BuildValue(
+ py_addr_tuple_local = Py_BuildValue(
"(si)",
addressBufferLocal,
BYTESWAP_USHORT(udp4Table->table[i].dwLocalPort));
}
else {
- addressTupleLocal = PyTuple_New(0);
+ py_addr_tuple_local = PyTuple_New(0);
}
- if (addressTupleLocal == NULL)
+ if (py_addr_tuple_local == NULL)
goto error;
- connectionTuple = Py_BuildValue(
+ py_conn_tuple = Py_BuildValue(
"(iiiNNiI)",
-1,
AF_INET,
SOCK_DGRAM,
- addressTupleLocal,
+ py_addr_tuple_local,
PyTuple_New(0),
PSUTIL_CONN_NONE,
udp4Table->table[i].dwOwningPid);
- if (!connectionTuple)
+ if (!py_conn_tuple)
goto error;
- if (PyList_Append(connectionsList, connectionTuple))
+ if (PyList_Append(py_retlist, py_conn_tuple))
goto error;
- Py_DECREF(connectionTuple);
+ Py_DECREF(py_conn_tuple);
}
}
@@ -1841,13 +1766,13 @@ psutil_net_connections(PyObject *self, PyObject *args)
// UDP IPv6
- if ((PySequence_Contains(af_filter, _AF_INET6) == 1) &&
- (PySequence_Contains(type_filter, _SOCK_DGRAM) == 1))
+ if ((PySequence_Contains(py_af_filter, _AF_INET6) == 1) &&
+ (PySequence_Contains(py_type_filter, _SOCK_DGRAM) == 1))
{
table = NULL;
- connectionTuple = NULL;
- addressTupleLocal = NULL;
- addressTupleRemote = NULL;
+ py_conn_tuple = NULL;
+ py_addr_tuple_local = NULL;
+ py_addr_tuple_remote = NULL;
tableSize = 0;
getExtendedUdpTable(NULL, &tableSize, FALSE,
AF_INET6, UDP_TABLE_OWNER_PID, 0);
@@ -1863,8 +1788,7 @@ psutil_net_connections(PyObject *self, PyObject *args)
{
udp6Table = table;
- for (i = 0; i < udp6Table->dwNumEntries; i++)
- {
+ for (i = 0; i < udp6Table->dwNumEntries; i++) {
if (pid != -1) {
if (udp6Table->table[i].dwOwningPid != pid) {
continue;
@@ -1878,32 +1802,32 @@ psutil_net_connections(PyObject *self, PyObject *args)
memcpy(&addr, udp6Table->table[i].ucLocalAddr, 16);
rtlIpv6AddressToStringA(&addr, addressBufferLocal);
- addressTupleLocal = Py_BuildValue(
+ py_addr_tuple_local = Py_BuildValue(
"(si)",
addressBufferLocal,
BYTESWAP_USHORT(udp6Table->table[i].dwLocalPort));
}
else {
- addressTupleLocal = PyTuple_New(0);
+ py_addr_tuple_local = PyTuple_New(0);
}
- if (addressTupleLocal == NULL)
+ if (py_addr_tuple_local == NULL)
goto error;
- connectionTuple = Py_BuildValue(
+ py_conn_tuple = Py_BuildValue(
"(iiiNNiI)",
-1,
AF_INET6,
SOCK_DGRAM,
- addressTupleLocal,
+ py_addr_tuple_local,
PyTuple_New(0),
PSUTIL_CONN_NONE,
udp6Table->table[i].dwOwningPid);
- if (!connectionTuple)
+ if (!py_conn_tuple)
goto error;
- if (PyList_Append(connectionsList, connectionTuple))
+ if (PyList_Append(py_retlist, py_conn_tuple))
goto error;
- Py_DECREF(connectionTuple);
+ Py_DECREF(py_conn_tuple);
}
}
@@ -1911,14 +1835,14 @@ psutil_net_connections(PyObject *self, PyObject *args)
}
_psutil_conn_decref_objs();
- return connectionsList;
+ return py_retlist;
error:
_psutil_conn_decref_objs();
- Py_XDECREF(connectionTuple);
- Py_XDECREF(addressTupleLocal);
- Py_XDECREF(addressTupleRemote);
- Py_DECREF(connectionsList);
+ Py_XDECREF(py_conn_tuple);
+ Py_XDECREF(py_addr_tuple_local);
+ Py_XDECREF(py_addr_tuple_remote);
+ Py_DECREF(py_retlist);
if (table != NULL)
free(table);
return NULL;
@@ -1929,20 +1853,16 @@ error:
* Get process priority as a Python integer.
*/
static PyObject *
-psutil_proc_priority_get(PyObject *self, PyObject *args)
-{
+psutil_proc_priority_get(PyObject *self, PyObject *args) {
long pid;
DWORD priority;
HANDLE hProcess;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
- return NULL;
- }
+ if (! PyArg_ParseTuple(args, "l", &pid))
+ return NULL;
hProcess = psutil_handle_from_pid(pid);
- if (hProcess == NULL) {
+ if (hProcess == NULL)
return NULL;
- }
-
priority = GetPriorityClass(hProcess);
CloseHandle(hProcess);
if (priority == 0) {
@@ -1957,23 +1877,18 @@ psutil_proc_priority_get(PyObject *self, PyObject *args)
* Set process priority.
*/
static PyObject *
-psutil_proc_priority_set(PyObject *self, PyObject *args)
-{
+psutil_proc_priority_set(PyObject *self, PyObject *args) {
long pid;
int priority;
int retval;
HANDLE hProcess;
- DWORD dwDesiredAccess = \
- PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION;
- if (! PyArg_ParseTuple(args, "li", &pid, &priority)) {
- return NULL;
- }
+ DWORD access = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION;
- hProcess = psutil_handle_from_pid_waccess(pid, dwDesiredAccess);
- if (hProcess == NULL) {
+ if (! PyArg_ParseTuple(args, "li", &pid, &priority))
+ return NULL;
+ hProcess = psutil_handle_from_pid_waccess(pid, access);
+ if (hProcess == NULL)
return NULL;
- }
-
retval = SetPriorityClass(hProcess, priority);
CloseHandle(hProcess);
if (retval == 0) {
@@ -1989,8 +1904,7 @@ psutil_proc_priority_set(PyObject *self, PyObject *args)
* Get process IO priority as a Python integer.
*/
static PyObject *
-psutil_proc_io_priority_get(PyObject *self, PyObject *args)
-{
+psutil_proc_io_priority_get(PyObject *self, PyObject *args) {
long pid;
HANDLE hProcess;
PULONG IoPriority;
@@ -1999,13 +1913,11 @@ psutil_proc_io_priority_get(PyObject *self, PyObject *args)
(_NtQueryInformationProcess)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
hProcess = psutil_handle_from_pid(pid);
- if (hProcess == NULL) {
+ if (hProcess == NULL)
return NULL;
- }
NtQueryInformationProcess(
hProcess,
@@ -2023,8 +1935,7 @@ psutil_proc_io_priority_get(PyObject *self, PyObject *args)
* Set process IO priority.
*/
static PyObject *
-psutil_proc_io_priority_set(PyObject *self, PyObject *args)
-{
+psutil_proc_io_priority_set(PyObject *self, PyObject *args) {
long pid;
int prio;
HANDLE hProcess;
@@ -2039,13 +1950,11 @@ psutil_proc_io_priority_set(PyObject *self, PyObject *args)
return NULL;
}
- if (! PyArg_ParseTuple(args, "li", &pid, &prio)) {
+ if (! PyArg_ParseTuple(args, "li", &pid, &prio))
return NULL;
- }
hProcess = psutil_handle_from_pid_waccess(pid, PROCESS_ALL_ACCESS);
- if (hProcess == NULL) {
+ if (hProcess == NULL)
return NULL;
- }
NtSetInformationProcess(
hProcess,
@@ -2064,19 +1973,16 @@ psutil_proc_io_priority_set(PyObject *self, PyObject *args)
* Return a Python tuple referencing process I/O counters.
*/
static PyObject *
-psutil_proc_io_counters(PyObject *self, PyObject *args)
-{
+psutil_proc_io_counters(PyObject *self, PyObject *args) {
DWORD pid;
HANDLE hProcess;
IO_COUNTERS IoCounters;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
hProcess = psutil_handle_from_pid(pid);
- if (NULL == hProcess) {
+ if (NULL == hProcess)
return NULL;
- }
if (! GetProcessIoCounters(hProcess, &IoCounters)) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
@@ -2091,45 +1997,17 @@ psutil_proc_io_counters(PyObject *self, PyObject *args)
/*
- * Alternative implementation of the one above but bypasses ACCESS DENIED.
- */
-static PyObject *
-psutil_proc_io_counters_2(PyObject *self, PyObject *args)
-{
- DWORD pid;
- PSYSTEM_PROCESS_INFORMATION process;
- PVOID buffer;
- LONGLONG rcount, wcount, rbytes, wbytes;
-
- if (! PyArg_ParseTuple(args, "l", &pid)) {
- return NULL;
- }
- if (! psutil_get_proc_info(pid, &process, &buffer)) {
- return NULL;
- }
- rcount = process->ReadOperationCount.QuadPart;
- wcount = process->WriteOperationCount.QuadPart;
- rbytes = process->ReadTransferCount.QuadPart;
- wbytes = process->WriteTransferCount.QuadPart;
- free(buffer);
- return Py_BuildValue("KKKK", rcount, wcount, rbytes, wbytes);
-}
-
-
-/*
* Return process CPU affinity as a bitmask
*/
static PyObject *
-psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
DWORD pid;
HANDLE hProcess;
- PDWORD_PTR proc_mask;
- PDWORD_PTR system_mask;
+ DWORD_PTR proc_mask;
+ DWORD_PTR system_mask;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
hProcess = psutil_handle_from_pid(pid);
if (hProcess == NULL) {
return NULL;
@@ -2152,8 +2030,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
* Set process CPU affinity
*/
static PyObject *
-psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
-{
+psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
DWORD pid;
HANDLE hProcess;
DWORD dwDesiredAccess = \
@@ -2169,9 +2046,8 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
return NULL;
}
hProcess = psutil_handle_from_pid_waccess(pid, dwDesiredAccess);
- if (hProcess == NULL) {
+ if (hProcess == NULL)
return NULL;
- }
if (SetProcessAffinityMask(hProcess, mask) == 0) {
CloseHandle(hProcess);
@@ -2188,16 +2064,14 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
* suspended status.
*/
static PyObject *
-psutil_proc_is_suspended(PyObject *self, PyObject *args)
-{
+psutil_proc_is_suspended(PyObject *self, PyObject *args) {
DWORD pid;
ULONG i;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
if (! psutil_get_proc_info(pid, &process, &buffer)) {
return NULL;
}
@@ -2218,8 +2092,7 @@ psutil_proc_is_suspended(PyObject *self, PyObject *args)
* Return path's disk total and free as a Python tuple.
*/
static PyObject *
-psutil_disk_usage(PyObject *self, PyObject *args)
-{
+psutil_disk_usage(PyObject *self, PyObject *args) {
BOOL retval;
ULARGE_INTEGER _, total, free;
char *path;
@@ -2257,52 +2130,22 @@ return_:
* Return a Python list of named tuples with overall network I/O information
*/
static PyObject *
-psutil_net_io_counters(PyObject *self, PyObject *args)
-{
- int attempts = 0;
- int i;
- int outBufLen = 15000;
- char ifname[MAX_PATH];
+psutil_net_io_counters(PyObject *self, PyObject *args) {
DWORD dwRetVal = 0;
MIB_IFROW *pIfRow = NULL;
- ULONG flags = 0;
- ULONG family = AF_UNSPEC;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
-
PyObject *py_retdict = PyDict_New();
PyObject *py_nic_info = NULL;
PyObject *py_nic_name = NULL;
- if (py_retdict == NULL) {
+ if (py_retdict == NULL)
return NULL;
- }
- do {
- pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
- if (pAddresses == NULL) {
- PyErr_NoMemory();
- goto error;
- }
-
- dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses,
- &outBufLen);
- if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
- free(pAddresses);
- pAddresses = NULL;
- }
- else {
- break;
- }
-
- attempts++;
- } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3));
-
- if (dwRetVal != NO_ERROR) {
- PyErr_SetString(PyExc_RuntimeError, "GetAdaptersAddresses() failed.");
+ pAddresses = psutil_get_nic_addresses();
+ if (pAddresses == NULL)
goto error;
- }
-
pCurrAddresses = pAddresses;
+
while (pCurrAddresses) {
py_nic_name = NULL;
py_nic_info = NULL;
@@ -2332,9 +2175,9 @@ psutil_net_io_counters(PyObject *self, PyObject *args)
if (!py_nic_info)
goto error;
- sprintf(ifname, "%wS", pCurrAddresses->FriendlyName);
- py_nic_name = PyUnicode_Decode(
- ifname, _tcslen(ifname), Py_FileSystemDefaultEncoding, "replace");
+ py_nic_name = PyUnicode_FromWideChar(
+ pCurrAddresses->FriendlyName,
+ wcslen(pCurrAddresses->FriendlyName));
if (py_nic_name == NULL)
goto error;
@@ -2361,29 +2204,12 @@ error:
return NULL;
}
-// fix for mingw32, see
-// https://github.com/giampaolo/psutil/issues/351#c2
-typedef struct _DISK_PERFORMANCE_WIN_2008 {
- LARGE_INTEGER BytesRead;
- LARGE_INTEGER BytesWritten;
- LARGE_INTEGER ReadTime;
- LARGE_INTEGER WriteTime;
- LARGE_INTEGER IdleTime;
- DWORD ReadCount;
- DWORD WriteCount;
- DWORD QueueDepth;
- DWORD SplitCount;
- LARGE_INTEGER QueryTime;
- DWORD StorageDeviceNumber;
- WCHAR StorageManagerName[8];
-} DISK_PERFORMANCE_WIN_2008;
/*
* Return a Python dict of tuples for disk I/O information
*/
static PyObject *
-psutil_disk_io_counters(PyObject *self, PyObject *args)
-{
+psutil_disk_io_counters(PyObject *self, PyObject *args) {
DISK_PERFORMANCE_WIN_2008 diskPerformance;
DWORD dwSize;
HANDLE hDevice = NULL;
@@ -2391,30 +2217,28 @@ psutil_disk_io_counters(PyObject *self, PyObject *args)
char szDeviceDisplay[MAX_PATH];
int devNum;
PyObject *py_retdict = PyDict_New();
- PyObject *py_disk_info = NULL;
- if (py_retdict == NULL) {
- return NULL;
- }
+ PyObject *py_tuple = NULL;
+ if (py_retdict == NULL)
+ return NULL;
// Apparently there's no way to figure out how many times we have
// to iterate in order to find valid drives.
// Let's assume 32, which is higher than 26, the number of letters
// in the alphabet (from A:\ to Z:\).
for (devNum = 0; devNum <= 32; ++devNum) {
- py_disk_info = NULL;
- sprintf(szDevice, "\\\\.\\PhysicalDrive%d", devNum);
+ py_tuple = NULL;
+ sprintf_s(szDevice, MAX_PATH, "\\\\.\\PhysicalDrive%d", devNum);
hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
- if (hDevice == INVALID_HANDLE_VALUE) {
+ if (hDevice == INVALID_HANDLE_VALUE)
continue;
- }
if (DeviceIoControl(hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
&diskPerformance, sizeof(diskPerformance),
&dwSize, NULL))
{
- sprintf(szDeviceDisplay, "PhysicalDrive%d", devNum);
- py_disk_info = Py_BuildValue(
+ sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%d", devNum);
+ py_tuple = Py_BuildValue(
"(IILLKK)",
diskPerformance.ReadCount,
diskPerformance.WriteCount,
@@ -2422,14 +2246,14 @@ psutil_disk_io_counters(PyObject *self, PyObject *args)
diskPerformance.BytesWritten,
(unsigned long long)(diskPerformance.ReadTime.QuadPart * 10) / 1000,
(unsigned long long)(diskPerformance.WriteTime.QuadPart * 10) / 1000);
- if (!py_disk_info)
+ if (!py_tuple)
goto error;
if (PyDict_SetItemString(py_retdict, szDeviceDisplay,
- py_disk_info))
+ py_tuple))
{
goto error;
}
- Py_XDECREF(py_disk_info);
+ Py_XDECREF(py_tuple);
}
else {
// XXX we might get here with ERROR_INSUFFICIENT_BUFFER when
@@ -2444,7 +2268,7 @@ psutil_disk_io_counters(PyObject *self, PyObject *args)
return py_retdict;
error:
- Py_XDECREF(py_disk_info);
+ Py_XDECREF(py_tuple);
Py_DECREF(py_retdict);
if (hDevice != NULL)
CloseHandle(hDevice);
@@ -2452,25 +2276,24 @@ error:
}
-static char *psutil_get_drive_type(int type)
-{
+static char *psutil_get_drive_type(int type) {
switch (type) {
- case DRIVE_FIXED:
- return "fixed";
- case DRIVE_CDROM:
- return "cdrom";
- case DRIVE_REMOVABLE:
- return "removable";
- case DRIVE_UNKNOWN:
- return "unknown";
- case DRIVE_NO_ROOT_DIR:
- return "unmounted";
- case DRIVE_REMOTE:
- return "remote";
- case DRIVE_RAMDISK:
- return "ramdisk";
- default:
- return "?";
+ case DRIVE_FIXED:
+ return "fixed";
+ case DRIVE_CDROM:
+ return "cdrom";
+ case DRIVE_REMOVABLE:
+ return "removable";
+ case DRIVE_UNKNOWN:
+ return "unknown";
+ case DRIVE_NO_ROOT_DIR:
+ return "unmounted";
+ case DRIVE_REMOTE:
+ return "remote";
+ case DRIVE_RAMDISK:
+ return "ramdisk";
+ default:
+ return "?";
}
}
@@ -2484,8 +2307,7 @@ static char *psutil_get_drive_type(int type)
* (drive_letter, drive_letter, type, "")
*/
static PyObject *
-psutil_disk_partitions(PyObject *self, PyObject *args)
-{
+psutil_disk_partitions(PyObject *self, PyObject *args) {
DWORD num_bytes;
char drive_strings[255];
char *drive_letter = drive_strings;
@@ -2507,9 +2329,8 @@ psutil_disk_partitions(PyObject *self, PyObject *args)
// see https://github.com/giampaolo/psutil/issues/264
SetErrorMode(SEM_FAILCRITICALERRORS);
- if (! PyArg_ParseTuple(args, "O", &py_all)) {
+ if (! PyArg_ParseTuple(args, "O", &py_all))
goto error;
- }
all = PyObject_IsTrue(py_all);
Py_BEGIN_ALLOW_THREADS
@@ -2554,25 +2375,21 @@ psutil_disk_partitions(PyObject *self, PyObject *args)
// which case the error is (21, "device not ready").
// Let's pretend it didn't happen as we already have
// the drive name and type ('removable').
- strcat(opts, "");
+ strcat_s(opts, _countof(opts), "");
SetLastError(0);
}
else {
- if (pflags & FILE_READ_ONLY_VOLUME) {
- strcat(opts, "ro");
- }
- else {
- strcat(opts, "rw");
- }
- if (pflags & FILE_VOLUME_IS_COMPRESSED) {
- strcat(opts, ",compressed");
- }
+ if (pflags & FILE_READ_ONLY_VOLUME)
+ strcat_s(opts, _countof(opts), "ro");
+ else
+ strcat_s(opts, _countof(opts), "rw");
+ if (pflags & FILE_VOLUME_IS_COMPRESSED)
+ strcat_s(opts, _countof(opts), ",compressed");
}
- if (strlen(opts) > 0) {
- strcat(opts, ",");
- }
- strcat(opts, psutil_get_drive_type(type));
+ if (strlen(opts) > 0)
+ strcat_s(opts, _countof(opts), ",");
+ strcat_s(opts, _countof(opts), psutil_get_drive_type(type));
py_tuple = Py_BuildValue(
"(ssss)",
@@ -2601,20 +2418,11 @@ error:
return NULL;
}
-
-#ifdef UNICODE
-#define WTSOpenServer WTSOpenServerW
-#else
-#define WTSOpenServer WTSOpenServerA
-#endif
-
-
/*
* Return a Python dict of tuples for disk I/O information
*/
static PyObject *
-psutil_users(PyObject *self, PyObject *args)
-{
+psutil_users(PyObject *self, PyObject *args) {
HANDLE hServer = NULL;
LPTSTR buffer_user = NULL;
LPTSTR buffer_addr = NULL;
@@ -2637,9 +2445,8 @@ psutil_users(PyObject *self, PyObject *args)
PyObject *py_address = NULL;
PyObject *py_buffer_user_encoded = NULL;
- if (py_retlist == NULL) {
+ if (py_retlist == NULL)
return NULL;
- }
hInstWinSta = LoadLibraryA("winsta.dll");
WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW) \
@@ -2660,12 +2467,10 @@ psutil_users(PyObject *self, PyObject *args)
py_address = NULL;
py_tuple = NULL;
sessionId = sessions[i].SessionId;
- if (buffer_user != NULL) {
+ if (buffer_user != NULL)
WTSFreeMemory(buffer_user);
- }
- if (buffer_addr != NULL) {
+ if (buffer_addr != NULL)
WTSFreeMemory(buffer_addr);
- }
buffer_user = NULL;
buffer_addr = NULL;
@@ -2677,9 +2482,8 @@ psutil_users(PyObject *self, PyObject *args)
PyErr_SetFromWindowsErr(0);
goto error;
}
- if (bytes == 1) {
+ if (bytes == 1)
continue;
- }
// address
bytes = 0;
@@ -2691,12 +2495,13 @@ psutil_users(PyObject *self, PyObject *args)
address = (PWTS_CLIENT_ADDRESS)buffer_addr;
if (address->AddressFamily == 0) { // AF_INET
- sprintf(address_str,
- "%u.%u.%u.%u",
- address->Address[0],
- address->Address[1],
- address->Address[2],
- address->Address[3]);
+ sprintf_s(address_str,
+ _countof(address_str),
+ "%u.%u.%u.%u",
+ address->Address[0],
+ address->Address[1],
+ address->Address[2],
+ address->Address[3]);
py_address = Py_BuildValue("s", address_str);
if (!py_address)
goto error;
@@ -2748,21 +2553,16 @@ error:
Py_XDECREF(py_address);
Py_DECREF(py_retlist);
- if (hInstWinSta != NULL) {
+ if (hInstWinSta != NULL)
FreeLibrary(hInstWinSta);
- }
- if (hServer != NULL) {
+ if (hServer != NULL)
WTSCloseServer(hServer);
- }
- if (sessions != NULL) {
+ if (sessions != NULL)
WTSFreeMemory(sessions);
- }
- if (buffer_user != NULL) {
+ if (buffer_user != NULL)
WTSFreeMemory(buffer_user);
- }
- if (buffer_addr != NULL) {
+ if (buffer_addr != NULL)
WTSFreeMemory(buffer_addr);
- }
return NULL;
}
@@ -2771,19 +2571,16 @@ error:
* Return the number of handles opened by process.
*/
static PyObject *
-psutil_proc_num_handles(PyObject *self, PyObject *args)
-{
+psutil_proc_num_handles(PyObject *self, PyObject *args) {
DWORD pid;
HANDLE hProcess;
DWORD handleCount;
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
hProcess = psutil_handle_from_pid(pid);
- if (NULL == hProcess) {
+ if (NULL == hProcess)
return NULL;
- }
if (! GetProcessHandleCount(hProcess, &handleCount)) {
CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
@@ -2794,75 +2591,100 @@ psutil_proc_num_handles(PyObject *self, PyObject *args)
/*
- * Alternative implementation of the one above but bypasses ACCESS DENIED.
- */
-static PyObject *
-psutil_proc_num_handles_2(PyObject *self, PyObject *args)
-{
- DWORD pid;
- PSYSTEM_PROCESS_INFORMATION process;
- PVOID buffer;
- ULONG count;
-
- if (! PyArg_ParseTuple(args, "l", &pid)) {
- return NULL;
- }
- if (! psutil_get_proc_info(pid, &process, &buffer)) {
- return NULL;
- }
- count = process->HandleCount;
- free(buffer);
- return Py_BuildValue("k", count);
-}
-
-
-/*
- * Return the number of context switches executed by process.
+ * Get various process information by using NtQuerySystemInformation.
+ * We use this as a fallback when faster functions fail with access
+ * denied. This is slower because it iterates over all processes.
+ * Returned tuple includes the following process info:
+ *
+ * - num_threads
+ * - ctx_switches
+ * - num_handles (fallback)
+ * - user/kernel times (fallback)
+ * - create time (fallback)
+ * - io counters (fallback)
*/
static PyObject *
-psutil_proc_num_ctx_switches(PyObject *self, PyObject *args)
-{
+psutil_proc_info(PyObject *self, PyObject *args) {
DWORD pid;
PSYSTEM_PROCESS_INFORMATION process;
PVOID buffer;
+ ULONG num_handles;
ULONG i;
- ULONG total = 0;
+ ULONG ctx_switches = 0;
+ double user_time;
+ double kernel_time;
+ long long create_time;
+ int num_threads;
+ LONGLONG io_rcount, io_wcount, io_rbytes, io_wbytes;
+
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
return NULL;
- }
- if (! psutil_get_proc_info(pid, &process, &buffer)) {
+ if (! psutil_get_proc_info(pid, &process, &buffer))
return NULL;
+
+ num_handles = process->HandleCount;
+ for (i = 0; i < process->NumberOfThreads; i++)
+ ctx_switches += process->Threads[i].ContextSwitches;
+ user_time = (double)process->UserTime.HighPart * 429.4967296 + \
+ (double)process->UserTime.LowPart * 1e-7;
+ kernel_time = (double)process->KernelTime.HighPart * 429.4967296 + \
+ (double)process->KernelTime.LowPart * 1e-7;
+ // Convert the LARGE_INTEGER union to a Unix time.
+ // It's the best I could find by googling and borrowing code here
+ // and there. The time returned has a precision of 1 second.
+ if (0 == pid || 4 == pid) {
+ // the python module will translate this into BOOT_TIME later
+ create_time = 0;
}
- for (i = 0; i < process->NumberOfThreads; i++) {
- total += process->Threads[i].ContextSwitches;
- }
+ else {
+ create_time = ((LONGLONG)process->CreateTime.HighPart) << 32;
+ create_time += process->CreateTime.LowPart - 116444736000000000LL;
+ create_time /= 10000000;
+ }
+ num_threads = (int)process->NumberOfThreads;
+ io_rcount = process->ReadOperationCount.QuadPart;
+ io_wcount = process->WriteOperationCount.QuadPart;
+ io_rbytes = process->ReadTransferCount.QuadPart;
+ io_wbytes = process->WriteTransferCount.QuadPart;
free(buffer);
- return Py_BuildValue("ki", total, 0);
+
+ return Py_BuildValue(
+ "kkdddiKKKK",
+ num_handles,
+ ctx_switches,
+ user_time,
+ kernel_time,
+ (double)create_time,
+ num_threads,
+ io_rcount,
+ io_wcount,
+ io_rbytes,
+ io_wbytes
+ );
}
-static char *get_region_protection_string(ULONG protection)
-{
+static char *get_region_protection_string(ULONG protection) {
switch (protection & 0xff) {
- case PAGE_NOACCESS:
- return "";
- case PAGE_READONLY:
- return "r";
- case PAGE_READWRITE:
- return "rw";
- case PAGE_WRITECOPY:
- return "wc";
- case PAGE_EXECUTE:
- return "x";
- case PAGE_EXECUTE_READ:
- return "xr";
- case PAGE_EXECUTE_READWRITE:
- return "xrw";
- case PAGE_EXECUTE_WRITECOPY:
- return "xwc";
- default:
- return "?";
+ case PAGE_NOACCESS:
+ return "";
+ case PAGE_READONLY:
+ return "r";
+ case PAGE_READWRITE:
+ return "rw";
+ case PAGE_WRITECOPY:
+ return "wc";
+ case PAGE_EXECUTE:
+ return "x";
+ case PAGE_EXECUTE_READ:
+ return "xr";
+ case PAGE_EXECUTE_READWRITE:
+ return "xrw";
+ case PAGE_EXECUTE_WRITECOPY:
+ return "xwc";
+ default:
+ return "?";
}
}
@@ -2871,8 +2693,7 @@ static char *get_region_protection_string(ULONG protection)
* Return a list of process's memory mappings.
*/
static PyObject *
-psutil_proc_memory_maps(PyObject *self, PyObject *args)
-{
+psutil_proc_memory_maps(PyObject *self, PyObject *args) {
DWORD pid;
HANDLE hProcess = NULL;
MEMORY_BASIC_INFORMATION basicInfo;
@@ -2881,19 +2702,16 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
CHAR mappedFileName[MAX_PATH];
SYSTEM_INFO system_info;
LPVOID maxAddr;
- PyObject *py_list = PyList_New(0);
+ PyObject *py_retlist = PyList_New(0);
PyObject *py_tuple = NULL;
- if (py_list == NULL) {
+ if (py_retlist == NULL)
return NULL;
- }
- if (! PyArg_ParseTuple(args, "l", &pid)) {
+ if (! PyArg_ParseTuple(args, "l", &pid))
goto error;
- }
hProcess = psutil_handle_from_pid(pid);
- if (NULL == hProcess) {
+ if (NULL == hProcess)
goto error;
- }
GetSystemInfo(&system_info);
maxAddr = system_info.lpMaximumApplicationAddress;
@@ -2904,9 +2722,8 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
sizeof(MEMORY_BASIC_INFORMATION)))
{
py_tuple = NULL;
- if (baseAddress > maxAddr) {
+ if (baseAddress > maxAddr)
break;
- }
if (GetMappedFileNameA(hProcess, baseAddress, mappedFileName,
sizeof(mappedFileName)))
{
@@ -2918,7 +2735,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
basicInfo.RegionSize);
if (!py_tuple)
goto error;
- if (PyList_Append(py_list, py_tuple))
+ if (PyList_Append(py_retlist, py_tuple))
goto error;
Py_DECREF(py_tuple);
}
@@ -2927,11 +2744,11 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args)
}
CloseHandle(hProcess);
- return py_list;
+ return py_retlist;
error:
Py_XDECREF(py_tuple);
- Py_DECREF(py_list);
+ Py_DECREF(py_retlist);
if (hProcess != NULL)
CloseHandle(hProcess);
return NULL;
@@ -2942,10 +2759,9 @@ error:
* Return a {pid:ppid, ...} dict for all running processes.
*/
static PyObject *
-psutil_ppid_map(PyObject *self, PyObject *args)
-{
- PyObject *pid = NULL;
- PyObject *ppid = NULL;
+psutil_ppid_map(PyObject *self, PyObject *args) {
+ PyObject *py_pid = NULL;
+ PyObject *py_ppid = NULL;
PyObject *py_retdict = PyDict_New();
HANDLE handle = NULL;
PROCESSENTRY32 pe = {0};
@@ -2962,16 +2778,16 @@ psutil_ppid_map(PyObject *self, PyObject *args)
if (Process32First(handle, &pe)) {
do {
- pid = Py_BuildValue("I", pe.th32ProcessID);
- if (pid == NULL)
+ py_pid = Py_BuildValue("I", pe.th32ProcessID);
+ if (py_pid == NULL)
goto error;
- ppid = Py_BuildValue("I", pe.th32ParentProcessID);
- if (ppid == NULL)
+ py_ppid = Py_BuildValue("I", pe.th32ParentProcessID);
+ if (py_ppid == NULL)
goto error;
- if (PyDict_SetItem(py_retdict, pid, ppid))
+ if (PyDict_SetItem(py_retdict, py_pid, py_ppid))
goto error;
- Py_DECREF(pid);
- Py_DECREF(ppid);
+ Py_DECREF(py_pid);
+ Py_DECREF(py_ppid);
} while (Process32Next(handle, &pe));
}
@@ -2979,25 +2795,309 @@ psutil_ppid_map(PyObject *self, PyObject *args)
return py_retdict;
error:
- Py_XDECREF(pid);
- Py_XDECREF(ppid);
+ Py_XDECREF(py_pid);
+ Py_XDECREF(py_ppid);
Py_DECREF(py_retdict);
CloseHandle(handle);
return NULL;
}
+/*
+ * Return NICs addresses.
+ */
+
+static PyObject *
+psutil_net_if_addrs(PyObject *self, PyObject *args) {
+ unsigned int i = 0;
+ ULONG family;
+ PCTSTR intRet;
+ char *ptr;
+ char buff[100];
+ DWORD bufflen = 100;
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+ PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+
+ PyObject *py_retlist = PyList_New(0);
+ PyObject *py_tuple = NULL;
+ PyObject *py_address = NULL;
+ PyObject *py_mac_address = NULL;
+ PyObject *py_nic_name = NULL;
+
+ if (py_retlist == NULL)
+ return NULL;
+
+ pAddresses = psutil_get_nic_addresses();
+ if (pAddresses == NULL)
+ goto error;
+ pCurrAddresses = pAddresses;
+
+ while (pCurrAddresses) {
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
+
+ py_nic_name = NULL;
+ py_nic_name = PyUnicode_FromWideChar(
+ pCurrAddresses->FriendlyName,
+ wcslen(pCurrAddresses->FriendlyName));
+ if (py_nic_name == NULL)
+ goto error;
+
+ // MAC address
+ if (pCurrAddresses->PhysicalAddressLength != 0) {
+ ptr = buff;
+ *ptr = '\0';
+ for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) {
+ if (i == (pCurrAddresses->PhysicalAddressLength - 1)) {
+ sprintf_s(ptr, _countof(buff), "%.2X\n",
+ (int)pCurrAddresses->PhysicalAddress[i]);
+ }
+ else {
+ sprintf_s(ptr, _countof(buff), "%.2X-",
+ (int)pCurrAddresses->PhysicalAddress[i]);
+ }
+ ptr += 3;
+ }
+ *--ptr = '\0';
+
+#if PY_MAJOR_VERSION >= 3
+ py_mac_address = PyUnicode_FromString(buff);
+#else
+ py_mac_address = PyString_FromString(buff);
+#endif
+ if (py_mac_address == NULL)
+ goto error;
+
+ Py_INCREF(Py_None);
+ Py_INCREF(Py_None);
+ Py_INCREF(Py_None);
+ py_tuple = Py_BuildValue(
+ "(OiOOOO)",
+ py_nic_name,
+ -1, // this will be converted later to AF_LINK
+ py_mac_address,
+ Py_None, // netmask (not supported)
+ Py_None, // broadcast (not supported)
+ Py_None // ptp (not supported on Windows)
+ );
+ if (! py_tuple)
+ goto error;
+ if (PyList_Append(py_retlist, py_tuple))
+ goto error;
+ Py_DECREF(py_tuple);
+ Py_DECREF(py_mac_address);
+ }
+
+ // find out the IP address associated with the NIC
+ if (pUnicast != NULL) {
+ for (i = 0; pUnicast != NULL; i++) {
+ family = pUnicast->Address.lpSockaddr->sa_family;
+ if (family == AF_INET) {
+ struct sockaddr_in *sa_in = (struct sockaddr_in *)
+ pUnicast->Address.lpSockaddr;
+ intRet = inet_ntop(AF_INET, &(sa_in->sin_addr), buff,
+ bufflen);
+ }
+ else if (family == AF_INET6) {
+ struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)
+ pUnicast->Address.lpSockaddr;
+ intRet = inet_ntop(AF_INET6, &(sa_in6->sin6_addr),
+ buff, bufflen);
+ }
+ else {
+ // we should never get here
+ pUnicast = pUnicast->Next;
+ continue;
+ }
+
+ if (intRet == NULL) {
+ PyErr_SetFromWindowsErr(GetLastError());
+ goto error;
+ }
+#if PY_MAJOR_VERSION >= 3
+ py_address = PyUnicode_FromString(buff);
+#else
+ py_address = PyString_FromString(buff);
+#endif
+ if (py_address == NULL)
+ goto error;
+
+ Py_INCREF(Py_None);
+ Py_INCREF(Py_None);
+ Py_INCREF(Py_None);
+ py_tuple = Py_BuildValue(
+ "(OiOOOO)",
+ py_nic_name,
+ family,
+ py_address,
+ Py_None, // netmask (not supported)
+ Py_None, // broadcast (not supported)
+ Py_None // ptp (not supported on Windows)
+ );
+
+ if (! py_tuple)
+ goto error;
+ if (PyList_Append(py_retlist, py_tuple))
+ goto error;
+ Py_DECREF(py_tuple);
+ Py_DECREF(py_address);
+
+ pUnicast = pUnicast->Next;
+ }
+ }
+ Py_DECREF(py_nic_name);
+ pCurrAddresses = pCurrAddresses->Next;
+ }
+
+ free(pAddresses);
+ return py_retlist;
+
+error:
+ if (pAddresses)
+ free(pAddresses);
+ Py_DECREF(py_retlist);
+ Py_XDECREF(py_tuple);
+ Py_XDECREF(py_address);
+ Py_XDECREF(py_nic_name);
+ return NULL;
+}
+
+
+/*
+ * Provides stats about NIC interfaces installed on the system.
+ * TODO: get 'duplex' (currently it's hard coded to '2', aka
+ 'full duplex')
+ */
+static PyObject *
+psutil_net_if_stats(PyObject *self, PyObject *args) {
+ int i;
+ DWORD dwSize = 0;
+ DWORD dwRetVal = 0;
+ MIB_IFTABLE *pIfTable;
+ MIB_IFROW *pIfRow;
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+ char descr[MAX_PATH];
+ int ifname_found;
+
+ PyObject *py_nic_name = NULL;
+ PyObject *py_retdict = PyDict_New();
+ PyObject *py_ifc_info = NULL;
+ PyObject *py_is_up = NULL;
+
+ if (py_retdict == NULL)
+ return NULL;
+
+ pAddresses = psutil_get_nic_addresses();
+ if (pAddresses == NULL)
+ goto error;
+
+ pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE));
+ if (pIfTable == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ dwSize = sizeof(MIB_IFTABLE);
+ if (GetIfTable(pIfTable, &dwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) {
+ free(pIfTable);
+ pIfTable = (MIB_IFTABLE *) malloc(dwSize);
+ if (pIfTable == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
+ }
+ // Make a second call to GetIfTable to get the actual
+ // data we want.
+ if ((dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE)) != NO_ERROR) {
+ PyErr_SetString(PyExc_RuntimeError, "GetIfTable() failed");
+ goto error;
+ }
+
+ for (i = 0; i < (int) pIfTable->dwNumEntries; i++) {
+ pIfRow = (MIB_IFROW *) & pIfTable->table[i];
+
+ // GetIfTable is not able to give us NIC with "friendly names"
+ // so we determine them via GetAdapterAddresses() which
+ // provides friendly names *and* descriptions and find the
+ // ones that match.
+ ifname_found = 0;
+ pCurrAddresses = pAddresses;
+ while (pCurrAddresses) {
+ sprintf_s(descr, MAX_PATH, "%wS", pCurrAddresses->Description);
+ if (lstrcmp(descr, pIfRow->bDescr) == 0) {
+ py_nic_name = PyUnicode_FromWideChar(
+ pCurrAddresses->FriendlyName,
+ wcslen(pCurrAddresses->FriendlyName));
+ if (py_nic_name == NULL)
+ goto error;
+ ifname_found = 1;
+ break;
+ }
+ pCurrAddresses = pCurrAddresses->Next;
+ }
+ if (ifname_found == 0) {
+ // Name not found means GetAdapterAddresses() doesn't list
+ // this NIC, only GetIfTable, meaning it's not really a NIC
+ // interface so we skip it.
+ continue;
+ }
+
+ // is up?
+ if((pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED ||
+ pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL) &&
+ pIfRow->dwAdminStatus == 1 ) {
+ py_is_up = Py_True;
+ }
+ else {
+ py_is_up = Py_False;
+ }
+ Py_INCREF(py_is_up);
+
+ py_ifc_info = Py_BuildValue(
+ "(Oikk)",
+ py_is_up,
+ 2, // there's no way to know duplex so let's assume 'full'
+ pIfRow->dwSpeed / 1000000, // expressed in bytes, we want Mb
+ pIfRow->dwMtu
+ );
+ if (!py_ifc_info)
+ goto error;
+ if (PyDict_SetItemString(py_retdict, py_nic_name, py_ifc_info))
+ goto error;
+ Py_DECREF(py_nic_name);
+ Py_DECREF(py_ifc_info);
+ }
+
+ free(pIfTable);
+ free(pAddresses);
+ return py_retdict;
+
+error:
+ Py_XDECREF(py_is_up);
+ Py_XDECREF(py_ifc_info);
+ Py_XDECREF(py_nic_name);
+ Py_DECREF(py_retdict);
+ if (pIfTable != NULL)
+ free(pIfTable);
+ if (pAddresses != NULL)
+ free(pAddresses);
+ return NULL;
+}
+
+
// ------------------------ Python init ---------------------------
static PyMethodDef
-PsutilMethods[] =
-{
+PsutilMethods[] = {
+
// --- per-process functions
{"proc_cmdline", psutil_proc_cmdline, METH_VARARGS,
"Return process cmdline as a list of cmdline arguments"},
{"proc_exe", psutil_proc_exe, METH_VARARGS,
"Return path of the process executable"},
+ {"proc_name", psutil_proc_name, METH_VARARGS,
+ "Return process name"},
{"proc_kill", psutil_proc_kill, METH_VARARGS,
"Kill the process identified by the given PID"},
{"proc_cpu_times", psutil_proc_cpu_times, METH_VARARGS,
@@ -3007,6 +3107,8 @@ PsutilMethods[] =
"seconds since the epoch"},
{"proc_memory_info", psutil_proc_memory_info, METH_VARARGS,
"Return a tuple of process memory information"},
+ {"proc_memory_info_2", psutil_proc_memory_info_2, METH_VARARGS,
+ "Alternate implementation"},
{"proc_cwd", psutil_proc_cwd, METH_VARARGS,
"Return process current working directory"},
{"proc_suspend", psutil_proc_suspend, METH_VARARGS,
@@ -3017,8 +3119,6 @@ PsutilMethods[] =
"Return files opened by process"},
{"proc_username", psutil_proc_username, METH_VARARGS,
"Return the username of a process"},
- {"proc_num_threads", psutil_proc_num_threads, METH_VARARGS,
- "Return the network connections of a process"},
{"proc_threads", psutil_proc_threads, METH_VARARGS,
"Return process threads information as a list of tuple"},
{"proc_wait", psutil_proc_wait, METH_VARARGS,
@@ -3043,22 +3143,12 @@ PsutilMethods[] =
"Return True if one of the process threads is in a suspended state"},
{"proc_num_handles", psutil_proc_num_handles, METH_VARARGS,
"Return the number of handles opened by process."},
- {"proc_num_ctx_switches", psutil_proc_num_ctx_switches, METH_VARARGS,
- "Return the number of context switches performed by process."},
{"proc_memory_maps", psutil_proc_memory_maps, METH_VARARGS,
"Return a list of process's memory mappings"},
// --- alternative pinfo interface
- {"proc_cpu_times_2", psutil_proc_cpu_times_2, METH_VARARGS,
- "Alternative implementation"},
- {"proc_create_time_2", psutil_proc_create_time_2, METH_VARARGS,
- "Alternative implementation"},
- {"proc_num_handles_2", psutil_proc_num_handles_2, METH_VARARGS,
- "Alternative implementation"},
- {"proc_io_counters_2", psutil_proc_io_counters_2, METH_VARARGS,
- "Alternative implementation"},
- {"proc_memory_info_2", psutil_proc_memory_info_2, METH_VARARGS,
- "Alternative implementation"},
+ {"proc_info", psutil_proc_info, METH_VARARGS,
+ "Various process information"},
// --- system-related functions
{"pids", psutil_pids, METH_VARARGS,
@@ -3091,7 +3181,10 @@ PsutilMethods[] =
"Return disk partitions."},
{"net_connections", psutil_net_connections, METH_VARARGS,
"Return system-wide connections"},
-
+ {"net_if_addrs", psutil_net_if_addrs, METH_VARARGS,
+ "Return NICs addresses."},
+ {"net_if_stats", psutil_net_if_stats, METH_VARARGS,
+ "Return NICs stats."},
// --- windows API bindings
{"win32_QueryDosDevice", psutil_win32_QueryDosDevice, METH_VARARGS,
@@ -3221,4 +3314,4 @@ void init_psutil_windows(void)
#if PY_MAJOR_VERSION >= 3
return module;
#endif
-} \ No newline at end of file
+}
diff --git a/psutil/_psutil_windows.h b/psutil/_psutil_windows.h
index 546704e3..c77f64e9 100644
--- a/psutil/_psutil_windows.h
+++ b/psutil/_psutil_windows.h
@@ -13,22 +13,18 @@ static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args);
static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
-static PyObject* psutil_proc_cpu_times_2(PyObject* self, PyObject* args);
static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args);
-static PyObject* psutil_proc_create_time_2(PyObject* self, PyObject* args);
static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
static PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
+static PyObject* psutil_proc_info(PyObject* self, PyObject* args);
static PyObject* psutil_proc_io_counters(PyObject* self, PyObject* args);
-static PyObject* psutil_proc_io_counters_2(PyObject* self, PyObject* args);
static PyObject* psutil_proc_is_suspended(PyObject* self, PyObject* args);
static PyObject* psutil_proc_kill(PyObject* self, PyObject* args);
static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args);
static PyObject* psutil_proc_memory_info_2(PyObject* self, PyObject* args);
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
-static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args);
+static PyObject* psutil_proc_name(PyObject* self, PyObject* args);
static PyObject* psutil_proc_num_handles(PyObject* self, PyObject* args);
-static PyObject* psutil_proc_num_handles_2(PyObject* self, PyObject* args);
-static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args);
static PyObject* psutil_proc_priority_get(PyObject* self, PyObject* args);
static PyObject* psutil_proc_priority_set(PyObject* self, PyObject* args);
@@ -60,6 +56,8 @@ static PyObject* psutil_pids(PyObject* self, PyObject* args);
static PyObject* psutil_ppid_map(PyObject* self, PyObject* args);
static PyObject* psutil_users(PyObject* self, PyObject* args);
static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
+static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args);
+static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
// --- windows API bindings
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index 47c049c1..5df17272 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -7,20 +7,33 @@
import errno
import functools
import os
+import sys
from collections import namedtuple
-from psutil import _common
-from psutil._common import conn_tmap, usage_percent, isfile_strict
-from psutil._compat import PY3, xrange, lru_cache
-import _psutil_windows as cext
+from . import _common
+from . import _psutil_windows as cext
+from ._common import conn_tmap, usage_percent, isfile_strict
+from ._common import sockfam_to_enum, socktype_to_enum
+from ._compat import PY3, xrange, lru_cache, long
+from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS,
+ BELOW_NORMAL_PRIORITY_CLASS,
+ HIGH_PRIORITY_CLASS,
+ IDLE_PRIORITY_CLASS,
+ NORMAL_PRIORITY_CLASS,
+ REALTIME_PRIORITY_CLASS)
+
+if sys.version_info >= (3, 4):
+ import enum
+else:
+ enum = None
# process priority constants, import from __init__.py:
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
__extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
- #
"CONN_DELETE_TCB",
+ "AF_LINK",
]
# --- module level constants (gets pushed up to psutil module)
@@ -29,6 +42,11 @@ CONN_DELETE_TCB = "DELETE_TCB"
WAIT_TIMEOUT = 0x00000102 # 258 in decimal
ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES,
cext.ERROR_ACCESS_DENIED])
+if enum is None:
+ AF_LINK = -1
+else:
+ AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1})
+ AF_LINK = AddressFamily.AF_LINK
TCP_STATUSES = {
cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED,
@@ -46,6 +64,16 @@ TCP_STATUSES = {
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
}
+if enum is not None:
+ class Priority(enum.IntEnum):
+ ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS
+ BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS
+ HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS
+ IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS
+ NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS
+ REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS
+
+ globals().update(Priority.__members__)
scputimes = namedtuple('scputimes', ['user', 'system', 'idle'])
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
@@ -56,6 +84,10 @@ pextmem = namedtuple(
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss'])
pmmap_ext = namedtuple(
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
+ntpinfo = namedtuple(
+ 'ntpinfo', ['num_handles', 'ctx_switches', 'user_time', 'kernel_time',
+ 'create_time', 'num_threads', 'io_rcount', 'io_wcount',
+ 'io_rbytes', 'io_wbytes'])
# set later from __init__.py
NoSuchProcess = None
@@ -79,6 +111,18 @@ def _convert_raw_path(s):
return os.path.join(driveletter, s[len(rawdrive):])
+def py2_strencode(s, encoding=sys.getfilesystemencoding()):
+ if PY3 or isinstance(s, str):
+ return s
+ else:
+ try:
+ return s.encode(encoding)
+ except UnicodeEncodeError:
+ # Filesystem codec failed, return the plain unicode
+ # string (this should never happen).
+ return s
+
+
# --- public functions
@@ -165,15 +209,42 @@ def net_connections(kind, _pid=-1):
% (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind]
rawlist = cext.net_connections(_pid, families, types)
- ret = []
+ ret = set()
for item in rawlist:
fd, fam, type, laddr, raddr, status, pid = item
status = TCP_STATUSES[status]
+ fam = sockfam_to_enum(fam)
+ type = socktype_to_enum(type)
if _pid == -1:
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
else:
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
- ret.append(nt)
+ ret.add(nt)
+ return list(ret)
+
+
+def net_if_stats():
+ ret = cext.net_if_stats()
+ for name, items in ret.items():
+ name = py2_strencode(name)
+ isup, duplex, speed, mtu = items
+ if hasattr(_common, 'NicDuplex'):
+ duplex = _common.NicDuplex(duplex)
+ ret[name] = _common.snicstats(isup, duplex, speed, mtu)
+ return ret
+
+
+def net_io_counters():
+ ret = cext.net_io_counters()
+ return dict([(py2_strencode(k), v) for k, v in ret.items()])
+
+
+def net_if_addrs():
+ ret = []
+ for items in cext.net_if_addrs():
+ items = list(items)
+ items[0] = py2_strencode(items[0])
+ ret.append(items)
return ret
@@ -183,6 +254,7 @@ def users():
rawlist = cext.users()
for item in rawlist:
user, hostname, tstamp = item
+ user = py2_strencode(user)
nt = _common.suser(user, None, hostname, tstamp)
retlist.append(nt)
return retlist
@@ -190,7 +262,6 @@ def users():
pids = cext.pids
pid_exists = cext.pid_exists
-net_io_counters = cext.net_io_counters
disk_io_counters = cext.disk_io_counters
ppid_map = cext.ppid_map # not meant to be public
@@ -218,11 +289,12 @@ def wrap_exceptions(fun):
class Process(object):
"""Wrapper class around underlying C implementation."""
- __slots__ = ["pid", "_name"]
+ __slots__ = ["pid", "_name", "_ppid"]
def __init__(self, pid):
self.pid = pid
self._name = None
+ self._ppid = None
@wrap_exceptions
def name(self):
@@ -236,7 +308,12 @@ class Process(object):
elif self.pid == 4:
return "System"
else:
- return os.path.basename(self.exe())
+ try:
+ # Note: this will fail with AD for most PIDs owned
+ # by another user but it's faster.
+ return py2_strencode(os.path.basename(self.exe()))
+ except AccessDenied:
+ return py2_strencode(cext.proc_name(self.pid))
@wrap_exceptions
def exe(self):
@@ -248,11 +325,15 @@ class Process(object):
# see https://github.com/giampaolo/psutil/issues/528
if self.pid in (0, 4):
raise AccessDenied(self.pid, self._name)
- return _convert_raw_path(cext.proc_exe(self.pid))
+ return py2_strencode(_convert_raw_path(cext.proc_exe(self.pid)))
@wrap_exceptions
def cmdline(self):
- return cext.proc_cmdline(self.pid)
+ ret = cext.proc_cmdline(self.pid)
+ if PY3:
+ return ret
+ else:
+ return [py2_strencode(s) for s in ret]
def ppid(self):
try:
@@ -265,6 +346,8 @@ class Process(object):
return cext.proc_memory_info(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
+ # TODO: the C ext can probably be refactored in order
+ # to get this from cext.proc_info()
return cext.proc_memory_info_2(self.pid)
raise
@@ -303,6 +386,10 @@ class Process(object):
return cext.proc_kill(self.pid)
@wrap_exceptions
+ def send_signal(self, sig):
+ os.kill(self.pid, sig)
+
+ @wrap_exceptions
def wait(self, timeout=None):
if timeout is None:
timeout = cext.INFINITE
@@ -332,12 +419,12 @@ class Process(object):
return cext.proc_create_time(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
- return cext.proc_create_time_2(self.pid)
+ return ntpinfo(*cext.proc_info(self.pid)).create_time
raise
@wrap_exceptions
def num_threads(self):
- return cext.proc_num_threads(self.pid)
+ return ntpinfo(*cext.proc_info(self.pid)).num_threads
@wrap_exceptions
def threads(self):
@@ -354,7 +441,8 @@ class Process(object):
ret = cext.proc_cpu_times(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
- ret = cext.proc_cpu_times_2(self.pid)
+ nt = ntpinfo(*cext.proc_info(self.pid))
+ ret = (nt.user_time, nt.kernel_time)
else:
raise
return _common.pcputimes(*ret)
@@ -374,24 +462,26 @@ class Process(object):
# return a normalized pathname since the native C function appends
# "\\" at the and of the path
path = cext.proc_cwd(self.pid)
- return os.path.normpath(path)
+ return py2_strencode(os.path.normpath(path))
@wrap_exceptions
def open_files(self):
if self.pid in (0, 4):
return []
- retlist = []
+ ret = set()
# Filenames come in in native format like:
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
# Convert the first part in the corresponding drive letter
# (e.g. "C:\") by using Windows's QueryDosDevice()
raw_file_names = cext.proc_open_files(self.pid)
- for file in raw_file_names:
- file = _convert_raw_path(file)
- if isfile_strict(file) and file not in retlist:
- ntuple = _common.popenfile(file, -1)
- retlist.append(ntuple)
- return retlist
+ for _file in raw_file_names:
+ _file = _convert_raw_path(_file)
+ if isfile_strict(_file):
+ if not PY3:
+ _file = py2_strencode(_file)
+ ntuple = _common.popenfile(_file, -1)
+ ret.add(ntuple)
+ return list(ret)
@wrap_exceptions
def connections(self, kind='inet'):
@@ -399,7 +489,10 @@ class Process(object):
@wrap_exceptions
def nice_get(self):
- return cext.proc_priority_get(self.pid)
+ value = cext.proc_priority_get(self.pid)
+ if enum is not None:
+ value = Priority(value)
+ return value
@wrap_exceptions
def nice_set(self, value):
@@ -427,7 +520,8 @@ class Process(object):
ret = cext.proc_io_counters(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
- ret = cext.proc_io_counters_2(self.pid)
+ nt = ntpinfo(*cext.proc_info(self.pid))
+ ret = (nt.io_rcount, nt.io_wcount, nt.io_rbytes, nt.io_wbytes)
else:
raise
return _common.pio(*ret)
@@ -442,7 +536,8 @@ class Process(object):
@wrap_exceptions
def cpu_affinity_get(self):
- from_bitmask = lambda x: [i for i in xrange(64) if (1 << i) & x]
+ def from_bitmask(x):
+ return [i for i in xrange(64) if (1 << i) & x]
bitmask = cext.proc_cpu_affinity_get(self.pid)
return from_bitmask(bitmask)
@@ -462,7 +557,11 @@ class Process(object):
allcpus = list(range(len(per_cpu_times())))
for cpu in value:
if cpu not in allcpus:
- raise ValueError("invalid CPU %r" % cpu)
+ if not isinstance(cpu, (int, long)):
+ raise TypeError(
+ "invalid CPU %r; an integer is required" % cpu)
+ else:
+ raise ValueError("invalid CPU %r" % cpu)
bitmask = to_bitmask(value)
cext.proc_cpu_affinity_set(self.pid, bitmask)
@@ -473,10 +572,11 @@ class Process(object):
return cext.proc_num_handles(self.pid)
except OSError as err:
if err.errno in ACCESS_DENIED_SET:
- return cext.proc_num_handles_2(self.pid)
+ return ntpinfo(*cext.proc_info(self.pid)).num_handles
raise
@wrap_exceptions
def num_ctx_switches(self):
- tupl = cext.proc_num_ctx_switches(self.pid)
- return _common.pctxsw(*tupl)
+ ctx_switches = ntpinfo(*cext.proc_info(self.pid)).ctx_switches
+ # only voluntary ctx switches are supported
+ return _common.pctxsw(ctx_switches, 0)
diff --git a/psutil/arch/bsd/process_info.c b/psutil/arch/bsd/process_info.c
index ea7cba0d..d343b655 100644
--- a/psutil/arch/bsd/process_info.c
+++ b/psutil/arch/bsd/process_info.c
@@ -33,8 +33,7 @@
* On error, the function returns a BSD errno value.
*/
int
-psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount)
-{
+psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
int err;
struct kinfo_proc *result;
int done;
@@ -113,8 +112,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount)
char
-*psutil_get_cmd_path(long pid, size_t *pathsize)
-{
+*psutil_get_cmd_path(long pid, size_t *pathsize) {
int mib[4];
char *path;
size_t size = 0;
@@ -128,9 +126,8 @@ char
mib[3] = pid;
// call with a null buffer first to determine if we need a buffer
- if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1) {
+ if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1)
return NULL;
- }
path = malloc(size);
if (path == NULL) {
@@ -162,8 +159,7 @@ char
* 1 for insufficient privileges.
*/
char
-*psutil_get_cmd_args(long pid, size_t *argsize)
-{
+*psutil_get_cmd_args(long pid, size_t *argsize) {
int mib[4], argmax;
size_t size = sizeof(argmax);
char *procargs = NULL;
@@ -205,44 +201,40 @@ char
// returns the command line as a python list object
PyObject *
-psutil_get_arg_list(long pid)
-{
+psutil_get_cmdline(long pid) {
char *argstr = NULL;
int pos = 0;
size_t argsize = 0;
- PyObject *retlist = Py_BuildValue("[]");
- PyObject *item = NULL;
-
- if (pid < 0) {
- return retlist;
- }
+ PyObject *py_retlist = Py_BuildValue("[]");
+ PyObject *py_arg = NULL;
+ if (pid < 0)
+ return py_retlist;
argstr = psutil_get_cmd_args(pid, &argsize);
- if (argstr == NULL) {
+ if (argstr == NULL)
goto error;
- }
// args are returned as a flattened string with \0 separators between
// arguments add each string to the list then step forward to the next
// separator
if (argsize > 0) {
while (pos < argsize) {
- item = Py_BuildValue("s", &argstr[pos]);
- if (!item)
+ py_arg = Py_BuildValue("s", &argstr[pos]);
+ if (!py_arg)
goto error;
- if (PyList_Append(retlist, item))
+ if (PyList_Append(py_retlist, py_arg))
goto error;
- Py_DECREF(item);
+ Py_DECREF(py_arg);
pos = pos + strlen(&argstr[pos]) + 1;
}
}
free(argstr);
- return retlist;
+ return py_retlist;
error:
- Py_XDECREF(item);
- Py_DECREF(retlist);
+ Py_XDECREF(py_arg);
+ Py_DECREF(py_retlist);
if (argstr != NULL)
free(argstr);
return NULL;
@@ -253,19 +245,15 @@ error:
* Return 1 if PID exists in the current process list, else 0.
*/
int
-psutil_pid_exists(long pid)
-{
+psutil_pid_exists(long pid) {
int kill_ret;
- if (pid < 0) {
- return 0;
- }
+ if (pid < 0)
+ return 0;
// if kill returns success of permission denied we know it's a valid PID
kill_ret = kill(pid , 0);
- if ((0 == kill_ret) || (EPERM == errno)) {
+ if ((0 == kill_ret) || (EPERM == errno))
return 1;
- }
-
// otherwise return 0 for PID not found
return 0;
}
diff --git a/psutil/arch/bsd/process_info.h b/psutil/arch/bsd/process_info.h
index 858bd88a..b70ca23c 100644
--- a/psutil/arch/bsd/process_info.h
+++ b/psutil/arch/bsd/process_info.h
@@ -12,4 +12,4 @@ char *psutil_get_cmd_args(long pid, size_t *argsize);
char *psutil_get_cmd_path(long pid, size_t *pathsize);
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
int psutil_pid_exists(long pid);
-PyObject* psutil_get_arg_list(long pid);
+PyObject* psutil_get_cmdline(long pid);
diff --git a/psutil/arch/osx/process_info.c b/psutil/arch/osx/process_info.c
index be8092ef..a165e039 100644
--- a/psutil/arch/osx/process_info.c
+++ b/psutil/arch/osx/process_info.c
@@ -27,20 +27,16 @@
* Return 1 if PID exists in the current process list, else 0.
*/
int
-psutil_pid_exists(long pid)
-{
+psutil_pid_exists(long pid) {
int kill_ret;
// save some time if it's an invalid PID
- if (pid < 0) {
+ if (pid < 0)
return 0;
- }
-
// if kill returns success of permission denied we know it's a valid PID
kill_ret = kill(pid , 0);
- if ( (0 == kill_ret) || (EPERM == errno) ) {
+ if ( (0 == kill_ret) || (EPERM == errno))
return 1;
- }
// otherwise return 0 for PID not found
return 0;
@@ -56,8 +52,7 @@ psutil_pid_exists(long pid)
* On error, the function returns a BSD errno value.
*/
int
-psutil_get_proc_list(kinfo_proc **procList, size_t *procCount)
-{
+psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) {
// Declaring mib as const requires use of a cast since the
// sysctl prototype doesn't include the const modifier.
static const int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
@@ -85,34 +80,29 @@ psutil_get_proc_list(kinfo_proc **procList, size_t *procCount)
*/
while (lim-- > 0) {
size = 0;
- if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1) {
+ if (sysctl((int *)mib3, 3, NULL, &size, NULL, 0) == -1)
return errno;
- }
-
size2 = size + (size >> 3); // add some
if (size2 > size) {
ptr = malloc(size2);
- if (ptr == NULL) {
+ if (ptr == NULL)
ptr = malloc(size);
- } else {
+ else
size = size2;
- }
}
else {
ptr = malloc(size);
}
- if (ptr == NULL) {
+ if (ptr == NULL)
return ENOMEM;
- }
if (sysctl((int *)mib3, 3, ptr, &size, NULL, 0) == -1) {
err = errno;
free(ptr);
- if (err != ENOMEM) {
+ if (err != ENOMEM)
return err;
- }
-
- } else {
+ }
+ else {
*procList = (kinfo_proc *)ptr;
*procCount = size / sizeof(kinfo_proc);
return 0;
@@ -124,23 +114,20 @@ psutil_get_proc_list(kinfo_proc **procList, size_t *procCount)
// Read the maximum argument size for processes
int
-psutil_get_argmax()
-{
+psutil_get_argmax() {
int argmax;
int mib[] = { CTL_KERN, KERN_ARGMAX };
size_t size = sizeof(argmax);
- if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) {
+ if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0)
return argmax;
- }
return 0;
}
// return process args as a python list
PyObject *
-psutil_get_arg_list(long pid)
-{
+psutil_get_cmdline(long pid) {
int mib[3];
int nargs;
int len;
@@ -149,13 +136,13 @@ psutil_get_arg_list(long pid)
char *arg_end;
char *curr_arg;
size_t argmax;
- PyObject *arg = NULL;
- PyObject *arglist = NULL;
+
+ PyObject *py_arg = NULL;
+ PyObject *py_retlist = NULL;
// special case for PID 0 (kernel_task) where cmdline cannot be fetched
- if (pid == 0) {
+ if (pid == 0)
return Py_BuildValue("[]");
- }
// read argmax and allocate memory for argument space.
argmax = psutil_get_argmax();
@@ -177,11 +164,10 @@ psutil_get_arg_list(long pid)
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
if (EINVAL == errno) {
// EINVAL == access denied OR nonexistent PID
- if ( psutil_pid_exists(pid) ) {
+ if (psutil_pid_exists(pid))
AccessDenied();
- } else {
+ else
NoSuchProcess();
- }
}
goto error;
}
@@ -201,24 +187,23 @@ psutil_get_arg_list(long pid)
// skip ahead to the first argument
for (; arg_ptr < arg_end; arg_ptr++) {
- if (*arg_ptr != '\0') {
+ if (*arg_ptr != '\0')
break;
- }
}
// iterate through arguments
curr_arg = arg_ptr;
- arglist = Py_BuildValue("[]");
- if (!arglist)
+ py_retlist = Py_BuildValue("[]");
+ if (!py_retlist)
goto error;
while (arg_ptr < arg_end && nargs > 0) {
if (*arg_ptr++ == '\0') {
- arg = Py_BuildValue("s", curr_arg);
- if (!arg)
+ py_arg = Py_BuildValue("s", curr_arg);
+ if (!py_arg)
goto error;
- if (PyList_Append(arglist, arg))
+ if (PyList_Append(py_retlist, py_arg))
goto error;
- Py_DECREF(arg);
+ Py_DECREF(py_arg);
// iterate to next arg and decrement # of args
curr_arg = arg_ptr;
nargs--;
@@ -226,11 +211,11 @@ psutil_get_arg_list(long pid)
}
free(procargs);
- return arglist;
+ return py_retlist;
error:
- Py_XDECREF(arg);
- Py_XDECREF(arglist);
+ Py_XDECREF(py_arg);
+ Py_XDECREF(py_retlist);
if (procargs != NULL)
free(procargs);
return NULL;
@@ -238,8 +223,7 @@ error:
int
-psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
-{
+psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp) {
int mib[4];
size_t len;
mib[0] = CTL_KERN;
@@ -270,8 +254,7 @@ psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
* A thin wrapper around proc_pidinfo()
*/
int
-psutil_proc_pidinfo(long pid, int flavor, void *pti, int size)
-{
+psutil_proc_pidinfo(long pid, int flavor, void *pti, int size) {
int ret = proc_pidinfo((int)pid, flavor, 0, pti, size);
if (ret == 0) {
if (! psutil_pid_exists(pid)) {
diff --git a/psutil/arch/osx/process_info.h b/psutil/arch/osx/process_info.h
index c89c8570..ac71bbe3 100644
--- a/psutil/arch/osx/process_info.h
+++ b/psutil/arch/osx/process_info.h
@@ -13,4 +13,4 @@ int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp);
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
int psutil_pid_exists(long pid);
int psutil_proc_pidinfo(long pid, int flavor, void *pti, int size);
-PyObject* psutil_get_arg_list(long pid);
+PyObject* psutil_get_cmdline(long pid);
diff --git a/psutil/arch/windows/inet_ntop.c b/psutil/arch/windows/inet_ntop.c
new file mode 100644
index 00000000..50dfb6ae
--- /dev/null
+++ b/psutil/arch/windows/inet_ntop.c
@@ -0,0 +1,38 @@
+#include "inet_ntop.h"
+
+// From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/
+PCSTR
+WSAAPI
+inet_ntop(__in INT Family,
+ __in PVOID pAddr,
+ __out_ecount(StringBufSize) PSTR pStringBuf,
+ __in size_t StringBufSize) {
+ DWORD dwAddressLength = 0;
+ struct sockaddr_storage srcaddr;
+ struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr;
+ struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr;
+
+ memset(&srcaddr, 0, sizeof(struct sockaddr_storage));
+ srcaddr.ss_family = Family;
+
+ if (Family == AF_INET)
+ {
+ dwAddressLength = sizeof(struct sockaddr_in);
+ memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr));
+ } else if (Family == AF_INET6)
+ {
+ dwAddressLength = sizeof(struct sockaddr_in6);
+ memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr));
+ } else {
+ return NULL;
+ }
+
+ if (WSAAddressToString((LPSOCKADDR) &srcaddr,
+ dwAddressLength,
+ 0,
+ pStringBuf,
+ (LPDWORD) &StringBufSize) != 0) {
+ return NULL;
+ }
+ return pStringBuf;
+}
diff --git a/psutil/arch/windows/inet_ntop.h b/psutil/arch/windows/inet_ntop.h
new file mode 100644
index 00000000..0d97e28c
--- /dev/null
+++ b/psutil/arch/windows/inet_ntop.h
@@ -0,0 +1,10 @@
+#include <ws2tcpip.h>
+
+PCSTR
+WSAAPI
+inet_ntop(
+ __in INT Family,
+ __in PVOID pAddr,
+ __out_ecount(StringBufSize) PSTR pStringBuf,
+ __in size_t StringBufSize
+); \ No newline at end of file
diff --git a/psutil/arch/windows/ntextapi.h b/psutil/arch/windows/ntextapi.h
index 298c0780..7f86c57a 100644
--- a/psutil/arch/windows/ntextapi.h
+++ b/psutil/arch/windows/ntextapi.h
@@ -3,6 +3,9 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+#if !defined(__NTEXTAPI_H__)
+#define __NTEXTAPI_H__
+#include <winternl.h>
typedef enum _KTHREAD_STATE {
Initialized,
@@ -63,23 +66,6 @@ typedef struct _CLIENT_ID {
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
-
-typedef struct _UNICODE_STRING {
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer;
-} UNICODE_STRING, *PUNICODE_STRING;
-
-typedef struct _SYSTEM_TIMEOFDAY_INFORMATION {
- LARGE_INTEGER BootTime;
- LARGE_INTEGER CurrentTime;
- LARGE_INTEGER TimeZoneBias;
- ULONG TimeZoneId;
- ULONG Reserved;
- ULONGLONG BootTimeBias;
- ULONGLONG SleepTimeBias;
-} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION;
-
typedef struct _SYSTEM_THREAD_INFORMATION {
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
@@ -108,7 +94,7 @@ typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
ULONG_PTR Reserved4;
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
-typedef struct _SYSTEM_PROCESS_INFORMATION {
+typedef struct _SYSTEM_PROCESS_INFORMATION2 {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER SpareLi1;
@@ -143,31 +129,10 @@ typedef struct _SYSTEM_PROCESS_INFORMATION {
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
SYSTEM_THREAD_INFORMATION Threads[1];
-} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
-
-
-// structures and enums from winternl.h (not available under mingw)
-typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
- LARGE_INTEGER IdleTime;
- LARGE_INTEGER KernelTime;
- LARGE_INTEGER UserTime;
- LARGE_INTEGER Reserved1[2];
- ULONG Reserved2;
-} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION,
- *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
-
+} SYSTEM_PROCESS_INFORMATION2, *PSYSTEM_PROCESS_INFORMATION2;
-typedef enum _SYSTEM_INFORMATION_CLASS {
- SystemBasicInformation = 0,
- SystemPerformanceInformation = 2,
- SystemTimeOfDayInformation = 3,
- SystemProcessInformation = 5,
- SystemProcessorPerformanceInformation = 8,
- SystemInterruptInformation = 23,
- SystemExceptionInformation = 33,
- SystemRegistryQuotaInformation = 37,
- SystemLookasideInformation = 45
-} SYSTEM_INFORMATION_CLASS;
+#define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2
+#define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2
// ================================================
@@ -186,32 +151,9 @@ typedef struct _WINSTATION_INFO {
FILETIME CurrentTime;
} WINSTATION_INFO, *PWINSTATION_INFO;
-typedef enum _WINSTATIONINFOCLASS {
- WinStationInformation = 8
-} WINSTATIONINFOCLASS;
-
typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)
(HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG);
-typedef struct _WINSTATIONINFORMATIONW {
- BYTE Reserved2[70];
- ULONG LogonId;
- BYTE Reserved3[1140];
-} WINSTATIONINFORMATIONW, *PWINSTATIONINFORMATIONW;
-
-// mingw support:
-// http://www.koders.com/c/fid7C02CAE627C526914CDEB427405B51DF393A5EFA.aspx
-#ifndef _INC_WTSAPI
-typedef struct _WTS_CLIENT_ADDRESS {
- DWORD AddressFamily; // AF_INET, AF_IPX, AF_NETBIOS, AF_UNSPEC
- BYTE Address[20]; // client network address
-} WTS_CLIENT_ADDRESS, * PWTS_CLIENT_ADDRESS;
-
-HANDLE WINAPI WTSOpenServerA(IN LPSTR pServerName);
-
-VOID WINAPI WTSCloseServer(IN HANDLE hServer);
-#endif
-
/*
* NtQueryInformationProcess code taken from
@@ -235,23 +177,16 @@ typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
DWORD ProcessInformationLength
);
-typedef struct _PROCESS_BASIC_INFORMATION {
- PVOID Reserved1;
- PVOID PebBaseAddress;
- PVOID Reserved2[2];
- ULONG_PTR UniqueProcessId;
- PVOID Reserved3;
-} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
-typedef enum _PROCESSINFOCLASS {
- ProcessBasicInformation,
+typedef enum _PROCESSINFOCLASS2 {
+ _ProcessBasicInformation,
ProcessQuotaLimits,
ProcessIoCounters,
ProcessVmCounters,
ProcessTimes,
ProcessBasePriority,
ProcessRaisePriority,
- ProcessDebugPort,
+ _ProcessDebugPort,
ProcessExceptionPort,
ProcessAccessToken,
ProcessLdtInformation,
@@ -270,9 +205,9 @@ typedef enum _PROCESSINFOCLASS {
ProcessDeviceMap,
ProcessSessionInformation,
ProcessForegroundInformation,
- ProcessWow64Information,
+ _ProcessWow64Information,
/* added after XP+ */
- ProcessImageFileName,
+ _ProcessImageFileName,
ProcessLUIDDeviceMapsEnabled,
ProcessBreakOnTermination,
ProcessDebugObjectHandle,
@@ -284,4 +219,12 @@ typedef enum _PROCESSINFOCLASS {
ProcessCookie,
ProcessImageInformation,
MaxProcessInfoClass
-} PROCESSINFOCLASS;
+} PROCESSINFOCLASS2;
+
+#define PROCESSINFOCLASS PROCESSINFOCLASS2
+#define ProcessBasicInformation _ProcessBasicInformation
+#define ProcessWow64Information _ProcessWow64Information
+#define ProcessDebugPort _ProcessDebugPort
+#define ProcessImageFileName _ProcessImageFileName
+
+#endif // __NTEXTAPI_H__
diff --git a/psutil/arch/windows/process_handles.c b/psutil/arch/windows/process_handles.c
index f7479e99..433da349 100644
--- a/psutil/arch/windows/process_handles.c
+++ b/psutil/arch/windows/process_handles.c
@@ -4,334 +4,531 @@
* found in the LICENSE file.
*
*/
-
-#ifndef UNICODE
-#define UNICODE
-#endif
-
-#include <Python.h>
-#include <windows.h>
-#include <stdio.h>
#include "process_handles.h"
-#ifndef NT_SUCCESS
-#define NT_SUCCESS(x) ((x) >= 0)
-#endif
-#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
-
-#define SystemHandleInformation 16
-#define ObjectBasicInformation 0
-#define ObjectNameInformation 1
-#define ObjectTypeInformation 2
-
-
-typedef LONG NTSTATUS;
-
-typedef struct _UNICODE_STRING {
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer;
-} UNICODE_STRING, *PUNICODE_STRING;
-
-typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
- ULONG SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- PULONG ReturnLength
-);
-
-typedef NTSTATUS (NTAPI *_NtDuplicateObject)(
- HANDLE SourceProcessHandle,
- HANDLE SourceHandle,
- HANDLE TargetProcessHandle,
- PHANDLE TargetHandle,
- ACCESS_MASK DesiredAccess,
- ULONG Attributes,
- ULONG Options
-);
-
-typedef NTSTATUS (NTAPI *_NtQueryObject)(
- HANDLE ObjectHandle,
- ULONG ObjectInformationClass,
- PVOID ObjectInformation,
- ULONG ObjectInformationLength,
- PULONG ReturnLength
-);
-
-typedef struct _SYSTEM_HANDLE {
- ULONG ProcessId;
- BYTE ObjectTypeNumber;
- BYTE Flags;
- USHORT Handle;
- PVOID Object;
- ACCESS_MASK GrantedAccess;
-} SYSTEM_HANDLE, *PSYSTEM_HANDLE;
-
-typedef struct _SYSTEM_HANDLE_INFORMATION {
- ULONG HandleCount;
- SYSTEM_HANDLE Handles[1];
-} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
-
-typedef enum _POOL_TYPE {
- NonPagedPool,
- PagedPool,
- NonPagedPoolMustSucceed,
- DontUseThisType,
- NonPagedPoolCacheAligned,
- PagedPoolCacheAligned,
- NonPagedPoolCacheAlignedMustS
-} POOL_TYPE, *PPOOL_TYPE;
-
-typedef struct _OBJECT_TYPE_INFORMATION {
- UNICODE_STRING Name;
- ULONG TotalNumberOfObjects;
- ULONG TotalNumberOfHandles;
- ULONG TotalPagedPoolUsage;
- ULONG TotalNonPagedPoolUsage;
- ULONG TotalNamePoolUsage;
- ULONG TotalHandleTableUsage;
- ULONG HighWaterNumberOfObjects;
- ULONG HighWaterNumberOfHandles;
- ULONG HighWaterPagedPoolUsage;
- ULONG HighWaterNonPagedPoolUsage;
- ULONG HighWaterNamePoolUsage;
- ULONG HighWaterHandleTableUsage;
- ULONG InvalidAttributes;
- GENERIC_MAPPING GenericMapping;
- ULONG ValidAccess;
- BOOLEAN SecurityRequired;
- BOOLEAN MaintainHandleCount;
- USHORT MaintainTypeList;
- POOL_TYPE PoolType;
- ULONG PagedPoolUsage;
- ULONG NonPagedPoolUsage;
-} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
+static _NtQuerySystemInformation __NtQuerySystemInformation = NULL;
+static _NtQueryObject __NtQueryObject = NULL;
+
+CRITICAL_SECTION g_cs;
+BOOL g_initialized = FALSE;
+NTSTATUS g_status;
+HANDLE g_hFile = NULL;
+HANDLE g_hEvtStart = NULL;
+HANDLE g_hEvtFinish = NULL;
+HANDLE g_hThread = NULL;
+PUNICODE_STRING g_pNameBuffer = NULL;
+ULONG g_dwSize = 0;
+ULONG g_dwLength = 0;
+PVOID g_fiber = NULL;
PVOID
-GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName)
-{
+GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) {
return GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
}
PyObject *
-psutil_get_open_files(long pid, HANDLE processHandle)
-{
- _NtQuerySystemInformation NtQuerySystemInformation =
+psutil_get_open_files(long dwPid, HANDLE hProcess) {
+ OSVERSIONINFO osvi;
+
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osvi);
+
+ // Threaded version only works for Vista+
+ if (osvi.dwMajorVersion >= 6)
+ return psutil_get_open_files_ntqueryobject(dwPid, hProcess);
+ else
+ return psutil_get_open_files_getmappedfilename(dwPid, hProcess);
+}
+
+
+VOID
+psutil_get_open_files_init(BOOL threaded) {
+ if (g_initialized == TRUE)
+ return;
+
+ // Resolve the Windows API calls
+ __NtQuerySystemInformation =
GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation");
- _NtQueryObject NtQueryObject =
- GetLibraryProcAddress("ntdll.dll", "NtQueryObject");
-
- NTSTATUS status;
- PSYSTEM_HANDLE_INFORMATION handleInfo;
- ULONG handleInfoSize = 0x10000;
- ULONG i;
- ULONG fileNameLength;
- PyObject *filesList = Py_BuildValue("[]");
- PyObject *arg = NULL;
- PyObject *fileFromWchar = NULL;
-
- if (filesList == NULL)
- return NULL;
-
- handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);
- if (handleInfo == NULL) {
- Py_DECREF(filesList);
- PyErr_NoMemory();
- return NULL;
+ __NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject");
+
+ // Create events for signalling work between threads
+ if (threaded == TRUE) {
+ g_hEvtStart = CreateEvent(NULL, FALSE, FALSE, NULL);
+ g_hEvtFinish = CreateEvent(NULL, FALSE, FALSE, NULL);
+ InitializeCriticalSection(&g_cs);
}
- // NtQuerySystemInformation won't give us the correct buffer size,
- // so we guess by doubling the buffer size.
- while ((status = NtQuerySystemInformation(
- SystemHandleInformation,
- handleInfo,
- handleInfoSize,
- NULL
- )) == STATUS_INFO_LENGTH_MISMATCH)
+ g_initialized = TRUE;
+}
+
+
+PyObject *
+psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
+ NTSTATUS status;
+ PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
+ DWORD dwInfoSize = 0x10000;
+ DWORD dwRet = 0;
+ PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
+ DWORD i = 0;
+ BOOLEAN error = FALSE;
+ DWORD dwWait = 0;
+ PyObject* py_retlist = NULL;
+ PyObject* py_path = NULL;
+
+ if (g_initialized == FALSE)
+ psutil_get_open_files_init(TRUE);
+
+ // Due to the use of global variables, ensure only 1 call
+ // to psutil_get_open_files() is running
+ EnterCriticalSection(&g_cs);
+
+ if (__NtQuerySystemInformation == NULL ||
+ __NtQueryObject == NULL ||
+ g_hEvtStart == NULL ||
+ g_hEvtFinish == NULL)
+
{
- handleInfo = (PSYSTEM_HANDLE_INFORMATION) \
- realloc(handleInfo, handleInfoSize *= 2);
+ PyErr_SetFromWindowsErr(0);
+ error = TRUE;
+ goto cleanup;
+ }
+
+ // Py_BuildValue raises an exception if NULL is returned
+ py_retlist = PyList_New(0);
+ if (py_retlist == NULL) {
+ error = TRUE;
+ goto cleanup;
}
+ do {
+ if (pHandleInfo != NULL) {
+ HeapFree(GetProcessHeap(), 0, pHandleInfo);
+ pHandleInfo = NULL;
+ }
+
+ // NtQuerySystemInformation won't give us the correct buffer size,
+ // so we guess by doubling the buffer size.
+ dwInfoSize *= 2;
+ pHandleInfo = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ dwInfoSize);
+
+ if (pHandleInfo == NULL) {
+ PyErr_NoMemory();
+ error = TRUE;
+ goto cleanup;
+ }
+ } while ((status = __NtQuerySystemInformation(
+ SystemExtendedHandleInformation,
+ pHandleInfo,
+ dwInfoSize,
+ &dwRet)) == STATUS_INFO_LENGTH_MISMATCH);
+
// NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH
if (!NT_SUCCESS(status)) {
- Py_DECREF(filesList);
- free(handleInfo);
- return NULL;
+ PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status));
+ error = TRUE;
+ goto cleanup;
}
- for (i = 0; i < handleInfo->HandleCount; i++) {
- SYSTEM_HANDLE handle = handleInfo->Handles[i];
- HANDLE dupHandle = NULL;
- HANDLE mapHandle = NULL;
- POBJECT_TYPE_INFORMATION objectTypeInfo = NULL;
- PVOID objectNameInfo;
- UNICODE_STRING objectName;
- ULONG returnLength;
- DWORD error = 0;
- fileFromWchar = NULL;
- arg = NULL;
-
- // Check if this handle belongs to the PID the user specified.
- if (handle.ProcessId != pid)
- continue;
-
- // Skip handles with the following access codes as the next call
- // to NtDuplicateObject() or NtQueryObject() might hang forever.
- if ((handle.GrantedAccess == 0x0012019f)
- || (handle.GrantedAccess == 0x001a019f)
- || (handle.GrantedAccess == 0x00120189)
- || (handle.GrantedAccess == 0x00100000)) {
- continue;
- }
+ for (i = 0; i < pHandleInfo->NumberOfHandles; i++) {
+ hHandle = &pHandleInfo->Handles[i];
+
+ // Check if this hHandle belongs to the PID the user specified.
+ if (hHandle->UniqueProcessId != (HANDLE)dwPid ||
+ hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE)
+ goto loop_cleanup;
- if (!DuplicateHandle(processHandle,
- handle.Handle,
+ if (!DuplicateHandle(hProcess,
+ hHandle->HandleValue,
GetCurrentProcess(),
- &dupHandle,
+ &g_hFile,
0,
TRUE,
DUPLICATE_SAME_ACCESS))
- {
- //printf("[%#x] Error: %d \n", handle.Handle, GetLastError());
- continue;
- }
-
-
- mapHandle = CreateFileMapping(dupHandle,
- NULL,
- PAGE_READONLY,
- 0,
- 0,
- NULL);
- if (mapHandle == NULL) {
- error = GetLastError();
- if (error == ERROR_INVALID_HANDLE || error == ERROR_BAD_EXE_FORMAT) {
- CloseHandle(dupHandle);
- //printf("CreateFileMapping Error: %d\n", error);
- continue;
- }
- }
- CloseHandle(mapHandle);
-
- // Query the object type.
- objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);
- if (!NT_SUCCESS(NtQueryObject(
- dupHandle,
- ObjectTypeInformation,
- objectTypeInfo,
- 0x1000,
- NULL
- )))
{
- free(objectTypeInfo);
- CloseHandle(dupHandle);
- continue;
+ /*
+ printf("[%d] DuplicateHandle (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
+ */
+ goto loop_cleanup;
}
- objectNameInfo = malloc(0x1000);
- if (!NT_SUCCESS(NtQueryObject(
- dupHandle,
- ObjectNameInformation,
- objectNameInfo,
- 0x1000,
- &returnLength
- )))
- {
- // Reallocate the buffer and try again.
- objectNameInfo = realloc(objectNameInfo, returnLength);
- if (!NT_SUCCESS(NtQueryObject(
- dupHandle,
- ObjectNameInformation,
- objectNameInfo,
- returnLength,
- NULL
- )))
- {
- // We have the type name, so just display that.
+ // Guess buffer size is MAX_PATH + 1
+ g_dwLength = (MAX_PATH+1) * sizeof(WCHAR);
+
+ do {
+ // Release any previously allocated buffer
+ if (g_pNameBuffer != NULL) {
+ HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
+ g_pNameBuffer = NULL;
+ g_dwSize = 0;
+ }
+
+ // NtQueryObject puts the required buffer size in g_dwLength
+ // WinXP edge case puts g_dwLength == 0, just skip this handle
+ if (g_dwLength == 0)
+ goto loop_cleanup;
+
+ g_dwSize = g_dwLength;
+ if (g_dwSize > 0) {
+ g_pNameBuffer = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ g_dwSize);
+
+ if (g_pNameBuffer == NULL)
+ goto loop_cleanup;
+ }
+
+ dwWait = psutil_NtQueryObject();
+
+ // If the call does not return, skip this handle
+ if (dwWait != WAIT_OBJECT_0)
+ goto loop_cleanup;
+
+ } while (g_status == STATUS_INFO_LENGTH_MISMATCH);
+
+ // NtQueryObject stopped returning STATUS_INFO_LENGTH_MISMATCH
+ if (!NT_SUCCESS(g_status))
+ goto loop_cleanup;
+
+ // Convert to PyUnicode and append it to the return list
+ if (g_pNameBuffer->Length > 0) {
+ /*
+ printf("[%d] Filename (%#x) %#d bytes: %S\n",
+ dwPid,
+ hHandle->HandleValue,
+ g_pNameBuffer->Length,
+ g_pNameBuffer->Buffer);
+ */
+
+ py_path = PyUnicode_FromWideChar(g_pNameBuffer->Buffer,
+ g_pNameBuffer->Length/2);
+ if (py_path == NULL) {
/*
- printf(
- "[%#x] %.*S: (could not get name)\n",
- handle.Handle,
- objectTypeInfo->Name.Length / 2,
- objectTypeInfo->Name.Buffer
- );
+ printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
*/
- free(objectTypeInfo);
- free(objectNameInfo);
- CloseHandle(dupHandle);
- continue;
+ error = TRUE;
+ goto loop_cleanup;
+ }
+ if (PyList_Append(py_retlist, py_path)) {
+ /*
+ printf("[%d] PyList_Append (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
+ */
+ error = TRUE;
+ goto loop_cleanup;
}
}
- // Cast our buffer into an UNICODE_STRING.
- objectName = *(PUNICODE_STRING)objectNameInfo;
+loop_cleanup:
+ Py_XDECREF(py_path);
+ py_path = NULL;
+
+ if (g_pNameBuffer != NULL)
+ HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
+ g_pNameBuffer = NULL;
+ g_dwSize = 0;
+ g_dwLength = 0;
+
+ if (g_hFile != NULL)
+ CloseHandle(g_hFile);
+ g_hFile = NULL;
+ }
+
+cleanup:
+ if (g_pNameBuffer != NULL)
+ HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
+ g_pNameBuffer = NULL;
+ g_dwSize = 0;
+ g_dwLength = 0;
+
+ if (g_hFile != NULL)
+ CloseHandle(g_hFile);
+ g_hFile = NULL;
+
+ if (pHandleInfo != NULL)
+ HeapFree(GetProcessHeap(), 0, pHandleInfo);
+ pHandleInfo = NULL;
+
+ if (error) {
+ Py_XDECREF(py_retlist);
+ py_retlist = NULL;
+ }
+
+ LeaveCriticalSection(&g_cs);
+
+ return py_retlist;
+}
+
+
+DWORD
+psutil_NtQueryObject() {
+ DWORD dwWait = 0;
+
+ if (g_hThread == NULL)
+ g_hThread = CreateThread(
+ NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)psutil_NtQueryObjectThread,
+ NULL,
+ 0,
+ NULL);
+ if (g_hThread == NULL)
+ return GetLastError();
+
+ // Signal the worker thread to start
+ SetEvent(g_hEvtStart);
+
+ // Wait for the worker thread to finish
+ dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT);
+
+ // If the thread hangs, kill it and cleanup
+ if (dwWait == WAIT_TIMEOUT) {
+ SuspendThread(g_hThread);
+ TerminateThread(g_hThread, 1);
+ WaitForSingleObject(g_hThread, INFINITE);
+ CloseHandle(g_hThread);
+
+ // Cleanup Fiber
+ if (g_fiber != NULL)
+ DeleteFiber(g_fiber);
+ g_fiber = NULL;
+
+ g_hThread = NULL;
+ }
+
+ return dwWait;
+}
- // Print the information!
- if (objectName.Length)
+
+void
+psutil_NtQueryObjectThread() {
+ // Prevent the thread stack from leaking when this
+ // thread gets terminated due to NTQueryObject hanging
+ g_fiber = ConvertThreadToFiber(NULL);
+
+ // Loop infinitely waiting for work
+ while (TRUE) {
+ WaitForSingleObject(g_hEvtStart, INFINITE);
+
+ g_status = __NtQueryObject(g_hFile,
+ ObjectNameInformation,
+ g_pNameBuffer,
+ g_dwSize,
+ &g_dwLength);
+ SetEvent(g_hEvtFinish);
+ }
+}
+
+
+PyObject *
+psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) {
+ NTSTATUS status;
+ PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
+ DWORD dwInfoSize = 0x10000;
+ DWORD dwRet = 0;
+ PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
+ HANDLE hFile = NULL;
+ HANDLE hMap = NULL;
+ DWORD i = 0;
+ BOOLEAN error = FALSE;
+ PyObject* py_retlist = NULL;
+ PyObject* py_path = NULL;
+ ULONG dwSize = 0;
+ LPVOID pMem = NULL;
+ TCHAR pszFilename[MAX_PATH+1];
+
+ if (g_initialized == FALSE)
+ psutil_get_open_files_init(FALSE);
+
+ if (__NtQuerySystemInformation == NULL || __NtQueryObject == NULL) {
+ PyErr_SetFromWindowsErr(0);
+ error = TRUE;
+ goto cleanup;
+ }
+
+ // Py_BuildValue raises an exception if NULL is returned
+ py_retlist = PyList_New(0);
+ if (py_retlist == NULL) {
+ error = TRUE;
+ goto cleanup;
+ }
+
+ do {
+ if (pHandleInfo != NULL) {
+ HeapFree(GetProcessHeap(), 0, pHandleInfo);
+ pHandleInfo = NULL;
+ }
+
+ // NtQuerySystemInformation won't give us the correct buffer size,
+ // so we guess by doubling the buffer size.
+ dwInfoSize *= 2;
+ pHandleInfo = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ dwInfoSize);
+
+ if (pHandleInfo == NULL) {
+ PyErr_NoMemory();
+ error = TRUE;
+ goto cleanup;
+ }
+ } while ((status = __NtQuerySystemInformation(
+ SystemExtendedHandleInformation,
+ pHandleInfo,
+ dwInfoSize,
+ &dwRet)) == STATUS_INFO_LENGTH_MISMATCH);
+
+ // NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH
+ if (!NT_SUCCESS(status)) {
+ PyErr_SetFromWindowsErr(HRESULT_FROM_NT(status));
+ error = TRUE;
+ goto cleanup;
+ }
+
+ for (i = 0; i < pHandleInfo->NumberOfHandles; i++) {
+ hHandle = &pHandleInfo->Handles[i];
+
+ // Check if this hHandle belongs to the PID the user specified.
+ if (hHandle->UniqueProcessId != (HANDLE)dwPid ||
+ hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE)
+ goto loop_cleanup;
+
+ if (!DuplicateHandle(hProcess,
+ hHandle->HandleValue,
+ GetCurrentProcess(),
+ &hFile,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS))
{
- // The object has a name. Make sure it is a file otherwise
- // ignore it
- fileNameLength = objectName.Length / 2;
- if (wcscmp(objectTypeInfo->Name.Buffer, L"File") == 0) {
- // printf("%.*S\n", objectName.Length / 2, objectName.Buffer);
- fileFromWchar = PyUnicode_FromWideChar(objectName.Buffer,
- fileNameLength);
- if (fileFromWchar == NULL)
- goto error_py_fun;
-#if PY_MAJOR_VERSION >= 3
- arg = Py_BuildValue("N",
- PyUnicode_AsUTF8String(fileFromWchar));
-#else
- arg = Py_BuildValue("N",
- PyUnicode_FromObject(fileFromWchar));
-#endif
- if (!arg)
- goto error_py_fun;
- Py_XDECREF(fileFromWchar);
- fileFromWchar = NULL;
- if (PyList_Append(filesList, arg))
- goto error_py_fun;
- Py_XDECREF(arg);
- }
/*
- printf(
- "[%#x] %.*S: %.*S\n",
- handle.Handle,
- objectTypeInfo->Name.Length / 2,
- objectTypeInfo->Name.Buffer,
- objectName.Length / 2,
- objectName.Buffer
- );
+ printf("[%d] DuplicateHandle (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
*/
+ goto loop_cleanup;
}
- else
- {
- // Print something else.
+
+ hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (hMap == NULL) {
/*
- printf(
- "[%#x] %.*S: (unnamed)\n",
- handle.Handle,
- objectTypeInfo->Name.Length / 2,
- objectTypeInfo->Name.Buffer
- );
+ printf("[%d] CreateFileMapping (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
*/
- ;;
+ goto loop_cleanup;
}
- free(objectTypeInfo);
- free(objectNameInfo);
- CloseHandle(dupHandle);
+
+ pMem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 1);
+
+ if (pMem == NULL) {
+ /*
+ printf("[%d] MapViewOfFile (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
+ */
+ goto loop_cleanup;
+ }
+
+ dwSize = GetMappedFileName(
+ GetCurrentProcess(), pMem, pszFilename, MAX_PATH);
+ if (dwSize == 0) {
+ /*
+ printf("[%d] GetMappedFileName (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
+ */
+ goto loop_cleanup;
+ }
+
+ pszFilename[dwSize] = '\0';
+ /*
+ printf("[%d] Filename (%#x) %#d bytes: %S\n",
+ dwPid,
+ hHandle->HandleValue,
+ dwSize,
+ pszFilename);
+ */
+
+ py_path = PyUnicode_FromWideChar(pszFilename, dwSize);
+ if (py_path == NULL) {
+ /*
+ printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
+ */
+ error = TRUE;
+ goto loop_cleanup;
+ }
+
+ if (PyList_Append(py_retlist, py_path)) {
+ /*
+ printf("[%d] PyList_Append (%#x): %#x \n",
+ dwPid,
+ hHandle->HandleValue,
+ GetLastError());
+ */
+ error = TRUE;
+ goto loop_cleanup;
+ }
+
+loop_cleanup:
+ Py_XDECREF(py_path);
+ py_path = NULL;
+
+ if (pMem != NULL)
+ UnmapViewOfFile(pMem);
+ pMem = NULL;
+
+ if (hMap != NULL)
+ CloseHandle(hMap);
+ hMap = NULL;
+
+ if (hFile != NULL)
+ CloseHandle(hFile);
+ hFile = NULL;
+
+ dwSize = 0;
}
- free(handleInfo);
- CloseHandle(processHandle);
- return filesList;
-
-error_py_fun:
- Py_XDECREF(arg);
- Py_XDECREF(fileFromWchar);
- Py_DECREF(filesList);
- return NULL;
+
+cleanup:
+ if (pMem != NULL)
+ UnmapViewOfFile(pMem);
+ pMem = NULL;
+
+ if (hMap != NULL)
+ CloseHandle(hMap);
+ hMap = NULL;
+
+ if (hFile != NULL)
+ CloseHandle(hFile);
+ hFile = NULL;
+
+ if (pHandleInfo != NULL)
+ HeapFree(GetProcessHeap(), 0, pHandleInfo);
+ pHandleInfo = NULL;
+
+ if (error) {
+ Py_XDECREF(py_retlist);
+ py_retlist = NULL;
+ }
+
+ return py_retlist;
}
diff --git a/psutil/arch/windows/process_handles.h b/psutil/arch/windows/process_handles.h
index 342ce8fd..ea5fbdbe 100644
--- a/psutil/arch/windows/process_handles.h
+++ b/psutil/arch/windows/process_handles.h
@@ -4,7 +4,108 @@
* found in the LICENSE file.
*/
+#ifndef __PROCESS_HANDLES_H__
+#define __PROCESS_HANDLES_H__
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
#include <Python.h>
+#include <stdio.h>
#include <windows.h>
+#include <strsafe.h>
+#include <winternl.h>
+#include <psapi.h>
+
+
+#ifndef NT_SUCCESS
+#define NT_SUCCESS(x) ((x) >= 0)
+#endif
+
+#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
+#define ObjectBasicInformation 0
+#define ObjectNameInformation 1
+#define ObjectTypeInformation 2
+#define HANDLE_TYPE_FILE 28
+#define NTQO_TIMEOUT 100
+
+typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
+ ULONG SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength
+);
+
+typedef NTSTATUS (NTAPI *_NtQueryObject)(
+ HANDLE ObjectHandle,
+ ULONG ObjectInformationClass,
+ PVOID ObjectInformation,
+ ULONG ObjectInformationLength,
+ PULONG ReturnLength
+);
+// Undocumented FILE_INFORMATION_CLASS: FileNameInformation
+static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64;
+
+typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
+ PVOID Object;
+ HANDLE UniqueProcessId;
+ HANDLE HandleValue;
+ ULONG GrantedAccess;
+ USHORT CreatorBackTraceIndex;
+ USHORT ObjectTypeIndex;
+ ULONG HandleAttributes;
+ ULONG Reserved;
+} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
+ ULONG_PTR NumberOfHandles;
+ ULONG_PTR Reserved;
+ SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
+
+typedef enum _POOL_TYPE {
+ NonPagedPool,
+ PagedPool,
+ NonPagedPoolMustSucceed,
+ DontUseThisType,
+ NonPagedPoolCacheAligned,
+ PagedPoolCacheAligned,
+ NonPagedPoolCacheAlignedMustS
+} POOL_TYPE, *PPOOL_TYPE;
+
+typedef struct _OBJECT_TYPE_INFORMATION {
+ UNICODE_STRING Name;
+ ULONG TotalNumberOfObjects;
+ ULONG TotalNumberOfHandles;
+ ULONG TotalPagedPoolUsage;
+ ULONG TotalNonPagedPoolUsage;
+ ULONG TotalNamePoolUsage;
+ ULONG TotalHandleTableUsage;
+ ULONG HighWaterNumberOfObjects;
+ ULONG HighWaterNumberOfHandles;
+ ULONG HighWaterPagedPoolUsage;
+ ULONG HighWaterNonPagedPoolUsage;
+ ULONG HighWaterNamePoolUsage;
+ ULONG HighWaterHandleTableUsage;
+ ULONG InvalidAttributes;
+ GENERIC_MAPPING GenericMapping;
+ ULONG ValidAccess;
+ BOOLEAN SecurityRequired;
+ BOOLEAN MaintainHandleCount;
+ USHORT MaintainTypeList;
+ POOL_TYPE PoolType;
+ ULONG PagedPoolUsage;
+ ULONG NonPagedPoolUsage;
+} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
+
+PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName);
+VOID psutil_get_open_files_init(BOOL threaded);
PyObject* psutil_get_open_files(long pid, HANDLE processHandle);
+PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess);
+PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess);
+DWORD psutil_NtQueryObject(void);
+void psutil_NtQueryObjectThread(void);
+
+#endif // __PROCESS_HANDLES_H__
diff --git a/psutil/arch/windows/process_info.c b/psutil/arch/windows/process_info.c
index 8298b16c..a064baa7 100644
--- a/psutil/arch/windows/process_info.c
+++ b/psutil/arch/windows/process_info.c
@@ -26,8 +26,7 @@
* Return a process handle or NULL.
*/
HANDLE
-psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess)
-{
+psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess) {
HANDLE hProcess;
DWORD processExitCode = 0;
@@ -38,12 +37,10 @@ psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess)
hProcess = OpenProcess(dwDesiredAccess, FALSE, pid);
if (hProcess == NULL) {
- if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER)
NoSuchProcess();
- }
- else {
+ else
PyErr_SetFromWindowsErr(0);
- }
return NULL;
}
@@ -72,8 +69,7 @@ psutil_handle_from_pid(DWORD pid) {
// fetch the PEB base address from NtQueryInformationProcess()
PVOID
-psutil_get_peb_address(HANDLE ProcessHandle)
-{
+psutil_get_peb_address(HANDLE ProcessHandle) {
_NtQueryInformationProcess NtQueryInformationProcess =
(_NtQueryInformationProcess)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
@@ -123,19 +119,15 @@ psutil_get_pids(DWORD *numberOfReturnedPIDs) {
int
-psutil_pid_is_running(DWORD pid)
-{
+psutil_pid_is_running(DWORD pid) {
HANDLE hProcess;
DWORD exitCode;
// Special case for PID 0 System Idle Process
- if (pid == 0) {
+ if (pid == 0)
return 1;
- }
-
- if (pid < 0) {
+ if (pid < 0)
return 0;
- }
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, pid);
@@ -176,17 +168,14 @@ psutil_pid_is_running(DWORD pid)
int
-psutil_pid_in_proclist(DWORD pid)
-{
+psutil_pid_in_proclist(DWORD pid) {
DWORD *proclist = NULL;
DWORD numberOfReturnedPIDs;
DWORD i;
proclist = psutil_get_pids(&numberOfReturnedPIDs);
- if (NULL == proclist) {
+ if (proclist == NULL)
return -1;
- }
-
for (i = 0; i < numberOfReturnedPIDs; i++) {
if (pid == proclist[i]) {
free(proclist);
@@ -202,16 +191,14 @@ psutil_pid_in_proclist(DWORD pid)
// Check exit code from a process handle. Return FALSE on an error also
// XXX - not used anymore
int
-handlep_is_running(HANDLE hProcess)
-{
+handlep_is_running(HANDLE hProcess) {
DWORD dwCode;
- if (NULL == hProcess) {
+
+ if (NULL == hProcess)
return 0;
- }
if (GetExitCodeProcess(hProcess, &dwCode)) {
- if (dwCode == STILL_ACTIVE) {
+ if (dwCode == STILL_ACTIVE)
return 1;
- }
}
return 0;
}
@@ -222,8 +209,7 @@ handlep_is_running(HANDLE hProcess)
* with given pid or NULL on error.
*/
PyObject *
-psutil_get_arg_list(long pid)
-{
+psutil_get_cmdline(long pid) {
int nArgs, i;
LPWSTR *szArglist = NULL;
HANDLE hProcess = NULL;
@@ -231,15 +217,12 @@ psutil_get_arg_list(long pid)
PVOID rtlUserProcParamsAddress;
UNICODE_STRING commandLine;
WCHAR *commandLineContents = NULL;
- PyObject *arg = NULL;
- PyObject *arg_from_wchar = NULL;
- PyObject *argList = NULL;
+ PyObject *py_unicode = NULL;
+ PyObject *py_retlist = NULL;
hProcess = psutil_handle_from_pid(pid);
- if (hProcess == NULL) {
+ if (hProcess == NULL)
return NULL;
- }
-
pebAddress = psutil_get_peb_address(hProcess);
// get the address of ProcessParameters
@@ -290,48 +273,27 @@ psutil_get_arg_list(long pid)
// commandLine.Length is in bytes.
commandLineContents[(commandLine.Length / sizeof(WCHAR))] = '\0';
- // attempt tp parse the command line using Win32 API, fall back
+ // attempt to parse the command line using Win32 API, fall back
// on string cmdline version otherwise
szArglist = CommandLineToArgvW(commandLineContents, &nArgs);
- if (NULL == szArglist) {
- // failed to parse arglist
- // encode as a UTF8 Python string object from WCHAR string
- arg_from_wchar = PyUnicode_FromWideChar(commandLineContents,
- commandLine.Length / 2);
- if (arg_from_wchar == NULL)
- goto error;
-#if PY_MAJOR_VERSION >= 3
- argList = Py_BuildValue("N", PyUnicode_AsUTF8String(arg_from_wchar));
-#else
- argList = Py_BuildValue("N", PyUnicode_FromObject(arg_from_wchar));
-#endif
- if (!argList)
- goto error;
+ if (szArglist == NULL) {
+ PyErr_SetFromWindowsErr(0);
+ goto error;
}
else {
// arglist parsed as array of UNICODE_STRING, so convert each to
// Python string object and add to arg list
- argList = Py_BuildValue("[]");
- if (argList == NULL)
+ py_retlist = Py_BuildValue("[]");
+ if (py_retlist == NULL)
goto error;
for (i = 0; i < nArgs; i++) {
- arg_from_wchar = NULL;
- arg = NULL;
- arg_from_wchar = PyUnicode_FromWideChar(szArglist[i],
- wcslen(szArglist[i]));
- if (arg_from_wchar == NULL)
- goto error;
-#if PY_MAJOR_VERSION >= 3
- arg = PyUnicode_FromObject(arg_from_wchar);
-#else
- arg = PyUnicode_AsUTF8String(arg_from_wchar);
-#endif
- if (arg == NULL)
+ py_unicode = PyUnicode_FromWideChar(
+ szArglist[i], wcslen(szArglist[i]));
+ if (py_unicode == NULL)
goto error;
- Py_XDECREF(arg_from_wchar);
- if (PyList_Append(argList, arg))
+ if (PyList_Append(py_retlist, py_unicode))
goto error;
- Py_XDECREF(arg);
+ Py_XDECREF(py_unicode);
}
}
@@ -339,12 +301,11 @@ psutil_get_arg_list(long pid)
LocalFree(szArglist);
free(commandLineContents);
CloseHandle(hProcess);
- return argList;
+ return py_retlist;
error:
- Py_XDECREF(arg);
- Py_XDECREF(arg_from_wchar);
- Py_XDECREF(argList);
+ Py_XDECREF(py_unicode);
+ Py_XDECREF(py_retlist);
if (hProcess != NULL)
CloseHandle(hProcess);
if (commandLineContents != NULL)
@@ -367,13 +328,15 @@ const int STATUS_BUFFER_TOO_SMALL = 0xC0000023L;
/*
* Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure
- * fills the structure with process information.
+ * fills the structure with various process information by using
+ * NtQuerySystemInformation.
+ * We use this as a fallback when faster functions fail with access
+ * denied. This is slower because it iterates over all processes.
* On success return 1, else 0 with Python exception already set.
*/
int
psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
- PVOID *retBuffer)
-{
+ PVOID *retBuffer) {
static ULONG initialBufferSize = 0x4000;
NTSTATUS status;
PVOID buffer;
@@ -419,9 +382,8 @@ psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
goto error;
}
- if (bufferSize <= 0x20000) {
+ if (bufferSize <= 0x20000)
initialBufferSize = bufferSize;
- }
process = PH_FIRST_PROCESS(buffer);
do {
diff --git a/psutil/arch/windows/process_info.h b/psutil/arch/windows/process_info.h
index 9544f5d6..c2699192 100644
--- a/psutil/arch/windows/process_info.h
+++ b/psutil/arch/windows/process_info.h
@@ -4,8 +4,13 @@
* found in the LICENSE file.
*/
+#if !defined(__PROCESS_INFO_H)
+#define __PROCESS_INFO_H
+
#include <Python.h>
#include <windows.h>
+#include "security.h"
+#include "ntextapi.h"
DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs);
HANDLE psutil_handle_from_pid(DWORD pid);
@@ -14,4 +19,8 @@ int psutil_handlep_is_running(HANDLE hProcess);
int psutil_pid_in_proclist(DWORD pid);
int psutil_pid_is_running(DWORD pid);
PVOID psutil_get_peb_address(HANDLE ProcessHandle);
-PyObject* psutil_get_arg_list(long pid);
+PyObject* psutil_get_cmdline(long pid);
+int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
+ PVOID *retBuffer);
+
+#endif
diff --git a/psutil/arch/windows/security.c b/psutil/arch/windows/security.c
index a837dfe4..331d9622 100644
--- a/psutil/arch/windows/security.c
+++ b/psutil/arch/windows/security.c
@@ -18,9 +18,8 @@ HANDLE
psutil_token_from_handle(HANDLE hProcess) {
HANDLE hToken = NULL;
- if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
+ if (! OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
return PyErr_SetFromWindowsErr(0);
- }
return hToken;
}
@@ -50,10 +49,8 @@ psutil_has_system_privilege(HANDLE hProcess) {
TOKEN_PRIVILEGES *tp = NULL;
HANDLE hToken = psutil_token_from_handle(hProcess);
- if (NULL == hToken) {
+ if (NULL == hToken)
return -1;
- }
-
// call GetTokenInformation first to get the buffer size
if (! GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize)) {
dwRetval = GetLastError();
@@ -111,8 +108,7 @@ psutil_has_system_privilege(HANDLE hProcess) {
BOOL
-psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege)
-{
+psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) {
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
@@ -140,14 +136,11 @@ psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege)
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
- if (bEnablePrivilege) {
+ if (bEnablePrivilege)
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
- }
-
- else {
+ else
tpPrevious.Privileges[0].Attributes ^=
(SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes);
- }
AdjustTokenPrivileges(
hToken,
@@ -165,8 +158,7 @@ psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege)
int
-psutil_set_se_debug()
-{
+psutil_set_se_debug() {
HANDLE hToken;
if (! OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
@@ -204,8 +196,7 @@ psutil_set_se_debug()
int
-psutil_unset_se_debug()
-{
+psutil_unset_se_debug() {
HANDLE hToken;
if (! OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
@@ -213,15 +204,12 @@ psutil_unset_se_debug()
&hToken)
) {
if (GetLastError() == ERROR_NO_TOKEN) {
- if (! ImpersonateSelf(SecurityImpersonation)) {
+ if (! ImpersonateSelf(SecurityImpersonation))
return 0;
- }
-
if (!OpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
- &hToken)
- )
+ &hToken))
{
return 0;
}
@@ -229,9 +217,8 @@ psutil_unset_se_debug()
}
// now disable SeDebug
- if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE)) {
+ if (! psutil_set_privilege(hToken, SE_DEBUG_NAME, FALSE))
return 0;
- }
CloseHandle(hToken);
return 1;
diff --git a/setup.py b/setup.py
index 2cbf5bee..b575db96 100644
--- a/setup.py
+++ b/setup.py
@@ -9,8 +9,12 @@ running processes and system utilization (CPU, memory, disks, network)
in Python.
"""
+import atexit
+import contextlib
+import io
import os
import sys
+import tempfile
try:
from setuptools import setup, Extension
except ImportError:
@@ -40,16 +44,33 @@ def get_description():
return f.read()
+@contextlib.contextmanager
+def silenced_output(stream_name):
+ class DummyFile(io.BytesIO):
+ def write(self, s):
+ pass
+
+ orig = getattr(sys, stream_name)
+ try:
+ setattr(sys, stream_name, DummyFile())
+ yield
+ finally:
+ setattr(sys, stream_name, orig)
+
+
VERSION = get_version()
VERSION_MACRO = ('PSUTIL_VERSION', int(VERSION.replace('.', '')))
# POSIX
if os.name == 'posix':
+ libraries = []
+ if sys.platform.startswith("sunos"):
+ libraries.append('socket')
posix_extension = Extension(
- '_psutil_posix',
+ 'psutil._psutil_posix',
sources=['psutil/_psutil_posix.c'],
- )
+ libraries=libraries)
# Windows
if sys.platform.startswith("win32"):
@@ -57,14 +78,15 @@ if sys.platform.startswith("win32"):
maj, min = sys.getwindowsversion()[0:2]
return '0x0%s' % ((maj * 100) + min)
- extensions = [Extension(
- '_psutil_windows',
+ ext = Extension(
+ 'psutil._psutil_windows',
sources=[
'psutil/_psutil_windows.c',
'psutil/_psutil_common.c',
'psutil/arch/windows/process_info.c',
'psutil/arch/windows/process_handles.c',
'psutil/arch/windows/security.c',
+ 'psutil/arch/windows/inet_ntop.c',
],
define_macros=[
VERSION_MACRO,
@@ -72,20 +94,22 @@ if sys.platform.startswith("win32"):
# http://www.mingw.org/wiki/Use_more_recent_defined_functions
('_WIN32_WINNT', get_winver()),
('_AVAIL_WINVER_', get_winver()),
+ ('_CRT_SECURE_NO_WARNINGS', None),
# see: https://github.com/giampaolo/psutil/issues/348
('PSAPI_VERSION', 1),
],
libraries=[
- "psapi", "kernel32", "advapi32", "shell32", "netapi32", "iphlpapi",
- "wtsapi32",
+ "psapi", "kernel32", "advapi32", "shell32", "netapi32",
+ "iphlpapi", "wtsapi32", "ws2_32",
],
# extra_compile_args=["/Z7"],
# extra_link_args=["/DEBUG"]
- )]
+ )
+ extensions = [ext]
# OS X
elif sys.platform.startswith("darwin"):
- extensions = [Extension(
- '_psutil_osx',
+ ext = Extension(
+ 'psutil._psutil_osx',
sources=[
'psutil/_psutil_osx.c',
'psutil/_psutil_common.c',
@@ -94,40 +118,64 @@ elif sys.platform.startswith("darwin"):
define_macros=[VERSION_MACRO],
extra_link_args=[
'-framework', 'CoreFoundation', '-framework', 'IOKit'
- ],
- ),
- posix_extension,
- ]
+ ])
+ extensions = [ext, posix_extension]
# FreeBSD
elif sys.platform.startswith("freebsd"):
- extensions = [Extension(
- '_psutil_bsd',
+ ext = Extension(
+ 'psutil._psutil_bsd',
sources=[
'psutil/_psutil_bsd.c',
'psutil/_psutil_common.c',
- 'psutil/arch/bsd/process_info.c'
- ],
+ 'psutil/arch/bsd/process_info.c'],
define_macros=[VERSION_MACRO],
- libraries=["devstat"]),
- posix_extension,
- ]
+ libraries=["devstat"])
+ extensions = [ext, posix_extension]
# Linux
elif sys.platform.startswith("linux"):
- extensions = [Extension(
- '_psutil_linux',
+ def get_ethtool_macro():
+ # see: https://github.com/giampaolo/psutil/issues/659
+ from distutils.unixccompiler import UnixCCompiler
+ from distutils.errors import CompileError
+
+ with tempfile.NamedTemporaryFile(
+ suffix='.c', delete=False, mode="wt") as f:
+ f.write("#include <linux/ethtool.h>")
+
+ @atexit.register
+ def on_exit():
+ try:
+ os.remove(f.name)
+ except OSError:
+ pass
+
+ compiler = UnixCCompiler()
+ try:
+ with silenced_output('stderr'):
+ with silenced_output('stdout'):
+ compiler.compile([f.name])
+ except CompileError:
+ return ("PSUTIL_ETHTOOL_MISSING_TYPES", 1)
+ else:
+ return None
+
+ ETHTOOL_MACRO = get_ethtool_macro()
+ macros = [VERSION_MACRO]
+ if ETHTOOL_MACRO is not None:
+ macros.append(ETHTOOL_MACRO)
+ ext = Extension(
+ 'psutil._psutil_linux',
sources=['psutil/_psutil_linux.c'],
- define_macros=[VERSION_MACRO]),
- posix_extension,
- ]
+ define_macros=macros)
+ extensions = [ext, posix_extension]
# Solaris
elif sys.platform.lower().startswith('sunos'):
- extensions = [Extension(
- '_psutil_sunos',
+ ext = Extension(
+ 'psutil._psutil_sunos',
sources=['psutil/_psutil_sunos.c'],
define_macros=[VERSION_MACRO],
- libraries=['kstat', 'nsl'],),
- posix_extension,
- ]
+ libraries=['kstat', 'nsl', 'socket'])
+ extensions = [ext, posix_extension]
else:
sys.exit('platform %s is not supported' % sys.platform)
diff --git a/test/README b/test/README
deleted file mode 100644
index 801f93d1..00000000
--- a/test/README
+++ /dev/null
@@ -1,15 +0,0 @@
-- The recommended way to run tests (also on Windows) is to cd into parent
- directory and run:
-
- make test
-
-- If you're on Python < 2.7 unittest2 module must be installed first:
- https://pypi.python.org/pypi/unittest2
-
-- The main test script is test_psutil.py, which also imports platform-specific
- _*.py scripts (which should be ignored).
-
-- test_memory_leaks.py looks for memory leaks into C extension modules and must
- be run separately with:
-
- make memtest
diff --git a/test/README.rst b/test/README.rst
new file mode 100644
index 00000000..3f2a468e
--- /dev/null
+++ b/test/README.rst
@@ -0,0 +1,21 @@
+- The recommended way to run tests (also on Windows) is to cd into parent
+ directory and run ``make test``
+
+- Dependencies for running tests:
+ - python 2.6: ipaddress, mock, unittest2
+ - python 2.7: ipaddress, mock
+ - python 3.2: ipaddress, mock
+ - python 3.3: ipaddress
+ - python >= 3.4: no deps required
+
+- The main test script is ``test_psutil.py``, which also imports platform-specific
+ ``_*.py`` scripts (which should be ignored).
+
+- ``test_memory_leaks.py`` looks for memory leaks into C extension modules and must
+ be run separately with ``make test-memleaks``.
+
+- To run tests on all supported Python version install tox (pip install tox)
+ then run ``tox``.
+
+- Every time a commit is pushed tests are automatically run on Travis:
+ https://travis-ci.org/giampaolo/psutil/
diff --git a/test/__init__.py b/test/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/test/__init__.py
+++ /dev/null
diff --git a/test/_bsd.py b/test/_bsd.py
index 59be49bf..da08383a 100644
--- a/test/_bsd.py
+++ b/test/_bsd.py
@@ -8,15 +8,15 @@
"""BSD specific tests. These are implicitly run by test_psutil.py."""
+import os
import subprocess
-import time
import sys
-import os
+import time
import psutil
from psutil._compat import PY3
-from test_psutil import (TOLERANCE, sh, get_test_subprocess, which,
+from test_psutil import (MEMORY_TOLERANCE, BSD, sh, get_test_subprocess, which,
retry_before_failing, reap_children, unittest)
@@ -50,6 +50,7 @@ def muse(field):
return int(line.split()[1])
+@unittest.skipUnless(BSD, "not a BSD system")
class BSDSpecificTestCase(unittest.TestCase):
@classmethod
@@ -106,6 +107,7 @@ class BSDSpecificTestCase(unittest.TestCase):
if abs(usage.used - used) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % (usage.used, used))
+ @retry_before_failing()
def test_memory_maps(self):
out = sh('procstat -v %s' % self.pid)
maps = psutil.Process(self.pid).memory_maps(grouped=False)
@@ -120,6 +122,29 @@ class BSDSpecificTestCase(unittest.TestCase):
if not map.path.startswith('['):
self.assertEqual(fields[10], map.path)
+ def test_exe(self):
+ out = sh('procstat -b %s' % self.pid)
+ self.assertEqual(psutil.Process(self.pid).exe(),
+ out.split('\n')[1].split()[-1])
+
+ def test_cmdline(self):
+ out = sh('procstat -c %s' % self.pid)
+ self.assertEqual(' '.join(psutil.Process(self.pid).cmdline()),
+ ' '.join(out.split('\n')[1].split()[2:]))
+
+ def test_uids_gids(self):
+ out = sh('procstat -s %s' % self.pid)
+ euid, ruid, suid, egid, rgid, sgid = out.split('\n')[1].split()[2:8]
+ p = psutil.Process(self.pid)
+ uids = p.uids()
+ gids = p.gids()
+ self.assertEqual(uids.real, int(ruid))
+ self.assertEqual(uids.effective, int(euid))
+ self.assertEqual(uids.saved, int(suid))
+ self.assertEqual(gids.real, int(rgid))
+ self.assertEqual(gids.effective, int(egid))
+ self.assertEqual(gids.saved, int(sgid))
+
# --- virtual_memory(); tests against sysctl
def test_vmem_total(self):
@@ -130,37 +155,41 @@ class BSDSpecificTestCase(unittest.TestCase):
def test_vmem_active(self):
syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE
self.assertAlmostEqual(psutil.virtual_memory().active, syst,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_inactive(self):
syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE
self.assertAlmostEqual(psutil.virtual_memory().inactive, syst,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_wired(self):
syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE
self.assertAlmostEqual(psutil.virtual_memory().wired, syst,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_cached(self):
syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE
self.assertAlmostEqual(psutil.virtual_memory().cached, syst,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_free(self):
syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE
self.assertAlmostEqual(psutil.virtual_memory().free, syst,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_buffers(self):
syst = sysctl("vfs.bufspace")
self.assertAlmostEqual(psutil.virtual_memory().buffers, syst,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
+
+ def test_cpu_count_logical(self):
+ syst = sysctl("hw.ncpu")
+ self.assertEqual(psutil.cpu_count(logical=True), syst)
# --- virtual_memory(); tests against muse
@@ -174,50 +203,50 @@ class BSDSpecificTestCase(unittest.TestCase):
def test_active(self):
num = muse('Active')
self.assertAlmostEqual(psutil.virtual_memory().active, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
@retry_before_failing()
def test_inactive(self):
num = muse('Inactive')
self.assertAlmostEqual(psutil.virtual_memory().inactive, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
@retry_before_failing()
def test_wired(self):
num = muse('Wired')
self.assertAlmostEqual(psutil.virtual_memory().wired, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
@retry_before_failing()
def test_cached(self):
num = muse('Cache')
self.assertAlmostEqual(psutil.virtual_memory().cached, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
@retry_before_failing()
def test_free(self):
num = muse('Free')
self.assertAlmostEqual(psutil.virtual_memory().free, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@unittest.skipUnless(MUSE_AVAILABLE, "muse cmdline tool is not available")
@retry_before_failing()
def test_buffers(self):
num = muse('Buffer')
self.assertAlmostEqual(psutil.virtual_memory().buffers, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
-def test_main():
+def main():
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase))
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
return result.wasSuccessful()
if __name__ == '__main__':
- if not test_main():
+ if not main():
sys.exit(1)
diff --git a/test/_linux.py b/test/_linux.py
index 77f6da27..c9e04a53 100644
--- a/test/_linux.py
+++ b/test/_linux.py
@@ -7,18 +7,70 @@
"""Linux specific tests. These are implicitly run by test_psutil.py."""
from __future__ import division
+import contextlib
+import errno
+import fcntl
+import io
import os
+import pprint
import re
+import socket
+import struct
import sys
+import tempfile
import time
+import warnings
-from test_psutil import POSIX, TOLERANCE, TRAVIS
+try:
+ from unittest import mock # py3
+except ImportError:
+ import mock # requires "pip install mock"
+
+from test_psutil import POSIX, MEMORY_TOLERANCE, TRAVIS, LINUX
from test_psutil import (skip_on_not_implemented, sh, get_test_subprocess,
- retry_before_failing, get_kernel_version, unittest)
+ retry_before_failing, get_kernel_version, unittest,
+ which, call_until)
import psutil
+import psutil._pslinux
+from psutil._compat import PY3, u
+
+
+SIOCGIFADDR = 0x8915
+SIOCGIFCONF = 0x8912
+SIOCGIFHWADDR = 0x8927
+
+
+def get_ipv4_address(ifname):
+ ifname = ifname[:15]
+ if PY3:
+ ifname = bytes(ifname, 'ascii')
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ with contextlib.closing(s):
+ return socket.inet_ntoa(
+ fcntl.ioctl(s.fileno(),
+ SIOCGIFADDR,
+ struct.pack('256s', ifname))[20:24])
+
+
+def get_mac_address(ifname):
+ ifname = ifname[:15]
+ if PY3:
+ ifname = bytes(ifname, 'ascii')
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ with contextlib.closing(s):
+ info = fcntl.ioctl(
+ s.fileno(), SIOCGIFHWADDR, struct.pack('256s', ifname))
+ if PY3:
+ def ord(x):
+ return x
+ else:
+ import __builtin__
+ ord = __builtin__.ord
+ return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
+@unittest.skipUnless(LINUX, "not a Linux system")
class LinuxSpecificTestCase(unittest.TestCase):
@unittest.skipIf(
@@ -79,28 +131,28 @@ class LinuxSpecificTestCase(unittest.TestCase):
lines = sh('free').split('\n')[1:]
used = int(lines[0].split()[2]) * 1024
self.assertAlmostEqual(used, psutil.virtual_memory().used,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_free(self):
lines = sh('free').split('\n')[1:]
free = int(lines[0].split()[3]) * 1024
self.assertAlmostEqual(free, psutil.virtual_memory().free,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_buffers(self):
lines = sh('free').split('\n')[1:]
buffers = int(lines[0].split()[5]) * 1024
self.assertAlmostEqual(buffers, psutil.virtual_memory().buffers,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_cached(self):
lines = sh('free').split('\n')[1:]
cached = int(lines[0].split()[6]) * 1024
self.assertAlmostEqual(cached, psutil.virtual_memory().cached,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
def test_swapmem_total(self):
lines = sh('free').split('\n')[1:]
@@ -112,14 +164,14 @@ class LinuxSpecificTestCase(unittest.TestCase):
lines = sh('free').split('\n')[1:]
used = int(lines[2].split()[2]) * 1024
self.assertAlmostEqual(used, psutil.swap_memory().used,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_swapmem_free(self):
lines = sh('free').split('\n')[1:]
free = int(lines[2].split()[3]) * 1024
self.assertAlmostEqual(free, psutil.swap_memory().free,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@unittest.skipIf(TRAVIS, "unknown failure on travis")
def test_cpu_times(self):
@@ -139,6 +191,241 @@ class LinuxSpecificTestCase(unittest.TestCase):
else:
self.assertNotIn('guest_nice', fields)
+ def test_net_if_addrs_ips(self):
+ for name, addrs in psutil.net_if_addrs().items():
+ for addr in addrs:
+ if addr.family == psutil.AF_LINK:
+ self.assertEqual(addr.address, get_mac_address(name))
+ elif addr.family == socket.AF_INET:
+ self.assertEqual(addr.address, get_ipv4_address(name))
+ # TODO: test for AF_INET6 family
+
+ @unittest.skipUnless(which('ip'), "'ip' utility not available")
+ @unittest.skipIf(TRAVIS, "skipped on Travis")
+ def test_net_if_names(self):
+ out = sh("ip addr").strip()
+ nics = psutil.net_if_addrs()
+ found = 0
+ for line in out.split('\n'):
+ line = line.strip()
+ if re.search("^\d+:", line):
+ found += 1
+ name = line.split(':')[1].strip()
+ self.assertIn(name, nics.keys())
+ self.assertEqual(len(nics), found, msg="%s\n---\n%s" % (
+ pprint.pformat(nics), out))
+
+ @unittest.skipUnless(which("nproc"), "nproc utility not available")
+ def test_cpu_count_logical_w_nproc(self):
+ num = int(sh("nproc --all"))
+ self.assertEqual(psutil.cpu_count(logical=True), num)
+
+ @unittest.skipUnless(which("lscpu"), "lscpu utility not available")
+ def test_cpu_count_logical_w_lscpu(self):
+ out = sh("lscpu -p")
+ num = len([x for x in out.split('\n') if not x.startswith('#')])
+ self.assertEqual(psutil.cpu_count(logical=True), num)
+
+ # --- mocked tests
+
+ def test_virtual_memory_mocked_warnings(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ with warnings.catch_warnings(record=True) as ws:
+ warnings.simplefilter("always")
+ ret = psutil._pslinux.virtual_memory()
+ assert m.called
+ self.assertEqual(len(ws), 1)
+ w = ws[0]
+ self.assertTrue(w.filename.endswith('psutil/_pslinux.py'))
+ self.assertIn(
+ "'cached', 'active' and 'inactive' memory stats couldn't "
+ "be determined", str(w.message))
+ self.assertEqual(ret.cached, 0)
+ self.assertEqual(ret.active, 0)
+ self.assertEqual(ret.inactive, 0)
+
+ def test_swap_memory_mocked_warnings(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ with warnings.catch_warnings(record=True) as ws:
+ warnings.simplefilter("always")
+ ret = psutil._pslinux.swap_memory()
+ assert m.called
+ self.assertEqual(len(ws), 1)
+ w = ws[0]
+ self.assertTrue(w.filename.endswith('psutil/_pslinux.py'))
+ self.assertIn(
+ "'sin' and 'sout' swap memory stats couldn't "
+ "be determined", str(w.message))
+ self.assertEqual(ret.sin, 0)
+ self.assertEqual(ret.sout, 0)
+
+ def test_cpu_count_logical_mocked(self):
+ import psutil._pslinux
+ original = psutil._pslinux.cpu_count_logical()
+ # Here we want to mock os.sysconf("SC_NPROCESSORS_ONLN") in
+ # order to cause the parsing of /proc/cpuinfo and /proc/stat.
+ with mock.patch(
+ 'psutil._pslinux.os.sysconf', side_effect=ValueError) as m:
+ self.assertEqual(psutil._pslinux.cpu_count_logical(), original)
+ assert m.called
+
+ # Let's have open() return emtpy data and make sure None is
+ # returned ('cause we mimick os.cpu_count()).
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertIsNone(psutil._pslinux.cpu_count_logical())
+ self.assertEqual(m.call_count, 2)
+ # /proc/stat should be the last one
+ self.assertEqual(m.call_args[0][0], '/proc/stat')
+
+ # Let's push this a bit further and make sure /proc/cpuinfo
+ # parsing works as expected.
+ with open('/proc/cpuinfo', 'rb') as f:
+ cpuinfo_data = f.read()
+ fake_file = io.BytesIO(cpuinfo_data)
+ with mock.patch('psutil._pslinux.open',
+ return_value=fake_file, create=True) as m:
+ self.assertEqual(psutil._pslinux.cpu_count_logical(), original)
+
+ def test_cpu_count_physical_mocked(self):
+ # Have open() return emtpy data and make sure None is returned
+ # ('cause we want to mimick os.cpu_count())
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertIsNone(psutil._pslinux.cpu_count_physical())
+ assert m.called
+
+ def test_proc_open_files_file_gone(self):
+ # simulates a file which gets deleted during open_files()
+ # execution
+ p = psutil.Process()
+ files = p.open_files()
+ with tempfile.NamedTemporaryFile():
+ # give the kernel some time to see the new file
+ call_until(p.open_files, "len(ret) != %i" % len(files))
+ with mock.patch('psutil._pslinux.os.readlink',
+ side_effect=OSError(errno.ENOENT, "")) as m:
+ files = p.open_files()
+ assert not files
+ assert m.called
+ # also simulate the case where os.readlink() returns EINVAL
+ # in which case psutil is supposed to 'continue'
+ with mock.patch('psutil._pslinux.os.readlink',
+ side_effect=OSError(errno.EINVAL, "")) as m:
+ self.assertEqual(p.open_files(), [])
+ assert m.called
+
+ def test_proc_terminal_mocked(self):
+ with mock.patch('psutil._pslinux._psposix._get_terminal_map',
+ return_value={}) as m:
+ self.assertIsNone(psutil._pslinux.Process(os.getpid()).terminal())
+ assert m.called
+
+ def test_proc_num_ctx_switches_mocked(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertRaises(
+ NotImplementedError,
+ psutil._pslinux.Process(os.getpid()).num_ctx_switches)
+ assert m.called
+
+ def test_proc_num_threads_mocked(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertRaises(
+ NotImplementedError,
+ psutil._pslinux.Process(os.getpid()).num_threads)
+ assert m.called
+
+ def test_proc_ppid_mocked(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertRaises(
+ NotImplementedError,
+ psutil._pslinux.Process(os.getpid()).ppid)
+ assert m.called
+
+ def test_proc_uids_mocked(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertRaises(
+ NotImplementedError,
+ psutil._pslinux.Process(os.getpid()).uids)
+ assert m.called
+
+ def test_proc_gids_mocked(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertRaises(
+ NotImplementedError,
+ psutil._pslinux.Process(os.getpid()).gids)
+ assert m.called
+
+ def test_proc_cmdline_mocked(self):
+ # see: https://github.com/giampaolo/psutil/issues/639
+ p = psutil.Process()
+ fake_file = io.StringIO(u('foo\x00bar\x00'))
+ with mock.patch('psutil._pslinux.open',
+ return_value=fake_file, create=True) as m:
+ p.cmdline() == ['foo', 'bar']
+ assert m.called
+ fake_file = io.StringIO(u('foo\x00bar\x00\x00'))
+ with mock.patch('psutil._pslinux.open',
+ return_value=fake_file, create=True) as m:
+ p.cmdline() == ['foo', 'bar', '']
+ assert m.called
+
+ def test_proc_io_counters_mocked(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertRaises(
+ NotImplementedError,
+ psutil._pslinux.Process(os.getpid()).io_counters)
+ assert m.called
+
+ def test_boot_time_mocked(self):
+ with mock.patch('psutil._pslinux.open', create=True) as m:
+ self.assertRaises(
+ RuntimeError,
+ psutil._pslinux.boot_time)
+ assert m.called
+
+ def test_users_mocked(self):
+ # Make sure ':0' and ':0.0' (returned by C ext) are converted
+ # to 'localhost'.
+ with mock.patch('psutil._pslinux.cext.users',
+ return_value=[('giampaolo', 'pts/2', ':0',
+ 1436573184.0, True)]) as m:
+ self.assertEqual(psutil.users()[0].host, 'localhost')
+ assert m.called
+ with mock.patch('psutil._pslinux.cext.users',
+ return_value=[('giampaolo', 'pts/2', ':0.0',
+ 1436573184.0, True)]) as m:
+ self.assertEqual(psutil.users()[0].host, 'localhost')
+ assert m.called
+ # ...otherwise it should be returned as-is
+ with mock.patch('psutil._pslinux.cext.users',
+ return_value=[('giampaolo', 'pts/2', 'foo',
+ 1436573184.0, True)]) as m:
+ self.assertEqual(psutil.users()[0].host, 'foo')
+ assert m.called
+
+ def test_disk_partitions_mocked(self):
+ # Test that ZFS partitions are returned.
+ with open("/proc/filesystems", "r") as f:
+ data = f.read()
+ if 'zfs' in data:
+ for part in psutil.disk_partitions():
+ if part.fstype == 'zfs':
+ break
+ else:
+ self.fail("couldn't find any ZFS partition")
+ else:
+ # No ZFS partitions on this system. Let's fake one.
+ fake_file = io.StringIO(u("nodev\tzfs\n"))
+ with mock.patch('psutil._pslinux.open',
+ return_value=fake_file, create=True) as m1:
+ with mock.patch(
+ 'psutil._pslinux.cext.disk_partitions',
+ return_value=[('/dev/sdb3', '/', 'zfs', 'rw')]) as m2:
+ ret = psutil.disk_partitions()
+ assert m1.called
+ assert m2.called
+ assert ret
+ self.assertEqual(ret[0].fstype, 'zfs')
+
# --- tests for specific kernel versions
@unittest.skipUnless(
@@ -175,12 +462,12 @@ class LinuxSpecificTestCase(unittest.TestCase):
self.assertTrue(hasattr(psutil, "RLIMIT_SIGPENDING"))
-def test_main():
+def main():
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(LinuxSpecificTestCase))
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
return result.wasSuccessful()
if __name__ == '__main__':
- if not test_main():
+ if not main():
sys.exit(1)
diff --git a/test/_osx.py b/test/_osx.py
index 784f00e0..2375a483 100644
--- a/test/_osx.py
+++ b/test/_osx.py
@@ -15,8 +15,9 @@ import time
import psutil
from psutil._compat import PY3
-from test_psutil import (TOLERANCE, sh, get_test_subprocess, reap_children,
- retry_before_failing, unittest)
+from test_psutil import (MEMORY_TOLERANCE, OSX, sh, get_test_subprocess,
+ reap_children, retry_before_failing, unittest,
+ TRAVIS)
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
@@ -47,6 +48,34 @@ def vm_stat(field):
return int(re.search('\d+', line).group(0)) * PAGESIZE
+# http://code.activestate.com/recipes/578019/
+def human2bytes(s):
+ SYMBOLS = {
+ 'customary': ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'),
+ }
+ init = s
+ num = ""
+ while s and s[0:1].isdigit() or s[0:1] == '.':
+ num += s[0]
+ s = s[1:]
+ num = float(num)
+ letter = s.strip()
+ for name, sset in SYMBOLS.items():
+ if letter in sset:
+ break
+ else:
+ if letter == 'k':
+ sset = SYMBOLS['customary']
+ letter = letter.upper()
+ else:
+ raise ValueError("can't interpret %r" % init)
+ prefix = {sset[0]: 1}
+ for i, s in enumerate(sset[1:]):
+ prefix[s] = 1 << (i+1)*10
+ return int(num * prefix[letter])
+
+
+@unittest.skipUnless(OSX, "not an OSX system")
class OSXSpecificTestCase(unittest.TestCase):
@classmethod
@@ -96,35 +125,44 @@ class OSXSpecificTestCase(unittest.TestCase):
if abs(usage.used - used) > 10 * 1024 * 1024:
self.fail("psutil=%s, df=%s" % usage.used, used)
+ def test_cpu_count_logical(self):
+ num = sysctl("sysctl hw.logicalcpu")
+ self.assertEqual(num, psutil.cpu_count(logical=True))
+
+ def test_cpu_count_physical(self):
+ num = sysctl("sysctl hw.physicalcpu")
+ self.assertEqual(num, psutil.cpu_count(logical=False))
+
# --- virtual mem
def test_vmem_total(self):
sysctl_hwphymem = sysctl('sysctl hw.memsize')
self.assertEqual(sysctl_hwphymem, psutil.virtual_memory().total)
+ @unittest.skipIf(TRAVIS, "")
@retry_before_failing()
def test_vmem_free(self):
num = vm_stat("free")
self.assertAlmostEqual(psutil.virtual_memory().free, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_active(self):
num = vm_stat("active")
self.assertAlmostEqual(psutil.virtual_memory().active, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_inactive(self):
num = vm_stat("inactive")
self.assertAlmostEqual(psutil.virtual_memory().inactive, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
@retry_before_failing()
def test_vmem_wired(self):
num = vm_stat("wired")
self.assertAlmostEqual(psutil.virtual_memory().wired, num,
- delta=TOLERANCE)
+ delta=MEMORY_TOLERANCE)
# --- swap mem
@@ -137,23 +175,22 @@ class OSXSpecificTestCase(unittest.TestCase):
self.assertEqual(psutil.swap_memory().sout, num)
def test_swapmem_total(self):
- tot1 = psutil.swap_memory().total
- tot2 = 0
- # OSX uses multiple cache files:
- # http://en.wikipedia.org/wiki/Paging#OS_X
- for name in os.listdir("/var/vm/"):
- file = os.path.join("/var/vm", name)
- if os.path.isfile(file):
- tot2 += os.path.getsize(file)
- self.assertEqual(tot1, tot2)
-
-
-def test_main():
+ out = sh('sysctl vm.swapusage')
+ out = out.replace('vm.swapusage: ', '')
+ total, used, free = re.findall('\d+.\d+\w', out)
+ psutil_smem = psutil.swap_memory()
+ self.assertEqual(psutil_smem.total, human2bytes(total))
+ self.assertEqual(psutil_smem.used, human2bytes(used))
+ self.assertEqual(psutil_smem.free, human2bytes(free))
+
+
+def main():
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(OSXSpecificTestCase))
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
return result.wasSuccessful()
+
if __name__ == '__main__':
- if not test_main():
+ if not main():
sys.exit(1)
diff --git a/test/_posix.py b/test/_posix.py
index 8cbd629a..e6c56aac 100644
--- a/test/_posix.py
+++ b/test/_posix.py
@@ -14,8 +14,8 @@ import time
import psutil
-from psutil._compat import PY3
-from test_psutil import LINUX, SUNOS, OSX, BSD, PYTHON
+from psutil._compat import PY3, callable
+from test_psutil import LINUX, SUNOS, OSX, BSD, PYTHON, POSIX, TRAVIS
from test_psutil import (get_test_subprocess, skip_on_access_denied,
retry_before_failing, reap_children, sh, unittest,
get_kernel_version, wait_for_pid)
@@ -42,6 +42,7 @@ def ps(cmd):
return output
+@unittest.skipUnless(POSIX, "not a POSIX system")
class PosixSpecificTestCase(unittest.TestCase):
"""Compare psutil results against 'ps' command line utility."""
@@ -111,11 +112,14 @@ class PosixSpecificTestCase(unittest.TestCase):
def test_process_create_time(self):
time_ps = ps("ps --no-headers -o start -p %s" % self.pid).split(' ')[0]
time_psutil = psutil.Process(self.pid).create_time()
- if SUNOS:
- time_psutil = round(time_psutil)
time_psutil_tstamp = datetime.datetime.fromtimestamp(
time_psutil).strftime("%H:%M:%S")
- self.assertEqual(time_ps, time_psutil_tstamp)
+ # sometimes ps shows the time rounded up instead of down, so we check
+ # for both possible values
+ round_time_psutil = round(time_psutil)
+ round_time_psutil_tstamp = datetime.datetime.fromtimestamp(
+ round_time_psutil).strftime("%H:%M:%S")
+ self.assertIn(time_ps, [time_psutil_tstamp, round_time_psutil_tstamp])
def test_process_exe(self):
ps_pathname = ps("ps --no-headers -o command -p %s" %
@@ -173,9 +177,10 @@ class PosixSpecificTestCase(unittest.TestCase):
[x for x in pids_ps if x not in pids_psutil]
self.fail("difference: " + str(difference))
- # for some reason ifconfig -a does not report differente interfaces
- # psutil does
+ # for some reason ifconfig -a does not report all interfaces
+ # returned by psutil
@unittest.skipIf(SUNOS, "test not reliable on SUNOS")
+ @unittest.skipIf(TRAVIS, "test not reliable on Travis")
def test_nic_names(self):
p = subprocess.Popen("ifconfig -a", shell=1, stdout=subprocess.PIPE)
output = p.communicate()[0].strip()
@@ -186,7 +191,9 @@ class PosixSpecificTestCase(unittest.TestCase):
if line.startswith(nic):
break
else:
- self.fail("couldn't find %s nic in 'ifconfig -a' output" % nic)
+ self.fail(
+ "couldn't find %s nic in 'ifconfig -a' output\n%s" % (
+ nic, output))
@retry_before_failing()
def test_users(self):
@@ -208,8 +215,6 @@ class PosixSpecificTestCase(unittest.TestCase):
if attr is not None and callable(attr):
if name == 'rlimit':
args = (psutil.RLIMIT_NOFILE,)
- elif name == 'set_rlimit':
- args = (psutil.RLIMIT_NOFILE, (5, 5))
attr(*args)
else:
attr
@@ -220,11 +225,10 @@ class PosixSpecificTestCase(unittest.TestCase):
'send_signal', 'wait', 'children', 'as_dict']
if LINUX and get_kernel_version() < (2, 6, 36):
ignored_names.append('rlimit')
+ if LINUX and get_kernel_version() < (2, 6, 23):
+ ignored_names.append('num_ctx_switches')
for name in dir(psutil.Process):
- if (name.startswith('_')
- or name.startswith('set_')
- or name.startswith('get') # deprecated APIs
- or name in ignored_names):
+ if (name.startswith('_') or name in ignored_names):
continue
else:
try:
@@ -243,12 +247,12 @@ class PosixSpecificTestCase(unittest.TestCase):
self.fail('\n' + '\n'.join(failures))
-def test_main():
+def main():
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(PosixSpecificTestCase))
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
return result.wasSuccessful()
if __name__ == '__main__':
- if not test_main():
+ if not main():
sys.exit(1)
diff --git a/test/_sunos.py b/test/_sunos.py
index 7fdc50b6..3d54ccd8 100644
--- a/test/_sunos.py
+++ b/test/_sunos.py
@@ -7,15 +7,17 @@
"""Sun OS specific tests. These are implicitly run by test_psutil.py."""
import sys
+import os
-from test_psutil import sh, unittest
+from test_psutil import SUNOS, sh, unittest
import psutil
+@unittest.skipUnless(SUNOS, "not a SunOS system")
class SunOSSpecificTestCase(unittest.TestCase):
def test_swap_memory(self):
- out = sh('swap -l -k')
+ out = sh('env PATH=/usr/sbin:/sbin:%s swap -l -k' % os.environ['PATH'])
lines = out.strip().split('\n')[1:]
if not lines:
raise ValueError('no swap device(s) configured')
@@ -35,12 +37,12 @@ class SunOSSpecificTestCase(unittest.TestCase):
self.assertEqual(psutil_swap.free, free)
-def test_main():
+def main():
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(SunOSSpecificTestCase))
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
return result.wasSuccessful()
if __name__ == '__main__':
- if not test_main():
+ if not main():
sys.exit(1)
diff --git a/test/_windows.py b/test/_windows.py
index 5f61bd20..827cc449 100644
--- a/test/_windows.py
+++ b/test/_windows.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+# -*- coding: UTF-8 -*
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
@@ -15,8 +16,10 @@ import sys
import time
import traceback
-from test_psutil import (get_test_subprocess, reap_children, unittest)
+from test_psutil import APPVEYOR, WINDOWS
+from test_psutil import get_test_subprocess, reap_children, unittest
+import mock
try:
import wmi
except ImportError:
@@ -28,16 +31,18 @@ except ImportError:
win32api = win32con = None
from psutil._compat import PY3, callable, long
-from psutil._pswindows import ACCESS_DENIED_SET
-import _psutil_windows
import psutil
+cext = psutil._psplatform.cext
+
+
def wrap_exceptions(fun):
def wrapper(self, *args, **kwargs):
try:
return fun(self, *args, **kwargs)
except OSError as err:
+ from psutil._pswindows import ACCESS_DENIED_SET
if err.errno in ACCESS_DENIED_SET:
raise psutil.AccessDenied(None, None)
if err.errno == errno.ESRCH:
@@ -46,6 +51,7 @@ def wrap_exceptions(fun):
return wrapper
+@unittest.skipUnless(WINDOWS, "not a Windows system")
class WindowsSpecificTestCase(unittest.TestCase):
@classmethod
@@ -113,7 +119,9 @@ class WindowsSpecificTestCase(unittest.TestCase):
def test_process_exe(self):
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
- self.assertEqual(p.exe(), w.ExecutablePath)
+ # Note: wmi reports the exe as a lower case string.
+ # Being Windows paths case-insensitive we ignore that.
+ self.assertEqual(p.exe().lower(), w.ExecutablePath.lower())
@unittest.skipIf(wmi is None, "wmi module is not installed")
def test_process_cmdline(self):
@@ -163,7 +171,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
# --- psutil namespace functions and constants tests
- @unittest.skipUnless(hasattr(os, 'NUMBER_OF_PROCESSORS'),
+ @unittest.skipUnless('NUMBER_OF_PROCESSORS' in os.environ,
'NUMBER_OF_PROCESSORS env var is not available')
def test_cpu_count(self):
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
@@ -187,20 +195,16 @@ class WindowsSpecificTestCase(unittest.TestCase):
# time.localtime(p.create_time()))
#
+ # Note: this test is not very reliable
@unittest.skipIf(wmi is None, "wmi module is not installed")
+ @unittest.skipIf(APPVEYOR, "test not relieable on appveyor")
def test_pids(self):
# Note: this test might fail if the OS is starting/killing
# other processes in the meantime
w = wmi.WMI().Win32_Process()
- wmi_pids = [x.ProcessId for x in w]
- wmi_pids.sort()
- psutil_pids = psutil.pids()
- psutil_pids.sort()
- if wmi_pids != psutil_pids:
- difference = \
- filter(lambda x: x not in wmi_pids, psutil_pids) + \
- filter(lambda x: x not in psutil_pids, wmi_pids)
- self.fail("difference: " + str(difference))
+ wmi_pids = set([x.ProcessId for x in w])
+ psutil_pids = set(psutil.pids())
+ self.assertEqual(wmi_pids, psutil_pids)
@unittest.skipIf(wmi is None, "wmi module is not installed")
def test_disks(self):
@@ -257,8 +261,6 @@ class WindowsSpecificTestCase(unittest.TestCase):
failures = []
for name in dir(psutil.Process):
if name.startswith('_') \
- or name.startswith('set_') \
- or name.startswith('get') \
or name in ('terminate', 'kill', 'suspend', 'resume',
'nice', 'send_signal', 'wait', 'children',
'as_dict'):
@@ -280,29 +282,55 @@ class WindowsSpecificTestCase(unittest.TestCase):
if failures:
self.fail('\n' + '\n'.join(failures))
+ def test_name_always_available(self):
+ # On Windows name() is never supposed to raise AccessDenied,
+ # see https://github.com/giampaolo/psutil/issues/627
+ for p in psutil.process_iter():
+ try:
+ p.name()
+ except psutil.NoSuchProcess:
+ pass
+ @unittest.skipUnless(sys.version_info >= (2, 7),
+ "CTRL_* signals not supported")
+ def test_ctrl_signals(self):
+ p = psutil.Process(get_test_subprocess().pid)
+ p.send_signal(signal.CTRL_C_EVENT)
+ p.send_signal(signal.CTRL_BREAK_EVENT)
+ p.kill()
+ p.wait()
+ self.assertRaises(psutil.NoSuchProcess,
+ p.send_signal, signal.CTRL_C_EVENT)
+ self.assertRaises(psutil.NoSuchProcess,
+ p.send_signal, signal.CTRL_BREAK_EVENT)
+
+
+@unittest.skipUnless(WINDOWS, "not a Windows system")
class TestDualProcessImplementation(unittest.TestCase):
+ """
+ Certain APIs on Windows have 2 internal implementations, one
+ based on documented Windows APIs, another one based
+ NtQuerySystemInformation() which gets called as fallback in
+ case the first fails because of limited permission error.
+ Here we test that the two methods return the exact same value,
+ see:
+ https://github.com/giampaolo/psutil/issues/304
+ """
+
fun_names = [
# function name, tolerance
('proc_cpu_times', 0.2),
('proc_create_time', 0.5),
('proc_num_handles', 1), # 1 because impl #1 opens a handle
- ('proc_io_counters', 0),
('proc_memory_info', 1024), # KB
+ ('proc_io_counters', 0),
]
def test_compare_values(self):
- # Certain APIs on Windows have 2 internal implementations, one
- # based on documented Windows APIs, another one based
- # NtQuerySystemInformation() which gets called as fallback in
- # case the first fails because of limited permission error.
- # Here we test that the two methods return the exact same value,
- # see:
- # https://github.com/giampaolo/psutil/issues/304
def assert_ge_0(obj):
if isinstance(obj, tuple):
for value in obj:
- self.assertGreaterEqual(value, 0)
+ self.assertGreaterEqual(value, 0, msg=obj)
elif isinstance(obj, (int, long, float)):
self.assertGreaterEqual(obj, 0)
else:
@@ -320,61 +348,132 @@ class TestDualProcessImplementation(unittest.TestCase):
diff = abs(a - b)
self.assertLessEqual(diff, tolerance)
+ from psutil._pswindows import ntpinfo
failures = []
- for name, tolerance in self.fun_names:
- meth1 = wrap_exceptions(getattr(_psutil_windows, name))
- meth2 = wrap_exceptions(getattr(_psutil_windows, name + '_2'))
- for p in psutil.process_iter():
+ for p in psutil.process_iter():
+ try:
+ nt = ntpinfo(*cext.proc_info(p.pid))
+ except psutil.NoSuchProcess:
+ continue
+ assert_ge_0(nt)
+
+ for name, tolerance in self.fun_names:
if name == 'proc_memory_info' and p.pid == os.getpid():
continue
- #
- try:
- ret1 = meth1(p.pid)
- except psutil.NoSuchProcess:
+ if name == 'proc_create_time' and p.pid in (0, 4):
continue
- except psutil.AccessDenied:
- ret1 = None
- #
+ meth = wrap_exceptions(getattr(cext, name))
try:
- ret2 = meth2(p.pid)
- except psutil.NoSuchProcess:
- # this is supposed to fail only in case of zombie process
- # never for permission error
+ ret = meth(p.pid)
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
-
# compare values
try:
- if ret1 is None:
- assert_ge_0(ret2)
- else:
- compare_with_tolerance(ret1, ret2, tolerance)
- assert_ge_0(ret1)
- assert_ge_0(ret2)
+ if name == 'proc_cpu_times':
+ compare_with_tolerance(ret[0], nt.user_time, tolerance)
+ compare_with_tolerance(ret[1],
+ nt.kernel_time, tolerance)
+ elif name == 'proc_create_time':
+ compare_with_tolerance(ret, nt.create_time, tolerance)
+ elif name == 'proc_num_handles':
+ compare_with_tolerance(ret, nt.num_handles, tolerance)
+ elif name == 'proc_io_counters':
+ compare_with_tolerance(ret[0], nt.io_rcount, tolerance)
+ compare_with_tolerance(ret[1], nt.io_wcount, tolerance)
+ compare_with_tolerance(ret[2], nt.io_rbytes, tolerance)
+ compare_with_tolerance(ret[3], nt.io_wbytes, tolerance)
+ elif name == 'proc_memory_info':
+ try:
+ rawtupl = cext.proc_memory_info_2(p.pid)
+ except psutil.NoSuchProcess:
+ continue
+ compare_with_tolerance(ret, rawtupl, tolerance)
except AssertionError:
trace = traceback.format_exc()
msg = '%s\npid=%s, method=%r, ret_1=%r, ret_2=%r' % (
- trace, p.pid, name, ret1, ret2)
+ trace, p.pid, name, ret, nt)
failures.append(msg)
break
+
if failures:
self.fail('\n\n'.join(failures))
+ # ---
+ # same tests as above but mimicks the AccessDenied failure of
+ # the first (fast) method failing with AD.
+ # TODO: currently does not take tolerance into account.
+
+ def test_name(self):
+ name = psutil.Process().name()
+ with mock.patch("psutil._psplatform.cext.proc_exe",
+ side_effect=psutil.AccessDenied(os.getpid())) as fun:
+ psutil.Process().name() == name
+ assert fun.called
+
+ def test_memory_info(self):
+ mem = psutil.Process().memory_info()
+ with mock.patch("psutil._psplatform.cext.proc_memory_info",
+ side_effect=OSError(errno.EPERM, "msg")) as fun:
+ psutil.Process().memory_info() == mem
+ assert fun.called
+
+ def test_create_time(self):
+ ctime = psutil.Process().create_time()
+ with mock.patch("psutil._psplatform.cext.proc_create_time",
+ side_effect=OSError(errno.EPERM, "msg")) as fun:
+ psutil.Process().create_time() == ctime
+ assert fun.called
+
+ def test_cpu_times(self):
+ cpu_times = psutil.Process().cpu_times()
+ with mock.patch("psutil._psplatform.cext.proc_cpu_times",
+ side_effect=OSError(errno.EPERM, "msg")) as fun:
+ psutil.Process().cpu_times() == cpu_times
+ assert fun.called
+
+ def test_io_counters(self):
+ io_counters = psutil.Process().io_counters()
+ with mock.patch("psutil._psplatform.cext.proc_io_counters",
+ side_effect=OSError(errno.EPERM, "msg")) as fun:
+ psutil.Process().io_counters() == io_counters
+ assert fun.called
+
+ def test_num_handles(self):
+ io_counters = psutil.Process().io_counters()
+ with mock.patch("psutil._psplatform.cext.proc_io_counters",
+ side_effect=OSError(errno.EPERM, "msg")) as fun:
+ psutil.Process().io_counters() == io_counters
+ assert fun.called
+
+ # --- other tests
+
+ def test_compare_name_exe(self):
+ for p in psutil.process_iter():
+ try:
+ a = os.path.basename(p.exe())
+ b = p.name()
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
+ pass
+ else:
+ self.assertEqual(a, b)
+
def test_zombies(self):
# test that NPS is raised by the 2nd implementation in case a
# process no longer exists
ZOMBIE_PID = max(psutil.pids()) + 5000
for name, _ in self.fun_names:
- meth = wrap_exceptions(getattr(_psutil_windows, name))
+ meth = wrap_exceptions(getattr(cext, name))
self.assertRaises(psutil.NoSuchProcess, meth, ZOMBIE_PID)
-def test_main():
+def main():
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(WindowsSpecificTestCase))
test_suite.addTest(unittest.makeSuite(TestDualProcessImplementation))
result = unittest.TextTestRunner(verbosity=2).run(test_suite)
return result.wasSuccessful()
+
if __name__ == '__main__':
- if not test_main():
+ if not main():
sys.exit(1)
diff --git a/test/test_memory_leaks.py b/test/test_memory_leaks.py
index be346269..c95734c8 100644
--- a/test/test_memory_leaks.py
+++ b/test/test_memory_leaks.py
@@ -10,6 +10,7 @@ functions many times and compare process memory usage before and
after the calls. It might produce false positives.
"""
+import functools
import gc
import os
import socket
@@ -17,23 +18,23 @@ import sys
import threading
import time
-if sys.version_info < (2, 7):
- import unittest2 as unittest # https://pypi.python.org/pypi/unittest2
-else:
- import unittest
-
import psutil
import psutil._common
-from psutil._compat import xrange
+from psutil._compat import xrange, callable
from test_psutil import (WINDOWS, POSIX, OSX, LINUX, SUNOS, BSD, TESTFN,
RLIMIT_SUPPORT, TRAVIS)
from test_psutil import (reap_children, supports_ipv6, safe_remove,
get_test_subprocess)
+if sys.version_info < (2, 7):
+ import unittest2 as unittest # https://pypi.python.org/pypi/unittest2
+else:
+ import unittest
+
LOOPS = 1000
-TOLERANCE = 4096
+MEMORY_TOLERANCE = 4096
SKIP_PYTHON_IMPL = True
@@ -64,7 +65,7 @@ class Base(unittest.TestCase):
rss2 = call_many_times()
difference = rss2 - rss1
- if difference > TOLERANCE:
+ if difference > MEMORY_TOLERANCE:
# This doesn't necessarily mean we have a leak yet.
# At this point we assume that after having called the
# function so many times the memory usage is stabilized
@@ -92,7 +93,7 @@ class Base(unittest.TestCase):
def get_mem(self):
return psutil.Process().memory_info()[0]
- def call(self, *args, **kwargs):
+ def call(self, function, *args, **kwargs):
raise NotImplementedError("must be implemented in subclass")
@@ -106,15 +107,25 @@ class TestProcessObjectLeaks(Base):
reap_children()
def call(self, function, *args, **kwargs):
- meth = getattr(self.proc, function)
- if '_exc' in kwargs:
- exc = kwargs.pop('_exc')
- self.assertRaises(exc, meth, *args, **kwargs)
+ if callable(function):
+ if '_exc' in kwargs:
+ exc = kwargs.pop('_exc')
+ self.assertRaises(exc, function, *args, **kwargs)
+ else:
+ try:
+ function(*args, **kwargs)
+ except psutil.Error:
+ pass
else:
- try:
- meth(*args, **kwargs)
- except psutil.Error:
- pass
+ meth = getattr(self.proc, function)
+ if '_exc' in kwargs:
+ exc = kwargs.pop('_exc')
+ self.assertRaises(exc, meth, *args, **kwargs)
+ else:
+ try:
+ meth(*args, **kwargs)
+ except psutil.Error:
+ pass
@skip_if_linux()
def test_name(self):
@@ -165,10 +176,12 @@ class TestProcessObjectLeaks(Base):
value = psutil.Process().ionice()
self.execute('ionice', value)
else:
+ from psutil._pslinux import cext
self.execute('ionice', psutil.IOPRIO_CLASS_NONE)
- self.execute_w_exc(OSError, 'ionice', -1)
+ fun = functools.partial(cext.proc_ioprio_set, os.getpid(), -1, 0)
+ self.execute_w_exc(OSError, fun)
- @unittest.skipIf(OSX, "feature not supported on this platform")
+ @unittest.skipIf(OSX or SUNOS, "feature not supported on this platform")
@skip_if_linux()
def test_io_counters(self):
self.execute('io_counters')
@@ -406,11 +419,19 @@ class TestModuleFunctionsLeaks(Base):
@unittest.skipIf(LINUX,
"not worth being tested on Linux (pure python)")
+ @unittest.skipIf(OSX and os.getuid() != 0, "need root access")
def test_net_connections(self):
self.execute('net_connections')
+ def test_net_if_addrs(self):
+ self.execute('net_if_addrs')
+
+ @unittest.skipIf(TRAVIS, "EPERM on travis")
+ def test_net_if_stats(self):
+ self.execute('net_if_stats')
+
-def test_main():
+def main():
test_suite = unittest.TestSuite()
tests = [TestProcessObjectLeaksZombie,
TestProcessObjectLeaks,
@@ -421,5 +442,5 @@ def test_main():
return result.wasSuccessful()
if __name__ == '__main__':
- if not test_main():
+ if not main():
sys.exit(1)
diff --git a/test/test_psutil.py b/test/test_psutil.py
index c8e14e87..94b330ee 100644
--- a/test/test_psutil.py
+++ b/test/test_psutil.py
@@ -22,9 +22,11 @@ import contextlib
import datetime
import errno
import functools
+import imp
import json
import os
import pickle
+import pprint
import re
import select
import shutil
@@ -41,14 +43,26 @@ import traceback
import types
import warnings
from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
+try:
+ import ipaddress # python >= 3.3
+except ImportError:
+ ipaddress = None
+try:
+ from unittest import mock # py3
+except ImportError:
+ import mock # requires "pip install mock"
+
+import psutil
+from psutil._compat import PY3, callable, long, unicode
if sys.version_info < (2, 7):
import unittest2 as unittest # https://pypi.python.org/pypi/unittest2
else:
import unittest
-
-import psutil
-from psutil._compat import PY3, callable, long, unicode
+if sys.version_info >= (3, 4):
+ import enum
+else:
+ enum = None
# ===================================================================
@@ -58,7 +72,7 @@ from psutil._compat import PY3, callable, long, unicode
# conf for retry_before_failing() decorator
NO_RETRIES = 10
# bytes tolerance for OS memory related tests
-TOLERANCE = 500 * 1024 # 500KB
+MEMORY_TOLERANCE = 500 * 1024 # 500KB
# the timeout used in functions which have to wait
GLOBAL_TIMEOUT = 3
@@ -90,6 +104,14 @@ VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil)
if x.startswith('STATUS_')]
# whether we're running this test suite on Travis (https://travis-ci.org/)
TRAVIS = bool(os.environ.get('TRAVIS'))
+# whether we're running this test suite on Appveyor for Windows
+# (http://www.appveyor.com/)
+APPVEYOR = bool(os.environ.get('APPVEYOR'))
+
+if TRAVIS or 'tox' in sys.argv[0]:
+ import ipaddress
+if TRAVIS or APPVEYOR:
+ GLOBAL_TIMEOUT = GLOBAL_TIMEOUT * 4
# ===================================================================
@@ -125,7 +147,7 @@ def get_test_subprocess(cmd=None, stdout=DEVNULL, stderr=DEVNULL,
pyline = ""
if wait:
pyline += "open(r'%s', 'w'); " % TESTFN
- pyline += "import time; time.sleep(2);"
+ pyline += "import time; time.sleep(60);"
cmd_ = [PYTHON, "-c", pyline]
else:
cmd_ = cmd
@@ -246,6 +268,23 @@ def wait_for_pid(pid, timeout=GLOBAL_TIMEOUT):
raise RuntimeError("Timed out")
+def wait_for_file(fname, timeout=GLOBAL_TIMEOUT, delete_file=True):
+ """Wait for a file to be written on disk."""
+ stop_at = time.time() + 3
+ while time.time() < stop_at:
+ try:
+ with open(fname, "r") as f:
+ data = f.read()
+ if not data:
+ continue
+ if delete_file:
+ os.remove(fname)
+ return data
+ except IOError:
+ time.sleep(0.001)
+ raise RuntimeError("timed out (couldn't read file)")
+
+
def reap_children(search_all=False):
"""Kill any subprocess started by this test suite and ensure that
no zombies stick around to hog resources and create problems when
@@ -277,34 +316,57 @@ def reap_children(search_all=False):
def check_ip_address(addr, family):
"""Attempts to check IP address's validity."""
- if not addr:
- return
- if family in (AF_INET, AF_INET6):
- assert isinstance(addr, tuple), addr
- ip, port = addr
- assert isinstance(port, int), port
- if family == AF_INET:
- ip = list(map(int, ip.split('.')))
- assert len(ip) == 4, ip
- for num in ip:
- assert 0 <= num <= 255, ip
- assert 0 <= port <= 65535, port
- elif family == AF_UNIX:
- assert isinstance(addr, (str, None)), addr
+ if enum and PY3:
+ assert isinstance(family, enum.IntEnum), family
+ if family == AF_INET:
+ octs = [int(x) for x in addr.split('.')]
+ assert len(octs) == 4, addr
+ for num in octs:
+ assert 0 <= num <= 255, addr
+ if ipaddress:
+ if not PY3:
+ addr = unicode(addr)
+ ipaddress.IPv4Address(addr)
+ elif family == AF_INET6:
+ assert isinstance(addr, str), addr
+ if ipaddress:
+ if not PY3:
+ addr = unicode(addr)
+ ipaddress.IPv6Address(addr)
+ elif family == psutil.AF_LINK:
+ assert re.match('([a-fA-F0-9]{2}[:|\-]?){6}', addr) is not None, addr
else:
raise ValueError("unknown family %r", family)
-def check_connection(conn):
+def check_connection_ntuple(conn):
"""Check validity of a connection namedtuple."""
valid_conn_states = [getattr(psutil, x) for x in dir(psutil) if
x.startswith('CONN_')]
-
+ assert conn[0] == conn.fd
+ assert conn[1] == conn.family
+ assert conn[2] == conn.type
+ assert conn[3] == conn.laddr
+ assert conn[4] == conn.raddr
+ assert conn[5] == conn.status
assert conn.type in (SOCK_STREAM, SOCK_DGRAM), repr(conn.type)
assert conn.family in (AF_INET, AF_INET6, AF_UNIX), repr(conn.family)
assert conn.status in valid_conn_states, conn.status
- check_ip_address(conn.laddr, conn.family)
- check_ip_address(conn.raddr, conn.family)
+
+ # check IP address and port sanity
+ for addr in (conn.laddr, conn.raddr):
+ if not addr:
+ continue
+ if conn.family in (AF_INET, AF_INET6):
+ assert isinstance(addr, tuple), addr
+ ip, port = addr
+ assert isinstance(port, int), port
+ assert 0 <= port <= 65535, port
+ check_ip_address(ip, conn.family)
+ elif conn.family == AF_UNIX:
+ assert isinstance(addr, (str, None)), addr
+ else:
+ raise ValueError("unknown family %r", conn.family)
if conn.family in (AF_INET, AF_INET6):
# actually try to bind the local socket; ignore IPv6
@@ -343,9 +405,9 @@ def safe_remove(file):
os.remove(file)
except OSError as err:
if err.errno != errno.ENOENT:
- # file is being used by another process
- if WINDOWS and isinstance(err, WindowsError) and err.errno == 13:
- return
+ # # file is being used by another process
+ # if WINDOWS and isinstance(err, WindowsError) and err.errno == 13:
+ # return
raise
@@ -358,6 +420,17 @@ def safe_rmdir(dir):
raise
+@contextlib.contextmanager
+def chdir(dirname):
+ """Context manager which temporarily changes the current directory."""
+ curdir = os.getcwd()
+ try:
+ os.chdir(dirname)
+ yield
+ finally:
+ os.chdir(curdir)
+
+
def call_until(fun, expr, timeout=GLOBAL_TIMEOUT):
"""Keep calling function for timeout secs and exit if eval()
expression is True.
@@ -378,7 +451,9 @@ def retry_before_failing(ntimes=None):
def decorator(fun):
@functools.wraps(fun)
def wrapper(*args, **kwargs):
- for x in range(ntimes or NO_RETRIES):
+ times = ntimes or NO_RETRIES
+ assert times, times
+ for x in range(times):
try:
return fun(*args, **kwargs)
except AssertionError:
@@ -401,8 +476,7 @@ def skip_on_access_denied(only_if=None):
raise
msg = "%r was skipped because it raised AccessDenied" \
% fun.__name__
- self = args[0]
- self.skip(msg)
+ raise unittest.SkipTest(msg)
return wrapper
return decorator
@@ -420,8 +494,7 @@ def skip_on_not_implemented(only_if=None):
raise
msg = "%r was skipped because it raised NotImplementedError" \
% fun.__name__
- self = args[0]
- self.skip(msg)
+ raise unittest.SkipTest(msg)
return wrapper
return decorator
@@ -516,19 +589,25 @@ class TestSystemAPIs(unittest.TestCase):
p.wait()
self.assertNotIn(sproc.pid, [x.pid for x in psutil.process_iter()])
- @retry_before_failing(50)
- def test_process_iter_against_pids(self):
- self.assertEqual(len(list(psutil.process_iter())), len(psutil.pids()))
+ with mock.patch('psutil.Process',
+ side_effect=psutil.NoSuchProcess(os.getpid())):
+ self.assertEqual(list(psutil.process_iter()), [])
+ with mock.patch('psutil.Process',
+ side_effect=psutil.AccessDenied(os.getpid())):
+ with self.assertRaises(psutil.AccessDenied):
+ list(psutil.process_iter())
def test_wait_procs(self):
- l = []
- callback = lambda p: l.append(p.pid)
+ def callback(p):
+ l.append(p.pid)
+ l = []
sproc1 = get_test_subprocess()
sproc2 = get_test_subprocess()
sproc3 = get_test_subprocess()
procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)]
self.assertRaises(ValueError, psutil.wait_procs, procs, timeout=-1)
+ self.assertRaises(TypeError, psutil.wait_procs, procs, callback=1)
t = time.time()
gone, alive = psutil.wait_procs(procs, timeout=0.01, callback=callback)
@@ -539,10 +618,16 @@ class TestSystemAPIs(unittest.TestCase):
for p in alive:
self.assertFalse(hasattr(p, 'returncode'))
+ @retry_before_failing(30)
+ def test(procs, callback):
+ gone, alive = psutil.wait_procs(procs, timeout=0.03,
+ callback=callback)
+ self.assertEqual(len(gone), 1)
+ self.assertEqual(len(alive), 2)
+ return gone, alive
+
sproc3.terminate()
- gone, alive = psutil.wait_procs(procs, timeout=0.03, callback=callback)
- self.assertEqual(len(gone), 1)
- self.assertEqual(len(alive), 2)
+ gone, alive = test(procs, callback)
self.assertIn(sproc3.pid, [x.pid for x in gone])
if POSIX:
self.assertEqual(gone.pop().returncode, signal.SIGTERM)
@@ -552,11 +637,17 @@ class TestSystemAPIs(unittest.TestCase):
for p in alive:
self.assertFalse(hasattr(p, 'returncode'))
+ @retry_before_failing(30)
+ def test(procs, callback):
+ gone, alive = psutil.wait_procs(procs, timeout=0.03,
+ callback=callback)
+ self.assertEqual(len(gone), 3)
+ self.assertEqual(len(alive), 0)
+ return gone, alive
+
sproc1.terminate()
sproc2.terminate()
- gone, alive = psutil.wait_procs(procs, timeout=0.03, callback=callback)
- self.assertEqual(len(gone), 3)
- self.assertEqual(len(alive), 0)
+ gone, alive = test(procs, callback)
self.assertEqual(set(l), set([sproc1.pid, sproc2.pid, sproc3.pid]))
for p in gone:
self.assertTrue(hasattr(p, 'returncode'))
@@ -584,92 +675,6 @@ class TestSystemAPIs(unittest.TestCase):
import resource
self.assertEqual(os.sysconf("SC_PAGE_SIZE"), resource.getpagesize())
- def test_deprecated_apis(self):
- with warnings.catch_warnings():
- warnings.filterwarnings("error")
- p = psutil.Process()
- # system APIs
- self.assertRaises(DeprecationWarning, getattr, psutil, 'NUM_CPUS')
- self.assertRaises(DeprecationWarning, getattr, psutil, 'BOOT_TIME')
- self.assertRaises(DeprecationWarning, getattr, psutil,
- 'TOTAL_PHYMEM')
- self.assertRaises(DeprecationWarning, psutil.get_pid_list)
- self.assertRaises(DeprecationWarning, psutil.get_users)
- self.assertRaises(DeprecationWarning, psutil.virtmem_usage)
- self.assertRaises(DeprecationWarning, psutil.used_phymem)
- self.assertRaises(DeprecationWarning, psutil.avail_phymem)
- self.assertRaises(DeprecationWarning, psutil.total_virtmem)
- self.assertRaises(DeprecationWarning, psutil.used_virtmem)
- self.assertRaises(DeprecationWarning, psutil.avail_virtmem)
- self.assertRaises(DeprecationWarning, psutil.phymem_usage)
- self.assertRaises(DeprecationWarning, psutil.get_process_list)
- self.assertRaises(DeprecationWarning, psutil.network_io_counters)
- if LINUX:
- self.assertRaises(DeprecationWarning, psutil.phymem_buffers)
- self.assertRaises(DeprecationWarning, psutil.cached_phymem)
-
- # Process class
- names = dir(psutil.Process)
- self.assertRaises(DeprecationWarning, p.get_children)
- self.assertRaises(DeprecationWarning, p.get_connections)
- if 'cpu_affinity' in names:
- self.assertRaises(DeprecationWarning, p.get_cpu_affinity)
- self.assertRaises(DeprecationWarning, p.get_cpu_percent)
- self.assertRaises(DeprecationWarning, p.get_cpu_times)
- self.assertRaises(DeprecationWarning, p.getcwd)
- self.assertRaises(DeprecationWarning, p.get_ext_memory_info)
- if 'io_counters' in names:
- self.assertRaises(DeprecationWarning, p.get_io_counters)
- if 'ionice' in names:
- self.assertRaises(DeprecationWarning, p.get_ionice)
- self.assertRaises(DeprecationWarning, p.get_memory_info)
- self.assertRaises(DeprecationWarning, p.get_memory_maps)
- self.assertRaises(DeprecationWarning, p.get_memory_percent)
- self.assertRaises(DeprecationWarning, p.get_nice)
- self.assertRaises(DeprecationWarning, p.get_num_ctx_switches)
- if 'num_fds' in names:
- self.assertRaises(DeprecationWarning, p.get_num_fds)
- if 'num_handles' in names:
- self.assertRaises(DeprecationWarning, p.get_num_handles)
- self.assertRaises(DeprecationWarning, p.get_num_threads)
- self.assertRaises(DeprecationWarning, p.get_open_files)
- if 'rlimit' in names:
- self.assertRaises(DeprecationWarning, p.get_rlimit)
- self.assertRaises(DeprecationWarning, p.get_threads)
- # ...just to be extra sure:
- for name in names:
- if name.startswith('get'):
- meth = getattr(p, name)
- try:
- self.assertRaises(DeprecationWarning, meth)
- except AssertionError:
- self.fail("%s did not raise DeprecationWarning" % name)
-
- # named tuples
- with contextlib.closing(socket.socket()) as s:
- s.bind(('localhost', 0))
- s.listen(1)
- ret = call_until(p.connections, "len(ret) != 0")
- self.assertRaises(DeprecationWarning,
- getattr, ret[0], 'local_address')
- self.assertRaises(DeprecationWarning,
- getattr, ret[0], 'remote_address')
-
- # check value against new APIs
- with warnings.catch_warnings():
- warnings.filterwarnings("ignore")
- self.assertEqual(psutil.get_pid_list(), psutil.pids())
- self.assertEqual(psutil.NUM_CPUS, psutil.cpu_count())
- self.assertEqual(psutil.BOOT_TIME, psutil.boot_time())
- self.assertEqual(psutil.TOTAL_PHYMEM,
- psutil.virtual_memory().total)
-
- def test_deprecated_apis_retval(self):
- with warnings.catch_warnings():
- warnings.filterwarnings("ignore")
- self.assertEqual(psutil.total_virtmem(),
- psutil.swap_memory().total)
-
def test_virtual_memory(self):
mem = psutil.virtual_memory()
assert mem.total > 0, mem
@@ -710,6 +715,8 @@ class TestSystemAPIs(unittest.TestCase):
self.assertFalse(psutil.pid_exists(sproc.pid))
self.assertFalse(psutil.pid_exists(-1))
self.assertEqual(psutil.pid_exists(0), 0 in psutil.pids())
+ # pid 0
+ psutil.pid_exists(0) == 0 in psutil.pids()
def test_pid_exists_2(self):
reap_children()
@@ -725,7 +732,7 @@ class TestSystemAPIs(unittest.TestCase):
self.fail(pid)
pids = range(max(pids) + 5000, max(pids) + 6000)
for pid in pids:
- self.assertFalse(psutil.pid_exists(pid))
+ self.assertFalse(psutil.pid_exists(pid), msg=pid)
def test_pids(self):
plist = [x.pid for x in psutil.process_iter()]
@@ -748,6 +755,11 @@ class TestSystemAPIs(unittest.TestCase):
self.assertEqual(logical, len(psutil.cpu_times(percpu=True)))
self.assertGreaterEqual(logical, 1)
#
+ if LINUX:
+ with open("/proc/cpuinfo") as fd:
+ cpuinfo_data = fd.read()
+ if "physical id" not in cpuinfo_data:
+ raise unittest.SkipTest("cpuinfo doesn't include physical id")
physical = psutil.cpu_count(logical=False)
self.assertGreaterEqual(physical, 1)
self.assertGreaterEqual(logical, physical)
@@ -762,19 +774,23 @@ class TestSystemAPIs(unittest.TestCase):
total += cp_time
self.assertEqual(total, sum(times))
str(times)
- if not WINDOWS:
- # CPU times are always supposed to increase over time or
- # remain the same but never go backwards, see:
- # https://github.com/giampaolo/psutil/issues/392
- last = psutil.cpu_times()
- for x in range(100):
- new = psutil.cpu_times()
- for field in new._fields:
- new_t = getattr(new, field)
- last_t = getattr(last, field)
- self.assertGreaterEqual(new_t, last_t,
- msg="%s %s" % (new_t, last_t))
- last = new
+ # CPU times are always supposed to increase over time
+ # or at least remain the same and that's because time
+ # cannot go backwards.
+ # Surprisingly sometimes this might not be the case (at
+ # least on Windows and Linux), see:
+ # https://github.com/giampaolo/psutil/issues/392
+ # https://github.com/giampaolo/psutil/issues/645
+ # if not WINDOWS:
+ # last = psutil.cpu_times()
+ # for x in range(100):
+ # new = psutil.cpu_times()
+ # for field in new._fields:
+ # new_t = getattr(new, field)
+ # last_t = getattr(last, field)
+ # self.assertGreaterEqual(new_t, last_t,
+ # msg="%s %s" % (new_t, last_t))
+ # last = new
def test_sys_cpu_times2(self):
t1 = sum(psutil.cpu_times())
@@ -796,24 +812,27 @@ class TestSystemAPIs(unittest.TestCase):
str(times)
self.assertEqual(len(psutil.cpu_times(percpu=True)[0]),
len(psutil.cpu_times(percpu=False)))
- if not WINDOWS:
- # CPU times are always supposed to increase over time or
- # remain the same but never go backwards, see:
- # https://github.com/giampaolo/psutil/issues/392
- last = psutil.cpu_times(percpu=True)
- for x in range(100):
- new = psutil.cpu_times(percpu=True)
- for index in range(len(new)):
- newcpu = new[index]
- lastcpu = last[index]
- for field in newcpu._fields:
- new_t = getattr(newcpu, field)
- last_t = getattr(lastcpu, field)
- self.assertGreaterEqual(
- new_t, last_t, msg="%s %s" % (lastcpu, newcpu))
- last = new
-
- def test_sys_per_cpu_times2(self):
+
+ # Note: in theory CPU times are always supposed to increase over
+ # time or remain the same but never go backwards. In practice
+ # sometimes this is not the case.
+ # This issue seemd to be afflict Windows:
+ # https://github.com/giampaolo/psutil/issues/392
+ # ...but it turns out also Linux (rarely) behaves the same.
+ # last = psutil.cpu_times(percpu=True)
+ # for x in range(100):
+ # new = psutil.cpu_times(percpu=True)
+ # for index in range(len(new)):
+ # newcpu = new[index]
+ # lastcpu = last[index]
+ # for field in newcpu._fields:
+ # new_t = getattr(newcpu, field)
+ # last_t = getattr(lastcpu, field)
+ # self.assertGreaterEqual(
+ # new_t, last_t, msg="%s %s" % (lastcpu, newcpu))
+ # last = new
+
+ def test_sys_per_cpu_times_2(self):
tot1 = psutil.cpu_times(percpu=True)
stop_at = time.time() + 0.1
while True:
@@ -827,42 +846,61 @@ class TestSystemAPIs(unittest.TestCase):
return
self.fail()
- def _test_cpu_percent(self, percent):
- self.assertIsInstance(percent, float)
- self.assertGreaterEqual(percent, 0.0)
- self.assertLessEqual(percent, 100.0 * psutil.cpu_count())
+ def _test_cpu_percent(self, percent, last_ret, new_ret):
+ try:
+ self.assertIsInstance(percent, float)
+ self.assertGreaterEqual(percent, 0.0)
+ self.assertIsNot(percent, -0.0)
+ self.assertLessEqual(percent, 100.0 * psutil.cpu_count())
+ except AssertionError as err:
+ raise AssertionError("\n%s\nlast=%s\nnew=%s" % (
+ err, pprint.pformat(last_ret), pprint.pformat(new_ret)))
def test_sys_cpu_percent(self):
- psutil.cpu_percent(interval=0.001)
+ last = psutil.cpu_percent(interval=0.001)
for x in range(100):
- self._test_cpu_percent(psutil.cpu_percent(interval=None))
+ new = psutil.cpu_percent(interval=None)
+ self._test_cpu_percent(new, last, new)
+ last = new
def test_sys_per_cpu_percent(self):
- self.assertEqual(len(psutil.cpu_percent(interval=0.001, percpu=True)),
- psutil.cpu_count())
+ last = psutil.cpu_percent(interval=0.001, percpu=True)
+ self.assertEqual(len(last), psutil.cpu_count())
for x in range(100):
- percents = psutil.cpu_percent(interval=None, percpu=True)
- for percent in percents:
- self._test_cpu_percent(percent)
+ new = psutil.cpu_percent(interval=None, percpu=True)
+ for percent in new:
+ self._test_cpu_percent(percent, last, new)
+ last = new
def test_sys_cpu_times_percent(self):
- psutil.cpu_times_percent(interval=0.001)
+ last = psutil.cpu_times_percent(interval=0.001)
for x in range(100):
- cpu = psutil.cpu_times_percent(interval=None)
- for percent in cpu:
- self._test_cpu_percent(percent)
- self._test_cpu_percent(sum(cpu))
+ new = psutil.cpu_times_percent(interval=None)
+ for percent in new:
+ self._test_cpu_percent(percent, last, new)
+ self._test_cpu_percent(sum(new), last, new)
+ last = new
def test_sys_per_cpu_times_percent(self):
- self.assertEqual(len(psutil.cpu_times_percent(interval=0.001,
- percpu=True)),
- psutil.cpu_count())
+ last = psutil.cpu_times_percent(interval=0.001, percpu=True)
+ self.assertEqual(len(last), psutil.cpu_count())
for x in range(100):
- cpus = psutil.cpu_times_percent(interval=None, percpu=True)
- for cpu in cpus:
+ new = psutil.cpu_times_percent(interval=None, percpu=True)
+ for cpu in new:
+ for percent in cpu:
+ self._test_cpu_percent(percent, last, new)
+ self._test_cpu_percent(sum(cpu), last, new)
+ last = new
+
+ def test_sys_per_cpu_times_percent_negative(self):
+ # see: https://github.com/giampaolo/psutil/issues/645
+ psutil.cpu_times_percent(percpu=True)
+ zero_times = [x._make([0 for x in range(len(x._fields))])
+ for x in psutil.cpu_times(percpu=True)]
+ with mock.patch('psutil.cpu_times', return_value=zero_times):
+ for cpu in psutil.cpu_times_percent(percpu=True):
for percent in cpu:
- self._test_cpu_percent(percent)
- self._test_cpu_percent(sum(cpu))
+ self._test_cpu_percent(percent, None, None)
@unittest.skipIf(POSIX and not hasattr(os, 'statvfs'),
"os.statvfs() function not available on this platform")
@@ -944,6 +982,8 @@ class TestSystemAPIs(unittest.TestCase):
try:
os.stat(disk.mountpoint)
except OSError as err:
+ if TRAVIS and OSX and err.errno == errno.EIO:
+ continue
# http://mail.python.org/pipermail/python-dev/
# 2012-June/120787.html
if err.errno not in (errno.EPERM, errno.EACCES):
@@ -982,6 +1022,7 @@ class TestSystemAPIs(unittest.TestCase):
continue
families, types_ = groups
cons = psutil.net_connections(kind)
+ self.assertEqual(len(cons), len(set(cons)))
check(cons, families, types_)
def test_net_io_counters(self):
@@ -1011,8 +1052,79 @@ class TestSystemAPIs(unittest.TestCase):
self.assertTrue(key)
check_ntuple(ret[key])
+ def test_net_if_addrs(self):
+ nics = psutil.net_if_addrs()
+ assert nics, nics
+
+ # Not reliable on all platforms (net_if_addrs() reports more
+ # interfaces).
+ # self.assertEqual(sorted(nics.keys()),
+ # sorted(psutil.net_io_counters(pernic=True).keys()))
+
+ families = set([socket.AF_INET, AF_INET6, psutil.AF_LINK])
+ for nic, addrs in nics.items():
+ self.assertEqual(len(set(addrs)), len(addrs))
+ for addr in addrs:
+ self.assertIsInstance(addr.family, int)
+ self.assertIsInstance(addr.address, str)
+ self.assertIsInstance(addr.netmask, (str, type(None)))
+ self.assertIsInstance(addr.broadcast, (str, type(None)))
+ self.assertIn(addr.family, families)
+ if sys.version_info >= (3, 4):
+ self.assertIsInstance(addr.family, enum.IntEnum)
+ if addr.family == socket.AF_INET:
+ s = socket.socket(addr.family)
+ with contextlib.closing(s):
+ s.bind((addr.address, 0))
+ elif addr.family == socket.AF_INET6:
+ info = socket.getaddrinfo(
+ addr.address, 0, socket.AF_INET6, socket.SOCK_STREAM,
+ 0, socket.AI_PASSIVE)[0]
+ af, socktype, proto, canonname, sa = info
+ s = socket.socket(af, socktype, proto)
+ with contextlib.closing(s):
+ s.bind(sa)
+ for ip in (addr.address, addr.netmask, addr.broadcast,
+ addr.ptp):
+ if ip is not None:
+ # TODO: skip AF_INET6 for now because I get:
+ # AddressValueError: Only hex digits permitted in
+ # u'c6f3%lxcbr0' in u'fe80::c8e0:fff:fe54:c6f3%lxcbr0'
+ if addr.family != AF_INET6:
+ check_ip_address(ip, addr.family)
+ # broadcast and ptp addresses are mutually exclusive
+ if addr.broadcast:
+ self.assertIsNone(addr.ptp)
+ elif addr.ptp:
+ self.assertIsNone(addr.broadcast)
+
+ if BSD or OSX or SUNOS:
+ if hasattr(socket, "AF_LINK"):
+ self.assertEqual(psutil.AF_LINK, socket.AF_LINK)
+ elif LINUX:
+ self.assertEqual(psutil.AF_LINK, socket.AF_PACKET)
+ elif WINDOWS:
+ self.assertEqual(psutil.AF_LINK, -1)
+
+ @unittest.skipIf(TRAVIS, "EPERM on travis")
+ def test_net_if_stats(self):
+ nics = psutil.net_if_stats()
+ assert nics, nics
+ all_duplexes = (psutil.NIC_DUPLEX_FULL,
+ psutil.NIC_DUPLEX_HALF,
+ psutil.NIC_DUPLEX_UNKNOWN)
+ for nic, stats in nics.items():
+ isup, duplex, speed, mtu = stats
+ self.assertIsInstance(isup, bool)
+ self.assertIn(duplex, all_duplexes)
+ self.assertIn(duplex, all_duplexes)
+ self.assertGreaterEqual(speed, 0)
+ self.assertGreaterEqual(mtu, 0)
+
@unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'),
'/proc/diskstats not available on this linux version')
+ @unittest.skipIf(APPVEYOR,
+ "can't find any physical disk on Appveyor")
def test_disk_io_counters(self):
def check_ntuple(nt):
self.assertEqual(nt[0], nt.read_count)
@@ -1045,7 +1157,8 @@ class TestSystemAPIs(unittest.TestCase):
def test_users(self):
users = psutil.users()
- self.assertNotEqual(users, [])
+ if not APPVEYOR:
+ self.assertNotEqual(users, [])
for user in users:
assert user.name, user
user.terminal
@@ -1095,13 +1208,30 @@ class TestProcess(unittest.TestCase):
def test_send_signal(self):
sig = signal.SIGKILL if POSIX else signal.SIGTERM
sproc = get_test_subprocess()
- test_pid = sproc.pid
- p = psutil.Process(test_pid)
+ p = psutil.Process(sproc.pid)
p.send_signal(sig)
exit_sig = p.wait()
- self.assertFalse(psutil.pid_exists(test_pid))
+ self.assertFalse(psutil.pid_exists(p.pid))
if POSIX:
self.assertEqual(exit_sig, sig)
+ #
+ sproc = get_test_subprocess()
+ p = psutil.Process(sproc.pid)
+ p.send_signal(sig)
+ with mock.patch('psutil.os.kill',
+ side_effect=OSError(errno.ESRCH, "")) as fun:
+ with self.assertRaises(psutil.NoSuchProcess):
+ p.send_signal(sig)
+ assert fun.called
+ #
+ sproc = get_test_subprocess()
+ p = psutil.Process(sproc.pid)
+ p.send_signal(sig)
+ with mock.patch('psutil.os.kill',
+ side_effect=OSError(errno.EPERM, "")) as fun:
+ with self.assertRaises(psutil.AccessDenied):
+ p.send_signal(sig)
+ assert fun.called
def test_wait(self):
# check exit code signal
@@ -1156,7 +1286,7 @@ class TestProcess(unittest.TestCase):
# test wait() against processes which are not our children
code = "import sys;"
code += "from subprocess import Popen, PIPE;"
- code += "cmd = ['%s', '-c', 'import time; time.sleep(2)'];" % PYTHON
+ code += "cmd = ['%s', '-c', 'import time; time.sleep(60)'];" % PYTHON
code += "sp = Popen(cmd, stdout=PIPE);"
code += "sys.stdout.write(str(sp.pid));"
sproc = get_test_subprocess([PYTHON, "-c", code],
@@ -1302,6 +1432,8 @@ class TestProcess(unittest.TestCase):
try:
p.ionice(2)
ioclass, value = p.ionice()
+ if enum is not None:
+ self.assertIsInstance(ioclass, enum.IntEnum)
self.assertEqual(ioclass, 2)
self.assertEqual(value, 4)
#
@@ -1318,12 +1450,26 @@ class TestProcess(unittest.TestCase):
ioclass, value = p.ionice()
self.assertEqual(ioclass, 2)
self.assertEqual(value, 7)
+ #
self.assertRaises(ValueError, p.ionice, 2, 10)
+ self.assertRaises(ValueError, p.ionice, 2, -1)
+ self.assertRaises(ValueError, p.ionice, 4)
+ self.assertRaises(TypeError, p.ionice, 2, "foo")
+ self.assertRaisesRegexp(
+ ValueError, "can't specify value with IOPRIO_CLASS_NONE",
+ p.ionice, psutil.IOPRIO_CLASS_NONE, 1)
+ self.assertRaisesRegexp(
+ ValueError, "can't specify value with IOPRIO_CLASS_IDLE",
+ p.ionice, psutil.IOPRIO_CLASS_IDLE, 1)
+ self.assertRaisesRegexp(
+ ValueError, "'ioclass' argument must be specified",
+ p.ionice, value=1)
finally:
p.ionice(IOPRIO_CLASS_NONE)
else:
p = psutil.Process()
original = p.ionice()
+ self.assertIsInstance(original, int)
try:
value = 0 # very low
if original == value:
@@ -1362,6 +1508,61 @@ class TestProcess(unittest.TestCase):
p = psutil.Process(sproc.pid)
p.rlimit(psutil.RLIMIT_NOFILE, (5, 5))
self.assertEqual(p.rlimit(psutil.RLIMIT_NOFILE), (5, 5))
+ # If pid is 0 prlimit() applies to the calling process and
+ # we don't want that.
+ with self.assertRaises(ValueError):
+ psutil._psplatform.Process(0).rlimit(0)
+ with self.assertRaises(ValueError):
+ p.rlimit(psutil.RLIMIT_NOFILE, (5, 5, 5))
+
+ @unittest.skipUnless(LINUX and RLIMIT_SUPPORT,
+ "only available on Linux >= 2.6.36")
+ def test_rlimit(self):
+ p = psutil.Process()
+ soft, hard = p.rlimit(psutil.RLIMIT_FSIZE)
+ try:
+ p.rlimit(psutil.RLIMIT_FSIZE, (1024, hard))
+ with open(TESTFN, "wb") as f:
+ f.write(b"X" * 1024)
+ # write() or flush() doesn't always cause the exception
+ # but close() will.
+ with self.assertRaises(IOError) as exc:
+ with open(TESTFN, "wb") as f:
+ f.write(b"X" * 1025)
+ self.assertEqual(exc.exception.errno if PY3 else exc.exception[0],
+ errno.EFBIG)
+ finally:
+ p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard))
+ self.assertEqual(p.rlimit(psutil.RLIMIT_FSIZE), (soft, hard))
+
+ @unittest.skipUnless(LINUX and RLIMIT_SUPPORT,
+ "only available on Linux >= 2.6.36")
+ def test_rlimit_infinity(self):
+ # First set a limit, then re-set it by specifying INFINITY
+ # and assume we overridden the previous limit.
+ p = psutil.Process()
+ soft, hard = p.rlimit(psutil.RLIMIT_FSIZE)
+ try:
+ p.rlimit(psutil.RLIMIT_FSIZE, (1024, hard))
+ p.rlimit(psutil.RLIMIT_FSIZE, (psutil.RLIM_INFINITY, hard))
+ with open(TESTFN, "wb") as f:
+ f.write(b"X" * 2048)
+ finally:
+ p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard))
+ self.assertEqual(p.rlimit(psutil.RLIMIT_FSIZE), (soft, hard))
+
+ @unittest.skipUnless(LINUX and RLIMIT_SUPPORT,
+ "only available on Linux >= 2.6.36")
+ def test_rlimit_infinity_value(self):
+ # RLIMIT_FSIZE should be RLIM_INFINITY, which will be a really
+ # big number on a platform with large file support. On these
+ # platforms we need to test that the get/setrlimit functions
+ # properly convert the number to a C long long and that the
+ # conversion doesn't raise an error.
+ p = psutil.Process()
+ soft, hard = p.rlimit(psutil.RLIMIT_FSIZE)
+ self.assertEqual(psutil.RLIM_INFINITY, hard)
+ p.rlimit(psutil.RLIMIT_FSIZE, (soft, hard))
def test_num_threads(self):
# on certain platforms such as Linux we might test for exact
@@ -1496,7 +1697,7 @@ class TestProcess(unittest.TestCase):
self.assertEqual(exe.replace(ver, ''), PYTHON.replace(ver, ''))
def test_cmdline(self):
- cmdline = [PYTHON, "-c", "import time; time.sleep(2)"]
+ cmdline = [PYTHON, "-c", "import time; time.sleep(60)"]
sproc = get_test_subprocess(cmdline, wait=True)
self.assertEqual(' '.join(psutil.Process(sproc.pid).cmdline()),
' '.join(cmdline))
@@ -1507,6 +1708,39 @@ class TestProcess(unittest.TestCase):
pyexe = os.path.basename(os.path.realpath(sys.executable)).lower()
assert pyexe.startswith(name), (pyexe, name)
+ @unittest.skipUnless(POSIX, "posix only")
+ # TODO: add support for other compilers
+ @unittest.skipUnless(which("gcc"), "gcc not available")
+ def test_prog_w_funky_name(self):
+ # Test that name(), exe() and cmdline() correctly handle programs
+ # with funky chars such as spaces and ")", see:
+ # https://github.com/giampaolo/psutil/issues/628
+ # funky_path = os.path.join(tempfile.gettempdir(), "foo bar )")
+ if OSX:
+ tmpdir = "/private/tmp"
+ else:
+ tmpdir = "/tmp"
+ fd, funky_path = tempfile.mkstemp(
+ prefix='psutil-', suffix='foo bar )', dir=tmpdir)
+ os.close(fd)
+ fd, c_file = tempfile.mkstemp(
+ prefix='psutil-', suffix='.c', dir=tmpdir)
+ os.close(fd)
+ self.addCleanup(safe_remove, c_file)
+ self.addCleanup(safe_remove, funky_path)
+ with open(c_file, "w") as f:
+ f.write("void main() { pause(); }")
+ subprocess.check_call(["gcc", c_file, "-o", funky_path])
+ sproc = get_test_subprocess(
+ [funky_path, "arg1", "arg2", "", "arg3", ""])
+ p = psutil.Process(sproc.pid)
+ # ...in order to try to prevent occasional failures on travis
+ wait_for_pid(p.pid)
+ self.assertEqual(p.name(), os.path.basename(funky_path))
+ self.assertEqual(p.exe(), funky_path)
+ self.assertEqual(
+ p.cmdline(), [funky_path, "arg1", "arg2", "", "arg3", ""])
+
@unittest.skipUnless(POSIX, 'posix only')
def test_uids(self):
p = psutil.Process()
@@ -1538,7 +1772,12 @@ class TestProcess(unittest.TestCase):
self.assertRaises(TypeError, p.nice, "str")
if WINDOWS:
try:
- self.assertEqual(p.nice(), psutil.NORMAL_PRIORITY_CLASS)
+ init = p.nice()
+ if sys.version_info > (3, 4):
+ self.assertIsInstance(init, enum.IntEnum)
+ else:
+ self.assertIsInstance(init, int)
+ self.assertEqual(init, psutil.NORMAL_PRIORITY_CLASS)
p.nice(psutil.HIGH_PRIORITY_CLASS)
self.assertEqual(p.nice(), psutil.HIGH_PRIORITY_CLASS)
p.nice(psutil.NORMAL_PRIORITY_CLASS)
@@ -1573,6 +1812,11 @@ class TestProcess(unittest.TestCase):
if POSIX:
import pwd
self.assertEqual(p.username(), pwd.getpwuid(os.getuid()).pw_name)
+ with mock.patch("psutil.pwd.getpwuid",
+ side_effect=KeyError) as fun:
+ p.username() == str(p.uids().real)
+ assert fun.called
+
elif WINDOWS and 'USERNAME' in os.environ:
expected_username = os.environ['USERNAME']
expected_domain = os.environ['USERDOMAIN']
@@ -1588,7 +1832,7 @@ class TestProcess(unittest.TestCase):
self.assertEqual(p.cwd(), os.getcwd())
def test_cwd_2(self):
- cmd = [PYTHON, "-c", "import os, time; os.chdir('..'); time.sleep(2)"]
+ cmd = [PYTHON, "-c", "import os, time; os.chdir('..'); time.sleep(60)"]
sproc = get_test_subprocess(cmd, wait=True)
p = psutil.Process(sproc.pid)
call_until(p.cwd, "ret == os.path.dirname(os.getcwd())")
@@ -1601,6 +1845,7 @@ class TestProcess(unittest.TestCase):
initial = p.cpu_affinity()
if hasattr(os, "sched_getaffinity"):
self.assertEqual(initial, list(os.sched_getaffinity(p.pid)))
+ self.assertEqual(len(initial), len(set(initial)))
all_cpus = list(range(len(psutil.cpu_percent(percpu=True))))
# setting on travis doesn't seem to work (always return all
# CPUs on get):
@@ -1620,16 +1865,25 @@ class TestProcess(unittest.TestCase):
#
self.assertRaises(TypeError, p.cpu_affinity, 1)
p.cpu_affinity(initial)
+ # it should work with all iterables, not only lists
+ p.cpu_affinity(set(all_cpus))
+ p.cpu_affinity(tuple(all_cpus))
invalid_cpu = [len(psutil.cpu_times(percpu=True)) + 10]
self.assertRaises(ValueError, p.cpu_affinity, invalid_cpu)
self.assertRaises(ValueError, p.cpu_affinity, range(10000, 11000))
+ self.assertRaises(TypeError, p.cpu_affinity, [0, "1"])
+ # TODO
+ @unittest.skipIf(BSD, "broken on BSD, see #595")
+ @unittest.skipIf(APPVEYOR,
+ "can't find any process file on Appveyor")
def test_open_files(self):
# current process
p = psutil.Process()
files = p.open_files()
self.assertFalse(TESTFN in files)
with open(TESTFN, 'w'):
+ # give the kernel some time to see the new file
call_until(p.open_files, "len(ret) != %i" % len(files))
filenames = [x.path for x in p.open_files()]
self.assertIn(TESTFN, filenames)
@@ -1637,7 +1891,7 @@ class TestProcess(unittest.TestCase):
assert os.path.isfile(file), file
# another process
- cmdline = "import time; f = open(r'%s', 'r'); time.sleep(2);" % TESTFN
+ cmdline = "import time; f = open(r'%s', 'r'); time.sleep(60);" % TESTFN
sproc = get_test_subprocess([PYTHON, "-c", cmdline], wait=True)
p = psutil.Process(sproc.pid)
@@ -1651,6 +1905,10 @@ class TestProcess(unittest.TestCase):
for file in filenames:
assert os.path.isfile(file), file
+ # TODO
+ @unittest.skipIf(BSD, "broken on BSD, see #595")
+ @unittest.skipIf(APPVEYOR,
+ "can't find any process file on Appveyor")
def test_open_files2(self):
# test fd and path fields
with open(TESTFN, 'w') as fileobj:
@@ -1683,185 +1941,163 @@ class TestProcess(unittest.TestCase):
proc_cons = [pconn(*[-1] + list(x[1:])) for x in proc_cons]
self.assertEqual(sorted(proc_cons), sorted(sys_cons))
- def test_connection_constants(self):
- ints = []
- strs = []
- for name in dir(psutil):
- if name.startswith('CONN_'):
- num = getattr(psutil, name)
- str_ = str(num)
- assert str_.isupper(), str_
- assert str_ not in strs, str_
- assert num not in ints, num
- ints.append(num)
- strs.append(str_)
- if SUNOS:
- psutil.CONN_IDLE
- psutil.CONN_BOUND
- if WINDOWS:
- psutil.CONN_DELETE_TCB
-
+ @skip_on_access_denied(only_if=OSX)
def test_connections(self):
- arg = "import socket, time;" \
- "s = socket.socket();" \
- "s.bind(('127.0.0.1', 0));" \
- "s.listen(1);" \
- "conn, addr = s.accept();" \
- "time.sleep(2);"
- sproc = get_test_subprocess([PYTHON, "-c", arg])
- p = psutil.Process(sproc.pid)
- cons = call_until(p.connections, "len(ret) != 0")
- self.assertEqual(len(cons), 1)
- con = cons[0]
- check_connection(con)
- self.assertEqual(con.family, AF_INET)
- self.assertEqual(con.type, SOCK_STREAM)
- self.assertEqual(con.status, psutil.CONN_LISTEN, con.status)
- self.assertEqual(con.laddr[0], '127.0.0.1')
- self.assertEqual(con.raddr, ())
- # test positions
- self.assertEqual(con[0], con.fd)
- self.assertEqual(con[1], con.family)
- self.assertEqual(con[2], con.type)
- self.assertEqual(con[3], con.laddr)
- self.assertEqual(con[4], con.raddr)
- self.assertEqual(con[5], con.status)
- # test kind arg
- self.assertRaises(ValueError, p.connections, 'foo')
- # compare against system-wide connections
- self.compare_proc_sys_cons(p.pid, cons)
-
- @unittest.skipUnless(supports_ipv6(), 'IPv6 is not supported')
- def test_connections_ipv6(self):
- with contextlib.closing(socket.socket(AF_INET6, SOCK_STREAM)) as s:
- s.bind(('::1', 0))
- s.listen(1)
- cons = psutil.Process().connections()
- self.assertEqual(len(cons), 1)
- self.assertEqual(cons[0].laddr[0], '::1')
- self.compare_proc_sys_cons(os.getpid(), cons)
-
- @unittest.skipUnless(hasattr(socket, 'AF_UNIX'),
- 'AF_UNIX is not supported')
- def test_connections_unix(self):
- def check(type):
- safe_remove(TESTFN)
- sock = socket.socket(AF_UNIX, type)
- with contextlib.closing(sock):
- sock.bind(TESTFN)
- cons = psutil.Process().connections(kind='unix')
- conn = cons[0]
- check_connection(conn)
- if conn.fd != -1: # != sunos and windows
- self.assertEqual(conn.fd, sock.fileno())
- self.assertEqual(conn.family, AF_UNIX)
- self.assertEqual(conn.type, type)
- self.assertEqual(conn.laddr, TESTFN)
- if not SUNOS:
- # XXX Solaris can't retrieve system-wide UNIX
- # sockets.
- self.compare_proc_sys_cons(os.getpid(), cons)
-
- check(SOCK_STREAM)
- check(SOCK_DGRAM)
-
- @unittest.skipUnless(hasattr(socket, "fromfd"),
- 'socket.fromfd() is not availble')
- @unittest.skipIf(WINDOWS or SUNOS,
- 'connection fd not available on this platform')
- def test_connection_fromfd(self):
- with contextlib.closing(socket.socket()) as sock:
- sock.bind(('localhost', 0))
- sock.listen(1)
- p = psutil.Process()
- for conn in p.connections():
- if conn.fd == sock.fileno():
- break
- else:
- self.fail("couldn't find socket fd")
- dupsock = socket.fromfd(conn.fd, conn.family, conn.type)
- with contextlib.closing(dupsock):
- self.assertEqual(dupsock.getsockname(), conn.laddr)
- self.assertNotEqual(sock.fileno(), dupsock.fileno())
+ def check_conn(proc, conn, family, type, laddr, raddr, status, kinds):
+ all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4",
+ "tcp6", "udp", "udp4", "udp6")
+ check_connection_ntuple(conn)
+ self.assertEqual(conn.family, family)
+ self.assertEqual(conn.type, type)
+ self.assertEqual(conn.laddr, laddr)
+ self.assertEqual(conn.raddr, raddr)
+ self.assertEqual(conn.status, status)
+ for kind in all_kinds:
+ cons = proc.connections(kind=kind)
+ if kind in kinds:
+ self.assertNotEqual(cons, [])
+ else:
+ self.assertEqual(cons, [])
+ # compare against system-wide connections
+ # XXX Solaris can't retrieve system-wide UNIX
+ # sockets.
+ if not SUNOS:
+ self.compare_proc_sys_cons(proc.pid, [conn])
- def test_connections_all(self):
tcp_template = textwrap.dedent("""
- import socket
+ import socket, time
s = socket.socket($family, socket.SOCK_STREAM)
s.bind(('$addr', 0))
s.listen(1)
- conn, addr = s.accept()
+ with open('$testfn', 'w') as f:
+ f.write(str(s.getsockname()[:2]))
+ time.sleep(60)
""")
udp_template = textwrap.dedent("""
import socket, time
s = socket.socket($family, socket.SOCK_DGRAM)
s.bind(('$addr', 0))
- time.sleep(2)
+ with open('$testfn', 'w') as f:
+ f.write(str(s.getsockname()[:2]))
+ time.sleep(60)
""")
from string import Template
+ testfile = os.path.basename(TESTFN)
tcp4_template = Template(tcp_template).substitute(
- family=int(AF_INET), addr="127.0.0.1")
+ family=int(AF_INET), addr="127.0.0.1", testfn=testfile)
udp4_template = Template(udp_template).substitute(
- family=int(AF_INET), addr="127.0.0.1")
+ family=int(AF_INET), addr="127.0.0.1", testfn=testfile)
tcp6_template = Template(tcp_template).substitute(
- family=int(AF_INET6), addr="::1")
+ family=int(AF_INET6), addr="::1", testfn=testfile)
udp6_template = Template(udp_template).substitute(
- family=int(AF_INET6), addr="::1")
+ family=int(AF_INET6), addr="::1", testfn=testfile)
# launch various subprocess instantiating a socket of various
# families and types to enrich psutil results
tcp4_proc = pyrun(tcp4_template)
+ tcp4_addr = eval(wait_for_file(testfile))
udp4_proc = pyrun(udp4_template)
+ udp4_addr = eval(wait_for_file(testfile))
if supports_ipv6():
tcp6_proc = pyrun(tcp6_template)
+ tcp6_addr = eval(wait_for_file(testfile))
udp6_proc = pyrun(udp6_template)
+ udp6_addr = eval(wait_for_file(testfile))
else:
tcp6_proc = None
udp6_proc = None
-
- # check matches against subprocesses just created
- all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4", "tcp6",
- "udp", "udp4", "udp6")
-
- def check_conn(proc, conn, family, type, laddr, raddr, status, kinds):
- self.assertEqual(conn.family, family)
- self.assertEqual(conn.type, type)
- self.assertIn(conn.laddr[0], laddr)
- self.assertEqual(conn.raddr, raddr)
- self.assertEqual(conn.status, status)
- for kind in all_kinds:
- cons = proc.connections(kind=kind)
- if kind in kinds:
- self.assertNotEqual(cons, [])
- else:
- self.assertEqual(cons, [])
+ tcp6_addr = None
+ udp6_addr = None
for p in psutil.Process().children():
cons = p.connections()
+ self.assertEqual(len(cons), 1)
for conn in cons:
# TCP v4
if p.pid == tcp4_proc.pid:
- check_conn(p, conn, AF_INET, SOCK_STREAM, "127.0.0.1", (),
+ check_conn(p, conn, AF_INET, SOCK_STREAM, tcp4_addr, (),
psutil.CONN_LISTEN,
("all", "inet", "inet4", "tcp", "tcp4"))
# UDP v4
elif p.pid == udp4_proc.pid:
- check_conn(p, conn, AF_INET, SOCK_DGRAM, "127.0.0.1", (),
+ check_conn(p, conn, AF_INET, SOCK_DGRAM, udp4_addr, (),
psutil.CONN_NONE,
("all", "inet", "inet4", "udp", "udp4"))
# TCP v6
elif p.pid == getattr(tcp6_proc, "pid", None):
- check_conn(p, conn, AF_INET6, SOCK_STREAM, ("::", "::1"),
- (), psutil.CONN_LISTEN,
+ check_conn(p, conn, AF_INET6, SOCK_STREAM, tcp6_addr, (),
+ psutil.CONN_LISTEN,
("all", "inet", "inet6", "tcp", "tcp6"))
# UDP v6
elif p.pid == getattr(udp6_proc, "pid", None):
- check_conn(p, conn, AF_INET6, SOCK_DGRAM, ("::", "::1"),
- (), psutil.CONN_NONE,
+ check_conn(p, conn, AF_INET6, SOCK_DGRAM, udp6_addr, (),
+ psutil.CONN_NONE,
("all", "inet", "inet6", "udp", "udp6"))
+ @unittest.skipUnless(hasattr(socket, 'AF_UNIX'),
+ 'AF_UNIX is not supported')
+ @skip_on_access_denied(only_if=OSX)
+ def test_connections_unix(self):
+ def check(type):
+ safe_remove(TESTFN)
+ sock = socket.socket(AF_UNIX, type)
+ with contextlib.closing(sock):
+ sock.bind(TESTFN)
+ cons = psutil.Process().connections(kind='unix')
+ conn = cons[0]
+ check_connection_ntuple(conn)
+ if conn.fd != -1: # != sunos and windows
+ self.assertEqual(conn.fd, sock.fileno())
+ self.assertEqual(conn.family, AF_UNIX)
+ self.assertEqual(conn.type, type)
+ self.assertEqual(conn.laddr, TESTFN)
+ if not SUNOS:
+ # XXX Solaris can't retrieve system-wide UNIX
+ # sockets.
+ self.compare_proc_sys_cons(os.getpid(), cons)
+
+ check(SOCK_STREAM)
+ check(SOCK_DGRAM)
+
+ @unittest.skipUnless(hasattr(socket, "fromfd"),
+ 'socket.fromfd() is not availble')
+ @unittest.skipIf(WINDOWS or SUNOS,
+ 'connection fd not available on this platform')
+ def test_connection_fromfd(self):
+ with contextlib.closing(socket.socket()) as sock:
+ sock.bind(('localhost', 0))
+ sock.listen(1)
+ p = psutil.Process()
+ for conn in p.connections():
+ if conn.fd == sock.fileno():
+ break
+ else:
+ self.fail("couldn't find socket fd")
+ dupsock = socket.fromfd(conn.fd, conn.family, conn.type)
+ with contextlib.closing(dupsock):
+ self.assertEqual(dupsock.getsockname(), conn.laddr)
+ self.assertNotEqual(sock.fileno(), dupsock.fileno())
+
+ def test_connection_constants(self):
+ ints = []
+ strs = []
+ for name in dir(psutil):
+ if name.startswith('CONN_'):
+ num = getattr(psutil, name)
+ str_ = str(num)
+ assert str_.isupper(), str_
+ assert str_ not in strs, str_
+ assert num not in ints, num
+ ints.append(num)
+ strs.append(str_)
+ if SUNOS:
+ psutil.CONN_IDLE
+ psutil.CONN_BOUND
+ if WINDOWS:
+ psutil.CONN_DELETE_TCB
+
@unittest.skipUnless(POSIX, 'posix only')
def test_num_fds(self):
p = psutil.Process()
@@ -1915,14 +2151,14 @@ class TestProcess(unittest.TestCase):
# A (parent) -> B (child) -> C (grandchild)
s = "import subprocess, os, sys, time;"
s += "PYTHON = os.path.realpath(sys.executable);"
- s += "cmd = [PYTHON, '-c', 'import time; time.sleep(2);'];"
+ s += "cmd = [PYTHON, '-c', 'import time; time.sleep(60);'];"
s += "subprocess.Popen(cmd);"
- s += "time.sleep(2);"
+ s += "time.sleep(60);"
get_test_subprocess(cmd=[PYTHON, "-c", s])
p = psutil.Process()
self.assertEqual(len(p.children(recursive=False)), 1)
# give the grandchild some time to start
- stop_at = time.time() + 1.5
+ stop_at = time.time() + GLOBAL_TIMEOUT
while time.time() < stop_at:
children = p.children(recursive=True)
if len(children) > 1:
@@ -1974,6 +2210,15 @@ class TestProcess(unittest.TestCase):
if not isinstance(d['connections'], list):
self.assertEqual(d['connections'], 'foo')
+ with mock.patch('psutil.getattr', create=True,
+ side_effect=NotImplementedError):
+ # By default APIs raising NotImplementedError are
+ # supposed to be skipped.
+ self.assertEqual(p.as_dict(), {})
+ # ...unless the user explicitly asked for some attr.
+ with self.assertRaises(NotImplementedError):
+ p.as_dict(attrs=["name"])
+
def test_halfway_terminated_process(self):
# Test that NoSuchProcess exception gets raised in case the
# process dies after we create the Process object.
@@ -1984,50 +2229,62 @@ class TestProcess(unittest.TestCase):
# Refers to Issue #15
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
- p.kill()
+ p.terminate()
p.wait()
+ # if WINDOWS:
+ # wait_for_pid(p.pid)
+ self.assertFalse(p.is_running())
+ # self.assertFalse(p.pid in psutil.pids(), msg="retcode = %s" %
+ # retcode)
excluded_names = ['pid', 'is_running', 'wait', 'create_time']
if LINUX and not RLIMIT_SUPPORT:
excluded_names.append('rlimit')
for name in dir(p):
- if (name.startswith('_')
- or name.startswith('get') # deprecated APIs
- or name.startswith('set') # deprecated APIs
- or name in excluded_names):
+ if (name.startswith('_') or
+ name in excluded_names):
continue
try:
meth = getattr(p, name)
# get/set methods
if name == 'nice':
if POSIX:
- meth(1)
+ ret = meth(1)
else:
- meth(psutil.NORMAL_PRIORITY_CLASS)
+ ret = meth(psutil.NORMAL_PRIORITY_CLASS)
elif name == 'ionice':
- meth()
- meth(2)
+ ret = meth()
+ ret = meth(2)
elif name == 'rlimit':
- meth(psutil.RLIMIT_NOFILE)
- meth(psutil.RLIMIT_NOFILE, (5, 5))
+ ret = meth(psutil.RLIMIT_NOFILE)
+ ret = meth(psutil.RLIMIT_NOFILE, (5, 5))
elif name == 'cpu_affinity':
- meth()
- meth([0])
+ ret = meth()
+ ret = meth([0])
elif name == 'send_signal':
- meth(signal.SIGTERM)
+ ret = meth(signal.SIGTERM)
else:
- meth()
+ ret = meth()
+ except psutil.ZombieProcess:
+ self.fail("ZombieProcess for %r was not supposed to happen" %
+ name)
except psutil.NoSuchProcess:
pass
except NotImplementedError:
pass
else:
- self.fail("NoSuchProcess exception not raised for %r" % name)
-
- self.assertFalse(p.is_running())
+ self.fail(
+ "NoSuchProcess exception not raised for %r, retval=%s" % (
+ name, ret))
@unittest.skipUnless(POSIX, 'posix only')
def test_zombie_process(self):
+ def succeed_or_zombie_p_exc(fun, *args, **kwargs):
+ try:
+ fun(*args, **kwargs)
+ except (psutil.ZombieProcess, psutil.AccessDenied):
+ pass
+
# Note: in this test we'll be creating two sub processes.
# Both of them are supposed to be freed / killed by
# reap_children() as they are attributable to 'us'
@@ -2064,10 +2321,37 @@ class TestProcess(unittest.TestCase):
zproc = psutil.Process(zpid)
# ...and at least its status always be querable
self.assertEqual(zproc.status(), psutil.STATUS_ZOMBIE)
+ # ...and it should be considered 'running'
+ self.assertTrue(zproc.is_running())
+ # ...and as_dict() shouldn't crash
+ zproc.as_dict()
+ if hasattr(zproc, "rlimit"):
+ succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE)
+ succeed_or_zombie_p_exc(zproc.rlimit, psutil.RLIMIT_NOFILE,
+ (5, 5))
+ # set methods
+ succeed_or_zombie_p_exc(zproc.parent)
+ if hasattr(zproc, 'cpu_affinity'):
+ succeed_or_zombie_p_exc(zproc.cpu_affinity, [0])
+ succeed_or_zombie_p_exc(zproc.nice, 0)
+ if hasattr(zproc, 'ionice'):
+ if LINUX:
+ succeed_or_zombie_p_exc(zproc.ionice, 2, 0)
+ else:
+ succeed_or_zombie_p_exc(zproc.ionice, 0) # Windows
+ if hasattr(zproc, 'rlimit'):
+ succeed_or_zombie_p_exc(zproc.rlimit,
+ psutil.RLIMIT_NOFILE, (5, 5))
+ succeed_or_zombie_p_exc(zproc.suspend)
+ succeed_or_zombie_p_exc(zproc.resume)
+ succeed_or_zombie_p_exc(zproc.terminate)
+ succeed_or_zombie_p_exc(zproc.kill)
+
# ...its parent should 'see' it
- descendants = [x.pid for x in psutil.Process().children(
- recursive=True)]
- self.assertIn(zpid, descendants)
+ # edit: not true on BSD and OSX
+ # descendants = [x.pid for x in psutil.Process().children(
+ # recursive=True)]
+ # self.assertIn(zpid, descendants)
# XXX should we also assume ppid be usable? Note: this
# would be an important use case as the only way to get
# rid of a zombie is to kill its parent.
@@ -2076,6 +2360,8 @@ class TestProcess(unittest.TestCase):
self.assertTrue(psutil.pid_exists(zpid))
self.assertIn(zpid, psutil.pids())
self.assertIn(zpid, [x.pid for x in psutil.process_iter()])
+ psutil._pmap = {}
+ self.assertIn(zpid, [x.pid for x in psutil.process_iter()])
finally:
reap_children(search_all=True)
@@ -2095,6 +2381,10 @@ class TestProcess(unittest.TestCase):
except psutil.AccessDenied:
pass
+ self.assertRaisesRegexp(
+ ValueError, "preventing sending signal to process with PID 0",
+ p.send_signal, signal.SIGTERM)
+
self.assertIn(p.ppid(), (0, 1))
# self.assertEqual(p.exe(), "")
p.cmdline()
@@ -2108,7 +2398,6 @@ class TestProcess(unittest.TestCase):
except psutil.AccessDenied:
pass
- # username property
try:
if POSIX:
self.assertEqual(p.username(), 'root')
@@ -2127,7 +2416,7 @@ class TestProcess(unittest.TestCase):
# XXX this test causes a ResourceWarning on Python 3 because
# psutil.__subproc instance doesn't get propertly freed.
# Not sure what to do though.
- cmd = [PYTHON, "-c", "import time; time.sleep(2);"]
+ cmd = [PYTHON, "-c", "import time; time.sleep(60);"]
proc = psutil.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
try:
@@ -2135,6 +2424,7 @@ class TestProcess(unittest.TestCase):
proc.stdin
self.assertTrue(hasattr(proc, 'name'))
self.assertTrue(hasattr(proc, 'stdin'))
+ self.assertTrue(dir(proc))
self.assertRaises(AttributeError, getattr, proc, 'foo')
finally:
proc.kill()
@@ -2169,11 +2459,6 @@ class TestFetchAllProcesses(unittest.TestCase):
for name in dir(psutil.Process):
if name.startswith("_"):
continue
- if name.startswith("get"):
- # deprecated APIs
- continue
- if name.startswith("set_"):
- continue
if name in excluded_names:
continue
attrs.append(name)
@@ -2341,8 +2626,9 @@ class TestFetchAllProcesses(unittest.TestCase):
self.assertTrue(ret >= 0)
def connections(self, ret):
+ self.assertEqual(len(ret), len(set(ret)))
for conn in ret:
- check_connection(conn)
+ check_connection_ntuple(conn)
def cwd(self, ret):
if ret is not None: # BSD may return None
@@ -2414,6 +2700,7 @@ class TestFetchAllProcesses(unittest.TestCase):
# --- Limited user tests
# ===================================================================
+@unittest.skipUnless(POSIX, "UNIX only")
@unittest.skipUnless(hasattr(os, 'getuid') and os.getuid() == 0,
"super user privileges are required")
class LimitedUserTestCase(TestProcess):
@@ -2442,9 +2729,9 @@ class LimitedUserTestCase(TestProcess):
def setUp(self):
safe_remove(TESTFN)
+ TestProcess.setUp(self)
os.setegid(1000)
os.seteuid(1000)
- TestProcess.setUp(self)
def tearDown(self):
os.setegid(self.PROCESS_UID)
@@ -2471,22 +2758,90 @@ class LimitedUserTestCase(TestProcess):
class TestMisc(unittest.TestCase):
"""Misc / generic tests."""
- def test__str__(self):
- sproc = get_test_subprocess()
- p = psutil.Process(sproc.pid)
- self.assertIn(str(sproc.pid), str(p))
- # python shows up as 'Python' in cmdline on OS X so
- # test fails on OS X
- if not OSX:
- self.assertIn(os.path.basename(PYTHON), str(p))
- sproc = get_test_subprocess()
- p = psutil.Process(sproc.pid)
- p.kill()
- p.wait()
- self.assertIn(str(sproc.pid), str(p))
- self.assertIn("terminated", str(p))
-
- def test__eq__(self):
+ def test_process__repr__(self, func=repr):
+ p = psutil.Process()
+ r = func(p)
+ self.assertIn("psutil.Process", r)
+ self.assertIn("pid=%s" % p.pid, r)
+ self.assertIn("name=", r)
+ self.assertIn(p.name(), r)
+ with mock.patch.object(psutil.Process, "name",
+ side_effect=psutil.ZombieProcess(os.getpid())):
+ p = psutil.Process()
+ r = func(p)
+ self.assertIn("pid=%s" % p.pid, r)
+ self.assertIn("zombie", r)
+ self.assertNotIn("name=", r)
+ with mock.patch.object(psutil.Process, "name",
+ side_effect=psutil.NoSuchProcess(os.getpid())):
+ p = psutil.Process()
+ r = func(p)
+ self.assertIn("pid=%s" % p.pid, r)
+ self.assertIn("terminated", r)
+ self.assertNotIn("name=", r)
+ with mock.patch.object(psutil.Process, "name",
+ side_effect=psutil.AccessDenied(os.getpid())):
+ p = psutil.Process()
+ r = func(p)
+ self.assertIn("pid=%s" % p.pid, r)
+ self.assertNotIn("name=", r)
+
+ def test_process__str__(self):
+ self.test_process__repr__(func=str)
+
+ def test_no_such_process__repr__(self, func=repr):
+ self.assertEqual(
+ repr(psutil.NoSuchProcess(321)),
+ "psutil.NoSuchProcess process no longer exists (pid=321)")
+ self.assertEqual(
+ repr(psutil.NoSuchProcess(321, name='foo')),
+ "psutil.NoSuchProcess process no longer exists (pid=321, "
+ "name='foo')")
+ self.assertEqual(
+ repr(psutil.NoSuchProcess(321, msg='foo')),
+ "psutil.NoSuchProcess foo")
+
+ def test_zombie_process__repr__(self, func=repr):
+ self.assertEqual(
+ repr(psutil.ZombieProcess(321)),
+ "psutil.ZombieProcess process still exists but it's a zombie "
+ "(pid=321)")
+ self.assertEqual(
+ repr(psutil.ZombieProcess(321, name='foo')),
+ "psutil.ZombieProcess process still exists but it's a zombie "
+ "(pid=321, name='foo')")
+ self.assertEqual(
+ repr(psutil.ZombieProcess(321, name='foo', ppid=1)),
+ "psutil.ZombieProcess process still exists but it's a zombie "
+ "(pid=321, name='foo', ppid=1)")
+ self.assertEqual(
+ repr(psutil.ZombieProcess(321, msg='foo')),
+ "psutil.ZombieProcess foo")
+
+ def test_access_denied__repr__(self, func=repr):
+ self.assertEqual(
+ repr(psutil.AccessDenied(321)),
+ "psutil.AccessDenied (pid=321)")
+ self.assertEqual(
+ repr(psutil.AccessDenied(321, name='foo')),
+ "psutil.AccessDenied (pid=321, name='foo')")
+ self.assertEqual(
+ repr(psutil.AccessDenied(321, msg='foo')),
+ "psutil.AccessDenied foo")
+
+ def test_timeout_expired__repr__(self, func=repr):
+ self.assertEqual(
+ repr(psutil.TimeoutExpired(321)),
+ "psutil.TimeoutExpired timeout after 321 seconds")
+ self.assertEqual(
+ repr(psutil.TimeoutExpired(321, pid=111)),
+ "psutil.TimeoutExpired timeout after 321 seconds (pid=111)")
+ self.assertEqual(
+ repr(psutil.TimeoutExpired(321, pid=111, name='foo')),
+ "psutil.TimeoutExpired timeout after 321 seconds "
+ "(pid=111, name='foo')")
+
+ def test_process__eq__(self):
p1 = psutil.Process()
p2 = psutil.Process()
self.assertEqual(p1, p2)
@@ -2494,12 +2849,13 @@ class TestMisc(unittest.TestCase):
self.assertNotEqual(p1, p2)
self.assertNotEqual(p1, 'foo')
- def test__hash__(self):
+ def test_process__hash__(self):
s = set([psutil.Process(), psutil.Process()])
self.assertEqual(len(s), 1)
def test__all__(self):
- for name in dir(psutil):
+ dir_psutil = dir(psutil)
+ for name in dir_psutil:
if name in ('callable', 'error', 'namedtuple',
'long', 'test', 'NUM_CPUS', 'BOOT_TIME',
'TOTAL_PHYMEM'):
@@ -2516,6 +2872,17 @@ class TestMisc(unittest.TestCase):
'deprecated' not in fun.__doc__.lower()):
self.fail('%r not in psutil.__all__' % name)
+ # Import 'star' will break if __all__ is inconsistent, see:
+ # https://github.com/giampaolo/psutil/issues/656
+ # Can't do `from psutil import *` as it won't work on python 3
+ # so we simply iterate over __all__.
+ for name in psutil.__all__:
+ self.assertIn(name, dir_psutil)
+
+ def test_version(self):
+ self.assertEqual('.'.join([str(x) for x in psutil.version_info]),
+ psutil.__version__)
+
def test_memoize(self):
from psutil._common import memoize
@@ -2553,6 +2920,23 @@ class TestMisc(unittest.TestCase):
# docstring
self.assertEqual(foo.__doc__, "foo docstring")
+ def test_isfile_strict(self):
+ from psutil._common import isfile_strict
+ this_file = os.path.abspath(__file__)
+ assert isfile_strict(this_file)
+ assert not isfile_strict(os.path.dirname(this_file))
+ with mock.patch('psutil._common.os.stat',
+ side_effect=OSError(errno.EPERM, "foo")):
+ self.assertRaises(OSError, isfile_strict, this_file)
+ with mock.patch('psutil._common.os.stat',
+ side_effect=OSError(errno.EACCES, "foo")):
+ self.assertRaises(OSError, isfile_strict, this_file)
+ with mock.patch('psutil._common.os.stat',
+ side_effect=OSError(errno.EINVAL, "foo")):
+ assert not isfile_strict(this_file)
+ with mock.patch('psutil._common.stat.S_ISREG', return_value=False):
+ assert not isfile_strict(this_file)
+
def test_serialization(self):
def check(ret):
if json is not None:
@@ -2570,11 +2954,36 @@ class TestMisc(unittest.TestCase):
if LINUX and not os.path.exists('/proc/diskstats'):
pass
else:
- check(psutil.disk_io_counters())
+ if not APPVEYOR:
+ check(psutil.disk_io_counters())
check(psutil.disk_partitions())
check(psutil.disk_usage(os.getcwd()))
check(psutil.users())
+ def test_setup_script(self):
+ here = os.path.abspath(os.path.dirname(__file__))
+ setup_py = os.path.realpath(os.path.join(here, '..', 'setup.py'))
+ module = imp.load_source('setup', setup_py)
+ self.assertRaises(SystemExit, module.setup)
+ self.assertEqual(module.get_version(), psutil.__version__)
+
+ def test_ad_on_process_creation(self):
+ # We are supposed to be able to instantiate Process also in case
+ # of zombie processes or access denied.
+ with mock.patch.object(psutil.Process, 'create_time',
+ side_effect=psutil.AccessDenied) as meth:
+ psutil.Process()
+ assert meth.called
+ with mock.patch.object(psutil.Process, 'create_time',
+ side_effect=psutil.ZombieProcess(1)) as meth:
+ psutil.Process()
+ assert meth.called
+ with mock.patch.object(psutil.Process, 'create_time',
+ side_effect=ValueError) as meth:
+ with self.assertRaises(ValueError):
+ psutil.Process()
+ assert meth.called
+
# ===================================================================
# --- Example script tests
@@ -2613,6 +3022,14 @@ class TestExampleScripts(unittest.TestCase):
self.fail('no test defined for %r script'
% os.path.join(EXAMPLES_DIR, name))
+ @unittest.skipUnless(POSIX, "UNIX only")
+ def test_executable(self):
+ for name in os.listdir(EXAMPLES_DIR):
+ if name.endswith('.py'):
+ path = os.path.join(EXAMPLES_DIR, name)
+ if not stat.S_IXUSR & os.stat(path)[stat.ST_MODE]:
+ self.fail('%r is not executable' % path)
+
def test_disk_usage(self):
self.assert_stdout('disk_usage.py')
@@ -2625,6 +3042,7 @@ class TestExampleScripts(unittest.TestCase):
def test_process_detail(self):
self.assert_stdout('process_detail.py')
+ @unittest.skipIf(APPVEYOR, "can't find users on Appveyor")
def test_who(self):
self.assert_stdout('who.py')
@@ -2637,6 +3055,10 @@ class TestExampleScripts(unittest.TestCase):
def test_netstat(self):
self.assert_stdout('netstat.py')
+ @unittest.skipIf(TRAVIS, "permission denied on travis")
+ def test_ifconfig(self):
+ self.assert_stdout('ifconfig.py')
+
def test_pmap(self):
self.assert_stdout('pmap.py', args=str(os.getpid()))
@@ -2665,7 +3087,73 @@ class TestExampleScripts(unittest.TestCase):
self.assertIn(str(os.getpid()), output)
-def test_main():
+class TestUnicode(unittest.TestCase):
+ # See: https://github.com/giampaolo/psutil/issues/655
+
+ @classmethod
+ def setUpClass(cls):
+ with tempfile.NamedTemporaryFile() as f:
+ tdir = os.path.dirname(f.name)
+ cls.uexe = os.path.realpath(os.path.join(tdir, "psutil-è.exe"))
+ shutil.copyfile(sys.executable, cls.uexe)
+ if POSIX:
+ st = os.stat(cls.uexe)
+ os.chmod(cls.uexe, st.st_mode | stat.S_IEXEC)
+
+ @classmethod
+ def tearDownClass(cls):
+ if not APPVEYOR:
+ safe_remove(cls.uexe)
+
+ def setUp(self):
+ reap_children()
+
+ tearDown = setUp
+
+ def test_proc_exe(self):
+ subp = get_test_subprocess(cmd=[self.uexe])
+ p = psutil.Process(subp.pid)
+ self.assertIsInstance(p.name(), str)
+ self.assertEqual(os.path.basename(p.name()), "psutil-è.exe")
+
+ def test_proc_name(self):
+ subp = get_test_subprocess(cmd=[self.uexe])
+ if WINDOWS:
+ from psutil._pswindows import py2_strencode
+ name = py2_strencode(psutil._psplatform.cext.proc_name(subp.pid))
+ else:
+ name = psutil.Process(subp.pid).name()
+ self.assertEqual(name, "psutil-è.exe")
+
+ def test_proc_cmdline(self):
+ subp = get_test_subprocess(cmd=[self.uexe])
+ p = psutil.Process(subp.pid)
+ self.assertIsInstance("".join(p.cmdline()), str)
+ self.assertEqual(p.cmdline(), [self.uexe])
+
+ def test_proc_cwd(self):
+ tdir = os.path.realpath(tempfile.mkdtemp(prefix="psutil-è-"))
+ self.addCleanup(safe_rmdir, tdir)
+ with chdir(tdir):
+ p = psutil.Process()
+ self.assertIsInstance(p.cwd(), str)
+ self.assertEqual(p.cwd(), tdir)
+
+ @unittest.skipIf(APPVEYOR, "")
+ def test_proc_open_files(self):
+ p = psutil.Process()
+ start = set(p.open_files())
+ with open(self.uexe, 'rb'):
+ new = set(p.open_files())
+ path = (new - start).pop().path
+ self.assertIsInstance(path, str)
+ if WINDOWS:
+ self.assertEqual(path.lower(), self.uexe.lower())
+ else:
+ self.assertEqual(path, self.uexe)
+
+
+def main():
tests = []
test_suite = unittest.TestSuite()
tests.append(TestSystemAPIs)
@@ -2674,6 +3162,7 @@ def test_main():
tests.append(TestMisc)
tests.append(TestExampleScripts)
tests.append(LimitedUserTestCase)
+ tests.append(TestUnicode)
if POSIX:
from _posix import PosixSpecificTestCase
@@ -2702,5 +3191,5 @@ def test_main():
return result.wasSuccessful()
if __name__ == '__main__':
- if not test_main():
+ if not main():
sys.exit(1)
diff --git a/tox.ini b/tox.ini
index 8f6d7f94..d80dd174 100644
--- a/tox.ini
+++ b/tox.ini
@@ -9,16 +9,24 @@ envlist = py26, py27, py32, py33, py34
[testenv]
deps =
- pytest
flake8
+ pytest
+ py26: ipaddress
+ py26: mock==1.0.1
+ py26: unittest2
+ py27: ipaddress
+ py27: mock
+ py32: ipaddress
+ py32: mock
+ py33: ipaddress
+
setenv =
PYTHONPATH = {toxinidir}/test
+
commands =
py.test {posargs}
- flake8 --exclude=build,.tox,.git
+ git ls-files | grep \\.py$ | xargs flake8
-[testenv:py26]
-deps =
- flake8
- pytest
- unittest2
+# suppress "WARNING: 'git' command found but not installed in testenv
+whitelist_externals = git
+usedevelop = True