forked from mirrors/gecko-dev
Backed out 4 changesets (bug 1666345, bug 1661624, bug 1667152, bug 1666347) for causing mochitest failures CLOSED TREE
Backed out changeset 8ce536574e74 (bug 1666347) Backed out changeset 7cc5b13a3bf6 (bug 1666345) Backed out changeset e112876ba18b (bug 1661624) Backed out changeset 0f03ce337449 (bug 1667152)
This commit is contained in:
parent
9d8148ba43
commit
f24bd4fcff
189 changed files with 74281 additions and 78 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -90,6 +90,12 @@ parser/html/java/translator.jar
|
|||
# Local Gradle configuration properties.
|
||||
/local.properties
|
||||
|
||||
# Python virtualenv artifacts.
|
||||
third_party/python/psutil/**/*.so
|
||||
third_party/python/psutil/**/*.pyd
|
||||
third_party/python/psutil/build/
|
||||
third_party/python/psutil/tmp/
|
||||
|
||||
# Ignore chrome.manifest files from the devtools loader
|
||||
devtools/client/chrome.manifest
|
||||
devtools/shared/chrome.manifest
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ _OPT\.OBJ/
|
|||
# Local Gradle configuration properties.
|
||||
^local.properties$
|
||||
|
||||
# Python stuff installed at build time.
|
||||
^third_party/python/psutil/.*\.so
|
||||
^third_party/python/psutil/.*\.pyd
|
||||
^third_party/python/psutil/build/
|
||||
^third_party/python/psutil/tmp/
|
||||
|
||||
# Git repositories
|
||||
.git/
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ mozilla.pth:third_party/python/pyrsistent
|
|||
mozilla.pth:third_party/python/python-hglib
|
||||
mozilla.pth:third_party/python/pluggy
|
||||
mozilla.pth:third_party/python/jsmin
|
||||
!windows:optional:setup.py:third_party/python/psutil:build_ext:--inplace
|
||||
!windows:mozilla.pth:third_party/python/psutil
|
||||
windows:mozilla.pth:third_party/python/psutil-cp27-none-win_amd64
|
||||
mozilla.pth:third_party/python/pylru
|
||||
mozilla.pth:third_party/python/pystache
|
||||
python2:mozilla.pth:third_party/python/PyYAML/lib
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import json
|
|||
import math
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import uuid
|
||||
|
|
@ -198,13 +197,6 @@ def bootstrap(topsrcdir, mozilla_dir=None):
|
|||
print("You are running Python", platform.python_version())
|
||||
sys.exit(1)
|
||||
|
||||
# This directory was deleted in bug 1666345, but there may be some ignored
|
||||
# files here. We can safely just delete it for the user so they don't have
|
||||
# to clean the repo themselves.
|
||||
deleted_dir = os.path.join(topsrcdir, "third_party", "python", "psutil")
|
||||
if os.path.exists(deleted_dir):
|
||||
shutil.rmtree(deleted_dir)
|
||||
|
||||
# Global build system and mach state is stored in a central directory. By
|
||||
# default, this is ~/.mozbuild. However, it can be defined via an
|
||||
# environment variable. We detect first run (by lack of this directory
|
||||
|
|
@ -511,8 +503,7 @@ def _finalize_telemetry_glean(telemetry, is_bootstrap, success):
|
|||
|
||||
has_psutil, logical_cores, physical_cores, memory_total = get_psutil_stats()
|
||||
if has_psutil:
|
||||
# psutil may not be available (we allow `mach create-mach-environment`
|
||||
# to fail to install it).
|
||||
# psutil may not be available if a successful build hasn't occurred yet.
|
||||
system_metrics.logical_cores.add(logical_cores)
|
||||
system_metrics.physical_cores.add(physical_cores)
|
||||
if memory_total is not None:
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ from mach.decorators import (
|
|||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
from mach.util import UserError
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
|
@ -54,15 +53,8 @@ class MachCommands(MachCommandBase):
|
|||
default=False,
|
||||
help="Use ipython instead of the default Python REPL.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--requirements",
|
||||
default=None,
|
||||
help="Install this requirements file before running Python",
|
||||
)
|
||||
@CommandArgument("args", nargs=argparse.REMAINDER)
|
||||
def python(
|
||||
self, no_virtualenv, no_activate, exec_file, ipython, requirements, args
|
||||
):
|
||||
def python(self, no_virtualenv, no_activate, exec_file, ipython, args):
|
||||
# Avoid logging the command
|
||||
self.log_manager.terminal_handler.setLevel(logging.CRITICAL)
|
||||
|
||||
|
|
@ -71,9 +63,6 @@ class MachCommands(MachCommandBase):
|
|||
"PYTHONDONTWRITEBYTECODE": str("1"),
|
||||
}
|
||||
|
||||
if requirements and no_virtualenv:
|
||||
raise UserError("Cannot pass both --requirements and --no-virtualenv.")
|
||||
|
||||
if no_virtualenv:
|
||||
from mach_bootstrap import mach_sys_path
|
||||
|
||||
|
|
@ -84,10 +73,6 @@ class MachCommands(MachCommandBase):
|
|||
if not no_activate:
|
||||
self.virtualenv_manager.activate()
|
||||
python_path = self.virtualenv_manager.python_path
|
||||
if requirements:
|
||||
self.virtualenv_manager.install_pip_requirements(
|
||||
requirements, require_hashes=False
|
||||
)
|
||||
|
||||
if exec_file:
|
||||
exec(open(exec_file).read())
|
||||
|
|
|
|||
|
|
@ -2097,16 +2097,6 @@ class CreateMachEnvironment(MachCommandBase):
|
|||
|
||||
manager.install_pip_package("zstandard>=0.9.0,<=0.13.0")
|
||||
|
||||
try:
|
||||
# `mach` can handle it perfectly fine if `psutil` is missing, so
|
||||
# there's no reason to freak out in this case.
|
||||
manager.install_pip_package("psutil==5.7.0")
|
||||
except subprocess.CalledProcessError:
|
||||
print(
|
||||
"Could not install psutil, so telemetry will be missing some "
|
||||
"data. Continuing."
|
||||
)
|
||||
|
||||
if not PY2:
|
||||
# This can fail on some platforms. See
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=1660120
|
||||
|
|
|
|||
|
|
@ -152,6 +152,12 @@ Please commit or stash these changes before vendoring, or re-run with `--ignore-
|
|||
description="Vendor Python packages from pypi.org into third_party/python. "
|
||||
"Some extra files like docs and tests will automatically be excluded.",
|
||||
)
|
||||
@CommandArgument(
|
||||
"--with-windows-wheel",
|
||||
action="store_true",
|
||||
help="Vendor a wheel for Windows along with the source package",
|
||||
default=False,
|
||||
)
|
||||
@CommandArgument(
|
||||
"--keep-extra-files",
|
||||
action="store_true",
|
||||
|
|
|
|||
57
python/mozbuild/mozbuild/vendor/vendor_python.py
vendored
57
python/mozbuild/mozbuild/vendor/vendor_python.py
vendored
|
|
@ -16,13 +16,17 @@ from mozpack.files import FileFinder
|
|||
|
||||
|
||||
class VendorPython(MozbuildObject):
|
||||
def vendor(self, packages=None, keep_extra_files=False):
|
||||
def vendor(self, packages=None, with_windows_wheel=False, keep_extra_files=False):
|
||||
self.populate_logger()
|
||||
self.log_manager.enable_unstructured()
|
||||
|
||||
vendor_dir = mozpath.join(self.topsrcdir, os.path.join("third_party", "python"))
|
||||
|
||||
packages = packages or []
|
||||
if with_windows_wheel and len(packages) != 1:
|
||||
raise Exception(
|
||||
"--with-windows-wheel is only supported for a single package!"
|
||||
)
|
||||
|
||||
self.activate_virtualenv()
|
||||
pip_compile = os.path.join(self.virtualenv_manager.bin_path, "pip-compile")
|
||||
|
|
@ -71,6 +75,30 @@ class VendorPython(MozbuildObject):
|
|||
"--disable-pip-version-check",
|
||||
]
|
||||
)
|
||||
if with_windows_wheel:
|
||||
# This is hardcoded to CPython 2.7 for win64, which is good
|
||||
# enough for what we need currently. If we need psutil for Python 3
|
||||
# in the future that could be added here as well.
|
||||
self.virtualenv_manager._run_pip(
|
||||
[
|
||||
"download",
|
||||
"--dest",
|
||||
tmp,
|
||||
"--no-deps",
|
||||
"--only-binary",
|
||||
":all:",
|
||||
"--platform",
|
||||
"win_amd64",
|
||||
"--implementation",
|
||||
"cp",
|
||||
"--python-version",
|
||||
"27",
|
||||
"--abi",
|
||||
"none",
|
||||
"--disable-pip-version-check",
|
||||
packages[0],
|
||||
]
|
||||
)
|
||||
self._extract(tmp, vendor_dir, keep_extra_files)
|
||||
|
||||
shutil.copyfile(tmpspec_absolute, spec)
|
||||
|
|
@ -119,14 +147,27 @@ class VendorPython(MozbuildObject):
|
|||
finder = FileFinder(src)
|
||||
for path, _ in finder.find("*"):
|
||||
base, ext = os.path.splitext(path)
|
||||
# packages extract into package-version directory name and we strip the version
|
||||
tld = mozfile.extract(os.path.join(finder.base, path), dest, ignore=ignore)[
|
||||
0
|
||||
]
|
||||
target = os.path.join(dest, tld.rpartition("-")[0])
|
||||
mozfile.remove(target) # remove existing version of vendored package
|
||||
mozfile.move(tld, target)
|
||||
if ext == ".whl":
|
||||
# Wheels would extract into a directory with the name of the package, but
|
||||
# we want the platform signifiers, minus the version number.
|
||||
# Wheel filenames look like:
|
||||
# {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}
|
||||
bits = base.split("-")
|
||||
|
||||
# Remove the version number.
|
||||
bits.pop(1)
|
||||
target = os.path.join(dest, "-".join(bits))
|
||||
mozfile.remove(target) # remove existing version of vendored package
|
||||
os.mkdir(target)
|
||||
mozfile.extract(os.path.join(finder.base, path), target, ignore=ignore)
|
||||
else:
|
||||
# packages extract into package-version directory name and we strip the version
|
||||
tld = mozfile.extract(
|
||||
os.path.join(finder.base, path), dest, ignore=ignore
|
||||
)[0]
|
||||
target = os.path.join(dest, tld.rpartition("-")[0])
|
||||
mozfile.remove(target) # remove existing version of vendored package
|
||||
mozfile.move(tld, target)
|
||||
# If any files inside the vendored package were symlinks, turn them into normal files
|
||||
# because hg.mozilla.org forbids symlinks in the repository.
|
||||
link_finder = FileFinder(target)
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ jobs:
|
|||
- deb8-mercurial
|
||||
- deb8-python3.6
|
||||
- deb8-python3-defaults
|
||||
- deb8-python-psutil
|
||||
- deb8-python-zstandard
|
||||
- deb8-xz-utils
|
||||
deb8-toolchain-build:
|
||||
|
|
|
|||
|
|
@ -207,20 +207,6 @@ jobs:
|
|||
sha256: 9727dcb3d6b655e4f2a92110f5db076a490aa50b739804be239905ecff3aacc8
|
||||
patch: gdb-jessie.diff
|
||||
|
||||
deb8-python-psutil:
|
||||
description: "python-psutil rebuild for python 3.6 in Debian jessie"
|
||||
treeherder:
|
||||
symbol: Deb8(python-psutil)
|
||||
run:
|
||||
using: debian-package
|
||||
dsc:
|
||||
url: http://snapshot.debian.org/archive/debian/20150815T034233Z/pool/main/p/python-psutil/python-psutil_2.2.1-3.dsc
|
||||
sha256: b47d1fc92094dfd5525cff7d0af5855f7c5335ade9de4c0e738ed490aa5bee7c
|
||||
packages:
|
||||
- deb8-dh-python
|
||||
- deb8-python3.6
|
||||
- deb8-python3-defaults
|
||||
|
||||
deb8-python-zstandard:
|
||||
description: "python-zstandard for Debian jessie"
|
||||
treeherder:
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@ RUN /usr/local/sbin/setup_packages.sh $TASKCLUSTER_ROOT_URL $DOCKER_IMAGE_PACKAG
|
|||
python3-minimal \
|
||||
python-zstandard \
|
||||
python3-zstandard \
|
||||
python-psutil \
|
||||
python3-psutil \
|
||||
vim-tiny \
|
||||
xz-utils
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2.2.2
|
||||
2.2.1
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ apt-get install -y --force-yes --no-install-recommends \
|
|||
python \
|
||||
sudo \
|
||||
python3 \
|
||||
python3-yaml \
|
||||
python-psutil \
|
||||
python3-psutil
|
||||
python3-yaml
|
||||
|
||||
BUILD=/root/build
|
||||
mkdir "$BUILD"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ RUN apt-get update && \
|
|||
libucl1 \
|
||||
libxml2 \
|
||||
patch \
|
||||
python3-dev \
|
||||
p7zip-full \
|
||||
scons \
|
||||
tar \
|
||||
|
|
|
|||
|
|
@ -144,9 +144,6 @@ pip install virtualenv==15.2.0
|
|||
pip install zstandard==0.13.0
|
||||
pip3 install zstandard==0.13.0
|
||||
|
||||
pip install psutil==5.7.0
|
||||
pip3 install psutil==5.7.0
|
||||
|
||||
# Build a list of packages to purge from the image.
|
||||
apt_packages=()
|
||||
apt_packages+=('*cheese*')
|
||||
|
|
|
|||
|
|
@ -99,10 +99,7 @@ fi
|
|||
|
||||
cd /builds/worker
|
||||
|
||||
$GECKO_PATH/mach python \
|
||||
--requirements $GECKO_PATH/taskcluster/scripts/builder/requirements.txt \
|
||||
-- \
|
||||
$GECKO_PATH/testing/${MOZHARNESS_SCRIPT} \
|
||||
$GECKO_PATH/mach python $GECKO_PATH/testing/${MOZHARNESS_SCRIPT} \
|
||||
${config_path_cmds} \
|
||||
${config_cmds} \
|
||||
$actions \
|
||||
|
|
|
|||
|
|
@ -114,10 +114,7 @@ fi
|
|||
|
||||
cd /builds/worker
|
||||
|
||||
$GECKO_PATH/mach python \
|
||||
--requirements $GECKO_PATH/taskcluster/scripts/builder/requirements.txt \
|
||||
-- \
|
||||
$GECKO_PATH/testing/${MOZHARNESS_SCRIPT} \
|
||||
$GECKO_PATH/mach python $GECKO_PATH/testing/${MOZHARNESS_SCRIPT} \
|
||||
${config_path_cmds} \
|
||||
${config_cmds} \
|
||||
$debug_flag \
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
psutil==5.7.0
|
||||
29
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/LICENSE
vendored
Normal file
29
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola'
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the psutil authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
582
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/METADATA
vendored
Normal file
582
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/METADATA
vendored
Normal file
|
|
@ -0,0 +1,582 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: psutil
|
||||
Version: 5.7.0
|
||||
Summary: Cross-platform lib for process and system monitoring in Python.
|
||||
Home-page: https://github.com/giampaolo/psutil
|
||||
Author: Giampaolo Rodola
|
||||
Author-email: g.rodola@gmail.com
|
||||
License: BSD
|
||||
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit,smem,performance,metrics,agent,observability
|
||||
Platform: Platform Independent
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Environment :: Win32 (MS Windows)
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: MacOS :: MacOS X
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows 7
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows 8
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows 8.1
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows Server 2003
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows Server 2008
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows Vista
|
||||
Classifier: Operating System :: Microsoft
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Operating System :: POSIX :: AIX
|
||||
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
|
||||
Classifier: Operating System :: POSIX :: BSD :: NetBSD
|
||||
Classifier: Operating System :: POSIX :: BSD :: OpenBSD
|
||||
Classifier: Operating System :: POSIX :: BSD
|
||||
Classifier: Operating System :: POSIX :: Linux
|
||||
Classifier: Operating System :: POSIX :: SunOS/Solaris
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Programming Language :: C
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Software Development :: Libraries
|
||||
Classifier: Topic :: System :: Benchmark
|
||||
Classifier: Topic :: System :: Hardware :: Hardware Drivers
|
||||
Classifier: Topic :: System :: Hardware
|
||||
Classifier: Topic :: System :: Monitoring
|
||||
Classifier: Topic :: System :: Networking :: Monitoring :: Hardware Watchdog
|
||||
Classifier: Topic :: System :: Networking :: Monitoring
|
||||
Classifier: Topic :: System :: Networking
|
||||
Classifier: Topic :: System :: Operating System
|
||||
Classifier: Topic :: System :: Systems Administration
|
||||
Classifier: Topic :: Utilities
|
||||
Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
|
||||
Provides-Extra: enum
|
||||
Requires-Dist: enum34 ; extra == 'enum'
|
||||
|
||||
| |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
||||
| |version| |py-versions| |packages| |license|
|
||||
| |travis| |appveyor| |cirrus| |doc| |twitter| |tidelift|
|
||||
|
||||
.. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pepy.tech/project/psutil
|
||||
:alt: Downloads
|
||||
|
||||
.. |stars| image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/stargazers
|
||||
:alt: Github stars
|
||||
|
||||
.. |forks| image:: https://img.shields.io/github/forks/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/network/members
|
||||
:alt: Github forks
|
||||
|
||||
.. |contributors| image:: https://img.shields.io/github/contributors/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/graphs/contributors
|
||||
:alt: Contributors
|
||||
|
||||
.. |quality| image:: https://img.shields.io/codacy/grade/ce63e7f7f69d44b5b59682196e6fbfca.svg
|
||||
:target: https://www.codacy.com/app/g-rodola/psutil?utm_source=github.com&utm_medium=referral&utm_content=giampaolo/psutil&utm_campaign=Badge_Grade
|
||||
:alt: Code quality
|
||||
|
||||
.. |travis| image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux,%20OSX,%20PyPy
|
||||
:target: https://travis-ci.org/giampaolo/psutil
|
||||
:alt: Linux tests (Travis)
|
||||
|
||||
.. |appveyor| image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
|
||||
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
||||
:alt: Windows tests (Appveyor)
|
||||
|
||||
.. |cirrus| image:: https://img.shields.io/cirrus/github/giampaolo/psutil?label=FreeBSD
|
||||
:target: https://cirrus-ci.com/github/giampaolo/psutil-cirrus-ci
|
||||
:alt: FreeBSD tests (Cirrus-Ci)
|
||||
|
||||
.. |coverage| image:: https://img.shields.io/coveralls/github/giampaolo/psutil.svg?label=test%20coverage
|
||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||
:alt: Test coverage (coverall.io)
|
||||
|
||||
.. |doc| image:: https://readthedocs.org/projects/psutil/badge/?version=latest
|
||||
:target: http://psutil.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. |version| image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
|
||||
:target: https://pypi.org/project/psutil
|
||||
:alt: Latest version
|
||||
|
||||
.. |py-versions| image:: https://img.shields.io/pypi/pyversions/psutil.svg
|
||||
:target: https://pypi.org/project/psutil
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. |packages| image:: https://repology.org/badge/tiny-repos/python:psutil.svg
|
||||
:target: https://repology.org/metapackage/python:psutil/versions
|
||||
:alt: Binary packages
|
||||
|
||||
.. |license| image:: https://img.shields.io/pypi/l/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/blob/master/LICENSE
|
||||
:alt: License
|
||||
|
||||
.. |twitter| image:: https://img.shields.io/twitter/follow/grodola.svg?label=follow&style=flat&logo=twitter&logoColor=4FADFF
|
||||
:target: https://twitter.com/grodola
|
||||
:alt: Twitter Follow
|
||||
|
||||
.. |tidelift| image:: https://tidelift.com/badges/github/giampaolo/psutil?style=flat
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
:alt: Tidelift
|
||||
|
||||
-----
|
||||
|
||||
Quick links
|
||||
===========
|
||||
|
||||
- `Home page <https://github.com/giampaolo/psutil>`_
|
||||
- `Install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
||||
- `Documentation <http://psutil.readthedocs.io>`_
|
||||
- `Download <https://pypi.org/project/psutil/#files>`_
|
||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
||||
- `StackOverflow <https://stackoverflow.com/questions/tagged/psutil>`_
|
||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst>`_
|
||||
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
|
||||
|
||||
Summary
|
||||
=======
|
||||
|
||||
psutil (process and system utilities) is a cross-platform library for
|
||||
retrieving information on **running processes** and **system utilization**
|
||||
(CPU, memory, disks, network, sensors) in Python.
|
||||
It is useful mainly for **system monitoring**, **profiling and limiting process
|
||||
resources** and **management of running processes**.
|
||||
It implements many functionalities offered by classic UNIX command line tools
|
||||
such as *ps, top, iotop, lsof, netstat, ifconfig, free* and others.
|
||||
psutil currently supports the following platforms:
|
||||
|
||||
- **Linux**
|
||||
- **Windows**
|
||||
- **macOS**
|
||||
- **FreeBSD, OpenBSD**, **NetBSD**
|
||||
- **Sun Solaris**
|
||||
- **AIX**
|
||||
|
||||
...both **32-bit** and **64-bit** architectures. Supported Python versions are **2.6**, **2.7** and **3.4+**. `PyPy3 <http://pypy.org/>`__ is also known to work.
|
||||
|
||||
psutil for enterprise
|
||||
=====================
|
||||
|
||||
.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png
|
||||
:width: 150
|
||||
:alt: Tidelift
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 150
|
||||
|
||||
* - |tideliftlogo|
|
||||
- The maintainer of psutil and thousands of other packages are working
|
||||
with Tidelift to deliver commercial support and maintenance for the open
|
||||
source dependencies you use to build your applications. Save time,
|
||||
reduce risk, and improve code health, while paying the maintainers of
|
||||
the exact dependencies you use.
|
||||
`Learn more <https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`__.
|
||||
|
||||
By subscribing to Tidelift you will help me (`Giampaolo Rodola`_) support
|
||||
psutil future development. Alternatively consider making a small
|
||||
`donation`_.
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
To report a security vulnerability, please use the `Tidelift security
|
||||
contact`_. Tidelift will coordinate the fix and disclosure.
|
||||
|
||||
Example applications
|
||||
====================
|
||||
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/top-small.png |
|
||||
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/top.png |
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap-small.png |
|
||||
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap.png |
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
|
||||
Also see `scripts directory <https://github.com/giampaolo/psutil/tree/master/scripts>`__
|
||||
and `doc recipes <http://psutil.readthedocs.io/#recipes/>`__.
|
||||
|
||||
Projects using psutil
|
||||
=====================
|
||||
|
||||
psutil has roughly the following monthly downloads:
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pepy.tech/project/psutil
|
||||
:alt: Downloads
|
||||
|
||||
There are over
|
||||
`10.000 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
|
||||
on github which depend from psutil.
|
||||
Here's some I find particularly interesting:
|
||||
|
||||
- https://github.com/google/grr
|
||||
- https://github.com/facebook/osquery/
|
||||
- https://github.com/nicolargo/glances
|
||||
- https://github.com/Jahaja/psdash
|
||||
- https://github.com/ajenti/ajenti
|
||||
- https://github.com/home-assistant/home-assistant/
|
||||
|
||||
|
||||
Portings
|
||||
========
|
||||
|
||||
- Go: https://github.com/shirou/gopsutil
|
||||
- C: https://github.com/hamon-in/cpslib
|
||||
- Rust: https://github.com/borntyping/rust-psutil
|
||||
- Nim: https://github.com/johnscillieri/psutil-nim
|
||||
|
||||
|
||||
Example usages
|
||||
==============
|
||||
|
||||
This represents pretty much the whole psutil API.
|
||||
|
||||
CPU
|
||||
---
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>>
|
||||
>>> psutil.cpu_times()
|
||||
scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1)
|
||||
...
|
||||
4.0
|
||||
5.9
|
||||
3.8
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1, percpu=True)
|
||||
...
|
||||
[4.0, 6.9, 3.7, 9.2]
|
||||
[7.0, 8.5, 2.4, 2.1]
|
||||
[1.2, 9.0, 9.9, 7.2]
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_times_percent(interval=1, percpu=False)
|
||||
...
|
||||
scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
>>>
|
||||
>>> psutil.cpu_count()
|
||||
4
|
||||
>>> psutil.cpu_count(logical=False)
|
||||
2
|
||||
>>>
|
||||
>>> psutil.cpu_stats()
|
||||
scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
|
||||
>>>
|
||||
>>> psutil.cpu_freq()
|
||||
scpufreq(current=931.42925, min=800.0, max=3500.0)
|
||||
>>>
|
||||
>>> psutil.getloadavg() # also on Windows (emulated)
|
||||
(3.14, 3.89, 4.67)
|
||||
|
||||
Memory
|
||||
------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.virtual_memory()
|
||||
svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)
|
||||
>>> psutil.swap_memory()
|
||||
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
||||
>>>
|
||||
|
||||
Disks
|
||||
-----
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.disk_partitions()
|
||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
||||
>>>
|
||||
>>> psutil.disk_usage('/')
|
||||
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
||||
>>>
|
||||
>>> psutil.disk_io_counters(perdisk=False)
|
||||
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)
|
||||
>>>
|
||||
|
||||
Network
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.net_io_counters(pernic=True)
|
||||
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
||||
'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()
|
||||
[sconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
|
||||
sconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),
|
||||
...]
|
||||
>>>
|
||||
>>> psutil.net_if_addrs()
|
||||
{'lo': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
|
||||
'wlan0': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
|
||||
snicaddr(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()
|
||||
{'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536),
|
||||
'wlan0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500)}
|
||||
>>>
|
||||
|
||||
Sensors
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.sensors_temperatures()
|
||||
{'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
|
||||
'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
|
||||
'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
|
||||
shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0)]}
|
||||
>>>
|
||||
>>> psutil.sensors_fans()
|
||||
{'asus': [sfan(label='cpu_fan', current=3200)]}
|
||||
>>>
|
||||
>>> psutil.sensors_battery()
|
||||
sbattery(percent=93, secsleft=16628, power_plugged=False)
|
||||
>>>
|
||||
|
||||
Other system info
|
||||
-----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.users()
|
||||
[suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),
|
||||
suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]
|
||||
>>>
|
||||
>>> psutil.boot_time()
|
||||
1365519115.0
|
||||
>>>
|
||||
|
||||
Process management
|
||||
------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.pids()
|
||||
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244,
|
||||
1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282,
|
||||
4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446,
|
||||
5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
||||
>>>
|
||||
>>> p = psutil.Process(7055)
|
||||
>>> p
|
||||
psutil.Process(pid=7055, name='python', started='09:04:44')
|
||||
>>> p.name()
|
||||
'python'
|
||||
>>> p.exe()
|
||||
'/usr/bin/python'
|
||||
>>> p.cwd()
|
||||
'/home/giampaolo'
|
||||
>>> p.cmdline()
|
||||
['/usr/bin/python', 'main.py']
|
||||
>>>
|
||||
>>> p.pid
|
||||
7055
|
||||
>>> p.ppid()
|
||||
7054
|
||||
>>> p.children(recursive=True)
|
||||
[psutil.Process(pid=29835, name='python2.7', started='11:45:38'),
|
||||
psutil.Process(pid=29836, name='python2.7', started='11:43:39')]
|
||||
>>>
|
||||
>>> p.parent()
|
||||
psutil.Process(pid=4699, name='bash', started='09:06:44')
|
||||
>>> p.parents()
|
||||
[psutil.Process(pid=4699, name='bash', started='09:06:44'),
|
||||
psutil.Process(pid=4689, name='gnome-terminal-server', started='0:06:44'),
|
||||
psutil.Process(pid=1, name='systemd', started='05:56:55')]
|
||||
>>>
|
||||
>>> p.status()
|
||||
'running'
|
||||
>>> p.username()
|
||||
'giampaolo'
|
||||
>>> p.create_time()
|
||||
1267551141.5019531
|
||||
>>> p.terminal()
|
||||
'/dev/pts/0'
|
||||
>>>
|
||||
>>> p.uids()
|
||||
puids(real=1000, effective=1000, saved=1000)
|
||||
>>> p.gids()
|
||||
pgids(real=1000, effective=1000, saved=1000)
|
||||
>>>
|
||||
>>> p.cpu_times()
|
||||
pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1, iowait=0.0)
|
||||
>>> p.cpu_percent(interval=1.0)
|
||||
12.1
|
||||
>>> p.cpu_affinity()
|
||||
[0, 1, 2, 3]
|
||||
>>> p.cpu_affinity([0, 1]) # set
|
||||
>>> p.cpu_num()
|
||||
1
|
||||
>>>
|
||||
>>> p.memory_info()
|
||||
pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)
|
||||
>>> p.memory_full_info() # "real" USS memory usage (Linux, macOS, Win only)
|
||||
pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)
|
||||
>>> p.memory_percent()
|
||||
0.7823
|
||||
>>> p.memory_maps()
|
||||
[pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),
|
||||
pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),
|
||||
pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
|
||||
pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
|
||||
...]
|
||||
>>>
|
||||
>>> p.io_counters()
|
||||
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
|
||||
>>>
|
||||
>>> p.open_files()
|
||||
[popenfile(path='/home/giampaolo/monit.py', fd=3, position=0, mode='r', flags=32768),
|
||||
popenfile(path='/var/log/monit.log', fd=4, position=235542, mode='a', flags=33793)]
|
||||
>>>
|
||||
>>> p.connections()
|
||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
|
||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING')]
|
||||
>>>
|
||||
>>> p.num_threads()
|
||||
4
|
||||
>>> p.num_fds()
|
||||
8
|
||||
>>> p.threads()
|
||||
[pthread(id=5234, user_time=22.5, system_time=9.2891),
|
||||
pthread(id=5237, user_time=0.0707, system_time=1.1)]
|
||||
>>>
|
||||
>>> p.num_ctx_switches()
|
||||
pctxsw(voluntary=78, involuntary=19)
|
||||
>>>
|
||||
>>> p.nice()
|
||||
0
|
||||
>>> p.nice(10) # set
|
||||
>>>
|
||||
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)
|
||||
>>> p.ionice()
|
||||
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)
|
||||
(5, 5)
|
||||
>>>
|
||||
>>> p.environ()
|
||||
{'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',
|
||||
'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg',
|
||||
...}
|
||||
>>>
|
||||
>>> p.as_dict()
|
||||
{'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}
|
||||
>>> p.is_running()
|
||||
True
|
||||
>>> p.suspend()
|
||||
>>> p.resume()
|
||||
>>>
|
||||
>>> p.terminate()
|
||||
>>> p.kill()
|
||||
>>> p.wait(timeout=3)
|
||||
0
|
||||
>>>
|
||||
>>> psutil.test()
|
||||
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
|
||||
root 1 0.0 0.0 24584 2240 Jun17 00:00 init
|
||||
root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd
|
||||
...
|
||||
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
|
||||
giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome
|
||||
root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1
|
||||
>>>
|
||||
|
||||
Further process APIs
|
||||
--------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> for proc in psutil.process_iter(['pid', 'name']):
|
||||
... print(proc.info)
|
||||
...
|
||||
{'pid': 1, 'name': 'systemd'}
|
||||
{'pid': 2, 'name': 'kthreadd'}
|
||||
{'pid': 3, 'name': 'ksoftirqd/0'}
|
||||
...
|
||||
>>>
|
||||
>>> psutil.pid_exists(3)
|
||||
True
|
||||
>>>
|
||||
>>> def on_terminate(proc):
|
||||
... print("process {} terminated".format(proc))
|
||||
...
|
||||
>>> # waits for multiple processes to terminate
|
||||
>>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)
|
||||
>>>
|
||||
|
||||
Popen wrapper:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> from subprocess import PIPE
|
||||
>>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE)
|
||||
>>> p.name()
|
||||
'python'
|
||||
>>> p.username()
|
||||
'giampaolo'
|
||||
>>> p.communicate()
|
||||
('hello\n', None)
|
||||
>>> p.wait(timeout=2)
|
||||
0
|
||||
>>>
|
||||
|
||||
Windows services
|
||||
----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> list(psutil.win_service_iter())
|
||||
[<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
|
||||
<WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
|
||||
<WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
|
||||
<WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
|
||||
...]
|
||||
>>> s = psutil.win_service_get('alg')
|
||||
>>> s.as_dict()
|
||||
{'binpath': 'C:\\Windows\\System32\\alg.exe',
|
||||
'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
|
||||
'display_name': 'Application Layer Gateway Service',
|
||||
'name': 'alg',
|
||||
'pid': None,
|
||||
'start_type': 'manual',
|
||||
'status': 'stopped',
|
||||
'username': 'NT AUTHORITY\\LocalService'}
|
||||
|
||||
|
||||
.. _`Giampaolo Rodola`: http://grodola.blogspot.com/p/about.html
|
||||
.. _`donation`: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||
.. _Tidelift security contact: https://tidelift.com/security
|
||||
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
|
||||
|
||||
|
||||
33
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/RECORD
vendored
Normal file
33
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/RECORD
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
psutil/__init__.py,sha256=gkuk8_HMEBXTFl0y4l8A5QGNCjUH1T0tpF_Y8hPJCPA,87126
|
||||
psutil/_common.py,sha256=6kuDg4DKKv3OGndSXLQ3LftF_hPySIEOprC8HE49eag,26001
|
||||
psutil/_compat.py,sha256=lrMSZr32TO6y9FQw7C2xTNyKwAnPU2o11xQrA_fS_Qw,11607
|
||||
psutil/_psaix.py,sha256=u9M_jJqkiGqNgdhum9MZTbnS4pjIfdCHNr3HAYHA0GQ,18458
|
||||
psutil/_psbsd.py,sha256=LHfBJ-iKy4fuumIcSjO7b6VFOvU_d-Pzwp7Eg84rHSw,30534
|
||||
psutil/_pslinux.py,sha256=WtQtqOAhXd-zqtVPV-E0re91Vqj4DYrKQ3Mj9CfBWak,79806
|
||||
psutil/_psosx.py,sha256=kvG3GKxA-L581H_UgU_BYaZ3eMPX7qMtEBM7AGC-t10,17090
|
||||
psutil/_psposix.py,sha256=FtbNSosrJiiUb9l0gfFdTwNxUwQb6Icy4L3si0x6ZMA,6047
|
||||
psutil/_pssunos.py,sha256=c-0et4xslK83ZiTizQ9W3LH0pMZy11ATEIBbQBJ_v-g,25398
|
||||
psutil/_psutil_windows.pyd,sha256=jERIIv4AR_vfAvx8oOqkyv41JBPuMskRgnM1O8KdokE,62976
|
||||
psutil/_pswindows.py,sha256=iFcfbA5KZehjdZfe1b-cLGRdavGNryI4Zxpkqb12UjU,36839
|
||||
psutil/tests/__init__.py,sha256=uH3lPOnYc6179FxdSy4xfMeJOBvB9CZid268Pg_owC0,35141
|
||||
psutil/tests/__main__.py,sha256=bBfMPu_gPzyiA4gfAFSZLk7LyLSPTUIHQFU1kFcj_Ok,291
|
||||
psutil/tests/runner.py,sha256=l7BrTzIOdjPgNB3D3kiir8jBiK_QJKMlJSYu4Zr0_po,5188
|
||||
psutil/tests/test_aix.py,sha256=LA8PR-1vx5DN2OkjU57MsO8uzNOB0y1ScR1yx5bZJyc,4464
|
||||
psutil/tests/test_bsd.py,sha256=3zlUvefRm2fFTbyLrqM9u8NMK8CThLT7irioTGgnNts,20612
|
||||
psutil/tests/test_connections.py,sha256=U2KCl7eW6kRds8S7t8SmZ62OrVSPfdBuksHsDlk2C28,25293
|
||||
psutil/tests/test_contracts.py,sha256=BOKrRiZs625Xj3KZBzOZ8Kr6edAQgzHq0OlznoCxKzw,25355
|
||||
psutil/tests/test_linux.py,sha256=KvqJ-LiINvbQQ3y18uM2SZRKnpnH4PqlA7CqWLRIH5s,87573
|
||||
psutil/tests/test_memory_leaks.py,sha256=M5nWBv_PYfN7bIoaz6r0UqEYY79hO6wvvDfkKWFMETI,18499
|
||||
psutil/tests/test_misc.py,sha256=wqXpnXL2ycHyE1vu3GB43XTET5auTKz9VdBSjr-vdp0,38748
|
||||
psutil/tests/test_osx.py,sha256=oQIO0YReUtH0PFFAwyk8FpUqvjIiuhVPehMFS1AWJpM,9257
|
||||
psutil/tests/test_posix.py,sha256=fSi5J1LxPhA7ZocrnLnqCSBn6JUuOtBeAljBWughIf4,16537
|
||||
psutil/tests/test_process.py,sha256=JJB9VdAwKFYK-rlpvWn1NyeYasmr0nL_XetzFHHjaJU,63924
|
||||
psutil/tests/test_sunos.py,sha256=GwqWfAP46nrxWlJr-srg85cPNEU2DXvoMelAgqegfLA,1294
|
||||
psutil/tests/test_system.py,sha256=4nWe_fFRmnaB8epV7Eji_0JFnIJbvbykMgSi8LFzbKM,36162
|
||||
psutil/tests/test_unicode.py,sha256=5v1hFoOQoi9_2Wg4ZTIWY_YDd29G00-59ln9FOe8Tsg,13246
|
||||
psutil/tests/test_windows.py,sha256=cGjEspgL48Sb5BQeSG5kIU0DSeImPU1bL9cpFfNX2Tk,33666
|
||||
psutil-5.7.0.dist-info/LICENSE,sha256=JMEphFAMqgf_3OGe68BjlsXm0kS1c7xsQ49KbvjlbBs,1549
|
||||
psutil-5.7.0.dist-info/METADATA,sha256=RmX2_-V4HrxQ1p78U2Os4H5Q0ZFvF5oc0uUTUt9-sRo,25022
|
||||
psutil-5.7.0.dist-info/WHEEL,sha256=Yt_rpa18HI_NXs5dEYG1uWuZ-4QRLVJrN8TSetG3BOI,106
|
||||
psutil-5.7.0.dist-info/top_level.txt,sha256=gCNhn57wzksDjSAISmgMJ0aiXzQulk0GJhb2-BAyYgw,7
|
||||
psutil-5.7.0.dist-info/RECORD,,
|
||||
5
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/WHEEL
vendored
Normal file
5
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/WHEEL
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.34.2)
|
||||
Root-Is-Purelib: false
|
||||
Tag: cp27-cp27m-win_amd64
|
||||
|
||||
1
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/top_level.txt
vendored
Normal file
1
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/top_level.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
psutil
|
||||
2409
third_party/python/psutil-cp27-none-win_amd64/psutil/__init__.py
vendored
Normal file
2409
third_party/python/psutil-cp27-none-win_amd64/psutil/__init__.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
846
third_party/python/psutil-cp27-none-win_amd64/psutil/_common.py
vendored
Normal file
846
third_party/python/psutil-cp27-none-win_amd64/psutil/_common.py
vendored
Normal file
|
|
@ -0,0 +1,846 @@
|
|||
# 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.
|
||||
|
||||
"""Common objects shared by __init__.py and _ps*.py modules."""
|
||||
|
||||
# Note: this module is imported by setup.py so it should not import
|
||||
# psutil or third-party modules.
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import socket
|
||||
import stat
|
||||
import sys
|
||||
import threading
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET
|
||||
from socket import SOCK_DGRAM
|
||||
from socket import SOCK_STREAM
|
||||
|
||||
try:
|
||||
from socket import AF_INET6
|
||||
except ImportError:
|
||||
AF_INET6 = None
|
||||
try:
|
||||
from socket import AF_UNIX
|
||||
except ImportError:
|
||||
AF_UNIX = None
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
import enum
|
||||
else:
|
||||
enum = None
|
||||
|
||||
|
||||
# can't take it from _common.py as this script is imported by setup.py
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
__all__ = [
|
||||
# OS constants
|
||||
'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'MACOS', 'OSX', 'POSIX',
|
||||
'SUNOS', 'WINDOWS',
|
||||
# connection constants
|
||||
'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED',
|
||||
'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN',
|
||||
'CONN_NONE', 'CONN_SYN_RECV', 'CONN_SYN_SENT', 'CONN_TIME_WAIT',
|
||||
# net constants
|
||||
'NIC_DUPLEX_FULL', 'NIC_DUPLEX_HALF', 'NIC_DUPLEX_UNKNOWN',
|
||||
# process status constants
|
||||
'STATUS_DEAD', 'STATUS_DISK_SLEEP', 'STATUS_IDLE', 'STATUS_LOCKED',
|
||||
'STATUS_RUNNING', 'STATUS_SLEEPING', 'STATUS_STOPPED', 'STATUS_SUSPENDED',
|
||||
'STATUS_TRACING_STOP', 'STATUS_WAITING', 'STATUS_WAKE_KILL',
|
||||
'STATUS_WAKING', 'STATUS_ZOMBIE', 'STATUS_PARKED',
|
||||
# other constants
|
||||
'ENCODING', 'ENCODING_ERRS', 'AF_INET6',
|
||||
# named tuples
|
||||
'pconn', 'pcputimes', 'pctxsw', 'pgids', 'pio', 'pionice', 'popenfile',
|
||||
'pthread', 'puids', 'sconn', 'scpustats', 'sdiskio', 'sdiskpart',
|
||||
'sdiskusage', 'snetio', 'snicaddr', 'snicstats', 'sswap', 'suser',
|
||||
# utility functions
|
||||
'conn_tmap', 'deprecated_method', 'isfile_strict', 'memoize',
|
||||
'parse_environ_block', 'path_exists_strict', 'usage_percent',
|
||||
'supports_ipv6', 'sockfam_to_enum', 'socktype_to_enum', "wrap_numbers",
|
||||
'bytes2human', 'conn_to_ntuple', 'debug',
|
||||
# shell utils
|
||||
'hilite', 'term_supports_colors', 'print_color',
|
||||
]
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- OS constants
|
||||
# ===================================================================
|
||||
|
||||
|
||||
POSIX = os.name == "posix"
|
||||
WINDOWS = os.name == "nt"
|
||||
LINUX = sys.platform.startswith("linux")
|
||||
MACOS = sys.platform.startswith("darwin")
|
||||
OSX = MACOS # deprecated alias
|
||||
FREEBSD = sys.platform.startswith("freebsd")
|
||||
OPENBSD = sys.platform.startswith("openbsd")
|
||||
NETBSD = sys.platform.startswith("netbsd")
|
||||
BSD = FREEBSD or OPENBSD or NETBSD
|
||||
SUNOS = sys.platform.startswith(("sunos", "solaris"))
|
||||
AIX = sys.platform.startswith("aix")
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- API constants
|
||||
# ===================================================================
|
||||
|
||||
|
||||
# Process.status()
|
||||
STATUS_RUNNING = "running"
|
||||
STATUS_SLEEPING = "sleeping"
|
||||
STATUS_DISK_SLEEP = "disk-sleep"
|
||||
STATUS_STOPPED = "stopped"
|
||||
STATUS_TRACING_STOP = "tracing-stop"
|
||||
STATUS_ZOMBIE = "zombie"
|
||||
STATUS_DEAD = "dead"
|
||||
STATUS_WAKE_KILL = "wake-kill"
|
||||
STATUS_WAKING = "waking"
|
||||
STATUS_IDLE = "idle" # Linux, macOS, FreeBSD
|
||||
STATUS_LOCKED = "locked" # FreeBSD
|
||||
STATUS_WAITING = "waiting" # FreeBSD
|
||||
STATUS_SUSPENDED = "suspended" # NetBSD
|
||||
STATUS_PARKED = "parked" # Linux
|
||||
|
||||
# Process.connections() and psutil.net_connections()
|
||||
CONN_ESTABLISHED = "ESTABLISHED"
|
||||
CONN_SYN_SENT = "SYN_SENT"
|
||||
CONN_SYN_RECV = "SYN_RECV"
|
||||
CONN_FIN_WAIT1 = "FIN_WAIT1"
|
||||
CONN_FIN_WAIT2 = "FIN_WAIT2"
|
||||
CONN_TIME_WAIT = "TIME_WAIT"
|
||||
CONN_CLOSE = "CLOSE"
|
||||
CONN_CLOSE_WAIT = "CLOSE_WAIT"
|
||||
CONN_LAST_ACK = "LAST_ACK"
|
||||
CONN_LISTEN = "LISTEN"
|
||||
CONN_CLOSING = "CLOSING"
|
||||
CONN_NONE = "NONE"
|
||||
|
||||
# net_if_stats()
|
||||
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__)
|
||||
|
||||
# sensors_battery()
|
||||
if enum is None:
|
||||
POWER_TIME_UNKNOWN = -1
|
||||
POWER_TIME_UNLIMITED = -2
|
||||
else:
|
||||
class BatteryTime(enum.IntEnum):
|
||||
POWER_TIME_UNKNOWN = -1
|
||||
POWER_TIME_UNLIMITED = -2
|
||||
|
||||
globals().update(BatteryTime.__members__)
|
||||
|
||||
# --- others
|
||||
|
||||
ENCODING = sys.getfilesystemencoding()
|
||||
if not PY3:
|
||||
ENCODING_ERRS = "replace"
|
||||
else:
|
||||
try:
|
||||
ENCODING_ERRS = sys.getfilesystemencodeerrors() # py 3.6
|
||||
except AttributeError:
|
||||
ENCODING_ERRS = "surrogateescape" if POSIX else "replace"
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- namedtuples
|
||||
# ===================================================================
|
||||
|
||||
# --- for system functions
|
||||
|
||||
# psutil.swap_memory()
|
||||
sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin',
|
||||
'sout'])
|
||||
# psutil.disk_usage()
|
||||
sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent'])
|
||||
# psutil.disk_io_counters()
|
||||
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes',
|
||||
'read_time', 'write_time'])
|
||||
# psutil.disk_partitions()
|
||||
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
|
||||
# psutil.net_io_counters()
|
||||
snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
|
||||
'packets_sent', 'packets_recv',
|
||||
'errin', 'errout',
|
||||
'dropin', 'dropout'])
|
||||
# psutil.users()
|
||||
suser = namedtuple('suser', ['name', 'terminal', 'host', 'started', 'pid'])
|
||||
# psutil.net_connections()
|
||||
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||
'status', 'pid'])
|
||||
# psutil.net_if_addrs()
|
||||
snicaddr = namedtuple('snicaddr',
|
||||
['family', 'address', 'netmask', 'broadcast', 'ptp'])
|
||||
# psutil.net_if_stats()
|
||||
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
|
||||
# psutil.cpu_stats()
|
||||
scpustats = namedtuple(
|
||||
'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'])
|
||||
# psutil.cpu_freq()
|
||||
scpufreq = namedtuple('scpufreq', ['current', 'min', 'max'])
|
||||
# psutil.sensors_temperatures()
|
||||
shwtemp = namedtuple(
|
||||
'shwtemp', ['label', 'current', 'high', 'critical'])
|
||||
# psutil.sensors_battery()
|
||||
sbattery = namedtuple('sbattery', ['percent', 'secsleft', 'power_plugged'])
|
||||
# psutil.sensors_fans()
|
||||
sfan = namedtuple('sfan', ['label', 'current'])
|
||||
|
||||
# --- for Process methods
|
||||
|
||||
# psutil.Process.cpu_times()
|
||||
pcputimes = namedtuple('pcputimes',
|
||||
['user', 'system', 'children_user', 'children_system'])
|
||||
# psutil.Process.open_files()
|
||||
popenfile = namedtuple('popenfile', ['path', 'fd'])
|
||||
# psutil.Process.threads()
|
||||
pthread = namedtuple('pthread', ['id', 'user_time', 'system_time'])
|
||||
# psutil.Process.uids()
|
||||
puids = namedtuple('puids', ['real', 'effective', 'saved'])
|
||||
# psutil.Process.gids()
|
||||
pgids = namedtuple('pgids', ['real', 'effective', 'saved'])
|
||||
# psutil.Process.io_counters()
|
||||
pio = namedtuple('pio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes'])
|
||||
# psutil.Process.ionice()
|
||||
pionice = namedtuple('pionice', ['ioclass', 'value'])
|
||||
# psutil.Process.ctx_switches()
|
||||
pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary'])
|
||||
# psutil.Process.connections()
|
||||
pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||
'status'])
|
||||
|
||||
# psutil.connections() and psutil.Process.connections()
|
||||
addr = namedtuple('addr', ['ip', 'port'])
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- Process.connections() 'kind' parameter mapping
|
||||
# ===================================================================
|
||||
|
||||
|
||||
conn_tmap = {
|
||||
"all": ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"tcp": ([AF_INET, AF_INET6], [SOCK_STREAM]),
|
||||
"tcp4": ([AF_INET], [SOCK_STREAM]),
|
||||
"udp": ([AF_INET, AF_INET6], [SOCK_DGRAM]),
|
||||
"udp4": ([AF_INET], [SOCK_DGRAM]),
|
||||
"inet": ([AF_INET, AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"inet4": ([AF_INET], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"inet6": ([AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
}
|
||||
|
||||
if AF_INET6 is not None:
|
||||
conn_tmap.update({
|
||||
"tcp6": ([AF_INET6], [SOCK_STREAM]),
|
||||
"udp6": ([AF_INET6], [SOCK_DGRAM]),
|
||||
})
|
||||
|
||||
if AF_UNIX is not None:
|
||||
conn_tmap.update({
|
||||
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
})
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- Exceptions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Base exception class. All other psutil exceptions inherit
|
||||
from this one.
|
||||
"""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, msg=""):
|
||||
Exception.__init__(self, msg)
|
||||
self.msg = msg
|
||||
|
||||
def __repr__(self):
|
||||
ret = "psutil.%s %s" % (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.
|
||||
"""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, pid, name=None, msg=None):
|
||||
Error.__init__(self, msg)
|
||||
self.pid = pid
|
||||
self.name = name
|
||||
self.msg = msg
|
||||
if msg is None:
|
||||
if name:
|
||||
details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
|
||||
else:
|
||||
details = "(pid=%s)" % self.pid
|
||||
self.msg = "process no longer exists " + details
|
||||
|
||||
def __path__(self):
|
||||
return 'xxx'
|
||||
|
||||
|
||||
class ZombieProcess(NoSuchProcess):
|
||||
"""Exception raised when querying a zombie process. This is
|
||||
raised on macOS, 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.
|
||||
"""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, pid, name=None, ppid=None, msg=None):
|
||||
NoSuchProcess.__init__(self, msg)
|
||||
self.pid = pid
|
||||
self.ppid = ppid
|
||||
self.name = name
|
||||
self.msg = msg
|
||||
if msg is None:
|
||||
args = ["pid=%s" % pid]
|
||||
if name:
|
||||
args.append("name=%s" % repr(self.name))
|
||||
if ppid:
|
||||
args.append("ppid=%s" % self.ppid)
|
||||
details = "(%s)" % ", ".join(args)
|
||||
self.msg = "process still exists but it's a zombie " + details
|
||||
|
||||
|
||||
class AccessDenied(Error):
|
||||
"""Exception raised when permission to perform an action is denied."""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, pid=None, name=None, msg=None):
|
||||
Error.__init__(self, msg)
|
||||
self.pid = pid
|
||||
self.name = name
|
||||
self.msg = msg
|
||||
if msg is None:
|
||||
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
|
||||
else:
|
||||
self.msg = ""
|
||||
|
||||
|
||||
class TimeoutExpired(Error):
|
||||
"""Raised on Process.wait(timeout) if timeout expires and process
|
||||
is still alive.
|
||||
"""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, seconds, pid=None, name=None):
|
||||
Error.__init__(self, "timeout after %s seconds" % seconds)
|
||||
self.seconds = seconds
|
||||
self.pid = pid
|
||||
self.name = name
|
||||
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
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- utils
|
||||
# ===================================================================
|
||||
|
||||
|
||||
def usage_percent(used, total, round_=None):
|
||||
"""Calculate percentage usage of 'used' against 'total'."""
|
||||
try:
|
||||
ret = (float(used) / total) * 100
|
||||
except ZeroDivisionError:
|
||||
return 0.0
|
||||
else:
|
||||
if round_ is not None:
|
||||
ret = round(ret, round_)
|
||||
return ret
|
||||
|
||||
|
||||
def memoize(fun):
|
||||
"""A simple memoize decorator for functions supporting (hashable)
|
||||
positional arguments.
|
||||
It also provides a cache_clear() function for clearing the cache:
|
||||
|
||||
>>> @memoize
|
||||
... def foo()
|
||||
... return 1
|
||||
...
|
||||
>>> foo()
|
||||
1
|
||||
>>> foo.cache_clear()
|
||||
>>>
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(*args, **kwargs):
|
||||
key = (args, frozenset(sorted(kwargs.items())))
|
||||
try:
|
||||
return cache[key]
|
||||
except KeyError:
|
||||
ret = cache[key] = fun(*args, **kwargs)
|
||||
return ret
|
||||
|
||||
def cache_clear():
|
||||
"""Clear cache."""
|
||||
cache.clear()
|
||||
|
||||
cache = {}
|
||||
wrapper.cache_clear = cache_clear
|
||||
return wrapper
|
||||
|
||||
|
||||
def memoize_when_activated(fun):
|
||||
"""A memoize decorator which is disabled by default. It can be
|
||||
activated and deactivated on request.
|
||||
For efficiency reasons it can be used only against class methods
|
||||
accepting no arguments.
|
||||
|
||||
>>> class Foo:
|
||||
... @memoize
|
||||
... def foo()
|
||||
... print(1)
|
||||
...
|
||||
>>> f = Foo()
|
||||
>>> # deactivated (default)
|
||||
>>> foo()
|
||||
1
|
||||
>>> foo()
|
||||
1
|
||||
>>>
|
||||
>>> # activated
|
||||
>>> foo.cache_activate(self)
|
||||
>>> foo()
|
||||
1
|
||||
>>> foo()
|
||||
>>> foo()
|
||||
>>>
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self):
|
||||
try:
|
||||
# case 1: we previously entered oneshot() ctx
|
||||
ret = self._cache[fun]
|
||||
except AttributeError:
|
||||
# case 2: we never entered oneshot() ctx
|
||||
return fun(self)
|
||||
except KeyError:
|
||||
# case 3: we entered oneshot() ctx but there's no cache
|
||||
# for this entry yet
|
||||
ret = self._cache[fun] = fun(self)
|
||||
return ret
|
||||
|
||||
def cache_activate(proc):
|
||||
"""Activate cache. Expects a Process instance. Cache will be
|
||||
stored as a "_cache" instance attribute."""
|
||||
proc._cache = {}
|
||||
|
||||
def cache_deactivate(proc):
|
||||
"""Deactivate and clear cache."""
|
||||
try:
|
||||
del proc._cache
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
wrapper.cache_activate = cache_activate
|
||||
wrapper.cache_deactivate = cache_deactivate
|
||||
return wrapper
|
||||
|
||||
|
||||
def isfile_strict(path):
|
||||
"""Same as os.path.isfile() but does not swallow EACCES / EPERM
|
||||
exceptions, see:
|
||||
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
|
||||
"""
|
||||
try:
|
||||
st = os.stat(path)
|
||||
except OSError as err:
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise
|
||||
return False
|
||||
else:
|
||||
return stat.S_ISREG(st.st_mode)
|
||||
|
||||
|
||||
def path_exists_strict(path):
|
||||
"""Same as os.path.exists() but does not swallow EACCES / EPERM
|
||||
exceptions, see:
|
||||
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
|
||||
"""
|
||||
try:
|
||||
os.stat(path)
|
||||
except OSError as err:
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
@memoize
|
||||
def supports_ipv6():
|
||||
"""Return True if IPv6 is supported on this platform."""
|
||||
if not socket.has_ipv6 or AF_INET6 is None:
|
||||
return False
|
||||
try:
|
||||
sock = socket.socket(AF_INET6, socket.SOCK_STREAM)
|
||||
with contextlib.closing(sock):
|
||||
sock.bind(("::1", 0))
|
||||
return True
|
||||
except socket.error:
|
||||
return False
|
||||
|
||||
|
||||
def parse_environ_block(data):
|
||||
"""Parse a C environ block of environment variables into a dictionary."""
|
||||
# The block is usually raw data from the target process. It might contain
|
||||
# trailing garbage and lines that do not look like assignments.
|
||||
ret = {}
|
||||
pos = 0
|
||||
|
||||
# localize global variable to speed up access.
|
||||
WINDOWS_ = WINDOWS
|
||||
while True:
|
||||
next_pos = data.find("\0", pos)
|
||||
# nul byte at the beginning or double nul byte means finish
|
||||
if next_pos <= pos:
|
||||
break
|
||||
# there might not be an equals sign
|
||||
equal_pos = data.find("=", pos, next_pos)
|
||||
if equal_pos > pos:
|
||||
key = data[pos:equal_pos]
|
||||
value = data[equal_pos + 1:next_pos]
|
||||
# Windows expects environment variables to be uppercase only
|
||||
if WINDOWS_:
|
||||
key = key.upper()
|
||||
ret[key] = value
|
||||
pos = next_pos + 1
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
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
|
||||
else: # pragma: no cover
|
||||
try:
|
||||
return socket.AddressFamily(num)
|
||||
except ValueError:
|
||||
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
|
||||
else: # pragma: no cover
|
||||
try:
|
||||
return socket.SocketKind(num)
|
||||
except ValueError:
|
||||
return num
|
||||
|
||||
|
||||
def conn_to_ntuple(fd, fam, type_, laddr, raddr, status, status_map, pid=None):
|
||||
"""Convert a raw connection tuple to a proper ntuple."""
|
||||
if fam in (socket.AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = addr(*laddr)
|
||||
if raddr:
|
||||
raddr = addr(*raddr)
|
||||
if type_ == socket.SOCK_STREAM and fam in (AF_INET, AF_INET6):
|
||||
status = status_map.get(status, CONN_NONE)
|
||||
else:
|
||||
status = CONN_NONE # ignore whatever C returned to us
|
||||
fam = sockfam_to_enum(fam)
|
||||
type_ = socktype_to_enum(type_)
|
||||
if pid is None:
|
||||
return pconn(fd, fam, type_, laddr, raddr, status)
|
||||
else:
|
||||
return sconn(fd, fam, type_, laddr, raddr, status, pid)
|
||||
|
||||
|
||||
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 and will be removed; 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
|
||||
|
||||
|
||||
class _WrapNumbers:
|
||||
"""Watches numbers so that they don't overflow and wrap
|
||||
(reset to zero).
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.lock = threading.Lock()
|
||||
self.cache = {}
|
||||
self.reminders = {}
|
||||
self.reminder_keys = {}
|
||||
|
||||
def _add_dict(self, input_dict, name):
|
||||
assert name not in self.cache
|
||||
assert name not in self.reminders
|
||||
assert name not in self.reminder_keys
|
||||
self.cache[name] = input_dict
|
||||
self.reminders[name] = defaultdict(int)
|
||||
self.reminder_keys[name] = defaultdict(set)
|
||||
|
||||
def _remove_dead_reminders(self, input_dict, name):
|
||||
"""In case the number of keys changed between calls (e.g. a
|
||||
disk disappears) this removes the entry from self.reminders.
|
||||
"""
|
||||
old_dict = self.cache[name]
|
||||
gone_keys = set(old_dict.keys()) - set(input_dict.keys())
|
||||
for gone_key in gone_keys:
|
||||
for remkey in self.reminder_keys[name][gone_key]:
|
||||
del self.reminders[name][remkey]
|
||||
del self.reminder_keys[name][gone_key]
|
||||
|
||||
def run(self, input_dict, name):
|
||||
"""Cache dict and sum numbers which overflow and wrap.
|
||||
Return an updated copy of `input_dict`
|
||||
"""
|
||||
if name not in self.cache:
|
||||
# This was the first call.
|
||||
self._add_dict(input_dict, name)
|
||||
return input_dict
|
||||
|
||||
self._remove_dead_reminders(input_dict, name)
|
||||
|
||||
old_dict = self.cache[name]
|
||||
new_dict = {}
|
||||
for key in input_dict.keys():
|
||||
input_tuple = input_dict[key]
|
||||
try:
|
||||
old_tuple = old_dict[key]
|
||||
except KeyError:
|
||||
# The input dict has a new key (e.g. a new disk or NIC)
|
||||
# which didn't exist in the previous call.
|
||||
new_dict[key] = input_tuple
|
||||
continue
|
||||
|
||||
bits = []
|
||||
for i in range(len(input_tuple)):
|
||||
input_value = input_tuple[i]
|
||||
old_value = old_tuple[i]
|
||||
remkey = (key, i)
|
||||
if input_value < old_value:
|
||||
# it wrapped!
|
||||
self.reminders[name][remkey] += old_value
|
||||
self.reminder_keys[name][key].add(remkey)
|
||||
bits.append(input_value + self.reminders[name][remkey])
|
||||
|
||||
new_dict[key] = tuple(bits)
|
||||
|
||||
self.cache[name] = input_dict
|
||||
return new_dict
|
||||
|
||||
def cache_clear(self, name=None):
|
||||
"""Clear the internal cache, optionally only for function 'name'."""
|
||||
with self.lock:
|
||||
if name is None:
|
||||
self.cache.clear()
|
||||
self.reminders.clear()
|
||||
self.reminder_keys.clear()
|
||||
else:
|
||||
self.cache.pop(name, None)
|
||||
self.reminders.pop(name, None)
|
||||
self.reminder_keys.pop(name, None)
|
||||
|
||||
def cache_info(self):
|
||||
"""Return internal cache dicts as a tuple of 3 elements."""
|
||||
with self.lock:
|
||||
return (self.cache, self.reminders, self.reminder_keys)
|
||||
|
||||
|
||||
def wrap_numbers(input_dict, name):
|
||||
"""Given an `input_dict` and a function `name`, adjust the numbers
|
||||
which "wrap" (restart from zero) across different calls by adding
|
||||
"old value" to "new value" and return an updated dict.
|
||||
"""
|
||||
with _wn.lock:
|
||||
return _wn.run(input_dict, name)
|
||||
|
||||
|
||||
_wn = _WrapNumbers()
|
||||
wrap_numbers.cache_clear = _wn.cache_clear
|
||||
wrap_numbers.cache_info = _wn.cache_info
|
||||
|
||||
|
||||
def open_binary(fname, **kwargs):
|
||||
return open(fname, "rb", **kwargs)
|
||||
|
||||
|
||||
def open_text(fname, **kwargs):
|
||||
"""On Python 3 opens a file in text mode by using fs encoding and
|
||||
a proper en/decoding errors handler.
|
||||
On Python 2 this is just an alias for open(name, 'rt').
|
||||
"""
|
||||
if PY3:
|
||||
# See:
|
||||
# https://github.com/giampaolo/psutil/issues/675
|
||||
# https://github.com/giampaolo/psutil/pull/733
|
||||
kwargs.setdefault('encoding', ENCODING)
|
||||
kwargs.setdefault('errors', ENCODING_ERRS)
|
||||
return open(fname, "rt", **kwargs)
|
||||
|
||||
|
||||
def bytes2human(n, format="%(value).1f%(symbol)s"):
|
||||
"""Used by various scripts. See:
|
||||
http://goo.gl/zeJZl
|
||||
|
||||
>>> bytes2human(10000)
|
||||
'9.8K'
|
||||
>>> bytes2human(100001221)
|
||||
'95.4M'
|
||||
"""
|
||||
symbols = ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols[1:]):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for symbol in reversed(symbols[1:]):
|
||||
if n >= prefix[symbol]:
|
||||
value = float(n) / prefix[symbol]
|
||||
return format % locals()
|
||||
return format % dict(symbol=symbols[0], value=n)
|
||||
|
||||
|
||||
def get_procfs_path():
|
||||
"""Return updated psutil.PROCFS_PATH constant."""
|
||||
return sys.modules['psutil'].PROCFS_PATH
|
||||
|
||||
|
||||
if PY3:
|
||||
def decode(s):
|
||||
return s.decode(encoding=ENCODING, errors=ENCODING_ERRS)
|
||||
else:
|
||||
def decode(s):
|
||||
return s
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- shell utils
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@memoize
|
||||
def term_supports_colors(file=sys.stdout):
|
||||
if os.name == 'nt':
|
||||
return True
|
||||
try:
|
||||
import curses
|
||||
assert file.isatty()
|
||||
curses.setupterm()
|
||||
assert curses.tigetnum("colors") > 0
|
||||
except Exception:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def hilite(s, color="green", bold=False):
|
||||
"""Return an highlighted version of 'string'."""
|
||||
if not term_supports_colors():
|
||||
return s
|
||||
attr = []
|
||||
colors = dict(green='32', red='91', brown='33')
|
||||
colors[None] = '29'
|
||||
try:
|
||||
color = colors[color]
|
||||
except KeyError:
|
||||
raise ValueError("invalid color %r; choose between %r" % (
|
||||
list(colors.keys())))
|
||||
attr.append(color)
|
||||
if bold:
|
||||
attr.append('1')
|
||||
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), s)
|
||||
|
||||
|
||||
def print_color(s, color="green", bold=False, file=sys.stdout):
|
||||
"""Print a colorized version of string."""
|
||||
if not term_supports_colors():
|
||||
print(s, file=file)
|
||||
elif POSIX:
|
||||
print(hilite(s, color, bold), file=file)
|
||||
else:
|
||||
import ctypes
|
||||
|
||||
DEFAULT_COLOR = 7
|
||||
GetStdHandle = ctypes.windll.Kernel32.GetStdHandle
|
||||
SetConsoleTextAttribute = \
|
||||
ctypes.windll.Kernel32.SetConsoleTextAttribute
|
||||
|
||||
colors = dict(green=2, red=4, brown=6)
|
||||
colors[None] = DEFAULT_COLOR
|
||||
try:
|
||||
color = colors[color]
|
||||
except KeyError:
|
||||
raise ValueError("invalid color %r; choose between %r" % (
|
||||
color, list(colors.keys())))
|
||||
if bold and color <= 7:
|
||||
color += 8
|
||||
|
||||
handle_id = -12 if file is sys.stderr else -11
|
||||
GetStdHandle.restype = ctypes.c_ulong
|
||||
handle = GetStdHandle(handle_id)
|
||||
SetConsoleTextAttribute(handle, color)
|
||||
try:
|
||||
print(s, file=file)
|
||||
finally:
|
||||
SetConsoleTextAttribute(handle, DEFAULT_COLOR)
|
||||
|
||||
|
||||
if bool(os.getenv('PSUTIL_DEBUG', 0)):
|
||||
import inspect
|
||||
|
||||
def debug(msg):
|
||||
"""If PSUTIL_DEBUG env var is set, print a debug message to stderr."""
|
||||
fname, lineno, func_name, lines, index = inspect.getframeinfo(
|
||||
inspect.currentframe().f_back)
|
||||
print("psutil-debug [%s:%s]> %s" % (fname, lineno, msg),
|
||||
file=sys.stderr)
|
||||
else:
|
||||
def debug(msg):
|
||||
pass
|
||||
345
third_party/python/psutil-cp27-none-win_amd64/psutil/_compat.py
vendored
Normal file
345
third_party/python/psutil-cp27-none-win_amd64/psutil/_compat.py
vendored
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
# 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.
|
||||
|
||||
"""Module which provides compatibility with older Python versions."""
|
||||
|
||||
import collections
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import sys
|
||||
|
||||
__all__ = ["PY3", "long", "xrange", "unicode", "basestring", "u", "b",
|
||||
"lru_cache", "which", "get_terminal_size",
|
||||
"FileNotFoundError", "PermissionError", "ProcessLookupError",
|
||||
"InterruptedError", "ChildProcessError", "FileExistsError"]
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
long = int
|
||||
xrange = range
|
||||
unicode = str
|
||||
basestring = str
|
||||
|
||||
def u(s):
|
||||
return s
|
||||
|
||||
def b(s):
|
||||
return s.encode("latin-1")
|
||||
else:
|
||||
long = long
|
||||
xrange = xrange
|
||||
unicode = unicode
|
||||
basestring = basestring
|
||||
|
||||
def u(s):
|
||||
return unicode(s, "unicode_escape")
|
||||
|
||||
def b(s):
|
||||
return s
|
||||
|
||||
|
||||
# --- exceptions
|
||||
|
||||
|
||||
if PY3:
|
||||
FileNotFoundError = FileNotFoundError # NOQA
|
||||
PermissionError = PermissionError # NOQA
|
||||
ProcessLookupError = ProcessLookupError # NOQA
|
||||
InterruptedError = InterruptedError # NOQA
|
||||
ChildProcessError = ChildProcessError # NOQA
|
||||
FileExistsError = FileExistsError # NOQA
|
||||
else:
|
||||
# https://github.com/PythonCharmers/python-future/blob/exceptions/
|
||||
# src/future/types/exceptions/pep3151.py
|
||||
import platform
|
||||
|
||||
_singleton = object()
|
||||
|
||||
def instance_checking_exception(base_exception=Exception):
|
||||
def wrapped(instance_checker):
|
||||
class TemporaryClass(base_exception):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(args) == 1 and isinstance(args[0], TemporaryClass):
|
||||
unwrap_me = args[0]
|
||||
for attr in dir(unwrap_me):
|
||||
if not attr.startswith('__'):
|
||||
setattr(self, attr, getattr(unwrap_me, attr))
|
||||
else:
|
||||
super(TemporaryClass, self).__init__(*args, **kwargs)
|
||||
|
||||
class __metaclass__(type):
|
||||
def __instancecheck__(cls, inst):
|
||||
return instance_checker(inst)
|
||||
|
||||
def __subclasscheck__(cls, classinfo):
|
||||
value = sys.exc_info()[1]
|
||||
return isinstance(value, cls)
|
||||
|
||||
TemporaryClass.__name__ = instance_checker.__name__
|
||||
TemporaryClass.__doc__ = instance_checker.__doc__
|
||||
return TemporaryClass
|
||||
|
||||
return wrapped
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def FileNotFoundError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.ENOENT
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def ProcessLookupError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.ESRCH
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def PermissionError(inst):
|
||||
return getattr(inst, 'errno', _singleton) in (
|
||||
errno.EACCES, errno.EPERM)
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def InterruptedError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.EINTR
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def ChildProcessError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.ECHILD
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def FileExistsError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.EEXIST
|
||||
|
||||
if platform.python_implementation() != "CPython":
|
||||
try:
|
||||
raise OSError(errno.EEXIST, "perm")
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError:
|
||||
raise RuntimeError(
|
||||
"broken / incompatible Python implementation, see: "
|
||||
"https://github.com/giampaolo/psutil/issues/1659")
|
||||
|
||||
|
||||
# --- stdlib additions
|
||||
|
||||
|
||||
# py 3.2 functools.lru_cache
|
||||
# Taken from: http://code.activestate.com/recipes/578078
|
||||
# Credit: Raymond Hettinger
|
||||
try:
|
||||
from functools import lru_cache
|
||||
except ImportError:
|
||||
try:
|
||||
from threading import RLock
|
||||
except ImportError:
|
||||
from dummy_threading import RLock
|
||||
|
||||
_CacheInfo = collections.namedtuple(
|
||||
"CacheInfo", ["hits", "misses", "maxsize", "currsize"])
|
||||
|
||||
class _HashedSeq(list):
|
||||
__slots__ = 'hashvalue'
|
||||
|
||||
def __init__(self, tup, hash=hash):
|
||||
self[:] = tup
|
||||
self.hashvalue = hash(tup)
|
||||
|
||||
def __hash__(self):
|
||||
return self.hashvalue
|
||||
|
||||
def _make_key(args, kwds, typed,
|
||||
kwd_mark=(object(), ),
|
||||
fasttypes=set((int, str, frozenset, type(None))),
|
||||
sorted=sorted, tuple=tuple, type=type, len=len):
|
||||
key = args
|
||||
if kwds:
|
||||
sorted_items = sorted(kwds.items())
|
||||
key += kwd_mark
|
||||
for item in sorted_items:
|
||||
key += item
|
||||
if typed:
|
||||
key += tuple(type(v) for v in args)
|
||||
if kwds:
|
||||
key += tuple(type(v) for k, v in sorted_items)
|
||||
elif len(key) == 1 and type(key[0]) in fasttypes:
|
||||
return key[0]
|
||||
return _HashedSeq(key)
|
||||
|
||||
def lru_cache(maxsize=100, typed=False):
|
||||
"""Least-recently-used cache decorator, see:
|
||||
http://docs.python.org/3/library/functools.html#functools.lru_cache
|
||||
"""
|
||||
def decorating_function(user_function):
|
||||
cache = dict()
|
||||
stats = [0, 0]
|
||||
HITS, MISSES = 0, 1
|
||||
make_key = _make_key
|
||||
cache_get = cache.get
|
||||
_len = len
|
||||
lock = RLock()
|
||||
root = []
|
||||
root[:] = [root, root, None, None]
|
||||
nonlocal_root = [root]
|
||||
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3
|
||||
if maxsize == 0:
|
||||
def wrapper(*args, **kwds):
|
||||
result = user_function(*args, **kwds)
|
||||
stats[MISSES] += 1
|
||||
return result
|
||||
elif maxsize is None:
|
||||
def wrapper(*args, **kwds):
|
||||
key = make_key(args, kwds, typed)
|
||||
result = cache_get(key, root)
|
||||
if result is not root:
|
||||
stats[HITS] += 1
|
||||
return result
|
||||
result = user_function(*args, **kwds)
|
||||
cache[key] = result
|
||||
stats[MISSES] += 1
|
||||
return result
|
||||
else:
|
||||
def wrapper(*args, **kwds):
|
||||
if kwds or typed:
|
||||
key = make_key(args, kwds, typed)
|
||||
else:
|
||||
key = args
|
||||
lock.acquire()
|
||||
try:
|
||||
link = cache_get(key)
|
||||
if link is not None:
|
||||
root, = nonlocal_root
|
||||
link_prev, link_next, key, result = link
|
||||
link_prev[NEXT] = link_next
|
||||
link_next[PREV] = link_prev
|
||||
last = root[PREV]
|
||||
last[NEXT] = root[PREV] = link
|
||||
link[PREV] = last
|
||||
link[NEXT] = root
|
||||
stats[HITS] += 1
|
||||
return result
|
||||
finally:
|
||||
lock.release()
|
||||
result = user_function(*args, **kwds)
|
||||
lock.acquire()
|
||||
try:
|
||||
root, = nonlocal_root
|
||||
if key in cache:
|
||||
pass
|
||||
elif _len(cache) >= maxsize:
|
||||
oldroot = root
|
||||
oldroot[KEY] = key
|
||||
oldroot[RESULT] = result
|
||||
root = nonlocal_root[0] = oldroot[NEXT]
|
||||
oldkey = root[KEY]
|
||||
root[KEY] = root[RESULT] = None
|
||||
del cache[oldkey]
|
||||
cache[key] = oldroot
|
||||
else:
|
||||
last = root[PREV]
|
||||
link = [last, root, key, result]
|
||||
last[NEXT] = root[PREV] = cache[key] = link
|
||||
stats[MISSES] += 1
|
||||
finally:
|
||||
lock.release()
|
||||
return result
|
||||
|
||||
def cache_info():
|
||||
"""Report cache statistics"""
|
||||
lock.acquire()
|
||||
try:
|
||||
return _CacheInfo(stats[HITS], stats[MISSES], maxsize,
|
||||
len(cache))
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
def cache_clear():
|
||||
"""Clear the cache and cache statistics"""
|
||||
lock.acquire()
|
||||
try:
|
||||
cache.clear()
|
||||
root = nonlocal_root[0]
|
||||
root[:] = [root, root, None, None]
|
||||
stats[:] = [0, 0]
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
wrapper.__wrapped__ = user_function
|
||||
wrapper.cache_info = cache_info
|
||||
wrapper.cache_clear = cache_clear
|
||||
return functools.update_wrapper(wrapper, user_function)
|
||||
|
||||
return decorating_function
|
||||
|
||||
|
||||
# python 3.3
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
||||
"""Given a command, mode, and a PATH string, return the path which
|
||||
conforms to the given mode on the PATH, or None if there is no such
|
||||
file.
|
||||
|
||||
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
|
||||
of os.environ.get("PATH"), or can be overridden with a custom search
|
||||
path.
|
||||
"""
|
||||
def _access_check(fn, mode):
|
||||
return (os.path.exists(fn) and os.access(fn, mode) and
|
||||
not os.path.isdir(fn))
|
||||
|
||||
if os.path.dirname(cmd):
|
||||
if _access_check(cmd, mode):
|
||||
return cmd
|
||||
return None
|
||||
|
||||
if path is None:
|
||||
path = os.environ.get("PATH", os.defpath)
|
||||
if not path:
|
||||
return None
|
||||
path = path.split(os.pathsep)
|
||||
|
||||
if sys.platform == "win32":
|
||||
if os.curdir not in path:
|
||||
path.insert(0, os.curdir)
|
||||
|
||||
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
|
||||
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
|
||||
files = [cmd]
|
||||
else:
|
||||
files = [cmd + ext for ext in pathext]
|
||||
else:
|
||||
files = [cmd]
|
||||
|
||||
seen = set()
|
||||
for dir in path:
|
||||
normdir = os.path.normcase(dir)
|
||||
if normdir not in seen:
|
||||
seen.add(normdir)
|
||||
for thefile in files:
|
||||
name = os.path.join(dir, thefile)
|
||||
if _access_check(name, mode):
|
||||
return name
|
||||
return None
|
||||
|
||||
|
||||
# python 3.3
|
||||
try:
|
||||
from shutil import get_terminal_size
|
||||
except ImportError:
|
||||
def get_terminal_size(fallback=(80, 24)):
|
||||
try:
|
||||
import fcntl
|
||||
import termios
|
||||
import struct
|
||||
except ImportError:
|
||||
return fallback
|
||||
else:
|
||||
try:
|
||||
# This should work on Linux.
|
||||
res = struct.unpack(
|
||||
'hh', fcntl.ioctl(1, termios.TIOCGWINSZ, '1234'))
|
||||
return (res[1], res[0])
|
||||
except Exception:
|
||||
return fallback
|
||||
550
third_party/python/psutil-cp27-none-win_amd64/psutil/_psaix.py
vendored
Normal file
550
third_party/python/psutil-cp27-none-win_amd64/psutil/_psaix.py
vendored
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
# Copyright (c) 2009, Giampaolo Rodola'
|
||||
# Copyright (c) 2017, Arnon Yaari
|
||||
# All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""AIX platform implementation."""
|
||||
|
||||
import functools
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_aix as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AccessDenied
|
||||
from ._common import conn_to_ntuple
|
||||
from ._common import get_procfs_path
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NIC_DUPLEX_FULL
|
||||
from ._common import NIC_DUPLEX_HALF
|
||||
from ._common import NIC_DUPLEX_UNKNOWN
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3
|
||||
|
||||
|
||||
__extra__all__ = ["PROCFS_PATH"]
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- globals
|
||||
# =====================================================================
|
||||
|
||||
|
||||
HAS_THREADS = hasattr(cext, "proc_threads")
|
||||
HAS_NET_IO_COUNTERS = hasattr(cext, "net_io_counters")
|
||||
HAS_PROC_IO_COUNTERS = hasattr(cext, "proc_io_counters")
|
||||
|
||||
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SACTIVE: _common.STATUS_RUNNING,
|
||||
cext.SSWAP: _common.STATUS_RUNNING, # TODO what status is this?
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
}
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
proc_info_map = dict(
|
||||
ppid=0,
|
||||
rss=1,
|
||||
vms=2,
|
||||
create_time=3,
|
||||
nice=4,
|
||||
num_threads=5,
|
||||
status=6,
|
||||
ttynr=7)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
# =====================================================================
|
||||
|
||||
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms'])
|
||||
# psutil.Process.memory_full_info()
|
||||
pfullmem = pmem
|
||||
# psutil.Process.cpu_times()
|
||||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
total, avail, free, pinned, inuse = cext.virtual_mem()
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, inuse, free)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
|
||||
total, free, sin, sout = cext.swap_mem()
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- CPU
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system-wide CPU times as a named tuple"""
|
||||
ret = cext.per_cpu_times()
|
||||
return scputimes(*[sum(x) for x in zip(*ret)])
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system per-CPU times as a list of named tuples"""
|
||||
ret = cext.per_cpu_times()
|
||||
return [scputimes(*x) for x in ret]
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
try:
|
||||
return os.sysconf("SC_NPROCESSORS_ONLN")
|
||||
except ValueError:
|
||||
# mimic os.cpu_count() behavior
|
||||
return None
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
cmd = "lsdev -Cc processor"
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError("%r command error\n%s" % (cmd, stderr))
|
||||
processors = stdout.strip().splitlines()
|
||||
return len(processors) or None
|
||||
|
||||
|
||||
def cpu_stats():
|
||||
"""Return various CPU stats as a named tuple."""
|
||||
ctx_switches, interrupts, soft_interrupts, syscalls = cext.cpu_stats()
|
||||
return _common.scpustats(
|
||||
ctx_switches, interrupts, soft_interrupts, syscalls)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- disks
|
||||
# =====================================================================
|
||||
|
||||
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
disk_usage = _psposix.disk_usage
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return system disk partitions."""
|
||||
# TODO - the filtering logic should be better checked so that
|
||||
# it tries to reflect 'df' as much as possible
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
# Differently from, say, Linux, we don't have a list of
|
||||
# common fs types so the best we can do, AFAIK, is to
|
||||
# filter by filesystem having a total size > 0.
|
||||
if not disk_usage(mountpoint).total:
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
||||
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
if HAS_NET_IO_COUNTERS:
|
||||
net_io_counters = cext.net_io_counters
|
||||
|
||||
|
||||
def net_connections(kind, _pid=-1):
|
||||
"""Return socket connections. If pid == -1 return system-wide
|
||||
connections (as opposed to connections opened by one process only).
|
||||
"""
|
||||
cmap = _common.conn_tmap
|
||||
if kind not in cmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||
families, types = _common.conn_tmap[kind]
|
||||
rawlist = cext.net_connections(_pid)
|
||||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type_, laddr, raddr, status, pid = item
|
||||
if fam not in families:
|
||||
continue
|
||||
if type_ not in types:
|
||||
continue
|
||||
nt = conn_to_ntuple(fd, fam, type_, laddr, raddr, status,
|
||||
TCP_STATUSES, pid=pid if _pid == -1 else None)
|
||||
ret.append(nt)
|
||||
return ret
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
duplex_map = {"Full": NIC_DUPLEX_FULL,
|
||||
"Half": NIC_DUPLEX_HALF}
|
||||
names = set([x[0] for x in net_if_addrs()])
|
||||
ret = {}
|
||||
for name in names:
|
||||
isup, mtu = cext.net_if_stats(name)
|
||||
|
||||
# try to get speed and duplex
|
||||
# TODO: rewrite this in C (entstat forks, so use truss -f to follow.
|
||||
# looks like it is using an undocumented ioctl?)
|
||||
duplex = ""
|
||||
speed = 0
|
||||
p = subprocess.Popen(["/usr/bin/entstat", "-d", name],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if p.returncode == 0:
|
||||
re_result = re.search(
|
||||
r"Running: (\d+) Mbps.*?(\w+) Duplex", stdout)
|
||||
if re_result is not None:
|
||||
speed = int(re_result.group(1))
|
||||
duplex = re_result.group(2)
|
||||
|
||||
duplex = duplex_map.get(duplex, NIC_DUPLEX_UNKNOWN)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- other system functions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
localhost = (':0.0', ':0')
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, user_process, pid = item
|
||||
# note: the underlying C function includes entries about
|
||||
# system boot, run level and others. We might want
|
||||
# to use them in the future.
|
||||
if not user_process:
|
||||
continue
|
||||
if hostname in localhost:
|
||||
hostname = 'localhost'
|
||||
nt = _common.suser(user, tty, hostname, tstamp, pid)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- processes
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def pids():
|
||||
"""Returns a list of PIDs currently running on the system."""
|
||||
return [int(x) for x in os.listdir(get_procfs_path()) if x.isdigit()]
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check for the existence of a unix pid."""
|
||||
return os.path.exists(os.path.join(get_procfs_path(), str(pid), "psinfo"))
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Call callable into a try/except clause and translate ENOENT,
|
||||
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# 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 not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
self._procfs_path = get_procfs_path()
|
||||
|
||||
def oneshot_enter(self):
|
||||
self._proc_basic_info.cache_activate(self)
|
||||
self._proc_cred.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self._proc_basic_info.cache_deactivate(self)
|
||||
self._proc_cred.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_basic_info(self):
|
||||
return cext.proc_basic_info(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_cred(self):
|
||||
return cext.proc_cred(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
if self.pid == 0:
|
||||
return "swapper"
|
||||
# note: max 16 characters
|
||||
return cext.proc_name(self.pid, self._procfs_path).rstrip("\x00")
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
# there is no way to get executable path in AIX other than to guess,
|
||||
# and guessing is more complex than what's in the wrapping class
|
||||
cmdline = self.cmdline()
|
||||
if not cmdline:
|
||||
return ''
|
||||
exe = cmdline[0]
|
||||
if os.path.sep in exe:
|
||||
# relative or absolute path
|
||||
if not os.path.isabs(exe):
|
||||
# if cwd has changed, we're out of luck - this may be wrong!
|
||||
exe = os.path.abspath(os.path.join(self.cwd(), exe))
|
||||
if (os.path.isabs(exe) and
|
||||
os.path.isfile(exe) and
|
||||
os.access(exe, os.X_OK)):
|
||||
return exe
|
||||
# not found, move to search in PATH using basename only
|
||||
exe = os.path.basename(exe)
|
||||
# search for exe name PATH
|
||||
for path in os.environ["PATH"].split(":"):
|
||||
possible_exe = os.path.abspath(os.path.join(path, exe))
|
||||
if (os.path.isfile(possible_exe) and
|
||||
os.access(possible_exe, os.X_OK)):
|
||||
return possible_exe
|
||||
return ''
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
return cext.proc_args(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def environ(self):
|
||||
return cext.proc_environ(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return self._proc_basic_info()[proc_info_map['create_time']]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return self._proc_basic_info()[proc_info_map['num_threads']]
|
||||
|
||||
if HAS_THREADS:
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
# The underlying C implementation retrieves all OS threads
|
||||
# and filters them by PID. At this point we can't tell whether
|
||||
# an empty list means there were no connections for process or
|
||||
# process is no longer active so we force NSP in case the PID
|
||||
# is no longer there.
|
||||
if not retlist:
|
||||
# will raise NSP if process is gone
|
||||
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
ret = net_connections(kind, _pid=self.pid)
|
||||
# The underlying C implementation retrieves all OS connections
|
||||
# and filters them by PID. At this point we can't tell whether
|
||||
# an empty list means there were no connections for process or
|
||||
# process is no longer active so we force NSP in case the PID
|
||||
# is no longer there.
|
||||
if not ret:
|
||||
# will raise NSP if process is gone
|
||||
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
return cext_posix.getpriority(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
self._ppid = self._proc_basic_info()[proc_info_map['ppid']]
|
||||
return self._ppid
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
real, effective, saved, _, _, _ = self._proc_cred()
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
_, _, _, real, effective, saved = self._proc_cred()
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
cpu_times = cext.proc_cpu_times(self.pid, self._procfs_path)
|
||||
return _common.pcputimes(*cpu_times)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
ttydev = self._proc_basic_info()[proc_info_map['ttynr']]
|
||||
# convert from 64-bit dev_t to 32-bit dev_t and then map the device
|
||||
ttydev = (((ttydev & 0x0000FFFF00000000) >> 16) | (ttydev & 0xFFFF))
|
||||
# try to match rdev of /dev/pts/* files ttydev
|
||||
for dev in glob.glob("/dev/**/*"):
|
||||
if os.stat(dev).st_rdev == ttydev:
|
||||
return dev
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
procfs_path = self._procfs_path
|
||||
try:
|
||||
result = os.readlink("%s/%s/cwd" % (procfs_path, self.pid))
|
||||
return result.rstrip('/')
|
||||
except FileNotFoundError:
|
||||
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
ret = self._proc_basic_info()
|
||||
rss = ret[proc_info_map['rss']] * 1024
|
||||
vms = ret[proc_info_map['vms']] * 1024
|
||||
return pmem(rss, vms)
|
||||
|
||||
memory_full_info = memory_info
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = self._proc_basic_info()[proc_info_map['status']]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
def open_files(self):
|
||||
# TODO rewrite without using procfiles (stat /proc/pid/fd/* and then
|
||||
# find matching name of the inode)
|
||||
p = subprocess.Popen(["/usr/bin/procfiles", "-n", str(self.pid)],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if "no such process" in stderr.lower():
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
procfiles = re.findall(r"(\d+): S_IFREG.*\s*.*name:(.*)\n", stdout)
|
||||
retlist = []
|
||||
for fd, path in procfiles:
|
||||
path = path.strip()
|
||||
if path.startswith("//"):
|
||||
path = path[1:]
|
||||
if path.lower() == "cannot be retrieved":
|
||||
continue
|
||||
retlist.append(_common.popenfile(path, int(fd)))
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
if self.pid == 0: # no /proc/0/fd
|
||||
return 0
|
||||
return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
return _common.pctxsw(
|
||||
*cext.proc_num_ctx_switches(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||
|
||||
if HAS_PROC_IO_COUNTERS:
|
||||
@wrap_exceptions
|
||||
def io_counters(self):
|
||||
try:
|
||||
rc, wc, rb, wb = cext.proc_io_counters(self.pid)
|
||||
except OSError:
|
||||
# if process is terminated, proc_io_counters returns OSError
|
||||
# instead of NSP
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise
|
||||
return _common.pio(rc, wc, rb, wb)
|
||||
903
third_party/python/psutil-cp27-none-win_amd64/psutil/_psbsd.py
vendored
Normal file
903
third_party/python/psutil-cp27-none-win_amd64/psutil/_psbsd.py
vendored
Normal file
|
|
@ -0,0 +1,903 @@
|
|||
# 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.
|
||||
|
||||
"""FreeBSD, OpenBSD and NetBSD platforms implementation."""
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import namedtuple
|
||||
from collections import defaultdict
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_bsd as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AccessDenied
|
||||
from ._common import conn_tmap
|
||||
from ._common import conn_to_ntuple
|
||||
from ._common import FREEBSD
|
||||
from ._common import memoize
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NETBSD
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import OPENBSD
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import which
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- globals
|
||||
# =====================================================================
|
||||
|
||||
|
||||
if FREEBSD:
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SWAIT: _common.STATUS_WAITING,
|
||||
cext.SLOCK: _common.STATUS_LOCKED,
|
||||
}
|
||||
elif OPENBSD or NETBSD:
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
# According to /usr/include/sys/proc.h SZOMB is unused.
|
||||
# test_zombie_process() shows that SDEAD is the right
|
||||
# equivalent. Also it appears there's no equivalent of
|
||||
# psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE.
|
||||
# cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SDEAD: _common.STATUS_ZOMBIE,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
# From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt
|
||||
# OpenBSD has SRUN and SONPROC: SRUN indicates that a process
|
||||
# is runnable but *not* yet running, i.e. is on a run queue.
|
||||
# SONPROC indicates that the process is actually executing on
|
||||
# a CPU, i.e. it is no longer on a run queue.
|
||||
# As such we'll map SRUN to STATUS_WAKING and SONPROC to
|
||||
# STATUS_RUNNING
|
||||
cext.SRUN: _common.STATUS_WAKING,
|
||||
cext.SONPROC: _common.STATUS_RUNNING,
|
||||
}
|
||||
elif NETBSD:
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SACTIVE: _common.STATUS_RUNNING,
|
||||
cext.SDYING: _common.STATUS_ZOMBIE,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SDEAD: _common.STATUS_DEAD,
|
||||
cext.SSUSPENDED: _common.STATUS_SUSPENDED, # unique to NetBSD
|
||||
}
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
if NETBSD:
|
||||
PAGESIZE = os.sysconf("SC_PAGESIZE")
|
||||
else:
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
HAS_PER_CPU_TIMES = hasattr(cext, "per_cpu_times")
|
||||
HAS_PROC_NUM_THREADS = hasattr(cext, "proc_num_threads")
|
||||
HAS_PROC_OPEN_FILES = hasattr(cext, 'proc_open_files')
|
||||
HAS_PROC_NUM_FDS = hasattr(cext, 'proc_num_fds')
|
||||
|
||||
kinfo_proc_map = dict(
|
||||
ppid=0,
|
||||
status=1,
|
||||
real_uid=2,
|
||||
effective_uid=3,
|
||||
saved_uid=4,
|
||||
real_gid=5,
|
||||
effective_gid=6,
|
||||
saved_gid=7,
|
||||
ttynr=8,
|
||||
create_time=9,
|
||||
ctx_switches_vol=10,
|
||||
ctx_switches_unvol=11,
|
||||
read_io_count=12,
|
||||
write_io_count=13,
|
||||
user_time=14,
|
||||
sys_time=15,
|
||||
ch_user_time=16,
|
||||
ch_sys_time=17,
|
||||
rss=18,
|
||||
vms=19,
|
||||
memtext=20,
|
||||
memdata=21,
|
||||
memstack=22,
|
||||
cpunum=23,
|
||||
name=24,
|
||||
)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
# =====================================================================
|
||||
|
||||
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple(
|
||||
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
||||
'active', 'inactive', 'buffers', 'cached', 'shared', 'wired'])
|
||||
# psutil.cpu_times()
|
||||
scputimes = namedtuple(
|
||||
'scputimes', ['user', 'nice', 'system', 'idle', 'irq'])
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms', 'text', 'data', 'stack'])
|
||||
# psutil.Process.memory_full_info()
|
||||
pfullmem = pmem
|
||||
# psutil.Process.cpu_times()
|
||||
pcputimes = namedtuple('pcputimes',
|
||||
['user', 'system', 'children_user', 'children_system'])
|
||||
# psutil.Process.memory_maps(grouped=True)
|
||||
pmmap_grouped = namedtuple(
|
||||
'pmmap_grouped', 'path rss, private, ref_count, shadow_count')
|
||||
# psutil.Process.memory_maps(grouped=False)
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count')
|
||||
# psutil.disk_io_counters()
|
||||
if FREEBSD:
|
||||
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes',
|
||||
'read_time', 'write_time',
|
||||
'busy_time'])
|
||||
else:
|
||||
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes'])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
"""System virtual memory as a namedtuple."""
|
||||
mem = cext.virtual_mem()
|
||||
total, free, active, inactive, wired, cached, buffers, shared = mem
|
||||
if NETBSD:
|
||||
# On NetBSD buffers and shared mem is determined via /proc.
|
||||
# The C ext set them to 0.
|
||||
with open('/proc/meminfo', 'rb') as f:
|
||||
for line in f:
|
||||
if line.startswith(b'Buffers:'):
|
||||
buffers = int(line.split()[1]) * 1024
|
||||
elif line.startswith(b'MemShared:'):
|
||||
shared = int(line.split()[1]) * 1024
|
||||
avail = inactive + cached + free
|
||||
used = active + wired + cached
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, used, free,
|
||||
active, inactive, buffers, cached, shared, wired)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""System swap memory as (total, used, free, sin, sout) namedtuple."""
|
||||
total, used, free, sin, sout = cext.swap_mem()
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- CPU
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system per-CPU times as a namedtuple"""
|
||||
user, nice, system, idle, irq = cext.cpu_times()
|
||||
return scputimes(user, nice, system, idle, irq)
|
||||
|
||||
|
||||
if HAS_PER_CPU_TIMES:
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a namedtuple"""
|
||||
ret = []
|
||||
for cpu_t in cext.per_cpu_times():
|
||||
user, nice, system, idle, irq = cpu_t
|
||||
item = scputimes(user, nice, system, idle, irq)
|
||||
ret.append(item)
|
||||
return ret
|
||||
else:
|
||||
# XXX
|
||||
# Ok, this is very dirty.
|
||||
# On FreeBSD < 8 we cannot gather per-cpu information, see:
|
||||
# https://github.com/giampaolo/psutil/issues/226
|
||||
# If num cpus > 1, on first call we return single cpu times to avoid a
|
||||
# crash at psutil import time.
|
||||
# Next calls will fail with NotImplementedError
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a namedtuple"""
|
||||
if cpu_count_logical() == 1:
|
||||
return [cpu_times()]
|
||||
if per_cpu_times.__called__:
|
||||
raise NotImplementedError("supported only starting from FreeBSD 8")
|
||||
per_cpu_times.__called__ = True
|
||||
return [cpu_times()]
|
||||
|
||||
per_cpu_times.__called__ = False
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
return cext.cpu_count_logical()
|
||||
|
||||
|
||||
if OPENBSD or NETBSD:
|
||||
def cpu_count_physical():
|
||||
# OpenBSD and NetBSD do not implement this.
|
||||
return 1 if cpu_count_logical() == 1 else None
|
||||
else:
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
# From the C module we'll get an XML string similar to this:
|
||||
# http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
|
||||
# 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]
|
||||
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 cpu_stats():
|
||||
"""Return various CPU stats as a named tuple."""
|
||||
if FREEBSD:
|
||||
# Note: the C ext is returning some metrics we are not exposing:
|
||||
# traps.
|
||||
ctxsw, intrs, soft_intrs, syscalls, traps = cext.cpu_stats()
|
||||
elif NETBSD:
|
||||
# XXX
|
||||
# Note about intrs: the C extension returns 0. intrs
|
||||
# can be determined via /proc/stat; it has the same value as
|
||||
# soft_intrs thought so the kernel is faking it (?).
|
||||
#
|
||||
# Note about syscalls: the C extension always sets it to 0 (?).
|
||||
#
|
||||
# Note: the C ext is returning some metrics we are not exposing:
|
||||
# traps, faults and forks.
|
||||
ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \
|
||||
cext.cpu_stats()
|
||||
with open('/proc/stat', 'rb') as f:
|
||||
for line in f:
|
||||
if line.startswith(b'intr'):
|
||||
intrs = int(line.split()[1])
|
||||
elif OPENBSD:
|
||||
# Note: the C ext is returning some metrics we are not exposing:
|
||||
# traps, faults and forks.
|
||||
ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \
|
||||
cext.cpu_stats()
|
||||
return _common.scpustats(ctxsw, intrs, soft_intrs, syscalls)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- disks
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return mounted disk partitions as a list of namedtuples.
|
||||
'all' argument is ignored, see:
|
||||
https://github.com/giampaolo/psutil/issues/906
|
||||
"""
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
disk_usage = _psposix.disk_usage
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
||||
|
||||
net_io_counters = cext.net_io_counters
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
names = net_io_counters().keys()
|
||||
ret = {}
|
||||
for name in names:
|
||||
try:
|
||||
mtu = cext_posix.net_if_mtu(name)
|
||||
isup = cext_posix.net_if_flags(name)
|
||||
duplex, speed = cext_posix.net_if_duplex_speed(name)
|
||||
except OSError as err:
|
||||
# https://github.com/giampaolo/psutil/issues/1279
|
||||
if err.errno != errno.ENODEV:
|
||||
raise
|
||||
else:
|
||||
if hasattr(_common, 'NicDuplex'):
|
||||
duplex = _common.NicDuplex(duplex)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
def net_connections(kind):
|
||||
"""System-wide network connections."""
|
||||
if OPENBSD:
|
||||
ret = []
|
||||
for pid in pids():
|
||||
try:
|
||||
cons = Process(pid).connections(kind)
|
||||
except (NoSuchProcess, ZombieProcess):
|
||||
continue
|
||||
else:
|
||||
for conn in cons:
|
||||
conn = list(conn)
|
||||
conn.append(pid)
|
||||
ret.append(_common.sconn(*conn))
|
||||
return ret
|
||||
|
||||
if kind not in _common.conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
families, types = conn_tmap[kind]
|
||||
ret = set()
|
||||
if NETBSD:
|
||||
rawlist = cext.net_connections(-1)
|
||||
else:
|
||||
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:
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES, pid)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- sensors
|
||||
# =====================================================================
|
||||
|
||||
|
||||
if FREEBSD:
|
||||
|
||||
def sensors_battery():
|
||||
"""Return battery info."""
|
||||
try:
|
||||
percent, minsleft, power_plugged = cext.sensors_battery()
|
||||
except NotImplementedError:
|
||||
# See: https://github.com/giampaolo/psutil/issues/1074
|
||||
return None
|
||||
power_plugged = power_plugged == 1
|
||||
if power_plugged:
|
||||
secsleft = _common.POWER_TIME_UNLIMITED
|
||||
elif minsleft == -1:
|
||||
secsleft = _common.POWER_TIME_UNKNOWN
|
||||
else:
|
||||
secsleft = minsleft * 60
|
||||
return _common.sbattery(percent, secsleft, power_plugged)
|
||||
|
||||
def sensors_temperatures():
|
||||
"Return CPU cores temperatures if available, else an empty dict."
|
||||
ret = defaultdict(list)
|
||||
num_cpus = cpu_count_logical()
|
||||
for cpu in range(num_cpus):
|
||||
try:
|
||||
current, high = cext.sensors_cpu_temperature(cpu)
|
||||
if high <= 0:
|
||||
high = None
|
||||
name = "Core %s" % cpu
|
||||
ret["coretemp"].append(
|
||||
_common.shwtemp(name, current, high, high))
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
return ret
|
||||
|
||||
def cpu_freq():
|
||||
"""Return frequency metrics for CPUs. As of Dec 2018 only
|
||||
CPU 0 appears to be supported by FreeBSD and all other cores
|
||||
match the frequency of CPU 0.
|
||||
"""
|
||||
ret = []
|
||||
num_cpus = cpu_count_logical()
|
||||
for cpu in range(num_cpus):
|
||||
try:
|
||||
current, available_freq = cext.cpu_frequency(cpu)
|
||||
except NotImplementedError:
|
||||
continue
|
||||
if available_freq:
|
||||
try:
|
||||
min_freq = int(available_freq.split(" ")[-1].split("/")[0])
|
||||
except(IndexError, ValueError):
|
||||
min_freq = None
|
||||
try:
|
||||
max_freq = int(available_freq.split(" ")[0].split("/")[0])
|
||||
except(IndexError, ValueError):
|
||||
max_freq = None
|
||||
ret.append(_common.scpufreq(current, min_freq, max_freq))
|
||||
return ret
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- other system functions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, pid = item
|
||||
if pid == -1:
|
||||
assert OPENBSD
|
||||
pid = None
|
||||
if tty == '~':
|
||||
continue # reboot or shutdown
|
||||
nt = _common.suser(user, tty or None, hostname, tstamp, pid)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- processes
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@memoize
|
||||
def _pid_0_exists():
|
||||
try:
|
||||
Process(0).name()
|
||||
except NoSuchProcess:
|
||||
return False
|
||||
except AccessDenied:
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def pids():
|
||||
"""Returns a list of PIDs currently running on the system."""
|
||||
ret = cext.pids()
|
||||
if OPENBSD and (0 not in ret) and _pid_0_exists():
|
||||
# On OpenBSD the kernel does not return PID 0 (neither does
|
||||
# ps) but it's actually querable (Process(0) will succeed).
|
||||
ret.insert(0, 0)
|
||||
return ret
|
||||
|
||||
|
||||
if OPENBSD or NETBSD:
|
||||
def pid_exists(pid):
|
||||
"""Return True if pid exists."""
|
||||
exists = _psposix.pid_exists(pid)
|
||||
if not exists:
|
||||
# We do this because _psposix.pid_exists() lies in case of
|
||||
# zombie processes.
|
||||
return pid in pids()
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
pid_exists = _psposix.pid_exists
|
||||
|
||||
|
||||
def is_zombie(pid):
|
||||
try:
|
||||
st = cext.proc_oneshot_info(pid)[kinfo_proc_map['status']]
|
||||
return st == cext.SZOMB
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Decorator which translates bare OSError exceptions into
|
||||
NoSuchProcess and AccessDenied.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except ProcessLookupError:
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
except OSError:
|
||||
if self.pid == 0:
|
||||
if 0 in pids():
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
else:
|
||||
raise
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def wrap_exceptions_procfs(inst):
|
||||
"""Same as above, for routines relying on reading /proc fs."""
|
||||
try:
|
||||
yield
|
||||
except (ProcessLookupError, FileNotFoundError):
|
||||
# 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 not pid_exists(inst.pid):
|
||||
raise NoSuchProcess(inst.pid, inst._name)
|
||||
else:
|
||||
raise ZombieProcess(inst.pid, inst._name, inst._ppid)
|
||||
except PermissionError:
|
||||
raise AccessDenied(inst.pid, inst._name)
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
|
||||
def _assert_alive(self):
|
||||
"""Raise NSP if the process disappeared on us."""
|
||||
# For those C function who do not raise NSP, possibly returning
|
||||
# incorrect or incomplete result.
|
||||
cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def oneshot(self):
|
||||
"""Retrieves multiple process info in one shot as a raw tuple."""
|
||||
ret = cext.proc_oneshot_info(self.pid)
|
||||
assert len(ret) == len(kinfo_proc_map)
|
||||
return ret
|
||||
|
||||
def oneshot_enter(self):
|
||||
self.oneshot.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self.oneshot.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
name = self.oneshot()[kinfo_proc_map['name']]
|
||||
return name if name is not None else cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
if FREEBSD:
|
||||
if self.pid == 0:
|
||||
return '' # else NSP
|
||||
return cext.proc_exe(self.pid)
|
||||
elif NETBSD:
|
||||
if self.pid == 0:
|
||||
# /proc/0 dir exists but /proc/0/exe doesn't
|
||||
return ""
|
||||
with wrap_exceptions_procfs(self):
|
||||
return os.readlink("/proc/%s/exe" % self.pid)
|
||||
else:
|
||||
# OpenBSD: exe cannot be determined; references:
|
||||
# https://chromium.googlesource.com/chromium/src/base/+/
|
||||
# master/base_paths_posix.cc
|
||||
# We try our best guess by using which against the first
|
||||
# cmdline arg (may return None).
|
||||
cmdline = self.cmdline()
|
||||
if cmdline:
|
||||
return which(cmdline[0]) or ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
if OPENBSD and self.pid == 0:
|
||||
return [] # ...else it crashes
|
||||
elif NETBSD:
|
||||
# XXX - most of the times the underlying sysctl() call on Net
|
||||
# and Open BSD returns a truncated string.
|
||||
# Also /proc/pid/cmdline behaves the same so it looks
|
||||
# like this is a kernel bug.
|
||||
try:
|
||||
return cext.proc_cmdline(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINVAL:
|
||||
if is_zombie(self.pid):
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
elif not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name, self._ppid)
|
||||
else:
|
||||
# XXX: this happens with unicode tests. It means the C
|
||||
# routine is unable to decode invalid unicode chars.
|
||||
return []
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
return cext.proc_cmdline(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
tty_nr = self.oneshot()[kinfo_proc_map['ttynr']]
|
||||
tmap = _psposix.get_terminal_map()
|
||||
try:
|
||||
return tmap[tty_nr]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
self._ppid = self.oneshot()[kinfo_proc_map['ppid']]
|
||||
return self._ppid
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.puids(
|
||||
rawtuple[kinfo_proc_map['real_uid']],
|
||||
rawtuple[kinfo_proc_map['effective_uid']],
|
||||
rawtuple[kinfo_proc_map['saved_uid']])
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.pgids(
|
||||
rawtuple[kinfo_proc_map['real_gid']],
|
||||
rawtuple[kinfo_proc_map['effective_gid']],
|
||||
rawtuple[kinfo_proc_map['saved_gid']])
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.pcputimes(
|
||||
rawtuple[kinfo_proc_map['user_time']],
|
||||
rawtuple[kinfo_proc_map['sys_time']],
|
||||
rawtuple[kinfo_proc_map['ch_user_time']],
|
||||
rawtuple[kinfo_proc_map['ch_sys_time']])
|
||||
|
||||
if FREEBSD:
|
||||
@wrap_exceptions
|
||||
def cpu_num(self):
|
||||
return self.oneshot()[kinfo_proc_map['cpunum']]
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
rawtuple = self.oneshot()
|
||||
return pmem(
|
||||
rawtuple[kinfo_proc_map['rss']],
|
||||
rawtuple[kinfo_proc_map['vms']],
|
||||
rawtuple[kinfo_proc_map['memtext']],
|
||||
rawtuple[kinfo_proc_map['memdata']],
|
||||
rawtuple[kinfo_proc_map['memstack']])
|
||||
|
||||
memory_full_info = memory_info
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return self.oneshot()[kinfo_proc_map['create_time']]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
if HAS_PROC_NUM_THREADS:
|
||||
# FreeBSD
|
||||
return cext.proc_num_threads(self.pid)
|
||||
else:
|
||||
return len(self.threads())
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.pctxsw(
|
||||
rawtuple[kinfo_proc_map['ctx_switches_vol']],
|
||||
rawtuple[kinfo_proc_map['ctx_switches_unvol']])
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
# Note: on OpenSBD this (/dev/mem) requires root access.
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
if OPENBSD:
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
if kind not in conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
|
||||
if NETBSD:
|
||||
families, types = conn_tmap[kind]
|
||||
ret = []
|
||||
rawlist = cext.net_connections(self.pid)
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status, pid = item
|
||||
assert pid == self.pid
|
||||
if fam in families and type in types:
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
self._assert_alive()
|
||||
return list(ret)
|
||||
|
||||
families, types = conn_tmap[kind]
|
||||
rawlist = cext.proc_connections(self.pid, families, types)
|
||||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
|
||||
if OPENBSD:
|
||||
self._assert_alive()
|
||||
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
return cext_posix.getpriority(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = self.oneshot()[kinfo_proc_map['status']]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
@wrap_exceptions
|
||||
def io_counters(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.pio(
|
||||
rawtuple[kinfo_proc_map['read_io_count']],
|
||||
rawtuple[kinfo_proc_map['write_io_count']],
|
||||
-1,
|
||||
-1)
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
"""Return process current working directory."""
|
||||
# sometimes we get an empty string, in which case we turn
|
||||
# it into None
|
||||
if OPENBSD and self.pid == 0:
|
||||
return None # ...else it would raise EINVAL
|
||||
elif NETBSD or HAS_PROC_OPEN_FILES:
|
||||
# FreeBSD < 8 does not support functions based on
|
||||
# kinfo_getfile() and kinfo_getvmmap()
|
||||
return cext.proc_cwd(self.pid) or None
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"supported only starting from FreeBSD 8" if
|
||||
FREEBSD else "")
|
||||
|
||||
nt_mmap_grouped = namedtuple(
|
||||
'mmap', 'path rss, private, ref_count, shadow_count')
|
||||
nt_mmap_ext = namedtuple(
|
||||
'mmap', 'addr, perms path rss, private, ref_count, shadow_count')
|
||||
|
||||
def _not_implemented(self):
|
||||
raise NotImplementedError
|
||||
|
||||
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||
# and kinfo_getvmmap()
|
||||
if HAS_PROC_OPEN_FILES:
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
"""Return files opened by process as a list of namedtuples."""
|
||||
rawlist = cext.proc_open_files(self.pid)
|
||||
return [_common.popenfile(path, fd) for path, fd in rawlist]
|
||||
else:
|
||||
open_files = _not_implemented
|
||||
|
||||
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||
# and kinfo_getvmmap()
|
||||
if HAS_PROC_NUM_FDS:
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
"""Return the number of file descriptors opened by this process."""
|
||||
ret = cext.proc_num_fds(self.pid)
|
||||
if NETBSD:
|
||||
self._assert_alive()
|
||||
return ret
|
||||
else:
|
||||
num_fds = _not_implemented
|
||||
|
||||
# --- FreeBSD only APIs
|
||||
|
||||
if FREEBSD:
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_affinity_get(self):
|
||||
return cext.proc_cpu_affinity_get(self.pid)
|
||||
|
||||
@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:
|
||||
# 'man cpuset_setaffinity' about EDEADLK:
|
||||
# <<the call would leave a thread without a valid CPU to run
|
||||
# on because the set does not overlap with the thread's
|
||||
# anonymous mask>>
|
||||
if err.errno in (errno.EINVAL, errno.EDEADLK):
|
||||
for cpu in cpus:
|
||||
if cpu not in allcpus:
|
||||
raise ValueError(
|
||||
"invalid CPU #%i (choose between %s)" % (
|
||||
cpu, allcpus))
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_maps(self):
|
||||
return cext.proc_memory_maps(self.pid)
|
||||
2095
third_party/python/psutil-cp27-none-win_amd64/psutil/_pslinux.py
vendored
Normal file
2095
third_party/python/psutil-cp27-none-win_amd64/psutil/_pslinux.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
564
third_party/python/psutil-cp27-none-win_amd64/psutil/_psosx.py
vendored
Normal file
564
third_party/python/psutil-cp27-none-win_amd64/psutil/_psosx.py
vendored
Normal file
|
|
@ -0,0 +1,564 @@
|
|||
# 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.
|
||||
|
||||
"""macOS platform implementation."""
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_osx as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AccessDenied
|
||||
from ._common import conn_tmap
|
||||
from ._common import conn_to_ntuple
|
||||
from ._common import isfile_strict
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import parse_environ_block
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- globals
|
||||
# =====================================================================
|
||||
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
}
|
||||
|
||||
kinfo_proc_map = dict(
|
||||
ppid=0,
|
||||
ruid=1,
|
||||
euid=2,
|
||||
suid=3,
|
||||
rgid=4,
|
||||
egid=5,
|
||||
sgid=6,
|
||||
ttynr=7,
|
||||
ctime=8,
|
||||
status=9,
|
||||
name=10,
|
||||
)
|
||||
|
||||
pidtaskinfo_map = dict(
|
||||
cpuutime=0,
|
||||
cpustime=1,
|
||||
rss=2,
|
||||
vms=3,
|
||||
pfaults=4,
|
||||
pageins=5,
|
||||
numthreads=6,
|
||||
volctxsw=7,
|
||||
)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
# =====================================================================
|
||||
|
||||
|
||||
# psutil.cpu_times()
|
||||
scputimes = namedtuple('scputimes', ['user', 'nice', 'system', 'idle'])
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple(
|
||||
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
||||
'active', 'inactive', 'wired'])
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms', 'pfaults', 'pageins'])
|
||||
# psutil.Process.memory_full_info()
|
||||
pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', ))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
"""System virtual memory as a namedtuple."""
|
||||
total, active, inactive, wired, free, speculative = cext.virtual_mem()
|
||||
# This is how Zabbix calculate avail and used mem:
|
||||
# https://github.com/zabbix/zabbix/blob/trunk/src/libs/zbxsysinfo/
|
||||
# osx/memory.c
|
||||
# Also see: https://github.com/giampaolo/psutil/issues/1277
|
||||
avail = inactive + free
|
||||
used = active + wired
|
||||
# This is NOT how Zabbix calculates free mem but it matches "free"
|
||||
# cmdline utility.
|
||||
free -= speculative
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, used, free,
|
||||
active, inactive, wired)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
|
||||
total, used, free, sin, sout = cext.swap_mem()
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- CPU
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system CPU times as a namedtuple."""
|
||||
user, nice, system, idle = cext.cpu_times()
|
||||
return scputimes(user, nice, system, idle)
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a named tuple"""
|
||||
ret = []
|
||||
for cpu_t in cext.per_cpu_times():
|
||||
user, nice, system, idle = cpu_t
|
||||
item = scputimes(user, nice, system, idle)
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
return cext.cpu_count_logical()
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
return cext.cpu_count_phys()
|
||||
|
||||
|
||||
def cpu_stats():
|
||||
ctx_switches, interrupts, soft_interrupts, syscalls, traps = \
|
||||
cext.cpu_stats()
|
||||
return _common.scpustats(
|
||||
ctx_switches, interrupts, soft_interrupts, syscalls)
|
||||
|
||||
|
||||
def cpu_freq():
|
||||
"""Return CPU frequency.
|
||||
On macOS per-cpu frequency is not supported.
|
||||
Also, the returned frequency never changes, see:
|
||||
https://arstechnica.com/civis/viewtopic.php?f=19&t=465002
|
||||
"""
|
||||
curr, min_, max_ = cext.cpu_freq()
|
||||
return [_common.scpufreq(curr, min_, max_)]
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- disks
|
||||
# =====================================================================
|
||||
|
||||
|
||||
disk_usage = _psposix.disk_usage
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return mounted disk partitions as a list of namedtuples."""
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
if not os.path.isabs(device) or not os.path.exists(device):
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- sensors
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def sensors_battery():
|
||||
"""Return battery information."""
|
||||
try:
|
||||
percent, minsleft, power_plugged = cext.sensors_battery()
|
||||
except NotImplementedError:
|
||||
# no power source - return None according to interface
|
||||
return None
|
||||
power_plugged = power_plugged == 1
|
||||
if power_plugged:
|
||||
secsleft = _common.POWER_TIME_UNLIMITED
|
||||
elif minsleft == -1:
|
||||
secsleft = _common.POWER_TIME_UNKNOWN
|
||||
else:
|
||||
secsleft = minsleft * 60
|
||||
return _common.sbattery(percent, secsleft, power_plugged)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
||||
|
||||
net_io_counters = cext.net_io_counters
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def net_connections(kind='inet'):
|
||||
"""System-wide network connections."""
|
||||
# Note: on macOS this will fail with AccessDenied unless
|
||||
# the process is owned by root.
|
||||
ret = []
|
||||
for pid in pids():
|
||||
try:
|
||||
cons = Process(pid).connections(kind)
|
||||
except NoSuchProcess:
|
||||
continue
|
||||
else:
|
||||
if cons:
|
||||
for c in cons:
|
||||
c = list(c) + [pid]
|
||||
ret.append(_common.sconn(*c))
|
||||
return ret
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
names = net_io_counters().keys()
|
||||
ret = {}
|
||||
for name in names:
|
||||
try:
|
||||
mtu = cext_posix.net_if_mtu(name)
|
||||
isup = cext_posix.net_if_flags(name)
|
||||
duplex, speed = cext_posix.net_if_duplex_speed(name)
|
||||
except OSError as err:
|
||||
# https://github.com/giampaolo/psutil/issues/1279
|
||||
if err.errno != errno.ENODEV:
|
||||
raise
|
||||
else:
|
||||
if hasattr(_common, 'NicDuplex'):
|
||||
duplex = _common.NicDuplex(duplex)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- other system functions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, pid = item
|
||||
if tty == '~':
|
||||
continue # reboot or shutdown
|
||||
if not tstamp:
|
||||
continue
|
||||
nt = _common.suser(user, tty or None, hostname or None, tstamp, pid)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- processes
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def pids():
|
||||
ls = cext.pids()
|
||||
if 0 not in ls:
|
||||
# On certain macOS versions pids() C doesn't return PID 0 but
|
||||
# "ps" does and the process is querable via sysctl():
|
||||
# https://travis-ci.org/giampaolo/psutil/jobs/309619941
|
||||
try:
|
||||
Process(0).create_time()
|
||||
ls.insert(0, 0)
|
||||
except NoSuchProcess:
|
||||
pass
|
||||
except AccessDenied:
|
||||
ls.insert(0, 0)
|
||||
return ls
|
||||
|
||||
|
||||
pid_exists = _psposix.pid_exists
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Decorator which translates bare OSError exceptions into
|
||||
NoSuchProcess and AccessDenied.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except ProcessLookupError:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
except cext.ZombieProcessError:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
return wrapper
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def catch_zombie(proc):
|
||||
"""There are some poor C APIs which incorrectly raise ESRCH when
|
||||
the process is still alive or it's a zombie, or even RuntimeError
|
||||
(those who don't set errno). This is here in order to solve:
|
||||
https://github.com/giampaolo/psutil/issues/1044
|
||||
"""
|
||||
try:
|
||||
yield
|
||||
except (OSError, RuntimeError) as err:
|
||||
if isinstance(err, RuntimeError) or err.errno == errno.ESRCH:
|
||||
try:
|
||||
# status() is not supposed to lie and correctly detect
|
||||
# zombies so if it raises ESRCH it's true.
|
||||
status = proc.status()
|
||||
except NoSuchProcess:
|
||||
raise err
|
||||
else:
|
||||
if status == _common.STATUS_ZOMBIE:
|
||||
raise ZombieProcess(proc.pid, proc._name, proc._ppid)
|
||||
else:
|
||||
raise AccessDenied(proc.pid, proc._name)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _get_kinfo_proc(self):
|
||||
# Note: should work with all PIDs without permission issues.
|
||||
ret = cext.proc_kinfo_oneshot(self.pid)
|
||||
assert len(ret) == len(kinfo_proc_map)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _get_pidtaskinfo(self):
|
||||
# Note: should work for PIDs owned by user only.
|
||||
with catch_zombie(self):
|
||||
ret = cext.proc_pidtaskinfo_oneshot(self.pid)
|
||||
assert len(ret) == len(pidtaskinfo_map)
|
||||
return ret
|
||||
|
||||
def oneshot_enter(self):
|
||||
self._get_kinfo_proc.cache_activate(self)
|
||||
self._get_pidtaskinfo.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self._get_kinfo_proc.cache_deactivate(self)
|
||||
self._get_pidtaskinfo.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
name = self._get_kinfo_proc()[kinfo_proc_map['name']]
|
||||
return name if name is not None else cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
with catch_zombie(self):
|
||||
return cext.proc_exe(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
with catch_zombie(self):
|
||||
return cext.proc_cmdline(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def environ(self):
|
||||
with catch_zombie(self):
|
||||
return parse_environ_block(cext.proc_environ(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
self._ppid = self._get_kinfo_proc()[kinfo_proc_map['ppid']]
|
||||
return self._ppid
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
with catch_zombie(self):
|
||||
return cext.proc_cwd(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
rawtuple = self._get_kinfo_proc()
|
||||
return _common.puids(
|
||||
rawtuple[kinfo_proc_map['ruid']],
|
||||
rawtuple[kinfo_proc_map['euid']],
|
||||
rawtuple[kinfo_proc_map['suid']])
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
rawtuple = self._get_kinfo_proc()
|
||||
return _common.puids(
|
||||
rawtuple[kinfo_proc_map['rgid']],
|
||||
rawtuple[kinfo_proc_map['egid']],
|
||||
rawtuple[kinfo_proc_map['sgid']])
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
tty_nr = self._get_kinfo_proc()[kinfo_proc_map['ttynr']]
|
||||
tmap = _psposix.get_terminal_map()
|
||||
try:
|
||||
return tmap[tty_nr]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
rawtuple = self._get_pidtaskinfo()
|
||||
return pmem(
|
||||
rawtuple[pidtaskinfo_map['rss']],
|
||||
rawtuple[pidtaskinfo_map['vms']],
|
||||
rawtuple[pidtaskinfo_map['pfaults']],
|
||||
rawtuple[pidtaskinfo_map['pageins']],
|
||||
)
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_full_info(self):
|
||||
basic_mem = self.memory_info()
|
||||
uss = cext.proc_memory_uss(self.pid)
|
||||
return pfullmem(*basic_mem + (uss, ))
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
rawtuple = self._get_pidtaskinfo()
|
||||
return _common.pcputimes(
|
||||
rawtuple[pidtaskinfo_map['cpuutime']],
|
||||
rawtuple[pidtaskinfo_map['cpustime']],
|
||||
# children user / system times are not retrievable (set to 0)
|
||||
0.0, 0.0)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return self._get_kinfo_proc()[kinfo_proc_map['ctime']]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
# Unvoluntary value seems not to be available;
|
||||
# getrusage() numbers seems to confirm this theory.
|
||||
# We set it to 0.
|
||||
vol = self._get_pidtaskinfo()[pidtaskinfo_map['volctxsw']]
|
||||
return _common.pctxsw(vol, 0)
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return self._get_pidtaskinfo()[pidtaskinfo_map['numthreads']]
|
||||
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
if self.pid == 0:
|
||||
return []
|
||||
files = []
|
||||
with catch_zombie(self):
|
||||
rawlist = cext.proc_open_files(self.pid)
|
||||
for path, fd in rawlist:
|
||||
if isfile_strict(path):
|
||||
ntuple = _common.popenfile(path, fd)
|
||||
files.append(ntuple)
|
||||
return files
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
if kind not in conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
families, types = conn_tmap[kind]
|
||||
with catch_zombie(self):
|
||||
rawlist = cext.proc_connections(self.pid, families, types)
|
||||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
if self.pid == 0:
|
||||
return 0
|
||||
with catch_zombie(self):
|
||||
return cext.proc_num_fds(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
with catch_zombie(self):
|
||||
return cext_posix.getpriority(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
with catch_zombie(self):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = self._get_kinfo_proc()[kinfo_proc_map['status']]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
175
third_party/python/psutil-cp27-none-win_amd64/psutil/_psposix.py
vendored
Normal file
175
third_party/python/psutil-cp27-none-win_amd64/psutil/_psposix.py
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# 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.
|
||||
|
||||
"""Routines common to all posix systems."""
|
||||
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from ._common import memoize
|
||||
from ._common import sdiskusage
|
||||
from ._common import TimeoutExpired
|
||||
from ._common import usage_percent
|
||||
from ._compat import ChildProcessError
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import InterruptedError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3
|
||||
from ._compat import unicode
|
||||
|
||||
|
||||
__all__ = ['pid_exists', 'wait_pid', 'disk_usage', 'get_terminal_map']
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check whether pid exists in the current process table."""
|
||||
if pid == 0:
|
||||
# According to "man 2 kill" PID 0 has a special meaning:
|
||||
# it refers to <<every process in the process group of the
|
||||
# calling process>> so we don't want to go any further.
|
||||
# If we get here it means this UNIX platform *does* have
|
||||
# a process with id 0.
|
||||
return True
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
except PermissionError:
|
||||
# EPERM clearly means there's a process to deny access to
|
||||
return True
|
||||
# According to "man 2 kill" possible error values are
|
||||
# (EINVAL, EPERM, ESRCH)
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def wait_pid(pid, timeout=None, proc_name=None):
|
||||
"""Wait for process with pid 'pid' to terminate and return its
|
||||
exit status code as an integer.
|
||||
|
||||
If pid is not a children of os.getpid() (current process) just
|
||||
waits until the process disappears and return None.
|
||||
|
||||
If pid does not exist at all return None immediately.
|
||||
|
||||
Raise TimeoutExpired on timeout expired.
|
||||
"""
|
||||
def check_timeout(delay):
|
||||
if timeout is not None:
|
||||
if timer() >= stop_at:
|
||||
raise TimeoutExpired(timeout, pid=pid, name=proc_name)
|
||||
time.sleep(delay)
|
||||
return min(delay * 2, 0.04)
|
||||
|
||||
timer = getattr(time, 'monotonic', time.time)
|
||||
if timeout is not None:
|
||||
def waitcall():
|
||||
return os.waitpid(pid, os.WNOHANG)
|
||||
stop_at = timer() + timeout
|
||||
else:
|
||||
def waitcall():
|
||||
return os.waitpid(pid, 0)
|
||||
|
||||
delay = 0.0001
|
||||
while True:
|
||||
try:
|
||||
retpid, status = waitcall()
|
||||
except InterruptedError:
|
||||
delay = check_timeout(delay)
|
||||
except ChildProcessError:
|
||||
# This has two meanings:
|
||||
# - pid is not a child of os.getpid() in which case
|
||||
# we keep polling until it's gone
|
||||
# - pid never existed in the first place
|
||||
# In both cases we'll eventually return None as we
|
||||
# can't determine its exit status code.
|
||||
while True:
|
||||
if pid_exists(pid):
|
||||
delay = check_timeout(delay)
|
||||
else:
|
||||
return
|
||||
else:
|
||||
if retpid == 0:
|
||||
# WNOHANG was used, pid is still running
|
||||
delay = check_timeout(delay)
|
||||
continue
|
||||
# process exited due to a signal; return the integer of
|
||||
# that signal
|
||||
if os.WIFSIGNALED(status):
|
||||
return -os.WTERMSIG(status)
|
||||
# process exited using exit(2) system call; return the
|
||||
# integer exit(2) system call has been called with
|
||||
elif os.WIFEXITED(status):
|
||||
return os.WEXITSTATUS(status)
|
||||
else:
|
||||
# should never happen
|
||||
raise ValueError("unknown process exit status %r" % status)
|
||||
|
||||
|
||||
def disk_usage(path):
|
||||
"""Return disk usage associated with path.
|
||||
Note: UNIX usually reserves 5% disk space which is not accessible
|
||||
by user. In this function "total" and "used" values reflect the
|
||||
total and used disk space whereas "free" and "percent" represent
|
||||
the "free" and "used percent" user disk space.
|
||||
"""
|
||||
if PY3:
|
||||
st = os.statvfs(path)
|
||||
else:
|
||||
# os.statvfs() does not support unicode on Python 2:
|
||||
# - https://github.com/giampaolo/psutil/issues/416
|
||||
# - http://bugs.python.org/issue18695
|
||||
try:
|
||||
st = os.statvfs(path)
|
||||
except UnicodeEncodeError:
|
||||
if isinstance(path, unicode):
|
||||
try:
|
||||
path = path.encode(sys.getfilesystemencoding())
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
st = os.statvfs(path)
|
||||
else:
|
||||
raise
|
||||
|
||||
# Total space which is only available to root (unless changed
|
||||
# at system level).
|
||||
total = (st.f_blocks * st.f_frsize)
|
||||
# Remaining free space usable by root.
|
||||
avail_to_root = (st.f_bfree * st.f_frsize)
|
||||
# Remaining free space usable by user.
|
||||
avail_to_user = (st.f_bavail * st.f_frsize)
|
||||
# Total space being used in general.
|
||||
used = (total - avail_to_root)
|
||||
# Total space which is available to user (same as 'total' but
|
||||
# for the user).
|
||||
total_user = used + avail_to_user
|
||||
# User usage percent compared to the total amount of space
|
||||
# the user can use. This number would be higher if compared
|
||||
# to root's because the user has less space (usually -5%).
|
||||
usage_percent_user = usage_percent(used, total_user, round_=1)
|
||||
|
||||
# NB: the percentage is -5% than what shown by df due to
|
||||
# reserved blocks that we are currently not considering:
|
||||
# https://github.com/giampaolo/psutil/issues/829#issuecomment-223750462
|
||||
return sdiskusage(
|
||||
total=total, used=used, free=avail_to_user, percent=usage_percent_user)
|
||||
|
||||
|
||||
@memoize
|
||||
def get_terminal_map():
|
||||
"""Get a map of device-id -> path as a dict.
|
||||
Used by Process.terminal()
|
||||
"""
|
||||
ret = {}
|
||||
ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*')
|
||||
for name in ls:
|
||||
assert name not in ret, name
|
||||
try:
|
||||
ret[os.stat(name).st_rdev] = name
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return ret
|
||||
725
third_party/python/psutil-cp27-none-win_amd64/psutil/_pssunos.py
vendored
Normal file
725
third_party/python/psutil-cp27-none-win_amd64/psutil/_pssunos.py
vendored
Normal file
|
|
@ -0,0 +1,725 @@
|
|||
# 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.
|
||||
|
||||
"""Sun OS Solaris platform implementation."""
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_posix as cext_posix
|
||||
from . import _psutil_sunos as cext
|
||||
from ._common import AccessDenied
|
||||
from ._common import AF_INET6
|
||||
from ._common import debug
|
||||
from ._common import get_procfs_path
|
||||
from ._common import isfile_strict
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import b
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3
|
||||
|
||||
|
||||
__extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"]
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- globals
|
||||
# =====================================================================
|
||||
|
||||
|
||||
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
IS_64_BIT = sys.maxsize > 2**32
|
||||
|
||||
CONN_IDLE = "IDLE"
|
||||
CONN_BOUND = "BOUND"
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SONPROC: _common.STATUS_RUNNING, # same as run
|
||||
cext.SWAIT: _common.STATUS_WAITING,
|
||||
}
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
cext.TCPS_IDLE: CONN_IDLE, # sunos specific
|
||||
cext.TCPS_BOUND: CONN_BOUND, # sunos specific
|
||||
}
|
||||
|
||||
proc_info_map = dict(
|
||||
ppid=0,
|
||||
rss=1,
|
||||
vms=2,
|
||||
create_time=3,
|
||||
nice=4,
|
||||
num_threads=5,
|
||||
status=6,
|
||||
ttynr=7,
|
||||
uid=8,
|
||||
euid=9,
|
||||
gid=10,
|
||||
egid=11)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
# =====================================================================
|
||||
|
||||
|
||||
# psutil.cpu_times()
|
||||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
||||
# psutil.cpu_times(percpu=True)
|
||||
pcputimes = namedtuple('pcputimes',
|
||||
['user', 'system', 'children_user', 'children_system'])
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms'])
|
||||
pfullmem = pmem
|
||||
# psutil.Process.memory_maps(grouped=True)
|
||||
pmmap_grouped = namedtuple('pmmap_grouped',
|
||||
['path', 'rss', 'anonymous', 'locked'])
|
||||
# psutil.Process.memory_maps(grouped=False)
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
"""Report virtual memory metrics."""
|
||||
# we could have done this with kstat, but IMHO this is good enough
|
||||
total = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE
|
||||
# note: there's no difference on Solaris
|
||||
free = avail = os.sysconf('SC_AVPHYS_PAGES') * PAGE_SIZE
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return svmem(total, avail, percent, used, free)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""Report swap memory metrics."""
|
||||
sin, sout = cext.swap_mem()
|
||||
# XXX
|
||||
# we are supposed to get total/free by doing so:
|
||||
# http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/
|
||||
# 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(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' %
|
||||
os.environ['PATH'], 'swap', '-l'],
|
||||
stdout=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout = stdout.decode(sys.stdout.encoding)
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError("'swap -l' failed (retcode=%s)" % p.returncode)
|
||||
|
||||
lines = stdout.strip().split('\n')[1:]
|
||||
if not lines:
|
||||
raise RuntimeError('no swap device(s) configured')
|
||||
total = free = 0
|
||||
for line in lines:
|
||||
line = line.split()
|
||||
t, f = line[-2:]
|
||||
total += int(int(t) * 512)
|
||||
free += int(int(f) * 512)
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent,
|
||||
sin * PAGE_SIZE, sout * PAGE_SIZE)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- CPU
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system-wide CPU times as a named tuple"""
|
||||
ret = cext.per_cpu_times()
|
||||
return scputimes(*[sum(x) for x in zip(*ret)])
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system per-CPU times as a list of named tuples"""
|
||||
ret = cext.per_cpu_times()
|
||||
return [scputimes(*x) for x in ret]
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
try:
|
||||
return os.sysconf("SC_NPROCESSORS_ONLN")
|
||||
except ValueError:
|
||||
# mimic os.cpu_count() behavior
|
||||
return None
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
return cext.cpu_count_phys()
|
||||
|
||||
|
||||
def cpu_stats():
|
||||
"""Return various CPU stats as a named tuple."""
|
||||
ctx_switches, interrupts, syscalls, traps = cext.cpu_stats()
|
||||
soft_interrupts = 0
|
||||
return _common.scpustats(ctx_switches, interrupts, soft_interrupts,
|
||||
syscalls)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- disks
|
||||
# =====================================================================
|
||||
|
||||
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
disk_usage = _psposix.disk_usage
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return system disk partitions."""
|
||||
# TODO - the filtering logic should be better checked so that
|
||||
# it tries to reflect 'df' as much as possible
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
# Differently from, say, Linux, we don't have a list of
|
||||
# common fs types so the best we can do, AFAIK, is to
|
||||
# filter by filesystem having a total size > 0.
|
||||
try:
|
||||
if not disk_usage(mountpoint).total:
|
||||
continue
|
||||
except OSError as err:
|
||||
# https://github.com/giampaolo/psutil/issues/1674
|
||||
debug("skipping %r: %r" % (mountpoint, err))
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
||||
|
||||
net_io_counters = cext.net_io_counters
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def net_connections(kind, _pid=-1):
|
||||
"""Return socket connections. If pid == -1 return system-wide
|
||||
connections (as opposed to connections opened by one process only).
|
||||
Only INET sockets are returned (UNIX are not).
|
||||
"""
|
||||
cmap = _common.conn_tmap.copy()
|
||||
if _pid == -1:
|
||||
cmap.pop('unix', 0)
|
||||
if kind not in cmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||
families, types = _common.conn_tmap[kind]
|
||||
rawlist = cext.net_connections(_pid)
|
||||
ret = set()
|
||||
for item in rawlist:
|
||||
fd, fam, type_, laddr, raddr, status, pid = item
|
||||
if fam not in families:
|
||||
continue
|
||||
if type_ not in types:
|
||||
continue
|
||||
# TODO: refactor and use _common.conn_to_ntuple.
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
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.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
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- other system functions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
localhost = (':0.0', ':0')
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, user_process, pid = item
|
||||
# note: the underlying C function includes entries about
|
||||
# system boot, run level and others. We might want
|
||||
# to use them in the future.
|
||||
if not user_process:
|
||||
continue
|
||||
if hostname in localhost:
|
||||
hostname = 'localhost'
|
||||
nt = _common.suser(user, tty, hostname, tstamp, pid)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- processes
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def pids():
|
||||
"""Returns a list of PIDs currently running on the system."""
|
||||
return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()]
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check for the existence of a unix pid."""
|
||||
return _psposix.pid_exists(pid)
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Call callable into a try/except clause and translate ENOENT,
|
||||
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# 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 not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
except OSError:
|
||||
if self.pid == 0:
|
||||
if 0 in pids():
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
else:
|
||||
raise
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
self._procfs_path = get_procfs_path()
|
||||
|
||||
def _assert_alive(self):
|
||||
"""Raise NSP if the process disappeared on us."""
|
||||
# For those C function who do not raise NSP, possibly returning
|
||||
# incorrect or incomplete result.
|
||||
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||
|
||||
def oneshot_enter(self):
|
||||
self._proc_name_and_args.cache_activate(self)
|
||||
self._proc_basic_info.cache_activate(self)
|
||||
self._proc_cred.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self._proc_name_and_args.cache_deactivate(self)
|
||||
self._proc_basic_info.cache_deactivate(self)
|
||||
self._proc_cred.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_name_and_args(self):
|
||||
return cext.proc_name_and_args(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_basic_info(self):
|
||||
if self.pid == 0 and not \
|
||||
os.path.exists('%s/%s/psinfo' % (self._procfs_path, self.pid)):
|
||||
raise AccessDenied(self.pid)
|
||||
ret = cext.proc_basic_info(self.pid, self._procfs_path)
|
||||
assert len(ret) == len(proc_info_map)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_cred(self):
|
||||
return cext.proc_cred(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
# note: max len == 15
|
||||
return self._proc_name_and_args()[0]
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
try:
|
||||
return os.readlink(
|
||||
"%s/%s/path/a.out" % (self._procfs_path, self.pid))
|
||||
except OSError:
|
||||
pass # continue and guess the exe name from the cmdline
|
||||
# Will be guessed later from cmdline but we want to explicitly
|
||||
# invoke cmdline here in order to get an AccessDenied
|
||||
# exception if the user has not enough privileges.
|
||||
self.cmdline()
|
||||
return ""
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
return self._proc_name_and_args()[1].split(' ')
|
||||
|
||||
@wrap_exceptions
|
||||
def environ(self):
|
||||
return cext.proc_environ(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return self._proc_basic_info()[proc_info_map['create_time']]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return self._proc_basic_info()[proc_info_map['num_threads']]
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
# Note #1: getpriority(3) doesn't work for realtime processes.
|
||||
# Psinfo is what ps uses, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1194
|
||||
return self._proc_basic_info()[proc_info_map['nice']]
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
if self.pid in (2, 3):
|
||||
# Special case PIDs: internally setpriority(3) return ESRCH
|
||||
# (no such process), no matter what.
|
||||
# The process actually exists though, as it has a name,
|
||||
# creation time, etc.
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
self._ppid = self._proc_basic_info()[proc_info_map['ppid']]
|
||||
return self._ppid
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
try:
|
||||
real, effective, saved, _, _, _ = self._proc_cred()
|
||||
except AccessDenied:
|
||||
real = self._proc_basic_info()[proc_info_map['uid']]
|
||||
effective = self._proc_basic_info()[proc_info_map['euid']]
|
||||
saved = None
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
try:
|
||||
_, _, _, real, effective, saved = self._proc_cred()
|
||||
except AccessDenied:
|
||||
real = self._proc_basic_info()[proc_info_map['gid']]
|
||||
effective = self._proc_basic_info()[proc_info_map['egid']]
|
||||
saved = None
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
try:
|
||||
times = cext.proc_cpu_times(self.pid, self._procfs_path)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||
# We may get here if we attempt to query a 64bit process
|
||||
# with a 32bit python.
|
||||
# Error originates from read() and also tools like "cat"
|
||||
# fail in the same way (!).
|
||||
# Since there simply is no way to determine CPU times we
|
||||
# return 0.0 as a fallback. See:
|
||||
# https://github.com/giampaolo/psutil/issues/857
|
||||
times = (0.0, 0.0, 0.0, 0.0)
|
||||
else:
|
||||
raise
|
||||
return _common.pcputimes(*times)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_num(self):
|
||||
return cext.proc_cpu_num(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
procfs_path = self._procfs_path
|
||||
hit_enoent = False
|
||||
tty = wrap_exceptions(
|
||||
self._proc_basic_info()[proc_info_map['ttynr']])
|
||||
if tty != cext.PRNODEV:
|
||||
for x in (0, 1, 2, 255):
|
||||
try:
|
||||
return os.readlink(
|
||||
'%s/%d/path/%d' % (procfs_path, self.pid, x))
|
||||
except FileNotFoundError:
|
||||
hit_enoent = True
|
||||
continue
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
# /proc/PID/path/cwd may not be resolved by readlink() even if
|
||||
# it exists (ls shows it). If that's the case and the process
|
||||
# is still alive return None (we can return None also on BSD).
|
||||
# Reference: http://goo.gl/55XgO
|
||||
procfs_path = self._procfs_path
|
||||
try:
|
||||
return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid))
|
||||
except FileNotFoundError:
|
||||
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
ret = self._proc_basic_info()
|
||||
rss = ret[proc_info_map['rss']] * 1024
|
||||
vms = ret[proc_info_map['vms']] * 1024
|
||||
return pmem(rss, vms)
|
||||
|
||||
memory_full_info = memory_info
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = self._proc_basic_info()[proc_info_map['status']]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
procfs_path = self._procfs_path
|
||||
ret = []
|
||||
tids = os.listdir('%s/%d/lwp' % (procfs_path, self.pid))
|
||||
hit_enoent = False
|
||||
for tid in tids:
|
||||
tid = int(tid)
|
||||
try:
|
||||
utime, stime = cext.query_process_thread(
|
||||
self.pid, tid, procfs_path)
|
||||
except EnvironmentError as err:
|
||||
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||
# We may get here if we attempt to query a 64bit process
|
||||
# with a 32bit python.
|
||||
# Error originates from read() and also tools like "cat"
|
||||
# fail in the same way (!).
|
||||
# Since there simply is no way to determine CPU times we
|
||||
# return 0.0 as a fallback. See:
|
||||
# https://github.com/giampaolo/psutil/issues/857
|
||||
continue
|
||||
# ENOENT == thread gone in meantime
|
||||
if err.errno == errno.ENOENT:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
nt = _common.pthread(tid, utime, stime)
|
||||
ret.append(nt)
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
retlist = []
|
||||
hit_enoent = False
|
||||
procfs_path = self._procfs_path
|
||||
pathdir = '%s/%d/path' % (procfs_path, self.pid)
|
||||
for fd in os.listdir('%s/%d/fd' % (procfs_path, self.pid)):
|
||||
path = os.path.join(pathdir, fd)
|
||||
if os.path.islink(path):
|
||||
try:
|
||||
file = os.readlink(path)
|
||||
except FileNotFoundError:
|
||||
hit_enoent = True
|
||||
continue
|
||||
else:
|
||||
if isfile_strict(file):
|
||||
retlist.append(_common.popenfile(file, int(fd)))
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
def _get_unix_sockets(self, pid):
|
||||
"""Get UNIX sockets used by process by parsing 'pfiles' output."""
|
||||
# TODO: rewrite this in C (...but the damn netstat source code
|
||||
# does not include this part! Argh!!)
|
||||
cmd = "pfiles %s" % pid
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if p.returncode != 0:
|
||||
if 'permission denied' in stderr.lower():
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
if 'no such process' in stderr.lower():
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise RuntimeError("%r command error\n%s" % (cmd, stderr))
|
||||
|
||||
lines = stdout.split('\n')[2:]
|
||||
for i, line in enumerate(lines):
|
||||
line = line.lstrip()
|
||||
if line.startswith('sockname: AF_UNIX'):
|
||||
path = line.split(' ', 2)[2]
|
||||
type = lines[i - 2].strip()
|
||||
if type == 'SOCK_STREAM':
|
||||
type = socket.SOCK_STREAM
|
||||
elif type == 'SOCK_DGRAM':
|
||||
type = socket.SOCK_DGRAM
|
||||
else:
|
||||
type = -1
|
||||
yield (-1, socket.AF_UNIX, type, path, "", _common.CONN_NONE)
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
ret = net_connections(kind, _pid=self.pid)
|
||||
# The underlying C implementation retrieves all OS connections
|
||||
# and filters them by PID. At this point we can't tell whether
|
||||
# an empty list means there were no connections for process or
|
||||
# process is no longer active so we force NSP in case the PID
|
||||
# is no longer there.
|
||||
if not ret:
|
||||
# will raise NSP if process is gone
|
||||
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||
|
||||
# UNIX sockets
|
||||
if kind in ('all', 'unix'):
|
||||
ret.extend([_common.pconn(*conn) for conn in
|
||||
self._get_unix_sockets(self.pid)])
|
||||
return ret
|
||||
|
||||
nt_mmap_grouped = namedtuple('mmap', 'path rss anon locked')
|
||||
nt_mmap_ext = namedtuple('mmap', 'addr perms path rss anon locked')
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_maps(self):
|
||||
def toaddr(start, end):
|
||||
return '%s-%s' % (hex(start)[2:].strip('L'),
|
||||
hex(end)[2:].strip('L'))
|
||||
|
||||
procfs_path = self._procfs_path
|
||||
retlist = []
|
||||
try:
|
||||
rawlist = cext.proc_memory_maps(self.pid, procfs_path)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||
# We may get here if we attempt to query a 64bit process
|
||||
# with a 32bit python.
|
||||
# Error originates from read() and also tools like "cat"
|
||||
# fail in the same way (!).
|
||||
# Since there simply is no way to determine CPU times we
|
||||
# return 0.0 as a fallback. See:
|
||||
# https://github.com/giampaolo/psutil/issues/857
|
||||
return []
|
||||
else:
|
||||
raise
|
||||
hit_enoent = False
|
||||
for item in rawlist:
|
||||
addr, addrsize, perm, name, rss, anon, locked = item
|
||||
addr = toaddr(addr, addrsize)
|
||||
if not name.startswith('['):
|
||||
try:
|
||||
name = os.readlink(
|
||||
'%s/%s/path/%s' % (procfs_path, self.pid, name))
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
# sometimes the link may not be resolved by
|
||||
# readlink() even if it exists (ls shows it).
|
||||
# If that's the case we just return the
|
||||
# unresolved link path.
|
||||
# This seems an incosistency with /proc similar
|
||||
# to: http://goo.gl/55XgO
|
||||
name = '%s/%s/path/%s' % (procfs_path, self.pid, name)
|
||||
hit_enoent = True
|
||||
else:
|
||||
raise
|
||||
retlist.append((addr, perm, name, rss, anon, locked))
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
return _common.pctxsw(
|
||||
*cext.proc_num_ctx_switches(self.pid, self._procfs_path))
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||
BIN
third_party/python/psutil-cp27-none-win_amd64/psutil/_psutil_windows.pyd
vendored
Normal file
BIN
third_party/python/psutil-cp27-none-win_amd64/psutil/_psutil_windows.pyd
vendored
Normal file
Binary file not shown.
1105
third_party/python/psutil-cp27-none-win_amd64/psutil/_pswindows.py
vendored
Normal file
1105
third_party/python/psutil-cp27-none-win_amd64/psutil/_pswindows.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
1137
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/__init__.py
vendored
Normal file
1137
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/__init__.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
13
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/__main__.py
vendored
Normal file
13
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/__main__.py
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Run unit tests. This is invoked by:
|
||||
$ python -m psutil.tests
|
||||
"""
|
||||
|
||||
from .runner import main
|
||||
main()
|
||||
162
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/runner.py
vendored
Normal file
162
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/runner.py
vendored
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Unit test runner, providing new features on top of unittest module:
|
||||
- colourized output (error, skip)
|
||||
- print failures/tracebacks on CTRL+C
|
||||
- re-run failed tests only (make test-failed)
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from unittest import TestResult
|
||||
from unittest import TextTestResult
|
||||
from unittest import TextTestRunner
|
||||
try:
|
||||
import ctypes
|
||||
except ImportError:
|
||||
ctypes = None
|
||||
|
||||
import psutil
|
||||
from psutil._common import hilite
|
||||
from psutil._common import print_color
|
||||
from psutil._common import term_supports_colors
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import TOX
|
||||
|
||||
|
||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||
VERBOSITY = 1 if TOX else 2
|
||||
FAILED_TESTS_FNAME = '.failed-tests.txt'
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- unittest subclasses
|
||||
# =====================================================================
|
||||
|
||||
|
||||
class ColouredResult(TextTestResult):
|
||||
|
||||
def _print_color(self, s, color, bold=False):
|
||||
file = sys.stderr if color == "red" else sys.stdout
|
||||
print_color(s, color, bold=bold, file=file)
|
||||
|
||||
def addSuccess(self, test):
|
||||
TestResult.addSuccess(self, test)
|
||||
self._print_color("OK", "green")
|
||||
|
||||
def addError(self, test, err):
|
||||
TestResult.addError(self, test, err)
|
||||
self._print_color("ERROR", "red", bold=True)
|
||||
|
||||
def addFailure(self, test, err):
|
||||
TestResult.addFailure(self, test, err)
|
||||
self._print_color("FAIL", "red")
|
||||
|
||||
def addSkip(self, test, reason):
|
||||
TestResult.addSkip(self, test, reason)
|
||||
self._print_color("skipped: %s" % reason, "brown")
|
||||
|
||||
def printErrorList(self, flavour, errors):
|
||||
flavour = hilite(flavour, "red", bold=flavour == 'ERROR')
|
||||
TextTestResult.printErrorList(self, flavour, errors)
|
||||
|
||||
|
||||
class ColouredRunner(TextTestRunner):
|
||||
resultclass = ColouredResult if term_supports_colors() else TextTestResult
|
||||
|
||||
def _makeResult(self):
|
||||
# Store result instance so that it can be accessed on
|
||||
# KeyboardInterrupt.
|
||||
self.result = TextTestRunner._makeResult(self)
|
||||
return self.result
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- public API
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def setup_tests():
|
||||
if 'PSUTIL_TESTING' not in os.environ:
|
||||
# This won't work on Windows but set_testing() below will do it.
|
||||
os.environ['PSUTIL_TESTING'] = '1'
|
||||
psutil._psplatform.cext.set_testing()
|
||||
|
||||
|
||||
def get_suite(name=None):
|
||||
suite = unittest.TestSuite()
|
||||
if name is None:
|
||||
testmods = [os.path.splitext(x)[0] for x in os.listdir(HERE)
|
||||
if x.endswith('.py') and x.startswith('test_') and not
|
||||
x.startswith('test_memory_leaks')]
|
||||
if "WHEELHOUSE_UPLOADER_USERNAME" in os.environ:
|
||||
testmods = [x for x in testmods if not x.endswith((
|
||||
"osx", "posix", "linux"))]
|
||||
for tm in testmods:
|
||||
# ...so that the full test paths are printed on screen
|
||||
tm = "psutil.tests.%s" % tm
|
||||
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(tm))
|
||||
else:
|
||||
name = os.path.splitext(os.path.basename(name))[0]
|
||||
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(name))
|
||||
return suite
|
||||
|
||||
|
||||
def get_suite_from_failed():
|
||||
# ...from previously failed test run
|
||||
suite = unittest.TestSuite()
|
||||
if not os.path.isfile(FAILED_TESTS_FNAME):
|
||||
return suite
|
||||
with open(FAILED_TESTS_FNAME, 'rt') as f:
|
||||
names = f.read().split()
|
||||
for n in names:
|
||||
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(n))
|
||||
return suite
|
||||
|
||||
|
||||
def save_failed_tests(result):
|
||||
if result.wasSuccessful():
|
||||
return safe_rmpath(FAILED_TESTS_FNAME)
|
||||
with open(FAILED_TESTS_FNAME, 'wt') as f:
|
||||
for t in result.errors + result.failures:
|
||||
tname = str(t[0])
|
||||
unittest.defaultTestLoader.loadTestsFromName(tname)
|
||||
f.write(tname + '\n')
|
||||
|
||||
|
||||
def run(name=None, last_failed=False):
|
||||
setup_tests()
|
||||
runner = ColouredRunner(verbosity=VERBOSITY)
|
||||
suite = get_suite_from_failed() if last_failed else get_suite(name)
|
||||
try:
|
||||
result = runner.run(suite)
|
||||
except (KeyboardInterrupt, SystemExit) as err:
|
||||
print("received %s" % err.__class__.__name__, file=sys.stderr)
|
||||
runner.result.printErrors()
|
||||
sys.exit(1)
|
||||
else:
|
||||
save_failed_tests(result)
|
||||
success = result.wasSuccessful()
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
|
||||
def main():
|
||||
usage = "python3 -m psutil.tests [opts]"
|
||||
parser = optparse.OptionParser(usage=usage, description="run unit tests")
|
||||
parser.add_option("--last-failed",
|
||||
action="store_true", default=False,
|
||||
help="only run last failed tests")
|
||||
opts, args = parser.parse_args()
|
||||
run(last_failed=opts.last_failed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
121
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_aix.py
vendored
Normal file
121
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_aix.py
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'
|
||||
# Copyright (c) 2017, Arnon Yaari
|
||||
# All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""AIX specific tests."""
|
||||
|
||||
import re
|
||||
|
||||
from psutil import AIX
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
import psutil
|
||||
|
||||
|
||||
@unittest.skipIf(not AIX, "AIX only")
|
||||
class AIXSpecificTestCase(unittest.TestCase):
|
||||
|
||||
def test_virtual_memory(self):
|
||||
out = sh('/usr/bin/svmon -O unit=KB')
|
||||
re_pattern = r"memory\s*"
|
||||
for field in ("size inuse free pin virtual available mmode").split():
|
||||
re_pattern += r"(?P<%s>\S+)\s+" % (field,)
|
||||
matchobj = re.search(re_pattern, out)
|
||||
|
||||
self.assertIsNotNone(
|
||||
matchobj, "svmon command returned unexpected output")
|
||||
|
||||
KB = 1024
|
||||
total = int(matchobj.group("size")) * KB
|
||||
available = int(matchobj.group("available")) * KB
|
||||
used = int(matchobj.group("inuse")) * KB
|
||||
free = int(matchobj.group("free")) * KB
|
||||
|
||||
psutil_result = psutil.virtual_memory()
|
||||
|
||||
# MEMORY_TOLERANCE from psutil.tests is not enough. For some reason
|
||||
# we're seeing differences of ~1.2 MB. 2 MB is still a good tolerance
|
||||
# when compared to GBs.
|
||||
MEMORY_TOLERANCE = 2 * KB * KB # 2 MB
|
||||
self.assertEqual(psutil_result.total, total)
|
||||
self.assertAlmostEqual(
|
||||
psutil_result.used, used, delta=MEMORY_TOLERANCE)
|
||||
self.assertAlmostEqual(
|
||||
psutil_result.available, available, delta=MEMORY_TOLERANCE)
|
||||
self.assertAlmostEqual(
|
||||
psutil_result.free, free, delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_swap_memory(self):
|
||||
out = sh('/usr/sbin/lsps -a')
|
||||
# From the man page, "The size is given in megabytes" so we assume
|
||||
# we'll always have 'MB' in the result
|
||||
# TODO maybe try to use "swap -l" to check "used" too, but its units
|
||||
# are not guaranteed to be "MB" so parsing may not be consistent
|
||||
matchobj = re.search(r"(?P<space>\S+)\s+"
|
||||
r"(?P<vol>\S+)\s+"
|
||||
r"(?P<vg>\S+)\s+"
|
||||
r"(?P<size>\d+)MB", out)
|
||||
|
||||
self.assertIsNotNone(
|
||||
matchobj, "lsps command returned unexpected output")
|
||||
|
||||
total_mb = int(matchobj.group("size"))
|
||||
MB = 1024 ** 2
|
||||
psutil_result = psutil.swap_memory()
|
||||
# we divide our result by MB instead of multiplying the lsps value by
|
||||
# MB because lsps may round down, so we round down too
|
||||
self.assertEqual(int(psutil_result.total / MB), total_mb)
|
||||
|
||||
def test_cpu_stats(self):
|
||||
out = sh('/usr/bin/mpstat -a')
|
||||
|
||||
re_pattern = r"ALL\s*"
|
||||
for field in ("min maj mpcs mpcr dev soft dec ph cs ics bound rq "
|
||||
"push S3pull S3grd S0rd S1rd S2rd S3rd S4rd S5rd "
|
||||
"sysc").split():
|
||||
re_pattern += r"(?P<%s>\S+)\s+" % (field,)
|
||||
matchobj = re.search(re_pattern, out)
|
||||
|
||||
self.assertIsNotNone(
|
||||
matchobj, "mpstat command returned unexpected output")
|
||||
|
||||
# numbers are usually in the millions so 1000 is ok for tolerance
|
||||
CPU_STATS_TOLERANCE = 1000
|
||||
psutil_result = psutil.cpu_stats()
|
||||
self.assertAlmostEqual(
|
||||
psutil_result.ctx_switches,
|
||||
int(matchobj.group("cs")),
|
||||
delta=CPU_STATS_TOLERANCE)
|
||||
self.assertAlmostEqual(
|
||||
psutil_result.syscalls,
|
||||
int(matchobj.group("sysc")),
|
||||
delta=CPU_STATS_TOLERANCE)
|
||||
self.assertAlmostEqual(
|
||||
psutil_result.interrupts,
|
||||
int(matchobj.group("dev")),
|
||||
delta=CPU_STATS_TOLERANCE)
|
||||
self.assertAlmostEqual(
|
||||
psutil_result.soft_interrupts,
|
||||
int(matchobj.group("soft")),
|
||||
delta=CPU_STATS_TOLERANCE)
|
||||
|
||||
def test_cpu_count_logical(self):
|
||||
out = sh('/usr/bin/mpstat -a')
|
||||
mpstat_lcpu = int(re.search(r"lcpu=(\d+)", out).group(1))
|
||||
psutil_lcpu = psutil.cpu_count(logical=True)
|
||||
self.assertEqual(mpstat_lcpu, psutil_lcpu)
|
||||
|
||||
def test_net_if_addrs_names(self):
|
||||
out = sh('/etc/ifconfig -l')
|
||||
ifconfig_names = set(out.split())
|
||||
psutil_names = set(psutil.net_if_addrs().keys())
|
||||
self.assertSetEqual(ifconfig_names, psutil_names)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
565
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_bsd.py
vendored
Normal file
565
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_bsd.py
vendored
Normal file
|
|
@ -0,0 +1,565 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
# TODO: (FreeBSD) add test for comparing connections with 'sockstat' cmd.
|
||||
|
||||
|
||||
"""Tests specific to all BSD platforms."""
|
||||
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import BSD
|
||||
from psutil import FREEBSD
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import MEMORY_TOLERANCE
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
from psutil.tests import which
|
||||
|
||||
|
||||
if BSD:
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
if os.getuid() == 0: # muse requires root privileges
|
||||
MUSE_AVAILABLE = which('muse')
|
||||
else:
|
||||
MUSE_AVAILABLE = False
|
||||
else:
|
||||
MUSE_AVAILABLE = False
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
"""Expects a sysctl command with an argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
result = sh("sysctl " + cmdline)
|
||||
if FREEBSD:
|
||||
result = result[result.find(": ") + 2:]
|
||||
elif OPENBSD or NETBSD:
|
||||
result = result[result.find("=") + 1:]
|
||||
try:
|
||||
return int(result)
|
||||
except ValueError:
|
||||
return result
|
||||
|
||||
|
||||
def muse(field):
|
||||
"""Thin wrapper around 'muse' cmdline utility."""
|
||||
out = sh('muse')
|
||||
for line in out.split('\n'):
|
||||
if line.startswith(field):
|
||||
break
|
||||
else:
|
||||
raise ValueError("line not found")
|
||||
return int(line.split()[1])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- All BSD*
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(not BSD, "BSD only")
|
||||
class BSDTestCase(unittest.TestCase):
|
||||
"""Generic tests common to all BSD variants."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
@unittest.skipIf(NETBSD, "-o lstart doesn't work on NETBSD")
|
||||
def test_process_create_time(self):
|
||||
output = sh("ps -o lstart -p %s" % self.pid)
|
||||
start_ps = output.replace('STARTED', '').strip()
|
||||
start_psutil = psutil.Process(self.pid).create_time()
|
||||
start_psutil = time.strftime("%a %b %e %H:%M:%S %Y",
|
||||
time.localtime(start_psutil))
|
||||
self.assertEqual(start_ps, start_psutil)
|
||||
|
||||
def test_disks(self):
|
||||
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||
# against "df -a"
|
||||
def df(path):
|
||||
out = sh('df -k "%s"' % path).strip()
|
||||
lines = out.split('\n')
|
||||
lines.pop(0)
|
||||
line = lines.pop(0)
|
||||
dev, total, used, free = line.split()[:4]
|
||||
if dev == 'none':
|
||||
dev = ''
|
||||
total = int(total) * 1024
|
||||
used = int(used) * 1024
|
||||
free = int(free) * 1024
|
||||
return dev, total, used, free
|
||||
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
dev, total, used, free = df(part.mountpoint)
|
||||
self.assertEqual(part.device, dev)
|
||||
self.assertEqual(usage.total, total)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.free, free))
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % (usage.used, used))
|
||||
|
||||
@unittest.skipIf(not which('sysctl'), "sysctl cmd not available")
|
||||
def test_cpu_count_logical(self):
|
||||
syst = sysctl("hw.ncpu")
|
||||
self.assertEqual(psutil.cpu_count(logical=True), syst)
|
||||
|
||||
@unittest.skipIf(not which('sysctl'), "sysctl cmd not available")
|
||||
def test_virtual_memory_total(self):
|
||||
num = sysctl('hw.physmem')
|
||||
self.assertEqual(num, psutil.virtual_memory().total)
|
||||
|
||||
def test_net_if_stats(self):
|
||||
for name, stats in psutil.net_if_stats().items():
|
||||
try:
|
||||
out = sh("ifconfig %s" % name)
|
||||
except RuntimeError:
|
||||
pass
|
||||
else:
|
||||
self.assertEqual(stats.isup, 'RUNNING' in out, msg=out)
|
||||
if "mtu" in out:
|
||||
self.assertEqual(stats.mtu,
|
||||
int(re.findall(r'mtu (\d+)', out)[0]))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- FreeBSD
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(not FREEBSD, "FREEBSD only")
|
||||
class FreeBSDProcessTestCase(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
@retry_on_failure()
|
||||
def test_memory_maps(self):
|
||||
out = sh('procstat -v %s' % self.pid)
|
||||
maps = psutil.Process(self.pid).memory_maps(grouped=False)
|
||||
lines = out.split('\n')[1:]
|
||||
while lines:
|
||||
line = lines.pop()
|
||||
fields = line.split()
|
||||
_, start, stop, perms, res = fields[:5]
|
||||
map = maps.pop()
|
||||
self.assertEqual("%s-%s" % (start, stop), map.addr)
|
||||
self.assertEqual(int(res), map.rss)
|
||||
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))
|
||||
|
||||
@retry_on_failure()
|
||||
def test_ctx_switches(self):
|
||||
tested = []
|
||||
out = sh('procstat -r %s' % self.pid)
|
||||
p = psutil.Process(self.pid)
|
||||
for line in out.split('\n'):
|
||||
line = line.lower().strip()
|
||||
if ' voluntary context' in line:
|
||||
pstat_value = int(line.split()[-1])
|
||||
psutil_value = p.num_ctx_switches().voluntary
|
||||
self.assertEqual(pstat_value, psutil_value)
|
||||
tested.append(None)
|
||||
elif ' involuntary context' in line:
|
||||
pstat_value = int(line.split()[-1])
|
||||
psutil_value = p.num_ctx_switches().involuntary
|
||||
self.assertEqual(pstat_value, psutil_value)
|
||||
tested.append(None)
|
||||
if len(tested) != 2:
|
||||
raise RuntimeError("couldn't find lines match in procstat out")
|
||||
|
||||
@retry_on_failure()
|
||||
def test_cpu_times(self):
|
||||
tested = []
|
||||
out = sh('procstat -r %s' % self.pid)
|
||||
p = psutil.Process(self.pid)
|
||||
for line in out.split('\n'):
|
||||
line = line.lower().strip()
|
||||
if 'user time' in line:
|
||||
pstat_value = float('0.' + line.split()[-1].split('.')[-1])
|
||||
psutil_value = p.cpu_times().user
|
||||
self.assertEqual(pstat_value, psutil_value)
|
||||
tested.append(None)
|
||||
elif 'system time' in line:
|
||||
pstat_value = float('0.' + line.split()[-1].split('.')[-1])
|
||||
psutil_value = p.cpu_times().system
|
||||
self.assertEqual(pstat_value, psutil_value)
|
||||
tested.append(None)
|
||||
if len(tested) != 2:
|
||||
raise RuntimeError("couldn't find lines match in procstat out")
|
||||
|
||||
|
||||
@unittest.skipIf(not FREEBSD, "FREEBSD only")
|
||||
class FreeBSDSystemTestCase(unittest.TestCase):
|
||||
|
||||
@staticmethod
|
||||
def parse_swapinfo():
|
||||
# the last line is always the total
|
||||
output = sh("swapinfo -k").splitlines()[-1]
|
||||
parts = re.split(r'\s+', output)
|
||||
|
||||
if not parts:
|
||||
raise ValueError("Can't parse swapinfo: %s" % output)
|
||||
|
||||
# the size is in 1k units, so multiply by 1024
|
||||
total, used, free = (int(p) * 1024 for p in parts[1:4])
|
||||
return total, used, free
|
||||
|
||||
def test_cpu_frequency_against_sysctl(self):
|
||||
# Currently only cpu 0 is frequency is supported in FreeBSD
|
||||
# All other cores use the same frequency.
|
||||
sensor = "dev.cpu.0.freq"
|
||||
try:
|
||||
sysctl_result = int(sysctl(sensor))
|
||||
except RuntimeError:
|
||||
self.skipTest("frequencies not supported by kernel")
|
||||
self.assertEqual(psutil.cpu_freq().current, sysctl_result)
|
||||
|
||||
sensor = "dev.cpu.0.freq_levels"
|
||||
sysctl_result = sysctl(sensor)
|
||||
# sysctl returns a string of the format:
|
||||
# <freq_level_1>/<voltage_level_1> <freq_level_2>/<voltage_level_2>...
|
||||
# Ordered highest available to lowest available.
|
||||
max_freq = int(sysctl_result.split()[0].split("/")[0])
|
||||
min_freq = int(sysctl_result.split()[-1].split("/")[0])
|
||||
self.assertEqual(psutil.cpu_freq().max, max_freq)
|
||||
self.assertEqual(psutil.cpu_freq().min, min_freq)
|
||||
|
||||
# --- virtual_memory(); tests against sysctl
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_active(self):
|
||||
syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().active, syst,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_inactive(self):
|
||||
syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().inactive, syst,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_wired(self):
|
||||
syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().wired, syst,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_cached(self):
|
||||
syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().cached, syst,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_free(self):
|
||||
syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE
|
||||
self.assertAlmostEqual(psutil.virtual_memory().free, syst,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_buffers(self):
|
||||
syst = sysctl("vfs.bufspace")
|
||||
self.assertAlmostEqual(psutil.virtual_memory().buffers, syst,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
# --- virtual_memory(); tests against muse
|
||||
|
||||
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||
def test_muse_vmem_total(self):
|
||||
num = muse('Total')
|
||||
self.assertEqual(psutil.virtual_memory().total, num)
|
||||
|
||||
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_active(self):
|
||||
num = muse('Active')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().active, num,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_inactive(self):
|
||||
num = muse('Inactive')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().inactive, num,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_wired(self):
|
||||
num = muse('Wired')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().wired, num,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_cached(self):
|
||||
num = muse('Cache')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().cached, num,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_free(self):
|
||||
num = muse('Free')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().free, num,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_buffers(self):
|
||||
num = muse('Buffer')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().buffers, num,
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_cpu_stats_ctx_switches(self):
|
||||
self.assertAlmostEqual(psutil.cpu_stats().ctx_switches,
|
||||
sysctl('vm.stats.sys.v_swtch'), delta=1000)
|
||||
|
||||
def test_cpu_stats_interrupts(self):
|
||||
self.assertAlmostEqual(psutil.cpu_stats().interrupts,
|
||||
sysctl('vm.stats.sys.v_intr'), delta=1000)
|
||||
|
||||
def test_cpu_stats_soft_interrupts(self):
|
||||
self.assertAlmostEqual(psutil.cpu_stats().soft_interrupts,
|
||||
sysctl('vm.stats.sys.v_soft'), delta=1000)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_cpu_stats_syscalls(self):
|
||||
# pretty high tolerance but it looks like it's OK.
|
||||
self.assertAlmostEqual(psutil.cpu_stats().syscalls,
|
||||
sysctl('vm.stats.sys.v_syscall'), delta=200000)
|
||||
|
||||
# def test_cpu_stats_traps(self):
|
||||
# self.assertAlmostEqual(psutil.cpu_stats().traps,
|
||||
# sysctl('vm.stats.sys.v_trap'), delta=1000)
|
||||
|
||||
# --- swap memory
|
||||
|
||||
def test_swapmem_free(self):
|
||||
total, used, free = self.parse_swapinfo()
|
||||
self.assertAlmostEqual(
|
||||
psutil.swap_memory().free, free, delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_swapmem_used(self):
|
||||
total, used, free = self.parse_swapinfo()
|
||||
self.assertAlmostEqual(
|
||||
psutil.swap_memory().used, used, delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_swapmem_total(self):
|
||||
total, used, free = self.parse_swapinfo()
|
||||
self.assertAlmostEqual(
|
||||
psutil.swap_memory().total, total, delta=MEMORY_TOLERANCE)
|
||||
|
||||
# --- others
|
||||
|
||||
def test_boot_time(self):
|
||||
s = sysctl('sysctl kern.boottime')
|
||||
s = s[s.find(" sec = ") + 7:]
|
||||
s = s[:s.find(',')]
|
||||
btime = int(s)
|
||||
self.assertEqual(btime, psutil.boot_time())
|
||||
|
||||
# --- sensors_battery
|
||||
|
||||
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||
def test_sensors_battery(self):
|
||||
def secs2hours(secs):
|
||||
m, s = divmod(secs, 60)
|
||||
h, m = divmod(m, 60)
|
||||
return "%d:%02d" % (h, m)
|
||||
|
||||
out = sh("acpiconf -i 0")
|
||||
fields = dict([(x.split('\t')[0], x.split('\t')[-1])
|
||||
for x in out.split("\n")])
|
||||
metrics = psutil.sensors_battery()
|
||||
percent = int(fields['Remaining capacity:'].replace('%', ''))
|
||||
remaining_time = fields['Remaining time:']
|
||||
self.assertEqual(metrics.percent, percent)
|
||||
if remaining_time == 'unknown':
|
||||
self.assertEqual(metrics.secsleft, psutil.POWER_TIME_UNLIMITED)
|
||||
else:
|
||||
self.assertEqual(secs2hours(metrics.secsleft), remaining_time)
|
||||
|
||||
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||
def test_sensors_battery_against_sysctl(self):
|
||||
self.assertEqual(psutil.sensors_battery().percent,
|
||||
sysctl("hw.acpi.battery.life"))
|
||||
self.assertEqual(psutil.sensors_battery().power_plugged,
|
||||
sysctl("hw.acpi.acline") == 1)
|
||||
secsleft = psutil.sensors_battery().secsleft
|
||||
if secsleft < 0:
|
||||
self.assertEqual(sysctl("hw.acpi.battery.time"), -1)
|
||||
else:
|
||||
self.assertEqual(secsleft, sysctl("hw.acpi.battery.time") * 60)
|
||||
|
||||
@unittest.skipIf(HAS_BATTERY, "has battery")
|
||||
def test_sensors_battery_no_battery(self):
|
||||
# If no battery is present one of these calls is supposed
|
||||
# to fail, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1074
|
||||
with self.assertRaises(RuntimeError):
|
||||
sysctl("hw.acpi.battery.life")
|
||||
sysctl("hw.acpi.battery.time")
|
||||
sysctl("hw.acpi.acline")
|
||||
self.assertIsNone(psutil.sensors_battery())
|
||||
|
||||
# --- sensors_temperatures
|
||||
|
||||
def test_sensors_temperatures_against_sysctl(self):
|
||||
num_cpus = psutil.cpu_count(True)
|
||||
for cpu in range(num_cpus):
|
||||
sensor = "dev.cpu.%s.temperature" % cpu
|
||||
# sysctl returns a string in the format 46.0C
|
||||
try:
|
||||
sysctl_result = int(float(sysctl(sensor)[:-1]))
|
||||
except RuntimeError:
|
||||
self.skipTest("temperatures not supported by kernel")
|
||||
self.assertAlmostEqual(
|
||||
psutil.sensors_temperatures()["coretemp"][cpu].current,
|
||||
sysctl_result, delta=10)
|
||||
|
||||
sensor = "dev.cpu.%s.coretemp.tjmax" % cpu
|
||||
sysctl_result = int(float(sysctl(sensor)[:-1]))
|
||||
self.assertEqual(
|
||||
psutil.sensors_temperatures()["coretemp"][cpu].high,
|
||||
sysctl_result)
|
||||
|
||||
# =====================================================================
|
||||
# --- OpenBSD
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(not OPENBSD, "OPENBSD only")
|
||||
class OpenBSDTestCase(unittest.TestCase):
|
||||
|
||||
def test_boot_time(self):
|
||||
s = sysctl('kern.boottime')
|
||||
sys_bt = datetime.datetime.strptime(s, "%a %b %d %H:%M:%S %Y")
|
||||
psutil_bt = datetime.datetime.fromtimestamp(psutil.boot_time())
|
||||
self.assertEqual(sys_bt, psutil_bt)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- NetBSD
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(not NETBSD, "NETBSD only")
|
||||
class NetBSDTestCase(unittest.TestCase):
|
||||
|
||||
@staticmethod
|
||||
def parse_meminfo(look_for):
|
||||
with open('/proc/meminfo', 'rt') as f:
|
||||
for line in f:
|
||||
if line.startswith(look_for):
|
||||
return int(line.split()[1]) * 1024
|
||||
raise ValueError("can't find %s" % look_for)
|
||||
|
||||
def test_vmem_total(self):
|
||||
self.assertEqual(
|
||||
psutil.virtual_memory().total, self.parse_meminfo("MemTotal:"))
|
||||
|
||||
def test_vmem_free(self):
|
||||
self.assertAlmostEqual(
|
||||
psutil.virtual_memory().free, self.parse_meminfo("MemFree:"),
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_vmem_buffers(self):
|
||||
self.assertAlmostEqual(
|
||||
psutil.virtual_memory().buffers, self.parse_meminfo("Buffers:"),
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_vmem_shared(self):
|
||||
self.assertAlmostEqual(
|
||||
psutil.virtual_memory().shared, self.parse_meminfo("MemShared:"),
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_swapmem_total(self):
|
||||
self.assertAlmostEqual(
|
||||
psutil.swap_memory().total, self.parse_meminfo("SwapTotal:"),
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_swapmem_free(self):
|
||||
self.assertAlmostEqual(
|
||||
psutil.swap_memory().free, self.parse_meminfo("SwapFree:"),
|
||||
delta=MEMORY_TOLERANCE)
|
||||
|
||||
def test_swapmem_used(self):
|
||||
smem = psutil.swap_memory()
|
||||
self.assertEqual(smem.used, smem.total - smem.free)
|
||||
|
||||
def test_cpu_stats_interrupts(self):
|
||||
with open('/proc/stat', 'rb') as f:
|
||||
for line in f:
|
||||
if line.startswith(b'intr'):
|
||||
interrupts = int(line.split()[1])
|
||||
break
|
||||
else:
|
||||
raise ValueError("couldn't find line")
|
||||
self.assertAlmostEqual(
|
||||
psutil.cpu_stats().interrupts, interrupts, delta=1000)
|
||||
|
||||
def test_cpu_stats_ctx_switches(self):
|
||||
with open('/proc/stat', 'rb') as f:
|
||||
for line in f:
|
||||
if line.startswith(b'ctxt'):
|
||||
ctx_switches = int(line.split()[1])
|
||||
break
|
||||
else:
|
||||
raise ValueError("couldn't find line")
|
||||
self.assertAlmostEqual(
|
||||
psutil.cpu_stats().ctx_switches, ctx_switches, delta=1000)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
637
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_connections.py
vendored
Normal file
637
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_connections.py
vendored
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
"""Tests for net_connections() and Process.connections() APIs."""
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import os
|
||||
import socket
|
||||
import textwrap
|
||||
from contextlib import closing
|
||||
from socket import AF_INET
|
||||
from socket import AF_INET6
|
||||
from socket import SOCK_DGRAM
|
||||
from socket import SOCK_STREAM
|
||||
|
||||
import psutil
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._common import supports_ipv6
|
||||
from psutil._compat import PY3
|
||||
from psutil.tests import AF_UNIX
|
||||
from psutil.tests import bind_socket
|
||||
from psutil.tests import bind_unix_socket
|
||||
from psutil.tests import check_net_address
|
||||
from psutil.tests import CIRRUS
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import enum
|
||||
from psutil.tests import get_free_port
|
||||
from psutil.tests import HAS_CONNECTIONS_UNIX
|
||||
from psutil.tests import pyrun
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import SKIP_SYSCONS
|
||||
from psutil.tests import tcp_socketpair
|
||||
from psutil.tests import TESTFN
|
||||
from psutil.tests import TRAVIS
|
||||
from psutil.tests import unittest
|
||||
from psutil.tests import unix_socket_path
|
||||
from psutil.tests import unix_socketpair
|
||||
from psutil.tests import wait_for_file
|
||||
|
||||
|
||||
thisproc = psutil.Process()
|
||||
SOCK_SEQPACKET = getattr(socket, "SOCK_SEQPACKET", object())
|
||||
|
||||
|
||||
class Base(object):
|
||||
|
||||
def setUp(self):
|
||||
safe_rmpath(TESTFN)
|
||||
if not (NETBSD or FREEBSD):
|
||||
# process opens a UNIX socket to /var/log/run.
|
||||
cons = thisproc.connections(kind='all')
|
||||
assert not cons, cons
|
||||
|
||||
def tearDown(self):
|
||||
safe_rmpath(TESTFN)
|
||||
reap_children()
|
||||
if not (FREEBSD or NETBSD):
|
||||
# Make sure we closed all resources.
|
||||
# NetBSD opens a UNIX socket to /var/log/run.
|
||||
cons = thisproc.connections(kind='all')
|
||||
assert not cons, cons
|
||||
|
||||
def compare_procsys_connections(self, pid, proc_cons, kind='all'):
|
||||
"""Given a process PID and its list of connections compare
|
||||
those against system-wide connections retrieved via
|
||||
psutil.net_connections.
|
||||
"""
|
||||
try:
|
||||
sys_cons = psutil.net_connections(kind=kind)
|
||||
except psutil.AccessDenied:
|
||||
# On MACOS, system-wide connections are retrieved by iterating
|
||||
# over all processes
|
||||
if MACOS:
|
||||
return
|
||||
else:
|
||||
raise
|
||||
# Filter for this proc PID and exlucde PIDs from the tuple.
|
||||
sys_cons = [c[:-1] for c in sys_cons if c.pid == pid]
|
||||
sys_cons.sort()
|
||||
proc_cons.sort()
|
||||
self.assertEqual(proc_cons, sys_cons)
|
||||
|
||||
def check_connection_ntuple(self, conn):
|
||||
"""Check validity of a connection namedtuple."""
|
||||
def check_ntuple(conn):
|
||||
has_pid = len(conn) == 7
|
||||
self.assertIn(len(conn), (6, 7))
|
||||
self.assertEqual(conn[0], conn.fd)
|
||||
self.assertEqual(conn[1], conn.family)
|
||||
self.assertEqual(conn[2], conn.type)
|
||||
self.assertEqual(conn[3], conn.laddr)
|
||||
self.assertEqual(conn[4], conn.raddr)
|
||||
self.assertEqual(conn[5], conn.status)
|
||||
if has_pid:
|
||||
self.assertEqual(conn[6], conn.pid)
|
||||
|
||||
def check_family(conn):
|
||||
self.assertIn(conn.family, (AF_INET, AF_INET6, AF_UNIX))
|
||||
if enum is not None:
|
||||
assert isinstance(conn.family, enum.IntEnum), conn
|
||||
else:
|
||||
assert isinstance(conn.family, int), conn
|
||||
if conn.family == AF_INET:
|
||||
# actually try to bind the local socket; ignore IPv6
|
||||
# sockets as their address might be represented as
|
||||
# an IPv4-mapped-address (e.g. "::127.0.0.1")
|
||||
# and that's rejected by bind()
|
||||
s = socket.socket(conn.family, conn.type)
|
||||
with contextlib.closing(s):
|
||||
try:
|
||||
s.bind((conn.laddr[0], 0))
|
||||
except socket.error as err:
|
||||
if err.errno != errno.EADDRNOTAVAIL:
|
||||
raise
|
||||
elif conn.family == AF_UNIX:
|
||||
self.assertEqual(conn.status, psutil.CONN_NONE)
|
||||
|
||||
def check_type(conn):
|
||||
# SOCK_SEQPACKET may happen in case of AF_UNIX socks
|
||||
self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
|
||||
if enum is not None:
|
||||
assert isinstance(conn.type, enum.IntEnum), conn
|
||||
else:
|
||||
assert isinstance(conn.type, int), conn
|
||||
if conn.type == SOCK_DGRAM:
|
||||
self.assertEqual(conn.status, psutil.CONN_NONE)
|
||||
|
||||
def check_addrs(conn):
|
||||
# check IP address and port sanity
|
||||
for addr in (conn.laddr, conn.raddr):
|
||||
if conn.family in (AF_INET, AF_INET6):
|
||||
self.assertIsInstance(addr, tuple)
|
||||
if not addr:
|
||||
continue
|
||||
self.assertIsInstance(addr.port, int)
|
||||
assert 0 <= addr.port <= 65535, addr.port
|
||||
check_net_address(addr.ip, conn.family)
|
||||
elif conn.family == AF_UNIX:
|
||||
self.assertIsInstance(addr, str)
|
||||
|
||||
def check_status(conn):
|
||||
self.assertIsInstance(conn.status, str)
|
||||
valids = [getattr(psutil, x) for x in dir(psutil)
|
||||
if x.startswith('CONN_')]
|
||||
self.assertIn(conn.status, valids)
|
||||
if conn.family in (AF_INET, AF_INET6) and conn.type == SOCK_STREAM:
|
||||
self.assertNotEqual(conn.status, psutil.CONN_NONE)
|
||||
else:
|
||||
self.assertEqual(conn.status, psutil.CONN_NONE)
|
||||
|
||||
check_ntuple(conn)
|
||||
check_family(conn)
|
||||
check_type(conn)
|
||||
check_addrs(conn)
|
||||
check_status(conn)
|
||||
|
||||
|
||||
class TestBase(Base, unittest.TestCase):
|
||||
|
||||
@unittest.skipIf(SKIP_SYSCONS, "requires root")
|
||||
def test_system(self):
|
||||
with create_sockets():
|
||||
for conn in psutil.net_connections(kind='all'):
|
||||
self.check_connection_ntuple(conn)
|
||||
|
||||
def test_process(self):
|
||||
with create_sockets():
|
||||
for conn in psutil.Process().connections(kind='all'):
|
||||
self.check_connection_ntuple(conn)
|
||||
|
||||
def test_invalid_kind(self):
|
||||
self.assertRaises(ValueError, thisproc.connections, kind='???')
|
||||
self.assertRaises(ValueError, psutil.net_connections, kind='???')
|
||||
|
||||
|
||||
class TestUnconnectedSockets(Base, unittest.TestCase):
|
||||
"""Tests sockets which are open but not connected to anything."""
|
||||
|
||||
def get_conn_from_sock(self, sock):
|
||||
cons = thisproc.connections(kind='all')
|
||||
smap = dict([(c.fd, c) for c in cons])
|
||||
if NETBSD or FREEBSD:
|
||||
# NetBSD opens a UNIX socket to /var/log/run
|
||||
# so there may be more connections.
|
||||
return smap[sock.fileno()]
|
||||
else:
|
||||
self.assertEqual(len(cons), 1)
|
||||
if cons[0].fd != -1:
|
||||
self.assertEqual(smap[sock.fileno()].fd, sock.fileno())
|
||||
return cons[0]
|
||||
|
||||
def check_socket(self, sock):
|
||||
"""Given a socket, makes sure it matches the one obtained
|
||||
via psutil. It assumes this process created one connection
|
||||
only (the one supposed to be checked).
|
||||
"""
|
||||
conn = self.get_conn_from_sock(sock)
|
||||
self.check_connection_ntuple(conn)
|
||||
|
||||
# fd, family, type
|
||||
if conn.fd != -1:
|
||||
self.assertEqual(conn.fd, sock.fileno())
|
||||
self.assertEqual(conn.family, sock.family)
|
||||
# see: http://bugs.python.org/issue30204
|
||||
self.assertEqual(
|
||||
conn.type, sock.getsockopt(socket.SOL_SOCKET, socket.SO_TYPE))
|
||||
|
||||
# local address
|
||||
laddr = sock.getsockname()
|
||||
if not laddr and PY3 and isinstance(laddr, bytes):
|
||||
# See: http://bugs.python.org/issue30205
|
||||
laddr = laddr.decode()
|
||||
if sock.family == AF_INET6:
|
||||
laddr = laddr[:2]
|
||||
if sock.family == AF_UNIX and OPENBSD:
|
||||
# No addresses are set for UNIX sockets on OpenBSD.
|
||||
pass
|
||||
else:
|
||||
self.assertEqual(conn.laddr, laddr)
|
||||
|
||||
# XXX Solaris can't retrieve system-wide UNIX sockets
|
||||
if sock.family == AF_UNIX and HAS_CONNECTIONS_UNIX:
|
||||
cons = thisproc.connections(kind='all')
|
||||
self.compare_procsys_connections(os.getpid(), cons, kind='all')
|
||||
return conn
|
||||
|
||||
def test_tcp_v4(self):
|
||||
addr = ("127.0.0.1", get_free_port())
|
||||
with closing(bind_socket(AF_INET, SOCK_STREAM, addr=addr)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert not conn.raddr
|
||||
self.assertEqual(conn.status, psutil.CONN_LISTEN)
|
||||
|
||||
@unittest.skipIf(not supports_ipv6(), "IPv6 not supported")
|
||||
def test_tcp_v6(self):
|
||||
addr = ("::1", get_free_port())
|
||||
with closing(bind_socket(AF_INET6, SOCK_STREAM, addr=addr)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert not conn.raddr
|
||||
self.assertEqual(conn.status, psutil.CONN_LISTEN)
|
||||
|
||||
def test_udp_v4(self):
|
||||
addr = ("127.0.0.1", get_free_port())
|
||||
with closing(bind_socket(AF_INET, SOCK_DGRAM, addr=addr)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert not conn.raddr
|
||||
self.assertEqual(conn.status, psutil.CONN_NONE)
|
||||
|
||||
@unittest.skipIf(not supports_ipv6(), "IPv6 not supported")
|
||||
def test_udp_v6(self):
|
||||
addr = ("::1", get_free_port())
|
||||
with closing(bind_socket(AF_INET6, SOCK_DGRAM, addr=addr)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert not conn.raddr
|
||||
self.assertEqual(conn.status, psutil.CONN_NONE)
|
||||
|
||||
@unittest.skipIf(not POSIX, 'POSIX only')
|
||||
def test_unix_tcp(self):
|
||||
with unix_socket_path() as name:
|
||||
with closing(bind_unix_socket(name, type=SOCK_STREAM)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert not conn.raddr
|
||||
self.assertEqual(conn.status, psutil.CONN_NONE)
|
||||
|
||||
@unittest.skipIf(not POSIX, 'POSIX only')
|
||||
def test_unix_udp(self):
|
||||
with unix_socket_path() as name:
|
||||
with closing(bind_unix_socket(name, type=SOCK_STREAM)) as sock:
|
||||
conn = self.check_socket(sock)
|
||||
assert not conn.raddr
|
||||
self.assertEqual(conn.status, psutil.CONN_NONE)
|
||||
|
||||
|
||||
class TestConnectedSocket(Base, unittest.TestCase):
|
||||
"""Test socket pairs which are are actually connected to
|
||||
each other.
|
||||
"""
|
||||
|
||||
# On SunOS, even after we close() it, the server socket stays around
|
||||
# in TIME_WAIT state.
|
||||
@unittest.skipIf(SUNOS, "unreliable on SUONS")
|
||||
def test_tcp(self):
|
||||
addr = ("127.0.0.1", get_free_port())
|
||||
assert not thisproc.connections(kind='tcp4')
|
||||
server, client = tcp_socketpair(AF_INET, addr=addr)
|
||||
try:
|
||||
cons = thisproc.connections(kind='tcp4')
|
||||
self.assertEqual(len(cons), 2)
|
||||
self.assertEqual(cons[0].status, psutil.CONN_ESTABLISHED)
|
||||
self.assertEqual(cons[1].status, psutil.CONN_ESTABLISHED)
|
||||
# May not be fast enough to change state so it stays
|
||||
# commenteed.
|
||||
# client.close()
|
||||
# cons = thisproc.connections(kind='all')
|
||||
# self.assertEqual(len(cons), 1)
|
||||
# self.assertEqual(cons[0].status, psutil.CONN_CLOSE_WAIT)
|
||||
finally:
|
||||
server.close()
|
||||
client.close()
|
||||
|
||||
@unittest.skipIf(not POSIX, 'POSIX only')
|
||||
def test_unix(self):
|
||||
with unix_socket_path() as name:
|
||||
server, client = unix_socketpair(name)
|
||||
try:
|
||||
cons = thisproc.connections(kind='unix')
|
||||
assert not (cons[0].laddr and cons[0].raddr)
|
||||
assert not (cons[1].laddr and cons[1].raddr)
|
||||
if NETBSD or FREEBSD:
|
||||
# On NetBSD creating a UNIX socket will cause
|
||||
# a UNIX connection to /var/run/log.
|
||||
cons = [c for c in cons if c.raddr != '/var/run/log']
|
||||
if CIRRUS:
|
||||
cons = [c for c in cons if c.fd in
|
||||
(server.fileno(), client.fileno())]
|
||||
self.assertEqual(len(cons), 2, msg=cons)
|
||||
if LINUX or FREEBSD or SUNOS:
|
||||
# remote path is never set
|
||||
self.assertEqual(cons[0].raddr, "")
|
||||
self.assertEqual(cons[1].raddr, "")
|
||||
# one local address should though
|
||||
self.assertEqual(name, cons[0].laddr or cons[1].laddr)
|
||||
elif OPENBSD:
|
||||
# No addresses whatsoever here.
|
||||
for addr in (cons[0].laddr, cons[0].raddr,
|
||||
cons[1].laddr, cons[1].raddr):
|
||||
self.assertEqual(addr, "")
|
||||
else:
|
||||
# On other systems either the laddr or raddr
|
||||
# of both peers are set.
|
||||
self.assertEqual(cons[0].laddr or cons[1].laddr, name)
|
||||
self.assertEqual(cons[0].raddr or cons[1].raddr, name)
|
||||
finally:
|
||||
server.close()
|
||||
client.close()
|
||||
|
||||
|
||||
class TestFilters(Base, unittest.TestCase):
|
||||
|
||||
def test_filters(self):
|
||||
def check(kind, families, types):
|
||||
for conn in thisproc.connections(kind=kind):
|
||||
self.assertIn(conn.family, families)
|
||||
self.assertIn(conn.type, types)
|
||||
if not SKIP_SYSCONS:
|
||||
for conn in psutil.net_connections(kind=kind):
|
||||
self.assertIn(conn.family, families)
|
||||
self.assertIn(conn.type, types)
|
||||
|
||||
with create_sockets():
|
||||
check('all',
|
||||
[AF_INET, AF_INET6, AF_UNIX],
|
||||
[SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET])
|
||||
check('inet',
|
||||
[AF_INET, AF_INET6],
|
||||
[SOCK_STREAM, SOCK_DGRAM])
|
||||
check('inet4',
|
||||
[AF_INET],
|
||||
[SOCK_STREAM, SOCK_DGRAM])
|
||||
check('tcp',
|
||||
[AF_INET, AF_INET6],
|
||||
[SOCK_STREAM])
|
||||
check('tcp4',
|
||||
[AF_INET],
|
||||
[SOCK_STREAM])
|
||||
check('tcp6',
|
||||
[AF_INET6],
|
||||
[SOCK_STREAM])
|
||||
check('udp',
|
||||
[AF_INET, AF_INET6],
|
||||
[SOCK_DGRAM])
|
||||
check('udp4',
|
||||
[AF_INET],
|
||||
[SOCK_DGRAM])
|
||||
check('udp6',
|
||||
[AF_INET6],
|
||||
[SOCK_DGRAM])
|
||||
if HAS_CONNECTIONS_UNIX:
|
||||
check('unix',
|
||||
[AF_UNIX],
|
||||
[SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET])
|
||||
|
||||
@skip_on_access_denied(only_if=MACOS)
|
||||
def test_combos(self):
|
||||
def check_conn(proc, conn, family, type, laddr, raddr, status, kinds):
|
||||
all_kinds = ("all", "inet", "inet4", "inet6", "tcp", "tcp4",
|
||||
"tcp6", "udp", "udp4", "udp6")
|
||||
self.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:
|
||||
assert cons
|
||||
else:
|
||||
assert not cons, cons
|
||||
# compare against system-wide connections
|
||||
# XXX Solaris can't retrieve system-wide UNIX
|
||||
# sockets.
|
||||
if HAS_CONNECTIONS_UNIX:
|
||||
self.compare_procsys_connections(proc.pid, [conn])
|
||||
|
||||
tcp_template = textwrap.dedent("""
|
||||
import socket, time
|
||||
s = socket.socket($family, socket.SOCK_STREAM)
|
||||
s.bind(('$addr', 0))
|
||||
s.listen(5)
|
||||
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))
|
||||
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", testfn=testfile)
|
||||
udp4_template = Template(udp_template).substitute(
|
||||
family=int(AF_INET), addr="127.0.0.1", testfn=testfile)
|
||||
tcp6_template = Template(tcp_template).substitute(
|
||||
family=int(AF_INET6), addr="::1", testfn=testfile)
|
||||
udp6_template = Template(udp_template).substitute(
|
||||
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
|
||||
tcp6_addr = None
|
||||
udp6_addr = None
|
||||
|
||||
for p in thisproc.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, 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, 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, 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, udp6_addr, (),
|
||||
psutil.CONN_NONE,
|
||||
("all", "inet", "inet6", "udp", "udp6"))
|
||||
|
||||
def test_count(self):
|
||||
with create_sockets():
|
||||
# tcp
|
||||
cons = thisproc.connections(kind='tcp')
|
||||
self.assertEqual(len(cons), 2 if supports_ipv6() else 1)
|
||||
for conn in cons:
|
||||
self.assertIn(conn.family, (AF_INET, AF_INET6))
|
||||
self.assertEqual(conn.type, SOCK_STREAM)
|
||||
# tcp4
|
||||
cons = thisproc.connections(kind='tcp4')
|
||||
self.assertEqual(len(cons), 1)
|
||||
self.assertEqual(cons[0].family, AF_INET)
|
||||
self.assertEqual(cons[0].type, SOCK_STREAM)
|
||||
# tcp6
|
||||
if supports_ipv6():
|
||||
cons = thisproc.connections(kind='tcp6')
|
||||
self.assertEqual(len(cons), 1)
|
||||
self.assertEqual(cons[0].family, AF_INET6)
|
||||
self.assertEqual(cons[0].type, SOCK_STREAM)
|
||||
# udp
|
||||
cons = thisproc.connections(kind='udp')
|
||||
self.assertEqual(len(cons), 2 if supports_ipv6() else 1)
|
||||
for conn in cons:
|
||||
self.assertIn(conn.family, (AF_INET, AF_INET6))
|
||||
self.assertEqual(conn.type, SOCK_DGRAM)
|
||||
# udp4
|
||||
cons = thisproc.connections(kind='udp4')
|
||||
self.assertEqual(len(cons), 1)
|
||||
self.assertEqual(cons[0].family, AF_INET)
|
||||
self.assertEqual(cons[0].type, SOCK_DGRAM)
|
||||
# udp6
|
||||
if supports_ipv6():
|
||||
cons = thisproc.connections(kind='udp6')
|
||||
self.assertEqual(len(cons), 1)
|
||||
self.assertEqual(cons[0].family, AF_INET6)
|
||||
self.assertEqual(cons[0].type, SOCK_DGRAM)
|
||||
# inet
|
||||
cons = thisproc.connections(kind='inet')
|
||||
self.assertEqual(len(cons), 4 if supports_ipv6() else 2)
|
||||
for conn in cons:
|
||||
self.assertIn(conn.family, (AF_INET, AF_INET6))
|
||||
self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM))
|
||||
# inet6
|
||||
if supports_ipv6():
|
||||
cons = thisproc.connections(kind='inet6')
|
||||
self.assertEqual(len(cons), 2)
|
||||
for conn in cons:
|
||||
self.assertEqual(conn.family, AF_INET6)
|
||||
self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM))
|
||||
# Skipped on BSD becayse by default the Python process
|
||||
# creates a UNIX socket to '/var/run/log'.
|
||||
if HAS_CONNECTIONS_UNIX and not (FREEBSD or NETBSD):
|
||||
cons = thisproc.connections(kind='unix')
|
||||
self.assertEqual(len(cons), 3)
|
||||
for conn in cons:
|
||||
self.assertEqual(conn.family, AF_UNIX)
|
||||
self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM))
|
||||
|
||||
|
||||
@unittest.skipIf(SKIP_SYSCONS, "requires root")
|
||||
class TestSystemWideConnections(Base, unittest.TestCase):
|
||||
"""Tests for net_connections()."""
|
||||
|
||||
def test_it(self):
|
||||
def check(cons, families, types_):
|
||||
for conn in cons:
|
||||
self.assertIn(conn.family, families, msg=conn)
|
||||
if conn.family != AF_UNIX:
|
||||
self.assertIn(conn.type, types_, msg=conn)
|
||||
self.check_connection_ntuple(conn)
|
||||
|
||||
with create_sockets():
|
||||
from psutil._common import conn_tmap
|
||||
for kind, groups in conn_tmap.items():
|
||||
# XXX: SunOS does not retrieve UNIX sockets.
|
||||
if kind == 'unix' and not HAS_CONNECTIONS_UNIX:
|
||||
continue
|
||||
families, types_ = groups
|
||||
cons = psutil.net_connections(kind)
|
||||
self.assertEqual(len(cons), len(set(cons)))
|
||||
check(cons, families, types_)
|
||||
|
||||
# See: https://travis-ci.org/giampaolo/psutil/jobs/237566297
|
||||
@unittest.skipIf(MACOS and TRAVIS, "unreliable on MACOS + TRAVIS")
|
||||
def test_multi_sockets_procs(self):
|
||||
# Creates multiple sub processes, each creating different
|
||||
# sockets. For each process check that proc.connections()
|
||||
# and net_connections() return the same results.
|
||||
# This is done mainly to check whether net_connections()'s
|
||||
# pid is properly set, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1013
|
||||
with create_sockets() as socks:
|
||||
expected = len(socks)
|
||||
pids = []
|
||||
times = 10
|
||||
for i in range(times):
|
||||
fname = os.path.realpath(TESTFN) + str(i)
|
||||
src = textwrap.dedent("""\
|
||||
import time, os
|
||||
from psutil.tests import create_sockets
|
||||
with create_sockets():
|
||||
with open(r'%s', 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
time.sleep(60)
|
||||
""" % fname)
|
||||
sproc = pyrun(src)
|
||||
pids.append(sproc.pid)
|
||||
self.addCleanup(safe_rmpath, fname)
|
||||
|
||||
# sync
|
||||
for i in range(times):
|
||||
fname = TESTFN + str(i)
|
||||
wait_for_file(fname)
|
||||
|
||||
syscons = [x for x in psutil.net_connections(kind='all') if x.pid
|
||||
in pids]
|
||||
for pid in pids:
|
||||
self.assertEqual(len([x for x in syscons if x.pid == pid]),
|
||||
expected)
|
||||
p = psutil.Process(pid)
|
||||
self.assertEqual(len(p.connections('all')), expected)
|
||||
|
||||
|
||||
class TestMisc(unittest.TestCase):
|
||||
|
||||
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_
|
||||
self.assertNotIn(str, strs)
|
||||
self.assertNotIn(num, ints)
|
||||
ints.append(num)
|
||||
strs.append(str_)
|
||||
if SUNOS:
|
||||
psutil.CONN_IDLE
|
||||
psutil.CONN_BOUND
|
||||
if WINDOWS:
|
||||
psutil.CONN_DELETE_TCB
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
690
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_contracts.py
vendored
Normal file
690
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_contracts.py
vendored
Normal file
|
|
@ -0,0 +1,690 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
"""Contracts tests. These tests mainly check API sanity in terms of
|
||||
returned types and APIs availability.
|
||||
Some of these are duplicates of tests test_system.py and test_process.py
|
||||
"""
|
||||
|
||||
import errno
|
||||
import os
|
||||
import stat
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from psutil import AIX
|
||||
from psutil import BSD
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil import OSX
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import long
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import enum
|
||||
from psutil.tests import get_kernel_version
|
||||
from psutil.tests import HAS_CPU_FREQ
|
||||
from psutil.tests import HAS_NET_IO_COUNTERS
|
||||
from psutil.tests import HAS_RLIMIT
|
||||
from psutil.tests import HAS_SENSORS_FANS
|
||||
from psutil.tests import HAS_SENSORS_TEMPERATURES
|
||||
from psutil.tests import is_namedtuple
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import SKIP_SYSCONS
|
||||
from psutil.tests import TESTFN
|
||||
from psutil.tests import unittest
|
||||
from psutil.tests import VALID_PROC_STATUSES
|
||||
from psutil.tests import warn
|
||||
import psutil
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- APIs availability
|
||||
# ===================================================================
|
||||
|
||||
# Make sure code reflects what doc promises in terms of APIs
|
||||
# availability.
|
||||
|
||||
class TestAvailConstantsAPIs(unittest.TestCase):
|
||||
|
||||
def test_PROCFS_PATH(self):
|
||||
self.assertEqual(hasattr(psutil, "PROCFS_PATH"),
|
||||
LINUX or SUNOS or AIX)
|
||||
|
||||
def test_win_priority(self):
|
||||
ae = self.assertEqual
|
||||
ae(hasattr(psutil, "ABOVE_NORMAL_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "BELOW_NORMAL_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "HIGH_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "IDLE_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "NORMAL_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "REALTIME_PRIORITY_CLASS"), WINDOWS)
|
||||
|
||||
def test_linux_ioprio_linux(self):
|
||||
ae = self.assertEqual
|
||||
ae(hasattr(psutil, "IOPRIO_CLASS_NONE"), LINUX)
|
||||
ae(hasattr(psutil, "IOPRIO_CLASS_RT"), LINUX)
|
||||
ae(hasattr(psutil, "IOPRIO_CLASS_BE"), LINUX)
|
||||
ae(hasattr(psutil, "IOPRIO_CLASS_IDLE"), LINUX)
|
||||
|
||||
def test_linux_ioprio_windows(self):
|
||||
ae = self.assertEqual
|
||||
ae(hasattr(psutil, "IOPRIO_HIGH"), WINDOWS)
|
||||
ae(hasattr(psutil, "IOPRIO_NORMAL"), WINDOWS)
|
||||
ae(hasattr(psutil, "IOPRIO_LOW"), WINDOWS)
|
||||
ae(hasattr(psutil, "IOPRIO_VERYLOW"), WINDOWS)
|
||||
|
||||
def test_linux_rlimit(self):
|
||||
ae = self.assertEqual
|
||||
hasit = LINUX and get_kernel_version() >= (2, 6, 36)
|
||||
ae(hasattr(psutil.Process, "rlimit"), hasit)
|
||||
ae(hasattr(psutil, "RLIM_INFINITY"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_AS"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_CORE"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_CPU"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_DATA"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_FSIZE"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_LOCKS"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_MEMLOCK"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_NOFILE"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_NPROC"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_RSS"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_STACK"), hasit)
|
||||
|
||||
hasit = LINUX and get_kernel_version() >= (3, 0)
|
||||
ae(hasattr(psutil, "RLIMIT_MSGQUEUE"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_NICE"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_RTPRIO"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_RTTIME"), hasit)
|
||||
ae(hasattr(psutil, "RLIMIT_SIGPENDING"), hasit)
|
||||
|
||||
|
||||
class TestAvailSystemAPIs(unittest.TestCase):
|
||||
|
||||
def test_win_service_iter(self):
|
||||
self.assertEqual(hasattr(psutil, "win_service_iter"), WINDOWS)
|
||||
|
||||
def test_win_service_get(self):
|
||||
self.assertEqual(hasattr(psutil, "win_service_get"), WINDOWS)
|
||||
|
||||
def test_cpu_freq(self):
|
||||
linux = (LINUX and
|
||||
(os.path.exists("/sys/devices/system/cpu/cpufreq") or
|
||||
os.path.exists("/sys/devices/system/cpu/cpu0/cpufreq")))
|
||||
self.assertEqual(hasattr(psutil, "cpu_freq"),
|
||||
linux or MACOS or WINDOWS or FREEBSD)
|
||||
|
||||
def test_sensors_temperatures(self):
|
||||
self.assertEqual(
|
||||
hasattr(psutil, "sensors_temperatures"), LINUX or FREEBSD)
|
||||
|
||||
def test_sensors_fans(self):
|
||||
self.assertEqual(hasattr(psutil, "sensors_fans"), LINUX)
|
||||
|
||||
def test_battery(self):
|
||||
self.assertEqual(hasattr(psutil, "sensors_battery"),
|
||||
LINUX or WINDOWS or FREEBSD or MACOS)
|
||||
|
||||
|
||||
class TestAvailProcessAPIs(unittest.TestCase):
|
||||
|
||||
def test_environ(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "environ"),
|
||||
LINUX or MACOS or WINDOWS or AIX or SUNOS)
|
||||
|
||||
def test_uids(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "uids"), POSIX)
|
||||
|
||||
def test_gids(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "uids"), POSIX)
|
||||
|
||||
def test_terminal(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "terminal"), POSIX)
|
||||
|
||||
def test_ionice(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "ionice"), LINUX or WINDOWS)
|
||||
|
||||
def test_rlimit(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "rlimit"), LINUX)
|
||||
|
||||
def test_io_counters(self):
|
||||
hasit = hasattr(psutil.Process, "io_counters")
|
||||
self.assertEqual(hasit, False if MACOS or SUNOS else True)
|
||||
|
||||
def test_num_fds(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "num_fds"), POSIX)
|
||||
|
||||
def test_num_handles(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "num_handles"), WINDOWS)
|
||||
|
||||
def test_cpu_affinity(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "cpu_affinity"),
|
||||
LINUX or WINDOWS or FREEBSD)
|
||||
|
||||
def test_cpu_num(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "cpu_num"),
|
||||
LINUX or FREEBSD or SUNOS)
|
||||
|
||||
def test_memory_maps(self):
|
||||
hasit = hasattr(psutil.Process, "memory_maps")
|
||||
self.assertEqual(
|
||||
hasit, False if OPENBSD or NETBSD or AIX or MACOS else True)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- System API types
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestSystemAPITypes(unittest.TestCase):
|
||||
"""Check the return types of system related APIs.
|
||||
Mainly we want to test we never return unicode on Python 2, see:
|
||||
https://github.com/giampaolo/psutil/issues/1039
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.proc = psutil.Process()
|
||||
|
||||
def tearDown(self):
|
||||
safe_rmpath(TESTFN)
|
||||
|
||||
def assert_ntuple_of_nums(self, nt, type_=float, gezero=True):
|
||||
assert is_namedtuple(nt)
|
||||
for n in nt:
|
||||
self.assertIsInstance(n, type_)
|
||||
if gezero:
|
||||
self.assertGreaterEqual(n, 0)
|
||||
|
||||
def test_cpu_times(self):
|
||||
self.assert_ntuple_of_nums(psutil.cpu_times())
|
||||
for nt in psutil.cpu_times(percpu=True):
|
||||
self.assert_ntuple_of_nums(nt)
|
||||
|
||||
def test_cpu_percent(self):
|
||||
self.assertIsInstance(psutil.cpu_percent(interval=None), float)
|
||||
self.assertIsInstance(psutil.cpu_percent(interval=0.00001), float)
|
||||
|
||||
def test_cpu_times_percent(self):
|
||||
self.assert_ntuple_of_nums(psutil.cpu_times_percent(interval=None))
|
||||
self.assert_ntuple_of_nums(psutil.cpu_times_percent(interval=0.0001))
|
||||
|
||||
def test_cpu_count(self):
|
||||
self.assertIsInstance(psutil.cpu_count(), int)
|
||||
|
||||
@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
|
||||
def test_cpu_freq(self):
|
||||
if psutil.cpu_freq() is None:
|
||||
raise self.skipTest("cpu_freq() returns None")
|
||||
self.assert_ntuple_of_nums(psutil.cpu_freq(), type_=(float, int, long))
|
||||
|
||||
def test_disk_io_counters(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for k, v in psutil.disk_io_counters(perdisk=True).items():
|
||||
self.assertIsInstance(k, str)
|
||||
self.assert_ntuple_of_nums(v, type_=(int, long))
|
||||
|
||||
def test_disk_partitions(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for disk in psutil.disk_partitions():
|
||||
self.assertIsInstance(disk.device, str)
|
||||
self.assertIsInstance(disk.mountpoint, str)
|
||||
self.assertIsInstance(disk.fstype, str)
|
||||
self.assertIsInstance(disk.opts, str)
|
||||
|
||||
@unittest.skipIf(SKIP_SYSCONS, "requires root")
|
||||
def test_net_connections(self):
|
||||
with create_sockets():
|
||||
ret = psutil.net_connections('all')
|
||||
self.assertEqual(len(ret), len(set(ret)))
|
||||
for conn in ret:
|
||||
assert is_namedtuple(conn)
|
||||
|
||||
def test_net_if_addrs(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for ifname, addrs in psutil.net_if_addrs().items():
|
||||
self.assertIsInstance(ifname, str)
|
||||
for addr in addrs:
|
||||
if enum is not None:
|
||||
assert isinstance(addr.family, enum.IntEnum), addr
|
||||
else:
|
||||
assert isinstance(addr.family, int), addr
|
||||
self.assertIsInstance(addr.address, str)
|
||||
self.assertIsInstance(addr.netmask, (str, type(None)))
|
||||
self.assertIsInstance(addr.broadcast, (str, type(None)))
|
||||
|
||||
def test_net_if_stats(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for ifname, info in psutil.net_if_stats().items():
|
||||
self.assertIsInstance(ifname, str)
|
||||
self.assertIsInstance(info.isup, bool)
|
||||
if enum is not None:
|
||||
self.assertIsInstance(info.duplex, enum.IntEnum)
|
||||
else:
|
||||
self.assertIsInstance(info.duplex, int)
|
||||
self.assertIsInstance(info.speed, int)
|
||||
self.assertIsInstance(info.mtu, int)
|
||||
|
||||
@unittest.skipIf(not HAS_NET_IO_COUNTERS, 'not supported')
|
||||
def test_net_io_counters(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for ifname, _ in psutil.net_io_counters(pernic=True).items():
|
||||
self.assertIsInstance(ifname, str)
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_FANS, "not supported")
|
||||
def test_sensors_fans(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for name, units in psutil.sensors_fans().items():
|
||||
self.assertIsInstance(name, str)
|
||||
for unit in units:
|
||||
self.assertIsInstance(unit.label, str)
|
||||
self.assertIsInstance(unit.current, (float, int, type(None)))
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_TEMPERATURES, "not supported")
|
||||
def test_sensors_temperatures(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for name, units in psutil.sensors_temperatures().items():
|
||||
self.assertIsInstance(name, str)
|
||||
for unit in units:
|
||||
self.assertIsInstance(unit.label, str)
|
||||
self.assertIsInstance(unit.current, (float, int, type(None)))
|
||||
self.assertIsInstance(unit.high, (float, int, type(None)))
|
||||
self.assertIsInstance(unit.critical, (float, int, type(None)))
|
||||
|
||||
def test_boot_time(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
self.assertIsInstance(psutil.boot_time(), float)
|
||||
|
||||
def test_users(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
for user in psutil.users():
|
||||
self.assertIsInstance(user.name, str)
|
||||
self.assertIsInstance(user.terminal, (str, type(None)))
|
||||
self.assertIsInstance(user.host, (str, type(None)))
|
||||
self.assertIsInstance(user.pid, (int, type(None)))
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- Featch all processes test
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestFetchAllProcesses(unittest.TestCase):
|
||||
"""Test which iterates over all running processes and performs
|
||||
some sanity checks against Process API's returned values.
|
||||
"""
|
||||
|
||||
def get_attr_names(self):
|
||||
excluded_names = set([
|
||||
'send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
|
||||
'as_dict', 'parent', 'parents', 'children', 'memory_info_ex',
|
||||
'oneshot',
|
||||
])
|
||||
if LINUX and not HAS_RLIMIT:
|
||||
excluded_names.add('rlimit')
|
||||
attrs = []
|
||||
for name in dir(psutil.Process):
|
||||
if name.startswith("_"):
|
||||
continue
|
||||
if name in excluded_names:
|
||||
continue
|
||||
attrs.append(name)
|
||||
return attrs
|
||||
|
||||
def iter_procs(self):
|
||||
attrs = self.get_attr_names()
|
||||
for p in psutil.process_iter():
|
||||
with p.oneshot():
|
||||
for name in attrs:
|
||||
yield (p, name)
|
||||
|
||||
def call_meth(self, p, name):
|
||||
args = ()
|
||||
kwargs = {}
|
||||
attr = getattr(p, name, None)
|
||||
if attr is not None and callable(attr):
|
||||
if name == 'rlimit':
|
||||
args = (psutil.RLIMIT_NOFILE,)
|
||||
elif name == 'memory_maps':
|
||||
kwargs = {'grouped': False}
|
||||
return attr(*args, **kwargs)
|
||||
else:
|
||||
return attr
|
||||
|
||||
def test_fetch_all(self):
|
||||
valid_procs = 0
|
||||
default = object()
|
||||
failures = []
|
||||
for p, name in self.iter_procs():
|
||||
ret = default
|
||||
try:
|
||||
ret = self.call_meth(p, name)
|
||||
except NotImplementedError:
|
||||
msg = "%r was skipped because not implemented" % (
|
||||
self.__class__.__name__ + '.test_' + name)
|
||||
warn(msg)
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied) as err:
|
||||
self.assertEqual(err.pid, p.pid)
|
||||
if err.name:
|
||||
# make sure exception's name attr is set
|
||||
# with the actual process name
|
||||
self.assertEqual(err.name, p.name())
|
||||
assert str(err)
|
||||
assert err.msg
|
||||
except Exception:
|
||||
s = '\n' + '=' * 70 + '\n'
|
||||
s += "FAIL: test_%s (proc=%s" % (name, p)
|
||||
if ret != default:
|
||||
s += ", ret=%s)" % repr(ret)
|
||||
s += ')\n'
|
||||
s += '-' * 70
|
||||
s += "\n%s" % traceback.format_exc()
|
||||
s = "\n".join((" " * 4) + i for i in s.splitlines())
|
||||
s += '\n'
|
||||
failures.append(s)
|
||||
break
|
||||
else:
|
||||
valid_procs += 1
|
||||
if ret not in (0, 0.0, [], None, '', {}):
|
||||
assert ret, ret
|
||||
meth = getattr(self, name)
|
||||
meth(ret, p)
|
||||
|
||||
if failures:
|
||||
self.fail(''.join(failures))
|
||||
|
||||
# we should always have a non-empty list, not including PID 0 etc.
|
||||
# special cases.
|
||||
assert valid_procs
|
||||
|
||||
def cmdline(self, ret, proc):
|
||||
self.assertIsInstance(ret, list)
|
||||
for part in ret:
|
||||
self.assertIsInstance(part, str)
|
||||
|
||||
def exe(self, ret, proc):
|
||||
self.assertIsInstance(ret, (str, type(None)))
|
||||
if not ret:
|
||||
self.assertEqual(ret, '')
|
||||
else:
|
||||
if WINDOWS and not ret.endswith('.exe'):
|
||||
return # May be "Registry", "MemCompression", ...
|
||||
assert os.path.isabs(ret), ret
|
||||
# Note: os.stat() may return False even if the file is there
|
||||
# hence we skip the test, see:
|
||||
# http://stackoverflow.com/questions/3112546/os-path-exists-lies
|
||||
if POSIX and os.path.isfile(ret):
|
||||
if hasattr(os, 'access') and hasattr(os, "X_OK"):
|
||||
# XXX may fail on MACOS
|
||||
assert os.access(ret, os.X_OK)
|
||||
|
||||
def pid(self, ret, proc):
|
||||
self.assertIsInstance(ret, int)
|
||||
self.assertGreaterEqual(ret, 0)
|
||||
|
||||
def ppid(self, ret, proc):
|
||||
self.assertIsInstance(ret, (int, long))
|
||||
self.assertGreaterEqual(ret, 0)
|
||||
|
||||
def name(self, ret, proc):
|
||||
self.assertIsInstance(ret, str)
|
||||
# on AIX, "<exiting>" processes don't have names
|
||||
if not AIX:
|
||||
assert ret
|
||||
|
||||
def create_time(self, ret, proc):
|
||||
self.assertIsInstance(ret, float)
|
||||
try:
|
||||
self.assertGreaterEqual(ret, 0)
|
||||
except AssertionError:
|
||||
# XXX
|
||||
if OPENBSD and proc.status() == psutil.STATUS_ZOMBIE:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
# this can't be taken for granted on all platforms
|
||||
# self.assertGreaterEqual(ret, psutil.boot_time())
|
||||
# make sure returned value can be pretty printed
|
||||
# with strftime
|
||||
time.strftime("%Y %m %d %H:%M:%S", time.localtime(ret))
|
||||
|
||||
def uids(self, ret, proc):
|
||||
assert is_namedtuple(ret)
|
||||
for uid in ret:
|
||||
self.assertIsInstance(uid, int)
|
||||
self.assertGreaterEqual(uid, 0)
|
||||
|
||||
def gids(self, ret, proc):
|
||||
assert is_namedtuple(ret)
|
||||
# note: testing all gids as above seems not to be reliable for
|
||||
# gid == 30 (nodoby); not sure why.
|
||||
for gid in ret:
|
||||
self.assertIsInstance(gid, int)
|
||||
if not MACOS and not NETBSD:
|
||||
self.assertGreaterEqual(gid, 0)
|
||||
|
||||
def username(self, ret, proc):
|
||||
self.assertIsInstance(ret, str)
|
||||
assert ret
|
||||
|
||||
def status(self, ret, proc):
|
||||
self.assertIsInstance(ret, str)
|
||||
assert ret
|
||||
self.assertNotEqual(ret, '?') # XXX
|
||||
self.assertIn(ret, VALID_PROC_STATUSES)
|
||||
|
||||
def io_counters(self, ret, proc):
|
||||
assert is_namedtuple(ret)
|
||||
for field in ret:
|
||||
self.assertIsInstance(field, (int, long))
|
||||
if field != -1:
|
||||
self.assertGreaterEqual(field, 0)
|
||||
|
||||
def ionice(self, ret, proc):
|
||||
if LINUX:
|
||||
self.assertIsInstance(ret.ioclass, int)
|
||||
self.assertIsInstance(ret.value, int)
|
||||
self.assertGreaterEqual(ret.ioclass, 0)
|
||||
self.assertGreaterEqual(ret.value, 0)
|
||||
else: # Windows, Cygwin
|
||||
choices = [
|
||||
psutil.IOPRIO_VERYLOW,
|
||||
psutil.IOPRIO_LOW,
|
||||
psutil.IOPRIO_NORMAL,
|
||||
psutil.IOPRIO_HIGH]
|
||||
self.assertIsInstance(ret, int)
|
||||
self.assertGreaterEqual(ret, 0)
|
||||
self.assertIn(ret, choices)
|
||||
|
||||
def num_threads(self, ret, proc):
|
||||
self.assertIsInstance(ret, int)
|
||||
self.assertGreaterEqual(ret, 1)
|
||||
|
||||
def threads(self, ret, proc):
|
||||
self.assertIsInstance(ret, list)
|
||||
for t in ret:
|
||||
assert is_namedtuple(t)
|
||||
self.assertGreaterEqual(t.id, 0)
|
||||
self.assertGreaterEqual(t.user_time, 0)
|
||||
self.assertGreaterEqual(t.system_time, 0)
|
||||
for field in t:
|
||||
self.assertIsInstance(field, (int, float))
|
||||
|
||||
def cpu_times(self, ret, proc):
|
||||
assert is_namedtuple(ret)
|
||||
for n in ret:
|
||||
self.assertIsInstance(n, float)
|
||||
self.assertGreaterEqual(n, 0)
|
||||
# TODO: check ntuple fields
|
||||
|
||||
def cpu_percent(self, ret, proc):
|
||||
self.assertIsInstance(ret, float)
|
||||
assert 0.0 <= ret <= 100.0, ret
|
||||
|
||||
def cpu_num(self, ret, proc):
|
||||
self.assertIsInstance(ret, int)
|
||||
if FREEBSD and ret == -1:
|
||||
return
|
||||
self.assertGreaterEqual(ret, 0)
|
||||
if psutil.cpu_count() == 1:
|
||||
self.assertEqual(ret, 0)
|
||||
self.assertIn(ret, list(range(psutil.cpu_count())))
|
||||
|
||||
def memory_info(self, ret, proc):
|
||||
assert is_namedtuple(ret)
|
||||
for value in ret:
|
||||
self.assertIsInstance(value, (int, long))
|
||||
self.assertGreaterEqual(value, 0)
|
||||
if WINDOWS:
|
||||
self.assertGreaterEqual(ret.peak_wset, ret.wset)
|
||||
self.assertGreaterEqual(ret.peak_paged_pool, ret.paged_pool)
|
||||
self.assertGreaterEqual(ret.peak_nonpaged_pool, ret.nonpaged_pool)
|
||||
self.assertGreaterEqual(ret.peak_pagefile, ret.pagefile)
|
||||
|
||||
def memory_full_info(self, ret, proc):
|
||||
assert is_namedtuple(ret)
|
||||
total = psutil.virtual_memory().total
|
||||
for name in ret._fields:
|
||||
value = getattr(ret, name)
|
||||
self.assertIsInstance(value, (int, long))
|
||||
self.assertGreaterEqual(value, 0, msg=(name, value))
|
||||
if LINUX or OSX and name in ('vms', 'data'):
|
||||
# On Linux there are processes (e.g. 'goa-daemon') whose
|
||||
# VMS is incredibly high for some reason.
|
||||
continue
|
||||
self.assertLessEqual(value, total, msg=(name, value, total))
|
||||
|
||||
if LINUX:
|
||||
self.assertGreaterEqual(ret.pss, ret.uss)
|
||||
|
||||
def open_files(self, ret, proc):
|
||||
self.assertIsInstance(ret, list)
|
||||
for f in ret:
|
||||
self.assertIsInstance(f.fd, int)
|
||||
self.assertIsInstance(f.path, str)
|
||||
if WINDOWS:
|
||||
self.assertEqual(f.fd, -1)
|
||||
elif LINUX:
|
||||
self.assertIsInstance(f.position, int)
|
||||
self.assertIsInstance(f.mode, str)
|
||||
self.assertIsInstance(f.flags, int)
|
||||
self.assertGreaterEqual(f.position, 0)
|
||||
self.assertIn(f.mode, ('r', 'w', 'a', 'r+', 'a+'))
|
||||
self.assertGreater(f.flags, 0)
|
||||
elif BSD and not f.path:
|
||||
# XXX see: https://github.com/giampaolo/psutil/issues/595
|
||||
continue
|
||||
assert os.path.isabs(f.path), f
|
||||
assert os.path.isfile(f.path), f
|
||||
|
||||
def num_fds(self, ret, proc):
|
||||
self.assertIsInstance(ret, int)
|
||||
self.assertGreaterEqual(ret, 0)
|
||||
|
||||
def connections(self, ret, proc):
|
||||
with create_sockets():
|
||||
self.assertEqual(len(ret), len(set(ret)))
|
||||
for conn in ret:
|
||||
assert is_namedtuple(conn)
|
||||
|
||||
def cwd(self, ret, proc):
|
||||
if ret: # 'ret' can be None or empty
|
||||
self.assertIsInstance(ret, str)
|
||||
assert os.path.isabs(ret), ret
|
||||
try:
|
||||
st = os.stat(ret)
|
||||
except OSError as err:
|
||||
if WINDOWS and err.errno in \
|
||||
psutil._psplatform.ACCESS_DENIED_SET:
|
||||
pass
|
||||
# directory has been removed in mean time
|
||||
elif err.errno != errno.ENOENT:
|
||||
raise
|
||||
else:
|
||||
assert stat.S_ISDIR(st.st_mode)
|
||||
|
||||
def memory_percent(self, ret, proc):
|
||||
self.assertIsInstance(ret, float)
|
||||
assert 0 <= ret <= 100, ret
|
||||
|
||||
def is_running(self, ret, proc):
|
||||
self.assertIsInstance(ret, bool)
|
||||
|
||||
def cpu_affinity(self, ret, proc):
|
||||
self.assertIsInstance(ret, list)
|
||||
assert ret != [], ret
|
||||
cpus = range(psutil.cpu_count())
|
||||
for n in ret:
|
||||
self.assertIsInstance(n, int)
|
||||
self.assertIn(n, cpus)
|
||||
|
||||
def terminal(self, ret, proc):
|
||||
self.assertIsInstance(ret, (str, type(None)))
|
||||
if ret is not None:
|
||||
assert os.path.isabs(ret), ret
|
||||
assert os.path.exists(ret), ret
|
||||
|
||||
def memory_maps(self, ret, proc):
|
||||
for nt in ret:
|
||||
self.assertIsInstance(nt.addr, str)
|
||||
self.assertIsInstance(nt.perms, str)
|
||||
self.assertIsInstance(nt.path, str)
|
||||
for fname in nt._fields:
|
||||
value = getattr(nt, fname)
|
||||
if fname == 'path':
|
||||
if not value.startswith('['):
|
||||
assert os.path.isabs(nt.path), nt.path
|
||||
# commented as on Linux we might get
|
||||
# '/foo/bar (deleted)'
|
||||
# assert os.path.exists(nt.path), nt.path
|
||||
elif fname == 'addr':
|
||||
assert value, repr(value)
|
||||
elif fname == 'perms':
|
||||
if not WINDOWS:
|
||||
assert value, repr(value)
|
||||
else:
|
||||
self.assertIsInstance(value, (int, long))
|
||||
self.assertGreaterEqual(value, 0)
|
||||
|
||||
def num_handles(self, ret, proc):
|
||||
self.assertIsInstance(ret, int)
|
||||
self.assertGreaterEqual(ret, 0)
|
||||
|
||||
def nice(self, ret, proc):
|
||||
self.assertIsInstance(ret, int)
|
||||
if POSIX:
|
||||
assert -20 <= ret <= 20, ret
|
||||
else:
|
||||
priorities = [getattr(psutil, x) for x in dir(psutil)
|
||||
if x.endswith('_PRIORITY_CLASS')]
|
||||
self.assertIn(ret, priorities)
|
||||
|
||||
def num_ctx_switches(self, ret, proc):
|
||||
assert is_namedtuple(ret)
|
||||
for value in ret:
|
||||
self.assertIsInstance(value, (int, long))
|
||||
self.assertGreaterEqual(value, 0)
|
||||
|
||||
def rlimit(self, ret, proc):
|
||||
self.assertIsInstance(ret, tuple)
|
||||
self.assertEqual(len(ret), 2)
|
||||
self.assertGreaterEqual(ret[0], -1)
|
||||
self.assertGreaterEqual(ret[1], -1)
|
||||
|
||||
def environ(self, ret, proc):
|
||||
self.assertIsInstance(ret, dict)
|
||||
for k, v in ret.items():
|
||||
self.assertIsInstance(k, str)
|
||||
self.assertIsInstance(v, str)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
2118
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_linux.py
vendored
Normal file
2118
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_linux.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
600
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_memory_leaks.py
vendored
Normal file
600
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_memory_leaks.py
vendored
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Tests for detecting function memory leaks (typically the ones
|
||||
implemented in C). It does so by calling a function many times and
|
||||
checking whether process memory usage keeps increasing between
|
||||
calls or over time.
|
||||
Note that this may produce false positives (especially on Windows
|
||||
for some reason).
|
||||
PyPy appears to be completely unstable for this framework, probably
|
||||
because of how its JIT handles memory, so tests are skipped.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import functools
|
||||
import gc
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
import psutil
|
||||
import psutil._common
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._common import bytes2human
|
||||
from psutil._compat import ProcessLookupError
|
||||
from psutil._compat import xrange
|
||||
from psutil.tests import CIRRUS
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import HAS_CPU_AFFINITY
|
||||
from psutil.tests import HAS_CPU_FREQ
|
||||
from psutil.tests import HAS_ENVIRON
|
||||
from psutil.tests import HAS_IONICE
|
||||
from psutil.tests import HAS_MEMORY_MAPS
|
||||
from psutil.tests import HAS_NET_IO_COUNTERS
|
||||
from psutil.tests import HAS_PROC_CPU_NUM
|
||||
from psutil.tests import HAS_PROC_IO_COUNTERS
|
||||
from psutil.tests import HAS_RLIMIT
|
||||
from psutil.tests import HAS_SENSORS_BATTERY
|
||||
from psutil.tests import HAS_SENSORS_FANS
|
||||
from psutil.tests import HAS_SENSORS_TEMPERATURES
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import TESTFN
|
||||
from psutil.tests import TRAVIS
|
||||
from psutil.tests import unittest
|
||||
|
||||
|
||||
# configurable opts
|
||||
LOOPS = 1000
|
||||
MEMORY_TOLERANCE = 4096
|
||||
RETRY_FOR = 3
|
||||
SKIP_PYTHON_IMPL = True
|
||||
|
||||
cext = psutil._psplatform.cext
|
||||
thisproc = psutil.Process()
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# utils
|
||||
# ===================================================================
|
||||
|
||||
|
||||
def skip_if_linux():
|
||||
return unittest.skipIf(LINUX and SKIP_PYTHON_IMPL,
|
||||
"worthless on LINUX (pure python)")
|
||||
|
||||
|
||||
@unittest.skipIf(PYPY, "unreliable on PYPY")
|
||||
class TestMemLeak(unittest.TestCase):
|
||||
"""Base framework class which calls a function many times and
|
||||
produces a failure if process memory usage keeps increasing
|
||||
between calls or over time.
|
||||
"""
|
||||
tolerance = MEMORY_TOLERANCE
|
||||
loops = LOOPS
|
||||
retry_for = RETRY_FOR
|
||||
|
||||
def setUp(self):
|
||||
gc.collect()
|
||||
|
||||
def execute(self, fun, *args, **kwargs):
|
||||
"""Test a callable."""
|
||||
def call_many_times():
|
||||
for x in xrange(loops):
|
||||
self._call(fun, *args, **kwargs)
|
||||
del x
|
||||
gc.collect()
|
||||
|
||||
tolerance = kwargs.pop('tolerance_', None) or self.tolerance
|
||||
loops = kwargs.pop('loops_', None) or self.loops
|
||||
retry_for = kwargs.pop('retry_for_', None) or self.retry_for
|
||||
|
||||
# warm up
|
||||
for x in range(10):
|
||||
self._call(fun, *args, **kwargs)
|
||||
self.assertEqual(gc.garbage, [])
|
||||
self.assertEqual(threading.active_count(), 1)
|
||||
self.assertEqual(thisproc.children(), [])
|
||||
|
||||
# Get 2 distinct memory samples, before and after having
|
||||
# called fun repeadetly.
|
||||
# step 1
|
||||
call_many_times()
|
||||
mem1 = self._get_mem()
|
||||
# step 2
|
||||
call_many_times()
|
||||
mem2 = self._get_mem()
|
||||
|
||||
diff1 = mem2 - mem1
|
||||
if diff1 > 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
|
||||
# and if there are no leaks it should not increase
|
||||
# anymore.
|
||||
# Let's keep calling fun for 3 more seconds and fail if
|
||||
# we notice any difference.
|
||||
ncalls = 0
|
||||
stop_at = time.time() + retry_for
|
||||
while time.time() <= stop_at:
|
||||
self._call(fun, *args, **kwargs)
|
||||
ncalls += 1
|
||||
|
||||
del stop_at
|
||||
gc.collect()
|
||||
mem3 = self._get_mem()
|
||||
diff2 = mem3 - mem2
|
||||
|
||||
if mem3 > mem2:
|
||||
# failure
|
||||
extra_proc_mem = bytes2human(diff1 + diff2)
|
||||
print("exta proc mem: %s" % extra_proc_mem, file=sys.stderr)
|
||||
msg = "+%s after %s calls, +%s after another %s calls, "
|
||||
msg += "+%s extra proc mem"
|
||||
msg = msg % (
|
||||
bytes2human(diff1), loops, bytes2human(diff2), ncalls,
|
||||
extra_proc_mem)
|
||||
self.fail(msg)
|
||||
|
||||
def execute_w_exc(self, exc, fun, *args, **kwargs):
|
||||
"""Convenience function which tests a callable raising
|
||||
an exception.
|
||||
"""
|
||||
def call():
|
||||
self.assertRaises(exc, fun, *args, **kwargs)
|
||||
|
||||
self.execute(call)
|
||||
|
||||
@staticmethod
|
||||
def _get_mem():
|
||||
# By using USS memory it seems it's less likely to bump
|
||||
# into false positives.
|
||||
if LINUX or WINDOWS or MACOS:
|
||||
return thisproc.memory_full_info().uss
|
||||
else:
|
||||
return thisproc.memory_info().rss
|
||||
|
||||
@staticmethod
|
||||
def _call(fun, *args, **kwargs):
|
||||
fun(*args, **kwargs)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Process class
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestProcessObjectLeaks(TestMemLeak):
|
||||
"""Test leaks of Process class methods."""
|
||||
|
||||
proc = thisproc
|
||||
|
||||
def test_coverage(self):
|
||||
skip = set((
|
||||
"pid", "as_dict", "children", "cpu_affinity", "cpu_percent",
|
||||
"ionice", "is_running", "kill", "memory_info_ex", "memory_percent",
|
||||
"nice", "oneshot", "parent", "parents", "rlimit", "send_signal",
|
||||
"suspend", "terminate", "wait"))
|
||||
for name in dir(psutil.Process):
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
if name in skip:
|
||||
continue
|
||||
self.assertTrue(hasattr(self, "test_" + name), msg=name)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_name(self):
|
||||
self.execute(self.proc.name)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cmdline(self):
|
||||
self.execute(self.proc.cmdline)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_exe(self):
|
||||
self.execute(self.proc.exe)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_ppid(self):
|
||||
self.execute(self.proc.ppid)
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
@skip_if_linux()
|
||||
def test_uids(self):
|
||||
self.execute(self.proc.uids)
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
@skip_if_linux()
|
||||
def test_gids(self):
|
||||
self.execute(self.proc.gids)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_status(self):
|
||||
self.execute(self.proc.status)
|
||||
|
||||
def test_nice_get(self):
|
||||
self.execute(self.proc.nice)
|
||||
|
||||
def test_nice_set(self):
|
||||
niceness = thisproc.nice()
|
||||
self.execute(self.proc.nice, niceness)
|
||||
|
||||
@unittest.skipIf(not HAS_IONICE, "not supported")
|
||||
def test_ionice_get(self):
|
||||
self.execute(self.proc.ionice)
|
||||
|
||||
@unittest.skipIf(not HAS_IONICE, "not supported")
|
||||
def test_ionice_set(self):
|
||||
if WINDOWS:
|
||||
value = thisproc.ionice()
|
||||
self.execute(self.proc.ionice, value)
|
||||
else:
|
||||
self.execute(self.proc.ionice, psutil.IOPRIO_CLASS_NONE)
|
||||
fun = functools.partial(cext.proc_ioprio_set, os.getpid(), -1, 0)
|
||||
self.execute_w_exc(OSError, fun)
|
||||
|
||||
@unittest.skipIf(not HAS_PROC_IO_COUNTERS, "not supported")
|
||||
@skip_if_linux()
|
||||
def test_io_counters(self):
|
||||
self.execute(self.proc.io_counters)
|
||||
|
||||
@unittest.skipIf(POSIX, "worthless on POSIX")
|
||||
def test_username(self):
|
||||
self.execute(self.proc.username)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_create_time(self):
|
||||
self.execute(self.proc.create_time)
|
||||
|
||||
@skip_if_linux()
|
||||
@skip_on_access_denied(only_if=OPENBSD)
|
||||
def test_num_threads(self):
|
||||
self.execute(self.proc.num_threads)
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
def test_num_handles(self):
|
||||
self.execute(self.proc.num_handles)
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
@skip_if_linux()
|
||||
def test_num_fds(self):
|
||||
self.execute(self.proc.num_fds)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_num_ctx_switches(self):
|
||||
self.execute(self.proc.num_ctx_switches)
|
||||
|
||||
@skip_if_linux()
|
||||
@skip_on_access_denied(only_if=OPENBSD)
|
||||
def test_threads(self):
|
||||
self.execute(self.proc.threads)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_times(self):
|
||||
self.execute(self.proc.cpu_times)
|
||||
|
||||
@skip_if_linux()
|
||||
@unittest.skipIf(not HAS_PROC_CPU_NUM, "not supported")
|
||||
def test_cpu_num(self):
|
||||
self.execute(self.proc.cpu_num)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_memory_info(self):
|
||||
self.execute(self.proc.memory_info)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_memory_full_info(self):
|
||||
self.execute(self.proc.memory_full_info)
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
@skip_if_linux()
|
||||
def test_terminal(self):
|
||||
self.execute(self.proc.terminal)
|
||||
|
||||
@unittest.skipIf(POSIX and SKIP_PYTHON_IMPL,
|
||||
"worthless on POSIX (pure python)")
|
||||
def test_resume(self):
|
||||
self.execute(self.proc.resume)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cwd(self):
|
||||
self.execute(self.proc.cwd)
|
||||
|
||||
@unittest.skipIf(not HAS_CPU_AFFINITY, "not supported")
|
||||
def test_cpu_affinity_get(self):
|
||||
self.execute(self.proc.cpu_affinity)
|
||||
|
||||
@unittest.skipIf(not HAS_CPU_AFFINITY, "not supported")
|
||||
def test_cpu_affinity_set(self):
|
||||
affinity = thisproc.cpu_affinity()
|
||||
self.execute(self.proc.cpu_affinity, affinity)
|
||||
if not TRAVIS:
|
||||
self.execute_w_exc(ValueError, self.proc.cpu_affinity, [-1])
|
||||
|
||||
@skip_if_linux()
|
||||
def test_open_files(self):
|
||||
safe_rmpath(TESTFN) # needed after UNIX socket test has run
|
||||
with open(TESTFN, 'w'):
|
||||
self.execute(self.proc.open_files)
|
||||
|
||||
@unittest.skipIf(not HAS_MEMORY_MAPS, "not supported")
|
||||
@skip_if_linux()
|
||||
def test_memory_maps(self):
|
||||
self.execute(self.proc.memory_maps)
|
||||
|
||||
@unittest.skipIf(not LINUX, "LINUX only")
|
||||
@unittest.skipIf(not HAS_RLIMIT, "not supported")
|
||||
def test_rlimit_get(self):
|
||||
self.execute(self.proc.rlimit, psutil.RLIMIT_NOFILE)
|
||||
|
||||
@unittest.skipIf(not LINUX, "LINUX only")
|
||||
@unittest.skipIf(not HAS_RLIMIT, "not supported")
|
||||
def test_rlimit_set(self):
|
||||
limit = thisproc.rlimit(psutil.RLIMIT_NOFILE)
|
||||
self.execute(self.proc.rlimit, psutil.RLIMIT_NOFILE, limit)
|
||||
self.execute_w_exc(OSError, self.proc.rlimit, -1)
|
||||
|
||||
@skip_if_linux()
|
||||
# Windows implementation is based on a single system-wide
|
||||
# function (tested later).
|
||||
@unittest.skipIf(WINDOWS, "worthless on WINDOWS")
|
||||
def test_connections(self):
|
||||
# TODO: UNIX sockets are temporarily implemented by parsing
|
||||
# 'pfiles' cmd output; we don't want that part of the code to
|
||||
# be executed.
|
||||
with create_sockets():
|
||||
kind = 'inet' if SUNOS else 'all'
|
||||
self.execute(self.proc.connections, kind)
|
||||
|
||||
@unittest.skipIf(not HAS_ENVIRON, "not supported")
|
||||
def test_environ(self):
|
||||
self.execute(self.proc.environ)
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
def test_proc_info(self):
|
||||
self.execute(cext.proc_info, os.getpid())
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestProcessDualImplementation(TestMemLeak):
|
||||
|
||||
def test_cmdline_peb_true(self):
|
||||
self.execute(cext.proc_cmdline, os.getpid(), use_peb=True)
|
||||
|
||||
def test_cmdline_peb_false(self):
|
||||
self.execute(cext.proc_cmdline, os.getpid(), use_peb=False)
|
||||
|
||||
|
||||
class TestTerminatedProcessLeaks(TestProcessObjectLeaks):
|
||||
"""Repeat the tests above looking for leaks occurring when dealing
|
||||
with terminated processes raising NoSuchProcess exception.
|
||||
The C functions are still invoked but will follow different code
|
||||
paths. We'll check those code paths.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestTerminatedProcessLeaks, cls).setUpClass()
|
||||
p = get_test_subprocess()
|
||||
cls.proc = psutil.Process(p.pid)
|
||||
cls.proc.kill()
|
||||
cls.proc.wait()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestTerminatedProcessLeaks, cls).tearDownClass()
|
||||
reap_children()
|
||||
|
||||
def _call(self, fun, *args, **kwargs):
|
||||
try:
|
||||
fun(*args, **kwargs)
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
if WINDOWS:
|
||||
|
||||
def test_kill(self):
|
||||
self.execute(self.proc.kill)
|
||||
|
||||
def test_terminate(self):
|
||||
self.execute(self.proc.terminate)
|
||||
|
||||
def test_suspend(self):
|
||||
self.execute(self.proc.suspend)
|
||||
|
||||
def test_resume(self):
|
||||
self.execute(self.proc.resume)
|
||||
|
||||
def test_wait(self):
|
||||
self.execute(self.proc.wait)
|
||||
|
||||
def test_proc_info(self):
|
||||
# test dual implementation
|
||||
def call():
|
||||
try:
|
||||
return cext.proc_info(self.proc.pid)
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
|
||||
self.execute(call)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# system APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestModuleFunctionsLeaks(TestMemLeak):
|
||||
"""Test leaks of psutil module functions."""
|
||||
|
||||
def test_coverage(self):
|
||||
skip = set((
|
||||
"version_info", "__version__", "process_iter", "wait_procs",
|
||||
"cpu_percent", "cpu_times_percent", "cpu_count"))
|
||||
for name in psutil.__all__:
|
||||
if not name.islower():
|
||||
continue
|
||||
if name in skip:
|
||||
continue
|
||||
self.assertTrue(hasattr(self, "test_" + name), msg=name)
|
||||
|
||||
# --- cpu
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_count_logical(self):
|
||||
self.execute(psutil.cpu_count, logical=True)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_count_physical(self):
|
||||
self.execute(psutil.cpu_count, logical=False)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_times(self):
|
||||
self.execute(psutil.cpu_times)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_per_cpu_times(self):
|
||||
self.execute(psutil.cpu_times, percpu=True)
|
||||
|
||||
@skip_if_linux()
|
||||
def test_cpu_stats(self):
|
||||
self.execute(psutil.cpu_stats)
|
||||
|
||||
@skip_if_linux()
|
||||
@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
|
||||
def test_cpu_freq(self):
|
||||
self.execute(psutil.cpu_freq)
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
def test_getloadavg(self):
|
||||
self.execute(psutil.getloadavg)
|
||||
|
||||
# --- mem
|
||||
|
||||
def test_virtual_memory(self):
|
||||
self.execute(psutil.virtual_memory)
|
||||
|
||||
# TODO: remove this skip when this gets fixed
|
||||
@unittest.skipIf(SUNOS, "worthless on SUNOS (uses a subprocess)")
|
||||
def test_swap_memory(self):
|
||||
self.execute(psutil.swap_memory)
|
||||
|
||||
@unittest.skipIf(POSIX and SKIP_PYTHON_IMPL,
|
||||
"worthless on POSIX (pure python)")
|
||||
def test_pid_exists(self):
|
||||
self.execute(psutil.pid_exists, os.getpid())
|
||||
|
||||
# --- disk
|
||||
|
||||
@unittest.skipIf(POSIX and SKIP_PYTHON_IMPL,
|
||||
"worthless on POSIX (pure python)")
|
||||
def test_disk_usage(self):
|
||||
self.execute(psutil.disk_usage, '.')
|
||||
|
||||
def test_disk_partitions(self):
|
||||
self.execute(psutil.disk_partitions)
|
||||
|
||||
@unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'),
|
||||
'/proc/diskstats not available on this Linux version')
|
||||
@skip_if_linux()
|
||||
def test_disk_io_counters(self):
|
||||
self.execute(psutil.disk_io_counters, nowrap=False)
|
||||
|
||||
# --- proc
|
||||
|
||||
@skip_if_linux()
|
||||
def test_pids(self):
|
||||
self.execute(psutil.pids)
|
||||
|
||||
# --- net
|
||||
|
||||
@unittest.skipIf(TRAVIS and MACOS, "false positive on TRAVIS + MACOS")
|
||||
@unittest.skipIf(CIRRUS and FREEBSD, "false positive on CIRRUS + FREEBSD")
|
||||
@skip_if_linux()
|
||||
@unittest.skipIf(not HAS_NET_IO_COUNTERS, 'not supported')
|
||||
def test_net_io_counters(self):
|
||||
self.execute(psutil.net_io_counters, nowrap=False)
|
||||
|
||||
@skip_if_linux()
|
||||
@unittest.skipIf(MACOS and os.getuid() != 0, "need root access")
|
||||
def test_net_connections(self):
|
||||
with create_sockets():
|
||||
self.execute(psutil.net_connections)
|
||||
|
||||
def test_net_if_addrs(self):
|
||||
# Note: verified that on Windows this was a false positive.
|
||||
self.execute(psutil.net_if_addrs,
|
||||
tolerance_=80 * 1024 if WINDOWS else None)
|
||||
|
||||
@unittest.skipIf(TRAVIS, "EPERM on travis")
|
||||
def test_net_if_stats(self):
|
||||
self.execute(psutil.net_if_stats)
|
||||
|
||||
# --- sensors
|
||||
|
||||
@skip_if_linux()
|
||||
@unittest.skipIf(not HAS_SENSORS_BATTERY, "not supported")
|
||||
def test_sensors_battery(self):
|
||||
self.execute(psutil.sensors_battery)
|
||||
|
||||
@skip_if_linux()
|
||||
@unittest.skipIf(not HAS_SENSORS_TEMPERATURES, "not supported")
|
||||
def test_sensors_temperatures(self):
|
||||
self.execute(psutil.sensors_temperatures)
|
||||
|
||||
@skip_if_linux()
|
||||
@unittest.skipIf(not HAS_SENSORS_FANS, "not supported")
|
||||
def test_sensors_fans(self):
|
||||
self.execute(psutil.sensors_fans)
|
||||
|
||||
# --- others
|
||||
|
||||
@skip_if_linux()
|
||||
def test_boot_time(self):
|
||||
self.execute(psutil.boot_time)
|
||||
|
||||
@unittest.skipIf(WINDOWS, "XXX produces a false positive on Windows")
|
||||
def test_users(self):
|
||||
self.execute(psutil.users)
|
||||
|
||||
if WINDOWS:
|
||||
|
||||
# --- win services
|
||||
|
||||
def test_win_service_iter(self):
|
||||
self.execute(cext.winservice_enumerate)
|
||||
|
||||
def test_win_service_get(self):
|
||||
pass
|
||||
|
||||
def test_win_service_get_config(self):
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
self.execute(cext.winservice_query_config, name)
|
||||
|
||||
def test_win_service_get_status(self):
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
self.execute(cext.winservice_query_status, name)
|
||||
|
||||
def test_win_service_get_description(self):
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
self.execute(cext.winservice_query_descr, name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
1065
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_misc.py
vendored
Normal file
1065
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_misc.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
294
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_osx.py
vendored
Normal file
294
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_osx.py
vendored
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
"""MACOS specific tests."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import MACOS
|
||||
from psutil.tests import create_zombie_proc
|
||||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import MEMORY_TOLERANCE
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE") if MACOS else None
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
"""Expects a sysctl command with an argument and parse the result
|
||||
returning only the value of interest.
|
||||
"""
|
||||
out = sh(cmdline)
|
||||
result = out.split()[1]
|
||||
try:
|
||||
return int(result)
|
||||
except ValueError:
|
||||
return result
|
||||
|
||||
|
||||
def vm_stat(field):
|
||||
"""Wrapper around 'vm_stat' cmdline utility."""
|
||||
out = sh('vm_stat')
|
||||
for line in out.split('\n'):
|
||||
if field in line:
|
||||
break
|
||||
else:
|
||||
raise ValueError("line not found")
|
||||
return int(re.search(r'\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.skipIf(not MACOS, "MACOS only")
|
||||
class TestProcess(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_process_create_time(self):
|
||||
output = sh("ps -o lstart -p %s" % self.pid)
|
||||
start_ps = output.replace('STARTED', '').strip()
|
||||
hhmmss = start_ps.split(' ')[-2]
|
||||
year = start_ps.split(' ')[-1]
|
||||
start_psutil = psutil.Process(self.pid).create_time()
|
||||
self.assertEqual(
|
||||
hhmmss,
|
||||
time.strftime("%H:%M:%S", time.localtime(start_psutil)))
|
||||
self.assertEqual(
|
||||
year,
|
||||
time.strftime("%Y", time.localtime(start_psutil)))
|
||||
|
||||
|
||||
@unittest.skipIf(not MACOS, "MACOS only")
|
||||
class TestZombieProcessAPIs(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
zpid = create_zombie_proc()
|
||||
cls.p = psutil.Process(zpid)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children(recursive=True)
|
||||
|
||||
def test_pidtask_info(self):
|
||||
self.assertEqual(self.p.status(), psutil.STATUS_ZOMBIE)
|
||||
self.p.ppid()
|
||||
self.p.uids()
|
||||
self.p.gids()
|
||||
self.p.terminal()
|
||||
self.p.create_time()
|
||||
|
||||
def test_exe(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.exe)
|
||||
|
||||
def test_cmdline(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.cmdline)
|
||||
|
||||
def test_environ(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.environ)
|
||||
|
||||
def test_cwd(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.cwd)
|
||||
|
||||
def test_memory_full_info(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.memory_full_info)
|
||||
|
||||
def test_cpu_times(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.cpu_times)
|
||||
|
||||
def test_num_ctx_switches(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.num_ctx_switches)
|
||||
|
||||
def test_num_threads(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.num_threads)
|
||||
|
||||
def test_open_files(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.open_files)
|
||||
|
||||
def test_connections(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.connections)
|
||||
|
||||
def test_num_fds(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.num_fds)
|
||||
|
||||
def test_threads(self):
|
||||
self.assertRaises((psutil.ZombieProcess, psutil.AccessDenied),
|
||||
self.p.threads)
|
||||
|
||||
|
||||
@unittest.skipIf(not MACOS, "MACOS only")
|
||||
class TestSystemAPIs(unittest.TestCase):
|
||||
|
||||
# --- disk
|
||||
|
||||
def test_disks(self):
|
||||
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||
# against "df -a"
|
||||
def df(path):
|
||||
out = sh('df -k "%s"' % path).strip()
|
||||
lines = out.split('\n')
|
||||
lines.pop(0)
|
||||
line = lines.pop(0)
|
||||
dev, total, used, free = line.split()[:4]
|
||||
if dev == 'none':
|
||||
dev = ''
|
||||
total = int(total) * 1024
|
||||
used = int(used) * 1024
|
||||
free = int(free) * 1024
|
||||
return dev, total, used, free
|
||||
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
dev, total, used, free = df(part.mountpoint)
|
||||
self.assertEqual(part.device, dev)
|
||||
self.assertEqual(usage.total, total)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % usage.free, free)
|
||||
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, df=%s" % usage.used, used)
|
||||
|
||||
# --- cpu
|
||||
|
||||
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))
|
||||
|
||||
def test_cpu_freq(self):
|
||||
freq = psutil.cpu_freq()
|
||||
self.assertEqual(
|
||||
freq.current * 1000 * 1000, sysctl("sysctl hw.cpufrequency"))
|
||||
self.assertEqual(
|
||||
freq.min * 1000 * 1000, sysctl("sysctl hw.cpufrequency_min"))
|
||||
self.assertEqual(
|
||||
freq.max * 1000 * 1000, sysctl("sysctl hw.cpufrequency_max"))
|
||||
|
||||
# --- virtual mem
|
||||
|
||||
def test_vmem_total(self):
|
||||
sysctl_hwphymem = sysctl('sysctl hw.memsize')
|
||||
self.assertEqual(sysctl_hwphymem, psutil.virtual_memory().total)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_free(self):
|
||||
vmstat_val = vm_stat("free")
|
||||
psutil_val = psutil.virtual_memory().free
|
||||
self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_active(self):
|
||||
vmstat_val = vm_stat("active")
|
||||
psutil_val = psutil.virtual_memory().active
|
||||
self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_inactive(self):
|
||||
vmstat_val = vm_stat("inactive")
|
||||
psutil_val = psutil.virtual_memory().inactive
|
||||
self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_vmem_wired(self):
|
||||
vmstat_val = vm_stat("wired")
|
||||
psutil_val = psutil.virtual_memory().wired
|
||||
self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE)
|
||||
|
||||
# --- swap mem
|
||||
|
||||
@retry_on_failure()
|
||||
def test_swapmem_sin(self):
|
||||
vmstat_val = vm_stat("Pageins")
|
||||
psutil_val = psutil.swap_memory().sin
|
||||
self.assertEqual(psutil_val, vmstat_val)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_swapmem_sout(self):
|
||||
vmstat_val = vm_stat("Pageout")
|
||||
psutil_val = psutil.swap_memory().sout
|
||||
self.assertEqual(psutil_val, vmstat_val)
|
||||
|
||||
# Not very reliable.
|
||||
# def test_swapmem_total(self):
|
||||
# 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))
|
||||
|
||||
# --- network
|
||||
|
||||
def test_net_if_stats(self):
|
||||
for name, stats in psutil.net_if_stats().items():
|
||||
try:
|
||||
out = sh("ifconfig %s" % name)
|
||||
except RuntimeError:
|
||||
pass
|
||||
else:
|
||||
self.assertEqual(stats.isup, 'RUNNING' in out, msg=out)
|
||||
self.assertEqual(stats.mtu,
|
||||
int(re.findall(r'mtu (\d+)', out)[0]))
|
||||
|
||||
# --- sensors_battery
|
||||
|
||||
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||
def test_sensors_battery(self):
|
||||
out = sh("pmset -g batt")
|
||||
percent = re.search(r"(\d+)%", out).group(1)
|
||||
drawing_from = re.search("Now drawing from '([^']+)'", out).group(1)
|
||||
power_plugged = drawing_from == "AC Power"
|
||||
psutil_result = psutil.sensors_battery()
|
||||
self.assertEqual(psutil_result.power_plugged, power_plugged)
|
||||
self.assertEqual(psutil_result.percent, int(percent))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
453
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_posix.py
vendored
Normal file
453
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_posix.py
vendored
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- 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
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""POSIX specific tests."""
|
||||
|
||||
import datetime
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import AIX
|
||||
from psutil import BSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil.tests import CI_TESTING
|
||||
from psutil.tests import get_kernel_version
|
||||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import HAS_NET_IO_COUNTERS
|
||||
from psutil.tests import mock
|
||||
from psutil.tests import PYTHON_EXE
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import TRAVIS
|
||||
from psutil.tests import unittest
|
||||
from psutil.tests import wait_for_pid
|
||||
from psutil.tests import which
|
||||
|
||||
|
||||
def ps(fmt, pid=None):
|
||||
"""
|
||||
Wrapper for calling the ps command with a little bit of cross-platform
|
||||
support for a narrow range of features.
|
||||
"""
|
||||
|
||||
cmd = ['ps']
|
||||
|
||||
if LINUX:
|
||||
cmd.append('--no-headers')
|
||||
|
||||
if pid is not None:
|
||||
cmd.extend(['-p', str(pid)])
|
||||
else:
|
||||
if SUNOS or AIX:
|
||||
cmd.append('-A')
|
||||
else:
|
||||
cmd.append('ax')
|
||||
|
||||
if SUNOS:
|
||||
fmt_map = set(('command', 'comm', 'start', 'stime'))
|
||||
fmt = fmt_map.get(fmt, fmt)
|
||||
|
||||
cmd.extend(['-o', fmt])
|
||||
|
||||
output = sh(cmd)
|
||||
|
||||
if LINUX:
|
||||
output = output.splitlines()
|
||||
else:
|
||||
output = output.splitlines()[1:]
|
||||
|
||||
all_output = []
|
||||
for line in output:
|
||||
line = line.strip()
|
||||
|
||||
try:
|
||||
line = int(line)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
all_output.append(line)
|
||||
|
||||
if pid is None:
|
||||
return all_output
|
||||
else:
|
||||
return all_output[0]
|
||||
|
||||
# ps "-o" field names differ wildly between platforms.
|
||||
# "comm" means "only executable name" but is not available on BSD platforms.
|
||||
# "args" means "command with all its arguments", and is also not available
|
||||
# on BSD platforms.
|
||||
# "command" is like "args" on most platforms, but like "comm" on AIX,
|
||||
# and not available on SUNOS.
|
||||
# so for the executable name we can use "comm" on Solaris and split "command"
|
||||
# on other platforms.
|
||||
# to get the cmdline (with args) we have to use "args" on AIX and
|
||||
# Solaris, and can use "command" on all others.
|
||||
|
||||
|
||||
def ps_name(pid):
|
||||
field = "command"
|
||||
if SUNOS:
|
||||
field = "comm"
|
||||
return ps(field, pid).split()[0]
|
||||
|
||||
|
||||
def ps_args(pid):
|
||||
field = "command"
|
||||
if AIX or SUNOS:
|
||||
field = "args"
|
||||
return ps(field, pid)
|
||||
|
||||
|
||||
def ps_rss(pid):
|
||||
field = "rss"
|
||||
if AIX:
|
||||
field = "rssize"
|
||||
return ps(field, pid)
|
||||
|
||||
|
||||
def ps_vsz(pid):
|
||||
field = "vsz"
|
||||
if AIX:
|
||||
field = "vsize"
|
||||
return ps(field, pid)
|
||||
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
class TestProcess(unittest.TestCase):
|
||||
"""Compare psutil results against 'ps' command line utility (mainly)."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess([PYTHON_EXE, "-E", "-O"],
|
||||
stdin=subprocess.PIPE).pid
|
||||
wait_for_pid(cls.pid)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_ppid(self):
|
||||
ppid_ps = ps('ppid', self.pid)
|
||||
ppid_psutil = psutil.Process(self.pid).ppid()
|
||||
self.assertEqual(ppid_ps, ppid_psutil)
|
||||
|
||||
def test_uid(self):
|
||||
uid_ps = ps('uid', self.pid)
|
||||
uid_psutil = psutil.Process(self.pid).uids().real
|
||||
self.assertEqual(uid_ps, uid_psutil)
|
||||
|
||||
def test_gid(self):
|
||||
gid_ps = ps('rgid', self.pid)
|
||||
gid_psutil = psutil.Process(self.pid).gids().real
|
||||
self.assertEqual(gid_ps, gid_psutil)
|
||||
|
||||
def test_username(self):
|
||||
username_ps = ps('user', self.pid)
|
||||
username_psutil = psutil.Process(self.pid).username()
|
||||
self.assertEqual(username_ps, username_psutil)
|
||||
|
||||
def test_username_no_resolution(self):
|
||||
# Emulate a case where the system can't resolve the uid to
|
||||
# a username in which case psutil is supposed to return
|
||||
# the stringified uid.
|
||||
p = psutil.Process()
|
||||
with mock.patch("psutil.pwd.getpwuid", side_effect=KeyError) as fun:
|
||||
self.assertEqual(p.username(), str(p.uids().real))
|
||||
assert fun.called
|
||||
|
||||
@skip_on_access_denied()
|
||||
@retry_on_failure()
|
||||
def test_rss_memory(self):
|
||||
# give python interpreter some time to properly initialize
|
||||
# so that the results are the same
|
||||
time.sleep(0.1)
|
||||
rss_ps = ps_rss(self.pid)
|
||||
rss_psutil = psutil.Process(self.pid).memory_info()[0] / 1024
|
||||
self.assertEqual(rss_ps, rss_psutil)
|
||||
|
||||
@skip_on_access_denied()
|
||||
@retry_on_failure()
|
||||
def test_vsz_memory(self):
|
||||
# give python interpreter some time to properly initialize
|
||||
# so that the results are the same
|
||||
time.sleep(0.1)
|
||||
vsz_ps = ps_vsz(self.pid)
|
||||
vsz_psutil = psutil.Process(self.pid).memory_info()[1] / 1024
|
||||
self.assertEqual(vsz_ps, vsz_psutil)
|
||||
|
||||
def test_name(self):
|
||||
name_ps = ps_name(self.pid)
|
||||
# remove path if there is any, from the command
|
||||
name_ps = os.path.basename(name_ps).lower()
|
||||
name_psutil = psutil.Process(self.pid).name().lower()
|
||||
# ...because of how we calculate PYTHON_EXE; on MACOS this may
|
||||
# be "pythonX.Y".
|
||||
name_ps = re.sub(r"\d.\d", "", name_ps)
|
||||
name_psutil = re.sub(r"\d.\d", "", name_psutil)
|
||||
# ...may also be "python.X"
|
||||
name_ps = re.sub(r"\d", "", name_ps)
|
||||
name_psutil = re.sub(r"\d", "", name_psutil)
|
||||
self.assertEqual(name_ps, name_psutil)
|
||||
|
||||
def test_name_long(self):
|
||||
# On UNIX the kernel truncates the name to the first 15
|
||||
# characters. In such a case psutil tries to determine the
|
||||
# full name from the cmdline.
|
||||
name = "long-program-name"
|
||||
cmdline = ["long-program-name-extended", "foo", "bar"]
|
||||
with mock.patch("psutil._psplatform.Process.name",
|
||||
return_value=name):
|
||||
with mock.patch("psutil._psplatform.Process.cmdline",
|
||||
return_value=cmdline):
|
||||
p = psutil.Process()
|
||||
self.assertEqual(p.name(), "long-program-name-extended")
|
||||
|
||||
def test_name_long_cmdline_ad_exc(self):
|
||||
# Same as above but emulates a case where cmdline() raises
|
||||
# AccessDenied in which case psutil is supposed to return
|
||||
# the truncated name instead of crashing.
|
||||
name = "long-program-name"
|
||||
with mock.patch("psutil._psplatform.Process.name",
|
||||
return_value=name):
|
||||
with mock.patch("psutil._psplatform.Process.cmdline",
|
||||
side_effect=psutil.AccessDenied(0, "")):
|
||||
p = psutil.Process()
|
||||
self.assertEqual(p.name(), "long-program-name")
|
||||
|
||||
def test_name_long_cmdline_nsp_exc(self):
|
||||
# Same as above but emulates a case where cmdline() raises NSP
|
||||
# which is supposed to propagate.
|
||||
name = "long-program-name"
|
||||
with mock.patch("psutil._psplatform.Process.name",
|
||||
return_value=name):
|
||||
with mock.patch("psutil._psplatform.Process.cmdline",
|
||||
side_effect=psutil.NoSuchProcess(0, "")):
|
||||
p = psutil.Process()
|
||||
self.assertRaises(psutil.NoSuchProcess, p.name)
|
||||
|
||||
@unittest.skipIf(MACOS or BSD, 'ps -o start not available')
|
||||
def test_create_time(self):
|
||||
time_ps = ps('start', self.pid)
|
||||
time_psutil = psutil.Process(self.pid).create_time()
|
||||
time_psutil_tstamp = datetime.datetime.fromtimestamp(
|
||||
time_psutil).strftime("%H:%M:%S")
|
||||
# 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_exe(self):
|
||||
ps_pathname = ps_name(self.pid)
|
||||
psutil_pathname = psutil.Process(self.pid).exe()
|
||||
try:
|
||||
self.assertEqual(ps_pathname, psutil_pathname)
|
||||
except AssertionError:
|
||||
# certain platforms such as BSD are more accurate returning:
|
||||
# "/usr/local/bin/python2.7"
|
||||
# ...instead of:
|
||||
# "/usr/local/bin/python"
|
||||
# We do not want to consider this difference in accuracy
|
||||
# an error.
|
||||
adjusted_ps_pathname = ps_pathname[:len(ps_pathname)]
|
||||
self.assertEqual(ps_pathname, adjusted_ps_pathname)
|
||||
|
||||
def test_cmdline(self):
|
||||
ps_cmdline = ps_args(self.pid)
|
||||
psutil_cmdline = " ".join(psutil.Process(self.pid).cmdline())
|
||||
self.assertEqual(ps_cmdline, psutil_cmdline)
|
||||
|
||||
# On SUNOS "ps" reads niceness /proc/pid/psinfo which returns an
|
||||
# incorrect value (20); the real deal is getpriority(2) which
|
||||
# returns 0; psutil relies on it, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1082
|
||||
# AIX has the same issue
|
||||
@unittest.skipIf(SUNOS, "not reliable on SUNOS")
|
||||
@unittest.skipIf(AIX, "not reliable on AIX")
|
||||
def test_nice(self):
|
||||
ps_nice = ps('nice', self.pid)
|
||||
psutil_nice = psutil.Process().nice()
|
||||
self.assertEqual(ps_nice, psutil_nice)
|
||||
|
||||
def test_num_fds(self):
|
||||
# Note: this fails from time to time; I'm keen on thinking
|
||||
# it doesn't mean something is broken
|
||||
def call(p, attr):
|
||||
args = ()
|
||||
attr = getattr(p, name, None)
|
||||
if attr is not None and callable(attr):
|
||||
if name == 'rlimit':
|
||||
args = (psutil.RLIMIT_NOFILE,)
|
||||
attr(*args)
|
||||
else:
|
||||
attr
|
||||
|
||||
p = psutil.Process(os.getpid())
|
||||
failures = []
|
||||
ignored_names = ['terminate', 'kill', 'suspend', 'resume', 'nice',
|
||||
'send_signal', 'wait', 'children', 'as_dict',
|
||||
'memory_info_ex', 'parent', 'parents']
|
||||
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 in ignored_names):
|
||||
continue
|
||||
else:
|
||||
try:
|
||||
num1 = p.num_fds()
|
||||
for x in range(2):
|
||||
call(p, name)
|
||||
num2 = p.num_fds()
|
||||
except psutil.AccessDenied:
|
||||
pass
|
||||
else:
|
||||
if abs(num2 - num1) > 1:
|
||||
fail = "failure while processing Process.%s method " \
|
||||
"(before=%s, after=%s)" % (name, num1, num2)
|
||||
failures.append(fail)
|
||||
if failures:
|
||||
self.fail('\n' + '\n'.join(failures))
|
||||
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
class TestSystemAPIs(unittest.TestCase):
|
||||
"""Test some system APIs."""
|
||||
|
||||
@retry_on_failure()
|
||||
def test_pids(self):
|
||||
# Note: this test might fail if the OS is starting/killing
|
||||
# other processes in the meantime
|
||||
pids_ps = sorted(ps("pid"))
|
||||
pids_psutil = psutil.pids()
|
||||
|
||||
# on MACOS and OPENBSD ps doesn't show pid 0
|
||||
if MACOS or OPENBSD and 0 not in pids_ps:
|
||||
pids_ps.insert(0, 0)
|
||||
|
||||
# There will often be one more process in pids_ps for ps itself
|
||||
if len(pids_ps) - len(pids_psutil) > 1:
|
||||
difference = [x for x in pids_psutil if x not in pids_ps] + \
|
||||
[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 all interfaces
|
||||
# returned by psutil
|
||||
@unittest.skipIf(SUNOS, "unreliable on SUNOS")
|
||||
@unittest.skipIf(TRAVIS, "unreliable on TRAVIS")
|
||||
@unittest.skipIf(not which('ifconfig'), "no ifconfig cmd")
|
||||
@unittest.skipIf(not HAS_NET_IO_COUNTERS, "not supported")
|
||||
def test_nic_names(self):
|
||||
output = sh("ifconfig -a")
|
||||
for nic in psutil.net_io_counters(pernic=True).keys():
|
||||
for line in output.split():
|
||||
if line.startswith(nic):
|
||||
break
|
||||
else:
|
||||
self.fail(
|
||||
"couldn't find %s nic in 'ifconfig -a' output\n%s" % (
|
||||
nic, output))
|
||||
|
||||
@unittest.skipIf(CI_TESTING and not psutil.users(), "unreliable on CI")
|
||||
@retry_on_failure()
|
||||
def test_users(self):
|
||||
out = sh("who")
|
||||
lines = out.split('\n')
|
||||
if not lines:
|
||||
raise self.skipTest("no users on this system")
|
||||
users = [x.split()[0] for x in lines]
|
||||
terminals = [x.split()[1] for x in lines]
|
||||
self.assertEqual(len(users), len(psutil.users()))
|
||||
for u in psutil.users():
|
||||
self.assertIn(u.name, users)
|
||||
self.assertIn(u.terminal, terminals)
|
||||
|
||||
def test_pid_exists_let_raise(self):
|
||||
# According to "man 2 kill" possible error values for kill
|
||||
# are (EINVAL, EPERM, ESRCH). Test that any other errno
|
||||
# results in an exception.
|
||||
with mock.patch("psutil._psposix.os.kill",
|
||||
side_effect=OSError(errno.EBADF, "")) as m:
|
||||
self.assertRaises(OSError, psutil._psposix.pid_exists, os.getpid())
|
||||
assert m.called
|
||||
|
||||
def test_os_waitpid_let_raise(self):
|
||||
# os.waitpid() is supposed to catch EINTR and ECHILD only.
|
||||
# Test that any other errno results in an exception.
|
||||
with mock.patch("psutil._psposix.os.waitpid",
|
||||
side_effect=OSError(errno.EBADF, "")) as m:
|
||||
self.assertRaises(OSError, psutil._psposix.wait_pid, os.getpid())
|
||||
assert m.called
|
||||
|
||||
def test_os_waitpid_eintr(self):
|
||||
# os.waitpid() is supposed to "retry" on EINTR.
|
||||
with mock.patch("psutil._psposix.os.waitpid",
|
||||
side_effect=OSError(errno.EINTR, "")) as m:
|
||||
self.assertRaises(
|
||||
psutil._psposix.TimeoutExpired,
|
||||
psutil._psposix.wait_pid, os.getpid(), timeout=0.01)
|
||||
assert m.called
|
||||
|
||||
def test_os_waitpid_bad_ret_status(self):
|
||||
# Simulate os.waitpid() returning a bad status.
|
||||
with mock.patch("psutil._psposix.os.waitpid",
|
||||
return_value=(1, -1)) as m:
|
||||
self.assertRaises(ValueError,
|
||||
psutil._psposix.wait_pid, os.getpid())
|
||||
assert m.called
|
||||
|
||||
# AIX can return '-' in df output instead of numbers, e.g. for /proc
|
||||
@unittest.skipIf(AIX, "unreliable on AIX")
|
||||
def test_disk_usage(self):
|
||||
def df(device):
|
||||
out = sh("df -k %s" % device).strip()
|
||||
line = out.split('\n')[1]
|
||||
fields = line.split()
|
||||
total = int(fields[1]) * 1024
|
||||
used = int(fields[2]) * 1024
|
||||
free = int(fields[3]) * 1024
|
||||
percent = float(fields[4].replace('%', ''))
|
||||
return (total, used, free, percent)
|
||||
|
||||
tolerance = 4 * 1024 * 1024 # 4MB
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
usage = psutil.disk_usage(part.mountpoint)
|
||||
try:
|
||||
total, used, free, percent = df(part.device)
|
||||
except RuntimeError as err:
|
||||
# see:
|
||||
# https://travis-ci.org/giampaolo/psutil/jobs/138338464
|
||||
# https://travis-ci.org/giampaolo/psutil/jobs/138343361
|
||||
err = str(err).lower()
|
||||
if "no such file or directory" in err or \
|
||||
"raw devices not supported" in err or \
|
||||
"permission denied" in err:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
self.assertAlmostEqual(usage.total, total, delta=tolerance)
|
||||
self.assertAlmostEqual(usage.used, used, delta=tolerance)
|
||||
self.assertAlmostEqual(usage.free, free, delta=tolerance)
|
||||
self.assertAlmostEqual(usage.percent, percent, delta=1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
1643
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_process.py
vendored
Normal file
1643
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_process.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
45
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_sunos.py
vendored
Normal file
45
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_sunos.py
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
"""Sun OS specific tests."""
|
||||
|
||||
import os
|
||||
|
||||
import psutil
|
||||
from psutil import SUNOS
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
|
||||
|
||||
@unittest.skipIf(not SUNOS, "SUNOS only")
|
||||
class SunOSSpecificTestCase(unittest.TestCase):
|
||||
|
||||
def test_swap_memory(self):
|
||||
out = sh('env PATH=/usr/sbin:/sbin:%s swap -l' % os.environ['PATH'])
|
||||
lines = out.strip().split('\n')[1:]
|
||||
if not lines:
|
||||
raise ValueError('no swap device(s) configured')
|
||||
total = free = 0
|
||||
for line in lines:
|
||||
line = line.split()
|
||||
t, f = line[-2:]
|
||||
total += int(int(t) * 512)
|
||||
free += int(int(f) * 512)
|
||||
used = total - free
|
||||
|
||||
psutil_swap = psutil.swap_memory()
|
||||
self.assertEqual(psutil_swap.total, total)
|
||||
self.assertEqual(psutil_swap.used, used)
|
||||
self.assertEqual(psutil_swap.free, free)
|
||||
|
||||
def test_cpu_count(self):
|
||||
out = sh("/usr/sbin/psrinfo")
|
||||
self.assertEqual(psutil.cpu_count(), len(out.split('\n')))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
904
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_system.py
vendored
Normal file
904
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_system.py
vendored
Normal file
|
|
@ -0,0 +1,904 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
"""Tests for system APIS."""
|
||||
|
||||
import contextlib
|
||||
import datetime
|
||||
import errno
|
||||
import os
|
||||
import pprint
|
||||
import shutil
|
||||
import signal
|
||||
import socket
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import AIX
|
||||
from psutil import BSD
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import MACOS
|
||||
from psutil import NETBSD
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import FileNotFoundError
|
||||
from psutil._compat import long
|
||||
from psutil.tests import ASCII_FS
|
||||
from psutil.tests import check_net_address
|
||||
from psutil.tests import CI_TESTING
|
||||
from psutil.tests import DEVNULL
|
||||
from psutil.tests import enum
|
||||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import HAS_CPU_FREQ
|
||||
from psutil.tests import HAS_GETLOADAVG
|
||||
from psutil.tests import HAS_NET_IO_COUNTERS
|
||||
from psutil.tests import HAS_SENSORS_BATTERY
|
||||
from psutil.tests import HAS_SENSORS_FANS
|
||||
from psutil.tests import HAS_SENSORS_TEMPERATURES
|
||||
from psutil.tests import mock
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import TESTFN
|
||||
from psutil.tests import TESTFN_UNICODE
|
||||
from psutil.tests import TRAVIS
|
||||
from psutil.tests import unittest
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- System-related API tests
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestProcessAPIs(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
safe_rmpath(TESTFN)
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
def test_process_iter(self):
|
||||
self.assertIn(os.getpid(), [x.pid for x in psutil.process_iter()])
|
||||
sproc = get_test_subprocess()
|
||||
self.assertIn(sproc.pid, [x.pid for x in psutil.process_iter()])
|
||||
p = psutil.Process(sproc.pid)
|
||||
p.kill()
|
||||
p.wait()
|
||||
self.assertNotIn(sproc.pid, [x.pid for x in psutil.process_iter()])
|
||||
|
||||
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_prcess_iter_w_attrs(self):
|
||||
for p in psutil.process_iter(attrs=['pid']):
|
||||
self.assertEqual(list(p.info.keys()), ['pid'])
|
||||
with self.assertRaises(ValueError):
|
||||
list(psutil.process_iter(attrs=['foo']))
|
||||
with mock.patch("psutil._psplatform.Process.cpu_times",
|
||||
side_effect=psutil.AccessDenied(0, "")) as m:
|
||||
for p in psutil.process_iter(attrs=["pid", "cpu_times"]):
|
||||
self.assertIsNone(p.info['cpu_times'])
|
||||
self.assertGreaterEqual(p.info['pid'], 0)
|
||||
assert m.called
|
||||
with mock.patch("psutil._psplatform.Process.cpu_times",
|
||||
side_effect=psutil.AccessDenied(0, "")) as m:
|
||||
flag = object()
|
||||
for p in psutil.process_iter(
|
||||
attrs=["pid", "cpu_times"], ad_value=flag):
|
||||
self.assertIs(p.info['cpu_times'], flag)
|
||||
self.assertGreaterEqual(p.info['pid'], 0)
|
||||
assert m.called
|
||||
|
||||
@unittest.skipIf(PYPY and WINDOWS,
|
||||
"get_test_subprocess() unreliable on PYPY + WINDOWS")
|
||||
def test_wait_procs(self):
|
||||
def callback(p):
|
||||
pids.append(p.pid)
|
||||
|
||||
pids = []
|
||||
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)
|
||||
|
||||
self.assertLess(time.time() - t, 0.5)
|
||||
self.assertEqual(gone, [])
|
||||
self.assertEqual(len(alive), 3)
|
||||
self.assertEqual(pids, [])
|
||||
for p in alive:
|
||||
self.assertFalse(hasattr(p, 'returncode'))
|
||||
|
||||
@retry_on_failure(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 = test(procs, callback)
|
||||
self.assertIn(sproc3.pid, [x.pid for x in gone])
|
||||
if POSIX:
|
||||
self.assertEqual(gone.pop().returncode, -signal.SIGTERM)
|
||||
else:
|
||||
self.assertEqual(gone.pop().returncode, 1)
|
||||
self.assertEqual(pids, [sproc3.pid])
|
||||
for p in alive:
|
||||
self.assertFalse(hasattr(p, 'returncode'))
|
||||
|
||||
@retry_on_failure(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 = test(procs, callback)
|
||||
self.assertEqual(set(pids), set([sproc1.pid, sproc2.pid, sproc3.pid]))
|
||||
for p in gone:
|
||||
self.assertTrue(hasattr(p, 'returncode'))
|
||||
|
||||
@unittest.skipIf(PYPY and WINDOWS,
|
||||
"get_test_subprocess() unreliable on PYPY + WINDOWS")
|
||||
def test_wait_procs_no_timeout(self):
|
||||
sproc1 = get_test_subprocess()
|
||||
sproc2 = get_test_subprocess()
|
||||
sproc3 = get_test_subprocess()
|
||||
procs = [psutil.Process(x.pid) for x in (sproc1, sproc2, sproc3)]
|
||||
for p in procs:
|
||||
p.terminate()
|
||||
gone, alive = psutil.wait_procs(procs)
|
||||
|
||||
def test_pid_exists(self):
|
||||
sproc = get_test_subprocess()
|
||||
self.assertTrue(psutil.pid_exists(sproc.pid))
|
||||
p = psutil.Process(sproc.pid)
|
||||
p.kill()
|
||||
p.wait()
|
||||
self.assertFalse(psutil.pid_exists(sproc.pid))
|
||||
self.assertFalse(psutil.pid_exists(-1))
|
||||
self.assertEqual(psutil.pid_exists(0), 0 in psutil.pids())
|
||||
|
||||
def test_pid_exists_2(self):
|
||||
reap_children()
|
||||
pids = psutil.pids()
|
||||
for pid in pids:
|
||||
try:
|
||||
assert psutil.pid_exists(pid)
|
||||
except AssertionError:
|
||||
# in case the process disappeared in meantime fail only
|
||||
# if it is no longer in psutil.pids()
|
||||
time.sleep(.1)
|
||||
if pid in psutil.pids():
|
||||
self.fail(pid)
|
||||
pids = range(max(pids) + 5000, max(pids) + 6000)
|
||||
for pid in pids:
|
||||
self.assertFalse(psutil.pid_exists(pid), msg=pid)
|
||||
|
||||
def test_pids(self):
|
||||
pidslist = psutil.pids()
|
||||
procslist = [x.pid for x in psutil.process_iter()]
|
||||
# make sure every pid is unique
|
||||
self.assertEqual(sorted(set(pidslist)), pidslist)
|
||||
self.assertEqual(pidslist, procslist)
|
||||
|
||||
|
||||
class TestMiscAPIs(unittest.TestCase):
|
||||
|
||||
def test_boot_time(self):
|
||||
bt = psutil.boot_time()
|
||||
self.assertIsInstance(bt, float)
|
||||
self.assertGreater(bt, 0)
|
||||
self.assertLess(bt, time.time())
|
||||
|
||||
@unittest.skipIf(CI_TESTING and not psutil.users(), "unreliable on CI")
|
||||
def test_users(self):
|
||||
users = psutil.users()
|
||||
self.assertNotEqual(users, [])
|
||||
for user in users:
|
||||
assert user.name, user
|
||||
self.assertIsInstance(user.name, str)
|
||||
self.assertIsInstance(user.terminal, (str, type(None)))
|
||||
if user.host is not None:
|
||||
self.assertIsInstance(user.host, (str, type(None)))
|
||||
user.terminal
|
||||
user.host
|
||||
assert user.started > 0.0, user
|
||||
datetime.datetime.fromtimestamp(user.started)
|
||||
if WINDOWS or OPENBSD:
|
||||
self.assertIsNone(user.pid)
|
||||
else:
|
||||
psutil.Process(user.pid)
|
||||
|
||||
@unittest.skipIf(not POSIX, 'POSIX only')
|
||||
def test_PAGESIZE(self):
|
||||
# pagesize is used internally to perform different calculations
|
||||
# and it's determined by using SC_PAGE_SIZE; make sure
|
||||
# getpagesize() returns the same value.
|
||||
import resource
|
||||
self.assertEqual(os.sysconf("SC_PAGE_SIZE"), resource.getpagesize())
|
||||
|
||||
def test_test(self):
|
||||
# test for psutil.test() function
|
||||
stdout = sys.stdout
|
||||
sys.stdout = DEVNULL
|
||||
try:
|
||||
psutil.test()
|
||||
finally:
|
||||
sys.stdout = stdout
|
||||
|
||||
def test_os_constants(self):
|
||||
names = ["POSIX", "WINDOWS", "LINUX", "MACOS", "FREEBSD", "OPENBSD",
|
||||
"NETBSD", "BSD", "SUNOS"]
|
||||
for name in names:
|
||||
self.assertIsInstance(getattr(psutil, name), bool, msg=name)
|
||||
|
||||
if os.name == 'posix':
|
||||
assert psutil.POSIX
|
||||
assert not psutil.WINDOWS
|
||||
names.remove("POSIX")
|
||||
if "linux" in sys.platform.lower():
|
||||
assert psutil.LINUX
|
||||
names.remove("LINUX")
|
||||
elif "bsd" in sys.platform.lower():
|
||||
assert psutil.BSD
|
||||
self.assertEqual([psutil.FREEBSD, psutil.OPENBSD,
|
||||
psutil.NETBSD].count(True), 1)
|
||||
names.remove("BSD")
|
||||
names.remove("FREEBSD")
|
||||
names.remove("OPENBSD")
|
||||
names.remove("NETBSD")
|
||||
elif "sunos" in sys.platform.lower() or \
|
||||
"solaris" in sys.platform.lower():
|
||||
assert psutil.SUNOS
|
||||
names.remove("SUNOS")
|
||||
elif "darwin" in sys.platform.lower():
|
||||
assert psutil.MACOS
|
||||
names.remove("MACOS")
|
||||
else:
|
||||
assert psutil.WINDOWS
|
||||
assert not psutil.POSIX
|
||||
names.remove("WINDOWS")
|
||||
|
||||
# assert all other constants are set to False
|
||||
for name in names:
|
||||
self.assertIs(getattr(psutil, name), False, msg=name)
|
||||
|
||||
|
||||
class TestMemoryAPIs(unittest.TestCase):
|
||||
|
||||
def test_virtual_memory(self):
|
||||
mem = psutil.virtual_memory()
|
||||
assert mem.total > 0, mem
|
||||
assert mem.available > 0, mem
|
||||
assert 0 <= mem.percent <= 100, mem
|
||||
assert mem.used > 0, mem
|
||||
assert mem.free >= 0, mem
|
||||
for name in mem._fields:
|
||||
value = getattr(mem, name)
|
||||
if name != 'percent':
|
||||
self.assertIsInstance(value, (int, long))
|
||||
if name != 'total':
|
||||
if not value >= 0:
|
||||
self.fail("%r < 0 (%s)" % (name, value))
|
||||
if value > mem.total:
|
||||
self.fail("%r > total (total=%s, %s=%s)"
|
||||
% (name, mem.total, name, value))
|
||||
|
||||
def test_swap_memory(self):
|
||||
mem = psutil.swap_memory()
|
||||
self.assertEqual(
|
||||
mem._fields, ('total', 'used', 'free', 'percent', 'sin', 'sout'))
|
||||
|
||||
assert mem.total >= 0, mem
|
||||
assert mem.used >= 0, mem
|
||||
if mem.total > 0:
|
||||
# likely a system with no swap partition
|
||||
assert mem.free > 0, mem
|
||||
else:
|
||||
assert mem.free == 0, mem
|
||||
assert 0 <= mem.percent <= 100, mem
|
||||
assert mem.sin >= 0, mem
|
||||
assert mem.sout >= 0, mem
|
||||
|
||||
|
||||
class TestCpuAPIs(unittest.TestCase):
|
||||
|
||||
def test_cpu_count_logical(self):
|
||||
logical = psutil.cpu_count()
|
||||
self.assertIsNotNone(logical)
|
||||
self.assertEqual(logical, len(psutil.cpu_times(percpu=True)))
|
||||
self.assertGreaterEqual(logical, 1)
|
||||
#
|
||||
if os.path.exists("/proc/cpuinfo"):
|
||||
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")
|
||||
|
||||
def test_cpu_count_physical(self):
|
||||
logical = psutil.cpu_count()
|
||||
physical = psutil.cpu_count(logical=False)
|
||||
if physical is None:
|
||||
raise self.skipTest("physical cpu_count() is None")
|
||||
if WINDOWS and sys.getwindowsversion()[:2] <= (6, 1): # <= Vista
|
||||
self.assertIsNone(physical)
|
||||
else:
|
||||
self.assertGreaterEqual(physical, 1)
|
||||
self.assertGreaterEqual(logical, physical)
|
||||
|
||||
def test_cpu_count_none(self):
|
||||
# https://github.com/giampaolo/psutil/issues/1085
|
||||
for val in (-1, 0, None):
|
||||
with mock.patch('psutil._psplatform.cpu_count_logical',
|
||||
return_value=val) as m:
|
||||
self.assertIsNone(psutil.cpu_count())
|
||||
assert m.called
|
||||
with mock.patch('psutil._psplatform.cpu_count_physical',
|
||||
return_value=val) as m:
|
||||
self.assertIsNone(psutil.cpu_count(logical=False))
|
||||
assert m.called
|
||||
|
||||
def test_cpu_times(self):
|
||||
# Check type, value >= 0, str().
|
||||
total = 0
|
||||
times = psutil.cpu_times()
|
||||
sum(times)
|
||||
for cp_time in times:
|
||||
self.assertIsInstance(cp_time, float)
|
||||
self.assertGreaterEqual(cp_time, 0.0)
|
||||
total += cp_time
|
||||
self.assertEqual(total, sum(times))
|
||||
str(times)
|
||||
# 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_cpu_times_time_increases(self):
|
||||
# Make sure time increases between calls.
|
||||
t1 = sum(psutil.cpu_times())
|
||||
stop_at = time.time() + 1
|
||||
while time.time() < stop_at:
|
||||
t2 = sum(psutil.cpu_times())
|
||||
if t2 > t1:
|
||||
return
|
||||
self.fail("time remained the same")
|
||||
|
||||
def test_per_cpu_times(self):
|
||||
# Check type, value >= 0, str().
|
||||
for times in psutil.cpu_times(percpu=True):
|
||||
total = 0
|
||||
sum(times)
|
||||
for cp_time in times:
|
||||
self.assertIsInstance(cp_time, float)
|
||||
self.assertGreaterEqual(cp_time, 0.0)
|
||||
total += cp_time
|
||||
self.assertEqual(total, sum(times))
|
||||
str(times)
|
||||
self.assertEqual(len(psutil.cpu_times(percpu=True)[0]),
|
||||
len(psutil.cpu_times(percpu=False)))
|
||||
|
||||
# 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_per_cpu_times_2(self):
|
||||
# Simulate some work load then make sure time have increased
|
||||
# between calls.
|
||||
tot1 = psutil.cpu_times(percpu=True)
|
||||
giveup_at = time.time() + 1
|
||||
while True:
|
||||
if time.time() >= giveup_at:
|
||||
return self.fail("timeout")
|
||||
tot2 = psutil.cpu_times(percpu=True)
|
||||
for t1, t2 in zip(tot1, tot2):
|
||||
t1, t2 = psutil._cpu_busy_time(t1), psutil._cpu_busy_time(t2)
|
||||
difference = t2 - t1
|
||||
if difference >= 0.05:
|
||||
return
|
||||
|
||||
def test_cpu_times_comparison(self):
|
||||
# Make sure the sum of all per cpu times is almost equal to
|
||||
# base "one cpu" times.
|
||||
base = psutil.cpu_times()
|
||||
per_cpu = psutil.cpu_times(percpu=True)
|
||||
summed_values = base._make([sum(num) for num in zip(*per_cpu)])
|
||||
for field in base._fields:
|
||||
self.assertAlmostEqual(
|
||||
getattr(base, field), getattr(summed_values, field), delta=1)
|
||||
|
||||
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_cpu_percent(self):
|
||||
last = psutil.cpu_percent(interval=0.001)
|
||||
for x in range(100):
|
||||
new = psutil.cpu_percent(interval=None)
|
||||
self._test_cpu_percent(new, last, new)
|
||||
last = new
|
||||
with self.assertRaises(ValueError):
|
||||
psutil.cpu_percent(interval=-1)
|
||||
|
||||
def test_per_cpu_percent(self):
|
||||
last = psutil.cpu_percent(interval=0.001, percpu=True)
|
||||
self.assertEqual(len(last), psutil.cpu_count())
|
||||
for x in range(100):
|
||||
new = psutil.cpu_percent(interval=None, percpu=True)
|
||||
for percent in new:
|
||||
self._test_cpu_percent(percent, last, new)
|
||||
last = new
|
||||
with self.assertRaises(ValueError):
|
||||
psutil.cpu_percent(interval=-1, percpu=True)
|
||||
|
||||
def test_cpu_times_percent(self):
|
||||
last = psutil.cpu_times_percent(interval=0.001)
|
||||
for x in range(100):
|
||||
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_per_cpu_times_percent(self):
|
||||
last = psutil.cpu_times_percent(interval=0.001, percpu=True)
|
||||
self.assertEqual(len(last), psutil.cpu_count())
|
||||
for x in range(100):
|
||||
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_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, None, None)
|
||||
|
||||
def test_cpu_stats(self):
|
||||
# Tested more extensively in per-platform test modules.
|
||||
infos = psutil.cpu_stats()
|
||||
self.assertEqual(
|
||||
infos._fields,
|
||||
('ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'))
|
||||
for name in infos._fields:
|
||||
value = getattr(infos, name)
|
||||
self.assertGreaterEqual(value, 0)
|
||||
# on AIX, ctx_switches is always 0
|
||||
if not AIX and name in ('ctx_switches', 'interrupts'):
|
||||
self.assertGreater(value, 0)
|
||||
|
||||
@unittest.skipIf(not HAS_CPU_FREQ, "not suported")
|
||||
def test_cpu_freq(self):
|
||||
def check_ls(ls):
|
||||
for nt in ls:
|
||||
self.assertEqual(nt._fields, ('current', 'min', 'max'))
|
||||
if nt.max != 0.0:
|
||||
self.assertLessEqual(nt.current, nt.max)
|
||||
for name in nt._fields:
|
||||
value = getattr(nt, name)
|
||||
self.assertIsInstance(value, (int, long, float))
|
||||
self.assertGreaterEqual(value, 0)
|
||||
|
||||
ls = psutil.cpu_freq(percpu=True)
|
||||
if TRAVIS and not ls:
|
||||
raise self.skipTest("skipped on Travis")
|
||||
if FREEBSD and not ls:
|
||||
raise self.skipTest("returns empty list on FreeBSD")
|
||||
|
||||
assert ls, ls
|
||||
check_ls([psutil.cpu_freq(percpu=False)])
|
||||
|
||||
if LINUX:
|
||||
self.assertEqual(len(ls), psutil.cpu_count())
|
||||
|
||||
@unittest.skipIf(not HAS_GETLOADAVG, "not supported")
|
||||
def test_getloadavg(self):
|
||||
loadavg = psutil.getloadavg()
|
||||
assert len(loadavg) == 3
|
||||
|
||||
for load in loadavg:
|
||||
self.assertIsInstance(load, float)
|
||||
self.assertGreaterEqual(load, 0.0)
|
||||
|
||||
|
||||
class TestDiskAPIs(unittest.TestCase):
|
||||
|
||||
def test_disk_usage(self):
|
||||
usage = psutil.disk_usage(os.getcwd())
|
||||
self.assertEqual(usage._fields, ('total', 'used', 'free', 'percent'))
|
||||
|
||||
assert usage.total > 0, usage
|
||||
assert usage.used > 0, usage
|
||||
assert usage.free > 0, usage
|
||||
assert usage.total > usage.used, usage
|
||||
assert usage.total > usage.free, usage
|
||||
assert 0 <= usage.percent <= 100, usage.percent
|
||||
if hasattr(shutil, 'disk_usage'):
|
||||
# py >= 3.3, see: http://bugs.python.org/issue12442
|
||||
shutil_usage = shutil.disk_usage(os.getcwd())
|
||||
tolerance = 5 * 1024 * 1024 # 5MB
|
||||
self.assertEqual(usage.total, shutil_usage.total)
|
||||
self.assertAlmostEqual(usage.free, shutil_usage.free,
|
||||
delta=tolerance)
|
||||
self.assertAlmostEqual(usage.used, shutil_usage.used,
|
||||
delta=tolerance)
|
||||
|
||||
# if path does not exist OSError ENOENT is expected across
|
||||
# all platforms
|
||||
fname = tempfile.mktemp()
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
psutil.disk_usage(fname)
|
||||
|
||||
def test_disk_usage_unicode(self):
|
||||
# See: https://github.com/giampaolo/psutil/issues/416
|
||||
if ASCII_FS:
|
||||
with self.assertRaises(UnicodeEncodeError):
|
||||
psutil.disk_usage(TESTFN_UNICODE)
|
||||
|
||||
def test_disk_usage_bytes(self):
|
||||
psutil.disk_usage(b'.')
|
||||
|
||||
def test_disk_partitions(self):
|
||||
# all = False
|
||||
ls = psutil.disk_partitions(all=False)
|
||||
# on travis we get:
|
||||
# self.assertEqual(p.cpu_affinity(), [n])
|
||||
# AssertionError: Lists differ: [0, 1, 2, 3, 4, 5, 6, 7,... != [0]
|
||||
self.assertTrue(ls, msg=ls)
|
||||
for disk in ls:
|
||||
self.assertIsInstance(disk.device, str)
|
||||
self.assertIsInstance(disk.mountpoint, str)
|
||||
self.assertIsInstance(disk.fstype, str)
|
||||
self.assertIsInstance(disk.opts, str)
|
||||
if WINDOWS and 'cdrom' in disk.opts:
|
||||
continue
|
||||
if not POSIX:
|
||||
assert os.path.exists(disk.device), disk
|
||||
else:
|
||||
# we cannot make any assumption about this, see:
|
||||
# http://goo.gl/p9c43
|
||||
disk.device
|
||||
# on modern systems mount points can also be files
|
||||
assert os.path.exists(disk.mountpoint), disk
|
||||
assert disk.fstype, disk
|
||||
|
||||
# all = True
|
||||
ls = psutil.disk_partitions(all=True)
|
||||
self.assertTrue(ls, msg=ls)
|
||||
for disk in psutil.disk_partitions(all=True):
|
||||
if not WINDOWS and disk.mountpoint:
|
||||
try:
|
||||
os.stat(disk.mountpoint)
|
||||
except OSError as err:
|
||||
if TRAVIS and MACOS 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):
|
||||
raise
|
||||
else:
|
||||
assert os.path.exists(disk.mountpoint), disk
|
||||
self.assertIsInstance(disk.fstype, str)
|
||||
self.assertIsInstance(disk.opts, str)
|
||||
|
||||
def find_mount_point(path):
|
||||
path = os.path.abspath(path)
|
||||
while not os.path.ismount(path):
|
||||
path = os.path.dirname(path)
|
||||
return path.lower()
|
||||
|
||||
mount = find_mount_point(__file__)
|
||||
mounts = [x.mountpoint.lower() for x in
|
||||
psutil.disk_partitions(all=True) if x.mountpoint]
|
||||
self.assertIn(mount, mounts)
|
||||
psutil.disk_usage(mount)
|
||||
|
||||
@unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'),
|
||||
'/proc/diskstats not available on this linux version')
|
||||
@unittest.skipIf(CI_TESTING and not psutil.disk_io_counters(),
|
||||
"unreliable on CI") # no visible disks
|
||||
def test_disk_io_counters(self):
|
||||
def check_ntuple(nt):
|
||||
self.assertEqual(nt[0], nt.read_count)
|
||||
self.assertEqual(nt[1], nt.write_count)
|
||||
self.assertEqual(nt[2], nt.read_bytes)
|
||||
self.assertEqual(nt[3], nt.write_bytes)
|
||||
if not (OPENBSD or NETBSD):
|
||||
self.assertEqual(nt[4], nt.read_time)
|
||||
self.assertEqual(nt[5], nt.write_time)
|
||||
if LINUX:
|
||||
self.assertEqual(nt[6], nt.read_merged_count)
|
||||
self.assertEqual(nt[7], nt.write_merged_count)
|
||||
self.assertEqual(nt[8], nt.busy_time)
|
||||
elif FREEBSD:
|
||||
self.assertEqual(nt[6], nt.busy_time)
|
||||
for name in nt._fields:
|
||||
assert getattr(nt, name) >= 0, nt
|
||||
|
||||
ret = psutil.disk_io_counters(perdisk=False)
|
||||
assert ret is not None, "no disks on this system?"
|
||||
check_ntuple(ret)
|
||||
ret = psutil.disk_io_counters(perdisk=True)
|
||||
# make sure there are no duplicates
|
||||
self.assertEqual(len(ret), len(set(ret)))
|
||||
for key in ret:
|
||||
assert key, key
|
||||
check_ntuple(ret[key])
|
||||
|
||||
def test_disk_io_counters_no_disks(self):
|
||||
# Emulate a case where no disks are installed, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1062
|
||||
with mock.patch('psutil._psplatform.disk_io_counters',
|
||||
return_value={}) as m:
|
||||
self.assertIsNone(psutil.disk_io_counters(perdisk=False))
|
||||
self.assertEqual(psutil.disk_io_counters(perdisk=True), {})
|
||||
assert m.called
|
||||
|
||||
|
||||
class TestNetAPIs(unittest.TestCase):
|
||||
|
||||
@unittest.skipIf(not HAS_NET_IO_COUNTERS, 'not supported')
|
||||
def test_net_io_counters(self):
|
||||
def check_ntuple(nt):
|
||||
self.assertEqual(nt[0], nt.bytes_sent)
|
||||
self.assertEqual(nt[1], nt.bytes_recv)
|
||||
self.assertEqual(nt[2], nt.packets_sent)
|
||||
self.assertEqual(nt[3], nt.packets_recv)
|
||||
self.assertEqual(nt[4], nt.errin)
|
||||
self.assertEqual(nt[5], nt.errout)
|
||||
self.assertEqual(nt[6], nt.dropin)
|
||||
self.assertEqual(nt[7], nt.dropout)
|
||||
assert nt.bytes_sent >= 0, nt
|
||||
assert nt.bytes_recv >= 0, nt
|
||||
assert nt.packets_sent >= 0, nt
|
||||
assert nt.packets_recv >= 0, nt
|
||||
assert nt.errin >= 0, nt
|
||||
assert nt.errout >= 0, nt
|
||||
assert nt.dropin >= 0, nt
|
||||
assert nt.dropout >= 0, nt
|
||||
|
||||
ret = psutil.net_io_counters(pernic=False)
|
||||
check_ntuple(ret)
|
||||
ret = psutil.net_io_counters(pernic=True)
|
||||
self.assertNotEqual(ret, [])
|
||||
for key in ret:
|
||||
self.assertTrue(key)
|
||||
self.assertIsInstance(key, str)
|
||||
check_ntuple(ret[key])
|
||||
|
||||
@unittest.skipIf(not HAS_NET_IO_COUNTERS, 'not supported')
|
||||
def test_net_io_counters_no_nics(self):
|
||||
# Emulate a case where no NICs are installed, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1062
|
||||
with mock.patch('psutil._psplatform.net_io_counters',
|
||||
return_value={}) as m:
|
||||
self.assertIsNone(psutil.net_io_counters(pernic=False))
|
||||
self.assertEqual(psutil.net_io_counters(pernic=True), {})
|
||||
assert m.called
|
||||
|
||||
def test_net_if_addrs(self):
|
||||
nics = psutil.net_if_addrs()
|
||||
assert nics, nics
|
||||
|
||||
nic_stats = psutil.net_if_stats()
|
||||
|
||||
# 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, socket.AF_INET6, psutil.AF_LINK])
|
||||
for nic, addrs in nics.items():
|
||||
self.assertIsInstance(nic, str)
|
||||
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 nic_stats[nic].isup:
|
||||
# Do not test binding to addresses of interfaces
|
||||
# that are down
|
||||
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 != socket.AF_INET6:
|
||||
check_net_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 MACOS 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)
|
||||
|
||||
def test_net_if_addrs_mac_null_bytes(self):
|
||||
# Simulate that the underlying C function returns an incomplete
|
||||
# MAC address. psutil is supposed to fill it with null bytes.
|
||||
# https://github.com/giampaolo/psutil/issues/786
|
||||
if POSIX:
|
||||
ret = [('em1', psutil.AF_LINK, '06:3d:29', None, None, None)]
|
||||
else:
|
||||
ret = [('em1', -1, '06-3d-29', None, None, None)]
|
||||
with mock.patch('psutil._psplatform.net_if_addrs',
|
||||
return_value=ret) as m:
|
||||
addr = psutil.net_if_addrs()['em1'][0]
|
||||
assert m.called
|
||||
if POSIX:
|
||||
self.assertEqual(addr.address, '06:3d:29:00:00:00')
|
||||
else:
|
||||
self.assertEqual(addr.address, '06-3d-29-00-00-00')
|
||||
|
||||
@unittest.skipIf(TRAVIS, "unreliable on TRAVIS") # raises EPERM
|
||||
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 name, stats in nics.items():
|
||||
self.assertIsInstance(name, str)
|
||||
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(not (LINUX or BSD or MACOS),
|
||||
"LINUX or BSD or MACOS specific")
|
||||
def test_net_if_stats_enodev(self):
|
||||
# See: https://github.com/giampaolo/psutil/issues/1279
|
||||
with mock.patch('psutil._psutil_posix.net_if_mtu',
|
||||
side_effect=OSError(errno.ENODEV, "")) as m:
|
||||
ret = psutil.net_if_stats()
|
||||
self.assertEqual(ret, {})
|
||||
assert m.called
|
||||
|
||||
|
||||
class TestSensorsAPIs(unittest.TestCase):
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_TEMPERATURES, "not supported")
|
||||
def test_sensors_temperatures(self):
|
||||
temps = psutil.sensors_temperatures()
|
||||
for name, entries in temps.items():
|
||||
self.assertIsInstance(name, str)
|
||||
for entry in entries:
|
||||
self.assertIsInstance(entry.label, str)
|
||||
if entry.current is not None:
|
||||
self.assertGreaterEqual(entry.current, 0)
|
||||
if entry.high is not None:
|
||||
self.assertGreaterEqual(entry.high, 0)
|
||||
if entry.critical is not None:
|
||||
self.assertGreaterEqual(entry.critical, 0)
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_TEMPERATURES, "not supported")
|
||||
def test_sensors_temperatures_fahreneit(self):
|
||||
d = {'coretemp': [('label', 50.0, 60.0, 70.0)]}
|
||||
with mock.patch("psutil._psplatform.sensors_temperatures",
|
||||
return_value=d) as m:
|
||||
temps = psutil.sensors_temperatures(
|
||||
fahrenheit=True)['coretemp'][0]
|
||||
assert m.called
|
||||
self.assertEqual(temps.current, 122.0)
|
||||
self.assertEqual(temps.high, 140.0)
|
||||
self.assertEqual(temps.critical, 158.0)
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_BATTERY, "not supported")
|
||||
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||
def test_sensors_battery(self):
|
||||
ret = psutil.sensors_battery()
|
||||
self.assertGreaterEqual(ret.percent, 0)
|
||||
self.assertLessEqual(ret.percent, 100)
|
||||
if ret.secsleft not in (psutil.POWER_TIME_UNKNOWN,
|
||||
psutil.POWER_TIME_UNLIMITED):
|
||||
self.assertGreaterEqual(ret.secsleft, 0)
|
||||
else:
|
||||
if ret.secsleft == psutil.POWER_TIME_UNLIMITED:
|
||||
self.assertTrue(ret.power_plugged)
|
||||
self.assertIsInstance(ret.power_plugged, bool)
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_FANS, "not supported")
|
||||
def test_sensors_fans(self):
|
||||
fans = psutil.sensors_fans()
|
||||
for name, entries in fans.items():
|
||||
self.assertIsInstance(name, str)
|
||||
for entry in entries:
|
||||
self.assertIsInstance(entry.label, str)
|
||||
self.assertIsInstance(entry.current, (int, long))
|
||||
self.assertGreaterEqual(entry.current, 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
372
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_unicode.py
vendored
Normal file
372
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_unicode.py
vendored
Normal file
|
|
@ -0,0 +1,372 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- 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
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""
|
||||
Notes about unicode handling in psutil
|
||||
======================================
|
||||
|
||||
Starting from version 5.3.0 psutil adds unicode support, see:
|
||||
https://github.com/giampaolo/psutil/issues/1040
|
||||
The notes below apply to *any* API returning a string such as
|
||||
process exe(), cwd() or username():
|
||||
|
||||
* all strings are encoded by using the OS filesystem encoding
|
||||
(sys.getfilesystemencoding()) which varies depending on the platform
|
||||
(e.g. "UTF-8" on macOS, "mbcs" on Win)
|
||||
* no API call is supposed to crash with UnicodeDecodeError
|
||||
* instead, in case of badly encoded data returned by the OS, the
|
||||
following error handlers are used to replace the corrupted characters in
|
||||
the string:
|
||||
* Python 3: sys.getfilesystemencodeerrors() (PY 3.6+) or
|
||||
"surrogatescape" on POSIX and "replace" on Windows
|
||||
* Python 2: "replace"
|
||||
* on Python 2 all APIs return bytes (str type), never unicode
|
||||
* on Python 2, you can go back to unicode by doing:
|
||||
|
||||
>>> unicode(p.exe(), sys.getdefaultencoding(), errors="replace")
|
||||
|
||||
For a detailed explanation of how psutil handles unicode see #1040.
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
List of APIs returning or dealing with a string:
|
||||
('not tested' means they are not tested to deal with non-ASCII strings):
|
||||
|
||||
* Process.cmdline()
|
||||
* Process.connections('unix')
|
||||
* Process.cwd()
|
||||
* Process.environ()
|
||||
* Process.exe()
|
||||
* Process.memory_maps()
|
||||
* Process.name()
|
||||
* Process.open_files()
|
||||
* Process.username() (not tested)
|
||||
|
||||
* disk_io_counters() (not tested)
|
||||
* disk_partitions() (not tested)
|
||||
* disk_usage(str)
|
||||
* net_connections('unix')
|
||||
* net_if_addrs() (not tested)
|
||||
* net_if_stats() (not tested)
|
||||
* net_io_counters() (not tested)
|
||||
* sensors_fans() (not tested)
|
||||
* sensors_temperatures() (not tested)
|
||||
* users() (not tested)
|
||||
|
||||
* WindowsService.binpath() (not tested)
|
||||
* WindowsService.description() (not tested)
|
||||
* WindowsService.display_name() (not tested)
|
||||
* WindowsService.name() (not tested)
|
||||
* WindowsService.status() (not tested)
|
||||
* WindowsService.username() (not tested)
|
||||
|
||||
In here we create a unicode path with a funky non-ASCII name and (where
|
||||
possible) make psutil return it back (e.g. on name(), exe(), open_files(),
|
||||
etc.) and make sure that:
|
||||
|
||||
* psutil never crashes with UnicodeDecodeError
|
||||
* the returned path matches
|
||||
"""
|
||||
|
||||
import os
|
||||
import traceback
|
||||
import warnings
|
||||
from contextlib import closing
|
||||
|
||||
from psutil import BSD
|
||||
from psutil import MACOS
|
||||
from psutil import OPENBSD
|
||||
from psutil import POSIX
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import PY3
|
||||
from psutil._compat import u
|
||||
from psutil.tests import APPVEYOR
|
||||
from psutil.tests import CIRRUS
|
||||
from psutil.tests import ASCII_FS
|
||||
from psutil.tests import bind_unix_socket
|
||||
from psutil.tests import chdir
|
||||
from psutil.tests import copyload_shared_lib
|
||||
from psutil.tests import create_exe
|
||||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import HAS_CONNECTIONS_UNIX
|
||||
from psutil.tests import HAS_ENVIRON
|
||||
from psutil.tests import HAS_MEMORY_MAPS
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import safe_mkdir
|
||||
from psutil.tests import safe_rmpath as _safe_rmpath
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import TESTFILE_PREFIX
|
||||
from psutil.tests import TESTFN
|
||||
from psutil.tests import TESTFN_UNICODE
|
||||
from psutil.tests import TRAVIS
|
||||
from psutil.tests import unittest
|
||||
from psutil.tests import unix_socket_path
|
||||
import psutil
|
||||
|
||||
|
||||
def safe_rmpath(path):
|
||||
if APPVEYOR:
|
||||
# TODO - this is quite random and I'm not sure why it happens,
|
||||
# nor I can reproduce it locally:
|
||||
# https://ci.appveyor.com/project/giampaolo/psutil/build/job/
|
||||
# jiq2cgd6stsbtn60
|
||||
# safe_rmpath() happens after reap_children() so this is weird
|
||||
# Perhaps wait_procs() on Windows is broken? Maybe because
|
||||
# of STILL_ACTIVE?
|
||||
# https://github.com/giampaolo/psutil/blob/
|
||||
# 68c7a70728a31d8b8b58f4be6c4c0baa2f449eda/psutil/arch/
|
||||
# windows/process_info.c#L146
|
||||
try:
|
||||
return _safe_rmpath(path)
|
||||
except WindowsError:
|
||||
traceback.print_exc()
|
||||
else:
|
||||
return _safe_rmpath(path)
|
||||
|
||||
|
||||
def subprocess_supports_unicode(name):
|
||||
"""Return True if both the fs and the subprocess module can
|
||||
deal with a unicode file name.
|
||||
"""
|
||||
if PY3:
|
||||
return True
|
||||
try:
|
||||
safe_rmpath(name)
|
||||
create_exe(name)
|
||||
get_test_subprocess(cmd=[name])
|
||||
except UnicodeEncodeError:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
finally:
|
||||
reap_children()
|
||||
|
||||
|
||||
# An invalid unicode string.
|
||||
if PY3:
|
||||
INVALID_NAME = (TESTFN.encode('utf8') + b"f\xc0\x80").decode(
|
||||
'utf8', 'surrogateescape')
|
||||
else:
|
||||
INVALID_NAME = TESTFN + "f\xc0\x80"
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# FS APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class _BaseFSAPIsTests(object):
|
||||
funky_name = None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
safe_rmpath(cls.funky_name)
|
||||
create_exe(cls.funky_name)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
safe_rmpath(cls.funky_name)
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
def expect_exact_path_match(self):
|
||||
raise NotImplementedError("must be implemented in subclass")
|
||||
|
||||
def test_proc_exe(self):
|
||||
subp = get_test_subprocess(cmd=[self.funky_name])
|
||||
p = psutil.Process(subp.pid)
|
||||
exe = p.exe()
|
||||
self.assertIsInstance(exe, str)
|
||||
if self.expect_exact_path_match():
|
||||
self.assertEqual(os.path.normcase(exe),
|
||||
os.path.normcase(self.funky_name))
|
||||
|
||||
def test_proc_name(self):
|
||||
subp = get_test_subprocess(cmd=[self.funky_name])
|
||||
name = psutil.Process(subp.pid).name()
|
||||
self.assertIsInstance(name, str)
|
||||
if self.expect_exact_path_match():
|
||||
self.assertEqual(name, os.path.basename(self.funky_name))
|
||||
|
||||
def test_proc_cmdline(self):
|
||||
subp = get_test_subprocess(cmd=[self.funky_name])
|
||||
p = psutil.Process(subp.pid)
|
||||
cmdline = p.cmdline()
|
||||
for part in cmdline:
|
||||
self.assertIsInstance(part, str)
|
||||
if self.expect_exact_path_match():
|
||||
self.assertEqual(cmdline, [self.funky_name])
|
||||
|
||||
def test_proc_cwd(self):
|
||||
dname = self.funky_name + "2"
|
||||
self.addCleanup(safe_rmpath, dname)
|
||||
safe_mkdir(dname)
|
||||
with chdir(dname):
|
||||
p = psutil.Process()
|
||||
cwd = p.cwd()
|
||||
self.assertIsInstance(p.cwd(), str)
|
||||
if self.expect_exact_path_match():
|
||||
self.assertEqual(cwd, dname)
|
||||
|
||||
@unittest.skipIf(PYPY and WINDOWS, "fails on PYPY + WINDOWS")
|
||||
def test_proc_open_files(self):
|
||||
p = psutil.Process()
|
||||
start = set(p.open_files())
|
||||
with open(self.funky_name, 'rb'):
|
||||
new = set(p.open_files())
|
||||
path = (new - start).pop().path
|
||||
self.assertIsInstance(path, str)
|
||||
if BSD and not path:
|
||||
# XXX - see https://github.com/giampaolo/psutil/issues/595
|
||||
return self.skipTest("open_files on BSD is broken")
|
||||
if self.expect_exact_path_match():
|
||||
self.assertEqual(os.path.normcase(path),
|
||||
os.path.normcase(self.funky_name))
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
def test_proc_connections(self):
|
||||
suffix = os.path.basename(self.funky_name)
|
||||
with unix_socket_path(suffix=suffix) as name:
|
||||
try:
|
||||
sock = bind_unix_socket(name)
|
||||
except UnicodeEncodeError:
|
||||
if PY3:
|
||||
raise
|
||||
else:
|
||||
raise unittest.SkipTest("not supported")
|
||||
with closing(sock):
|
||||
conn = psutil.Process().connections('unix')[0]
|
||||
self.assertIsInstance(conn.laddr, str)
|
||||
# AF_UNIX addr not set on OpenBSD
|
||||
if not OPENBSD and not CIRRUS: # XXX
|
||||
self.assertEqual(conn.laddr, name)
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
@unittest.skipIf(not HAS_CONNECTIONS_UNIX, "can't list UNIX sockets")
|
||||
@skip_on_access_denied()
|
||||
def test_net_connections(self):
|
||||
def find_sock(cons):
|
||||
for conn in cons:
|
||||
if os.path.basename(conn.laddr).startswith(TESTFILE_PREFIX):
|
||||
return conn
|
||||
raise ValueError("connection not found")
|
||||
|
||||
suffix = os.path.basename(self.funky_name)
|
||||
with unix_socket_path(suffix=suffix) as name:
|
||||
try:
|
||||
sock = bind_unix_socket(name)
|
||||
except UnicodeEncodeError:
|
||||
if PY3:
|
||||
raise
|
||||
else:
|
||||
raise unittest.SkipTest("not supported")
|
||||
with closing(sock):
|
||||
cons = psutil.net_connections(kind='unix')
|
||||
# AF_UNIX addr not set on OpenBSD
|
||||
if not OPENBSD:
|
||||
conn = find_sock(cons)
|
||||
self.assertIsInstance(conn.laddr, str)
|
||||
self.assertEqual(conn.laddr, name)
|
||||
|
||||
def test_disk_usage(self):
|
||||
dname = self.funky_name + "2"
|
||||
self.addCleanup(safe_rmpath, dname)
|
||||
safe_mkdir(dname)
|
||||
psutil.disk_usage(dname)
|
||||
|
||||
@unittest.skipIf(not HAS_MEMORY_MAPS, "not supported")
|
||||
@unittest.skipIf(not PY3, "ctypes does not support unicode on PY2")
|
||||
@unittest.skipIf(PYPY and WINDOWS,
|
||||
"copyload_shared_lib() unsupported on PYPY + WINDOWS")
|
||||
def test_memory_maps(self):
|
||||
# XXX: on Python 2, using ctypes.CDLL with a unicode path
|
||||
# opens a message box which blocks the test run.
|
||||
with copyload_shared_lib(dst_prefix=self.funky_name) as funky_path:
|
||||
def normpath(p):
|
||||
return os.path.realpath(os.path.normcase(p))
|
||||
libpaths = [normpath(x.path)
|
||||
for x in psutil.Process().memory_maps()]
|
||||
# ...just to have a clearer msg in case of failure
|
||||
libpaths = [x for x in libpaths if TESTFILE_PREFIX in x]
|
||||
self.assertIn(normpath(funky_path), libpaths)
|
||||
for path in libpaths:
|
||||
self.assertIsInstance(path, str)
|
||||
|
||||
|
||||
# https://travis-ci.org/giampaolo/psutil/jobs/440073249
|
||||
@unittest.skipIf(PYPY and TRAVIS, "unreliable on PYPY + TRAVIS")
|
||||
@unittest.skipIf(MACOS and TRAVIS, "unreliable on TRAVIS") # TODO
|
||||
@unittest.skipIf(ASCII_FS, "ASCII fs")
|
||||
@unittest.skipIf(not subprocess_supports_unicode(TESTFN_UNICODE),
|
||||
"subprocess can't deal with unicode")
|
||||
class TestFSAPIs(_BaseFSAPIsTests, unittest.TestCase):
|
||||
"""Test FS APIs with a funky, valid, UTF8 path name."""
|
||||
funky_name = TESTFN_UNICODE
|
||||
|
||||
@classmethod
|
||||
def expect_exact_path_match(cls):
|
||||
# Do not expect psutil to correctly handle unicode paths on
|
||||
# Python 2 if os.listdir() is not able either.
|
||||
here = '.' if isinstance(cls.funky_name, str) else u('.')
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
return cls.funky_name in os.listdir(here)
|
||||
|
||||
|
||||
@unittest.skipIf(PYPY and TRAVIS, "unreliable on PYPY + TRAVIS")
|
||||
@unittest.skipIf(MACOS and TRAVIS, "unreliable on TRAVIS") # TODO
|
||||
@unittest.skipIf(PYPY, "unreliable on PYPY")
|
||||
@unittest.skipIf(not subprocess_supports_unicode(INVALID_NAME),
|
||||
"subprocess can't deal with invalid unicode")
|
||||
class TestFSAPIsWithInvalidPath(_BaseFSAPIsTests, unittest.TestCase):
|
||||
"""Test FS APIs with a funky, invalid path name."""
|
||||
funky_name = INVALID_NAME
|
||||
|
||||
@classmethod
|
||||
def expect_exact_path_match(cls):
|
||||
# Invalid unicode names are supposed to work on Python 2.
|
||||
return True
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Non fs APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestNonFSAPIS(unittest.TestCase):
|
||||
"""Unicode tests for non fs-related APIs."""
|
||||
|
||||
def tearDown(self):
|
||||
reap_children()
|
||||
|
||||
@unittest.skipIf(not HAS_ENVIRON, "not supported")
|
||||
@unittest.skipIf(PYPY and WINDOWS, "segfaults on PYPY + WINDOWS")
|
||||
def test_proc_environ(self):
|
||||
# Note: differently from others, this test does not deal
|
||||
# with fs paths. On Python 2 subprocess module is broken as
|
||||
# it's not able to handle with non-ASCII env vars, so
|
||||
# we use "è", which is part of the extended ASCII table
|
||||
# (unicode point <= 255).
|
||||
env = os.environ.copy()
|
||||
funky_str = TESTFN_UNICODE if PY3 else 'è'
|
||||
env['FUNNY_ARG'] = funky_str
|
||||
sproc = get_test_subprocess(env=env)
|
||||
p = psutil.Process(sproc.pid)
|
||||
env = p.environ()
|
||||
for k, v in env.items():
|
||||
self.assertIsInstance(k, str)
|
||||
self.assertIsInstance(v, str)
|
||||
self.assertEqual(env['FUNNY_ARG'], funky_str)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
870
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_windows.py
vendored
Normal file
870
third_party/python/psutil-cp27-none-win_amd64/psutil/tests/test_windows.py
vendored
Normal file
|
|
@ -0,0 +1,870 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- 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
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Windows specific tests."""
|
||||
|
||||
import datetime
|
||||
import errno
|
||||
import glob
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
|
||||
import psutil
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import FileNotFoundError
|
||||
from psutil.tests import APPVEYOR
|
||||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import mock
|
||||
from psutil.tests import PY3
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
|
||||
|
||||
if WINDOWS and not PYPY:
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
import win32api # requires "pip install pypiwin32"
|
||||
import win32con
|
||||
import win32process
|
||||
import wmi # requires "pip install wmi" / "make setup-dev-env"
|
||||
|
||||
|
||||
cext = psutil._psplatform.cext
|
||||
|
||||
# are we a 64 bit process
|
||||
IS_64_BIT = sys.maxsize > 2**32
|
||||
|
||||
|
||||
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:
|
||||
raise psutil.NoSuchProcess(None, None)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
@unittest.skipIf(PYPY, "pywin32 not available on PYPY") # skip whole module
|
||||
class TestCase(unittest.TestCase):
|
||||
pass
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# System APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestCpuAPIs(TestCase):
|
||||
|
||||
@unittest.skipIf('NUMBER_OF_PROCESSORS' not in os.environ,
|
||||
'NUMBER_OF_PROCESSORS env var is not available')
|
||||
def test_cpu_count_vs_NUMBER_OF_PROCESSORS(self):
|
||||
# Will likely fail on many-cores systems:
|
||||
# https://stackoverflow.com/questions/31209256
|
||||
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
|
||||
self.assertEqual(num_cpus, psutil.cpu_count())
|
||||
|
||||
def test_cpu_count_vs_GetSystemInfo(self):
|
||||
# Will likely fail on many-cores systems:
|
||||
# https://stackoverflow.com/questions/31209256
|
||||
sys_value = win32api.GetSystemInfo()[5]
|
||||
psutil_value = psutil.cpu_count()
|
||||
self.assertEqual(sys_value, psutil_value)
|
||||
|
||||
def test_cpu_count_logical_vs_wmi(self):
|
||||
w = wmi.WMI()
|
||||
proc = w.Win32_Processor()[0]
|
||||
self.assertEqual(psutil.cpu_count(), proc.NumberOfLogicalProcessors)
|
||||
|
||||
def test_cpu_count_phys_vs_wmi(self):
|
||||
w = wmi.WMI()
|
||||
proc = w.Win32_Processor()[0]
|
||||
self.assertEqual(psutil.cpu_count(logical=False), proc.NumberOfCores)
|
||||
|
||||
def test_cpu_count_vs_cpu_times(self):
|
||||
self.assertEqual(psutil.cpu_count(),
|
||||
len(psutil.cpu_times(percpu=True)))
|
||||
|
||||
def test_cpu_freq(self):
|
||||
w = wmi.WMI()
|
||||
proc = w.Win32_Processor()[0]
|
||||
self.assertEqual(proc.CurrentClockSpeed, psutil.cpu_freq().current)
|
||||
self.assertEqual(proc.MaxClockSpeed, psutil.cpu_freq().max)
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestSystemAPIs(TestCase):
|
||||
|
||||
def test_nic_names(self):
|
||||
out = sh('ipconfig /all')
|
||||
nics = psutil.net_io_counters(pernic=True).keys()
|
||||
for nic in nics:
|
||||
if "pseudo-interface" in nic.replace(' ', '-').lower():
|
||||
continue
|
||||
if nic not in out:
|
||||
self.fail(
|
||||
"%r nic wasn't found in 'ipconfig /all' output" % nic)
|
||||
|
||||
def test_total_phymem(self):
|
||||
w = wmi.WMI().Win32_ComputerSystem()[0]
|
||||
self.assertEqual(int(w.TotalPhysicalMemory),
|
||||
psutil.virtual_memory().total)
|
||||
|
||||
# @unittest.skipIf(wmi is None, "wmi module is not installed")
|
||||
# def test__UPTIME(self):
|
||||
# # _UPTIME constant is not public but it is used internally
|
||||
# # as value to return for pid 0 creation time.
|
||||
# # WMI behaves the same.
|
||||
# w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
# p = psutil.Process(0)
|
||||
# wmic_create = str(w.CreationDate.split('.')[0])
|
||||
# psutil_create = time.strftime("%Y%m%d%H%M%S",
|
||||
# time.localtime(p.create_time()))
|
||||
|
||||
# Note: this test is not very reliable
|
||||
@unittest.skipIf(APPVEYOR, "test not relieable on appveyor")
|
||||
@retry_on_failure()
|
||||
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 = set([x.ProcessId for x in w])
|
||||
psutil_pids = set(psutil.pids())
|
||||
self.assertEqual(wmi_pids, psutil_pids)
|
||||
|
||||
@retry_on_failure()
|
||||
def test_disks(self):
|
||||
ps_parts = psutil.disk_partitions(all=True)
|
||||
wmi_parts = wmi.WMI().Win32_LogicalDisk()
|
||||
for ps_part in ps_parts:
|
||||
for wmi_part in wmi_parts:
|
||||
if ps_part.device.replace('\\', '') == wmi_part.DeviceID:
|
||||
if not ps_part.mountpoint:
|
||||
# this is usually a CD-ROM with no disk inserted
|
||||
break
|
||||
if 'cdrom' in ps_part.opts:
|
||||
break
|
||||
try:
|
||||
usage = psutil.disk_usage(ps_part.mountpoint)
|
||||
except FileNotFoundError:
|
||||
# usually this is the floppy
|
||||
break
|
||||
self.assertEqual(usage.total, int(wmi_part.Size))
|
||||
wmi_free = int(wmi_part.FreeSpace)
|
||||
self.assertEqual(usage.free, wmi_free)
|
||||
# 10 MB tollerance
|
||||
if abs(usage.free - wmi_free) > 10 * 1024 * 1024:
|
||||
self.fail("psutil=%s, wmi=%s" % (
|
||||
usage.free, wmi_free))
|
||||
break
|
||||
else:
|
||||
self.fail("can't find partition %s" % repr(ps_part))
|
||||
|
||||
def test_disk_usage(self):
|
||||
for disk in psutil.disk_partitions():
|
||||
if 'cdrom' in disk.opts:
|
||||
continue
|
||||
sys_value = win32api.GetDiskFreeSpaceEx(disk.mountpoint)
|
||||
psutil_value = psutil.disk_usage(disk.mountpoint)
|
||||
self.assertAlmostEqual(sys_value[0], psutil_value.free,
|
||||
delta=1024 * 1024)
|
||||
self.assertAlmostEqual(sys_value[1], psutil_value.total,
|
||||
delta=1024 * 1024)
|
||||
self.assertEqual(psutil_value.used,
|
||||
psutil_value.total - psutil_value.free)
|
||||
|
||||
def test_disk_partitions(self):
|
||||
sys_value = [
|
||||
x + '\\' for x in win32api.GetLogicalDriveStrings().split("\\\x00")
|
||||
if x and not x.startswith('A:')]
|
||||
psutil_value = [x.mountpoint for x in psutil.disk_partitions(all=True)]
|
||||
self.assertEqual(sys_value, psutil_value)
|
||||
|
||||
def test_net_if_stats(self):
|
||||
ps_names = set(cext.net_if_stats())
|
||||
wmi_adapters = wmi.WMI().Win32_NetworkAdapter()
|
||||
wmi_names = set()
|
||||
for wmi_adapter in wmi_adapters:
|
||||
wmi_names.add(wmi_adapter.Name)
|
||||
wmi_names.add(wmi_adapter.NetConnectionID)
|
||||
self.assertTrue(ps_names & wmi_names,
|
||||
"no common entries in %s, %s" % (ps_names, wmi_names))
|
||||
|
||||
def test_boot_time(self):
|
||||
wmi_os = wmi.WMI().Win32_OperatingSystem()
|
||||
wmi_btime_str = wmi_os[0].LastBootUpTime.split('.')[0]
|
||||
wmi_btime_dt = datetime.datetime.strptime(
|
||||
wmi_btime_str, "%Y%m%d%H%M%S")
|
||||
psutil_dt = datetime.datetime.fromtimestamp(psutil.boot_time())
|
||||
diff = abs((wmi_btime_dt - psutil_dt).total_seconds())
|
||||
self.assertLessEqual(diff, 3)
|
||||
|
||||
def test_boot_time_fluctuation(self):
|
||||
# https://github.com/giampaolo/psutil/issues/1007
|
||||
with mock.patch('psutil._pswindows.cext.boot_time', return_value=5):
|
||||
self.assertEqual(psutil.boot_time(), 5)
|
||||
with mock.patch('psutil._pswindows.cext.boot_time', return_value=4):
|
||||
self.assertEqual(psutil.boot_time(), 5)
|
||||
with mock.patch('psutil._pswindows.cext.boot_time', return_value=6):
|
||||
self.assertEqual(psutil.boot_time(), 5)
|
||||
with mock.patch('psutil._pswindows.cext.boot_time', return_value=333):
|
||||
self.assertEqual(psutil.boot_time(), 333)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# sensors_battery()
|
||||
# ===================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestSensorsBattery(TestCase):
|
||||
|
||||
def test_has_battery(self):
|
||||
if win32api.GetPwrCapabilities()['SystemBatteriesPresent']:
|
||||
self.assertIsNotNone(psutil.sensors_battery())
|
||||
else:
|
||||
self.assertIsNone(psutil.sensors_battery())
|
||||
|
||||
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||
def test_percent(self):
|
||||
w = wmi.WMI()
|
||||
battery_wmi = w.query('select * from Win32_Battery')[0]
|
||||
battery_psutil = psutil.sensors_battery()
|
||||
self.assertAlmostEqual(
|
||||
battery_psutil.percent, battery_wmi.EstimatedChargeRemaining,
|
||||
delta=1)
|
||||
|
||||
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||
def test_power_plugged(self):
|
||||
w = wmi.WMI()
|
||||
battery_wmi = w.query('select * from Win32_Battery')[0]
|
||||
battery_psutil = psutil.sensors_battery()
|
||||
# Status codes:
|
||||
# https://msdn.microsoft.com/en-us/library/aa394074(v=vs.85).aspx
|
||||
self.assertEqual(battery_psutil.power_plugged,
|
||||
battery_wmi.BatteryStatus == 2)
|
||||
|
||||
def test_emulate_no_battery(self):
|
||||
with mock.patch("psutil._pswindows.cext.sensors_battery",
|
||||
return_value=(0, 128, 0, 0)) as m:
|
||||
self.assertIsNone(psutil.sensors_battery())
|
||||
assert m.called
|
||||
|
||||
def test_emulate_power_connected(self):
|
||||
with mock.patch("psutil._pswindows.cext.sensors_battery",
|
||||
return_value=(1, 0, 0, 0)) as m:
|
||||
self.assertEqual(psutil.sensors_battery().secsleft,
|
||||
psutil.POWER_TIME_UNLIMITED)
|
||||
assert m.called
|
||||
|
||||
def test_emulate_power_charging(self):
|
||||
with mock.patch("psutil._pswindows.cext.sensors_battery",
|
||||
return_value=(0, 8, 0, 0)) as m:
|
||||
self.assertEqual(psutil.sensors_battery().secsleft,
|
||||
psutil.POWER_TIME_UNLIMITED)
|
||||
assert m.called
|
||||
|
||||
def test_emulate_secs_left_unknown(self):
|
||||
with mock.patch("psutil._pswindows.cext.sensors_battery",
|
||||
return_value=(0, 0, 0, -1)) as m:
|
||||
self.assertEqual(psutil.sensors_battery().secsleft,
|
||||
psutil.POWER_TIME_UNKNOWN)
|
||||
assert m.called
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Process APIs
|
||||
# ===================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestProcess(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_issue_24(self):
|
||||
p = psutil.Process(0)
|
||||
self.assertRaises(psutil.AccessDenied, p.kill)
|
||||
|
||||
def test_special_pid(self):
|
||||
p = psutil.Process(4)
|
||||
self.assertEqual(p.name(), 'System')
|
||||
# use __str__ to access all common Process properties to check
|
||||
# that nothing strange happens
|
||||
str(p)
|
||||
p.username()
|
||||
self.assertTrue(p.create_time() >= 0.0)
|
||||
try:
|
||||
rss, vms = p.memory_info()[:2]
|
||||
except psutil.AccessDenied:
|
||||
# expected on Windows Vista and Windows 7
|
||||
if not platform.uname()[1] in ('vista', 'win-7', 'win7'):
|
||||
raise
|
||||
else:
|
||||
self.assertTrue(rss > 0)
|
||||
|
||||
def test_send_signal(self):
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertRaises(ValueError, p.send_signal, signal.SIGINT)
|
||||
|
||||
def test_num_handles_increment(self):
|
||||
p = psutil.Process(os.getpid())
|
||||
before = p.num_handles()
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
win32con.FALSE, os.getpid())
|
||||
after = p.num_handles()
|
||||
self.assertEqual(after, before + 1)
|
||||
win32api.CloseHandle(handle)
|
||||
self.assertEqual(p.num_handles(), before)
|
||||
|
||||
def test_handles_leak(self):
|
||||
# Call all Process methods and make sure no handles are left
|
||||
# open. This is here mainly to make sure functions using
|
||||
# OpenProcess() always call CloseHandle().
|
||||
def call(p, attr):
|
||||
attr = getattr(p, name, None)
|
||||
if attr is not None and callable(attr):
|
||||
attr()
|
||||
else:
|
||||
attr
|
||||
|
||||
p = psutil.Process(self.pid)
|
||||
failures = []
|
||||
for name in dir(psutil.Process):
|
||||
if name.startswith('_') \
|
||||
or name in ('terminate', 'kill', 'suspend', 'resume',
|
||||
'nice', 'send_signal', 'wait', 'children',
|
||||
'as_dict', 'memory_info_ex'):
|
||||
continue
|
||||
else:
|
||||
try:
|
||||
call(p, name)
|
||||
num1 = p.num_handles()
|
||||
call(p, name)
|
||||
num2 = p.num_handles()
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
else:
|
||||
if num2 > num1:
|
||||
fail = \
|
||||
"failure while processing Process.%s method " \
|
||||
"(before=%s, after=%s)" % (name, num1, num2)
|
||||
failures.append(fail)
|
||||
if failures:
|
||||
self.fail('\n' + '\n'.join(failures))
|
||||
|
||||
@unittest.skipIf(not 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)
|
||||
|
||||
def test_username(self):
|
||||
self.assertEqual(psutil.Process().username(),
|
||||
win32api.GetUserNameEx(win32con.NameSamCompatible))
|
||||
|
||||
def test_cmdline(self):
|
||||
sys_value = re.sub(' +', ' ', win32api.GetCommandLine()).strip()
|
||||
psutil_value = ' '.join(psutil.Process().cmdline())
|
||||
self.assertEqual(sys_value, psutil_value)
|
||||
|
||||
# XXX - occasional failures
|
||||
|
||||
# def test_cpu_times(self):
|
||||
# handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
# win32con.FALSE, os.getpid())
|
||||
# self.addCleanup(win32api.CloseHandle, handle)
|
||||
# sys_value = win32process.GetProcessTimes(handle)
|
||||
# psutil_value = psutil.Process().cpu_times()
|
||||
# self.assertAlmostEqual(
|
||||
# psutil_value.user, sys_value['UserTime'] / 10000000.0,
|
||||
# delta=0.2)
|
||||
# self.assertAlmostEqual(
|
||||
# psutil_value.user, sys_value['KernelTime'] / 10000000.0,
|
||||
# delta=0.2)
|
||||
|
||||
def test_nice(self):
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
win32con.FALSE, os.getpid())
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
sys_value = win32process.GetPriorityClass(handle)
|
||||
psutil_value = psutil.Process().nice()
|
||||
self.assertEqual(psutil_value, sys_value)
|
||||
|
||||
def test_memory_info(self):
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
win32con.FALSE, self.pid)
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
sys_value = win32process.GetProcessMemoryInfo(handle)
|
||||
psutil_value = psutil.Process(self.pid).memory_info()
|
||||
self.assertEqual(
|
||||
sys_value['PeakWorkingSetSize'], psutil_value.peak_wset)
|
||||
self.assertEqual(
|
||||
sys_value['WorkingSetSize'], psutil_value.wset)
|
||||
self.assertEqual(
|
||||
sys_value['QuotaPeakPagedPoolUsage'], psutil_value.peak_paged_pool)
|
||||
self.assertEqual(
|
||||
sys_value['QuotaPagedPoolUsage'], psutil_value.paged_pool)
|
||||
self.assertEqual(
|
||||
sys_value['QuotaPeakNonPagedPoolUsage'],
|
||||
psutil_value.peak_nonpaged_pool)
|
||||
self.assertEqual(
|
||||
sys_value['QuotaNonPagedPoolUsage'], psutil_value.nonpaged_pool)
|
||||
self.assertEqual(
|
||||
sys_value['PagefileUsage'], psutil_value.pagefile)
|
||||
self.assertEqual(
|
||||
sys_value['PeakPagefileUsage'], psutil_value.peak_pagefile)
|
||||
|
||||
self.assertEqual(psutil_value.rss, psutil_value.wset)
|
||||
self.assertEqual(psutil_value.vms, psutil_value.pagefile)
|
||||
|
||||
def test_wait(self):
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
win32con.FALSE, self.pid)
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
p = psutil.Process(self.pid)
|
||||
p.terminate()
|
||||
psutil_value = p.wait()
|
||||
sys_value = win32process.GetExitCodeProcess(handle)
|
||||
self.assertEqual(psutil_value, sys_value)
|
||||
|
||||
def test_cpu_affinity(self):
|
||||
def from_bitmask(x):
|
||||
return [i for i in range(64) if (1 << i) & x]
|
||||
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
win32con.FALSE, self.pid)
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
sys_value = from_bitmask(
|
||||
win32process.GetProcessAffinityMask(handle)[0])
|
||||
psutil_value = psutil.Process(self.pid).cpu_affinity()
|
||||
self.assertEqual(psutil_value, sys_value)
|
||||
|
||||
def test_io_counters(self):
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
|
||||
win32con.FALSE, os.getpid())
|
||||
self.addCleanup(win32api.CloseHandle, handle)
|
||||
sys_value = win32process.GetProcessIoCounters(handle)
|
||||
psutil_value = psutil.Process().io_counters()
|
||||
self.assertEqual(
|
||||
psutil_value.read_count, sys_value['ReadOperationCount'])
|
||||
self.assertEqual(
|
||||
psutil_value.write_count, sys_value['WriteOperationCount'])
|
||||
self.assertEqual(
|
||||
psutil_value.read_bytes, sys_value['ReadTransferCount'])
|
||||
self.assertEqual(
|
||||
psutil_value.write_bytes, sys_value['WriteTransferCount'])
|
||||
self.assertEqual(
|
||||
psutil_value.other_count, sys_value['OtherOperationCount'])
|
||||
self.assertEqual(
|
||||
psutil_value.other_bytes, sys_value['OtherTransferCount'])
|
||||
|
||||
def test_num_handles(self):
|
||||
import ctypes
|
||||
import ctypes.wintypes
|
||||
PROCESS_QUERY_INFORMATION = 0x400
|
||||
handle = ctypes.windll.kernel32.OpenProcess(
|
||||
PROCESS_QUERY_INFORMATION, 0, self.pid)
|
||||
self.addCleanup(ctypes.windll.kernel32.CloseHandle, handle)
|
||||
|
||||
hndcnt = ctypes.wintypes.DWORD()
|
||||
ctypes.windll.kernel32.GetProcessHandleCount(
|
||||
handle, ctypes.byref(hndcnt))
|
||||
sys_value = hndcnt.value
|
||||
psutil_value = psutil.Process(self.pid).num_handles()
|
||||
self.assertEqual(psutil_value, sys_value)
|
||||
|
||||
def test_error_partial_copy(self):
|
||||
# https://github.com/giampaolo/psutil/issues/875
|
||||
exc = WindowsError()
|
||||
exc.winerror = 299
|
||||
with mock.patch("psutil._psplatform.cext.proc_cwd", side_effect=exc):
|
||||
with mock.patch("time.sleep") as m:
|
||||
p = psutil.Process()
|
||||
self.assertRaises(psutil.AccessDenied, p.cwd)
|
||||
self.assertGreaterEqual(m.call_count, 5)
|
||||
|
||||
def test_exe(self):
|
||||
# NtQuerySystemInformation succeeds if process is gone. Make sure
|
||||
# it raises NSP for a non existent pid.
|
||||
pid = psutil.pids()[-1] + 99999
|
||||
proc = psutil._psplatform.Process(pid)
|
||||
self.assertRaises(psutil.NoSuchProcess, proc.exe)
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestProcessWMI(TestCase):
|
||||
"""Compare Process API results with WMI."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_name(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertEqual(p.name(), w.Caption)
|
||||
|
||||
def test_exe(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
# 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())
|
||||
|
||||
def test_cmdline(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
self.assertEqual(' '.join(p.cmdline()),
|
||||
w.CommandLine.replace('"', ''))
|
||||
|
||||
def test_username(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
domain, _, username = w.GetOwner()
|
||||
username = "%s\\%s" % (domain, username)
|
||||
self.assertEqual(p.username(), username)
|
||||
|
||||
def test_memory_rss(self):
|
||||
time.sleep(0.1)
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
rss = p.memory_info().rss
|
||||
self.assertEqual(rss, int(w.WorkingSetSize))
|
||||
|
||||
def test_memory_vms(self):
|
||||
time.sleep(0.1)
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
vms = p.memory_info().vms
|
||||
# http://msdn.microsoft.com/en-us/library/aa394372(VS.85).aspx
|
||||
# ...claims that PageFileUsage is represented in Kilo
|
||||
# bytes but funnily enough on certain platforms bytes are
|
||||
# returned instead.
|
||||
wmi_usage = int(w.PageFileUsage)
|
||||
if (vms != wmi_usage) and (vms != wmi_usage * 1024):
|
||||
self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms))
|
||||
|
||||
def test_create_time(self):
|
||||
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
|
||||
p = psutil.Process(self.pid)
|
||||
wmic_create = str(w.CreationDate.split('.')[0])
|
||||
psutil_create = time.strftime("%Y%m%d%H%M%S",
|
||||
time.localtime(p.create_time()))
|
||||
self.assertEqual(wmic_create, psutil_create)
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestDualProcessImplementation(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
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.pid = get_test_subprocess().pid
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_memory_info(self):
|
||||
mem_1 = psutil.Process(self.pid).memory_info()
|
||||
with mock.patch("psutil._psplatform.cext.proc_memory_info",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
mem_2 = psutil.Process(self.pid).memory_info()
|
||||
self.assertEqual(len(mem_1), len(mem_2))
|
||||
for i in range(len(mem_1)):
|
||||
self.assertGreaterEqual(mem_1[i], 0)
|
||||
self.assertGreaterEqual(mem_2[i], 0)
|
||||
self.assertAlmostEqual(mem_1[i], mem_2[i], delta=512)
|
||||
assert fun.called
|
||||
|
||||
def test_create_time(self):
|
||||
ctime = psutil.Process(self.pid).create_time()
|
||||
with mock.patch("psutil._psplatform.cext.proc_times",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
self.assertEqual(psutil.Process(self.pid).create_time(), ctime)
|
||||
assert fun.called
|
||||
|
||||
def test_cpu_times(self):
|
||||
cpu_times_1 = psutil.Process(self.pid).cpu_times()
|
||||
with mock.patch("psutil._psplatform.cext.proc_times",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
cpu_times_2 = psutil.Process(self.pid).cpu_times()
|
||||
assert fun.called
|
||||
self.assertAlmostEqual(
|
||||
cpu_times_1.user, cpu_times_2.user, delta=0.01)
|
||||
self.assertAlmostEqual(
|
||||
cpu_times_1.system, cpu_times_2.system, delta=0.01)
|
||||
|
||||
def test_io_counters(self):
|
||||
io_counters_1 = psutil.Process(self.pid).io_counters()
|
||||
with mock.patch("psutil._psplatform.cext.proc_io_counters",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
io_counters_2 = psutil.Process(self.pid).io_counters()
|
||||
for i in range(len(io_counters_1)):
|
||||
self.assertAlmostEqual(
|
||||
io_counters_1[i], io_counters_2[i], delta=5)
|
||||
assert fun.called
|
||||
|
||||
def test_num_handles(self):
|
||||
num_handles = psutil.Process(self.pid).num_handles()
|
||||
with mock.patch("psutil._psplatform.cext.proc_num_handles",
|
||||
side_effect=OSError(errno.EPERM, "msg")) as fun:
|
||||
self.assertEqual(psutil.Process(self.pid).num_handles(),
|
||||
num_handles)
|
||||
assert fun.called
|
||||
|
||||
def test_cmdline(self):
|
||||
from psutil._pswindows import convert_oserror
|
||||
for pid in psutil.pids():
|
||||
try:
|
||||
a = cext.proc_cmdline(pid, use_peb=True)
|
||||
b = cext.proc_cmdline(pid, use_peb=False)
|
||||
except OSError as err:
|
||||
err = convert_oserror(err)
|
||||
if not isinstance(err, (psutil.AccessDenied,
|
||||
psutil.NoSuchProcess)):
|
||||
raise
|
||||
else:
|
||||
self.assertEqual(a, b)
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class RemoteProcessTestCase(TestCase):
|
||||
"""Certain functions require calling ReadProcessMemory.
|
||||
This trivially works when called on the current process.
|
||||
Check that this works on other processes, especially when they
|
||||
have a different bitness.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def find_other_interpreter():
|
||||
# find a python interpreter that is of the opposite bitness from us
|
||||
code = "import sys; sys.stdout.write(str(sys.maxsize > 2**32))"
|
||||
|
||||
# XXX: a different and probably more stable approach might be to access
|
||||
# the registry but accessing 64 bit paths from a 32 bit process
|
||||
for filename in glob.glob(r"C:\Python*\python.exe"):
|
||||
proc = subprocess.Popen(args=[filename, "-c", code],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
output, _ = proc.communicate()
|
||||
if output == str(not IS_64_BIT):
|
||||
return filename
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
other_python = cls.find_other_interpreter()
|
||||
|
||||
if other_python is None:
|
||||
raise unittest.SkipTest(
|
||||
"could not find interpreter with opposite bitness")
|
||||
|
||||
if IS_64_BIT:
|
||||
cls.python64 = sys.executable
|
||||
cls.python32 = other_python
|
||||
else:
|
||||
cls.python64 = other_python
|
||||
cls.python32 = sys.executable
|
||||
|
||||
test_args = ["-c", "import sys; sys.stdin.read()"]
|
||||
|
||||
def setUp(self):
|
||||
env = os.environ.copy()
|
||||
env["THINK_OF_A_NUMBER"] = str(os.getpid())
|
||||
self.proc32 = get_test_subprocess([self.python32] + self.test_args,
|
||||
env=env,
|
||||
stdin=subprocess.PIPE)
|
||||
self.proc64 = get_test_subprocess([self.python64] + self.test_args,
|
||||
env=env,
|
||||
stdin=subprocess.PIPE)
|
||||
|
||||
def tearDown(self):
|
||||
self.proc32.communicate()
|
||||
self.proc64.communicate()
|
||||
reap_children()
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
def test_cmdline_32(self):
|
||||
p = psutil.Process(self.proc32.pid)
|
||||
self.assertEqual(len(p.cmdline()), 3)
|
||||
self.assertEqual(p.cmdline()[1:], self.test_args)
|
||||
|
||||
def test_cmdline_64(self):
|
||||
p = psutil.Process(self.proc64.pid)
|
||||
self.assertEqual(len(p.cmdline()), 3)
|
||||
self.assertEqual(p.cmdline()[1:], self.test_args)
|
||||
|
||||
def test_cwd_32(self):
|
||||
p = psutil.Process(self.proc32.pid)
|
||||
self.assertEqual(p.cwd(), os.getcwd())
|
||||
|
||||
def test_cwd_64(self):
|
||||
p = psutil.Process(self.proc64.pid)
|
||||
self.assertEqual(p.cwd(), os.getcwd())
|
||||
|
||||
def test_environ_32(self):
|
||||
p = psutil.Process(self.proc32.pid)
|
||||
e = p.environ()
|
||||
self.assertIn("THINK_OF_A_NUMBER", e)
|
||||
self.assertEquals(e["THINK_OF_A_NUMBER"], str(os.getpid()))
|
||||
|
||||
def test_environ_64(self):
|
||||
p = psutil.Process(self.proc64.pid)
|
||||
try:
|
||||
p.environ()
|
||||
except psutil.AccessDenied:
|
||||
pass
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Windows services
|
||||
# ===================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestServices(TestCase):
|
||||
|
||||
def test_win_service_iter(self):
|
||||
valid_statuses = set([
|
||||
"running",
|
||||
"paused",
|
||||
"start",
|
||||
"pause",
|
||||
"continue",
|
||||
"stop",
|
||||
"stopped",
|
||||
])
|
||||
valid_start_types = set([
|
||||
"automatic",
|
||||
"manual",
|
||||
"disabled",
|
||||
])
|
||||
valid_statuses = set([
|
||||
"running",
|
||||
"paused",
|
||||
"start_pending",
|
||||
"pause_pending",
|
||||
"continue_pending",
|
||||
"stop_pending",
|
||||
"stopped"
|
||||
])
|
||||
for serv in psutil.win_service_iter():
|
||||
data = serv.as_dict()
|
||||
self.assertIsInstance(data['name'], str)
|
||||
self.assertNotEqual(data['name'].strip(), "")
|
||||
self.assertIsInstance(data['display_name'], str)
|
||||
self.assertIsInstance(data['username'], str)
|
||||
self.assertIn(data['status'], valid_statuses)
|
||||
if data['pid'] is not None:
|
||||
psutil.Process(data['pid'])
|
||||
self.assertIsInstance(data['binpath'], str)
|
||||
self.assertIsInstance(data['username'], str)
|
||||
self.assertIsInstance(data['start_type'], str)
|
||||
self.assertIn(data['start_type'], valid_start_types)
|
||||
self.assertIn(data['status'], valid_statuses)
|
||||
self.assertIsInstance(data['description'], str)
|
||||
pid = serv.pid()
|
||||
if pid is not None:
|
||||
p = psutil.Process(pid)
|
||||
self.assertTrue(p.is_running())
|
||||
# win_service_get
|
||||
s = psutil.win_service_get(serv.name())
|
||||
# test __eq__
|
||||
self.assertEqual(serv, s)
|
||||
|
||||
def test_win_service_get(self):
|
||||
ERROR_SERVICE_DOES_NOT_EXIST = \
|
||||
psutil._psplatform.cext.ERROR_SERVICE_DOES_NOT_EXIST
|
||||
ERROR_ACCESS_DENIED = psutil._psplatform.cext.ERROR_ACCESS_DENIED
|
||||
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
with self.assertRaises(psutil.NoSuchProcess) as cm:
|
||||
psutil.win_service_get(name + '???')
|
||||
self.assertEqual(cm.exception.name, name + '???')
|
||||
|
||||
# test NoSuchProcess
|
||||
service = psutil.win_service_get(name)
|
||||
if PY3:
|
||||
args = (0, "msg", 0, ERROR_SERVICE_DOES_NOT_EXIST)
|
||||
else:
|
||||
args = (ERROR_SERVICE_DOES_NOT_EXIST, "msg")
|
||||
exc = WindowsError(*args)
|
||||
with mock.patch("psutil._psplatform.cext.winservice_query_status",
|
||||
side_effect=exc):
|
||||
self.assertRaises(psutil.NoSuchProcess, service.status)
|
||||
with mock.patch("psutil._psplatform.cext.winservice_query_config",
|
||||
side_effect=exc):
|
||||
self.assertRaises(psutil.NoSuchProcess, service.username)
|
||||
|
||||
# test AccessDenied
|
||||
if PY3:
|
||||
args = (0, "msg", 0, ERROR_ACCESS_DENIED)
|
||||
else:
|
||||
args = (ERROR_ACCESS_DENIED, "msg")
|
||||
exc = WindowsError(*args)
|
||||
with mock.patch("psutil._psplatform.cext.winservice_query_status",
|
||||
side_effect=exc):
|
||||
self.assertRaises(psutil.AccessDenied, service.status)
|
||||
with mock.patch("psutil._psplatform.cext.winservice_query_config",
|
||||
side_effect=exc):
|
||||
self.assertRaises(psutil.AccessDenied, service.username)
|
||||
|
||||
# test __str__ and __repr__
|
||||
self.assertIn(service.name(), str(service))
|
||||
self.assertIn(service.display_name(), str(service))
|
||||
self.assertIn(service.name(), repr(service))
|
||||
self.assertIn(service.display_name(), repr(service))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
31
third_party/python/psutil/.cirrus.yml
vendored
Normal file
31
third_party/python/psutil/.cirrus.yml
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
freebsd_12_1_py3_task:
|
||||
freebsd_instance:
|
||||
image: freebsd-12-1-release-amd64
|
||||
env:
|
||||
CIRRUS: 1
|
||||
install_script:
|
||||
- pkg install -y python3 gcc py37-pip
|
||||
script:
|
||||
- python3 -m pip install --user setuptools
|
||||
- make clean
|
||||
- make install
|
||||
- make test
|
||||
- make test-memleaks
|
||||
- PSUTIL_TESTING=1 python3 -Wa scripts/internal/print_access_denied.py
|
||||
- PSUTIL_TESTING=1 python3 -Wa scripts/internal/print_api_speed.py
|
||||
|
||||
freebsd_12_1_py2_task:
|
||||
freebsd_instance:
|
||||
image: freebsd-12-1-release-amd64
|
||||
env:
|
||||
CIRRUS: 1
|
||||
install_script:
|
||||
- pkg install -y python gcc py27-pip
|
||||
script:
|
||||
- python2.7 -m pip install --user setuptools ipaddress mock
|
||||
- make clean
|
||||
- make install
|
||||
- make test
|
||||
- make test-memleaks
|
||||
- PSUTIL_TESTING=1 python3 -Wa scripts/internal/print_access_denied.py
|
||||
- PSUTIL_TESTING=1 python3 -Wa scripts/internal/print_api_speed.py
|
||||
32
third_party/python/psutil/.coveragerc
vendored
Normal file
32
third_party/python/psutil/.coveragerc
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
[report]
|
||||
|
||||
include =
|
||||
*psutil*
|
||||
omit =
|
||||
psutil/_compat.py
|
||||
psutil/tests/*
|
||||
setup.py
|
||||
exclude_lines =
|
||||
enum.IntEnum
|
||||
except ImportError:
|
||||
globals().update
|
||||
if __name__ == .__main__.:
|
||||
if _WINDOWS:
|
||||
if BSD
|
||||
if enum is None:
|
||||
if enum is not None:
|
||||
if FREEBSD
|
||||
if has_enums:
|
||||
if LINUX
|
||||
if LITTLE_ENDIAN:
|
||||
if NETBSD
|
||||
if OPENBSD
|
||||
if MACOS
|
||||
if ppid_map is None:
|
||||
if PY3:
|
||||
if SUNOS
|
||||
if sys.platform.startswith
|
||||
if WINDOWS
|
||||
import enum
|
||||
pragma: no cover
|
||||
raise NotImplementedError
|
||||
19
third_party/python/psutil/.gitignore
vendored
Normal file
19
third_party/python/psutil/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
syntax: glob
|
||||
*.al
|
||||
*.bak
|
||||
*.egg-info
|
||||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
*.orig
|
||||
*.pyc
|
||||
*.pyd
|
||||
*.rej
|
||||
*.so
|
||||
*.swp
|
||||
.failed-tests.txt
|
||||
.cache/
|
||||
.idea/
|
||||
.tox/
|
||||
build/
|
||||
dist/
|
||||
666
third_party/python/psutil/CREDITS
vendored
Normal file
666
third_party/python/psutil/CREDITS
vendored
Normal file
|
|
@ -0,0 +1,666 @@
|
|||
Intro
|
||||
=====
|
||||
|
||||
I would like to recognize some of the people who have been instrumental in the
|
||||
development of psutil. I'm sure I'm forgetting somebody (feel free to email me)
|
||||
but here is a short list. It's modeled after the Linux CREDITS file where the
|
||||
fields are: name (N), e-mail (E), website (W), country (C), description (D),
|
||||
(I) issues. Issue tracker is at https://github.com/giampaolo/psutil/issues).
|
||||
A big thanks to all of you.
|
||||
|
||||
- Giampaolo
|
||||
|
||||
Author
|
||||
======
|
||||
|
||||
N: Giampaolo Rodola
|
||||
C: Italy
|
||||
E: g.rodola@gmail.com
|
||||
W: http://grodola.blogspot.com/
|
||||
|
||||
Experts
|
||||
=======
|
||||
|
||||
Github usernames of people to CC on github when in need of help.
|
||||
|
||||
- NetBSD:
|
||||
- 0-wiz-0, Thomas Klausner
|
||||
- ryoqun, Ryo Onodera
|
||||
- OpenBSD:
|
||||
- landryb, Landry Breuil
|
||||
- FreeBSD:
|
||||
- glebius, Gleb Smirnoff (#1013)
|
||||
- sunpoet, Po-Chuan Hsieh (pkg maintainer, #1105)
|
||||
- kostikbel, Konstantin Belousov (#1105)
|
||||
- macOS:
|
||||
- whitlockjc, Jeremy Whitlock
|
||||
- Windows:
|
||||
- mrjefftang, Jeff Tang
|
||||
- wj32, Wen Jia Liu
|
||||
- fbenkstein, Frank Benkstein
|
||||
- SunOS:
|
||||
- wiggin15, Arnon Yaari
|
||||
- alxchk, Oleksii Shevchuk
|
||||
- AIX:
|
||||
- wiggin15, Arnon Yaari (maintainer)
|
||||
|
||||
Top contributors
|
||||
================
|
||||
|
||||
N: Jay Loden
|
||||
C: NJ, USA
|
||||
E: jloden@gmail.com
|
||||
D: original co-author, initial design/bootstrap and occasional bug fixes
|
||||
W: http://www.jayloden.com
|
||||
|
||||
N: Arnon Yaari (wiggin15)
|
||||
W: https://github.com/wiggin15
|
||||
D: AIX implementation, expert on multiple fronts
|
||||
I: 517, 607, 610, 1131, 1123, 1130, 1154, 1164, 1174, 1177, 1210, 1214, 1408,
|
||||
1329, 1276, 1494, 1528.
|
||||
|
||||
N: Alex Manuskin
|
||||
W: https://github.com/amanusk
|
||||
D: FreeBSD cpu_freq(), OSX temperatures, support for Linux temperatures.
|
||||
I: 1284, 1345, 1350, 1352, 1472, 1481, 1487.
|
||||
|
||||
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 macOS C development.
|
||||
I: 125, 150, 174, 206
|
||||
|
||||
N: Landry Breuil
|
||||
W: https://github.com/landryb
|
||||
D: OpenBSD implementation.
|
||||
I: 615
|
||||
|
||||
N: Justin Venus
|
||||
E: justin.venus@gmail.com
|
||||
D: Solaris support
|
||||
I: 18
|
||||
|
||||
N: Thomas Klausner
|
||||
W: https://github.com/0-wiz-0
|
||||
D: NetBSD implementation (co-author).
|
||||
I: 557
|
||||
|
||||
N: Ryo Onodera
|
||||
W: https://github.com/ryoon
|
||||
D: NetBSD implementation (co-author).
|
||||
I: 557
|
||||
|
||||
Contributors
|
||||
============
|
||||
|
||||
N: wj32
|
||||
E: wj32.64@gmail.com
|
||||
D: process username() and get_connections() on Windows
|
||||
I: 114, 115
|
||||
|
||||
N: Yan Raber
|
||||
C: Bologna, Italy
|
||||
E: yanraber@gmail.com
|
||||
D: help on Windows development (initial version of Process.username())
|
||||
|
||||
N: Dave Daeschler
|
||||
C: USA
|
||||
E: david.daeschler@gmail.com
|
||||
W: http://daviddaeschler.com
|
||||
D: some contributions to initial design/bootstrap plus occasional bug fixing
|
||||
I: 522, 536
|
||||
|
||||
N: cjgohlke
|
||||
E: cjgohlke@gmail.com
|
||||
D: Windows 64 bit support
|
||||
I: 107
|
||||
|
||||
N: Frank Benkstein
|
||||
D: process environ()
|
||||
W: https://github.com/fbenkstein
|
||||
I: 732, 733
|
||||
|
||||
N: Mozilla Foundation
|
||||
D: sample code for process USS memory.
|
||||
|
||||
N: EccoTheFlintstone
|
||||
W: https://github.com/EccoTheFlintstone
|
||||
I: 1368, 1348
|
||||
|
||||
----
|
||||
|
||||
N: Jeffery Kline
|
||||
E: jeffery.kline@gmail.com
|
||||
I: 130
|
||||
|
||||
N: Grabriel Monnerat
|
||||
E: gabrielmonnerat@gmail.com
|
||||
I: 146
|
||||
|
||||
N: Philip Roberts
|
||||
E: philip.roberts@gmail.com
|
||||
I: 168
|
||||
|
||||
N: jcscoobyrs
|
||||
E: jcscoobyrs@gmail.com
|
||||
I: 125
|
||||
|
||||
N: Sandro Tosi
|
||||
E: sandro.tosi@gmail.com
|
||||
I: 200, 201
|
||||
|
||||
N: Andrew Colin
|
||||
E: andrew.colin@gmail.com
|
||||
I: 248
|
||||
|
||||
N: Amoser
|
||||
E: amoser@google.com
|
||||
I: 266, 267, 340
|
||||
|
||||
N: Matthew Grant
|
||||
E: matthewgrant5@gmail.com
|
||||
I: 271
|
||||
|
||||
N: oweidner
|
||||
E: oweidner@cct.lsu.edu
|
||||
I: 275
|
||||
|
||||
N: Tarek Ziade
|
||||
E: ziade.tarek
|
||||
I: 281
|
||||
|
||||
N: Luca Cipriani
|
||||
C: Turin, Italy
|
||||
E: luca.opensource@gmail.com
|
||||
I: 278
|
||||
|
||||
N: Maciej Lach,
|
||||
E: maciej.lach@gmail.com
|
||||
I: 294
|
||||
|
||||
N: James Pye
|
||||
E: james.pye@gmail.com
|
||||
I: 305, 306
|
||||
|
||||
N: Stanchev Emil
|
||||
E: stanchev.emil
|
||||
I: 314
|
||||
|
||||
N: Kim Gräsman
|
||||
E: kim.grasman@gmail.com
|
||||
D: ...also kindly donated some money.
|
||||
I: 316
|
||||
|
||||
N: Riccardo Murri
|
||||
C: Italy
|
||||
I: 318
|
||||
|
||||
N: Florent Xicluna
|
||||
E: florent.xicluna@gmail.com
|
||||
I: 319
|
||||
|
||||
N: Michal Spondr
|
||||
E: michal.spondr
|
||||
I: 313
|
||||
|
||||
N: Jean Sebastien
|
||||
E: dumbboules@gmail.com
|
||||
I: 344
|
||||
|
||||
N: Rob Smith
|
||||
W: http://www.kormoc.com/
|
||||
I: 341
|
||||
|
||||
N: Youngsik Kim
|
||||
W: https://plus.google.com/101320747613749824490/
|
||||
I: 317
|
||||
|
||||
N: Gregory Szorc
|
||||
W: https://plus.google.com/116873264322260110710/posts
|
||||
I: 323
|
||||
|
||||
N: André Oriani
|
||||
E: aoriani@gmail.com
|
||||
I: 361
|
||||
|
||||
N: clackwell
|
||||
E: clackwell@gmail.com
|
||||
I: 356
|
||||
|
||||
N: m.malycha
|
||||
E: m.malycha@gmail.com
|
||||
I: 351
|
||||
|
||||
N: John Baldwin
|
||||
E: jhb@FreeBSD.org
|
||||
I: 370
|
||||
|
||||
N: Jan Beich
|
||||
E: jbeich@tormail.org
|
||||
I: 325
|
||||
|
||||
N: floppymaster
|
||||
E: floppymaster@gmail.com
|
||||
I: 380
|
||||
|
||||
N: Arfrever.FTA
|
||||
E: Arfrever.FTA@gmail.com
|
||||
I: 369, 404
|
||||
|
||||
N: danudey
|
||||
E: danudey@gmail.com
|
||||
I: 386
|
||||
|
||||
N: Adrien Fallou
|
||||
I: 224
|
||||
|
||||
N: Gisle Vanem
|
||||
E: gisle.vanem@gmail.com
|
||||
I: 411
|
||||
|
||||
N: thepyr0
|
||||
E: thepyr0@gmail.com
|
||||
I: 414
|
||||
|
||||
N: John Pankov
|
||||
E: john.pankov@gmail.com
|
||||
I: 435
|
||||
|
||||
N: Matt Good
|
||||
W: http://matt-good.net/
|
||||
I: 438
|
||||
|
||||
N: Ulrich Klank
|
||||
E: ulrich.klank@scitics.de
|
||||
I: 448
|
||||
|
||||
N: Josiah Carlson
|
||||
E: josiah.carlson@gmail.com
|
||||
I: 451, 452
|
||||
|
||||
N: Raymond Hettinger
|
||||
D: namedtuple and lru_cache backward compatible implementations.
|
||||
|
||||
N: Jason Kirtland
|
||||
D: backward compatible implementation of collections.defaultdict.
|
||||
|
||||
M: Ken Seeho
|
||||
D: @cached_property decorator
|
||||
|
||||
N: crusaderky
|
||||
E: crusaderky@gmail.com
|
||||
I: 470, 477
|
||||
|
||||
E: alex@mroja.net
|
||||
I: 471
|
||||
|
||||
N: Gautam Singh
|
||||
E: gautam.singh@gmail.com
|
||||
I: 466
|
||||
|
||||
E: lhn@hupfeldtit.dk
|
||||
I: 476, 479
|
||||
|
||||
N: Francois Charron
|
||||
E: francois.charron.1@gmail.com
|
||||
I: 474
|
||||
|
||||
N: Naveed Roudsari
|
||||
E: naveed.roudsari@gmail.com
|
||||
I: 421
|
||||
|
||||
N: Alexander Grothe
|
||||
E: Alexander.Grothe@gmail.com
|
||||
I: 497
|
||||
|
||||
N: Szigeti Gabor Niif
|
||||
E: szigeti.gabor.niif@gmail.com
|
||||
I: 446
|
||||
|
||||
N: msabramo
|
||||
E: msabramo@gmail.com
|
||||
I: 492
|
||||
|
||||
N: Yaolong Huang
|
||||
E: airekans@gmail.com
|
||||
W: http://airekans.github.io/
|
||||
I: 530
|
||||
|
||||
N: Anders Chrigström
|
||||
W: https://github.com/anders-chrigstrom
|
||||
I: 496
|
||||
|
||||
N: spacewander
|
||||
W: https://github.com/spacewander
|
||||
E: spacewanderlzx@gmail.com
|
||||
I: 561, 603
|
||||
|
||||
N: Sylvain Mouquet
|
||||
E: sylvain.mouquet@gmail.com
|
||||
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
|
||||
|
||||
N: dasumin
|
||||
W: https://github.com/dasumin
|
||||
I: 541
|
||||
|
||||
N: Mike Sarahan
|
||||
W: https://github.com/msarahan
|
||||
I: 688
|
||||
|
||||
N: Syohei YOSHIDA
|
||||
W: https://github.com/syohex
|
||||
I: 730
|
||||
|
||||
N: Visa Hankala
|
||||
E: visa@openbsd.org
|
||||
I: 741
|
||||
|
||||
N: Sebastian-Gabriel Brestin
|
||||
C: Romania
|
||||
E: sebastianbrestin@gmail.com
|
||||
I: 704
|
||||
|
||||
N: Timmy Konick
|
||||
W: https://github.com/tijko
|
||||
I: 751
|
||||
|
||||
N: mpderbec
|
||||
W: https://github.com/mpderbec
|
||||
I: 660
|
||||
|
||||
N: wxwright
|
||||
W: https://github.com/wxwright
|
||||
I: 776
|
||||
|
||||
N: Farhan Khan
|
||||
E: khanzf@gmail.com
|
||||
I: 823
|
||||
|
||||
N: Jake Omann
|
||||
E: https://github.com/jomann09
|
||||
I: 816, 775
|
||||
|
||||
N: Jeremy Humble
|
||||
W: https://github.com/jhumble
|
||||
I: 863
|
||||
|
||||
N: Ilya Georgievsky
|
||||
W: https://github.com/xBeAsTx
|
||||
I: 870
|
||||
|
||||
N: Yago Jesus
|
||||
W: https://github.com/YJesus
|
||||
I: 798
|
||||
|
||||
N: Andre Caron
|
||||
C: Montreal, QC, Canada
|
||||
E: andre.l.caron@gmail.com
|
||||
W: https://github.com/AndreLouisCaron
|
||||
I: 880
|
||||
|
||||
N: ewedlund
|
||||
W: https://github.com/ewedlund
|
||||
I: 874
|
||||
|
||||
N: Arcadiy Ivanov
|
||||
W: https://github.com/arcivanov
|
||||
I: 919
|
||||
|
||||
N: Max Bélanger
|
||||
W: https://github.com/maxbelanger
|
||||
I: 936, 1133
|
||||
|
||||
N: Pierre Fersing
|
||||
C: France
|
||||
E: pierre.fersing@bleemeo.com
|
||||
I: 950
|
||||
|
||||
N: Thiago Borges Abdnur
|
||||
W: https://github.com/bolaum
|
||||
I: 959
|
||||
|
||||
N: Nicolas Hennion
|
||||
W: https://github.com/nicolargo
|
||||
I: 974
|
||||
|
||||
N: Baruch Siach
|
||||
W: https://github.com/baruchsiach
|
||||
I: 872
|
||||
|
||||
N: Danek Duvall
|
||||
W: https://github.com/dhduvall
|
||||
I: 1002
|
||||
|
||||
N: Alexander Hasselhuhn
|
||||
C: Germany
|
||||
W: https://github.com/alexanha
|
||||
|
||||
N: Himanshu Shekhar
|
||||
W: https://github.com/himanshub16
|
||||
I: 1036
|
||||
|
||||
N: Yannick Gingras
|
||||
W: https://github.com/ygingras
|
||||
I: 1057
|
||||
|
||||
N: Gleb Smirnoff
|
||||
W: https://github.com/glebius
|
||||
D: good help with FreeBSD
|
||||
I: 1042, 1079, 1070
|
||||
|
||||
N: Oleksii Shevchuk
|
||||
W: https://github.com/alxchk
|
||||
I: 1077, 1093, 1091, 1220, 1346
|
||||
|
||||
N: Prodesire
|
||||
W: https://github.com/Prodesire
|
||||
I: 1138
|
||||
|
||||
N: Sebastian Saip
|
||||
W: https://github.com/ssaip
|
||||
I: 1141
|
||||
|
||||
N: Jakub Bacic
|
||||
W: https://github.com/jakub-bacic
|
||||
I: 1127
|
||||
|
||||
N: Akos Kiss
|
||||
W: https://github.com/akosthekiss
|
||||
I: 1150
|
||||
|
||||
N: Adrian Page
|
||||
W: https://github.com/adpag
|
||||
I: 1159, 1160, 1161
|
||||
|
||||
N: Matthew Long
|
||||
W: https://github.com/matray
|
||||
I: 1167
|
||||
|
||||
N: janderbrain
|
||||
W: https://github.com/janderbrain
|
||||
I: 1169
|
||||
|
||||
N: Dan Vinakovsky
|
||||
W: https://github.com/hexaclock
|
||||
I: 1216
|
||||
|
||||
N: stswandering
|
||||
W: https://github.com/stswandering
|
||||
I: 1243
|
||||
|
||||
N: Georg Sauthoff
|
||||
W: https://github.com/gsauthof
|
||||
I: 1193, 1194
|
||||
|
||||
N: Maxime Mouial
|
||||
W: https://github.com/hush-hush
|
||||
I: 1239
|
||||
|
||||
N: Denis Krienbühl
|
||||
W: https://github.com/href
|
||||
I: 1260
|
||||
|
||||
N: Jean-Luc Migot
|
||||
W: https://github.com/jmigot-tehtris
|
||||
I: 1258, 1289
|
||||
|
||||
N: Nikhil Marathe
|
||||
W: https://github.com/nikhilm
|
||||
I: 1278
|
||||
|
||||
N: Sylvain Duchesne
|
||||
W: https://github.com/sylvainduchesne
|
||||
I: 1294
|
||||
|
||||
N: Lawrence Ye
|
||||
W: https://github.com/LEAFERx
|
||||
I: 1321
|
||||
|
||||
N: Ilya Yanok
|
||||
W: https://github.com/yanok
|
||||
I: 1332
|
||||
|
||||
N: Jaime Fullaondo
|
||||
W: https://github.com/truthbk
|
||||
D: AIX support
|
||||
I: 1320
|
||||
|
||||
N: Koen Kooi
|
||||
W: https://github.com/koenkooi
|
||||
I: 1360
|
||||
|
||||
N: Ghislain Le Meur
|
||||
W: https://github.com/gigi206
|
||||
D: idea for Process.parents()
|
||||
I: 1379
|
||||
|
||||
N: Benjamin Drung
|
||||
D: make tests invariant to LANG setting
|
||||
W: https://github.com/bdrung
|
||||
I: 1462
|
||||
|
||||
N: Xiaoling Bao
|
||||
I: 1223
|
||||
|
||||
N: Cedric Lamoriniere
|
||||
W: https://github.com/clamoriniere
|
||||
I: 1470
|
||||
|
||||
N: Daniel Beer
|
||||
W: https://github.com/dbeer1
|
||||
I: 1471
|
||||
|
||||
N: Samer Masterson
|
||||
W: https://github.com/samertm
|
||||
I: 1480
|
||||
|
||||
N: Ammar Askar
|
||||
E: ammar@ammaraskar.com
|
||||
W: http://ammaraskar.com/
|
||||
I: 604, 1484
|
||||
|
||||
N: agnewee
|
||||
W: https://github.com/Agnewee
|
||||
C: China
|
||||
I: 1491
|
||||
|
||||
N: Kamil Rytarowski
|
||||
W: https://github.com/krytarowski
|
||||
C: Poland
|
||||
I: 1526, 1530
|
||||
|
||||
N: Athos Ribeiro
|
||||
W: https://github.com/athos-ribeiro
|
||||
I: 1585
|
||||
|
||||
N: Erwan Le Pape
|
||||
W: https://github.com/erwan-le-pape
|
||||
I: 1570
|
||||
|
||||
N: Étienne Servais
|
||||
W: https://github.com/vser1
|
||||
I: 1607, 1637
|
||||
|
||||
N: Bernát Gábor
|
||||
W: https://github.com/gaborbernat
|
||||
I: 1565
|
||||
|
||||
N: Nathan Houghton
|
||||
W: https://github.com/n1000
|
||||
I: 1619
|
||||
|
||||
N: Riccardo Schirone
|
||||
W: https://github.com/ret2libc
|
||||
C: Milano, Italy
|
||||
I: 1616
|
||||
|
||||
N: Po-Chuan Hsieh
|
||||
W: https://github.com/sunpoet
|
||||
C: Taiwan
|
||||
I: 1646
|
||||
|
||||
N: Javad Karabi
|
||||
W: https://github.com/karabijavad
|
||||
I: 1648
|
||||
|
||||
N: Mike Hommey
|
||||
W: https://github.com/glandium
|
||||
I: 1665
|
||||
|
||||
N: Anselm Kruis
|
||||
W: https://github.com/akruis
|
||||
I: 1695
|
||||
4141
third_party/python/psutil/HISTORY.rst
vendored
Normal file
4141
third_party/python/psutil/HISTORY.rst
vendored
Normal file
File diff suppressed because it is too large
Load diff
140
third_party/python/psutil/INSTALL.rst
vendored
Normal file
140
third_party/python/psutil/INSTALL.rst
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
Install pip
|
||||
===========
|
||||
|
||||
pip is the easiest way to install psutil. It is shipped by default with Python
|
||||
2.7.9+ and 3.4+. For other Python versions you can install it manually.
|
||||
On Linux or via wget::
|
||||
|
||||
wget https://bootstrap.pypa.io/get-pip.py -O - | python
|
||||
|
||||
On macOS or via curl::
|
||||
|
||||
python < <(curl -s https://bootstrap.pypa.io/get-pip.py)
|
||||
|
||||
On Windows, `download pip <https://pip.pypa.io/en/latest/installing/>`__, open
|
||||
cmd.exe and install it::
|
||||
|
||||
C:\Python27\python.exe get-pip.py
|
||||
|
||||
Permission issues (UNIX)
|
||||
========================
|
||||
|
||||
The commands below assume you're running as root.
|
||||
If you aren't or you bump into permission errors you can either install psutil
|
||||
for your user only::
|
||||
|
||||
pip3 install --user psutil
|
||||
|
||||
...or prepend ``sudo`` and install it globally, e.g.::
|
||||
|
||||
sudo pip3 install psutil
|
||||
|
||||
Linux
|
||||
=====
|
||||
|
||||
Ubuntu / Debian::
|
||||
|
||||
sudo apt-get install gcc python3-dev
|
||||
pip3 install psutil
|
||||
|
||||
RedHat / CentOS::
|
||||
|
||||
sudo yum install gcc python3-devel
|
||||
pip3 install psutil
|
||||
|
||||
If you're on Python 2 use ``python-dev`` instead.
|
||||
|
||||
macOS
|
||||
=====
|
||||
|
||||
Install `Xcode <https://developer.apple.com/downloads/?name=Xcode>`__ then run::
|
||||
|
||||
pip3 install psutil
|
||||
|
||||
Windows
|
||||
=======
|
||||
|
||||
Open a cmd.exe shell and run::
|
||||
|
||||
python3 -m pip install psutil
|
||||
|
||||
This assumes "python" is in your PATH. If not, specify the full python.exe
|
||||
path.
|
||||
|
||||
In order to compile psutil from sources you'll need **Visual Studio** (Mingw32
|
||||
is not supported).
|
||||
This `blog post <https://blog.ionelmc.ro/2014/12/21/compiling-python-extensions-on-windows/>`__
|
||||
provides numerous info on how to properly set up VS. The needed VS versions are:
|
||||
|
||||
* Python 2.6, 2.7: `VS-2008 <http://www.microsoft.com/en-us/download/details.aspx?id=44266>`__
|
||||
* Python 3.4: `VS-2010 <http://www.visualstudio.com/downloads/download-visual-studio-vs#d-2010-express>`__
|
||||
* Python 3.5+: `VS-2015 <http://www.visualstudio.com/en-au/news/vs2015-preview-vs>`__
|
||||
|
||||
Compiling 64 bit versions of Python 2.6 and 2.7 with VS 2008 requires
|
||||
`Windows SDK and .NET Framework 3.5 SP1 <https://www.microsoft.com/en-us/download/details.aspx?id=3138>`__.
|
||||
Once installed run `vcvars64.bat`
|
||||
(see `here <http://stackoverflow.com/questions/11072521/>`__).
|
||||
Once VS is setup open a cmd.exe shell, cd into psutil directory and run::
|
||||
|
||||
python3 setup.py build
|
||||
python3 setup.py install
|
||||
|
||||
FreeBSD
|
||||
=======
|
||||
|
||||
::
|
||||
|
||||
pkg install python3 gcc
|
||||
python -m pip3 install psutil
|
||||
|
||||
OpenBSD
|
||||
=======
|
||||
|
||||
::
|
||||
|
||||
export PKG_PATH=http://ftp.eu.openbsd.org/pub/OpenBSD/`uname -r`/packages/`uname -m`/
|
||||
pkg_add -v python gcc
|
||||
python3 -m pip install psutil
|
||||
|
||||
NetBSD
|
||||
======
|
||||
|
||||
::
|
||||
|
||||
export PKG_PATH="ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/`uname -m`/`uname -r`/All"
|
||||
pkg_add -v pkgin
|
||||
pkgin install python3 gcc
|
||||
python3 -m pip install psutil
|
||||
|
||||
Solaris
|
||||
=======
|
||||
|
||||
If ``cc`` compiler is not installed create a symlink to ``gcc``::
|
||||
|
||||
sudo ln -s /usr/bin/gcc /usr/local/bin/cc
|
||||
|
||||
Install::
|
||||
|
||||
pkg install gcc
|
||||
python3 -m pip install psutil
|
||||
|
||||
Install from sources
|
||||
====================
|
||||
|
||||
::
|
||||
|
||||
git clone https://github.com/giampaolo/psutil.git
|
||||
cd psutil
|
||||
python3 setup.py install
|
||||
|
||||
Testing installation
|
||||
====================
|
||||
|
||||
::
|
||||
|
||||
python3 -m psutil.tests
|
||||
|
||||
Dev Guide
|
||||
=========
|
||||
|
||||
See: `dev guide <https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst>`__.
|
||||
29
third_party/python/psutil/LICENSE
vendored
Normal file
29
third_party/python/psutil/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola'
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the psutil authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
145
third_party/python/psutil/MANIFEST.in
vendored
Normal file
145
third_party/python/psutil/MANIFEST.in
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
include .cirrus.yml
|
||||
include .coveragerc
|
||||
include .gitignore
|
||||
include CREDITS
|
||||
include HISTORY.rst
|
||||
include INSTALL.rst
|
||||
include LICENSE
|
||||
include MANIFEST.in
|
||||
include Makefile
|
||||
include README.rst
|
||||
include docs/DEVGUIDE.rst
|
||||
include docs/DEVNOTES
|
||||
include docs/Makefile
|
||||
include docs/README
|
||||
include docs/_static/copybutton.js
|
||||
include docs/_static/css/custom.css
|
||||
include docs/_static/favicon.ico
|
||||
include docs/_static/sidebar.js
|
||||
include docs/conf.py
|
||||
include docs/index.rst
|
||||
include docs/make.bat
|
||||
include make.bat
|
||||
include psutil/__init__.py
|
||||
include psutil/_common.py
|
||||
include psutil/_compat.py
|
||||
include psutil/_psaix.py
|
||||
include psutil/_psbsd.py
|
||||
include psutil/_pslinux.py
|
||||
include psutil/_psosx.py
|
||||
include psutil/_psposix.py
|
||||
include psutil/_pssunos.py
|
||||
include psutil/_psutil_aix.c
|
||||
include psutil/_psutil_bsd.c
|
||||
include psutil/_psutil_common.c
|
||||
include psutil/_psutil_common.h
|
||||
include psutil/_psutil_linux.c
|
||||
include psutil/_psutil_osx.c
|
||||
include psutil/_psutil_posix.c
|
||||
include psutil/_psutil_posix.h
|
||||
include psutil/_psutil_sunos.c
|
||||
include psutil/_psutil_windows.c
|
||||
include psutil/_pswindows.py
|
||||
include psutil/arch/aix/common.c
|
||||
include psutil/arch/aix/common.h
|
||||
include psutil/arch/aix/ifaddrs.c
|
||||
include psutil/arch/aix/ifaddrs.h
|
||||
include psutil/arch/aix/net_connections.c
|
||||
include psutil/arch/aix/net_connections.h
|
||||
include psutil/arch/aix/net_kernel_structs.h
|
||||
include psutil/arch/freebsd/proc_socks.c
|
||||
include psutil/arch/freebsd/proc_socks.h
|
||||
include psutil/arch/freebsd/specific.c
|
||||
include psutil/arch/freebsd/specific.h
|
||||
include psutil/arch/freebsd/sys_socks.c
|
||||
include psutil/arch/freebsd/sys_socks.h
|
||||
include psutil/arch/netbsd/socks.c
|
||||
include psutil/arch/netbsd/socks.h
|
||||
include psutil/arch/netbsd/specific.c
|
||||
include psutil/arch/netbsd/specific.h
|
||||
include psutil/arch/openbsd/specific.c
|
||||
include psutil/arch/openbsd/specific.h
|
||||
include psutil/arch/osx/process_info.c
|
||||
include psutil/arch/osx/process_info.h
|
||||
include psutil/arch/solaris/environ.c
|
||||
include psutil/arch/solaris/environ.h
|
||||
include psutil/arch/solaris/v10/ifaddrs.c
|
||||
include psutil/arch/solaris/v10/ifaddrs.h
|
||||
include psutil/arch/windows/cpu.c
|
||||
include psutil/arch/windows/cpu.h
|
||||
include psutil/arch/windows/disk.c
|
||||
include psutil/arch/windows/disk.h
|
||||
include psutil/arch/windows/net.c
|
||||
include psutil/arch/windows/net.h
|
||||
include psutil/arch/windows/ntextapi.h
|
||||
include psutil/arch/windows/process_handles.c
|
||||
include psutil/arch/windows/process_handles.h
|
||||
include psutil/arch/windows/process_info.c
|
||||
include psutil/arch/windows/process_info.h
|
||||
include psutil/arch/windows/process_utils.c
|
||||
include psutil/arch/windows/process_utils.h
|
||||
include psutil/arch/windows/security.c
|
||||
include psutil/arch/windows/security.h
|
||||
include psutil/arch/windows/services.c
|
||||
include psutil/arch/windows/services.h
|
||||
include psutil/arch/windows/socks.c
|
||||
include psutil/arch/windows/socks.h
|
||||
include psutil/arch/windows/wmi.c
|
||||
include psutil/arch/windows/wmi.h
|
||||
include psutil/tests/README.rst
|
||||
include psutil/tests/__init__.py
|
||||
include psutil/tests/__main__.py
|
||||
include psutil/tests/runner.py
|
||||
include psutil/tests/test_aix.py
|
||||
include psutil/tests/test_bsd.py
|
||||
include psutil/tests/test_connections.py
|
||||
include psutil/tests/test_contracts.py
|
||||
include psutil/tests/test_linux.py
|
||||
include psutil/tests/test_memory_leaks.py
|
||||
include psutil/tests/test_misc.py
|
||||
include psutil/tests/test_osx.py
|
||||
include psutil/tests/test_posix.py
|
||||
include psutil/tests/test_process.py
|
||||
include psutil/tests/test_sunos.py
|
||||
include psutil/tests/test_system.py
|
||||
include psutil/tests/test_unicode.py
|
||||
include psutil/tests/test_windows.py
|
||||
include scripts/battery.py
|
||||
include scripts/cpu_distribution.py
|
||||
include scripts/disk_usage.py
|
||||
include scripts/fans.py
|
||||
include scripts/free.py
|
||||
include scripts/ifconfig.py
|
||||
include scripts/internal/.git-pre-commit
|
||||
include scripts/internal/README
|
||||
include scripts/internal/bench_oneshot.py
|
||||
include scripts/internal/bench_oneshot_2.py
|
||||
include scripts/internal/check_broken_links.py
|
||||
include scripts/internal/clinter.py
|
||||
include scripts/internal/fix_flake8.py
|
||||
include scripts/internal/generate_manifest.py
|
||||
include scripts/internal/print_access_denied.py
|
||||
include scripts/internal/print_announce.py
|
||||
include scripts/internal/print_api_speed.py
|
||||
include scripts/internal/print_timeline.py
|
||||
include scripts/internal/purge_installation.py
|
||||
include scripts/internal/win_download_wheels.py
|
||||
include scripts/internal/winmake.py
|
||||
include scripts/iotop.py
|
||||
include scripts/killall.py
|
||||
include scripts/meminfo.py
|
||||
include scripts/netstat.py
|
||||
include scripts/nettop.py
|
||||
include scripts/pidof.py
|
||||
include scripts/pmap.py
|
||||
include scripts/procinfo.py
|
||||
include scripts/procsmem.py
|
||||
include scripts/ps.py
|
||||
include scripts/pstree.py
|
||||
include scripts/sensors.py
|
||||
include scripts/temperatures.py
|
||||
include scripts/top.py
|
||||
include scripts/who.py
|
||||
include scripts/winservices.py
|
||||
include setup.py
|
||||
include tox.ini
|
||||
292
third_party/python/psutil/Makefile
vendored
Normal file
292
third_party/python/psutil/Makefile
vendored
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
# Shortcuts for various tasks (UNIX only).
|
||||
# To use a specific Python version run: "make install PYTHON=python3.3"
|
||||
# You can set the variables below from the command line.
|
||||
|
||||
PYTHON = python3
|
||||
TSCRIPT = psutil/tests/runner.py
|
||||
ARGS =
|
||||
# List of nice-to-have dev libs.
|
||||
DEPS = \
|
||||
argparse \
|
||||
check-manifest \
|
||||
coverage \
|
||||
flake8 \
|
||||
pyperf \
|
||||
requests \
|
||||
setuptools \
|
||||
twine \
|
||||
virtualenv \
|
||||
wheel
|
||||
PY2_DEPS = \
|
||||
futures \
|
||||
ipaddress \
|
||||
mock==1.0.1 \
|
||||
unittest2
|
||||
DEPS += `$(PYTHON) -c \
|
||||
"import sys; print('$(PY2_DEPS)' if sys.version_info[0] == 2 else '')"`
|
||||
# In not in a virtualenv, add --user options for install commands.
|
||||
INSTALL_OPTS = `$(PYTHON) -c \
|
||||
"import sys; print('' if hasattr(sys, 'real_prefix') else '--user')"`
|
||||
TEST_PREFIX = PYTHONWARNINGS=all PSUTIL_TESTING=1 PSUTIL_DEBUG=1
|
||||
|
||||
all: test
|
||||
|
||||
# ===================================================================
|
||||
# Install
|
||||
# ===================================================================
|
||||
|
||||
clean: ## Remove all build files.
|
||||
rm -rf `find . -type d -name __pycache__ \
|
||||
-o -type f -name \*.bak \
|
||||
-o -type f -name \*.orig \
|
||||
-o -type f -name \*.pyc \
|
||||
-o -type f -name \*.pyd \
|
||||
-o -type f -name \*.pyo \
|
||||
-o -type f -name \*.rej \
|
||||
-o -type f -name \*.so \
|
||||
-o -type f -name \*.~ \
|
||||
-o -type f -name \*\$testfn`
|
||||
rm -rf \
|
||||
*.core \
|
||||
*.egg-info \
|
||||
*\$testfn* \
|
||||
.coverage \
|
||||
.failed-tests.txt \
|
||||
.tox \
|
||||
build/ \
|
||||
dist/ \
|
||||
docs/_build/ \
|
||||
htmlcov/
|
||||
|
||||
_:
|
||||
|
||||
build: _ ## Compile without installing.
|
||||
# make sure setuptools is installed (needed for 'develop' / edit mode)
|
||||
$(PYTHON) -c "import setuptools"
|
||||
PYTHONWARNINGS=all $(PYTHON) setup.py build
|
||||
@# copies compiled *.so files in ./psutil directory in order to allow
|
||||
@# "import psutil" when using the interactive interpreter from within
|
||||
@# this directory.
|
||||
PYTHONWARNINGS=all $(PYTHON) setup.py build_ext -i
|
||||
$(PYTHON) -c "import psutil" # make sure it actually worked
|
||||
|
||||
install: ## Install this package as current user in "edit" mode.
|
||||
${MAKE} build
|
||||
PYTHONWARNINGS=all $(PYTHON) setup.py develop $(INSTALL_OPTS)
|
||||
|
||||
uninstall: ## Uninstall this package via pip.
|
||||
cd ..; $(PYTHON) -m pip uninstall -y -v psutil || true
|
||||
$(PYTHON) scripts/internal/purge_installation.py
|
||||
|
||||
install-pip: ## Install pip (no-op if already installed).
|
||||
$(PYTHON) -c \
|
||||
"import sys, ssl, os, pkgutil, tempfile, atexit; \
|
||||
sys.exit(0) if pkgutil.find_loader('pip') else None; \
|
||||
pyexc = 'from urllib.request import urlopen' if sys.version_info[0] == 3 else 'from urllib2 import urlopen'; \
|
||||
exec(pyexc); \
|
||||
ctx = ssl._create_unverified_context() if hasattr(ssl, '_create_unverified_context') else None; \
|
||||
kw = dict(context=ctx) if ctx else {}; \
|
||||
req = urlopen('https://bootstrap.pypa.io/get-pip.py', **kw); \
|
||||
data = req.read(); \
|
||||
f = tempfile.NamedTemporaryFile(suffix='.py'); \
|
||||
atexit.register(f.close); \
|
||||
f.write(data); \
|
||||
f.flush(); \
|
||||
print('downloaded %s' % f.name); \
|
||||
code = os.system('%s %s --user' % (sys.executable, f.name)); \
|
||||
f.close(); \
|
||||
sys.exit(code);"
|
||||
|
||||
setup-dev-env: ## Install GIT hooks, pip, test deps (also upgrades them).
|
||||
${MAKE} install-git-hooks
|
||||
${MAKE} install-pip
|
||||
$(PYTHON) -m pip install $(INSTALL_OPTS) --upgrade --trusted-host files.pythonhosted.org pip
|
||||
$(PYTHON) -m pip install $(INSTALL_OPTS) --upgrade --trusted-host files.pythonhosted.org $(DEPS)
|
||||
|
||||
# ===================================================================
|
||||
# Tests
|
||||
# ===================================================================
|
||||
|
||||
test: ## Run all tests.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) $(TSCRIPT)
|
||||
|
||||
test-process: ## Run process-related API tests.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_process.py
|
||||
|
||||
test-system: ## Run system-related API tests.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_system.py
|
||||
|
||||
test-misc: ## Run miscellaneous tests.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_misc.py
|
||||
|
||||
test-unicode: ## Test APIs dealing with strings.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_unicode.py
|
||||
|
||||
test-contracts: ## APIs sanity tests.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_contracts.py
|
||||
|
||||
test-connections: ## Test net_connections() and Process.connections().
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_connections.py
|
||||
|
||||
test-posix: ## POSIX specific tests.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_posix.py
|
||||
|
||||
test-platform: ## Run specific platform tests only.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_`$(PYTHON) -c 'import psutil; print([x.lower() for x in ("LINUX", "BSD", "OSX", "SUNOS", "WINDOWS", "AIX") if getattr(psutil, x)][0])'`.py
|
||||
|
||||
test-memleaks: ## Memory leak tests.
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_memory_leaks.py
|
||||
|
||||
test-by-name: ## e.g. make test-by-name ARGS=psutil.tests.test_system.TestSystemAPIs
|
||||
${MAKE} install
|
||||
@$(TEST_PREFIX) $(PYTHON) -m unittest -v $(ARGS)
|
||||
|
||||
test-failed: ## Re-run tests which failed on last run
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) $(TSCRIPT) --last-failed
|
||||
|
||||
test-coverage: ## Run test coverage.
|
||||
${MAKE} install
|
||||
# Note: coverage options are controlled by .coveragerc file
|
||||
rm -rf .coverage htmlcov
|
||||
$(TEST_PREFIX) $(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
|
||||
|
||||
# ===================================================================
|
||||
# Linters
|
||||
# ===================================================================
|
||||
|
||||
lint-py: ## Run Python (flake8) linter.
|
||||
@git ls-files '*.py' | xargs $(PYTHON) -m flake8
|
||||
|
||||
lint-c: ## Run C linter.
|
||||
@git ls-files '*.c' '*.h' | xargs $(PYTHON) scripts/internal/clinter.py
|
||||
|
||||
lint: ## Run Python (flake8) and C linters.
|
||||
${MAKE} lint-py
|
||||
${MAKE} lint-c
|
||||
|
||||
fix-lint: ## Attempt to automatically fix some Python lint issues.
|
||||
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8 --exit-zero | $(PYTHON) scripts/internal/fix_flake8.py
|
||||
|
||||
# ===================================================================
|
||||
# GIT
|
||||
# ===================================================================
|
||||
|
||||
git-tag-release: ## Git-tag a new release.
|
||||
git tag -a release-`python -c "import setup; print(setup.get_version())"` -m `git rev-list HEAD --count`:`git rev-parse --short HEAD`
|
||||
git push --follow-tags
|
||||
|
||||
install-git-hooks: ## Install GIT pre-commit hook.
|
||||
ln -sf ../../scripts/internal/.git-pre-commit .git/hooks/pre-commit
|
||||
chmod +x .git/hooks/pre-commit
|
||||
|
||||
# ===================================================================
|
||||
# Distribution
|
||||
# ===================================================================
|
||||
|
||||
sdist: ## Create tar.gz source distribution.
|
||||
${MAKE} generate-manifest
|
||||
$(PYTHON) setup.py sdist
|
||||
|
||||
wheel: ## Generate wheel.
|
||||
$(PYTHON) setup.py bdist_wheel
|
||||
|
||||
win-download-wheels: ## Download wheels hosted on appveyor.
|
||||
$(TEST_PREFIX) $(PYTHON) scripts/internal/win_download_wheels.py --user giampaolo --project psutil
|
||||
|
||||
upload-src: ## Upload source tarball on https://pypi.org/project/psutil/
|
||||
${MAKE} sdist
|
||||
$(PYTHON) setup.py sdist upload
|
||||
|
||||
upload-win-wheels: ## Upload wheels in dist/* directory on PyPI.
|
||||
$(PYTHON) -m twine upload dist/*.whl
|
||||
|
||||
# --- others
|
||||
|
||||
check-sdist: ## Create source distribution and checks its sanity (MANIFEST)
|
||||
rm -rf dist
|
||||
${MAKE} clean
|
||||
$(PYTHON) -m virtualenv --clear --no-wheel --quiet build/venv
|
||||
PYTHONWARNINGS=all $(PYTHON) setup.py sdist
|
||||
build/venv/bin/python -m pip install -v --isolated --quiet dist/*.tar.gz
|
||||
build/venv/bin/python -c "import os; os.chdir('build/venv'); import psutil"
|
||||
|
||||
pre-release: ## Check if we're ready to produce a new release.
|
||||
${MAKE} check-sdist
|
||||
${MAKE} install
|
||||
${MAKE} generate-manifest
|
||||
git diff MANIFEST.in > /dev/null # ...otherwise 'git diff-index HEAD' will complain
|
||||
${MAKE} win-download-wheels
|
||||
${MAKE} sdist
|
||||
$(PYTHON) -c \
|
||||
"from psutil import __version__ as ver; \
|
||||
doc = open('docs/index.rst').read(); \
|
||||
history = open('HISTORY.rst').read(); \
|
||||
assert ver in doc, '%r not in docs/index.rst' % ver; \
|
||||
assert ver in history, '%r not in HISTORY.rst' % ver; \
|
||||
assert 'XXXX' not in history, 'XXXX in HISTORY.rst';"
|
||||
$(PYTHON) -c "import subprocess, sys; out = subprocess.check_output('git diff --quiet && git diff --cached --quiet', shell=True).strip(); sys.exit('there are uncommitted changes:\n%s' % out) if out else 0 ;"
|
||||
|
||||
release: ## Create a release (down/uploads tar.gz, wheels, git tag release).
|
||||
${MAKE} pre-release
|
||||
$(PYTHON) -m twine upload dist/* # upload tar.gz and Windows wheels on PyPI
|
||||
${MAKE} git-tag-release
|
||||
|
||||
check-manifest: ## Inspect MANIFEST.in file.
|
||||
$(PYTHON) -m check_manifest -v $(ARGS)
|
||||
|
||||
generate-manifest: ## Generates MANIFEST.in file.
|
||||
$(PYTHON) scripts/internal/generate_manifest.py > MANIFEST.in
|
||||
|
||||
# ===================================================================
|
||||
# Printers
|
||||
# ===================================================================
|
||||
|
||||
print-announce: ## Print announce of new release.
|
||||
@$(PYTHON) scripts/internal/print_announce.py
|
||||
|
||||
print-timeline: ## Print releases' timeline.
|
||||
@$(PYTHON) scripts/internal/print_timeline.py
|
||||
|
||||
print-access-denied: ## Print AD exceptions
|
||||
${MAKE} install
|
||||
@$(TEST_PREFIX) $(PYTHON) scripts/internal/print_access_denied.py
|
||||
|
||||
print-api-speed: ## Benchmark all API calls
|
||||
${MAKE} install
|
||||
@$(TEST_PREFIX) $(PYTHON) scripts/internal/print_api_speed.py $(ARGS)
|
||||
|
||||
# ===================================================================
|
||||
# Misc
|
||||
# ===================================================================
|
||||
|
||||
grep-todos: ## Look for TODOs in the source files.
|
||||
git grep -EIn "TODO|FIXME|XXX"
|
||||
|
||||
bench-oneshot: ## Benchmarks for oneshot() ctx manager (see #799).
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) scripts/internal/bench_oneshot.py
|
||||
|
||||
bench-oneshot-2: ## Same as above but using perf module (supposed to be more precise)
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) scripts/internal/bench_oneshot_2.py
|
||||
|
||||
check-broken-links: ## Look for broken links in source files.
|
||||
git ls-files | xargs $(PYTHON) -Wa scripts/internal/check_broken_links.py
|
||||
|
||||
help: ## Display callable targets.
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
||||
578
third_party/python/psutil/PKG-INFO
vendored
Normal file
578
third_party/python/psutil/PKG-INFO
vendored
Normal file
|
|
@ -0,0 +1,578 @@
|
|||
Metadata-Version: 1.2
|
||||
Name: psutil
|
||||
Version: 5.7.0
|
||||
Summary: Cross-platform lib for process and system monitoring in Python.
|
||||
Home-page: https://github.com/giampaolo/psutil
|
||||
Author: Giampaolo Rodola
|
||||
Author-email: g.rodola@gmail.com
|
||||
License: BSD
|
||||
Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
||||
| |version| |py-versions| |packages| |license|
|
||||
| |travis| |appveyor| |cirrus| |doc| |twitter| |tidelift|
|
||||
|
||||
.. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pepy.tech/project/psutil
|
||||
:alt: Downloads
|
||||
|
||||
.. |stars| image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/stargazers
|
||||
:alt: Github stars
|
||||
|
||||
.. |forks| image:: https://img.shields.io/github/forks/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/network/members
|
||||
:alt: Github forks
|
||||
|
||||
.. |contributors| image:: https://img.shields.io/github/contributors/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/graphs/contributors
|
||||
:alt: Contributors
|
||||
|
||||
.. |quality| image:: https://img.shields.io/codacy/grade/ce63e7f7f69d44b5b59682196e6fbfca.svg
|
||||
:target: https://www.codacy.com/app/g-rodola/psutil?utm_source=github.com&utm_medium=referral&utm_content=giampaolo/psutil&utm_campaign=Badge_Grade
|
||||
:alt: Code quality
|
||||
|
||||
.. |travis| image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux,%20OSX,%20PyPy
|
||||
:target: https://travis-ci.org/giampaolo/psutil
|
||||
:alt: Linux tests (Travis)
|
||||
|
||||
.. |appveyor| image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
|
||||
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
||||
:alt: Windows tests (Appveyor)
|
||||
|
||||
.. |cirrus| image:: https://img.shields.io/cirrus/github/giampaolo/psutil?label=FreeBSD
|
||||
:target: https://cirrus-ci.com/github/giampaolo/psutil-cirrus-ci
|
||||
:alt: FreeBSD tests (Cirrus-Ci)
|
||||
|
||||
.. |coverage| image:: https://img.shields.io/coveralls/github/giampaolo/psutil.svg?label=test%20coverage
|
||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||
:alt: Test coverage (coverall.io)
|
||||
|
||||
.. |doc| image:: https://readthedocs.org/projects/psutil/badge/?version=latest
|
||||
:target: http://psutil.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. |version| image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
|
||||
:target: https://pypi.org/project/psutil
|
||||
:alt: Latest version
|
||||
|
||||
.. |py-versions| image:: https://img.shields.io/pypi/pyversions/psutil.svg
|
||||
:target: https://pypi.org/project/psutil
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. |packages| image:: https://repology.org/badge/tiny-repos/python:psutil.svg
|
||||
:target: https://repology.org/metapackage/python:psutil/versions
|
||||
:alt: Binary packages
|
||||
|
||||
.. |license| image:: https://img.shields.io/pypi/l/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/blob/master/LICENSE
|
||||
:alt: License
|
||||
|
||||
.. |twitter| image:: https://img.shields.io/twitter/follow/grodola.svg?label=follow&style=flat&logo=twitter&logoColor=4FADFF
|
||||
:target: https://twitter.com/grodola
|
||||
:alt: Twitter Follow
|
||||
|
||||
.. |tidelift| image:: https://tidelift.com/badges/github/giampaolo/psutil?style=flat
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
:alt: Tidelift
|
||||
|
||||
-----
|
||||
|
||||
Quick links
|
||||
===========
|
||||
|
||||
- `Home page <https://github.com/giampaolo/psutil>`_
|
||||
- `Install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
||||
- `Documentation <http://psutil.readthedocs.io>`_
|
||||
- `Download <https://pypi.org/project/psutil/#files>`_
|
||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
||||
- `StackOverflow <https://stackoverflow.com/questions/tagged/psutil>`_
|
||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst>`_
|
||||
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
|
||||
|
||||
Summary
|
||||
=======
|
||||
|
||||
psutil (process and system utilities) is a cross-platform library for
|
||||
retrieving information on **running processes** and **system utilization**
|
||||
(CPU, memory, disks, network, sensors) in Python.
|
||||
It is useful mainly for **system monitoring**, **profiling and limiting process
|
||||
resources** and **management of running processes**.
|
||||
It implements many functionalities offered by classic UNIX command line tools
|
||||
such as *ps, top, iotop, lsof, netstat, ifconfig, free* and others.
|
||||
psutil currently supports the following platforms:
|
||||
|
||||
- **Linux**
|
||||
- **Windows**
|
||||
- **macOS**
|
||||
- **FreeBSD, OpenBSD**, **NetBSD**
|
||||
- **Sun Solaris**
|
||||
- **AIX**
|
||||
|
||||
...both **32-bit** and **64-bit** architectures. Supported Python versions are **2.6**, **2.7** and **3.4+**. `PyPy3 <http://pypy.org/>`__ is also known to work.
|
||||
|
||||
psutil for enterprise
|
||||
=====================
|
||||
|
||||
.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png
|
||||
:width: 150
|
||||
:alt: Tidelift
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 150
|
||||
|
||||
* - |tideliftlogo|
|
||||
- The maintainer of psutil and thousands of other packages are working
|
||||
with Tidelift to deliver commercial support and maintenance for the open
|
||||
source dependencies you use to build your applications. Save time,
|
||||
reduce risk, and improve code health, while paying the maintainers of
|
||||
the exact dependencies you use.
|
||||
`Learn more <https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`__.
|
||||
|
||||
By subscribing to Tidelift you will help me (`Giampaolo Rodola`_) support
|
||||
psutil future development. Alternatively consider making a small
|
||||
`donation`_.
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
To report a security vulnerability, please use the `Tidelift security
|
||||
contact`_. Tidelift will coordinate the fix and disclosure.
|
||||
|
||||
Example applications
|
||||
====================
|
||||
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/top-small.png |
|
||||
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/top.png |
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap-small.png |
|
||||
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap.png |
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
|
||||
Also see `scripts directory <https://github.com/giampaolo/psutil/tree/master/scripts>`__
|
||||
and `doc recipes <http://psutil.readthedocs.io/#recipes/>`__.
|
||||
|
||||
Projects using psutil
|
||||
=====================
|
||||
|
||||
psutil has roughly the following monthly downloads:
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pepy.tech/project/psutil
|
||||
:alt: Downloads
|
||||
|
||||
There are over
|
||||
`10.000 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
|
||||
on github which depend from psutil.
|
||||
Here's some I find particularly interesting:
|
||||
|
||||
- https://github.com/google/grr
|
||||
- https://github.com/facebook/osquery/
|
||||
- https://github.com/nicolargo/glances
|
||||
- https://github.com/Jahaja/psdash
|
||||
- https://github.com/ajenti/ajenti
|
||||
- https://github.com/home-assistant/home-assistant/
|
||||
|
||||
|
||||
Portings
|
||||
========
|
||||
|
||||
- Go: https://github.com/shirou/gopsutil
|
||||
- C: https://github.com/hamon-in/cpslib
|
||||
- Rust: https://github.com/borntyping/rust-psutil
|
||||
- Nim: https://github.com/johnscillieri/psutil-nim
|
||||
|
||||
|
||||
Example usages
|
||||
==============
|
||||
|
||||
This represents pretty much the whole psutil API.
|
||||
|
||||
CPU
|
||||
---
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>>
|
||||
>>> psutil.cpu_times()
|
||||
scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1)
|
||||
...
|
||||
4.0
|
||||
5.9
|
||||
3.8
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1, percpu=True)
|
||||
...
|
||||
[4.0, 6.9, 3.7, 9.2]
|
||||
[7.0, 8.5, 2.4, 2.1]
|
||||
[1.2, 9.0, 9.9, 7.2]
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_times_percent(interval=1, percpu=False)
|
||||
...
|
||||
scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
>>>
|
||||
>>> psutil.cpu_count()
|
||||
4
|
||||
>>> psutil.cpu_count(logical=False)
|
||||
2
|
||||
>>>
|
||||
>>> psutil.cpu_stats()
|
||||
scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
|
||||
>>>
|
||||
>>> psutil.cpu_freq()
|
||||
scpufreq(current=931.42925, min=800.0, max=3500.0)
|
||||
>>>
|
||||
>>> psutil.getloadavg() # also on Windows (emulated)
|
||||
(3.14, 3.89, 4.67)
|
||||
|
||||
Memory
|
||||
------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.virtual_memory()
|
||||
svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)
|
||||
>>> psutil.swap_memory()
|
||||
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
||||
>>>
|
||||
|
||||
Disks
|
||||
-----
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.disk_partitions()
|
||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
||||
>>>
|
||||
>>> psutil.disk_usage('/')
|
||||
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
||||
>>>
|
||||
>>> psutil.disk_io_counters(perdisk=False)
|
||||
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)
|
||||
>>>
|
||||
|
||||
Network
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.net_io_counters(pernic=True)
|
||||
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
||||
'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()
|
||||
[sconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
|
||||
sconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),
|
||||
...]
|
||||
>>>
|
||||
>>> psutil.net_if_addrs()
|
||||
{'lo': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
|
||||
'wlan0': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
|
||||
snicaddr(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()
|
||||
{'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536),
|
||||
'wlan0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500)}
|
||||
>>>
|
||||
|
||||
Sensors
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.sensors_temperatures()
|
||||
{'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
|
||||
'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
|
||||
'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
|
||||
shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0)]}
|
||||
>>>
|
||||
>>> psutil.sensors_fans()
|
||||
{'asus': [sfan(label='cpu_fan', current=3200)]}
|
||||
>>>
|
||||
>>> psutil.sensors_battery()
|
||||
sbattery(percent=93, secsleft=16628, power_plugged=False)
|
||||
>>>
|
||||
|
||||
Other system info
|
||||
-----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.users()
|
||||
[suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),
|
||||
suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]
|
||||
>>>
|
||||
>>> psutil.boot_time()
|
||||
1365519115.0
|
||||
>>>
|
||||
|
||||
Process management
|
||||
------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.pids()
|
||||
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244,
|
||||
1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282,
|
||||
4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446,
|
||||
5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
||||
>>>
|
||||
>>> p = psutil.Process(7055)
|
||||
>>> p
|
||||
psutil.Process(pid=7055, name='python', started='09:04:44')
|
||||
>>> p.name()
|
||||
'python'
|
||||
>>> p.exe()
|
||||
'/usr/bin/python'
|
||||
>>> p.cwd()
|
||||
'/home/giampaolo'
|
||||
>>> p.cmdline()
|
||||
['/usr/bin/python', 'main.py']
|
||||
>>>
|
||||
>>> p.pid
|
||||
7055
|
||||
>>> p.ppid()
|
||||
7054
|
||||
>>> p.children(recursive=True)
|
||||
[psutil.Process(pid=29835, name='python2.7', started='11:45:38'),
|
||||
psutil.Process(pid=29836, name='python2.7', started='11:43:39')]
|
||||
>>>
|
||||
>>> p.parent()
|
||||
psutil.Process(pid=4699, name='bash', started='09:06:44')
|
||||
>>> p.parents()
|
||||
[psutil.Process(pid=4699, name='bash', started='09:06:44'),
|
||||
psutil.Process(pid=4689, name='gnome-terminal-server', started='0:06:44'),
|
||||
psutil.Process(pid=1, name='systemd', started='05:56:55')]
|
||||
>>>
|
||||
>>> p.status()
|
||||
'running'
|
||||
>>> p.username()
|
||||
'giampaolo'
|
||||
>>> p.create_time()
|
||||
1267551141.5019531
|
||||
>>> p.terminal()
|
||||
'/dev/pts/0'
|
||||
>>>
|
||||
>>> p.uids()
|
||||
puids(real=1000, effective=1000, saved=1000)
|
||||
>>> p.gids()
|
||||
pgids(real=1000, effective=1000, saved=1000)
|
||||
>>>
|
||||
>>> p.cpu_times()
|
||||
pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1, iowait=0.0)
|
||||
>>> p.cpu_percent(interval=1.0)
|
||||
12.1
|
||||
>>> p.cpu_affinity()
|
||||
[0, 1, 2, 3]
|
||||
>>> p.cpu_affinity([0, 1]) # set
|
||||
>>> p.cpu_num()
|
||||
1
|
||||
>>>
|
||||
>>> p.memory_info()
|
||||
pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)
|
||||
>>> p.memory_full_info() # "real" USS memory usage (Linux, macOS, Win only)
|
||||
pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)
|
||||
>>> p.memory_percent()
|
||||
0.7823
|
||||
>>> p.memory_maps()
|
||||
[pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),
|
||||
pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),
|
||||
pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
|
||||
pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
|
||||
...]
|
||||
>>>
|
||||
>>> p.io_counters()
|
||||
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
|
||||
>>>
|
||||
>>> p.open_files()
|
||||
[popenfile(path='/home/giampaolo/monit.py', fd=3, position=0, mode='r', flags=32768),
|
||||
popenfile(path='/var/log/monit.log', fd=4, position=235542, mode='a', flags=33793)]
|
||||
>>>
|
||||
>>> p.connections()
|
||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
|
||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING')]
|
||||
>>>
|
||||
>>> p.num_threads()
|
||||
4
|
||||
>>> p.num_fds()
|
||||
8
|
||||
>>> p.threads()
|
||||
[pthread(id=5234, user_time=22.5, system_time=9.2891),
|
||||
pthread(id=5237, user_time=0.0707, system_time=1.1)]
|
||||
>>>
|
||||
>>> p.num_ctx_switches()
|
||||
pctxsw(voluntary=78, involuntary=19)
|
||||
>>>
|
||||
>>> p.nice()
|
||||
0
|
||||
>>> p.nice(10) # set
|
||||
>>>
|
||||
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)
|
||||
>>> p.ionice()
|
||||
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)
|
||||
(5, 5)
|
||||
>>>
|
||||
>>> p.environ()
|
||||
{'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',
|
||||
'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg',
|
||||
...}
|
||||
>>>
|
||||
>>> p.as_dict()
|
||||
{'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}
|
||||
>>> p.is_running()
|
||||
True
|
||||
>>> p.suspend()
|
||||
>>> p.resume()
|
||||
>>>
|
||||
>>> p.terminate()
|
||||
>>> p.kill()
|
||||
>>> p.wait(timeout=3)
|
||||
0
|
||||
>>>
|
||||
>>> psutil.test()
|
||||
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
|
||||
root 1 0.0 0.0 24584 2240 Jun17 00:00 init
|
||||
root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd
|
||||
...
|
||||
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
|
||||
giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome
|
||||
root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1
|
||||
>>>
|
||||
|
||||
Further process APIs
|
||||
--------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> for proc in psutil.process_iter(['pid', 'name']):
|
||||
... print(proc.info)
|
||||
...
|
||||
{'pid': 1, 'name': 'systemd'}
|
||||
{'pid': 2, 'name': 'kthreadd'}
|
||||
{'pid': 3, 'name': 'ksoftirqd/0'}
|
||||
...
|
||||
>>>
|
||||
>>> psutil.pid_exists(3)
|
||||
True
|
||||
>>>
|
||||
>>> def on_terminate(proc):
|
||||
... print("process {} terminated".format(proc))
|
||||
...
|
||||
>>> # waits for multiple processes to terminate
|
||||
>>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)
|
||||
>>>
|
||||
|
||||
Popen wrapper:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> from subprocess import PIPE
|
||||
>>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE)
|
||||
>>> p.name()
|
||||
'python'
|
||||
>>> p.username()
|
||||
'giampaolo'
|
||||
>>> p.communicate()
|
||||
('hello\n', None)
|
||||
>>> p.wait(timeout=2)
|
||||
0
|
||||
>>>
|
||||
|
||||
Windows services
|
||||
----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> list(psutil.win_service_iter())
|
||||
[<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
|
||||
<WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
|
||||
<WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
|
||||
<WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
|
||||
...]
|
||||
>>> s = psutil.win_service_get('alg')
|
||||
>>> s.as_dict()
|
||||
{'binpath': 'C:\\Windows\\System32\\alg.exe',
|
||||
'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
|
||||
'display_name': 'Application Layer Gateway Service',
|
||||
'name': 'alg',
|
||||
'pid': None,
|
||||
'start_type': 'manual',
|
||||
'status': 'stopped',
|
||||
'username': 'NT AUTHORITY\\LocalService'}
|
||||
|
||||
|
||||
.. _`Giampaolo Rodola`: http://grodola.blogspot.com/p/about.html
|
||||
.. _`donation`: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||
.. _Tidelift security contact: https://tidelift.com/security
|
||||
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
|
||||
|
||||
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit,smem,performance,metrics,agent,observability
|
||||
Platform: Platform Independent
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Environment :: Win32 (MS Windows)
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: MacOS :: MacOS X
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows 7
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows 8
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows 8.1
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows Server 2003
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows Server 2008
|
||||
Classifier: Operating System :: Microsoft :: Windows :: Windows Vista
|
||||
Classifier: Operating System :: Microsoft
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Operating System :: POSIX :: AIX
|
||||
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
|
||||
Classifier: Operating System :: POSIX :: BSD :: NetBSD
|
||||
Classifier: Operating System :: POSIX :: BSD :: OpenBSD
|
||||
Classifier: Operating System :: POSIX :: BSD
|
||||
Classifier: Operating System :: POSIX :: Linux
|
||||
Classifier: Operating System :: POSIX :: SunOS/Solaris
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Programming Language :: C
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: Software Development :: Libraries
|
||||
Classifier: Topic :: System :: Benchmark
|
||||
Classifier: Topic :: System :: Hardware :: Hardware Drivers
|
||||
Classifier: Topic :: System :: Hardware
|
||||
Classifier: Topic :: System :: Monitoring
|
||||
Classifier: Topic :: System :: Networking :: Monitoring :: Hardware Watchdog
|
||||
Classifier: Topic :: System :: Networking :: Monitoring
|
||||
Classifier: Topic :: System :: Networking
|
||||
Classifier: Topic :: System :: Operating System
|
||||
Classifier: Topic :: System :: Systems Administration
|
||||
Classifier: Topic :: Utilities
|
||||
Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
|
||||
521
third_party/python/psutil/README.rst
vendored
Normal file
521
third_party/python/psutil/README.rst
vendored
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
| |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
||||
| |version| |py-versions| |packages| |license|
|
||||
| |travis| |appveyor| |cirrus| |doc| |twitter| |tidelift|
|
||||
|
||||
.. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pepy.tech/project/psutil
|
||||
:alt: Downloads
|
||||
|
||||
.. |stars| image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/stargazers
|
||||
:alt: Github stars
|
||||
|
||||
.. |forks| image:: https://img.shields.io/github/forks/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/network/members
|
||||
:alt: Github forks
|
||||
|
||||
.. |contributors| image:: https://img.shields.io/github/contributors/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/graphs/contributors
|
||||
:alt: Contributors
|
||||
|
||||
.. |quality| image:: https://img.shields.io/codacy/grade/ce63e7f7f69d44b5b59682196e6fbfca.svg
|
||||
:target: https://www.codacy.com/app/g-rodola/psutil?utm_source=github.com&utm_medium=referral&utm_content=giampaolo/psutil&utm_campaign=Badge_Grade
|
||||
:alt: Code quality
|
||||
|
||||
.. |travis| image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux,%20OSX,%20PyPy
|
||||
:target: https://travis-ci.org/giampaolo/psutil
|
||||
:alt: Linux tests (Travis)
|
||||
|
||||
.. |appveyor| image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
|
||||
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
||||
:alt: Windows tests (Appveyor)
|
||||
|
||||
.. |cirrus| image:: https://img.shields.io/cirrus/github/giampaolo/psutil?label=FreeBSD
|
||||
:target: https://cirrus-ci.com/github/giampaolo/psutil-cirrus-ci
|
||||
:alt: FreeBSD tests (Cirrus-Ci)
|
||||
|
||||
.. |coverage| image:: https://img.shields.io/coveralls/github/giampaolo/psutil.svg?label=test%20coverage
|
||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||
:alt: Test coverage (coverall.io)
|
||||
|
||||
.. |doc| image:: https://readthedocs.org/projects/psutil/badge/?version=latest
|
||||
:target: http://psutil.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. |version| image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
|
||||
:target: https://pypi.org/project/psutil
|
||||
:alt: Latest version
|
||||
|
||||
.. |py-versions| image:: https://img.shields.io/pypi/pyversions/psutil.svg
|
||||
:target: https://pypi.org/project/psutil
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. |packages| image:: https://repology.org/badge/tiny-repos/python:psutil.svg
|
||||
:target: https://repology.org/metapackage/python:psutil/versions
|
||||
:alt: Binary packages
|
||||
|
||||
.. |license| image:: https://img.shields.io/pypi/l/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/blob/master/LICENSE
|
||||
:alt: License
|
||||
|
||||
.. |twitter| image:: https://img.shields.io/twitter/follow/grodola.svg?label=follow&style=flat&logo=twitter&logoColor=4FADFF
|
||||
:target: https://twitter.com/grodola
|
||||
:alt: Twitter Follow
|
||||
|
||||
.. |tidelift| image:: https://tidelift.com/badges/github/giampaolo/psutil?style=flat
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
:alt: Tidelift
|
||||
|
||||
-----
|
||||
|
||||
Quick links
|
||||
===========
|
||||
|
||||
- `Home page <https://github.com/giampaolo/psutil>`_
|
||||
- `Install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
||||
- `Documentation <http://psutil.readthedocs.io>`_
|
||||
- `Download <https://pypi.org/project/psutil/#files>`_
|
||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
||||
- `StackOverflow <https://stackoverflow.com/questions/tagged/psutil>`_
|
||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst>`_
|
||||
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
|
||||
|
||||
Summary
|
||||
=======
|
||||
|
||||
psutil (process and system utilities) is a cross-platform library for
|
||||
retrieving information on **running processes** and **system utilization**
|
||||
(CPU, memory, disks, network, sensors) in Python.
|
||||
It is useful mainly for **system monitoring**, **profiling and limiting process
|
||||
resources** and **management of running processes**.
|
||||
It implements many functionalities offered by classic UNIX command line tools
|
||||
such as *ps, top, iotop, lsof, netstat, ifconfig, free* and others.
|
||||
psutil currently supports the following platforms:
|
||||
|
||||
- **Linux**
|
||||
- **Windows**
|
||||
- **macOS**
|
||||
- **FreeBSD, OpenBSD**, **NetBSD**
|
||||
- **Sun Solaris**
|
||||
- **AIX**
|
||||
|
||||
...both **32-bit** and **64-bit** architectures. Supported Python versions are **2.6**, **2.7** and **3.4+**. `PyPy3 <http://pypy.org/>`__ is also known to work.
|
||||
|
||||
psutil for enterprise
|
||||
=====================
|
||||
|
||||
.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png
|
||||
:width: 150
|
||||
:alt: Tidelift
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 150
|
||||
|
||||
* - |tideliftlogo|
|
||||
- The maintainer of psutil and thousands of other packages are working
|
||||
with Tidelift to deliver commercial support and maintenance for the open
|
||||
source dependencies you use to build your applications. Save time,
|
||||
reduce risk, and improve code health, while paying the maintainers of
|
||||
the exact dependencies you use.
|
||||
`Learn more <https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`__.
|
||||
|
||||
By subscribing to Tidelift you will help me (`Giampaolo Rodola`_) support
|
||||
psutil future development. Alternatively consider making a small
|
||||
`donation`_.
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
To report a security vulnerability, please use the `Tidelift security
|
||||
contact`_. Tidelift will coordinate the fix and disclosure.
|
||||
|
||||
Example applications
|
||||
====================
|
||||
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/top-small.png |
|
||||
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/top.png |
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap-small.png |
|
||||
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap.png |
|
||||
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||
|
||||
Also see `scripts directory <https://github.com/giampaolo/psutil/tree/master/scripts>`__
|
||||
and `doc recipes <http://psutil.readthedocs.io/#recipes/>`__.
|
||||
|
||||
Projects using psutil
|
||||
=====================
|
||||
|
||||
psutil has roughly the following monthly downloads:
|
||||
|
||||
.. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pepy.tech/project/psutil
|
||||
:alt: Downloads
|
||||
|
||||
There are over
|
||||
`10.000 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
|
||||
on github which depend from psutil.
|
||||
Here's some I find particularly interesting:
|
||||
|
||||
- https://github.com/google/grr
|
||||
- https://github.com/facebook/osquery/
|
||||
- https://github.com/nicolargo/glances
|
||||
- https://github.com/Jahaja/psdash
|
||||
- https://github.com/ajenti/ajenti
|
||||
- https://github.com/home-assistant/home-assistant/
|
||||
|
||||
|
||||
Portings
|
||||
========
|
||||
|
||||
- Go: https://github.com/shirou/gopsutil
|
||||
- C: https://github.com/hamon-in/cpslib
|
||||
- Rust: https://github.com/borntyping/rust-psutil
|
||||
- Nim: https://github.com/johnscillieri/psutil-nim
|
||||
|
||||
|
||||
Example usages
|
||||
==============
|
||||
|
||||
This represents pretty much the whole psutil API.
|
||||
|
||||
CPU
|
||||
---
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>>
|
||||
>>> psutil.cpu_times()
|
||||
scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1)
|
||||
...
|
||||
4.0
|
||||
5.9
|
||||
3.8
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_percent(interval=1, percpu=True)
|
||||
...
|
||||
[4.0, 6.9, 3.7, 9.2]
|
||||
[7.0, 8.5, 2.4, 2.1]
|
||||
[1.2, 9.0, 9.9, 7.2]
|
||||
>>>
|
||||
>>> for x in range(3):
|
||||
... psutil.cpu_times_percent(interval=1, percpu=False)
|
||||
...
|
||||
scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
||||
>>>
|
||||
>>> psutil.cpu_count()
|
||||
4
|
||||
>>> psutil.cpu_count(logical=False)
|
||||
2
|
||||
>>>
|
||||
>>> psutil.cpu_stats()
|
||||
scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
|
||||
>>>
|
||||
>>> psutil.cpu_freq()
|
||||
scpufreq(current=931.42925, min=800.0, max=3500.0)
|
||||
>>>
|
||||
>>> psutil.getloadavg() # also on Windows (emulated)
|
||||
(3.14, 3.89, 4.67)
|
||||
|
||||
Memory
|
||||
------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.virtual_memory()
|
||||
svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)
|
||||
>>> psutil.swap_memory()
|
||||
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
||||
>>>
|
||||
|
||||
Disks
|
||||
-----
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.disk_partitions()
|
||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
||||
>>>
|
||||
>>> psutil.disk_usage('/')
|
||||
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
||||
>>>
|
||||
>>> psutil.disk_io_counters(perdisk=False)
|
||||
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)
|
||||
>>>
|
||||
|
||||
Network
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> psutil.net_io_counters(pernic=True)
|
||||
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
||||
'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()
|
||||
[sconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
|
||||
sconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),
|
||||
...]
|
||||
>>>
|
||||
>>> psutil.net_if_addrs()
|
||||
{'lo': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
|
||||
'wlan0': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
|
||||
snicaddr(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
|
||||
snicaddr(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()
|
||||
{'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536),
|
||||
'wlan0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500)}
|
||||
>>>
|
||||
|
||||
Sensors
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.sensors_temperatures()
|
||||
{'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
|
||||
'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
|
||||
'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
|
||||
shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0)]}
|
||||
>>>
|
||||
>>> psutil.sensors_fans()
|
||||
{'asus': [sfan(label='cpu_fan', current=3200)]}
|
||||
>>>
|
||||
>>> psutil.sensors_battery()
|
||||
sbattery(percent=93, secsleft=16628, power_plugged=False)
|
||||
>>>
|
||||
|
||||
Other system info
|
||||
-----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.users()
|
||||
[suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),
|
||||
suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]
|
||||
>>>
|
||||
>>> psutil.boot_time()
|
||||
1365519115.0
|
||||
>>>
|
||||
|
||||
Process management
|
||||
------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.pids()
|
||||
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244,
|
||||
1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282,
|
||||
4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446,
|
||||
5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
||||
>>>
|
||||
>>> p = psutil.Process(7055)
|
||||
>>> p
|
||||
psutil.Process(pid=7055, name='python', started='09:04:44')
|
||||
>>> p.name()
|
||||
'python'
|
||||
>>> p.exe()
|
||||
'/usr/bin/python'
|
||||
>>> p.cwd()
|
||||
'/home/giampaolo'
|
||||
>>> p.cmdline()
|
||||
['/usr/bin/python', 'main.py']
|
||||
>>>
|
||||
>>> p.pid
|
||||
7055
|
||||
>>> p.ppid()
|
||||
7054
|
||||
>>> p.children(recursive=True)
|
||||
[psutil.Process(pid=29835, name='python2.7', started='11:45:38'),
|
||||
psutil.Process(pid=29836, name='python2.7', started='11:43:39')]
|
||||
>>>
|
||||
>>> p.parent()
|
||||
psutil.Process(pid=4699, name='bash', started='09:06:44')
|
||||
>>> p.parents()
|
||||
[psutil.Process(pid=4699, name='bash', started='09:06:44'),
|
||||
psutil.Process(pid=4689, name='gnome-terminal-server', started='0:06:44'),
|
||||
psutil.Process(pid=1, name='systemd', started='05:56:55')]
|
||||
>>>
|
||||
>>> p.status()
|
||||
'running'
|
||||
>>> p.username()
|
||||
'giampaolo'
|
||||
>>> p.create_time()
|
||||
1267551141.5019531
|
||||
>>> p.terminal()
|
||||
'/dev/pts/0'
|
||||
>>>
|
||||
>>> p.uids()
|
||||
puids(real=1000, effective=1000, saved=1000)
|
||||
>>> p.gids()
|
||||
pgids(real=1000, effective=1000, saved=1000)
|
||||
>>>
|
||||
>>> p.cpu_times()
|
||||
pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1, iowait=0.0)
|
||||
>>> p.cpu_percent(interval=1.0)
|
||||
12.1
|
||||
>>> p.cpu_affinity()
|
||||
[0, 1, 2, 3]
|
||||
>>> p.cpu_affinity([0, 1]) # set
|
||||
>>> p.cpu_num()
|
||||
1
|
||||
>>>
|
||||
>>> p.memory_info()
|
||||
pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)
|
||||
>>> p.memory_full_info() # "real" USS memory usage (Linux, macOS, Win only)
|
||||
pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)
|
||||
>>> p.memory_percent()
|
||||
0.7823
|
||||
>>> p.memory_maps()
|
||||
[pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),
|
||||
pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),
|
||||
pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
|
||||
pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
|
||||
...]
|
||||
>>>
|
||||
>>> p.io_counters()
|
||||
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
|
||||
>>>
|
||||
>>> p.open_files()
|
||||
[popenfile(path='/home/giampaolo/monit.py', fd=3, position=0, mode='r', flags=32768),
|
||||
popenfile(path='/var/log/monit.log', fd=4, position=235542, mode='a', flags=33793)]
|
||||
>>>
|
||||
>>> p.connections()
|
||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
|
||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING')]
|
||||
>>>
|
||||
>>> p.num_threads()
|
||||
4
|
||||
>>> p.num_fds()
|
||||
8
|
||||
>>> p.threads()
|
||||
[pthread(id=5234, user_time=22.5, system_time=9.2891),
|
||||
pthread(id=5237, user_time=0.0707, system_time=1.1)]
|
||||
>>>
|
||||
>>> p.num_ctx_switches()
|
||||
pctxsw(voluntary=78, involuntary=19)
|
||||
>>>
|
||||
>>> p.nice()
|
||||
0
|
||||
>>> p.nice(10) # set
|
||||
>>>
|
||||
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)
|
||||
>>> p.ionice()
|
||||
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)
|
||||
(5, 5)
|
||||
>>>
|
||||
>>> p.environ()
|
||||
{'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',
|
||||
'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg',
|
||||
...}
|
||||
>>>
|
||||
>>> p.as_dict()
|
||||
{'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}
|
||||
>>> p.is_running()
|
||||
True
|
||||
>>> p.suspend()
|
||||
>>> p.resume()
|
||||
>>>
|
||||
>>> p.terminate()
|
||||
>>> p.kill()
|
||||
>>> p.wait(timeout=3)
|
||||
0
|
||||
>>>
|
||||
>>> psutil.test()
|
||||
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
|
||||
root 1 0.0 0.0 24584 2240 Jun17 00:00 init
|
||||
root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd
|
||||
...
|
||||
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
|
||||
giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome
|
||||
root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1
|
||||
>>>
|
||||
|
||||
Further process APIs
|
||||
--------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> for proc in psutil.process_iter(['pid', 'name']):
|
||||
... print(proc.info)
|
||||
...
|
||||
{'pid': 1, 'name': 'systemd'}
|
||||
{'pid': 2, 'name': 'kthreadd'}
|
||||
{'pid': 3, 'name': 'ksoftirqd/0'}
|
||||
...
|
||||
>>>
|
||||
>>> psutil.pid_exists(3)
|
||||
True
|
||||
>>>
|
||||
>>> def on_terminate(proc):
|
||||
... print("process {} terminated".format(proc))
|
||||
...
|
||||
>>> # waits for multiple processes to terminate
|
||||
>>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)
|
||||
>>>
|
||||
|
||||
Popen wrapper:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> from subprocess import PIPE
|
||||
>>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE)
|
||||
>>> p.name()
|
||||
'python'
|
||||
>>> p.username()
|
||||
'giampaolo'
|
||||
>>> p.communicate()
|
||||
('hello\n', None)
|
||||
>>> p.wait(timeout=2)
|
||||
0
|
||||
>>>
|
||||
|
||||
Windows services
|
||||
----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> list(psutil.win_service_iter())
|
||||
[<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
|
||||
<WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
|
||||
<WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
|
||||
<WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
|
||||
...]
|
||||
>>> s = psutil.win_service_get('alg')
|
||||
>>> s.as_dict()
|
||||
{'binpath': 'C:\\Windows\\System32\\alg.exe',
|
||||
'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
|
||||
'display_name': 'Application Layer Gateway Service',
|
||||
'name': 'alg',
|
||||
'pid': None,
|
||||
'start_type': 'manual',
|
||||
'status': 'stopped',
|
||||
'username': 'NT AUTHORITY\\LocalService'}
|
||||
|
||||
|
||||
.. _`Giampaolo Rodola`: http://grodola.blogspot.com/p/about.html
|
||||
.. _`donation`: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||
.. _Tidelift security contact: https://tidelift.com/security
|
||||
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
|
||||
37
third_party/python/psutil/make.bat
vendored
Normal file
37
third_party/python/psutil/make.bat
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
@echo off
|
||||
|
||||
rem ==========================================================================
|
||||
rem Shortcuts for various tasks, emulating UNIX "make" on Windows.
|
||||
rem It is primarly intended as a shortcut for compiling / installing
|
||||
rem psutil ("make.bat build", "make.bat install") and running tests
|
||||
rem ("make.bat test").
|
||||
rem
|
||||
rem This script is modeled after my Windows installation which uses:
|
||||
rem - Visual studio 2008 for Python 2.6, 2.7
|
||||
rem - Visual studio 2010 for Python 3.4+
|
||||
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 To use a different test script:
|
||||
rem set PYTHON=C:\Python34\python.exe & set TSCRIPT=foo.py & make.bat test
|
||||
rem ==========================================================================
|
||||
|
||||
if "%PYTHON%" == "" (
|
||||
if exist "C:\Python38-64\python.exe" (
|
||||
set PYTHON=C:\Python38-64\python.exe
|
||||
) else (
|
||||
set PYTHON=C:\Python27\python.exe
|
||||
)
|
||||
)
|
||||
|
||||
if "%TSCRIPT%" == "" (
|
||||
set TSCRIPT=psutil\tests\runner.py
|
||||
)
|
||||
|
||||
rem Needed to locate the .pypirc file and upload exes on PyPI.
|
||||
set HOME=%USERPROFILE%
|
||||
|
||||
%PYTHON% scripts\internal\winmake.py %1 %2 %3 %4 %5 %6
|
||||
2409
third_party/python/psutil/psutil/__init__.py
vendored
Normal file
2409
third_party/python/psutil/psutil/__init__.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
846
third_party/python/psutil/psutil/_common.py
vendored
Normal file
846
third_party/python/psutil/psutil/_common.py
vendored
Normal file
|
|
@ -0,0 +1,846 @@
|
|||
# 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.
|
||||
|
||||
"""Common objects shared by __init__.py and _ps*.py modules."""
|
||||
|
||||
# Note: this module is imported by setup.py so it should not import
|
||||
# psutil or third-party modules.
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import socket
|
||||
import stat
|
||||
import sys
|
||||
import threading
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET
|
||||
from socket import SOCK_DGRAM
|
||||
from socket import SOCK_STREAM
|
||||
|
||||
try:
|
||||
from socket import AF_INET6
|
||||
except ImportError:
|
||||
AF_INET6 = None
|
||||
try:
|
||||
from socket import AF_UNIX
|
||||
except ImportError:
|
||||
AF_UNIX = None
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
import enum
|
||||
else:
|
||||
enum = None
|
||||
|
||||
|
||||
# can't take it from _common.py as this script is imported by setup.py
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
__all__ = [
|
||||
# OS constants
|
||||
'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'MACOS', 'OSX', 'POSIX',
|
||||
'SUNOS', 'WINDOWS',
|
||||
# connection constants
|
||||
'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED',
|
||||
'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN',
|
||||
'CONN_NONE', 'CONN_SYN_RECV', 'CONN_SYN_SENT', 'CONN_TIME_WAIT',
|
||||
# net constants
|
||||
'NIC_DUPLEX_FULL', 'NIC_DUPLEX_HALF', 'NIC_DUPLEX_UNKNOWN',
|
||||
# process status constants
|
||||
'STATUS_DEAD', 'STATUS_DISK_SLEEP', 'STATUS_IDLE', 'STATUS_LOCKED',
|
||||
'STATUS_RUNNING', 'STATUS_SLEEPING', 'STATUS_STOPPED', 'STATUS_SUSPENDED',
|
||||
'STATUS_TRACING_STOP', 'STATUS_WAITING', 'STATUS_WAKE_KILL',
|
||||
'STATUS_WAKING', 'STATUS_ZOMBIE', 'STATUS_PARKED',
|
||||
# other constants
|
||||
'ENCODING', 'ENCODING_ERRS', 'AF_INET6',
|
||||
# named tuples
|
||||
'pconn', 'pcputimes', 'pctxsw', 'pgids', 'pio', 'pionice', 'popenfile',
|
||||
'pthread', 'puids', 'sconn', 'scpustats', 'sdiskio', 'sdiskpart',
|
||||
'sdiskusage', 'snetio', 'snicaddr', 'snicstats', 'sswap', 'suser',
|
||||
# utility functions
|
||||
'conn_tmap', 'deprecated_method', 'isfile_strict', 'memoize',
|
||||
'parse_environ_block', 'path_exists_strict', 'usage_percent',
|
||||
'supports_ipv6', 'sockfam_to_enum', 'socktype_to_enum', "wrap_numbers",
|
||||
'bytes2human', 'conn_to_ntuple', 'debug',
|
||||
# shell utils
|
||||
'hilite', 'term_supports_colors', 'print_color',
|
||||
]
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- OS constants
|
||||
# ===================================================================
|
||||
|
||||
|
||||
POSIX = os.name == "posix"
|
||||
WINDOWS = os.name == "nt"
|
||||
LINUX = sys.platform.startswith("linux")
|
||||
MACOS = sys.platform.startswith("darwin")
|
||||
OSX = MACOS # deprecated alias
|
||||
FREEBSD = sys.platform.startswith("freebsd")
|
||||
OPENBSD = sys.platform.startswith("openbsd")
|
||||
NETBSD = sys.platform.startswith("netbsd")
|
||||
BSD = FREEBSD or OPENBSD or NETBSD
|
||||
SUNOS = sys.platform.startswith(("sunos", "solaris"))
|
||||
AIX = sys.platform.startswith("aix")
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- API constants
|
||||
# ===================================================================
|
||||
|
||||
|
||||
# Process.status()
|
||||
STATUS_RUNNING = "running"
|
||||
STATUS_SLEEPING = "sleeping"
|
||||
STATUS_DISK_SLEEP = "disk-sleep"
|
||||
STATUS_STOPPED = "stopped"
|
||||
STATUS_TRACING_STOP = "tracing-stop"
|
||||
STATUS_ZOMBIE = "zombie"
|
||||
STATUS_DEAD = "dead"
|
||||
STATUS_WAKE_KILL = "wake-kill"
|
||||
STATUS_WAKING = "waking"
|
||||
STATUS_IDLE = "idle" # Linux, macOS, FreeBSD
|
||||
STATUS_LOCKED = "locked" # FreeBSD
|
||||
STATUS_WAITING = "waiting" # FreeBSD
|
||||
STATUS_SUSPENDED = "suspended" # NetBSD
|
||||
STATUS_PARKED = "parked" # Linux
|
||||
|
||||
# Process.connections() and psutil.net_connections()
|
||||
CONN_ESTABLISHED = "ESTABLISHED"
|
||||
CONN_SYN_SENT = "SYN_SENT"
|
||||
CONN_SYN_RECV = "SYN_RECV"
|
||||
CONN_FIN_WAIT1 = "FIN_WAIT1"
|
||||
CONN_FIN_WAIT2 = "FIN_WAIT2"
|
||||
CONN_TIME_WAIT = "TIME_WAIT"
|
||||
CONN_CLOSE = "CLOSE"
|
||||
CONN_CLOSE_WAIT = "CLOSE_WAIT"
|
||||
CONN_LAST_ACK = "LAST_ACK"
|
||||
CONN_LISTEN = "LISTEN"
|
||||
CONN_CLOSING = "CLOSING"
|
||||
CONN_NONE = "NONE"
|
||||
|
||||
# net_if_stats()
|
||||
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__)
|
||||
|
||||
# sensors_battery()
|
||||
if enum is None:
|
||||
POWER_TIME_UNKNOWN = -1
|
||||
POWER_TIME_UNLIMITED = -2
|
||||
else:
|
||||
class BatteryTime(enum.IntEnum):
|
||||
POWER_TIME_UNKNOWN = -1
|
||||
POWER_TIME_UNLIMITED = -2
|
||||
|
||||
globals().update(BatteryTime.__members__)
|
||||
|
||||
# --- others
|
||||
|
||||
ENCODING = sys.getfilesystemencoding()
|
||||
if not PY3:
|
||||
ENCODING_ERRS = "replace"
|
||||
else:
|
||||
try:
|
||||
ENCODING_ERRS = sys.getfilesystemencodeerrors() # py 3.6
|
||||
except AttributeError:
|
||||
ENCODING_ERRS = "surrogateescape" if POSIX else "replace"
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- namedtuples
|
||||
# ===================================================================
|
||||
|
||||
# --- for system functions
|
||||
|
||||
# psutil.swap_memory()
|
||||
sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin',
|
||||
'sout'])
|
||||
# psutil.disk_usage()
|
||||
sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent'])
|
||||
# psutil.disk_io_counters()
|
||||
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes',
|
||||
'read_time', 'write_time'])
|
||||
# psutil.disk_partitions()
|
||||
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
|
||||
# psutil.net_io_counters()
|
||||
snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
|
||||
'packets_sent', 'packets_recv',
|
||||
'errin', 'errout',
|
||||
'dropin', 'dropout'])
|
||||
# psutil.users()
|
||||
suser = namedtuple('suser', ['name', 'terminal', 'host', 'started', 'pid'])
|
||||
# psutil.net_connections()
|
||||
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||
'status', 'pid'])
|
||||
# psutil.net_if_addrs()
|
||||
snicaddr = namedtuple('snicaddr',
|
||||
['family', 'address', 'netmask', 'broadcast', 'ptp'])
|
||||
# psutil.net_if_stats()
|
||||
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
|
||||
# psutil.cpu_stats()
|
||||
scpustats = namedtuple(
|
||||
'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'])
|
||||
# psutil.cpu_freq()
|
||||
scpufreq = namedtuple('scpufreq', ['current', 'min', 'max'])
|
||||
# psutil.sensors_temperatures()
|
||||
shwtemp = namedtuple(
|
||||
'shwtemp', ['label', 'current', 'high', 'critical'])
|
||||
# psutil.sensors_battery()
|
||||
sbattery = namedtuple('sbattery', ['percent', 'secsleft', 'power_plugged'])
|
||||
# psutil.sensors_fans()
|
||||
sfan = namedtuple('sfan', ['label', 'current'])
|
||||
|
||||
# --- for Process methods
|
||||
|
||||
# psutil.Process.cpu_times()
|
||||
pcputimes = namedtuple('pcputimes',
|
||||
['user', 'system', 'children_user', 'children_system'])
|
||||
# psutil.Process.open_files()
|
||||
popenfile = namedtuple('popenfile', ['path', 'fd'])
|
||||
# psutil.Process.threads()
|
||||
pthread = namedtuple('pthread', ['id', 'user_time', 'system_time'])
|
||||
# psutil.Process.uids()
|
||||
puids = namedtuple('puids', ['real', 'effective', 'saved'])
|
||||
# psutil.Process.gids()
|
||||
pgids = namedtuple('pgids', ['real', 'effective', 'saved'])
|
||||
# psutil.Process.io_counters()
|
||||
pio = namedtuple('pio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes'])
|
||||
# psutil.Process.ionice()
|
||||
pionice = namedtuple('pionice', ['ioclass', 'value'])
|
||||
# psutil.Process.ctx_switches()
|
||||
pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary'])
|
||||
# psutil.Process.connections()
|
||||
pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||
'status'])
|
||||
|
||||
# psutil.connections() and psutil.Process.connections()
|
||||
addr = namedtuple('addr', ['ip', 'port'])
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- Process.connections() 'kind' parameter mapping
|
||||
# ===================================================================
|
||||
|
||||
|
||||
conn_tmap = {
|
||||
"all": ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"tcp": ([AF_INET, AF_INET6], [SOCK_STREAM]),
|
||||
"tcp4": ([AF_INET], [SOCK_STREAM]),
|
||||
"udp": ([AF_INET, AF_INET6], [SOCK_DGRAM]),
|
||||
"udp4": ([AF_INET], [SOCK_DGRAM]),
|
||||
"inet": ([AF_INET, AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"inet4": ([AF_INET], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
"inet6": ([AF_INET6], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
}
|
||||
|
||||
if AF_INET6 is not None:
|
||||
conn_tmap.update({
|
||||
"tcp6": ([AF_INET6], [SOCK_STREAM]),
|
||||
"udp6": ([AF_INET6], [SOCK_DGRAM]),
|
||||
})
|
||||
|
||||
if AF_UNIX is not None:
|
||||
conn_tmap.update({
|
||||
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
})
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- Exceptions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Base exception class. All other psutil exceptions inherit
|
||||
from this one.
|
||||
"""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, msg=""):
|
||||
Exception.__init__(self, msg)
|
||||
self.msg = msg
|
||||
|
||||
def __repr__(self):
|
||||
ret = "psutil.%s %s" % (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.
|
||||
"""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, pid, name=None, msg=None):
|
||||
Error.__init__(self, msg)
|
||||
self.pid = pid
|
||||
self.name = name
|
||||
self.msg = msg
|
||||
if msg is None:
|
||||
if name:
|
||||
details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
|
||||
else:
|
||||
details = "(pid=%s)" % self.pid
|
||||
self.msg = "process no longer exists " + details
|
||||
|
||||
def __path__(self):
|
||||
return 'xxx'
|
||||
|
||||
|
||||
class ZombieProcess(NoSuchProcess):
|
||||
"""Exception raised when querying a zombie process. This is
|
||||
raised on macOS, 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.
|
||||
"""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, pid, name=None, ppid=None, msg=None):
|
||||
NoSuchProcess.__init__(self, msg)
|
||||
self.pid = pid
|
||||
self.ppid = ppid
|
||||
self.name = name
|
||||
self.msg = msg
|
||||
if msg is None:
|
||||
args = ["pid=%s" % pid]
|
||||
if name:
|
||||
args.append("name=%s" % repr(self.name))
|
||||
if ppid:
|
||||
args.append("ppid=%s" % self.ppid)
|
||||
details = "(%s)" % ", ".join(args)
|
||||
self.msg = "process still exists but it's a zombie " + details
|
||||
|
||||
|
||||
class AccessDenied(Error):
|
||||
"""Exception raised when permission to perform an action is denied."""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, pid=None, name=None, msg=None):
|
||||
Error.__init__(self, msg)
|
||||
self.pid = pid
|
||||
self.name = name
|
||||
self.msg = msg
|
||||
if msg is None:
|
||||
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
|
||||
else:
|
||||
self.msg = ""
|
||||
|
||||
|
||||
class TimeoutExpired(Error):
|
||||
"""Raised on Process.wait(timeout) if timeout expires and process
|
||||
is still alive.
|
||||
"""
|
||||
__module__ = 'psutil'
|
||||
|
||||
def __init__(self, seconds, pid=None, name=None):
|
||||
Error.__init__(self, "timeout after %s seconds" % seconds)
|
||||
self.seconds = seconds
|
||||
self.pid = pid
|
||||
self.name = name
|
||||
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
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- utils
|
||||
# ===================================================================
|
||||
|
||||
|
||||
def usage_percent(used, total, round_=None):
|
||||
"""Calculate percentage usage of 'used' against 'total'."""
|
||||
try:
|
||||
ret = (float(used) / total) * 100
|
||||
except ZeroDivisionError:
|
||||
return 0.0
|
||||
else:
|
||||
if round_ is not None:
|
||||
ret = round(ret, round_)
|
||||
return ret
|
||||
|
||||
|
||||
def memoize(fun):
|
||||
"""A simple memoize decorator for functions supporting (hashable)
|
||||
positional arguments.
|
||||
It also provides a cache_clear() function for clearing the cache:
|
||||
|
||||
>>> @memoize
|
||||
... def foo()
|
||||
... return 1
|
||||
...
|
||||
>>> foo()
|
||||
1
|
||||
>>> foo.cache_clear()
|
||||
>>>
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(*args, **kwargs):
|
||||
key = (args, frozenset(sorted(kwargs.items())))
|
||||
try:
|
||||
return cache[key]
|
||||
except KeyError:
|
||||
ret = cache[key] = fun(*args, **kwargs)
|
||||
return ret
|
||||
|
||||
def cache_clear():
|
||||
"""Clear cache."""
|
||||
cache.clear()
|
||||
|
||||
cache = {}
|
||||
wrapper.cache_clear = cache_clear
|
||||
return wrapper
|
||||
|
||||
|
||||
def memoize_when_activated(fun):
|
||||
"""A memoize decorator which is disabled by default. It can be
|
||||
activated and deactivated on request.
|
||||
For efficiency reasons it can be used only against class methods
|
||||
accepting no arguments.
|
||||
|
||||
>>> class Foo:
|
||||
... @memoize
|
||||
... def foo()
|
||||
... print(1)
|
||||
...
|
||||
>>> f = Foo()
|
||||
>>> # deactivated (default)
|
||||
>>> foo()
|
||||
1
|
||||
>>> foo()
|
||||
1
|
||||
>>>
|
||||
>>> # activated
|
||||
>>> foo.cache_activate(self)
|
||||
>>> foo()
|
||||
1
|
||||
>>> foo()
|
||||
>>> foo()
|
||||
>>>
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self):
|
||||
try:
|
||||
# case 1: we previously entered oneshot() ctx
|
||||
ret = self._cache[fun]
|
||||
except AttributeError:
|
||||
# case 2: we never entered oneshot() ctx
|
||||
return fun(self)
|
||||
except KeyError:
|
||||
# case 3: we entered oneshot() ctx but there's no cache
|
||||
# for this entry yet
|
||||
ret = self._cache[fun] = fun(self)
|
||||
return ret
|
||||
|
||||
def cache_activate(proc):
|
||||
"""Activate cache. Expects a Process instance. Cache will be
|
||||
stored as a "_cache" instance attribute."""
|
||||
proc._cache = {}
|
||||
|
||||
def cache_deactivate(proc):
|
||||
"""Deactivate and clear cache."""
|
||||
try:
|
||||
del proc._cache
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
wrapper.cache_activate = cache_activate
|
||||
wrapper.cache_deactivate = cache_deactivate
|
||||
return wrapper
|
||||
|
||||
|
||||
def isfile_strict(path):
|
||||
"""Same as os.path.isfile() but does not swallow EACCES / EPERM
|
||||
exceptions, see:
|
||||
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
|
||||
"""
|
||||
try:
|
||||
st = os.stat(path)
|
||||
except OSError as err:
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise
|
||||
return False
|
||||
else:
|
||||
return stat.S_ISREG(st.st_mode)
|
||||
|
||||
|
||||
def path_exists_strict(path):
|
||||
"""Same as os.path.exists() but does not swallow EACCES / EPERM
|
||||
exceptions, see:
|
||||
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
|
||||
"""
|
||||
try:
|
||||
os.stat(path)
|
||||
except OSError as err:
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
@memoize
|
||||
def supports_ipv6():
|
||||
"""Return True if IPv6 is supported on this platform."""
|
||||
if not socket.has_ipv6 or AF_INET6 is None:
|
||||
return False
|
||||
try:
|
||||
sock = socket.socket(AF_INET6, socket.SOCK_STREAM)
|
||||
with contextlib.closing(sock):
|
||||
sock.bind(("::1", 0))
|
||||
return True
|
||||
except socket.error:
|
||||
return False
|
||||
|
||||
|
||||
def parse_environ_block(data):
|
||||
"""Parse a C environ block of environment variables into a dictionary."""
|
||||
# The block is usually raw data from the target process. It might contain
|
||||
# trailing garbage and lines that do not look like assignments.
|
||||
ret = {}
|
||||
pos = 0
|
||||
|
||||
# localize global variable to speed up access.
|
||||
WINDOWS_ = WINDOWS
|
||||
while True:
|
||||
next_pos = data.find("\0", pos)
|
||||
# nul byte at the beginning or double nul byte means finish
|
||||
if next_pos <= pos:
|
||||
break
|
||||
# there might not be an equals sign
|
||||
equal_pos = data.find("=", pos, next_pos)
|
||||
if equal_pos > pos:
|
||||
key = data[pos:equal_pos]
|
||||
value = data[equal_pos + 1:next_pos]
|
||||
# Windows expects environment variables to be uppercase only
|
||||
if WINDOWS_:
|
||||
key = key.upper()
|
||||
ret[key] = value
|
||||
pos = next_pos + 1
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
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
|
||||
else: # pragma: no cover
|
||||
try:
|
||||
return socket.AddressFamily(num)
|
||||
except ValueError:
|
||||
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
|
||||
else: # pragma: no cover
|
||||
try:
|
||||
return socket.SocketKind(num)
|
||||
except ValueError:
|
||||
return num
|
||||
|
||||
|
||||
def conn_to_ntuple(fd, fam, type_, laddr, raddr, status, status_map, pid=None):
|
||||
"""Convert a raw connection tuple to a proper ntuple."""
|
||||
if fam in (socket.AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = addr(*laddr)
|
||||
if raddr:
|
||||
raddr = addr(*raddr)
|
||||
if type_ == socket.SOCK_STREAM and fam in (AF_INET, AF_INET6):
|
||||
status = status_map.get(status, CONN_NONE)
|
||||
else:
|
||||
status = CONN_NONE # ignore whatever C returned to us
|
||||
fam = sockfam_to_enum(fam)
|
||||
type_ = socktype_to_enum(type_)
|
||||
if pid is None:
|
||||
return pconn(fd, fam, type_, laddr, raddr, status)
|
||||
else:
|
||||
return sconn(fd, fam, type_, laddr, raddr, status, pid)
|
||||
|
||||
|
||||
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 and will be removed; 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
|
||||
|
||||
|
||||
class _WrapNumbers:
|
||||
"""Watches numbers so that they don't overflow and wrap
|
||||
(reset to zero).
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.lock = threading.Lock()
|
||||
self.cache = {}
|
||||
self.reminders = {}
|
||||
self.reminder_keys = {}
|
||||
|
||||
def _add_dict(self, input_dict, name):
|
||||
assert name not in self.cache
|
||||
assert name not in self.reminders
|
||||
assert name not in self.reminder_keys
|
||||
self.cache[name] = input_dict
|
||||
self.reminders[name] = defaultdict(int)
|
||||
self.reminder_keys[name] = defaultdict(set)
|
||||
|
||||
def _remove_dead_reminders(self, input_dict, name):
|
||||
"""In case the number of keys changed between calls (e.g. a
|
||||
disk disappears) this removes the entry from self.reminders.
|
||||
"""
|
||||
old_dict = self.cache[name]
|
||||
gone_keys = set(old_dict.keys()) - set(input_dict.keys())
|
||||
for gone_key in gone_keys:
|
||||
for remkey in self.reminder_keys[name][gone_key]:
|
||||
del self.reminders[name][remkey]
|
||||
del self.reminder_keys[name][gone_key]
|
||||
|
||||
def run(self, input_dict, name):
|
||||
"""Cache dict and sum numbers which overflow and wrap.
|
||||
Return an updated copy of `input_dict`
|
||||
"""
|
||||
if name not in self.cache:
|
||||
# This was the first call.
|
||||
self._add_dict(input_dict, name)
|
||||
return input_dict
|
||||
|
||||
self._remove_dead_reminders(input_dict, name)
|
||||
|
||||
old_dict = self.cache[name]
|
||||
new_dict = {}
|
||||
for key in input_dict.keys():
|
||||
input_tuple = input_dict[key]
|
||||
try:
|
||||
old_tuple = old_dict[key]
|
||||
except KeyError:
|
||||
# The input dict has a new key (e.g. a new disk or NIC)
|
||||
# which didn't exist in the previous call.
|
||||
new_dict[key] = input_tuple
|
||||
continue
|
||||
|
||||
bits = []
|
||||
for i in range(len(input_tuple)):
|
||||
input_value = input_tuple[i]
|
||||
old_value = old_tuple[i]
|
||||
remkey = (key, i)
|
||||
if input_value < old_value:
|
||||
# it wrapped!
|
||||
self.reminders[name][remkey] += old_value
|
||||
self.reminder_keys[name][key].add(remkey)
|
||||
bits.append(input_value + self.reminders[name][remkey])
|
||||
|
||||
new_dict[key] = tuple(bits)
|
||||
|
||||
self.cache[name] = input_dict
|
||||
return new_dict
|
||||
|
||||
def cache_clear(self, name=None):
|
||||
"""Clear the internal cache, optionally only for function 'name'."""
|
||||
with self.lock:
|
||||
if name is None:
|
||||
self.cache.clear()
|
||||
self.reminders.clear()
|
||||
self.reminder_keys.clear()
|
||||
else:
|
||||
self.cache.pop(name, None)
|
||||
self.reminders.pop(name, None)
|
||||
self.reminder_keys.pop(name, None)
|
||||
|
||||
def cache_info(self):
|
||||
"""Return internal cache dicts as a tuple of 3 elements."""
|
||||
with self.lock:
|
||||
return (self.cache, self.reminders, self.reminder_keys)
|
||||
|
||||
|
||||
def wrap_numbers(input_dict, name):
|
||||
"""Given an `input_dict` and a function `name`, adjust the numbers
|
||||
which "wrap" (restart from zero) across different calls by adding
|
||||
"old value" to "new value" and return an updated dict.
|
||||
"""
|
||||
with _wn.lock:
|
||||
return _wn.run(input_dict, name)
|
||||
|
||||
|
||||
_wn = _WrapNumbers()
|
||||
wrap_numbers.cache_clear = _wn.cache_clear
|
||||
wrap_numbers.cache_info = _wn.cache_info
|
||||
|
||||
|
||||
def open_binary(fname, **kwargs):
|
||||
return open(fname, "rb", **kwargs)
|
||||
|
||||
|
||||
def open_text(fname, **kwargs):
|
||||
"""On Python 3 opens a file in text mode by using fs encoding and
|
||||
a proper en/decoding errors handler.
|
||||
On Python 2 this is just an alias for open(name, 'rt').
|
||||
"""
|
||||
if PY3:
|
||||
# See:
|
||||
# https://github.com/giampaolo/psutil/issues/675
|
||||
# https://github.com/giampaolo/psutil/pull/733
|
||||
kwargs.setdefault('encoding', ENCODING)
|
||||
kwargs.setdefault('errors', ENCODING_ERRS)
|
||||
return open(fname, "rt", **kwargs)
|
||||
|
||||
|
||||
def bytes2human(n, format="%(value).1f%(symbol)s"):
|
||||
"""Used by various scripts. See:
|
||||
http://goo.gl/zeJZl
|
||||
|
||||
>>> bytes2human(10000)
|
||||
'9.8K'
|
||||
>>> bytes2human(100001221)
|
||||
'95.4M'
|
||||
"""
|
||||
symbols = ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols[1:]):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for symbol in reversed(symbols[1:]):
|
||||
if n >= prefix[symbol]:
|
||||
value = float(n) / prefix[symbol]
|
||||
return format % locals()
|
||||
return format % dict(symbol=symbols[0], value=n)
|
||||
|
||||
|
||||
def get_procfs_path():
|
||||
"""Return updated psutil.PROCFS_PATH constant."""
|
||||
return sys.modules['psutil'].PROCFS_PATH
|
||||
|
||||
|
||||
if PY3:
|
||||
def decode(s):
|
||||
return s.decode(encoding=ENCODING, errors=ENCODING_ERRS)
|
||||
else:
|
||||
def decode(s):
|
||||
return s
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- shell utils
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@memoize
|
||||
def term_supports_colors(file=sys.stdout):
|
||||
if os.name == 'nt':
|
||||
return True
|
||||
try:
|
||||
import curses
|
||||
assert file.isatty()
|
||||
curses.setupterm()
|
||||
assert curses.tigetnum("colors") > 0
|
||||
except Exception:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def hilite(s, color="green", bold=False):
|
||||
"""Return an highlighted version of 'string'."""
|
||||
if not term_supports_colors():
|
||||
return s
|
||||
attr = []
|
||||
colors = dict(green='32', red='91', brown='33')
|
||||
colors[None] = '29'
|
||||
try:
|
||||
color = colors[color]
|
||||
except KeyError:
|
||||
raise ValueError("invalid color %r; choose between %s" % (
|
||||
list(colors.keys())))
|
||||
attr.append(color)
|
||||
if bold:
|
||||
attr.append('1')
|
||||
return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), s)
|
||||
|
||||
|
||||
def print_color(s, color="green", bold=False, file=sys.stdout):
|
||||
"""Print a colorized version of string."""
|
||||
if not term_supports_colors():
|
||||
print(s, file=file)
|
||||
elif POSIX:
|
||||
print(hilite(s, color, bold), file=file)
|
||||
else:
|
||||
import ctypes
|
||||
|
||||
DEFAULT_COLOR = 7
|
||||
GetStdHandle = ctypes.windll.Kernel32.GetStdHandle
|
||||
SetConsoleTextAttribute = \
|
||||
ctypes.windll.Kernel32.SetConsoleTextAttribute
|
||||
|
||||
colors = dict(green=2, red=4, brown=6)
|
||||
colors[None] = DEFAULT_COLOR
|
||||
try:
|
||||
color = colors[color]
|
||||
except KeyError:
|
||||
raise ValueError("invalid color %r; choose between %r" % (
|
||||
color, list(colors.keys())))
|
||||
if bold and color <= 7:
|
||||
color += 8
|
||||
|
||||
handle_id = -12 if file is sys.stderr else -11
|
||||
GetStdHandle.restype = ctypes.c_ulong
|
||||
handle = GetStdHandle(handle_id)
|
||||
SetConsoleTextAttribute(handle, color)
|
||||
try:
|
||||
print(s, file=file)
|
||||
finally:
|
||||
SetConsoleTextAttribute(handle, DEFAULT_COLOR)
|
||||
|
||||
|
||||
if bool(os.getenv('PSUTIL_DEBUG', 0)):
|
||||
import inspect
|
||||
|
||||
def debug(msg):
|
||||
"""If PSUTIL_DEBUG env var is set, print a debug message to stderr."""
|
||||
fname, lineno, func_name, lines, index = inspect.getframeinfo(
|
||||
inspect.currentframe().f_back)
|
||||
print("psutil-debug [%s:%s]> %s" % (fname, lineno, msg),
|
||||
file=sys.stderr)
|
||||
else:
|
||||
def debug(msg):
|
||||
pass
|
||||
345
third_party/python/psutil/psutil/_compat.py
vendored
Normal file
345
third_party/python/psutil/psutil/_compat.py
vendored
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
# 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.
|
||||
|
||||
"""Module which provides compatibility with older Python versions."""
|
||||
|
||||
import collections
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import sys
|
||||
|
||||
__all__ = ["PY3", "long", "xrange", "unicode", "basestring", "u", "b",
|
||||
"lru_cache", "which", "get_terminal_size",
|
||||
"FileNotFoundError", "PermissionError", "ProcessLookupError",
|
||||
"InterruptedError", "ChildProcessError", "FileExistsError"]
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
long = int
|
||||
xrange = range
|
||||
unicode = str
|
||||
basestring = str
|
||||
|
||||
def u(s):
|
||||
return s
|
||||
|
||||
def b(s):
|
||||
return s.encode("latin-1")
|
||||
else:
|
||||
long = long
|
||||
xrange = xrange
|
||||
unicode = unicode
|
||||
basestring = basestring
|
||||
|
||||
def u(s):
|
||||
return unicode(s, "unicode_escape")
|
||||
|
||||
def b(s):
|
||||
return s
|
||||
|
||||
|
||||
# --- exceptions
|
||||
|
||||
|
||||
if PY3:
|
||||
FileNotFoundError = FileNotFoundError # NOQA
|
||||
PermissionError = PermissionError # NOQA
|
||||
ProcessLookupError = ProcessLookupError # NOQA
|
||||
InterruptedError = InterruptedError # NOQA
|
||||
ChildProcessError = ChildProcessError # NOQA
|
||||
FileExistsError = FileExistsError # NOQA
|
||||
else:
|
||||
# https://github.com/PythonCharmers/python-future/blob/exceptions/
|
||||
# src/future/types/exceptions/pep3151.py
|
||||
import platform
|
||||
|
||||
_singleton = object()
|
||||
|
||||
def instance_checking_exception(base_exception=Exception):
|
||||
def wrapped(instance_checker):
|
||||
class TemporaryClass(base_exception):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(args) == 1 and isinstance(args[0], TemporaryClass):
|
||||
unwrap_me = args[0]
|
||||
for attr in dir(unwrap_me):
|
||||
if not attr.startswith('__'):
|
||||
setattr(self, attr, getattr(unwrap_me, attr))
|
||||
else:
|
||||
super(TemporaryClass, self).__init__(*args, **kwargs)
|
||||
|
||||
class __metaclass__(type):
|
||||
def __instancecheck__(cls, inst):
|
||||
return instance_checker(inst)
|
||||
|
||||
def __subclasscheck__(cls, classinfo):
|
||||
value = sys.exc_info()[1]
|
||||
return isinstance(value, cls)
|
||||
|
||||
TemporaryClass.__name__ = instance_checker.__name__
|
||||
TemporaryClass.__doc__ = instance_checker.__doc__
|
||||
return TemporaryClass
|
||||
|
||||
return wrapped
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def FileNotFoundError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.ENOENT
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def ProcessLookupError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.ESRCH
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def PermissionError(inst):
|
||||
return getattr(inst, 'errno', _singleton) in (
|
||||
errno.EACCES, errno.EPERM)
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def InterruptedError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.EINTR
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def ChildProcessError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.ECHILD
|
||||
|
||||
@instance_checking_exception(EnvironmentError)
|
||||
def FileExistsError(inst):
|
||||
return getattr(inst, 'errno', _singleton) == errno.EEXIST
|
||||
|
||||
if platform.python_implementation() != "CPython":
|
||||
try:
|
||||
raise OSError(errno.EEXIST, "perm")
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError:
|
||||
raise RuntimeError(
|
||||
"broken / incompatible Python implementation, see: "
|
||||
"https://github.com/giampaolo/psutil/issues/1659")
|
||||
|
||||
|
||||
# --- stdlib additions
|
||||
|
||||
|
||||
# py 3.2 functools.lru_cache
|
||||
# Taken from: http://code.activestate.com/recipes/578078
|
||||
# Credit: Raymond Hettinger
|
||||
try:
|
||||
from functools import lru_cache
|
||||
except ImportError:
|
||||
try:
|
||||
from threading import RLock
|
||||
except ImportError:
|
||||
from dummy_threading import RLock
|
||||
|
||||
_CacheInfo = collections.namedtuple(
|
||||
"CacheInfo", ["hits", "misses", "maxsize", "currsize"])
|
||||
|
||||
class _HashedSeq(list):
|
||||
__slots__ = 'hashvalue'
|
||||
|
||||
def __init__(self, tup, hash=hash):
|
||||
self[:] = tup
|
||||
self.hashvalue = hash(tup)
|
||||
|
||||
def __hash__(self):
|
||||
return self.hashvalue
|
||||
|
||||
def _make_key(args, kwds, typed,
|
||||
kwd_mark=(object(), ),
|
||||
fasttypes=set((int, str, frozenset, type(None))),
|
||||
sorted=sorted, tuple=tuple, type=type, len=len):
|
||||
key = args
|
||||
if kwds:
|
||||
sorted_items = sorted(kwds.items())
|
||||
key += kwd_mark
|
||||
for item in sorted_items:
|
||||
key += item
|
||||
if typed:
|
||||
key += tuple(type(v) for v in args)
|
||||
if kwds:
|
||||
key += tuple(type(v) for k, v in sorted_items)
|
||||
elif len(key) == 1 and type(key[0]) in fasttypes:
|
||||
return key[0]
|
||||
return _HashedSeq(key)
|
||||
|
||||
def lru_cache(maxsize=100, typed=False):
|
||||
"""Least-recently-used cache decorator, see:
|
||||
http://docs.python.org/3/library/functools.html#functools.lru_cache
|
||||
"""
|
||||
def decorating_function(user_function):
|
||||
cache = dict()
|
||||
stats = [0, 0]
|
||||
HITS, MISSES = 0, 1
|
||||
make_key = _make_key
|
||||
cache_get = cache.get
|
||||
_len = len
|
||||
lock = RLock()
|
||||
root = []
|
||||
root[:] = [root, root, None, None]
|
||||
nonlocal_root = [root]
|
||||
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3
|
||||
if maxsize == 0:
|
||||
def wrapper(*args, **kwds):
|
||||
result = user_function(*args, **kwds)
|
||||
stats[MISSES] += 1
|
||||
return result
|
||||
elif maxsize is None:
|
||||
def wrapper(*args, **kwds):
|
||||
key = make_key(args, kwds, typed)
|
||||
result = cache_get(key, root)
|
||||
if result is not root:
|
||||
stats[HITS] += 1
|
||||
return result
|
||||
result = user_function(*args, **kwds)
|
||||
cache[key] = result
|
||||
stats[MISSES] += 1
|
||||
return result
|
||||
else:
|
||||
def wrapper(*args, **kwds):
|
||||
if kwds or typed:
|
||||
key = make_key(args, kwds, typed)
|
||||
else:
|
||||
key = args
|
||||
lock.acquire()
|
||||
try:
|
||||
link = cache_get(key)
|
||||
if link is not None:
|
||||
root, = nonlocal_root
|
||||
link_prev, link_next, key, result = link
|
||||
link_prev[NEXT] = link_next
|
||||
link_next[PREV] = link_prev
|
||||
last = root[PREV]
|
||||
last[NEXT] = root[PREV] = link
|
||||
link[PREV] = last
|
||||
link[NEXT] = root
|
||||
stats[HITS] += 1
|
||||
return result
|
||||
finally:
|
||||
lock.release()
|
||||
result = user_function(*args, **kwds)
|
||||
lock.acquire()
|
||||
try:
|
||||
root, = nonlocal_root
|
||||
if key in cache:
|
||||
pass
|
||||
elif _len(cache) >= maxsize:
|
||||
oldroot = root
|
||||
oldroot[KEY] = key
|
||||
oldroot[RESULT] = result
|
||||
root = nonlocal_root[0] = oldroot[NEXT]
|
||||
oldkey = root[KEY]
|
||||
root[KEY] = root[RESULT] = None
|
||||
del cache[oldkey]
|
||||
cache[key] = oldroot
|
||||
else:
|
||||
last = root[PREV]
|
||||
link = [last, root, key, result]
|
||||
last[NEXT] = root[PREV] = cache[key] = link
|
||||
stats[MISSES] += 1
|
||||
finally:
|
||||
lock.release()
|
||||
return result
|
||||
|
||||
def cache_info():
|
||||
"""Report cache statistics"""
|
||||
lock.acquire()
|
||||
try:
|
||||
return _CacheInfo(stats[HITS], stats[MISSES], maxsize,
|
||||
len(cache))
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
def cache_clear():
|
||||
"""Clear the cache and cache statistics"""
|
||||
lock.acquire()
|
||||
try:
|
||||
cache.clear()
|
||||
root = nonlocal_root[0]
|
||||
root[:] = [root, root, None, None]
|
||||
stats[:] = [0, 0]
|
||||
finally:
|
||||
lock.release()
|
||||
|
||||
wrapper.__wrapped__ = user_function
|
||||
wrapper.cache_info = cache_info
|
||||
wrapper.cache_clear = cache_clear
|
||||
return functools.update_wrapper(wrapper, user_function)
|
||||
|
||||
return decorating_function
|
||||
|
||||
|
||||
# python 3.3
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
||||
"""Given a command, mode, and a PATH string, return the path which
|
||||
conforms to the given mode on the PATH, or None if there is no such
|
||||
file.
|
||||
|
||||
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
|
||||
of os.environ.get("PATH"), or can be overridden with a custom search
|
||||
path.
|
||||
"""
|
||||
def _access_check(fn, mode):
|
||||
return (os.path.exists(fn) and os.access(fn, mode) and
|
||||
not os.path.isdir(fn))
|
||||
|
||||
if os.path.dirname(cmd):
|
||||
if _access_check(cmd, mode):
|
||||
return cmd
|
||||
return None
|
||||
|
||||
if path is None:
|
||||
path = os.environ.get("PATH", os.defpath)
|
||||
if not path:
|
||||
return None
|
||||
path = path.split(os.pathsep)
|
||||
|
||||
if sys.platform == "win32":
|
||||
if os.curdir not in path:
|
||||
path.insert(0, os.curdir)
|
||||
|
||||
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
|
||||
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
|
||||
files = [cmd]
|
||||
else:
|
||||
files = [cmd + ext for ext in pathext]
|
||||
else:
|
||||
files = [cmd]
|
||||
|
||||
seen = set()
|
||||
for dir in path:
|
||||
normdir = os.path.normcase(dir)
|
||||
if normdir not in seen:
|
||||
seen.add(normdir)
|
||||
for thefile in files:
|
||||
name = os.path.join(dir, thefile)
|
||||
if _access_check(name, mode):
|
||||
return name
|
||||
return None
|
||||
|
||||
|
||||
# python 3.3
|
||||
try:
|
||||
from shutil import get_terminal_size
|
||||
except ImportError:
|
||||
def get_terminal_size(fallback=(80, 24)):
|
||||
try:
|
||||
import fcntl
|
||||
import termios
|
||||
import struct
|
||||
except ImportError:
|
||||
return fallback
|
||||
else:
|
||||
try:
|
||||
# This should work on Linux.
|
||||
res = struct.unpack(
|
||||
'hh', fcntl.ioctl(1, termios.TIOCGWINSZ, '1234'))
|
||||
return (res[1], res[0])
|
||||
except Exception:
|
||||
return fallback
|
||||
550
third_party/python/psutil/psutil/_psaix.py
vendored
Normal file
550
third_party/python/psutil/psutil/_psaix.py
vendored
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
# Copyright (c) 2009, Giampaolo Rodola'
|
||||
# Copyright (c) 2017, Arnon Yaari
|
||||
# All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""AIX platform implementation."""
|
||||
|
||||
import functools
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_aix as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AccessDenied
|
||||
from ._common import conn_to_ntuple
|
||||
from ._common import get_procfs_path
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NIC_DUPLEX_FULL
|
||||
from ._common import NIC_DUPLEX_HALF
|
||||
from ._common import NIC_DUPLEX_UNKNOWN
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3
|
||||
|
||||
|
||||
__extra__all__ = ["PROCFS_PATH"]
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- globals
|
||||
# =====================================================================
|
||||
|
||||
|
||||
HAS_THREADS = hasattr(cext, "proc_threads")
|
||||
HAS_NET_IO_COUNTERS = hasattr(cext, "net_io_counters")
|
||||
HAS_PROC_IO_COUNTERS = hasattr(cext, "proc_io_counters")
|
||||
|
||||
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SACTIVE: _common.STATUS_RUNNING,
|
||||
cext.SSWAP: _common.STATUS_RUNNING, # TODO what status is this?
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
}
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
proc_info_map = dict(
|
||||
ppid=0,
|
||||
rss=1,
|
||||
vms=2,
|
||||
create_time=3,
|
||||
nice=4,
|
||||
num_threads=5,
|
||||
status=6,
|
||||
ttynr=7)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
# =====================================================================
|
||||
|
||||
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms'])
|
||||
# psutil.Process.memory_full_info()
|
||||
pfullmem = pmem
|
||||
# psutil.Process.cpu_times()
|
||||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
total, avail, free, pinned, inuse = cext.virtual_mem()
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, inuse, free)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
|
||||
total, free, sin, sout = cext.swap_mem()
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- CPU
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system-wide CPU times as a named tuple"""
|
||||
ret = cext.per_cpu_times()
|
||||
return scputimes(*[sum(x) for x in zip(*ret)])
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system per-CPU times as a list of named tuples"""
|
||||
ret = cext.per_cpu_times()
|
||||
return [scputimes(*x) for x in ret]
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
try:
|
||||
return os.sysconf("SC_NPROCESSORS_ONLN")
|
||||
except ValueError:
|
||||
# mimic os.cpu_count() behavior
|
||||
return None
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
cmd = "lsdev -Cc processor"
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError("%r command error\n%s" % (cmd, stderr))
|
||||
processors = stdout.strip().splitlines()
|
||||
return len(processors) or None
|
||||
|
||||
|
||||
def cpu_stats():
|
||||
"""Return various CPU stats as a named tuple."""
|
||||
ctx_switches, interrupts, soft_interrupts, syscalls = cext.cpu_stats()
|
||||
return _common.scpustats(
|
||||
ctx_switches, interrupts, soft_interrupts, syscalls)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- disks
|
||||
# =====================================================================
|
||||
|
||||
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
disk_usage = _psposix.disk_usage
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return system disk partitions."""
|
||||
# TODO - the filtering logic should be better checked so that
|
||||
# it tries to reflect 'df' as much as possible
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
# Differently from, say, Linux, we don't have a list of
|
||||
# common fs types so the best we can do, AFAIK, is to
|
||||
# filter by filesystem having a total size > 0.
|
||||
if not disk_usage(mountpoint).total:
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
||||
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
if HAS_NET_IO_COUNTERS:
|
||||
net_io_counters = cext.net_io_counters
|
||||
|
||||
|
||||
def net_connections(kind, _pid=-1):
|
||||
"""Return socket connections. If pid == -1 return system-wide
|
||||
connections (as opposed to connections opened by one process only).
|
||||
"""
|
||||
cmap = _common.conn_tmap
|
||||
if kind not in cmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||
families, types = _common.conn_tmap[kind]
|
||||
rawlist = cext.net_connections(_pid)
|
||||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type_, laddr, raddr, status, pid = item
|
||||
if fam not in families:
|
||||
continue
|
||||
if type_ not in types:
|
||||
continue
|
||||
nt = conn_to_ntuple(fd, fam, type_, laddr, raddr, status,
|
||||
TCP_STATUSES, pid=pid if _pid == -1 else None)
|
||||
ret.append(nt)
|
||||
return ret
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
duplex_map = {"Full": NIC_DUPLEX_FULL,
|
||||
"Half": NIC_DUPLEX_HALF}
|
||||
names = set([x[0] for x in net_if_addrs()])
|
||||
ret = {}
|
||||
for name in names:
|
||||
isup, mtu = cext.net_if_stats(name)
|
||||
|
||||
# try to get speed and duplex
|
||||
# TODO: rewrite this in C (entstat forks, so use truss -f to follow.
|
||||
# looks like it is using an undocumented ioctl?)
|
||||
duplex = ""
|
||||
speed = 0
|
||||
p = subprocess.Popen(["/usr/bin/entstat", "-d", name],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if p.returncode == 0:
|
||||
re_result = re.search(
|
||||
r"Running: (\d+) Mbps.*?(\w+) Duplex", stdout)
|
||||
if re_result is not None:
|
||||
speed = int(re_result.group(1))
|
||||
duplex = re_result.group(2)
|
||||
|
||||
duplex = duplex_map.get(duplex, NIC_DUPLEX_UNKNOWN)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- other system functions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
localhost = (':0.0', ':0')
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, user_process, pid = item
|
||||
# note: the underlying C function includes entries about
|
||||
# system boot, run level and others. We might want
|
||||
# to use them in the future.
|
||||
if not user_process:
|
||||
continue
|
||||
if hostname in localhost:
|
||||
hostname = 'localhost'
|
||||
nt = _common.suser(user, tty, hostname, tstamp, pid)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- processes
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def pids():
|
||||
"""Returns a list of PIDs currently running on the system."""
|
||||
return [int(x) for x in os.listdir(get_procfs_path()) if x.isdigit()]
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check for the existence of a unix pid."""
|
||||
return os.path.exists(os.path.join(get_procfs_path(), str(pid), "psinfo"))
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Call callable into a try/except clause and translate ENOENT,
|
||||
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# 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 not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
self._procfs_path = get_procfs_path()
|
||||
|
||||
def oneshot_enter(self):
|
||||
self._proc_basic_info.cache_activate(self)
|
||||
self._proc_cred.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self._proc_basic_info.cache_deactivate(self)
|
||||
self._proc_cred.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_basic_info(self):
|
||||
return cext.proc_basic_info(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_cred(self):
|
||||
return cext.proc_cred(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
if self.pid == 0:
|
||||
return "swapper"
|
||||
# note: max 16 characters
|
||||
return cext.proc_name(self.pid, self._procfs_path).rstrip("\x00")
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
# there is no way to get executable path in AIX other than to guess,
|
||||
# and guessing is more complex than what's in the wrapping class
|
||||
cmdline = self.cmdline()
|
||||
if not cmdline:
|
||||
return ''
|
||||
exe = cmdline[0]
|
||||
if os.path.sep in exe:
|
||||
# relative or absolute path
|
||||
if not os.path.isabs(exe):
|
||||
# if cwd has changed, we're out of luck - this may be wrong!
|
||||
exe = os.path.abspath(os.path.join(self.cwd(), exe))
|
||||
if (os.path.isabs(exe) and
|
||||
os.path.isfile(exe) and
|
||||
os.access(exe, os.X_OK)):
|
||||
return exe
|
||||
# not found, move to search in PATH using basename only
|
||||
exe = os.path.basename(exe)
|
||||
# search for exe name PATH
|
||||
for path in os.environ["PATH"].split(":"):
|
||||
possible_exe = os.path.abspath(os.path.join(path, exe))
|
||||
if (os.path.isfile(possible_exe) and
|
||||
os.access(possible_exe, os.X_OK)):
|
||||
return possible_exe
|
||||
return ''
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
return cext.proc_args(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def environ(self):
|
||||
return cext.proc_environ(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return self._proc_basic_info()[proc_info_map['create_time']]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return self._proc_basic_info()[proc_info_map['num_threads']]
|
||||
|
||||
if HAS_THREADS:
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
# The underlying C implementation retrieves all OS threads
|
||||
# and filters them by PID. At this point we can't tell whether
|
||||
# an empty list means there were no connections for process or
|
||||
# process is no longer active so we force NSP in case the PID
|
||||
# is no longer there.
|
||||
if not retlist:
|
||||
# will raise NSP if process is gone
|
||||
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
ret = net_connections(kind, _pid=self.pid)
|
||||
# The underlying C implementation retrieves all OS connections
|
||||
# and filters them by PID. At this point we can't tell whether
|
||||
# an empty list means there were no connections for process or
|
||||
# process is no longer active so we force NSP in case the PID
|
||||
# is no longer there.
|
||||
if not ret:
|
||||
# will raise NSP if process is gone
|
||||
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
return cext_posix.getpriority(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
self._ppid = self._proc_basic_info()[proc_info_map['ppid']]
|
||||
return self._ppid
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
real, effective, saved, _, _, _ = self._proc_cred()
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
_, _, _, real, effective, saved = self._proc_cred()
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
cpu_times = cext.proc_cpu_times(self.pid, self._procfs_path)
|
||||
return _common.pcputimes(*cpu_times)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
ttydev = self._proc_basic_info()[proc_info_map['ttynr']]
|
||||
# convert from 64-bit dev_t to 32-bit dev_t and then map the device
|
||||
ttydev = (((ttydev & 0x0000FFFF00000000) >> 16) | (ttydev & 0xFFFF))
|
||||
# try to match rdev of /dev/pts/* files ttydev
|
||||
for dev in glob.glob("/dev/**/*"):
|
||||
if os.stat(dev).st_rdev == ttydev:
|
||||
return dev
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
procfs_path = self._procfs_path
|
||||
try:
|
||||
result = os.readlink("%s/%s/cwd" % (procfs_path, self.pid))
|
||||
return result.rstrip('/')
|
||||
except FileNotFoundError:
|
||||
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
ret = self._proc_basic_info()
|
||||
rss = ret[proc_info_map['rss']] * 1024
|
||||
vms = ret[proc_info_map['vms']] * 1024
|
||||
return pmem(rss, vms)
|
||||
|
||||
memory_full_info = memory_info
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = self._proc_basic_info()[proc_info_map['status']]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
def open_files(self):
|
||||
# TODO rewrite without using procfiles (stat /proc/pid/fd/* and then
|
||||
# find matching name of the inode)
|
||||
p = subprocess.Popen(["/usr/bin/procfiles", "-n", str(self.pid)],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if "no such process" in stderr.lower():
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
procfiles = re.findall(r"(\d+): S_IFREG.*\s*.*name:(.*)\n", stdout)
|
||||
retlist = []
|
||||
for fd, path in procfiles:
|
||||
path = path.strip()
|
||||
if path.startswith("//"):
|
||||
path = path[1:]
|
||||
if path.lower() == "cannot be retrieved":
|
||||
continue
|
||||
retlist.append(_common.popenfile(path, int(fd)))
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
if self.pid == 0: # no /proc/0/fd
|
||||
return 0
|
||||
return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
return _common.pctxsw(
|
||||
*cext.proc_num_ctx_switches(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||
|
||||
if HAS_PROC_IO_COUNTERS:
|
||||
@wrap_exceptions
|
||||
def io_counters(self):
|
||||
try:
|
||||
rc, wc, rb, wb = cext.proc_io_counters(self.pid)
|
||||
except OSError:
|
||||
# if process is terminated, proc_io_counters returns OSError
|
||||
# instead of NSP
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise
|
||||
return _common.pio(rc, wc, rb, wb)
|
||||
903
third_party/python/psutil/psutil/_psbsd.py
vendored
Normal file
903
third_party/python/psutil/psutil/_psbsd.py
vendored
Normal file
|
|
@ -0,0 +1,903 @@
|
|||
# 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.
|
||||
|
||||
"""FreeBSD, OpenBSD and NetBSD platforms implementation."""
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import namedtuple
|
||||
from collections import defaultdict
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_bsd as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AccessDenied
|
||||
from ._common import conn_tmap
|
||||
from ._common import conn_to_ntuple
|
||||
from ._common import FREEBSD
|
||||
from ._common import memoize
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NETBSD
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import OPENBSD
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import which
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- globals
|
||||
# =====================================================================
|
||||
|
||||
|
||||
if FREEBSD:
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SWAIT: _common.STATUS_WAITING,
|
||||
cext.SLOCK: _common.STATUS_LOCKED,
|
||||
}
|
||||
elif OPENBSD or NETBSD:
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
# According to /usr/include/sys/proc.h SZOMB is unused.
|
||||
# test_zombie_process() shows that SDEAD is the right
|
||||
# equivalent. Also it appears there's no equivalent of
|
||||
# psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE.
|
||||
# cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SDEAD: _common.STATUS_ZOMBIE,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
# From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt
|
||||
# OpenBSD has SRUN and SONPROC: SRUN indicates that a process
|
||||
# is runnable but *not* yet running, i.e. is on a run queue.
|
||||
# SONPROC indicates that the process is actually executing on
|
||||
# a CPU, i.e. it is no longer on a run queue.
|
||||
# As such we'll map SRUN to STATUS_WAKING and SONPROC to
|
||||
# STATUS_RUNNING
|
||||
cext.SRUN: _common.STATUS_WAKING,
|
||||
cext.SONPROC: _common.STATUS_RUNNING,
|
||||
}
|
||||
elif NETBSD:
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SACTIVE: _common.STATUS_RUNNING,
|
||||
cext.SDYING: _common.STATUS_ZOMBIE,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SDEAD: _common.STATUS_DEAD,
|
||||
cext.SSUSPENDED: _common.STATUS_SUSPENDED, # unique to NetBSD
|
||||
}
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
if NETBSD:
|
||||
PAGESIZE = os.sysconf("SC_PAGESIZE")
|
||||
else:
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
HAS_PER_CPU_TIMES = hasattr(cext, "per_cpu_times")
|
||||
HAS_PROC_NUM_THREADS = hasattr(cext, "proc_num_threads")
|
||||
HAS_PROC_OPEN_FILES = hasattr(cext, 'proc_open_files')
|
||||
HAS_PROC_NUM_FDS = hasattr(cext, 'proc_num_fds')
|
||||
|
||||
kinfo_proc_map = dict(
|
||||
ppid=0,
|
||||
status=1,
|
||||
real_uid=2,
|
||||
effective_uid=3,
|
||||
saved_uid=4,
|
||||
real_gid=5,
|
||||
effective_gid=6,
|
||||
saved_gid=7,
|
||||
ttynr=8,
|
||||
create_time=9,
|
||||
ctx_switches_vol=10,
|
||||
ctx_switches_unvol=11,
|
||||
read_io_count=12,
|
||||
write_io_count=13,
|
||||
user_time=14,
|
||||
sys_time=15,
|
||||
ch_user_time=16,
|
||||
ch_sys_time=17,
|
||||
rss=18,
|
||||
vms=19,
|
||||
memtext=20,
|
||||
memdata=21,
|
||||
memstack=22,
|
||||
cpunum=23,
|
||||
name=24,
|
||||
)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
# =====================================================================
|
||||
|
||||
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple(
|
||||
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
||||
'active', 'inactive', 'buffers', 'cached', 'shared', 'wired'])
|
||||
# psutil.cpu_times()
|
||||
scputimes = namedtuple(
|
||||
'scputimes', ['user', 'nice', 'system', 'idle', 'irq'])
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms', 'text', 'data', 'stack'])
|
||||
# psutil.Process.memory_full_info()
|
||||
pfullmem = pmem
|
||||
# psutil.Process.cpu_times()
|
||||
pcputimes = namedtuple('pcputimes',
|
||||
['user', 'system', 'children_user', 'children_system'])
|
||||
# psutil.Process.memory_maps(grouped=True)
|
||||
pmmap_grouped = namedtuple(
|
||||
'pmmap_grouped', 'path rss, private, ref_count, shadow_count')
|
||||
# psutil.Process.memory_maps(grouped=False)
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count')
|
||||
# psutil.disk_io_counters()
|
||||
if FREEBSD:
|
||||
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes',
|
||||
'read_time', 'write_time',
|
||||
'busy_time'])
|
||||
else:
|
||||
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes'])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
"""System virtual memory as a namedtuple."""
|
||||
mem = cext.virtual_mem()
|
||||
total, free, active, inactive, wired, cached, buffers, shared = mem
|
||||
if NETBSD:
|
||||
# On NetBSD buffers and shared mem is determined via /proc.
|
||||
# The C ext set them to 0.
|
||||
with open('/proc/meminfo', 'rb') as f:
|
||||
for line in f:
|
||||
if line.startswith(b'Buffers:'):
|
||||
buffers = int(line.split()[1]) * 1024
|
||||
elif line.startswith(b'MemShared:'):
|
||||
shared = int(line.split()[1]) * 1024
|
||||
avail = inactive + cached + free
|
||||
used = active + wired + cached
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, used, free,
|
||||
active, inactive, buffers, cached, shared, wired)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""System swap memory as (total, used, free, sin, sout) namedtuple."""
|
||||
total, used, free, sin, sout = cext.swap_mem()
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- CPU
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system per-CPU times as a namedtuple"""
|
||||
user, nice, system, idle, irq = cext.cpu_times()
|
||||
return scputimes(user, nice, system, idle, irq)
|
||||
|
||||
|
||||
if HAS_PER_CPU_TIMES:
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a namedtuple"""
|
||||
ret = []
|
||||
for cpu_t in cext.per_cpu_times():
|
||||
user, nice, system, idle, irq = cpu_t
|
||||
item = scputimes(user, nice, system, idle, irq)
|
||||
ret.append(item)
|
||||
return ret
|
||||
else:
|
||||
# XXX
|
||||
# Ok, this is very dirty.
|
||||
# On FreeBSD < 8 we cannot gather per-cpu information, see:
|
||||
# https://github.com/giampaolo/psutil/issues/226
|
||||
# If num cpus > 1, on first call we return single cpu times to avoid a
|
||||
# crash at psutil import time.
|
||||
# Next calls will fail with NotImplementedError
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a namedtuple"""
|
||||
if cpu_count_logical() == 1:
|
||||
return [cpu_times()]
|
||||
if per_cpu_times.__called__:
|
||||
raise NotImplementedError("supported only starting from FreeBSD 8")
|
||||
per_cpu_times.__called__ = True
|
||||
return [cpu_times()]
|
||||
|
||||
per_cpu_times.__called__ = False
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
return cext.cpu_count_logical()
|
||||
|
||||
|
||||
if OPENBSD or NETBSD:
|
||||
def cpu_count_physical():
|
||||
# OpenBSD and NetBSD do not implement this.
|
||||
return 1 if cpu_count_logical() == 1 else None
|
||||
else:
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
# From the C module we'll get an XML string similar to this:
|
||||
# http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
|
||||
# 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]
|
||||
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 cpu_stats():
|
||||
"""Return various CPU stats as a named tuple."""
|
||||
if FREEBSD:
|
||||
# Note: the C ext is returning some metrics we are not exposing:
|
||||
# traps.
|
||||
ctxsw, intrs, soft_intrs, syscalls, traps = cext.cpu_stats()
|
||||
elif NETBSD:
|
||||
# XXX
|
||||
# Note about intrs: the C extension returns 0. intrs
|
||||
# can be determined via /proc/stat; it has the same value as
|
||||
# soft_intrs thought so the kernel is faking it (?).
|
||||
#
|
||||
# Note about syscalls: the C extension always sets it to 0 (?).
|
||||
#
|
||||
# Note: the C ext is returning some metrics we are not exposing:
|
||||
# traps, faults and forks.
|
||||
ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \
|
||||
cext.cpu_stats()
|
||||
with open('/proc/stat', 'rb') as f:
|
||||
for line in f:
|
||||
if line.startswith(b'intr'):
|
||||
intrs = int(line.split()[1])
|
||||
elif OPENBSD:
|
||||
# Note: the C ext is returning some metrics we are not exposing:
|
||||
# traps, faults and forks.
|
||||
ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \
|
||||
cext.cpu_stats()
|
||||
return _common.scpustats(ctxsw, intrs, soft_intrs, syscalls)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- disks
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return mounted disk partitions as a list of namedtuples.
|
||||
'all' argument is ignored, see:
|
||||
https://github.com/giampaolo/psutil/issues/906
|
||||
"""
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
disk_usage = _psposix.disk_usage
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
||||
|
||||
net_io_counters = cext.net_io_counters
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
names = net_io_counters().keys()
|
||||
ret = {}
|
||||
for name in names:
|
||||
try:
|
||||
mtu = cext_posix.net_if_mtu(name)
|
||||
isup = cext_posix.net_if_flags(name)
|
||||
duplex, speed = cext_posix.net_if_duplex_speed(name)
|
||||
except OSError as err:
|
||||
# https://github.com/giampaolo/psutil/issues/1279
|
||||
if err.errno != errno.ENODEV:
|
||||
raise
|
||||
else:
|
||||
if hasattr(_common, 'NicDuplex'):
|
||||
duplex = _common.NicDuplex(duplex)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
def net_connections(kind):
|
||||
"""System-wide network connections."""
|
||||
if OPENBSD:
|
||||
ret = []
|
||||
for pid in pids():
|
||||
try:
|
||||
cons = Process(pid).connections(kind)
|
||||
except (NoSuchProcess, ZombieProcess):
|
||||
continue
|
||||
else:
|
||||
for conn in cons:
|
||||
conn = list(conn)
|
||||
conn.append(pid)
|
||||
ret.append(_common.sconn(*conn))
|
||||
return ret
|
||||
|
||||
if kind not in _common.conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
families, types = conn_tmap[kind]
|
||||
ret = set()
|
||||
if NETBSD:
|
||||
rawlist = cext.net_connections(-1)
|
||||
else:
|
||||
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:
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES, pid)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- sensors
|
||||
# =====================================================================
|
||||
|
||||
|
||||
if FREEBSD:
|
||||
|
||||
def sensors_battery():
|
||||
"""Return battery info."""
|
||||
try:
|
||||
percent, minsleft, power_plugged = cext.sensors_battery()
|
||||
except NotImplementedError:
|
||||
# See: https://github.com/giampaolo/psutil/issues/1074
|
||||
return None
|
||||
power_plugged = power_plugged == 1
|
||||
if power_plugged:
|
||||
secsleft = _common.POWER_TIME_UNLIMITED
|
||||
elif minsleft == -1:
|
||||
secsleft = _common.POWER_TIME_UNKNOWN
|
||||
else:
|
||||
secsleft = minsleft * 60
|
||||
return _common.sbattery(percent, secsleft, power_plugged)
|
||||
|
||||
def sensors_temperatures():
|
||||
"Return CPU cores temperatures if available, else an empty dict."
|
||||
ret = defaultdict(list)
|
||||
num_cpus = cpu_count_logical()
|
||||
for cpu in range(num_cpus):
|
||||
try:
|
||||
current, high = cext.sensors_cpu_temperature(cpu)
|
||||
if high <= 0:
|
||||
high = None
|
||||
name = "Core %s" % cpu
|
||||
ret["coretemp"].append(
|
||||
_common.shwtemp(name, current, high, high))
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
return ret
|
||||
|
||||
def cpu_freq():
|
||||
"""Return frequency metrics for CPUs. As of Dec 2018 only
|
||||
CPU 0 appears to be supported by FreeBSD and all other cores
|
||||
match the frequency of CPU 0.
|
||||
"""
|
||||
ret = []
|
||||
num_cpus = cpu_count_logical()
|
||||
for cpu in range(num_cpus):
|
||||
try:
|
||||
current, available_freq = cext.cpu_frequency(cpu)
|
||||
except NotImplementedError:
|
||||
continue
|
||||
if available_freq:
|
||||
try:
|
||||
min_freq = int(available_freq.split(" ")[-1].split("/")[0])
|
||||
except(IndexError, ValueError):
|
||||
min_freq = None
|
||||
try:
|
||||
max_freq = int(available_freq.split(" ")[0].split("/")[0])
|
||||
except(IndexError, ValueError):
|
||||
max_freq = None
|
||||
ret.append(_common.scpufreq(current, min_freq, max_freq))
|
||||
return ret
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- other system functions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, pid = item
|
||||
if pid == -1:
|
||||
assert OPENBSD
|
||||
pid = None
|
||||
if tty == '~':
|
||||
continue # reboot or shutdown
|
||||
nt = _common.suser(user, tty or None, hostname, tstamp, pid)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- processes
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@memoize
|
||||
def _pid_0_exists():
|
||||
try:
|
||||
Process(0).name()
|
||||
except NoSuchProcess:
|
||||
return False
|
||||
except AccessDenied:
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def pids():
|
||||
"""Returns a list of PIDs currently running on the system."""
|
||||
ret = cext.pids()
|
||||
if OPENBSD and (0 not in ret) and _pid_0_exists():
|
||||
# On OpenBSD the kernel does not return PID 0 (neither does
|
||||
# ps) but it's actually querable (Process(0) will succeed).
|
||||
ret.insert(0, 0)
|
||||
return ret
|
||||
|
||||
|
||||
if OPENBSD or NETBSD:
|
||||
def pid_exists(pid):
|
||||
"""Return True if pid exists."""
|
||||
exists = _psposix.pid_exists(pid)
|
||||
if not exists:
|
||||
# We do this because _psposix.pid_exists() lies in case of
|
||||
# zombie processes.
|
||||
return pid in pids()
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
pid_exists = _psposix.pid_exists
|
||||
|
||||
|
||||
def is_zombie(pid):
|
||||
try:
|
||||
st = cext.proc_oneshot_info(pid)[kinfo_proc_map['status']]
|
||||
return st == cext.SZOMB
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Decorator which translates bare OSError exceptions into
|
||||
NoSuchProcess and AccessDenied.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except ProcessLookupError:
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
except OSError:
|
||||
if self.pid == 0:
|
||||
if 0 in pids():
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
else:
|
||||
raise
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def wrap_exceptions_procfs(inst):
|
||||
"""Same as above, for routines relying on reading /proc fs."""
|
||||
try:
|
||||
yield
|
||||
except (ProcessLookupError, FileNotFoundError):
|
||||
# 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 not pid_exists(inst.pid):
|
||||
raise NoSuchProcess(inst.pid, inst._name)
|
||||
else:
|
||||
raise ZombieProcess(inst.pid, inst._name, inst._ppid)
|
||||
except PermissionError:
|
||||
raise AccessDenied(inst.pid, inst._name)
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
|
||||
def _assert_alive(self):
|
||||
"""Raise NSP if the process disappeared on us."""
|
||||
# For those C function who do not raise NSP, possibly returning
|
||||
# incorrect or incomplete result.
|
||||
cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def oneshot(self):
|
||||
"""Retrieves multiple process info in one shot as a raw tuple."""
|
||||
ret = cext.proc_oneshot_info(self.pid)
|
||||
assert len(ret) == len(kinfo_proc_map)
|
||||
return ret
|
||||
|
||||
def oneshot_enter(self):
|
||||
self.oneshot.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self.oneshot.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
name = self.oneshot()[kinfo_proc_map['name']]
|
||||
return name if name is not None else cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
if FREEBSD:
|
||||
if self.pid == 0:
|
||||
return '' # else NSP
|
||||
return cext.proc_exe(self.pid)
|
||||
elif NETBSD:
|
||||
if self.pid == 0:
|
||||
# /proc/0 dir exists but /proc/0/exe doesn't
|
||||
return ""
|
||||
with wrap_exceptions_procfs(self):
|
||||
return os.readlink("/proc/%s/exe" % self.pid)
|
||||
else:
|
||||
# OpenBSD: exe cannot be determined; references:
|
||||
# https://chromium.googlesource.com/chromium/src/base/+/
|
||||
# master/base_paths_posix.cc
|
||||
# We try our best guess by using which against the first
|
||||
# cmdline arg (may return None).
|
||||
cmdline = self.cmdline()
|
||||
if cmdline:
|
||||
return which(cmdline[0]) or ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
if OPENBSD and self.pid == 0:
|
||||
return [] # ...else it crashes
|
||||
elif NETBSD:
|
||||
# XXX - most of the times the underlying sysctl() call on Net
|
||||
# and Open BSD returns a truncated string.
|
||||
# Also /proc/pid/cmdline behaves the same so it looks
|
||||
# like this is a kernel bug.
|
||||
try:
|
||||
return cext.proc_cmdline(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINVAL:
|
||||
if is_zombie(self.pid):
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
elif not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name, self._ppid)
|
||||
else:
|
||||
# XXX: this happens with unicode tests. It means the C
|
||||
# routine is unable to decode invalid unicode chars.
|
||||
return []
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
return cext.proc_cmdline(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
tty_nr = self.oneshot()[kinfo_proc_map['ttynr']]
|
||||
tmap = _psposix.get_terminal_map()
|
||||
try:
|
||||
return tmap[tty_nr]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
self._ppid = self.oneshot()[kinfo_proc_map['ppid']]
|
||||
return self._ppid
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.puids(
|
||||
rawtuple[kinfo_proc_map['real_uid']],
|
||||
rawtuple[kinfo_proc_map['effective_uid']],
|
||||
rawtuple[kinfo_proc_map['saved_uid']])
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.pgids(
|
||||
rawtuple[kinfo_proc_map['real_gid']],
|
||||
rawtuple[kinfo_proc_map['effective_gid']],
|
||||
rawtuple[kinfo_proc_map['saved_gid']])
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.pcputimes(
|
||||
rawtuple[kinfo_proc_map['user_time']],
|
||||
rawtuple[kinfo_proc_map['sys_time']],
|
||||
rawtuple[kinfo_proc_map['ch_user_time']],
|
||||
rawtuple[kinfo_proc_map['ch_sys_time']])
|
||||
|
||||
if FREEBSD:
|
||||
@wrap_exceptions
|
||||
def cpu_num(self):
|
||||
return self.oneshot()[kinfo_proc_map['cpunum']]
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
rawtuple = self.oneshot()
|
||||
return pmem(
|
||||
rawtuple[kinfo_proc_map['rss']],
|
||||
rawtuple[kinfo_proc_map['vms']],
|
||||
rawtuple[kinfo_proc_map['memtext']],
|
||||
rawtuple[kinfo_proc_map['memdata']],
|
||||
rawtuple[kinfo_proc_map['memstack']])
|
||||
|
||||
memory_full_info = memory_info
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return self.oneshot()[kinfo_proc_map['create_time']]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
if HAS_PROC_NUM_THREADS:
|
||||
# FreeBSD
|
||||
return cext.proc_num_threads(self.pid)
|
||||
else:
|
||||
return len(self.threads())
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.pctxsw(
|
||||
rawtuple[kinfo_proc_map['ctx_switches_vol']],
|
||||
rawtuple[kinfo_proc_map['ctx_switches_unvol']])
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
# Note: on OpenSBD this (/dev/mem) requires root access.
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
if OPENBSD:
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
if kind not in conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
|
||||
if NETBSD:
|
||||
families, types = conn_tmap[kind]
|
||||
ret = []
|
||||
rawlist = cext.net_connections(self.pid)
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status, pid = item
|
||||
assert pid == self.pid
|
||||
if fam in families and type in types:
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
self._assert_alive()
|
||||
return list(ret)
|
||||
|
||||
families, types = conn_tmap[kind]
|
||||
rawlist = cext.proc_connections(self.pid, families, types)
|
||||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
|
||||
if OPENBSD:
|
||||
self._assert_alive()
|
||||
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
return cext_posix.getpriority(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = self.oneshot()[kinfo_proc_map['status']]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
@wrap_exceptions
|
||||
def io_counters(self):
|
||||
rawtuple = self.oneshot()
|
||||
return _common.pio(
|
||||
rawtuple[kinfo_proc_map['read_io_count']],
|
||||
rawtuple[kinfo_proc_map['write_io_count']],
|
||||
-1,
|
||||
-1)
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
"""Return process current working directory."""
|
||||
# sometimes we get an empty string, in which case we turn
|
||||
# it into None
|
||||
if OPENBSD and self.pid == 0:
|
||||
return None # ...else it would raise EINVAL
|
||||
elif NETBSD or HAS_PROC_OPEN_FILES:
|
||||
# FreeBSD < 8 does not support functions based on
|
||||
# kinfo_getfile() and kinfo_getvmmap()
|
||||
return cext.proc_cwd(self.pid) or None
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"supported only starting from FreeBSD 8" if
|
||||
FREEBSD else "")
|
||||
|
||||
nt_mmap_grouped = namedtuple(
|
||||
'mmap', 'path rss, private, ref_count, shadow_count')
|
||||
nt_mmap_ext = namedtuple(
|
||||
'mmap', 'addr, perms path rss, private, ref_count, shadow_count')
|
||||
|
||||
def _not_implemented(self):
|
||||
raise NotImplementedError
|
||||
|
||||
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||
# and kinfo_getvmmap()
|
||||
if HAS_PROC_OPEN_FILES:
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
"""Return files opened by process as a list of namedtuples."""
|
||||
rawlist = cext.proc_open_files(self.pid)
|
||||
return [_common.popenfile(path, fd) for path, fd in rawlist]
|
||||
else:
|
||||
open_files = _not_implemented
|
||||
|
||||
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||
# and kinfo_getvmmap()
|
||||
if HAS_PROC_NUM_FDS:
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
"""Return the number of file descriptors opened by this process."""
|
||||
ret = cext.proc_num_fds(self.pid)
|
||||
if NETBSD:
|
||||
self._assert_alive()
|
||||
return ret
|
||||
else:
|
||||
num_fds = _not_implemented
|
||||
|
||||
# --- FreeBSD only APIs
|
||||
|
||||
if FREEBSD:
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_affinity_get(self):
|
||||
return cext.proc_cpu_affinity_get(self.pid)
|
||||
|
||||
@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:
|
||||
# 'man cpuset_setaffinity' about EDEADLK:
|
||||
# <<the call would leave a thread without a valid CPU to run
|
||||
# on because the set does not overlap with the thread's
|
||||
# anonymous mask>>
|
||||
if err.errno in (errno.EINVAL, errno.EDEADLK):
|
||||
for cpu in cpus:
|
||||
if cpu not in allcpus:
|
||||
raise ValueError(
|
||||
"invalid CPU #%i (choose between %s)" % (
|
||||
cpu, allcpus))
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_maps(self):
|
||||
return cext.proc_memory_maps(self.pid)
|
||||
2095
third_party/python/psutil/psutil/_pslinux.py
vendored
Normal file
2095
third_party/python/psutil/psutil/_pslinux.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
564
third_party/python/psutil/psutil/_psosx.py
vendored
Normal file
564
third_party/python/psutil/psutil/_psosx.py
vendored
Normal file
|
|
@ -0,0 +1,564 @@
|
|||
# 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.
|
||||
|
||||
"""macOS platform implementation."""
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_osx as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AccessDenied
|
||||
from ._common import conn_tmap
|
||||
from ._common import conn_to_ntuple
|
||||
from ._common import isfile_strict
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import parse_environ_block
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- globals
|
||||
# =====================================================================
|
||||
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RECEIVED: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
}
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
}
|
||||
|
||||
kinfo_proc_map = dict(
|
||||
ppid=0,
|
||||
ruid=1,
|
||||
euid=2,
|
||||
suid=3,
|
||||
rgid=4,
|
||||
egid=5,
|
||||
sgid=6,
|
||||
ttynr=7,
|
||||
ctime=8,
|
||||
status=9,
|
||||
name=10,
|
||||
)
|
||||
|
||||
pidtaskinfo_map = dict(
|
||||
cpuutime=0,
|
||||
cpustime=1,
|
||||
rss=2,
|
||||
vms=3,
|
||||
pfaults=4,
|
||||
pageins=5,
|
||||
numthreads=6,
|
||||
volctxsw=7,
|
||||
)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
# =====================================================================
|
||||
|
||||
|
||||
# psutil.cpu_times()
|
||||
scputimes = namedtuple('scputimes', ['user', 'nice', 'system', 'idle'])
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple(
|
||||
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
||||
'active', 'inactive', 'wired'])
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms', 'pfaults', 'pageins'])
|
||||
# psutil.Process.memory_full_info()
|
||||
pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', ))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
"""System virtual memory as a namedtuple."""
|
||||
total, active, inactive, wired, free, speculative = cext.virtual_mem()
|
||||
# This is how Zabbix calculate avail and used mem:
|
||||
# https://github.com/zabbix/zabbix/blob/trunk/src/libs/zbxsysinfo/
|
||||
# osx/memory.c
|
||||
# Also see: https://github.com/giampaolo/psutil/issues/1277
|
||||
avail = inactive + free
|
||||
used = active + wired
|
||||
# This is NOT how Zabbix calculates free mem but it matches "free"
|
||||
# cmdline utility.
|
||||
free -= speculative
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, used, free,
|
||||
active, inactive, wired)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
|
||||
total, used, free, sin, sout = cext.swap_mem()
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- CPU
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system CPU times as a namedtuple."""
|
||||
user, nice, system, idle = cext.cpu_times()
|
||||
return scputimes(user, nice, system, idle)
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a named tuple"""
|
||||
ret = []
|
||||
for cpu_t in cext.per_cpu_times():
|
||||
user, nice, system, idle = cpu_t
|
||||
item = scputimes(user, nice, system, idle)
|
||||
ret.append(item)
|
||||
return ret
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
return cext.cpu_count_logical()
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
return cext.cpu_count_phys()
|
||||
|
||||
|
||||
def cpu_stats():
|
||||
ctx_switches, interrupts, soft_interrupts, syscalls, traps = \
|
||||
cext.cpu_stats()
|
||||
return _common.scpustats(
|
||||
ctx_switches, interrupts, soft_interrupts, syscalls)
|
||||
|
||||
|
||||
def cpu_freq():
|
||||
"""Return CPU frequency.
|
||||
On macOS per-cpu frequency is not supported.
|
||||
Also, the returned frequency never changes, see:
|
||||
https://arstechnica.com/civis/viewtopic.php?f=19&t=465002
|
||||
"""
|
||||
curr, min_, max_ = cext.cpu_freq()
|
||||
return [_common.scpufreq(curr, min_, max_)]
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- disks
|
||||
# =====================================================================
|
||||
|
||||
|
||||
disk_usage = _psposix.disk_usage
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return mounted disk partitions as a list of namedtuples."""
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
if not os.path.isabs(device) or not os.path.exists(device):
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- sensors
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def sensors_battery():
|
||||
"""Return battery information."""
|
||||
try:
|
||||
percent, minsleft, power_plugged = cext.sensors_battery()
|
||||
except NotImplementedError:
|
||||
# no power source - return None according to interface
|
||||
return None
|
||||
power_plugged = power_plugged == 1
|
||||
if power_plugged:
|
||||
secsleft = _common.POWER_TIME_UNLIMITED
|
||||
elif minsleft == -1:
|
||||
secsleft = _common.POWER_TIME_UNKNOWN
|
||||
else:
|
||||
secsleft = minsleft * 60
|
||||
return _common.sbattery(percent, secsleft, power_plugged)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
||||
|
||||
net_io_counters = cext.net_io_counters
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def net_connections(kind='inet'):
|
||||
"""System-wide network connections."""
|
||||
# Note: on macOS this will fail with AccessDenied unless
|
||||
# the process is owned by root.
|
||||
ret = []
|
||||
for pid in pids():
|
||||
try:
|
||||
cons = Process(pid).connections(kind)
|
||||
except NoSuchProcess:
|
||||
continue
|
||||
else:
|
||||
if cons:
|
||||
for c in cons:
|
||||
c = list(c) + [pid]
|
||||
ret.append(_common.sconn(*c))
|
||||
return ret
|
||||
|
||||
|
||||
def net_if_stats():
|
||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||
names = net_io_counters().keys()
|
||||
ret = {}
|
||||
for name in names:
|
||||
try:
|
||||
mtu = cext_posix.net_if_mtu(name)
|
||||
isup = cext_posix.net_if_flags(name)
|
||||
duplex, speed = cext_posix.net_if_duplex_speed(name)
|
||||
except OSError as err:
|
||||
# https://github.com/giampaolo/psutil/issues/1279
|
||||
if err.errno != errno.ENODEV:
|
||||
raise
|
||||
else:
|
||||
if hasattr(_common, 'NicDuplex'):
|
||||
duplex = _common.NicDuplex(duplex)
|
||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||
return ret
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- other system functions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, pid = item
|
||||
if tty == '~':
|
||||
continue # reboot or shutdown
|
||||
if not tstamp:
|
||||
continue
|
||||
nt = _common.suser(user, tty or None, hostname or None, tstamp, pid)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- processes
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def pids():
|
||||
ls = cext.pids()
|
||||
if 0 not in ls:
|
||||
# On certain macOS versions pids() C doesn't return PID 0 but
|
||||
# "ps" does and the process is querable via sysctl():
|
||||
# https://travis-ci.org/giampaolo/psutil/jobs/309619941
|
||||
try:
|
||||
Process(0).create_time()
|
||||
ls.insert(0, 0)
|
||||
except NoSuchProcess:
|
||||
pass
|
||||
except AccessDenied:
|
||||
ls.insert(0, 0)
|
||||
return ls
|
||||
|
||||
|
||||
pid_exists = _psposix.pid_exists
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Decorator which translates bare OSError exceptions into
|
||||
NoSuchProcess and AccessDenied.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except ProcessLookupError:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
except cext.ZombieProcessError:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
return wrapper
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def catch_zombie(proc):
|
||||
"""There are some poor C APIs which incorrectly raise ESRCH when
|
||||
the process is still alive or it's a zombie, or even RuntimeError
|
||||
(those who don't set errno). This is here in order to solve:
|
||||
https://github.com/giampaolo/psutil/issues/1044
|
||||
"""
|
||||
try:
|
||||
yield
|
||||
except (OSError, RuntimeError) as err:
|
||||
if isinstance(err, RuntimeError) or err.errno == errno.ESRCH:
|
||||
try:
|
||||
# status() is not supposed to lie and correctly detect
|
||||
# zombies so if it raises ESRCH it's true.
|
||||
status = proc.status()
|
||||
except NoSuchProcess:
|
||||
raise err
|
||||
else:
|
||||
if status == _common.STATUS_ZOMBIE:
|
||||
raise ZombieProcess(proc.pid, proc._name, proc._ppid)
|
||||
else:
|
||||
raise AccessDenied(proc.pid, proc._name)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _get_kinfo_proc(self):
|
||||
# Note: should work with all PIDs without permission issues.
|
||||
ret = cext.proc_kinfo_oneshot(self.pid)
|
||||
assert len(ret) == len(kinfo_proc_map)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _get_pidtaskinfo(self):
|
||||
# Note: should work for PIDs owned by user only.
|
||||
with catch_zombie(self):
|
||||
ret = cext.proc_pidtaskinfo_oneshot(self.pid)
|
||||
assert len(ret) == len(pidtaskinfo_map)
|
||||
return ret
|
||||
|
||||
def oneshot_enter(self):
|
||||
self._get_kinfo_proc.cache_activate(self)
|
||||
self._get_pidtaskinfo.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self._get_kinfo_proc.cache_deactivate(self)
|
||||
self._get_pidtaskinfo.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
name = self._get_kinfo_proc()[kinfo_proc_map['name']]
|
||||
return name if name is not None else cext.proc_name(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
with catch_zombie(self):
|
||||
return cext.proc_exe(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
with catch_zombie(self):
|
||||
return cext.proc_cmdline(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def environ(self):
|
||||
with catch_zombie(self):
|
||||
return parse_environ_block(cext.proc_environ(self.pid))
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
self._ppid = self._get_kinfo_proc()[kinfo_proc_map['ppid']]
|
||||
return self._ppid
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
with catch_zombie(self):
|
||||
return cext.proc_cwd(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
rawtuple = self._get_kinfo_proc()
|
||||
return _common.puids(
|
||||
rawtuple[kinfo_proc_map['ruid']],
|
||||
rawtuple[kinfo_proc_map['euid']],
|
||||
rawtuple[kinfo_proc_map['suid']])
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
rawtuple = self._get_kinfo_proc()
|
||||
return _common.puids(
|
||||
rawtuple[kinfo_proc_map['rgid']],
|
||||
rawtuple[kinfo_proc_map['egid']],
|
||||
rawtuple[kinfo_proc_map['sgid']])
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
tty_nr = self._get_kinfo_proc()[kinfo_proc_map['ttynr']]
|
||||
tmap = _psposix.get_terminal_map()
|
||||
try:
|
||||
return tmap[tty_nr]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
rawtuple = self._get_pidtaskinfo()
|
||||
return pmem(
|
||||
rawtuple[pidtaskinfo_map['rss']],
|
||||
rawtuple[pidtaskinfo_map['vms']],
|
||||
rawtuple[pidtaskinfo_map['pfaults']],
|
||||
rawtuple[pidtaskinfo_map['pageins']],
|
||||
)
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_full_info(self):
|
||||
basic_mem = self.memory_info()
|
||||
uss = cext.proc_memory_uss(self.pid)
|
||||
return pfullmem(*basic_mem + (uss, ))
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
rawtuple = self._get_pidtaskinfo()
|
||||
return _common.pcputimes(
|
||||
rawtuple[pidtaskinfo_map['cpuutime']],
|
||||
rawtuple[pidtaskinfo_map['cpustime']],
|
||||
# children user / system times are not retrievable (set to 0)
|
||||
0.0, 0.0)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return self._get_kinfo_proc()[kinfo_proc_map['ctime']]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
# Unvoluntary value seems not to be available;
|
||||
# getrusage() numbers seems to confirm this theory.
|
||||
# We set it to 0.
|
||||
vol = self._get_pidtaskinfo()[pidtaskinfo_map['volctxsw']]
|
||||
return _common.pctxsw(vol, 0)
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return self._get_pidtaskinfo()[pidtaskinfo_map['numthreads']]
|
||||
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
if self.pid == 0:
|
||||
return []
|
||||
files = []
|
||||
with catch_zombie(self):
|
||||
rawlist = cext.proc_open_files(self.pid)
|
||||
for path, fd in rawlist:
|
||||
if isfile_strict(path):
|
||||
ntuple = _common.popenfile(path, fd)
|
||||
files.append(ntuple)
|
||||
return files
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
if kind not in conn_tmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||
families, types = conn_tmap[kind]
|
||||
with catch_zombie(self):
|
||||
rawlist = cext.proc_connections(self.pid, families, types)
|
||||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
if self.pid == 0:
|
||||
return 0
|
||||
with catch_zombie(self):
|
||||
return cext.proc_num_fds(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
with catch_zombie(self):
|
||||
return cext_posix.getpriority(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
with catch_zombie(self):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = self._get_kinfo_proc()[kinfo_proc_map['status']]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
rawlist = cext.proc_threads(self.pid)
|
||||
retlist = []
|
||||
for thread_id, utime, stime in rawlist:
|
||||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
175
third_party/python/psutil/psutil/_psposix.py
vendored
Normal file
175
third_party/python/psutil/psutil/_psposix.py
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# 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.
|
||||
|
||||
"""Routines common to all posix systems."""
|
||||
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from ._common import memoize
|
||||
from ._common import sdiskusage
|
||||
from ._common import TimeoutExpired
|
||||
from ._common import usage_percent
|
||||
from ._compat import ChildProcessError
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import InterruptedError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3
|
||||
from ._compat import unicode
|
||||
|
||||
|
||||
__all__ = ['pid_exists', 'wait_pid', 'disk_usage', 'get_terminal_map']
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check whether pid exists in the current process table."""
|
||||
if pid == 0:
|
||||
# According to "man 2 kill" PID 0 has a special meaning:
|
||||
# it refers to <<every process in the process group of the
|
||||
# calling process>> so we don't want to go any further.
|
||||
# If we get here it means this UNIX platform *does* have
|
||||
# a process with id 0.
|
||||
return True
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
except PermissionError:
|
||||
# EPERM clearly means there's a process to deny access to
|
||||
return True
|
||||
# According to "man 2 kill" possible error values are
|
||||
# (EINVAL, EPERM, ESRCH)
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def wait_pid(pid, timeout=None, proc_name=None):
|
||||
"""Wait for process with pid 'pid' to terminate and return its
|
||||
exit status code as an integer.
|
||||
|
||||
If pid is not a children of os.getpid() (current process) just
|
||||
waits until the process disappears and return None.
|
||||
|
||||
If pid does not exist at all return None immediately.
|
||||
|
||||
Raise TimeoutExpired on timeout expired.
|
||||
"""
|
||||
def check_timeout(delay):
|
||||
if timeout is not None:
|
||||
if timer() >= stop_at:
|
||||
raise TimeoutExpired(timeout, pid=pid, name=proc_name)
|
||||
time.sleep(delay)
|
||||
return min(delay * 2, 0.04)
|
||||
|
||||
timer = getattr(time, 'monotonic', time.time)
|
||||
if timeout is not None:
|
||||
def waitcall():
|
||||
return os.waitpid(pid, os.WNOHANG)
|
||||
stop_at = timer() + timeout
|
||||
else:
|
||||
def waitcall():
|
||||
return os.waitpid(pid, 0)
|
||||
|
||||
delay = 0.0001
|
||||
while True:
|
||||
try:
|
||||
retpid, status = waitcall()
|
||||
except InterruptedError:
|
||||
delay = check_timeout(delay)
|
||||
except ChildProcessError:
|
||||
# This has two meanings:
|
||||
# - pid is not a child of os.getpid() in which case
|
||||
# we keep polling until it's gone
|
||||
# - pid never existed in the first place
|
||||
# In both cases we'll eventually return None as we
|
||||
# can't determine its exit status code.
|
||||
while True:
|
||||
if pid_exists(pid):
|
||||
delay = check_timeout(delay)
|
||||
else:
|
||||
return
|
||||
else:
|
||||
if retpid == 0:
|
||||
# WNOHANG was used, pid is still running
|
||||
delay = check_timeout(delay)
|
||||
continue
|
||||
# process exited due to a signal; return the integer of
|
||||
# that signal
|
||||
if os.WIFSIGNALED(status):
|
||||
return -os.WTERMSIG(status)
|
||||
# process exited using exit(2) system call; return the
|
||||
# integer exit(2) system call has been called with
|
||||
elif os.WIFEXITED(status):
|
||||
return os.WEXITSTATUS(status)
|
||||
else:
|
||||
# should never happen
|
||||
raise ValueError("unknown process exit status %r" % status)
|
||||
|
||||
|
||||
def disk_usage(path):
|
||||
"""Return disk usage associated with path.
|
||||
Note: UNIX usually reserves 5% disk space which is not accessible
|
||||
by user. In this function "total" and "used" values reflect the
|
||||
total and used disk space whereas "free" and "percent" represent
|
||||
the "free" and "used percent" user disk space.
|
||||
"""
|
||||
if PY3:
|
||||
st = os.statvfs(path)
|
||||
else:
|
||||
# os.statvfs() does not support unicode on Python 2:
|
||||
# - https://github.com/giampaolo/psutil/issues/416
|
||||
# - http://bugs.python.org/issue18695
|
||||
try:
|
||||
st = os.statvfs(path)
|
||||
except UnicodeEncodeError:
|
||||
if isinstance(path, unicode):
|
||||
try:
|
||||
path = path.encode(sys.getfilesystemencoding())
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
st = os.statvfs(path)
|
||||
else:
|
||||
raise
|
||||
|
||||
# Total space which is only available to root (unless changed
|
||||
# at system level).
|
||||
total = (st.f_blocks * st.f_frsize)
|
||||
# Remaining free space usable by root.
|
||||
avail_to_root = (st.f_bfree * st.f_frsize)
|
||||
# Remaining free space usable by user.
|
||||
avail_to_user = (st.f_bavail * st.f_frsize)
|
||||
# Total space being used in general.
|
||||
used = (total - avail_to_root)
|
||||
# Total space which is available to user (same as 'total' but
|
||||
# for the user).
|
||||
total_user = used + avail_to_user
|
||||
# User usage percent compared to the total amount of space
|
||||
# the user can use. This number would be higher if compared
|
||||
# to root's because the user has less space (usually -5%).
|
||||
usage_percent_user = usage_percent(used, total_user, round_=1)
|
||||
|
||||
# NB: the percentage is -5% than what shown by df due to
|
||||
# reserved blocks that we are currently not considering:
|
||||
# https://github.com/giampaolo/psutil/issues/829#issuecomment-223750462
|
||||
return sdiskusage(
|
||||
total=total, used=used, free=avail_to_user, percent=usage_percent_user)
|
||||
|
||||
|
||||
@memoize
|
||||
def get_terminal_map():
|
||||
"""Get a map of device-id -> path as a dict.
|
||||
Used by Process.terminal()
|
||||
"""
|
||||
ret = {}
|
||||
ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*')
|
||||
for name in ls:
|
||||
assert name not in ret, name
|
||||
try:
|
||||
ret[os.stat(name).st_rdev] = name
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return ret
|
||||
725
third_party/python/psutil/psutil/_pssunos.py
vendored
Normal file
725
third_party/python/psutil/psutil/_pssunos.py
vendored
Normal file
|
|
@ -0,0 +1,725 @@
|
|||
# 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.
|
||||
|
||||
"""Sun OS Solaris platform implementation."""
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_posix as cext_posix
|
||||
from . import _psutil_sunos as cext
|
||||
from ._common import AccessDenied
|
||||
from ._common import AF_INET6
|
||||
from ._common import debug
|
||||
from ._common import get_procfs_path
|
||||
from ._common import isfile_strict
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import b
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3
|
||||
|
||||
|
||||
__extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"]
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- globals
|
||||
# =====================================================================
|
||||
|
||||
|
||||
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
|
||||
AF_LINK = cext_posix.AF_LINK
|
||||
IS_64_BIT = sys.maxsize > 2**32
|
||||
|
||||
CONN_IDLE = "IDLE"
|
||||
CONN_BOUND = "BOUND"
|
||||
|
||||
PROC_STATUSES = {
|
||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||
cext.SRUN: _common.STATUS_RUNNING,
|
||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||
cext.SSTOP: _common.STATUS_STOPPED,
|
||||
cext.SIDL: _common.STATUS_IDLE,
|
||||
cext.SONPROC: _common.STATUS_RUNNING, # same as run
|
||||
cext.SWAIT: _common.STATUS_WAITING,
|
||||
}
|
||||
|
||||
TCP_STATUSES = {
|
||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||
cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV,
|
||||
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||
cext.TCPS_IDLE: CONN_IDLE, # sunos specific
|
||||
cext.TCPS_BOUND: CONN_BOUND, # sunos specific
|
||||
}
|
||||
|
||||
proc_info_map = dict(
|
||||
ppid=0,
|
||||
rss=1,
|
||||
vms=2,
|
||||
create_time=3,
|
||||
nice=4,
|
||||
num_threads=5,
|
||||
status=6,
|
||||
ttynr=7,
|
||||
uid=8,
|
||||
euid=9,
|
||||
gid=10,
|
||||
egid=11)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
# =====================================================================
|
||||
|
||||
|
||||
# psutil.cpu_times()
|
||||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
||||
# psutil.cpu_times(percpu=True)
|
||||
pcputimes = namedtuple('pcputimes',
|
||||
['user', 'system', 'children_user', 'children_system'])
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||
# psutil.Process.memory_info()
|
||||
pmem = namedtuple('pmem', ['rss', 'vms'])
|
||||
pfullmem = pmem
|
||||
# psutil.Process.memory_maps(grouped=True)
|
||||
pmmap_grouped = namedtuple('pmmap_grouped',
|
||||
['path', 'rss', 'anonymous', 'locked'])
|
||||
# psutil.Process.memory_maps(grouped=False)
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def virtual_memory():
|
||||
"""Report virtual memory metrics."""
|
||||
# we could have done this with kstat, but IMHO this is good enough
|
||||
total = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE
|
||||
# note: there's no difference on Solaris
|
||||
free = avail = os.sysconf('SC_AVPHYS_PAGES') * PAGE_SIZE
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return svmem(total, avail, percent, used, free)
|
||||
|
||||
|
||||
def swap_memory():
|
||||
"""Report swap memory metrics."""
|
||||
sin, sout = cext.swap_mem()
|
||||
# XXX
|
||||
# we are supposed to get total/free by doing so:
|
||||
# http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/
|
||||
# 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(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' %
|
||||
os.environ['PATH'], 'swap', '-l'],
|
||||
stdout=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout = stdout.decode(sys.stdout.encoding)
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError("'swap -l' failed (retcode=%s)" % p.returncode)
|
||||
|
||||
lines = stdout.strip().split('\n')[1:]
|
||||
if not lines:
|
||||
raise RuntimeError('no swap device(s) configured')
|
||||
total = free = 0
|
||||
for line in lines:
|
||||
line = line.split()
|
||||
t, f = line[-2:]
|
||||
total += int(int(t) * 512)
|
||||
free += int(int(f) * 512)
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent,
|
||||
sin * PAGE_SIZE, sout * PAGE_SIZE)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- CPU
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def cpu_times():
|
||||
"""Return system-wide CPU times as a named tuple"""
|
||||
ret = cext.per_cpu_times()
|
||||
return scputimes(*[sum(x) for x in zip(*ret)])
|
||||
|
||||
|
||||
def per_cpu_times():
|
||||
"""Return system per-CPU times as a list of named tuples"""
|
||||
ret = cext.per_cpu_times()
|
||||
return [scputimes(*x) for x in ret]
|
||||
|
||||
|
||||
def cpu_count_logical():
|
||||
"""Return the number of logical CPUs in the system."""
|
||||
try:
|
||||
return os.sysconf("SC_NPROCESSORS_ONLN")
|
||||
except ValueError:
|
||||
# mimic os.cpu_count() behavior
|
||||
return None
|
||||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
return cext.cpu_count_phys()
|
||||
|
||||
|
||||
def cpu_stats():
|
||||
"""Return various CPU stats as a named tuple."""
|
||||
ctx_switches, interrupts, syscalls, traps = cext.cpu_stats()
|
||||
soft_interrupts = 0
|
||||
return _common.scpustats(ctx_switches, interrupts, soft_interrupts,
|
||||
syscalls)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- disks
|
||||
# =====================================================================
|
||||
|
||||
|
||||
disk_io_counters = cext.disk_io_counters
|
||||
disk_usage = _psposix.disk_usage
|
||||
|
||||
|
||||
def disk_partitions(all=False):
|
||||
"""Return system disk partitions."""
|
||||
# TODO - the filtering logic should be better checked so that
|
||||
# it tries to reflect 'df' as much as possible
|
||||
retlist = []
|
||||
partitions = cext.disk_partitions()
|
||||
for partition in partitions:
|
||||
device, mountpoint, fstype, opts = partition
|
||||
if device == 'none':
|
||||
device = ''
|
||||
if not all:
|
||||
# Differently from, say, Linux, we don't have a list of
|
||||
# common fs types so the best we can do, AFAIK, is to
|
||||
# filter by filesystem having a total size > 0.
|
||||
try:
|
||||
if not disk_usage(mountpoint).total:
|
||||
continue
|
||||
except OSError as err:
|
||||
# https://github.com/giampaolo/psutil/issues/1674
|
||||
debug("skipping %r: %r" % (mountpoint, err))
|
||||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
||||
|
||||
net_io_counters = cext.net_io_counters
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
|
||||
def net_connections(kind, _pid=-1):
|
||||
"""Return socket connections. If pid == -1 return system-wide
|
||||
connections (as opposed to connections opened by one process only).
|
||||
Only INET sockets are returned (UNIX are not).
|
||||
"""
|
||||
cmap = _common.conn_tmap.copy()
|
||||
if _pid == -1:
|
||||
cmap.pop('unix', 0)
|
||||
if kind not in cmap:
|
||||
raise ValueError("invalid %r kind argument; choose between %s"
|
||||
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||
families, types = _common.conn_tmap[kind]
|
||||
rawlist = cext.net_connections(_pid)
|
||||
ret = set()
|
||||
for item in rawlist:
|
||||
fd, fam, type_, laddr, raddr, status, pid = item
|
||||
if fam not in families:
|
||||
continue
|
||||
if type_ not in types:
|
||||
continue
|
||||
# TODO: refactor and use _common.conn_to_ntuple.
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
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.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
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- other system functions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def boot_time():
|
||||
"""The system boot time expressed in seconds since the epoch."""
|
||||
return cext.boot_time()
|
||||
|
||||
|
||||
def users():
|
||||
"""Return currently connected users as a list of namedtuples."""
|
||||
retlist = []
|
||||
rawlist = cext.users()
|
||||
localhost = (':0.0', ':0')
|
||||
for item in rawlist:
|
||||
user, tty, hostname, tstamp, user_process, pid = item
|
||||
# note: the underlying C function includes entries about
|
||||
# system boot, run level and others. We might want
|
||||
# to use them in the future.
|
||||
if not user_process:
|
||||
continue
|
||||
if hostname in localhost:
|
||||
hostname = 'localhost'
|
||||
nt = _common.suser(user, tty, hostname, tstamp, pid)
|
||||
retlist.append(nt)
|
||||
return retlist
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- processes
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def pids():
|
||||
"""Returns a list of PIDs currently running on the system."""
|
||||
return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()]
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check for the existence of a unix pid."""
|
||||
return _psposix.pid_exists(pid)
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Call callable into a try/except clause and translate ENOENT,
|
||||
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# 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 not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
except OSError:
|
||||
if self.pid == 0:
|
||||
if 0 in pids():
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
else:
|
||||
raise
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
self._name = None
|
||||
self._ppid = None
|
||||
self._procfs_path = get_procfs_path()
|
||||
|
||||
def _assert_alive(self):
|
||||
"""Raise NSP if the process disappeared on us."""
|
||||
# For those C function who do not raise NSP, possibly returning
|
||||
# incorrect or incomplete result.
|
||||
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||
|
||||
def oneshot_enter(self):
|
||||
self._proc_name_and_args.cache_activate(self)
|
||||
self._proc_basic_info.cache_activate(self)
|
||||
self._proc_cred.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self._proc_name_and_args.cache_deactivate(self)
|
||||
self._proc_basic_info.cache_deactivate(self)
|
||||
self._proc_cred.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_name_and_args(self):
|
||||
return cext.proc_name_and_args(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_basic_info(self):
|
||||
if self.pid == 0 and not \
|
||||
os.path.exists('%s/%s/psinfo' % (self._procfs_path, self.pid)):
|
||||
raise AccessDenied(self.pid)
|
||||
ret = cext.proc_basic_info(self.pid, self._procfs_path)
|
||||
assert len(ret) == len(proc_info_map)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def _proc_cred(self):
|
||||
return cext.proc_cred(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
# note: max len == 15
|
||||
return self._proc_name_and_args()[0]
|
||||
|
||||
@wrap_exceptions
|
||||
def exe(self):
|
||||
try:
|
||||
return os.readlink(
|
||||
"%s/%s/path/a.out" % (self._procfs_path, self.pid))
|
||||
except OSError:
|
||||
pass # continue and guess the exe name from the cmdline
|
||||
# Will be guessed later from cmdline but we want to explicitly
|
||||
# invoke cmdline here in order to get an AccessDenied
|
||||
# exception if the user has not enough privileges.
|
||||
self.cmdline()
|
||||
return ""
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
return self._proc_name_and_args()[1].split(' ')
|
||||
|
||||
@wrap_exceptions
|
||||
def environ(self):
|
||||
return cext.proc_environ(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
return self._proc_basic_info()[proc_info_map['create_time']]
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return self._proc_basic_info()[proc_info_map['num_threads']]
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
# Note #1: getpriority(3) doesn't work for realtime processes.
|
||||
# Psinfo is what ps uses, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1194
|
||||
return self._proc_basic_info()[proc_info_map['nice']]
|
||||
|
||||
@wrap_exceptions
|
||||
def nice_set(self, value):
|
||||
if self.pid in (2, 3):
|
||||
# Special case PIDs: internally setpriority(3) return ESRCH
|
||||
# (no such process), no matter what.
|
||||
# The process actually exists though, as it has a name,
|
||||
# creation time, etc.
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
@wrap_exceptions
|
||||
def ppid(self):
|
||||
self._ppid = self._proc_basic_info()[proc_info_map['ppid']]
|
||||
return self._ppid
|
||||
|
||||
@wrap_exceptions
|
||||
def uids(self):
|
||||
try:
|
||||
real, effective, saved, _, _, _ = self._proc_cred()
|
||||
except AccessDenied:
|
||||
real = self._proc_basic_info()[proc_info_map['uid']]
|
||||
effective = self._proc_basic_info()[proc_info_map['euid']]
|
||||
saved = None
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def gids(self):
|
||||
try:
|
||||
_, _, _, real, effective, saved = self._proc_cred()
|
||||
except AccessDenied:
|
||||
real = self._proc_basic_info()[proc_info_map['gid']]
|
||||
effective = self._proc_basic_info()[proc_info_map['egid']]
|
||||
saved = None
|
||||
return _common.puids(real, effective, saved)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
try:
|
||||
times = cext.proc_cpu_times(self.pid, self._procfs_path)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||
# We may get here if we attempt to query a 64bit process
|
||||
# with a 32bit python.
|
||||
# Error originates from read() and also tools like "cat"
|
||||
# fail in the same way (!).
|
||||
# Since there simply is no way to determine CPU times we
|
||||
# return 0.0 as a fallback. See:
|
||||
# https://github.com/giampaolo/psutil/issues/857
|
||||
times = (0.0, 0.0, 0.0, 0.0)
|
||||
else:
|
||||
raise
|
||||
return _common.pcputimes(*times)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_num(self):
|
||||
return cext.proc_cpu_num(self.pid, self._procfs_path)
|
||||
|
||||
@wrap_exceptions
|
||||
def terminal(self):
|
||||
procfs_path = self._procfs_path
|
||||
hit_enoent = False
|
||||
tty = wrap_exceptions(
|
||||
self._proc_basic_info()[proc_info_map['ttynr']])
|
||||
if tty != cext.PRNODEV:
|
||||
for x in (0, 1, 2, 255):
|
||||
try:
|
||||
return os.readlink(
|
||||
'%s/%d/path/%d' % (procfs_path, self.pid, x))
|
||||
except FileNotFoundError:
|
||||
hit_enoent = True
|
||||
continue
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
# /proc/PID/path/cwd may not be resolved by readlink() even if
|
||||
# it exists (ls shows it). If that's the case and the process
|
||||
# is still alive return None (we can return None also on BSD).
|
||||
# Reference: http://goo.gl/55XgO
|
||||
procfs_path = self._procfs_path
|
||||
try:
|
||||
return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid))
|
||||
except FileNotFoundError:
|
||||
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||
return None
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
ret = self._proc_basic_info()
|
||||
rss = ret[proc_info_map['rss']] * 1024
|
||||
vms = ret[proc_info_map['vms']] * 1024
|
||||
return pmem(rss, vms)
|
||||
|
||||
memory_full_info = memory_info
|
||||
|
||||
@wrap_exceptions
|
||||
def status(self):
|
||||
code = self._proc_basic_info()[proc_info_map['status']]
|
||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||
return PROC_STATUSES.get(code, '?')
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
procfs_path = self._procfs_path
|
||||
ret = []
|
||||
tids = os.listdir('%s/%d/lwp' % (procfs_path, self.pid))
|
||||
hit_enoent = False
|
||||
for tid in tids:
|
||||
tid = int(tid)
|
||||
try:
|
||||
utime, stime = cext.query_process_thread(
|
||||
self.pid, tid, procfs_path)
|
||||
except EnvironmentError as err:
|
||||
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||
# We may get here if we attempt to query a 64bit process
|
||||
# with a 32bit python.
|
||||
# Error originates from read() and also tools like "cat"
|
||||
# fail in the same way (!).
|
||||
# Since there simply is no way to determine CPU times we
|
||||
# return 0.0 as a fallback. See:
|
||||
# https://github.com/giampaolo/psutil/issues/857
|
||||
continue
|
||||
# ENOENT == thread gone in meantime
|
||||
if err.errno == errno.ENOENT:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
nt = _common.pthread(tid, utime, stime)
|
||||
ret.append(nt)
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
retlist = []
|
||||
hit_enoent = False
|
||||
procfs_path = self._procfs_path
|
||||
pathdir = '%s/%d/path' % (procfs_path, self.pid)
|
||||
for fd in os.listdir('%s/%d/fd' % (procfs_path, self.pid)):
|
||||
path = os.path.join(pathdir, fd)
|
||||
if os.path.islink(path):
|
||||
try:
|
||||
file = os.readlink(path)
|
||||
except FileNotFoundError:
|
||||
hit_enoent = True
|
||||
continue
|
||||
else:
|
||||
if isfile_strict(file):
|
||||
retlist.append(_common.popenfile(file, int(fd)))
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
def _get_unix_sockets(self, pid):
|
||||
"""Get UNIX sockets used by process by parsing 'pfiles' output."""
|
||||
# TODO: rewrite this in C (...but the damn netstat source code
|
||||
# does not include this part! Argh!!)
|
||||
cmd = "pfiles %s" % pid
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
if PY3:
|
||||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if p.returncode != 0:
|
||||
if 'permission denied' in stderr.lower():
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
if 'no such process' in stderr.lower():
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise RuntimeError("%r command error\n%s" % (cmd, stderr))
|
||||
|
||||
lines = stdout.split('\n')[2:]
|
||||
for i, line in enumerate(lines):
|
||||
line = line.lstrip()
|
||||
if line.startswith('sockname: AF_UNIX'):
|
||||
path = line.split(' ', 2)[2]
|
||||
type = lines[i - 2].strip()
|
||||
if type == 'SOCK_STREAM':
|
||||
type = socket.SOCK_STREAM
|
||||
elif type == 'SOCK_DGRAM':
|
||||
type = socket.SOCK_DGRAM
|
||||
else:
|
||||
type = -1
|
||||
yield (-1, socket.AF_UNIX, type, path, "", _common.CONN_NONE)
|
||||
|
||||
@wrap_exceptions
|
||||
def connections(self, kind='inet'):
|
||||
ret = net_connections(kind, _pid=self.pid)
|
||||
# The underlying C implementation retrieves all OS connections
|
||||
# and filters them by PID. At this point we can't tell whether
|
||||
# an empty list means there were no connections for process or
|
||||
# process is no longer active so we force NSP in case the PID
|
||||
# is no longer there.
|
||||
if not ret:
|
||||
# will raise NSP if process is gone
|
||||
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||
|
||||
# UNIX sockets
|
||||
if kind in ('all', 'unix'):
|
||||
ret.extend([_common.pconn(*conn) for conn in
|
||||
self._get_unix_sockets(self.pid)])
|
||||
return ret
|
||||
|
||||
nt_mmap_grouped = namedtuple('mmap', 'path rss anon locked')
|
||||
nt_mmap_ext = namedtuple('mmap', 'addr perms path rss anon locked')
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_maps(self):
|
||||
def toaddr(start, end):
|
||||
return '%s-%s' % (hex(start)[2:].strip('L'),
|
||||
hex(end)[2:].strip('L'))
|
||||
|
||||
procfs_path = self._procfs_path
|
||||
retlist = []
|
||||
try:
|
||||
rawlist = cext.proc_memory_maps(self.pid, procfs_path)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||
# We may get here if we attempt to query a 64bit process
|
||||
# with a 32bit python.
|
||||
# Error originates from read() and also tools like "cat"
|
||||
# fail in the same way (!).
|
||||
# Since there simply is no way to determine CPU times we
|
||||
# return 0.0 as a fallback. See:
|
||||
# https://github.com/giampaolo/psutil/issues/857
|
||||
return []
|
||||
else:
|
||||
raise
|
||||
hit_enoent = False
|
||||
for item in rawlist:
|
||||
addr, addrsize, perm, name, rss, anon, locked = item
|
||||
addr = toaddr(addr, addrsize)
|
||||
if not name.startswith('['):
|
||||
try:
|
||||
name = os.readlink(
|
||||
'%s/%s/path/%s' % (procfs_path, self.pid, name))
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
# sometimes the link may not be resolved by
|
||||
# readlink() even if it exists (ls shows it).
|
||||
# If that's the case we just return the
|
||||
# unresolved link path.
|
||||
# This seems an incosistency with /proc similar
|
||||
# to: http://goo.gl/55XgO
|
||||
name = '%s/%s/path/%s' % (procfs_path, self.pid, name)
|
||||
hit_enoent = True
|
||||
else:
|
||||
raise
|
||||
retlist.append((addr, perm, name, rss, anon, locked))
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
def num_fds(self):
|
||||
return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
return _common.pctxsw(
|
||||
*cext.proc_num_ctx_switches(self.pid, self._procfs_path))
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||
1136
third_party/python/psutil/psutil/_psutil_aix.c
vendored
Normal file
1136
third_party/python/psutil/psutil/_psutil_aix.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1102
third_party/python/psutil/psutil/_psutil_bsd.c
vendored
Normal file
1102
third_party/python/psutil/psutil/_psutil_bsd.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
403
third_party/python/psutil/psutil/_psutil_common.c
vendored
Normal file
403
third_party/python/psutil/psutil/_psutil_common.c
vendored
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Routines common to all platforms.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include "_psutil_common.h"
|
||||
|
||||
// ====================================================================
|
||||
// --- Global vars
|
||||
// ====================================================================
|
||||
|
||||
int PSUTIL_DEBUG = 0;
|
||||
int PSUTIL_TESTING = 0;
|
||||
// PSUTIL_CONN_NONE
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// --- Backward compatibility with missing Python.h APIs
|
||||
// ====================================================================
|
||||
|
||||
// PyPy on Windows
|
||||
#if defined(PSUTIL_WINDOWS) && \
|
||||
defined(PYPY_VERSION) && \
|
||||
!defined(PyErr_SetFromWindowsErrWithFilename)
|
||||
PyObject *
|
||||
PyErr_SetFromWindowsErrWithFilename(int winerr, const char *filename) {
|
||||
PyObject *py_exc = NULL;
|
||||
PyObject *py_winerr = NULL;
|
||||
|
||||
if (winerr == 0)
|
||||
winerr = GetLastError();
|
||||
if (filename == NULL) {
|
||||
py_exc = PyObject_CallFunction(PyExc_OSError, "(is)", winerr,
|
||||
strerror(winerr));
|
||||
}
|
||||
else {
|
||||
py_exc = PyObject_CallFunction(PyExc_OSError, "(iss)", winerr,
|
||||
strerror(winerr), filename);
|
||||
}
|
||||
if (py_exc == NULL)
|
||||
return NULL;
|
||||
|
||||
py_winerr = Py_BuildValue("i", winerr);
|
||||
if (py_winerr == NULL)
|
||||
goto error;
|
||||
if (PyObject_SetAttrString(py_exc, "winerror", py_winerr) != 0)
|
||||
goto error;
|
||||
PyErr_SetObject(PyExc_OSError, py_exc);
|
||||
Py_XDECREF(py_exc);
|
||||
return NULL;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_exc);
|
||||
Py_XDECREF(py_winerr);
|
||||
return NULL;
|
||||
}
|
||||
#endif // PYPY on Windows
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// --- Custom exceptions
|
||||
// ====================================================================
|
||||
|
||||
/*
|
||||
* Same as PyErr_SetFromErrno(0) but adds the syscall to the exception
|
||||
* message.
|
||||
*/
|
||||
PyObject *
|
||||
PyErr_SetFromOSErrnoWithSyscall(const char *syscall) {
|
||||
char fullmsg[1024];
|
||||
|
||||
#ifdef PSUTIL_WINDOWS
|
||||
sprintf(fullmsg, "(originated from %s)", syscall);
|
||||
PyErr_SetFromWindowsErrWithFilename(GetLastError(), fullmsg);
|
||||
#else
|
||||
PyObject *exc;
|
||||
sprintf(fullmsg, "%s (originated from %s)", strerror(errno), syscall);
|
||||
exc = PyObject_CallFunction(PyExc_OSError, "(is)", errno, fullmsg);
|
||||
PyErr_SetObject(PyExc_OSError, exc);
|
||||
Py_XDECREF(exc);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set OSError(errno=ESRCH, strerror="No such process (originated from")
|
||||
* Python exception.
|
||||
*/
|
||||
PyObject *
|
||||
NoSuchProcess(const char *syscall) {
|
||||
PyObject *exc;
|
||||
char msg[1024];
|
||||
|
||||
sprintf(msg, "No such process (originated from %s)", syscall);
|
||||
exc = PyObject_CallFunction(PyExc_OSError, "(is)", ESRCH, msg);
|
||||
PyErr_SetObject(PyExc_OSError, exc);
|
||||
Py_XDECREF(exc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set OSError(errno=EACCES, strerror="Permission denied" (originated from ...)
|
||||
* Python exception.
|
||||
*/
|
||||
PyObject *
|
||||
AccessDenied(const char *syscall) {
|
||||
PyObject *exc;
|
||||
char msg[1024];
|
||||
|
||||
sprintf(msg, "Access denied (originated from %s)", syscall);
|
||||
exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg);
|
||||
PyErr_SetObject(PyExc_OSError, exc);
|
||||
Py_XDECREF(exc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// --- Global utils
|
||||
// ====================================================================
|
||||
|
||||
/*
|
||||
* Enable testing mode. This has the same effect as setting PSUTIL_TESTING
|
||||
* env var. This dual method exists because updating os.environ on
|
||||
* Windows has no effect. Called on unit tests setup.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_set_testing(PyObject *self, PyObject *args) {
|
||||
PSUTIL_TESTING = 1;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print a debug message on stderr. No-op if PSUTIL_DEBUG env var is not set.
|
||||
*/
|
||||
void
|
||||
psutil_debug(const char* format, ...) {
|
||||
va_list argptr;
|
||||
if (PSUTIL_DEBUG) {
|
||||
va_start(argptr, format);
|
||||
fprintf(stderr, "psutil-debug> ");
|
||||
vfprintf(stderr, format, argptr);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(argptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called on module import on all platforms.
|
||||
*/
|
||||
int
|
||||
psutil_setup(void) {
|
||||
if (getenv("PSUTIL_DEBUG") != NULL)
|
||||
PSUTIL_DEBUG = 1;
|
||||
if (getenv("PSUTIL_TESTING") != NULL)
|
||||
PSUTIL_TESTING = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// --- Windows
|
||||
// ====================================================================
|
||||
|
||||
#ifdef PSUTIL_WINDOWS
|
||||
#include <windows.h>
|
||||
|
||||
// Needed to make these globally visible.
|
||||
int PSUTIL_WINVER;
|
||||
SYSTEM_INFO PSUTIL_SYSTEM_INFO;
|
||||
CRITICAL_SECTION PSUTIL_CRITICAL_SECTION;
|
||||
|
||||
#define NT_FACILITY_MASK 0xfff
|
||||
#define NT_FACILITY_SHIFT 16
|
||||
#define NT_FACILITY(Status) \
|
||||
((((ULONG)(Status)) >> NT_FACILITY_SHIFT) & NT_FACILITY_MASK)
|
||||
#define NT_NTWIN32(status) (NT_FACILITY(Status) == FACILITY_WIN32)
|
||||
#define WIN32_FROM_NTSTATUS(Status) (((ULONG)(Status)) & 0xffff)
|
||||
|
||||
|
||||
// A wrapper around GetModuleHandle and GetProcAddress.
|
||||
PVOID
|
||||
psutil_GetProcAddress(LPCSTR libname, LPCSTR procname) {
|
||||
HMODULE mod;
|
||||
FARPROC addr;
|
||||
|
||||
if ((mod = GetModuleHandleA(libname)) == NULL) {
|
||||
PyErr_SetFromWindowsErrWithFilename(0, libname);
|
||||
return NULL;
|
||||
}
|
||||
if ((addr = GetProcAddress(mod, procname)) == NULL) {
|
||||
PyErr_SetFromWindowsErrWithFilename(0, procname);
|
||||
return NULL;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
// A wrapper around LoadLibrary and GetProcAddress.
|
||||
PVOID
|
||||
psutil_GetProcAddressFromLib(LPCSTR libname, LPCSTR procname) {
|
||||
HMODULE mod;
|
||||
FARPROC addr;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
mod = LoadLibraryA(libname);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (mod == NULL) {
|
||||
PyErr_SetFromWindowsErrWithFilename(0, libname);
|
||||
return NULL;
|
||||
}
|
||||
if ((addr = GetProcAddress(mod, procname)) == NULL) {
|
||||
PyErr_SetFromWindowsErrWithFilename(0, procname);
|
||||
FreeLibrary(mod);
|
||||
return NULL;
|
||||
}
|
||||
// Causes crash.
|
||||
// FreeLibrary(mod);
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert a NTSTATUS value to a Win32 error code and set the proper
|
||||
* Python exception.
|
||||
*/
|
||||
PVOID
|
||||
psutil_SetFromNTStatusErr(NTSTATUS Status, const char *syscall) {
|
||||
ULONG err;
|
||||
char fullmsg[1024];
|
||||
|
||||
if (NT_NTWIN32(Status))
|
||||
err = WIN32_FROM_NTSTATUS(Status);
|
||||
else
|
||||
err = RtlNtStatusToDosErrorNoTeb(Status);
|
||||
// if (GetLastError() != 0)
|
||||
// err = GetLastError();
|
||||
sprintf(fullmsg, "(originated from %s)", syscall);
|
||||
return PyErr_SetFromWindowsErrWithFilename(err, fullmsg);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
psutil_loadlibs() {
|
||||
// --- Mandatory
|
||||
NtQuerySystemInformation = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "NtQuerySystemInformation");
|
||||
if (! NtQuerySystemInformation)
|
||||
return 1;
|
||||
NtQueryInformationProcess = psutil_GetProcAddress(
|
||||
"ntdll.dll", "NtQueryInformationProcess");
|
||||
if (! NtQueryInformationProcess)
|
||||
return 1;
|
||||
NtSetInformationProcess = psutil_GetProcAddress(
|
||||
"ntdll.dll", "NtSetInformationProcess");
|
||||
if (! NtSetInformationProcess)
|
||||
return 1;
|
||||
WinStationQueryInformationW = psutil_GetProcAddressFromLib(
|
||||
"winsta.dll", "WinStationQueryInformationW");
|
||||
if (! WinStationQueryInformationW)
|
||||
return 1;
|
||||
NtQueryObject = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "NtQueryObject");
|
||||
if (! NtQueryObject)
|
||||
return 1;
|
||||
RtlIpv4AddressToStringA = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "RtlIpv4AddressToStringA");
|
||||
if (! RtlIpv4AddressToStringA)
|
||||
return 1;
|
||||
GetExtendedTcpTable = psutil_GetProcAddressFromLib(
|
||||
"iphlpapi.dll", "GetExtendedTcpTable");
|
||||
if (! GetExtendedTcpTable)
|
||||
return 1;
|
||||
GetExtendedUdpTable = psutil_GetProcAddressFromLib(
|
||||
"iphlpapi.dll", "GetExtendedUdpTable");
|
||||
if (! GetExtendedUdpTable)
|
||||
return 1;
|
||||
RtlGetVersion = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "RtlGetVersion");
|
||||
if (! RtlGetVersion)
|
||||
return 1;
|
||||
NtSuspendProcess = psutil_GetProcAddressFromLib(
|
||||
"ntdll", "NtSuspendProcess");
|
||||
if (! NtSuspendProcess)
|
||||
return 1;
|
||||
NtResumeProcess = psutil_GetProcAddressFromLib(
|
||||
"ntdll", "NtResumeProcess");
|
||||
if (! NtResumeProcess)
|
||||
return 1;
|
||||
NtQueryVirtualMemory = psutil_GetProcAddressFromLib(
|
||||
"ntdll", "NtQueryVirtualMemory");
|
||||
if (! NtQueryVirtualMemory)
|
||||
return 1;
|
||||
RtlNtStatusToDosErrorNoTeb = psutil_GetProcAddressFromLib(
|
||||
"ntdll", "RtlNtStatusToDosErrorNoTeb");
|
||||
if (! RtlNtStatusToDosErrorNoTeb)
|
||||
return 1;
|
||||
GetTickCount64 = psutil_GetProcAddress(
|
||||
"kernel32", "GetTickCount64");
|
||||
if (! GetTickCount64)
|
||||
return 1;
|
||||
RtlIpv6AddressToStringA = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "RtlIpv6AddressToStringA");
|
||||
if (! RtlIpv6AddressToStringA)
|
||||
return 1;
|
||||
|
||||
// --- Optional
|
||||
// minimum requirement: Win 7
|
||||
GetActiveProcessorCount = psutil_GetProcAddress(
|
||||
"kernel32", "GetActiveProcessorCount");
|
||||
// minumum requirement: Win 7
|
||||
GetLogicalProcessorInformationEx = psutil_GetProcAddressFromLib(
|
||||
"kernel32", "GetLogicalProcessorInformationEx");
|
||||
|
||||
PyErr_Clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
psutil_set_winver() {
|
||||
RTL_OSVERSIONINFOEXW versionInfo;
|
||||
ULONG maj;
|
||||
ULONG min;
|
||||
|
||||
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
|
||||
memset(&versionInfo, 0, sizeof(RTL_OSVERSIONINFOEXW));
|
||||
RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo);
|
||||
maj = versionInfo.dwMajorVersion;
|
||||
min = versionInfo.dwMinorVersion;
|
||||
if (maj == 6 && min == 0)
|
||||
PSUTIL_WINVER = PSUTIL_WINDOWS_VISTA; // or Server 2008
|
||||
else if (maj == 6 && min == 1)
|
||||
PSUTIL_WINVER = PSUTIL_WINDOWS_7;
|
||||
else if (maj == 6 && min == 2)
|
||||
PSUTIL_WINVER = PSUTIL_WINDOWS_8;
|
||||
else if (maj == 6 && min == 3)
|
||||
PSUTIL_WINVER = PSUTIL_WINDOWS_8_1;
|
||||
else if (maj == 10 && min == 0)
|
||||
PSUTIL_WINVER = PSUTIL_WINDOWS_10;
|
||||
else
|
||||
PSUTIL_WINVER = PSUTIL_WINDOWS_NEW;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_load_globals() {
|
||||
if (psutil_loadlibs() != 0)
|
||||
return 1;
|
||||
if (psutil_set_winver() != 0)
|
||||
return 1;
|
||||
GetSystemInfo(&PSUTIL_SYSTEM_INFO);
|
||||
InitializeCriticalSection(&PSUTIL_CRITICAL_SECTION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert the hi and lo parts of a FILETIME structure or a LARGE_INTEGER
|
||||
* to a UNIX time.
|
||||
* A FILETIME contains a 64-bit value representing the number of
|
||||
* 100-nanosecond intervals since January 1, 1601 (UTC).
|
||||
* A UNIX time is the number of seconds that have elapsed since the
|
||||
* UNIX epoch, that is the time 00:00:00 UTC on 1 January 1970.
|
||||
*/
|
||||
static double
|
||||
_to_unix_time(ULONGLONG hiPart, ULONGLONG loPart) {
|
||||
ULONGLONG ret;
|
||||
|
||||
// 100 nanosecond intervals since January 1, 1601.
|
||||
ret = hiPart << 32;
|
||||
ret += loPart;
|
||||
// Change starting time to the Epoch (00:00:00 UTC, January 1, 1970).
|
||||
ret -= 116444736000000000ull;
|
||||
// Convert nano secs to secs.
|
||||
return (double) ret / 10000000ull;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
psutil_FiletimeToUnixTime(FILETIME ft) {
|
||||
return _to_unix_time((ULONGLONG)ft.dwHighDateTime,
|
||||
(ULONGLONG)ft.dwLowDateTime);
|
||||
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
psutil_LargeIntegerToUnixTime(LARGE_INTEGER li) {
|
||||
return _to_unix_time((ULONGLONG)li.HighPart,
|
||||
(ULONGLONG)li.LowPart);
|
||||
}
|
||||
#endif // PSUTIL_WINDOWS
|
||||
139
third_party/python/psutil/psutil/_psutil_common.h
vendored
Normal file
139
third_party/python/psutil/psutil/_psutil_common.h
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
// ====================================================================
|
||||
// --- Global vars / constants
|
||||
// ====================================================================
|
||||
|
||||
extern int PSUTIL_TESTING;
|
||||
extern int PSUTIL_DEBUG;
|
||||
// a signaler for connections without an actual status
|
||||
static const int PSUTIL_CONN_NONE = 128;
|
||||
|
||||
// ====================================================================
|
||||
// --- Backward compatibility with missing Python.h APIs
|
||||
// ====================================================================
|
||||
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
// On Python 2 we just return a plain byte string, which is never
|
||||
// supposed to raise decoding errors, see:
|
||||
// https://github.com/giampaolo/psutil/issues/1040
|
||||
#define PyUnicode_DecodeFSDefault PyString_FromString
|
||||
#define PyUnicode_DecodeFSDefaultAndSize PyString_FromStringAndSize
|
||||
#endif
|
||||
|
||||
#if defined(PSUTIL_WINDOWS) && \
|
||||
defined(PYPY_VERSION) && \
|
||||
!defined(PyErr_SetFromWindowsErrWithFilename)
|
||||
PyObject *PyErr_SetFromWindowsErrWithFilename(int ierr,
|
||||
const char *filename);
|
||||
#endif
|
||||
|
||||
// --- _Py_PARSE_PID
|
||||
|
||||
// SIZEOF_INT|LONG is missing on Linux + PyPy (only?).
|
||||
// SIZEOF_PID_T is missing on Windows + Python2.
|
||||
// In this case we guess it from setup.py. It's not 100% bullet proof,
|
||||
// If wrong we'll probably get compiler warnings.
|
||||
// FWIW on all UNIX platforms I've seen pid_t is defined as an int.
|
||||
// _getpid() on Windows also returns an int.
|
||||
#if !defined(SIZEOF_INT)
|
||||
#define SIZEOF_INT 4
|
||||
#endif
|
||||
#if !defined(SIZEOF_LONG)
|
||||
#define SIZEOF_LONG 8
|
||||
#endif
|
||||
#if !defined(SIZEOF_PID_T)
|
||||
#define SIZEOF_PID_T PSUTIL_SIZEOF_PID_T // set as a macro in setup.py
|
||||
#endif
|
||||
|
||||
// _Py_PARSE_PID is Python 3 only, but since it's private make sure it's
|
||||
// always present.
|
||||
#ifndef _Py_PARSE_PID
|
||||
#if SIZEOF_PID_T == SIZEOF_INT
|
||||
#define _Py_PARSE_PID "i"
|
||||
#elif SIZEOF_PID_T == SIZEOF_LONG
|
||||
#define _Py_PARSE_PID "l"
|
||||
#elif defined(SIZEOF_LONG_LONG) && SIZEOF_PID_T == SIZEOF_LONG_LONG
|
||||
#define _Py_PARSE_PID "L"
|
||||
#else
|
||||
#error "_Py_PARSE_PID: sizeof(pid_t) is neither sizeof(int), "
|
||||
"sizeof(long) or sizeof(long long)"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Python 2 or PyPy on Windows
|
||||
#ifndef PyLong_FromPid
|
||||
#if ((SIZEOF_PID_T == SIZEOF_INT) || (SIZEOF_PID_T == SIZEOF_LONG))
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define PyLong_FromPid PyLong_FromLong
|
||||
#else
|
||||
#define PyLong_FromPid PyInt_FromLong
|
||||
#endif
|
||||
#elif defined(SIZEOF_LONG_LONG) && SIZEOF_PID_T == SIZEOF_LONG_LONG
|
||||
#define PyLong_FromPid PyLong_FromLongLong
|
||||
#else
|
||||
#error "PyLong_FromPid: sizeof(pid_t) is neither sizeof(int), "
|
||||
"sizeof(long) or sizeof(long long)"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ====================================================================
|
||||
// --- Custom exceptions
|
||||
// ====================================================================
|
||||
|
||||
PyObject* AccessDenied(const char *msg);
|
||||
PyObject* NoSuchProcess(const char *msg);
|
||||
PyObject* PyErr_SetFromOSErrnoWithSyscall(const char *syscall);
|
||||
|
||||
// ====================================================================
|
||||
// --- Global utils
|
||||
// ====================================================================
|
||||
|
||||
PyObject* psutil_set_testing(PyObject *self, PyObject *args);
|
||||
void psutil_debug(const char* format, ...);
|
||||
int psutil_setup(void);
|
||||
|
||||
// ====================================================================
|
||||
// --- Windows
|
||||
// ====================================================================
|
||||
|
||||
#ifdef PSUTIL_WINDOWS
|
||||
#include <windows.h>
|
||||
// make it available to any file which includes this module
|
||||
#include "arch/windows/ntextapi.h"
|
||||
|
||||
extern int PSUTIL_WINVER;
|
||||
extern SYSTEM_INFO PSUTIL_SYSTEM_INFO;
|
||||
extern CRITICAL_SECTION PSUTIL_CRITICAL_SECTION;
|
||||
|
||||
#define PSUTIL_WINDOWS_VISTA 60
|
||||
#define PSUTIL_WINDOWS_7 61
|
||||
#define PSUTIL_WINDOWS_8 62
|
||||
#define PSUTIL_WINDOWS_8_1 63
|
||||
#define PSUTIL_WINDOWS_10 100
|
||||
#define PSUTIL_WINDOWS_NEW MAXLONG
|
||||
|
||||
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
||||
#define MALLOC_ZERO(x) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x))
|
||||
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
||||
|
||||
#define LO_T 1e-7
|
||||
#define HI_T 429.4967296
|
||||
|
||||
#ifndef AF_INET6
|
||||
#define AF_INET6 23
|
||||
#endif
|
||||
|
||||
int psutil_load_globals();
|
||||
PVOID psutil_GetProcAddress(LPCSTR libname, LPCSTR procname);
|
||||
PVOID psutil_GetProcAddressFromLib(LPCSTR libname, LPCSTR procname);
|
||||
PVOID psutil_SetFromNTStatusErr(NTSTATUS Status, const char *syscall);
|
||||
double psutil_FiletimeToUnixTime(FILETIME ft);
|
||||
double psutil_LargeIntegerToUnixTime(LARGE_INTEGER li);
|
||||
#endif
|
||||
673
third_party/python/psutil/psutil/_psutil_linux.c
vendored
Normal file
673
third_party/python/psutil/psutil/_psutil_linux.c
vendored
Normal file
|
|
@ -0,0 +1,673 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Linux-specific functions.
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
#include <Python.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <mntent.h>
|
||||
#include <features.h>
|
||||
#include <utmp.h>
|
||||
#include <sched.h>
|
||||
#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
|
||||
/* Avoid redefinition of struct sysinfo with musl libc */
|
||||
#define _LINUX_SYSINFO_H
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
/* The minimum number of CPUs allocated in a cpu_set_t */
|
||||
static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
|
||||
|
||||
// Linux >= 2.6.13
|
||||
#define PSUTIL_HAVE_IOPRIO defined(__NR_ioprio_get) && defined(__NR_ioprio_set)
|
||||
|
||||
// Linux >= 2.6.36 (supposedly) and glibc >= 13
|
||||
#define PSUTIL_HAVE_PRLIMIT \
|
||||
(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) && \
|
||||
(__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 13) && \
|
||||
defined(__NR_prlimit64)
|
||||
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#include <time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
// Should exist starting from CentOS 6 (year 2011).
|
||||
#ifdef CPU_ALLOC
|
||||
#define PSUTIL_HAVE_CPU_AFFINITY
|
||||
#endif
|
||||
|
||||
#include "_psutil_common.h"
|
||||
#include "_psutil_posix.h"
|
||||
|
||||
// May happen on old RedHat versions, see:
|
||||
// https://github.com/giampaolo/psutil/issues/607
|
||||
#ifndef DUPLEX_UNKNOWN
|
||||
#define DUPLEX_UNKNOWN 0xff
|
||||
#endif
|
||||
|
||||
|
||||
#if PSUTIL_HAVE_IOPRIO
|
||||
enum {
|
||||
IOPRIO_WHO_PROCESS = 1,
|
||||
};
|
||||
|
||||
static inline int
|
||||
ioprio_get(int which, int who) {
|
||||
return syscall(__NR_ioprio_get, which, who);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ioprio_set(int which, int who, int ioprio) {
|
||||
return syscall(__NR_ioprio_set, which, who, ioprio);
|
||||
}
|
||||
|
||||
#define IOPRIO_CLASS_SHIFT 13
|
||||
#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
|
||||
|
||||
#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
|
||||
#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
|
||||
#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
|
||||
|
||||
|
||||
/*
|
||||
* Return a (ioclass, iodata) Python tuple representing process I/O priority.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_proc_ioprio_get(PyObject *self, PyObject *args) {
|
||||
pid_t pid;
|
||||
int ioprio, ioclass, iodata;
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
|
||||
if (ioprio == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
ioclass = IOPRIO_PRIO_CLASS(ioprio);
|
||||
iodata = IOPRIO_PRIO_DATA(ioprio);
|
||||
return Py_BuildValue("ii", ioclass, iodata);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A wrapper around ioprio_set(); sets process I/O priority.
|
||||
* ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE
|
||||
* or 0. iodata goes from 0 to 7 depending on ioclass specified.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_proc_ioprio_set(PyObject *self, PyObject *args) {
|
||||
pid_t pid;
|
||||
int ioprio, ioclass, iodata;
|
||||
int retval;
|
||||
|
||||
if (! PyArg_ParseTuple(
|
||||
args, _Py_PARSE_PID "ii", &pid, &ioclass, &iodata)) {
|
||||
return NULL;
|
||||
}
|
||||
ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
|
||||
retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
|
||||
if (retval == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
/*
|
||||
* A wrapper around prlimit(2); sets process resource limits.
|
||||
* This can be used for both get and set, in which case extra
|
||||
* 'soft' and 'hard' args must be provided.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_linux_prlimit(PyObject *self, PyObject *args) {
|
||||
pid_t pid;
|
||||
int ret, resource;
|
||||
struct rlimit old, new;
|
||||
struct rlimit *newp = NULL;
|
||||
PyObject *py_soft = NULL;
|
||||
PyObject *py_hard = NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID "i|OO", &pid, &resource,
|
||||
&py_soft, &py_hard)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get
|
||||
if (py_soft == NULL && py_hard == NULL) {
|
||||
ret = prlimit(pid, resource, NULL, &old);
|
||||
if (ret == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
#if defined(PSUTIL_HAVE_LONG_LONG)
|
||||
if (sizeof(old.rlim_cur) > sizeof(long)) {
|
||||
return Py_BuildValue("LL",
|
||||
(PY_LONG_LONG)old.rlim_cur,
|
||||
(PY_LONG_LONG)old.rlim_max);
|
||||
}
|
||||
#endif
|
||||
return Py_BuildValue("ll", (long)old.rlim_cur, (long)old.rlim_max);
|
||||
}
|
||||
|
||||
// set
|
||||
else {
|
||||
#if defined(PSUTIL_HAVE_LARGEFILE_SUPPORT)
|
||||
new.rlim_cur = PyLong_AsLongLong(py_soft);
|
||||
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
new.rlim_max = PyLong_AsLongLong(py_hard);
|
||||
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
#else
|
||||
new.rlim_cur = PyLong_AsLong(py_soft);
|
||||
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
new.rlim_max = PyLong_AsLong(py_hard);
|
||||
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
#endif
|
||||
newp = &new;
|
||||
ret = prlimit(pid, resource, newp, &old);
|
||||
if (ret == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Return disk mounted partitions as a list of tuples including device,
|
||||
* mount point and filesystem type
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_disk_partitions(PyObject *self, PyObject *args) {
|
||||
FILE *file = NULL;
|
||||
struct mntent *entry;
|
||||
char *mtab_path;
|
||||
PyObject *py_dev = NULL;
|
||||
PyObject *py_mountp = NULL;
|
||||
PyObject *py_tuple = NULL;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &mtab_path))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
file = setmntent(mtab_path, "r");
|
||||
Py_END_ALLOW_THREADS
|
||||
if ((file == 0) || (file == NULL)) {
|
||||
psutil_debug("setmntent() failed");
|
||||
PyErr_SetFromErrnoWithFilename(PyExc_OSError, mtab_path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
while ((entry = getmntent(file))) {
|
||||
if (entry == NULL) {
|
||||
PyErr_Format(PyExc_RuntimeError, "getmntent() syscall failed");
|
||||
goto error;
|
||||
}
|
||||
py_dev = PyUnicode_DecodeFSDefault(entry->mnt_fsname);
|
||||
if (! py_dev)
|
||||
goto error;
|
||||
py_mountp = PyUnicode_DecodeFSDefault(entry->mnt_dir);
|
||||
if (! py_mountp)
|
||||
goto error;
|
||||
py_tuple = Py_BuildValue("(OOss)",
|
||||
py_dev, // device
|
||||
py_mountp, // mount point
|
||||
entry->mnt_type, // fs type
|
||||
entry->mnt_opts); // options
|
||||
if (! py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_CLEAR(py_dev);
|
||||
Py_CLEAR(py_mountp);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
endmntent(file);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
if (file != NULL)
|
||||
endmntent(file);
|
||||
Py_XDECREF(py_dev);
|
||||
Py_XDECREF(py_mountp);
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_DECREF(py_retlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A wrapper around sysinfo(), return system memory usage statistics.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_linux_sysinfo(PyObject *self, PyObject *args) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) != 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
// note: boot time might also be determined from here
|
||||
return Py_BuildValue(
|
||||
"(kkkkkkI)",
|
||||
info.totalram, // total
|
||||
info.freeram, // free
|
||||
info.bufferram, // buffer
|
||||
info.sharedram, // shared
|
||||
info.totalswap, // swap tot
|
||||
info.freeswap, // swap free
|
||||
info.mem_unit // multiplier
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return process CPU affinity as a Python list
|
||||
*/
|
||||
#ifdef PSUTIL_HAVE_CPU_AFFINITY
|
||||
|
||||
static PyObject *
|
||||
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
|
||||
int cpu, ncpus, count, cpucount_s;
|
||||
pid_t pid;
|
||||
size_t setsize;
|
||||
cpu_set_t *mask = NULL;
|
||||
PyObject *py_list = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
ncpus = NCPUS_START;
|
||||
while (1) {
|
||||
setsize = CPU_ALLOC_SIZE(ncpus);
|
||||
mask = CPU_ALLOC(ncpus);
|
||||
if (mask == NULL) {
|
||||
psutil_debug("CPU_ALLOC() failed");
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
if (sched_getaffinity(pid, setsize, mask) == 0)
|
||||
break;
|
||||
CPU_FREE(mask);
|
||||
if (errno != EINVAL)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
if (ncpus > INT_MAX / 2) {
|
||||
PyErr_SetString(PyExc_OverflowError, "could not allocate "
|
||||
"a large enough CPU set");
|
||||
return NULL;
|
||||
}
|
||||
ncpus = ncpus * 2;
|
||||
}
|
||||
|
||||
py_list = PyList_New(0);
|
||||
if (py_list == NULL)
|
||||
goto error;
|
||||
|
||||
cpucount_s = CPU_COUNT_S(setsize, mask);
|
||||
for (cpu = 0, count = cpucount_s; count; cpu++) {
|
||||
if (CPU_ISSET_S(cpu, setsize, mask)) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *cpu_num = PyLong_FromLong(cpu);
|
||||
#else
|
||||
PyObject *cpu_num = PyInt_FromLong(cpu);
|
||||
#endif
|
||||
if (cpu_num == NULL)
|
||||
goto error;
|
||||
if (PyList_Append(py_list, cpu_num)) {
|
||||
Py_DECREF(cpu_num);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(cpu_num);
|
||||
--count;
|
||||
}
|
||||
}
|
||||
CPU_FREE(mask);
|
||||
return py_list;
|
||||
|
||||
error:
|
||||
if (mask)
|
||||
CPU_FREE(mask);
|
||||
Py_XDECREF(py_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set process CPU affinity; expects a bitmask
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
|
||||
cpu_set_t cpu_set;
|
||||
size_t len;
|
||||
pid_t pid;
|
||||
int i, seq_len;
|
||||
PyObject *py_cpu_set;
|
||||
PyObject *py_cpu_seq = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O", &pid, &py_cpu_set))
|
||||
return NULL;
|
||||
|
||||
if (!PySequence_Check(py_cpu_set)) {
|
||||
PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s",
|
||||
Py_TYPE(py_cpu_set)->tp_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer");
|
||||
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++) {
|
||||
PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i);
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
long value = PyLong_AsLong(item);
|
||||
#else
|
||||
long value = PyInt_AsLong(item);
|
||||
#endif
|
||||
if ((value == -1) || PyErr_Occurred()) {
|
||||
if (!PyErr_Occurred())
|
||||
PyErr_SetString(PyExc_ValueError, "invalid CPU value");
|
||||
goto error;
|
||||
}
|
||||
CPU_SET(value, &cpu_set);
|
||||
}
|
||||
|
||||
len = sizeof(cpu_set);
|
||||
if (sched_setaffinity(pid, len, &cpu_set)) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_DECREF(py_cpu_seq);
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
if (py_cpu_seq != NULL)
|
||||
Py_DECREF(py_cpu_seq);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* PSUTIL_HAVE_CPU_AFFINITY */
|
||||
|
||||
|
||||
/*
|
||||
* Return currently connected users as a list of tuples.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_users(PyObject *self, PyObject *args) {
|
||||
struct utmp *ut;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
PyObject *py_tuple = NULL;
|
||||
PyObject *py_username = NULL;
|
||||
PyObject *py_tty = NULL;
|
||||
PyObject *py_hostname = NULL;
|
||||
PyObject *py_user_proc = NULL;
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
setutent();
|
||||
while (NULL != (ut = getutent())) {
|
||||
py_tuple = NULL;
|
||||
py_user_proc = NULL;
|
||||
if (ut->ut_type == USER_PROCESS)
|
||||
py_user_proc = Py_True;
|
||||
else
|
||||
py_user_proc = Py_False;
|
||||
py_username = PyUnicode_DecodeFSDefault(ut->ut_user);
|
||||
if (! py_username)
|
||||
goto error;
|
||||
py_tty = PyUnicode_DecodeFSDefault(ut->ut_line);
|
||||
if (! py_tty)
|
||||
goto error;
|
||||
py_hostname = PyUnicode_DecodeFSDefault(ut->ut_host);
|
||||
if (! py_hostname)
|
||||
goto error;
|
||||
|
||||
py_tuple = Py_BuildValue(
|
||||
"OOOfO" _Py_PARSE_PID,
|
||||
py_username, // username
|
||||
py_tty, // tty
|
||||
py_hostname, // hostname
|
||||
(float)ut->ut_tv.tv_sec, // tstamp
|
||||
py_user_proc, // (bool) user process
|
||||
ut->ut_pid // process id
|
||||
);
|
||||
if (! py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_CLEAR(py_username);
|
||||
Py_CLEAR(py_tty);
|
||||
Py_CLEAR(py_hostname);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
endutent();
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_username);
|
||||
Py_XDECREF(py_tty);
|
||||
Py_XDECREF(py_hostname);
|
||||
Py_XDECREF(py_tuple);
|
||||
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_duplex_speed(PyObject* self, PyObject* args) {
|
||||
char *nic_name;
|
||||
int sock = 0;
|
||||
int ret;
|
||||
int duplex;
|
||||
int speed;
|
||||
struct ifreq ifr;
|
||||
struct ethtool_cmd ethcmd;
|
||||
PyObject *py_retlist = NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||
return NULL;
|
||||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == -1)
|
||||
return PyErr_SetFromOSErrnoWithSyscall("socket()");
|
||||
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||
|
||||
// duplex and speed
|
||||
memset(ðcmd, 0, sizeof ethcmd);
|
||||
ethcmd.cmd = ETHTOOL_GSET;
|
||||
ifr.ifr_data = (void *)ðcmd;
|
||||
ret = ioctl(sock, SIOCETHTOOL, &ifr);
|
||||
|
||||
if (ret != -1) {
|
||||
duplex = ethcmd.duplex;
|
||||
speed = ethcmd.speed;
|
||||
}
|
||||
else {
|
||||
if ((errno == EOPNOTSUPP) || (errno == EINVAL)) {
|
||||
// EOPNOTSUPP may occur in case of wi-fi cards.
|
||||
// For EINVAL see:
|
||||
// https://github.com/giampaolo/psutil/issues/797
|
||||
// #issuecomment-202999532
|
||||
duplex = DUPLEX_UNKNOWN;
|
||||
speed = 0;
|
||||
}
|
||||
else {
|
||||
PyErr_SetFromOSErrnoWithSyscall("ioctl(SIOCETHTOOL)");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
py_retlist = Py_BuildValue("[ii]", duplex, speed);
|
||||
if (!py_retlist)
|
||||
goto error;
|
||||
close(sock);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
if (sock != -1)
|
||||
close(sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Module init.
|
||||
*/
|
||||
|
||||
static PyMethodDef mod_methods[] = {
|
||||
// --- per-process functions
|
||||
|
||||
#if PSUTIL_HAVE_IOPRIO
|
||||
{"proc_ioprio_get", psutil_proc_ioprio_get, METH_VARARGS,
|
||||
"Get process I/O priority"},
|
||||
{"proc_ioprio_set", psutil_proc_ioprio_set, METH_VARARGS,
|
||||
"Set process I/O priority"},
|
||||
#endif
|
||||
#ifdef PSUTIL_HAVE_CPU_AFFINITY
|
||||
{"proc_cpu_affinity_get", psutil_proc_cpu_affinity_get, METH_VARARGS,
|
||||
"Return process CPU affinity as a Python long (the bitmask)."},
|
||||
{"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS,
|
||||
"Set process CPU affinity; expects a bitmask."},
|
||||
#endif
|
||||
|
||||
// --- system related functions
|
||||
|
||||
{"disk_partitions", psutil_disk_partitions, METH_VARARGS,
|
||||
"Return disk mounted partitions as a list of tuples including "
|
||||
"device, mount point and filesystem type"},
|
||||
{"users", psutil_users, METH_VARARGS,
|
||||
"Return currently connected users as a list of tuples"},
|
||||
{"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS,
|
||||
"Return duplex and speed info about a NIC"},
|
||||
|
||||
// --- linux specific
|
||||
|
||||
{"linux_sysinfo", psutil_linux_sysinfo, METH_VARARGS,
|
||||
"A wrapper around sysinfo(), return system memory usage statistics"},
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
{"linux_prlimit", psutil_linux_prlimit, METH_VARARGS,
|
||||
"Get or set process resource limits."},
|
||||
#endif
|
||||
// --- others
|
||||
{"set_testing", psutil_set_testing, METH_NOARGS,
|
||||
"Set psutil in testing mode"},
|
||||
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define INITERR return NULL
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_psutil_linux",
|
||||
NULL,
|
||||
-1,
|
||||
mod_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyObject *PyInit__psutil_linux(void)
|
||||
#else /* PY_MAJOR_VERSION */
|
||||
#define INITERR return
|
||||
|
||||
void init_psutil_linux(void)
|
||||
#endif /* PY_MAJOR_VERSION */
|
||||
{
|
||||
PyObject *v;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *mod = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *mod = Py_InitModule("_psutil_linux", mod_methods);
|
||||
#endif
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
|
||||
if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) INITERR;
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_AS", RLIMIT_AS)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_CORE", RLIMIT_CORE)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_CPU", RLIMIT_CPU)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_DATA", RLIMIT_DATA)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_FSIZE", RLIMIT_FSIZE)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", RLIMIT_LOCKS)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", RLIMIT_NOFILE)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_NPROC", RLIMIT_NPROC)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_RSS", RLIMIT_RSS)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_STACK", RLIMIT_STACK)) INITERR;
|
||||
|
||||
#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(mod, "RLIM_INFINITY", v);
|
||||
}
|
||||
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE)) INITERR;
|
||||
#endif
|
||||
#ifdef RLIMIT_NICE
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_NICE", RLIMIT_NICE)) INITERR;
|
||||
#endif
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_RTPRIO", RLIMIT_RTPRIO)) INITERR;
|
||||
#endif
|
||||
#ifdef RLIMIT_RTTIME
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_RTTIME", RLIMIT_RTTIME)) INITERR;
|
||||
#endif
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING))
|
||||
INITERR;
|
||||
#endif
|
||||
#endif
|
||||
if (PyModule_AddIntConstant(mod, "DUPLEX_HALF", DUPLEX_HALF)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "DUPLEX_FULL", DUPLEX_FULL)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN)) INITERR;
|
||||
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return mod;
|
||||
#endif
|
||||
}
|
||||
1906
third_party/python/psutil/psutil/_psutil_osx.c
vendored
Normal file
1906
third_party/python/psutil/psutil/_psutil_osx.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
680
third_party/python/psutil/psutil/_psutil_posix.c
vendored
Normal file
680
third_party/python/psutil/psutil/_psutil_posix.c
vendored
Normal file
|
|
@ -0,0 +1,680 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Functions specific to all POSIX compliant platforms.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#ifdef PSUTIL_SUNOS10
|
||||
#include "arch/solaris/v10/ifaddrs.h"
|
||||
#elif PSUTIL_AIX
|
||||
#include "arch/aix/ifaddrs.h"
|
||||
#else
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#if defined(PSUTIL_LINUX)
|
||||
#include <netdb.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_packet.h>
|
||||
#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if.h>
|
||||
#elif defined(PSUTIL_SUNOS)
|
||||
#include <netdb.h>
|
||||
#include <sys/sockio.h>
|
||||
#elif defined(PSUTIL_AIX)
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include "_psutil_common.h"
|
||||
|
||||
/*
|
||||
* Check if PID exists. Return values:
|
||||
* 1: exists
|
||||
* 0: does not exist
|
||||
* -1: error (Python exception is set)
|
||||
*/
|
||||
int
|
||||
psutil_pid_exists(pid_t pid) {
|
||||
int ret;
|
||||
|
||||
// No negative PID exists, plus -1 is an alias for sending signal
|
||||
// too all processes except system ones. Not what we want.
|
||||
if (pid < 0)
|
||||
return 0;
|
||||
|
||||
// As per "man 2 kill" PID 0 is an alias for sending the signal to
|
||||
// every process in the process group of the calling process.
|
||||
// Not what we want. Some platforms have PID 0, some do not.
|
||||
// We decide that at runtime.
|
||||
if (pid == 0) {
|
||||
#if defined(PSUTIL_LINUX) || defined(PSUTIL_FREEBSD)
|
||||
return 0;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = kill(pid , 0);
|
||||
if (ret == 0)
|
||||
return 1;
|
||||
else {
|
||||
if (errno == ESRCH) {
|
||||
// ESRCH == No such process
|
||||
return 0;
|
||||
}
|
||||
else if (errno == EPERM) {
|
||||
// EPERM clearly indicates there's a process to deny
|
||||
// access to.
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
// According to "man 2 kill" possible error values are
|
||||
// (EINVAL, EPERM, ESRCH) therefore we should never get
|
||||
// here. If we do let's be explicit in considering this
|
||||
// an error.
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Utility used for those syscalls which do not return a meaningful
|
||||
* error that we can translate into an exception which makes sense.
|
||||
* As such, we'll have to guess.
|
||||
* On UNIX, if errno is set, we return that one (OSError).
|
||||
* Else, if PID does not exist we assume the syscall failed because
|
||||
* of that so we raise NoSuchProcess.
|
||||
* If none of this is true we giveup and raise RuntimeError(msg).
|
||||
* This will always set a Python exception and return NULL.
|
||||
*/
|
||||
void
|
||||
psutil_raise_for_pid(long pid, char *syscall) {
|
||||
if (errno != 0) // unlikely
|
||||
PyErr_SetFromOSErrnoWithSyscall(syscall);
|
||||
else if (psutil_pid_exists(pid) == 0)
|
||||
NoSuchProcess(syscall);
|
||||
else
|
||||
PyErr_Format(PyExc_RuntimeError, "%s syscall failed", syscall);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a PID return process priority as a Python integer.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_posix_getpriority(PyObject *self, PyObject *args) {
|
||||
pid_t pid;
|
||||
int priority;
|
||||
errno = 0;
|
||||
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
#ifdef PSUTIL_OSX
|
||||
priority = getpriority(PRIO_PROCESS, (id_t)pid);
|
||||
#else
|
||||
priority = getpriority(PRIO_PROCESS, pid);
|
||||
#endif
|
||||
if (errno != 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
return Py_BuildValue("i", priority);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a PID and a value change process priority.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_posix_setpriority(PyObject *self, PyObject *args) {
|
||||
pid_t pid;
|
||||
int priority;
|
||||
int retval;
|
||||
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID "i", &pid, &priority))
|
||||
return NULL;
|
||||
|
||||
#ifdef PSUTIL_OSX
|
||||
retval = setpriority(PRIO_PROCESS, (id_t)pid, priority);
|
||||
#else
|
||||
retval = setpriority(PRIO_PROCESS, pid, priority);
|
||||
#endif
|
||||
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;
|
||||
size_t 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 PSUTIL_LINUX
|
||||
else if (family == AF_PACKET) {
|
||||
struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
|
||||
len = lladdr->sll_halen;
|
||||
data = (const char *)lladdr->sll_addr;
|
||||
}
|
||||
#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
|
||||
else if (addr->sa_family == AF_LINK) {
|
||||
// Note: prior to Python 3.4 socket module does not expose
|
||||
// AF_LINK so we'll do.
|
||||
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_CLEAR(py_tuple);
|
||||
Py_CLEAR(py_address);
|
||||
Py_CLEAR(py_netmask);
|
||||
Py_CLEAR(py_broadcast);
|
||||
Py_CLEAR(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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return NIC MTU. References:
|
||||
* http://www.i-scream.org/libstatgrab/
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_net_if_mtu(PyObject *self, PyObject *args) {
|
||||
char *nic_name;
|
||||
int sock = -1;
|
||||
int ret;
|
||||
#ifdef PSUTIL_SUNOS10
|
||||
struct lifreq lifr;
|
||||
#else
|
||||
struct ifreq ifr;
|
||||
#endif
|
||||
|
||||
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||
return NULL;
|
||||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == -1)
|
||||
goto error;
|
||||
|
||||
#ifdef PSUTIL_SUNOS10
|
||||
strncpy(lifr.lifr_name, nic_name, sizeof(lifr.lifr_name));
|
||||
ret = ioctl(sock, SIOCGIFMTU, &lifr);
|
||||
#else
|
||||
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||
ret = ioctl(sock, SIOCGIFMTU, &ifr);
|
||||
#endif
|
||||
if (ret == -1)
|
||||
goto error;
|
||||
close(sock);
|
||||
|
||||
#ifdef PSUTIL_SUNOS10
|
||||
return Py_BuildValue("i", lifr.lifr_mtu);
|
||||
#else
|
||||
return Py_BuildValue("i", ifr.ifr_mtu);
|
||||
#endif
|
||||
|
||||
error:
|
||||
if (sock != -1)
|
||||
close(sock);
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Inspect NIC flags, returns a bool indicating whether the NIC is
|
||||
* running. References:
|
||||
* http://www.i-scream.org/libstatgrab/
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_net_if_flags(PyObject *self, PyObject *args) {
|
||||
char *nic_name;
|
||||
int sock = -1;
|
||||
int ret;
|
||||
struct ifreq ifr;
|
||||
|
||||
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));
|
||||
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
|
||||
if (ret == -1)
|
||||
goto error;
|
||||
|
||||
close(sock);
|
||||
if ((ifr.ifr_flags & IFF_UP) != 0)
|
||||
return Py_BuildValue("O", Py_True);
|
||||
else
|
||||
return Py_BuildValue("O", Py_False);
|
||||
|
||||
error:
|
||||
if (sock != -1)
|
||||
close(sock);
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* net_if_stats() macOS/BSD implementation.
|
||||
*/
|
||||
#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
|
||||
|
||||
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(PSUTIL_OPENBSD)
|
||||
// FreeBSD 4 and others (but NOT OpenBSD) -> #define IFM_1000_T in net/if_media.h
|
||||
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_duplex_speed(PyObject *self, PyObject *args) {
|
||||
char *nic_name;
|
||||
int sock = -1;
|
||||
int ret;
|
||||
int duplex;
|
||||
int speed;
|
||||
struct ifreq ifr;
|
||||
struct ifmediareq ifmed;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||
return NULL;
|
||||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == -1)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||
|
||||
// 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);
|
||||
return Py_BuildValue("[ii]", duplex, speed);
|
||||
}
|
||||
#endif // net_if_stats() macOS/BSD implementation
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* define the psutil C module methods and initialize the module.
|
||||
*/
|
||||
static PyMethodDef mod_methods[] = {
|
||||
{"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"},
|
||||
{"net_if_mtu", psutil_net_if_mtu, METH_VARARGS,
|
||||
"Retrieve NIC MTU"},
|
||||
{"net_if_flags", psutil_net_if_flags, METH_VARARGS,
|
||||
"Retrieve NIC flags"},
|
||||
#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
|
||||
{"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS,
|
||||
"Return NIC stats."},
|
||||
#endif
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define INITERR return NULL
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_psutil_posix",
|
||||
NULL,
|
||||
-1,
|
||||
mod_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyObject *PyInit__psutil_posix(void)
|
||||
#else /* PY_MAJOR_VERSION */
|
||||
#define INITERR return
|
||||
|
||||
void init_psutil_posix(void)
|
||||
#endif /* PY_MAJOR_VERSION */
|
||||
{
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *mod = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *mod = Py_InitModule("_psutil_posix", mod_methods);
|
||||
#endif
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
|
||||
#if defined(PSUTIL_BSD) || \
|
||||
defined(PSUTIL_OSX) || \
|
||||
defined(PSUTIL_SUNOS) || \
|
||||
defined(PSUTIL_AIX)
|
||||
if (PyModule_AddIntConstant(mod, "AF_LINK", AF_LINK)) INITERR;
|
||||
#endif
|
||||
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return mod;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
8
third_party/python/psutil/psutil/_psutil_posix.h
vendored
Normal file
8
third_party/python/psutil/psutil/_psutil_posix.h
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
int psutil_pid_exists(pid_t pid);
|
||||
void psutil_raise_for_pid(pid_t pid, char *msg);
|
||||
1787
third_party/python/psutil/psutil/_psutil_sunos.c
vendored
Normal file
1787
third_party/python/psutil/psutil/_psutil_sunos.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1825
third_party/python/psutil/psutil/_psutil_windows.c
vendored
Normal file
1825
third_party/python/psutil/psutil/_psutil_windows.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
1105
third_party/python/psutil/psutil/_pswindows.py
vendored
Normal file
1105
third_party/python/psutil/psutil/_pswindows.py
vendored
Normal file
File diff suppressed because it is too large
Load diff
79
third_party/python/psutil/psutil/arch/aix/common.c
vendored
Normal file
79
third_party/python/psutil/psutil/arch/aix/common.c
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Arnon Yaari
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <sys/core.h>
|
||||
#include <stdlib.h>
|
||||
#include "common.h"
|
||||
|
||||
/* psutil_kread() - read from kernel memory */
|
||||
int
|
||||
psutil_kread(
|
||||
int Kd, /* kernel memory file descriptor */
|
||||
KA_T addr, /* kernel memory address */
|
||||
char *buf, /* buffer to receive data */
|
||||
size_t len) { /* length to read */
|
||||
int br;
|
||||
|
||||
if (lseek64(Kd, (off64_t)addr, L_SET) == (off64_t)-1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return 1;
|
||||
}
|
||||
br = read(Kd, buf, len);
|
||||
if (br == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return 1;
|
||||
}
|
||||
if (br != len) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"size mismatch when reading kernel memory fd");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct procentry64 *
|
||||
psutil_read_process_table(int * num) {
|
||||
size_t msz;
|
||||
pid32_t pid = 0;
|
||||
struct procentry64 *processes = (struct procentry64 *)NULL;
|
||||
struct procentry64 *p;
|
||||
int Np = 0; /* number of processes allocated in 'processes' */
|
||||
int np = 0; /* number of processes read into 'processes' */
|
||||
int i; /* number of processes read in current iteration */
|
||||
|
||||
msz = (size_t)(PROCSIZE * PROCINFO_INCR);
|
||||
processes = (struct procentry64 *)malloc(msz);
|
||||
if (!processes) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
Np = PROCINFO_INCR;
|
||||
p = processes;
|
||||
while ((i = getprocs64(p, PROCSIZE, (struct fdsinfo64 *)NULL, 0, &pid,
|
||||
PROCINFO_INCR))
|
||||
== PROCINFO_INCR) {
|
||||
np += PROCINFO_INCR;
|
||||
if (np >= Np) {
|
||||
msz = (size_t)(PROCSIZE * (Np + PROCINFO_INCR));
|
||||
processes = (struct procentry64 *)realloc((char *)processes, msz);
|
||||
if (!processes) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
Np += PROCINFO_INCR;
|
||||
}
|
||||
p = (struct procentry64 *)((char *)processes + (np * PROCSIZE));
|
||||
}
|
||||
|
||||
/* add the number of processes read in the last iteration */
|
||||
if (i > 0)
|
||||
np += i;
|
||||
|
||||
*num = np;
|
||||
return processes;
|
||||
}
|
||||
31
third_party/python/psutil/psutil/arch/aix/common.h
vendored
Normal file
31
third_party/python/psutil/psutil/arch/aix/common.h
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Arnon Yaari
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef __PSUTIL_AIX_COMMON_H__
|
||||
#define __PSUTIL_AIX_COMMON_H__
|
||||
|
||||
#include <sys/core.h>
|
||||
|
||||
#define PROCINFO_INCR (256)
|
||||
#define PROCSIZE (sizeof(struct procentry64))
|
||||
#define FDSINFOSIZE (sizeof(struct fdsinfo64))
|
||||
#define KMEM "/dev/kmem"
|
||||
|
||||
typedef u_longlong_t KA_T;
|
||||
|
||||
/* psutil_kread() - read from kernel memory */
|
||||
int psutil_kread(int Kd, /* kernel memory file descriptor */
|
||||
KA_T addr, /* kernel memory address */
|
||||
char *buf, /* buffer to receive data */
|
||||
size_t len); /* length to read */
|
||||
|
||||
struct procentry64 *
|
||||
psutil_read_process_table(
|
||||
int * num /* out - number of processes read */
|
||||
);
|
||||
|
||||
#endif /* __PSUTIL_AIX_COMMON_H__ */
|
||||
149
third_party/python/psutil/psutil/arch/aix/ifaddrs.c
vendored
Normal file
149
third_party/python/psutil/psutil/arch/aix/ifaddrs.c
vendored
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Arnon Yaari
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/*! Based on code from
|
||||
https://lists.samba.org/archive/samba-technical/2009-February/063079.html
|
||||
!*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "ifaddrs.h"
|
||||
|
||||
#define MAX(x,y) ((x)>(y)?(x):(y))
|
||||
#define SIZE(p) MAX((p).sa_len,sizeof(p))
|
||||
|
||||
|
||||
static struct sockaddr *
|
||||
sa_dup(struct sockaddr *sa1)
|
||||
{
|
||||
struct sockaddr *sa2;
|
||||
size_t sz = sa1->sa_len;
|
||||
sa2 = (struct sockaddr *) calloc(1, sz);
|
||||
if (sa2 == NULL)
|
||||
return NULL;
|
||||
memcpy(sa2, sa1, sz);
|
||||
return sa2;
|
||||
}
|
||||
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifp)
|
||||
{
|
||||
if (NULL == ifp) return;
|
||||
free(ifp->ifa_name);
|
||||
free(ifp->ifa_addr);
|
||||
free(ifp->ifa_netmask);
|
||||
free(ifp->ifa_dstaddr);
|
||||
freeifaddrs(ifp->ifa_next);
|
||||
free(ifp);
|
||||
}
|
||||
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
int sd, ifsize;
|
||||
char *ccp, *ecp;
|
||||
struct ifconf ifc;
|
||||
struct ifreq *ifr;
|
||||
struct ifaddrs *cifa = NULL; /* current */
|
||||
struct ifaddrs *pifa = NULL; /* previous */
|
||||
const size_t IFREQSZ = sizeof(struct ifreq);
|
||||
int fam;
|
||||
|
||||
*ifap = NULL;
|
||||
|
||||
sd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sd == -1)
|
||||
goto error;
|
||||
|
||||
/* find how much memory to allocate for the SIOCGIFCONF call */
|
||||
if (ioctl(sd, SIOCGSIZIFCONF, (caddr_t)&ifsize) < 0)
|
||||
goto error;
|
||||
|
||||
ifc.ifc_req = (struct ifreq *) calloc(1, ifsize);
|
||||
if (ifc.ifc_req == NULL)
|
||||
goto error;
|
||||
ifc.ifc_len = ifsize;
|
||||
|
||||
if (ioctl(sd, SIOCGIFCONF, &ifc) < 0)
|
||||
goto error;
|
||||
|
||||
ccp = (char *)ifc.ifc_req;
|
||||
ecp = ccp + ifsize;
|
||||
|
||||
while (ccp < ecp) {
|
||||
|
||||
ifr = (struct ifreq *) ccp;
|
||||
ifsize = sizeof(ifr->ifr_name) + SIZE(ifr->ifr_addr);
|
||||
fam = ifr->ifr_addr.sa_family;
|
||||
|
||||
if (fam == AF_INET || fam == AF_INET6) {
|
||||
cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs));
|
||||
if (cifa == NULL)
|
||||
goto error;
|
||||
cifa->ifa_next = NULL;
|
||||
|
||||
if (pifa == NULL) *ifap = cifa; /* first one */
|
||||
else pifa->ifa_next = cifa;
|
||||
|
||||
cifa->ifa_name = strdup(ifr->ifr_name);
|
||||
if (cifa->ifa_name == NULL)
|
||||
goto error;
|
||||
cifa->ifa_flags = 0;
|
||||
cifa->ifa_dstaddr = NULL;
|
||||
|
||||
cifa->ifa_addr = sa_dup(&ifr->ifr_addr);
|
||||
if (cifa->ifa_addr == NULL)
|
||||
goto error;
|
||||
|
||||
if (fam == AF_INET) {
|
||||
if (ioctl(sd, SIOCGIFNETMASK, ifr, IFREQSZ) < 0)
|
||||
goto error;
|
||||
cifa->ifa_netmask = sa_dup(&ifr->ifr_addr);
|
||||
if (cifa->ifa_netmask == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (0 == ioctl(sd, SIOCGIFFLAGS, ifr)) /* optional */
|
||||
cifa->ifa_flags = ifr->ifr_flags;
|
||||
|
||||
if (fam == AF_INET) {
|
||||
if (ioctl(sd, SIOCGIFDSTADDR, ifr, IFREQSZ) < 0) {
|
||||
if (0 == ioctl(sd, SIOCGIFBRDADDR, ifr, IFREQSZ)) {
|
||||
cifa->ifa_dstaddr = sa_dup(&ifr->ifr_addr);
|
||||
if (cifa->ifa_dstaddr == NULL)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cifa->ifa_dstaddr = sa_dup(&ifr->ifr_addr);
|
||||
if (cifa->ifa_dstaddr == NULL)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
pifa = cifa;
|
||||
}
|
||||
|
||||
ccp += ifsize;
|
||||
}
|
||||
free(ifc.ifc_req);
|
||||
close(sd);
|
||||
return 0;
|
||||
error:
|
||||
if (ifc.ifc_req != NULL)
|
||||
free(ifc.ifc_req);
|
||||
if (sd != -1)
|
||||
close(sd);
|
||||
freeifaddrs(*ifap);
|
||||
return (-1);
|
||||
}
|
||||
34
third_party/python/psutil/psutil/arch/aix/ifaddrs.h
vendored
Normal file
34
third_party/python/psutil/psutil/arch/aix/ifaddrs.h
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Arnon Yaari
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/*! Based on code from
|
||||
https://lists.samba.org/archive/samba-technical/2009-February/063079.html
|
||||
!*/
|
||||
|
||||
|
||||
#ifndef GENERIC_AIX_IFADDRS_H
|
||||
#define GENERIC_AIX_IFADDRS_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#undef ifa_dstaddr
|
||||
#undef ifa_broadaddr
|
||||
#define ifa_broadaddr ifa_dstaddr
|
||||
|
||||
struct ifaddrs {
|
||||
struct ifaddrs *ifa_next;
|
||||
char *ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr *ifa_addr;
|
||||
struct sockaddr *ifa_netmask;
|
||||
struct sockaddr *ifa_dstaddr;
|
||||
};
|
||||
|
||||
extern int getifaddrs(struct ifaddrs **);
|
||||
extern void freeifaddrs(struct ifaddrs *);
|
||||
#endif
|
||||
287
third_party/python/psutil/psutil/arch/aix/net_connections.c
vendored
Normal file
287
third_party/python/psutil/psutil/arch/aix/net_connections.c
vendored
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Arnon Yaari
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* Baded on code from lsof:
|
||||
* http://www.ibm.com/developerworks/aix/library/au-lsof.html
|
||||
* - dialects/aix/dproc.c:gather_proc_info
|
||||
* - lib/prfp.c:process_file
|
||||
* - dialects/aix/dsock.c:process_socket
|
||||
* - dialects/aix/dproc.c:get_kernel_access
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#define _KERNEL
|
||||
#include <sys/file.h>
|
||||
#undef _KERNEL
|
||||
#include <sys/types.h>
|
||||
#include <sys/core.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/un.h>
|
||||
#include <netinet/in_pcb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
#include "net_kernel_structs.h"
|
||||
#include "net_connections.h"
|
||||
#include "common.h"
|
||||
|
||||
#define NO_SOCKET (PyObject *)(-1)
|
||||
|
||||
static int
|
||||
read_unp_addr(
|
||||
int Kd,
|
||||
KA_T unp_addr,
|
||||
char *buf,
|
||||
size_t buflen
|
||||
) {
|
||||
struct sockaddr_un *ua = (struct sockaddr_un *)NULL;
|
||||
struct sockaddr_un un;
|
||||
struct mbuf64 mb;
|
||||
int uo;
|
||||
|
||||
if (psutil_kread(Kd, unp_addr, (char *)&mb, sizeof(mb))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uo = (int)(mb.m_hdr.mh_data - unp_addr);
|
||||
if ((uo + sizeof(struct sockaddr)) <= sizeof(mb))
|
||||
ua = (struct sockaddr_un *)((char *)&mb + uo);
|
||||
else {
|
||||
if (psutil_kread(Kd, (KA_T)mb.m_hdr.mh_data,
|
||||
(char *)&un, sizeof(un))) {
|
||||
return 1;
|
||||
}
|
||||
ua = &un;
|
||||
}
|
||||
if (ua && ua->sun_path[0]) {
|
||||
if (mb.m_len > sizeof(struct sockaddr_un))
|
||||
mb.m_len = sizeof(struct sockaddr_un);
|
||||
*((char *)ua + mb.m_len - 1) = '\0';
|
||||
snprintf(buf, buflen, "%s", ua->sun_path);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
process_file(int Kd, pid32_t pid, int fd, KA_T fp) {
|
||||
struct file64 f;
|
||||
struct socket64 s;
|
||||
struct protosw64 p;
|
||||
struct domain d;
|
||||
struct inpcb64 inp;
|
||||
int fam;
|
||||
struct tcpcb64 t;
|
||||
int state = PSUTIL_CONN_NONE;
|
||||
unsigned char *laddr = (unsigned char *)NULL;
|
||||
unsigned char *raddr = (unsigned char *)NULL;
|
||||
int rport, lport;
|
||||
char laddr_str[INET6_ADDRSTRLEN];
|
||||
char raddr_str[INET6_ADDRSTRLEN];
|
||||
struct unpcb64 unp;
|
||||
char unix_laddr_str[PATH_MAX] = { 0 };
|
||||
char unix_raddr_str[PATH_MAX] = { 0 };
|
||||
|
||||
/* Read file structure */
|
||||
if (psutil_kread(Kd, fp, (char *)&f, sizeof(f))) {
|
||||
return NULL;
|
||||
}
|
||||
if (!f.f_count || f.f_type != DTYPE_SOCKET) {
|
||||
return NO_SOCKET;
|
||||
}
|
||||
|
||||
if (psutil_kread(Kd, (KA_T) f.f_data, (char *) &s, sizeof(s))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!s.so_type) {
|
||||
return NO_SOCKET;
|
||||
}
|
||||
|
||||
if (!s.so_proto) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "invalid socket protocol handle");
|
||||
return NULL;
|
||||
}
|
||||
if (psutil_kread(Kd, (KA_T)s.so_proto, (char *)&p, sizeof(p))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!p.pr_domain) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "invalid socket protocol domain");
|
||||
return NULL;
|
||||
}
|
||||
if (psutil_kread(Kd, (KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fam = d.dom_family;
|
||||
if (fam == AF_INET || fam == AF_INET6) {
|
||||
/* Read protocol control block */
|
||||
if (!s.so_pcb) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "invalid socket PCB");
|
||||
return NULL;
|
||||
}
|
||||
if (psutil_kread(Kd, (KA_T) s.so_pcb, (char *) &inp, sizeof(inp))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (p.pr_protocol == IPPROTO_TCP) {
|
||||
/* If this is a TCP socket, read its control block */
|
||||
if (inp.inp_ppcb
|
||||
&& !psutil_kread(Kd, (KA_T)inp.inp_ppcb,
|
||||
(char *)&t, sizeof(t)))
|
||||
state = t.t_state;
|
||||
}
|
||||
|
||||
if (fam == AF_INET6) {
|
||||
laddr = (unsigned char *)&inp.inp_laddr6;
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&inp.inp_faddr6)) {
|
||||
raddr = (unsigned char *)&inp.inp_faddr6;
|
||||
rport = (int)ntohs(inp.inp_fport);
|
||||
}
|
||||
}
|
||||
if (fam == AF_INET) {
|
||||
laddr = (unsigned char *)&inp.inp_laddr;
|
||||
if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
|
||||
raddr = (unsigned char *)&inp.inp_faddr;
|
||||
rport = (int)ntohs(inp.inp_fport);
|
||||
}
|
||||
}
|
||||
lport = (int)ntohs(inp.inp_lport);
|
||||
|
||||
inet_ntop(fam, laddr, laddr_str, sizeof(laddr_str));
|
||||
|
||||
if (raddr != NULL) {
|
||||
inet_ntop(fam, raddr, raddr_str, sizeof(raddr_str));
|
||||
return Py_BuildValue("(iii(si)(si)ii)", fd, fam,
|
||||
s.so_type, laddr_str, lport, raddr_str,
|
||||
rport, state, pid);
|
||||
}
|
||||
else {
|
||||
return Py_BuildValue("(iii(si)()ii)", fd, fam,
|
||||
s.so_type, laddr_str, lport, state,
|
||||
pid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (fam == AF_UNIX) {
|
||||
if (psutil_kread(Kd, (KA_T) s.so_pcb, (char *)&unp, sizeof(unp))) {
|
||||
return NULL;
|
||||
}
|
||||
if ((KA_T) f.f_data != (KA_T) unp.unp_socket) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "unp_socket mismatch");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (unp.unp_addr) {
|
||||
if (read_unp_addr(Kd, unp.unp_addr, unix_laddr_str,
|
||||
sizeof(unix_laddr_str))) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (unp.unp_conn) {
|
||||
if (psutil_kread(Kd, (KA_T) unp.unp_conn, (char *)&unp,
|
||||
sizeof(unp))) {
|
||||
return NULL;
|
||||
}
|
||||
if (read_unp_addr(Kd, unp.unp_addr, unix_raddr_str,
|
||||
sizeof(unix_raddr_str))) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return Py_BuildValue("(iiissii)", fd, d.dom_family,
|
||||
s.so_type, unix_laddr_str, unix_raddr_str, PSUTIL_CONN_NONE,
|
||||
pid);
|
||||
}
|
||||
return NO_SOCKET;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
psutil_net_connections(PyObject *self, PyObject *args) {
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
PyObject *py_tuple = NULL;
|
||||
KA_T fp;
|
||||
int Kd = -1;
|
||||
int i, np;
|
||||
struct procentry64 *p;
|
||||
struct fdsinfo64 *fds = (struct fdsinfo64 *)NULL;
|
||||
pid32_t requested_pid;
|
||||
pid32_t pid;
|
||||
struct procentry64 *processes = (struct procentry64 *)NULL;
|
||||
/* the process table */
|
||||
|
||||
if (py_retlist == NULL)
|
||||
goto error;
|
||||
if (! PyArg_ParseTuple(args, "i", &requested_pid))
|
||||
goto error;
|
||||
|
||||
Kd = open(KMEM, O_RDONLY, 0);
|
||||
if (Kd < 0) {
|
||||
PyErr_SetFromErrnoWithFilename(PyExc_OSError, KMEM);
|
||||
goto error;
|
||||
}
|
||||
|
||||
processes = psutil_read_process_table(&np);
|
||||
if (!processes)
|
||||
goto error;
|
||||
|
||||
/* Loop through processes */
|
||||
for (p = processes; np > 0; np--, p++) {
|
||||
pid = p->pi_pid;
|
||||
if (requested_pid != -1 && requested_pid != pid)
|
||||
continue;
|
||||
if (p->pi_state == 0 || p->pi_state == SZOMB)
|
||||
continue;
|
||||
|
||||
if (!fds) {
|
||||
fds = (struct fdsinfo64 *)malloc((size_t)FDSINFOSIZE);
|
||||
if (!fds) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (getprocs64((struct procentry64 *)NULL, PROCSIZE, fds, FDSINFOSIZE,
|
||||
&pid, 1)
|
||||
!= 1)
|
||||
continue;
|
||||
|
||||
/* loop over file descriptors */
|
||||
for (i = 0; i < p->pi_maxofile; i++) {
|
||||
fp = (KA_T)fds->pi_ufd[i].fp;
|
||||
if (fp) {
|
||||
py_tuple = process_file(Kd, p->pi_pid, i, fp);
|
||||
if (py_tuple == NULL)
|
||||
goto error;
|
||||
if (py_tuple != NO_SOCKET) {
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
close(Kd);
|
||||
free(processes);
|
||||
if (fds != NULL)
|
||||
free(fds);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_DECREF(py_retlist);
|
||||
if (Kd > 0)
|
||||
close(Kd);
|
||||
if (processes != NULL)
|
||||
free(processes);
|
||||
if (fds != NULL)
|
||||
free(fds);
|
||||
return NULL;
|
||||
}
|
||||
15
third_party/python/psutil/psutil/arch/aix/net_connections.h
vendored
Normal file
15
third_party/python/psutil/psutil/arch/aix/net_connections.h
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Arnon Yaari
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef __NET_CONNECTIONS_H__
|
||||
#define __NET_CONNECTIONS_H__
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
PyObject* psutil_net_connections(PyObject *self, PyObject *args);
|
||||
|
||||
#endif /* __NET_CONNECTIONS_H__ */
|
||||
111
third_party/python/psutil/psutil/arch/aix/net_kernel_structs.h
vendored
Normal file
111
third_party/python/psutil/psutil/arch/aix/net_kernel_structs.h
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Arnon Yaari
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* The kernel is always 64 bit but Python is usually compiled as a 32 bit
|
||||
* process. We're reading the kernel memory to get the network connections,
|
||||
* so we need the structs we read to be defined with 64 bit "pointers".
|
||||
* Here are the partial definitions of the structs we use, taken from the
|
||||
* header files, with data type sizes converted to their 64 bit counterparts,
|
||||
* and unused data truncated. */
|
||||
|
||||
#ifdef __64BIT__
|
||||
/* In case we're in a 64 bit process after all */
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/unpcb.h>
|
||||
#include <sys/mbuf_base.h>
|
||||
#include <sys/mbuf_macro.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/tcpip.h>
|
||||
#include <netinet/tcp_timer.h>
|
||||
#include <netinet/tcp_var.h>
|
||||
#define file64 file
|
||||
#define socket64 socket
|
||||
#define protosw64 protosw
|
||||
#define inpcb64 inpcb
|
||||
#define tcpcb64 tcpcb
|
||||
#define unpcb64 unpcb
|
||||
#define mbuf64 mbuf
|
||||
#else /* __64BIT__ */
|
||||
struct file64 {
|
||||
int f_flag;
|
||||
int f_count;
|
||||
int f_options;
|
||||
int f_type;
|
||||
u_longlong_t f_data;
|
||||
};
|
||||
|
||||
struct socket64 {
|
||||
short so_type; /* generic type, see socket.h */
|
||||
short so_options; /* from socket call, see socket.h */
|
||||
ushort so_linger; /* time to linger while closing */
|
||||
short so_state; /* internal state flags SS_*, below */
|
||||
u_longlong_t so_pcb; /* protocol control block */
|
||||
u_longlong_t so_proto; /* protocol handle */
|
||||
};
|
||||
|
||||
struct protosw64 {
|
||||
short pr_type; /* socket type used for */
|
||||
u_longlong_t pr_domain; /* domain protocol a member of */
|
||||
short pr_protocol; /* protocol number */
|
||||
short pr_flags; /* see below */
|
||||
};
|
||||
|
||||
struct inpcb64 {
|
||||
u_longlong_t inp_next,inp_prev;
|
||||
/* pointers to other pcb's */
|
||||
u_longlong_t inp_head; /* pointer back to chain of inpcb's
|
||||
for this protocol */
|
||||
u_int32_t inp_iflowinfo; /* input flow label */
|
||||
u_short inp_fport; /* foreign port */
|
||||
u_int16_t inp_fatype; /* foreign address type */
|
||||
union in_addr_6 inp_faddr_6; /* foreign host table entry */
|
||||
u_int32_t inp_oflowinfo; /* output flow label */
|
||||
u_short inp_lport; /* local port */
|
||||
u_int16_t inp_latype; /* local address type */
|
||||
union in_addr_6 inp_laddr_6; /* local host table entry */
|
||||
u_longlong_t inp_socket; /* back pointer to socket */
|
||||
u_longlong_t inp_ppcb; /* pointer to per-protocol pcb */
|
||||
u_longlong_t space_rt;
|
||||
struct sockaddr_in6 spare_dst;
|
||||
u_longlong_t inp_ifa; /* interface address to use */
|
||||
int inp_flags; /* generic IP/datagram flags */
|
||||
};
|
||||
|
||||
struct tcpcb64 {
|
||||
u_longlong_t seg__next;
|
||||
u_longlong_t seg__prev;
|
||||
short t_state; /* state of this connection */
|
||||
};
|
||||
|
||||
struct unpcb64 {
|
||||
u_longlong_t unp_socket; /* pointer back to socket */
|
||||
u_longlong_t unp_vnode; /* if associated with file */
|
||||
ino_t unp_vno; /* fake vnode number */
|
||||
u_longlong_t unp_conn; /* control block of connected socket */
|
||||
u_longlong_t unp_refs; /* referencing socket linked list */
|
||||
u_longlong_t unp_nextref; /* link in unp_refs list */
|
||||
u_longlong_t unp_addr; /* bound address of socket */
|
||||
};
|
||||
|
||||
struct m_hdr64
|
||||
{
|
||||
u_longlong_t mh_next; /* next buffer in chain */
|
||||
u_longlong_t mh_nextpkt; /* next chain in queue/record */
|
||||
long mh_len; /* amount of data in this mbuf */
|
||||
u_longlong_t mh_data; /* location of data */
|
||||
};
|
||||
|
||||
struct mbuf64
|
||||
{
|
||||
struct m_hdr64 m_hdr;
|
||||
};
|
||||
|
||||
#define m_len m_hdr.mh_len
|
||||
|
||||
#endif /* __64BIT__ */
|
||||
371
third_party/python/psutil/psutil/arch/freebsd/proc_socks.c
vendored
Normal file
371
third_party/python/psutil/psutil/arch/freebsd/proc_socks.c
vendored
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Retrieves per-process open socket connections.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/socketvar.h> // for struct xsocket
|
||||
#include <sys/un.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <netinet/in.h> // for xinpcb struct
|
||||
#include <netinet/in_pcb.h>
|
||||
#include <netinet/tcp_var.h> // for struct xtcpcb
|
||||
#include <arpa/inet.h> // for inet_ntop()
|
||||
#include <libutil.h>
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
#include "../../_psutil_posix.h"
|
||||
|
||||
|
||||
// The tcplist fetching and walking is borrowed from netstat/inet.c.
|
||||
static char *
|
||||
psutil_fetch_tcplist(void) {
|
||||
char *buf;
|
||||
size_t len;
|
||||
|
||||
for (;;) {
|
||||
if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
buf = malloc(len);
|
||||
if (buf == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) {
|
||||
free(buf);
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
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 {
|
||||
sin6 = (struct sockaddr_in6 *)ss;
|
||||
return (sin6->sin6_port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
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 {
|
||||
sin6 = (struct sockaddr_in6 *)ss;
|
||||
return (&sin6->sin6_addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static socklen_t
|
||||
psutil_sockaddr_addrlen(int family) {
|
||||
if (family == AF_INET)
|
||||
return (sizeof(struct in_addr));
|
||||
else
|
||||
return (sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
psutil_sockaddr_matches(int family, int port, void *pcb_addr,
|
||||
struct sockaddr_storage *ss) {
|
||||
if (psutil_sockaddr_port(family, ss) != port)
|
||||
return (0);
|
||||
return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr,
|
||||
psutil_sockaddr_addrlen(family)) == 0);
|
||||
}
|
||||
|
||||
|
||||
#if __FreeBSD_version >= 1200026
|
||||
static struct xtcpcb *
|
||||
psutil_search_tcplist(char *buf, struct kinfo_file *kif) {
|
||||
struct xtcpcb *tp;
|
||||
struct xinpcb *inp;
|
||||
#else
|
||||
static struct tcpcb *
|
||||
psutil_search_tcplist(char *buf, struct kinfo_file *kif) {
|
||||
struct tcpcb *tp;
|
||||
struct inpcb *inp;
|
||||
#endif
|
||||
struct xinpgen *xig, *oxig;
|
||||
struct xsocket *so;
|
||||
|
||||
oxig = xig = (struct xinpgen *)buf;
|
||||
for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
|
||||
xig->xig_len > sizeof(struct xinpgen);
|
||||
xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
|
||||
|
||||
#if __FreeBSD_version >= 1200026
|
||||
tp = (struct xtcpcb *)xig;
|
||||
inp = &tp->xt_inp;
|
||||
so = &inp->xi_socket;
|
||||
#else
|
||||
tp = &((struct xtcpcb *)xig)->xt_tp;
|
||||
inp = &((struct xtcpcb *)xig)->xt_inp;
|
||||
so = &((struct xtcpcb *)xig)->xt_socket;
|
||||
#endif
|
||||
|
||||
if (so->so_type != kif->kf_sock_type ||
|
||||
so->xso_family != kif->kf_sock_domain ||
|
||||
so->xso_protocol != kif->kf_sock_protocol)
|
||||
continue;
|
||||
|
||||
if (kif->kf_sock_domain == AF_INET) {
|
||||
if (!psutil_sockaddr_matches(
|
||||
AF_INET, inp->inp_lport, &inp->inp_laddr,
|
||||
#if __FreeBSD_version < 1200031
|
||||
&kif->kf_sa_local))
|
||||
#else
|
||||
&kif->kf_un.kf_sock.kf_sa_local))
|
||||
#endif
|
||||
continue;
|
||||
if (!psutil_sockaddr_matches(
|
||||
AF_INET, inp->inp_fport, &inp->inp_faddr,
|
||||
#if __FreeBSD_version < 1200031
|
||||
&kif->kf_sa_peer))
|
||||
#else
|
||||
&kif->kf_un.kf_sock.kf_sa_peer))
|
||||
#endif
|
||||
continue;
|
||||
} else {
|
||||
if (!psutil_sockaddr_matches(
|
||||
AF_INET6, inp->inp_lport, &inp->in6p_laddr,
|
||||
#if __FreeBSD_version < 1200031
|
||||
&kif->kf_sa_local))
|
||||
#else
|
||||
&kif->kf_un.kf_sock.kf_sa_local))
|
||||
#endif
|
||||
continue;
|
||||
if (!psutil_sockaddr_matches(
|
||||
AF_INET6, inp->inp_fport, &inp->in6p_faddr,
|
||||
#if __FreeBSD_version < 1200031
|
||||
&kif->kf_sa_peer))
|
||||
#else
|
||||
&kif->kf_un.kf_sock.kf_sa_peer))
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
return (tp);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PyObject *
|
||||
psutil_proc_connections(PyObject *self, PyObject *args) {
|
||||
// Return connections opened by process.
|
||||
pid_t pid;
|
||||
int i;
|
||||
int cnt;
|
||||
struct kinfo_file *freep = NULL;
|
||||
struct kinfo_file *kif;
|
||||
char *tcplist = NULL;
|
||||
#if __FreeBSD_version >= 1200026
|
||||
struct xtcpcb *tcp;
|
||||
#else
|
||||
struct tcpcb *tcp;
|
||||
#endif
|
||||
|
||||
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 (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID "OO", &pid,
|
||||
&py_af_filter, &py_type_filter))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
freep = kinfo_getfile(pid, &cnt);
|
||||
if (freep == NULL) {
|
||||
psutil_raise_for_pid(pid, "kinfo_getfile()");
|
||||
goto error;
|
||||
}
|
||||
|
||||
tcplist = psutil_fetch_tcplist();
|
||||
if (tcplist == NULL) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
int lport, rport, state;
|
||||
char lip[200], rip[200];
|
||||
char path[PATH_MAX];
|
||||
int inseq;
|
||||
py_tuple = NULL;
|
||||
py_laddr = NULL;
|
||||
py_raddr = NULL;
|
||||
|
||||
kif = &freep[i];
|
||||
if (kif->kf_type == KF_TYPE_SOCKET) {
|
||||
// apply filters
|
||||
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;
|
||||
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)) {
|
||||
// fill status
|
||||
state = PSUTIL_CONN_NONE;
|
||||
if (kif->kf_sock_type == SOCK_STREAM) {
|
||||
tcp = psutil_search_tcplist(tcplist, kif);
|
||||
if (tcp != NULL)
|
||||
state = (int)tcp->t_state;
|
||||
}
|
||||
|
||||
// build addr and port
|
||||
inet_ntop(
|
||||
kif->kf_sock_domain,
|
||||
psutil_sockaddr_addr(kif->kf_sock_domain,
|
||||
#if __FreeBSD_version < 1200031
|
||||
&kif->kf_sa_local),
|
||||
#else
|
||||
&kif->kf_un.kf_sock.kf_sa_local),
|
||||
#endif
|
||||
lip,
|
||||
sizeof(lip));
|
||||
inet_ntop(
|
||||
kif->kf_sock_domain,
|
||||
psutil_sockaddr_addr(kif->kf_sock_domain,
|
||||
#if __FreeBSD_version < 1200031
|
||||
&kif->kf_sa_peer),
|
||||
#else
|
||||
&kif->kf_un.kf_sock.kf_sa_peer),
|
||||
#endif
|
||||
rip,
|
||||
sizeof(rip));
|
||||
lport = htons(psutil_sockaddr_port(kif->kf_sock_domain,
|
||||
#if __FreeBSD_version < 1200031
|
||||
&kif->kf_sa_local));
|
||||
#else
|
||||
&kif->kf_un.kf_sock.kf_sa_local));
|
||||
#endif
|
||||
rport = htons(psutil_sockaddr_port(kif->kf_sock_domain,
|
||||
#if __FreeBSD_version < 1200031
|
||||
&kif->kf_sa_peer));
|
||||
#else
|
||||
&kif->kf_un.kf_sock.kf_sa_peer));
|
||||
#endif
|
||||
|
||||
// construct python tuple/list
|
||||
py_laddr = Py_BuildValue("(si)", lip, lport);
|
||||
if (!py_laddr)
|
||||
goto error;
|
||||
if (rport != 0)
|
||||
py_raddr = Py_BuildValue("(si)", rip, rport);
|
||||
else
|
||||
py_raddr = Py_BuildValue("()");
|
||||
if (!py_raddr)
|
||||
goto error;
|
||||
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(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
}
|
||||
// UNIX socket.
|
||||
// Note: remote path cannot be determined.
|
||||
else if (kif->kf_sock_domain == AF_UNIX) {
|
||||
struct sockaddr_un *sun;
|
||||
|
||||
#if __FreeBSD_version < 1200031
|
||||
sun = (struct sockaddr_un *)&kif->kf_sa_local;
|
||||
#else
|
||||
sun = (struct sockaddr_un *)&kif->kf_un.kf_sock.kf_sa_local;
|
||||
#endif
|
||||
snprintf(
|
||||
path, sizeof(path), "%.*s",
|
||||
(int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
|
||||
sun->sun_path);
|
||||
|
||||
py_laddr = PyUnicode_DecodeFSDefault(path);
|
||||
if (! py_laddr)
|
||||
goto error;
|
||||
|
||||
py_tuple = Py_BuildValue(
|
||||
"(iiiOsi)",
|
||||
kif->kf_fd,
|
||||
kif->kf_sock_domain,
|
||||
kif->kf_sock_type,
|
||||
py_laddr,
|
||||
"", // raddr can't be determined
|
||||
PSUTIL_CONN_NONE
|
||||
);
|
||||
if (!py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_DECREF(py_laddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(freep);
|
||||
free(tcplist);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_XDECREF(py_laddr);
|
||||
Py_XDECREF(py_raddr);
|
||||
Py_DECREF(py_retlist);
|
||||
if (freep != NULL)
|
||||
free(freep);
|
||||
if (tcplist != NULL)
|
||||
free(tcplist);
|
||||
return NULL;
|
||||
}
|
||||
9
third_party/python/psutil/psutil/arch/freebsd/proc_socks.h
vendored
Normal file
9
third_party/python/psutil/psutil/arch/freebsd/proc_socks.h
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
PyObject* psutil_proc_connections(PyObject* self, PyObject* args);
|
||||
1077
third_party/python/psutil/psutil/arch/freebsd/specific.c
vendored
Normal file
1077
third_party/python/psutil/psutil/arch/freebsd/specific.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
34
third_party/python/psutil/psutil/arch/freebsd/specific.h
vendored
Normal file
34
third_party/python/psutil/psutil/arch/freebsd/specific.h
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Jay Loden, 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.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
typedef struct kinfo_proc kinfo_proc;
|
||||
|
||||
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
|
||||
int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc);
|
||||
|
||||
//
|
||||
PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_get_cmdline(long pid);
|
||||
PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
|
||||
#if defined(PSUTIL_FREEBSD)
|
||||
PyObject* psutil_sensors_battery(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_sensors_cpu_temperature(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_cpu_freq(PyObject* self, PyObject* args);
|
||||
#endif
|
||||
363
third_party/python/psutil/psutil/arch/freebsd/sys_socks.c
vendored
Normal file
363
third_party/python/psutil/psutil/arch/freebsd/sys_socks.c
vendored
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Retrieves system-wide open socket connections. This is based off of
|
||||
* sockstat utility source code:
|
||||
* https://github.com/freebsd/freebsd/blob/master/usr.bin/sockstat/sockstat.c
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/socketvar.h> // for struct xsocket
|
||||
#include <sys/un.h>
|
||||
#include <sys/unpcb.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <netinet/in.h> // for xinpcb struct
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/in_pcb.h>
|
||||
#include <netinet/tcp_var.h> // for struct xtcpcb
|
||||
#include <arpa/inet.h> // for inet_ntop()
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
#include "../../_psutil_posix.h"
|
||||
|
||||
static struct xfile *psutil_xfiles;
|
||||
static int psutil_nxfiles;
|
||||
|
||||
|
||||
int
|
||||
psutil_populate_xfiles() {
|
||||
size_t len;
|
||||
|
||||
if ((psutil_xfiles = malloc(len = sizeof *psutil_xfiles)) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return 0;
|
||||
}
|
||||
while (sysctlbyname("kern.file", psutil_xfiles, &len, 0, 0) == -1) {
|
||||
if (errno != ENOMEM) {
|
||||
PyErr_SetFromErrno(0);
|
||||
return 0;
|
||||
}
|
||||
len *= 2;
|
||||
if ((psutil_xfiles = realloc(psutil_xfiles, len)) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (len > 0 && psutil_xfiles->xf_size != sizeof *psutil_xfiles) {
|
||||
PyErr_Format(PyExc_RuntimeError, "struct xfile size mismatch");
|
||||
return 0;
|
||||
}
|
||||
psutil_nxfiles = len / sizeof *psutil_xfiles;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
struct xfile *
|
||||
psutil_get_file_from_sock(void *sock) {
|
||||
struct xfile *xf;
|
||||
int n;
|
||||
|
||||
for (xf = psutil_xfiles, n = 0; n < psutil_nxfiles; ++n, ++xf) {
|
||||
if (xf->xf_data == sock)
|
||||
return xf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Reference:
|
||||
// https://github.com/freebsd/freebsd/blob/master/usr.bin/sockstat/sockstat.c
|
||||
int psutil_gather_inet(int proto, PyObject *py_retlist) {
|
||||
struct xinpgen *xig, *exig;
|
||||
struct xinpcb *xip;
|
||||
struct xtcpcb *xtp;
|
||||
#if __FreeBSD_version >= 1200026
|
||||
struct xinpcb *inp;
|
||||
#else
|
||||
struct inpcb *inp;
|
||||
#endif
|
||||
struct xsocket *so;
|
||||
const char *varname = NULL;
|
||||
size_t len, bufsize;
|
||||
void *buf;
|
||||
int retry;
|
||||
int type;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
buf = NULL;
|
||||
bufsize = 8192;
|
||||
retry = 5;
|
||||
do {
|
||||
for (;;) {
|
||||
buf = realloc(buf, bufsize);
|
||||
if (buf == NULL)
|
||||
continue; // XXX
|
||||
len = bufsize;
|
||||
if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
|
||||
break;
|
||||
if (errno != ENOMEM) {
|
||||
PyErr_SetFromErrno(0);
|
||||
goto error;
|
||||
}
|
||||
bufsize *= 2;
|
||||
}
|
||||
xig = (struct xinpgen *)buf;
|
||||
exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig);
|
||||
if (xig->xig_len != sizeof *xig || exig->xig_len != sizeof *exig) {
|
||||
PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch");
|
||||
goto error;
|
||||
}
|
||||
} while (xig->xig_gen != exig->xig_gen && retry--);
|
||||
|
||||
for (;;) {
|
||||
struct xfile *xf;
|
||||
int lport, rport, 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;
|
||||
}
|
||||
inp = &xtp->xt_inp;
|
||||
#if __FreeBSD_version >= 1200026
|
||||
so = &inp->xi_socket;
|
||||
status = xtp->t_state;
|
||||
#else
|
||||
so = &xtp->xt_socket;
|
||||
status = xtp->xt_tp.t_state;
|
||||
#endif
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
xip = (struct xinpcb *)xig;
|
||||
if (xip->xi_len != sizeof *xip) {
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"struct xinpcb size mismatch");
|
||||
goto error;
|
||||
}
|
||||
#if __FreeBSD_version >= 1200026
|
||||
inp = xip;
|
||||
#else
|
||||
inp = &xip->xi_inp;
|
||||
#endif
|
||||
so = &xip->xi_socket;
|
||||
status = PSUTIL_CONN_NONE;
|
||||
break;
|
||||
default:
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid proto");
|
||||
goto error;
|
||||
}
|
||||
|
||||
char lip[200], rip[200];
|
||||
|
||||
xf = psutil_get_file_from_sock(so->xso_so);
|
||||
if (xf == NULL)
|
||||
continue;
|
||||
lport = ntohs(inp->inp_lport);
|
||||
rport = ntohs(inp->inp_fport);
|
||||
|
||||
if (inp->inp_vflag & INP_IPV4) {
|
||||
family = AF_INET;
|
||||
inet_ntop(AF_INET, &inp->inp_laddr.s_addr, lip, sizeof(lip));
|
||||
inet_ntop(AF_INET, &inp->inp_faddr.s_addr, rip, sizeof(rip));
|
||||
}
|
||||
else if (inp->inp_vflag & INP_IPV6) {
|
||||
family = AF_INET6;
|
||||
inet_ntop(AF_INET6, &inp->in6p_laddr.s6_addr, lip, sizeof(lip));
|
||||
inet_ntop(AF_INET6, &inp->in6p_faddr.s6_addr, rip, sizeof(rip));
|
||||
}
|
||||
|
||||
// construct python tuple/list
|
||||
py_laddr = Py_BuildValue("(si)", lip, lport);
|
||||
if (!py_laddr)
|
||||
goto error;
|
||||
if (rport != 0)
|
||||
py_raddr = Py_BuildValue("(si)", rip, rport);
|
||||
else
|
||||
py_raddr = Py_BuildValue("()");
|
||||
if (!py_raddr)
|
||||
goto error;
|
||||
py_tuple = Py_BuildValue(
|
||||
"iiiNNi" _Py_PARSE_PID,
|
||||
xf->xf_fd, // fd
|
||||
family, // family
|
||||
type, // type
|
||||
py_laddr, // laddr
|
||||
py_raddr, // raddr
|
||||
status, // status
|
||||
xf->xf_pid // pid
|
||||
);
|
||||
if (!py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
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) {
|
||||
struct xunpgen *xug, *exug;
|
||||
struct xunpcb *xup;
|
||||
const char *varname = NULL;
|
||||
const char *protoname = NULL;
|
||||
size_t len;
|
||||
size_t bufsize;
|
||||
void *buf;
|
||||
int retry;
|
||||
struct sockaddr_un *sun;
|
||||
char path[PATH_MAX];
|
||||
|
||||
PyObject *py_tuple = NULL;
|
||||
PyObject *py_lpath = 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;
|
||||
}
|
||||
|
||||
buf = NULL;
|
||||
bufsize = 8192;
|
||||
retry = 5;
|
||||
|
||||
do {
|
||||
for (;;) {
|
||||
buf = realloc(buf, bufsize);
|
||||
if (buf == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
len = bufsize;
|
||||
if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
|
||||
break;
|
||||
if (errno != ENOMEM) {
|
||||
PyErr_SetFromErrno(0);
|
||||
goto error;
|
||||
}
|
||||
bufsize *= 2;
|
||||
}
|
||||
xug = (struct xunpgen *)buf;
|
||||
exug = (struct xunpgen *)(void *)
|
||||
((char *)buf + len - sizeof *exug);
|
||||
if (xug->xug_len != sizeof *xug || exug->xug_len != sizeof *exug) {
|
||||
PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch");
|
||||
goto error;
|
||||
}
|
||||
} while (xug->xug_gen != exug->xug_gen && retry--);
|
||||
|
||||
for (;;) {
|
||||
struct xfile *xf;
|
||||
|
||||
xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len);
|
||||
if (xug >= exug)
|
||||
break;
|
||||
xup = (struct xunpcb *)xug;
|
||||
if (xup->xu_len != sizeof *xup)
|
||||
goto error;
|
||||
|
||||
xf = psutil_get_file_from_sock(xup->xu_socket.xso_so);
|
||||
if (xf == NULL)
|
||||
continue;
|
||||
|
||||
sun = (struct sockaddr_un *)&xup->xu_addr;
|
||||
snprintf(path, sizeof(path), "%.*s",
|
||||
(int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
|
||||
sun->sun_path);
|
||||
py_lpath = PyUnicode_DecodeFSDefault(path);
|
||||
if (! py_lpath)
|
||||
goto error;
|
||||
|
||||
py_tuple = Py_BuildValue("(iiiOsii)",
|
||||
xf->xf_fd, // fd
|
||||
AF_UNIX, // family
|
||||
proto, // type
|
||||
py_lpath, // lpath
|
||||
"", // rath
|
||||
PSUTIL_CONN_NONE, // status
|
||||
xf->xf_pid); // pid
|
||||
if (!py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_lpath);
|
||||
Py_DECREF(py_tuple);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_XDECREF(py_lpath);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyObject*
|
||||
psutil_net_connections(PyObject* self, PyObject* args) {
|
||||
// Return system-wide open connections.
|
||||
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)
|
||||
goto error;
|
||||
if (psutil_gather_unix(SOCK_STREAM, py_retlist) == 0)
|
||||
goto error;
|
||||
if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0)
|
||||
goto error;
|
||||
|
||||
free(psutil_xfiles);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_DECREF(py_retlist);
|
||||
free(psutil_xfiles);
|
||||
return NULL;
|
||||
}
|
||||
10
third_party/python/psutil/psutil/arch/freebsd/sys_socks.h
vendored
Normal file
10
third_party/python/psutil/psutil/arch/freebsd/sys_socks.h
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
PyObject* psutil_net_connections(PyObject* self, PyObject* args);
|
||||
447
third_party/python/psutil/psutil/arch/netbsd/socks.c
vendored
Normal file
447
third_party/python/psutil/psutil/arch/netbsd/socks.c
vendored
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'.
|
||||
* Copyright (c) 2015, Ryo ONODERA.
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
#include "../../_psutil_posix.h"
|
||||
|
||||
|
||||
// address family filter
|
||||
enum af_filter {
|
||||
INET,
|
||||
INET4,
|
||||
INET6,
|
||||
TCP,
|
||||
TCP4,
|
||||
TCP6,
|
||||
UDP,
|
||||
UDP4,
|
||||
UDP6,
|
||||
UNIX,
|
||||
ALL,
|
||||
};
|
||||
|
||||
// kinfo_file results
|
||||
struct kif {
|
||||
SLIST_ENTRY(kif) kifs;
|
||||
struct kinfo_file *kif;
|
||||
};
|
||||
|
||||
// kinfo_file results list
|
||||
SLIST_HEAD(kifhead, kif) kihead = SLIST_HEAD_INITIALIZER(kihead);
|
||||
|
||||
|
||||
// kinfo_pcb results
|
||||
struct kpcb {
|
||||
SLIST_ENTRY(kpcb) kpcbs;
|
||||
struct kinfo_pcb *kpcb;
|
||||
};
|
||||
|
||||
// kinfo_pcb results list
|
||||
SLIST_HEAD(kpcbhead, kpcb) kpcbhead = SLIST_HEAD_INITIALIZER(kpcbhead);
|
||||
|
||||
static void psutil_kiflist_init(void);
|
||||
static void psutil_kiflist_clear(void);
|
||||
static void psutil_kpcblist_init(void);
|
||||
static void psutil_kpcblist_clear(void);
|
||||
static int psutil_get_files(void);
|
||||
static int psutil_get_sockets(const char *name);
|
||||
static int psutil_get_info(int aff);
|
||||
|
||||
|
||||
// Initialize kinfo_file results list.
|
||||
static void
|
||||
psutil_kiflist_init(void) {
|
||||
SLIST_INIT(&kihead);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Clear kinfo_file results list.
|
||||
static void
|
||||
psutil_kiflist_clear(void) {
|
||||
while (!SLIST_EMPTY(&kihead)) {
|
||||
SLIST_REMOVE_HEAD(&kihead, kifs);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Initialize kinof_pcb result list.
|
||||
static void
|
||||
psutil_kpcblist_init(void) {
|
||||
SLIST_INIT(&kpcbhead);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Clear kinof_pcb result list.
|
||||
static void
|
||||
psutil_kpcblist_clear(void) {
|
||||
while (!SLIST_EMPTY(&kpcbhead)) {
|
||||
SLIST_REMOVE_HEAD(&kpcbhead, kpcbs);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get all open files including socket.
|
||||
static int
|
||||
psutil_get_files(void) {
|
||||
size_t len;
|
||||
size_t j;
|
||||
int mib[6];
|
||||
char *buf;
|
||||
off_t offset;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_FILE2;
|
||||
mib[2] = KERN_FILE_BYFILE;
|
||||
mib[3] = 0;
|
||||
mib[4] = sizeof(struct kinfo_file);
|
||||
mib[5] = 0;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = len % sizeof(off_t);
|
||||
mib[5] = len / sizeof(struct kinfo_file);
|
||||
|
||||
if ((buf = malloc(len + offset)) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sysctl(mib, 6, buf + offset, &len, NULL, 0) == -1) {
|
||||
free(buf);
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len /= sizeof(struct kinfo_file);
|
||||
struct kinfo_file *ki = (struct kinfo_file *)(buf + offset);
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
struct kif *kif = malloc(sizeof(struct kif));
|
||||
kif->kif = &ki[j];
|
||||
SLIST_INSERT_HEAD(&kihead, kif, kifs);
|
||||
}
|
||||
|
||||
/*
|
||||
// debug
|
||||
struct kif *k;
|
||||
SLIST_FOREACH(k, &kihead, kifs) {
|
||||
printf("%d\n", k->kif->ki_pid);
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Get open sockets.
|
||||
static int
|
||||
psutil_get_sockets(const char *name) {
|
||||
size_t namelen;
|
||||
int mib[8];
|
||||
struct kinfo_pcb *pcb;
|
||||
size_t len;
|
||||
size_t j;
|
||||
|
||||
memset(mib, 0, sizeof(mib));
|
||||
|
||||
if (sysctlnametomib(name, mib, &namelen) == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((pcb = malloc(len)) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
memset(pcb, 0, len);
|
||||
|
||||
mib[6] = sizeof(*pcb);
|
||||
mib[7] = len / sizeof(*pcb);
|
||||
|
||||
if (sysctl(mib, __arraycount(mib), pcb, &len, NULL, 0) == -1) {
|
||||
free(pcb);
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
len /= sizeof(struct kinfo_pcb);
|
||||
struct kinfo_pcb *kp = (struct kinfo_pcb *)pcb;
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
struct kpcb *kpcb = malloc(sizeof(struct kpcb));
|
||||
kpcb->kpcb = &kp[j];
|
||||
SLIST_INSERT_HEAD(&kpcbhead, kpcb, kpcbs);
|
||||
}
|
||||
|
||||
/*
|
||||
// debug
|
||||
struct kif *k;
|
||||
struct kpcb *k;
|
||||
SLIST_FOREACH(k, &kpcbhead, kpcbs) {
|
||||
printf("ki_type: %d\n", k->kpcb->ki_type);
|
||||
printf("ki_family: %d\n", k->kpcb->ki_family);
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Collect open file and connections.
|
||||
static int
|
||||
psutil_get_info(int aff) {
|
||||
switch (aff) {
|
||||
case INET:
|
||||
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case INET4:
|
||||
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case INET6:
|
||||
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case TCP:
|
||||
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case TCP4:
|
||||
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case TCP6:
|
||||
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case UDP:
|
||||
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case UDP4:
|
||||
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case UDP6:
|
||||
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case UNIX:
|
||||
if (psutil_get_sockets("net.local.stream.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
case ALL:
|
||||
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.local.stream.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
|
||||
return -1;
|
||||
if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return system-wide connections (unless a pid != -1 is passed).
|
||||
*/
|
||||
PyObject *
|
||||
psutil_net_connections(PyObject *self, PyObject *args) {
|
||||
char laddr[PATH_MAX];
|
||||
char raddr[PATH_MAX];
|
||||
int32_t lport;
|
||||
int32_t rport;
|
||||
int32_t status;
|
||||
pid_t pid;
|
||||
PyObject *py_tuple = NULL;
|
||||
PyObject *py_laddr = NULL;
|
||||
PyObject *py_raddr = NULL;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
return NULL;
|
||||
|
||||
psutil_kiflist_init();
|
||||
psutil_kpcblist_init();
|
||||
if (psutil_get_files() != 0)
|
||||
goto error;
|
||||
if (psutil_get_info(ALL) != 0)
|
||||
goto error;
|
||||
|
||||
struct kif *k;
|
||||
SLIST_FOREACH(k, &kihead, kifs) {
|
||||
struct kpcb *kp;
|
||||
if ((pid != -1) && (k->kif->ki_pid != (unsigned int)pid))
|
||||
continue;
|
||||
SLIST_FOREACH(kp, &kpcbhead, kpcbs) {
|
||||
if (k->kif->ki_fdata != kp->kpcb->ki_sockaddr)
|
||||
continue;
|
||||
|
||||
// IPv4 or IPv6
|
||||
if ((kp->kpcb->ki_family == AF_INET) ||
|
||||
(kp->kpcb->ki_family == AF_INET6)) {
|
||||
|
||||
if (kp->kpcb->ki_family == AF_INET) {
|
||||
// IPv4
|
||||
struct sockaddr_in *sin_src =
|
||||
(struct sockaddr_in *)&kp->kpcb->ki_src;
|
||||
struct sockaddr_in *sin_dst =
|
||||
(struct sockaddr_in *)&kp->kpcb->ki_dst;
|
||||
// source addr and port
|
||||
inet_ntop(AF_INET, &sin_src->sin_addr, laddr,
|
||||
sizeof(laddr));
|
||||
lport = ntohs(sin_src->sin_port);
|
||||
// remote addr and port
|
||||
inet_ntop(AF_INET, &sin_dst->sin_addr, raddr,
|
||||
sizeof(raddr));
|
||||
rport = ntohs(sin_dst->sin_port);
|
||||
}
|
||||
else {
|
||||
// IPv6
|
||||
struct sockaddr_in6 *sin6_src =
|
||||
(struct sockaddr_in6 *)&kp->kpcb->ki_src;
|
||||
struct sockaddr_in6 *sin6_dst =
|
||||
(struct sockaddr_in6 *)&kp->kpcb->ki_dst;
|
||||
// local addr and port
|
||||
inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr,
|
||||
sizeof(laddr));
|
||||
lport = ntohs(sin6_src->sin6_port);
|
||||
// remote addr and port
|
||||
inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr,
|
||||
sizeof(raddr));
|
||||
rport = ntohs(sin6_dst->sin6_port);
|
||||
}
|
||||
|
||||
// status
|
||||
if (kp->kpcb->ki_type == SOCK_STREAM)
|
||||
status = kp->kpcb->ki_tstate;
|
||||
else
|
||||
status = PSUTIL_CONN_NONE;
|
||||
|
||||
// build addr tuple
|
||||
py_laddr = Py_BuildValue("(si)", laddr, lport);
|
||||
if (! py_laddr)
|
||||
goto error;
|
||||
if (rport != 0)
|
||||
py_raddr = Py_BuildValue("(si)", raddr, rport);
|
||||
else
|
||||
py_raddr = Py_BuildValue("()");
|
||||
if (! py_raddr)
|
||||
goto error;
|
||||
}
|
||||
else if (kp->kpcb->ki_family == AF_UNIX) {
|
||||
// UNIX sockets
|
||||
struct sockaddr_un *sun_src =
|
||||
(struct sockaddr_un *)&kp->kpcb->ki_src;
|
||||
struct sockaddr_un *sun_dst =
|
||||
(struct sockaddr_un *)&kp->kpcb->ki_dst;
|
||||
strcpy(laddr, sun_src->sun_path);
|
||||
strcpy(raddr, sun_dst->sun_path);
|
||||
status = PSUTIL_CONN_NONE;
|
||||
py_laddr = PyUnicode_DecodeFSDefault(laddr);
|
||||
if (! py_laddr)
|
||||
goto error;
|
||||
py_raddr = PyUnicode_DecodeFSDefault(raddr);
|
||||
if (! py_raddr)
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// append tuple to list
|
||||
py_tuple = Py_BuildValue(
|
||||
"(iiiOOii)",
|
||||
k->kif->ki_fd,
|
||||
kp->kpcb->ki_family,
|
||||
kp->kpcb->ki_type,
|
||||
py_laddr,
|
||||
py_raddr,
|
||||
status,
|
||||
k->kif->ki_pid);
|
||||
if (! py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_laddr);
|
||||
Py_DECREF(py_raddr);
|
||||
Py_DECREF(py_tuple);
|
||||
}
|
||||
}
|
||||
|
||||
psutil_kiflist_clear();
|
||||
psutil_kpcblist_clear();
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_XDECREF(py_laddr);
|
||||
Py_XDECREF(py_raddr);
|
||||
return 0;
|
||||
}
|
||||
10
third_party/python/psutil/psutil/arch/netbsd/socks.h
vendored
Normal file
10
third_party/python/psutil/psutil/arch/netbsd/socks.h
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola'.
|
||||
* Copyright (c) 2015, Ryo ONODERA.
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
PyObject *psutil_proc_connections(PyObject *, PyObject *);
|
||||
PyObject *psutil_net_connections(PyObject *, PyObject *);
|
||||
688
third_party/python/psutil/psutil/arch/netbsd/specific.c
vendored
Normal file
688
third_party/python/psutil/psutil/arch/netbsd/specific.c
vendored
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Platform-specific module methods for NetBSD.
|
||||
*/
|
||||
|
||||
#if defined(PSUTIL_NETBSD)
|
||||
#define _KMEMUSER
|
||||
#endif
|
||||
|
||||
#include <Python.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/swap.h> // for swap_mem
|
||||
#include <signal.h>
|
||||
#include <kvm.h>
|
||||
// connection stuff
|
||||
#include <netdb.h> // for NI_MAXHOST
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sched.h> // for CPUSTATES & CP_*
|
||||
#define _KERNEL // for DTYPE_*
|
||||
#include <sys/file.h>
|
||||
#undef _KERNEL
|
||||
#include <sys/disk.h> // struct diskstats
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
#include "../../_psutil_posix.h"
|
||||
#include "specific.h"
|
||||
|
||||
|
||||
#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0)
|
||||
#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Utility functions
|
||||
// ============================================================================
|
||||
|
||||
|
||||
int
|
||||
psutil_kinfo_proc(pid_t pid, kinfo_proc *proc) {
|
||||
// Fills a kinfo_proc struct based on process pid.
|
||||
int ret;
|
||||
int mib[6];
|
||||
size_t size = sizeof(kinfo_proc);
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC2;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = pid;
|
||||
mib[4] = size;
|
||||
mib[5] = 1;
|
||||
|
||||
ret = sysctl((int*)mib, 6, proc, &size, NULL, 0);
|
||||
if (ret == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return -1;
|
||||
}
|
||||
// sysctl stores 0 in the size if we can't find the process information.
|
||||
if (size == 0) {
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct kinfo_file *
|
||||
kinfo_getfile(pid_t pid, int* cnt) {
|
||||
// Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an
|
||||
// int as arg and returns an array with cnt struct kinfo_file.
|
||||
int mib[6];
|
||||
size_t len;
|
||||
struct kinfo_file* kf;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_FILE2;
|
||||
mib[2] = KERN_FILE_BYPID;
|
||||
mib[3] = (int) pid;
|
||||
mib[4] = sizeof(struct kinfo_file);
|
||||
mib[5] = 0;
|
||||
|
||||
// get the size of what would be returned
|
||||
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
if ((kf = malloc(len)) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
mib[5] = (int)(len / sizeof(struct kinfo_file));
|
||||
if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*cnt = (int)(len / sizeof(struct kinfo_file));
|
||||
return kf;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
psutil_proc_cwd(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
|
||||
char path[MAXPATHLEN];
|
||||
size_t pathlen = sizeof path;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
return NULL;
|
||||
|
||||
#ifdef KERN_PROC_CWD
|
||||
int name[] = { CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_CWD};
|
||||
if (sysctl(name, 4, path, &pathlen, NULL, 0) != 0) {
|
||||
if (errno == ENOENT)
|
||||
NoSuchProcess("");
|
||||
else
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
char *buf;
|
||||
if (asprintf(&buf, "/proc/%d/cwd", (int)pid) < 0) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize_t len = readlink(buf, path, sizeof(path) - 1);
|
||||
free(buf);
|
||||
if (len == -1) {
|
||||
if (errno == ENOENT)
|
||||
NoSuchProcess("readlink (ENOENT)");
|
||||
else
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
path[len] = '\0';
|
||||
#endif
|
||||
|
||||
return PyUnicode_DecodeFSDefault(path);
|
||||
}
|
||||
|
||||
|
||||
// XXX: This is no longer used as per
|
||||
// https://github.com/giampaolo/psutil/pull/557#issuecomment-171912820
|
||||
// Current implementation uses /proc instead.
|
||||
// Left here just in case.
|
||||
/*
|
||||
PyObject *
|
||||
psutil_proc_exe(PyObject *self, PyObject *args) {
|
||||
#if __NetBSD_Version__ >= 799000000
|
||||
pid_t pid;
|
||||
char pathname[MAXPATHLEN];
|
||||
int error;
|
||||
int mib[4];
|
||||
int ret;
|
||||
size_t size;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
return NULL;
|
||||
if (pid == 0) {
|
||||
// else returns ENOENT
|
||||
return Py_BuildValue("s", "");
|
||||
}
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC_ARGS;
|
||||
mib[2] = pid;
|
||||
mib[3] = KERN_PROC_PATHNAME;
|
||||
|
||||
size = sizeof(pathname);
|
||||
error = sysctl(mib, 4, NULL, &size, NULL, 0);
|
||||
if (error == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error = sysctl(mib, 4, pathname, &size, NULL, 0);
|
||||
if (error == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
if (size == 0 || strlen(pathname) == 0) {
|
||||
ret = psutil_pid_exists(pid);
|
||||
if (ret == -1)
|
||||
return NULL;
|
||||
else if (ret == 0)
|
||||
return NoSuchProcess("psutil_pid_exists");
|
||||
else
|
||||
strcpy(pathname, "");
|
||||
}
|
||||
|
||||
return PyUnicode_DecodeFSDefault(pathname);
|
||||
#else
|
||||
return Py_BuildValue("s", "");
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
PyObject *
|
||||
psutil_proc_num_threads(PyObject *self, PyObject *args) {
|
||||
// Return number of threads used by process as a Python integer.
|
||||
long pid;
|
||||
kinfo_proc kp;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
return NULL;
|
||||
if (psutil_kinfo_proc(pid, &kp) == -1)
|
||||
return NULL;
|
||||
return Py_BuildValue("l", (long)kp.p_nlwps);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
psutil_proc_threads(PyObject *self, PyObject *args) {
|
||||
pid_t pid;
|
||||
int mib[5];
|
||||
int i, nlwps;
|
||||
ssize_t st;
|
||||
size_t size;
|
||||
struct kinfo_lwp *kl = NULL;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
PyObject *py_tuple = NULL;
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
goto error;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_LWP;
|
||||
mib[2] = pid;
|
||||
mib[3] = sizeof(struct kinfo_lwp);
|
||||
mib[4] = 0;
|
||||
|
||||
st = sysctl(mib, 5, NULL, &size, NULL, 0);
|
||||
if (st == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
if (size == 0) {
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
mib[4] = size / sizeof(size_t);
|
||||
kl = malloc(size);
|
||||
if (kl == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
|
||||
st = sysctl(mib, 5, kl, &size, NULL, 0);
|
||||
if (st == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
if (size == 0) {
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
nlwps = (int)(size / sizeof(struct kinfo_lwp));
|
||||
for (i = 0; i < nlwps; i++) {
|
||||
py_tuple = Py_BuildValue("idd",
|
||||
(&kl[i])->l_lid,
|
||||
PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime),
|
||||
PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime));
|
||||
if (py_tuple == NULL)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
}
|
||||
free(kl);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_DECREF(py_retlist);
|
||||
if (kl != NULL)
|
||||
free(kl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// APIS
|
||||
// ============================================================================
|
||||
|
||||
int
|
||||
psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) {
|
||||
// Returns a list of all BSD processes on the system. This routine
|
||||
// allocates the list and puts it in *procList and a count of the
|
||||
// number of entries in *procCount. You are responsible for freeing
|
||||
// this list (use "free" from System framework).
|
||||
// On success, the function returns 0.
|
||||
// On error, the function returns a BSD errno value.
|
||||
kinfo_proc *result;
|
||||
// Declaring name as const requires us to cast it when passing it to
|
||||
// sysctl because the prototype doesn't include the const modifier.
|
||||
char errbuf[_POSIX2_LINE_MAX];
|
||||
int cnt;
|
||||
kvm_t *kd;
|
||||
|
||||
assert( procList != NULL);
|
||||
assert(*procList == NULL);
|
||||
assert(procCount != NULL);
|
||||
|
||||
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
|
||||
|
||||
if (kd == NULL) {
|
||||
PyErr_Format(
|
||||
PyExc_RuntimeError, "kvm_openfiles() syscall failed: %s", errbuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(kinfo_proc), &cnt);
|
||||
if (result == NULL) {
|
||||
PyErr_Format(PyExc_RuntimeError, "kvm_getproc2() syscall failed");
|
||||
kvm_close(kd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*procCount = (size_t)cnt;
|
||||
|
||||
size_t mlen = cnt * sizeof(kinfo_proc);
|
||||
|
||||
if ((*procList = malloc(mlen)) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
kvm_close(kd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(*procList, result, mlen);
|
||||
assert(*procList != NULL);
|
||||
kvm_close(kd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
psutil_get_cmd_args(pid_t pid, size_t *argsize) {
|
||||
int mib[4];
|
||||
int st;
|
||||
size_t len;
|
||||
char *procargs;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC_ARGS;
|
||||
mib[2] = pid;
|
||||
mib[3] = KERN_PROC_ARGV;
|
||||
len = 0;
|
||||
|
||||
st = sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0);
|
||||
if (st == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
procargs = (char *)malloc(len);
|
||||
if (procargs == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
st = sysctl(mib, __arraycount(mib), procargs, &len, NULL, 0);
|
||||
if (st == -1) {
|
||||
free(procargs);
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*argsize = len;
|
||||
return procargs;
|
||||
}
|
||||
|
||||
|
||||
// Return the command line as a python list object.
|
||||
// XXX - most of the times sysctl() returns a truncated string.
|
||||
// Also /proc/pid/cmdline behaves the same so it looks like this
|
||||
// is a kernel bug.
|
||||
PyObject *
|
||||
psutil_get_cmdline(pid_t pid) {
|
||||
char *argstr = NULL;
|
||||
size_t pos = 0;
|
||||
size_t argsize = 0;
|
||||
PyObject *py_arg = NULL;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (pid == 0)
|
||||
return py_retlist;
|
||||
|
||||
argstr = psutil_get_cmd_args(pid, &argsize);
|
||||
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) {
|
||||
py_arg = PyUnicode_DecodeFSDefault(&argstr[pos]);
|
||||
if (!py_arg)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_arg))
|
||||
goto error;
|
||||
Py_DECREF(py_arg);
|
||||
pos = pos + strlen(&argstr[pos]) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(argstr);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_arg);
|
||||
Py_DECREF(py_retlist);
|
||||
if (argstr != NULL)
|
||||
free(argstr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Virtual memory stats, taken from:
|
||||
* https://github.com/satterly/zabbix-stats/blob/master/src/libs/zbxsysinfo/
|
||||
* netbsd/memory.c
|
||||
*/
|
||||
PyObject *
|
||||
psutil_virtual_mem(PyObject *self, PyObject *args) {
|
||||
size_t size;
|
||||
struct uvmexp_sysctl uv;
|
||||
int mib[] = {CTL_VM, VM_UVMEXP2};
|
||||
long pagesize = getpagesize();
|
||||
|
||||
size = sizeof(uv);
|
||||
if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Py_BuildValue("KKKKKKKK",
|
||||
(unsigned long long) uv.npages << uv.pageshift, // total
|
||||
(unsigned long long) uv.free << uv.pageshift, // free
|
||||
(unsigned long long) uv.active << uv.pageshift, // active
|
||||
(unsigned long long) uv.inactive << uv.pageshift, // inactive
|
||||
(unsigned long long) uv.wired << uv.pageshift, // wired
|
||||
(unsigned long long) uv.filepages + uv.execpages * pagesize, // cached
|
||||
// These are determined from /proc/meminfo in Python.
|
||||
(unsigned long long) 0, // buffers
|
||||
(unsigned long long) 0 // shared
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
psutil_swap_mem(PyObject *self, PyObject *args) {
|
||||
uint64_t swap_total, swap_free;
|
||||
struct swapent *swdev;
|
||||
int nswap, i;
|
||||
|
||||
nswap = swapctl(SWAP_NSWAP, 0, 0);
|
||||
if (nswap == 0) {
|
||||
// This means there's no swap partition.
|
||||
return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
swdev = calloc(nswap, sizeof(*swdev));
|
||||
if (swdev == NULL) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (swapctl(SWAP_STATS, swdev, nswap) == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Total things up.
|
||||
swap_total = swap_free = 0;
|
||||
for (i = 0; i < nswap; i++) {
|
||||
if (swdev[i].se_flags & SWF_ENABLE) {
|
||||
swap_total += swdev[i].se_nblks * DEV_BSIZE;
|
||||
swap_free += (swdev[i].se_nblks - swdev[i].se_inuse) * DEV_BSIZE;
|
||||
}
|
||||
}
|
||||
free(swdev);
|
||||
|
||||
// Get swap in/out
|
||||
unsigned int total;
|
||||
size_t size = sizeof(total);
|
||||
struct uvmexp_sysctl uv;
|
||||
int mib[] = {CTL_VM, VM_UVMEXP2};
|
||||
long pagesize = getpagesize();
|
||||
size = sizeof(uv);
|
||||
if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return Py_BuildValue("(LLLll)",
|
||||
swap_total,
|
||||
(swap_total - swap_free),
|
||||
swap_free,
|
||||
(long) uv.pgswapin * pagesize, // swap in
|
||||
(long) uv.pgswapout * pagesize); // swap out
|
||||
|
||||
error:
|
||||
free(swdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
psutil_proc_num_fds(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
int cnt;
|
||||
|
||||
struct kinfo_file *freep;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
return NULL;
|
||||
|
||||
errno = 0;
|
||||
freep = kinfo_getfile(pid, &cnt);
|
||||
if (freep == NULL) {
|
||||
psutil_raise_for_pid(pid, "kinfo_getfile()");
|
||||
return NULL;
|
||||
}
|
||||
free(freep);
|
||||
|
||||
return Py_BuildValue("i", cnt);
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
psutil_per_cpu_times(PyObject *self, PyObject *args) {
|
||||
// XXX: why static?
|
||||
int mib[3];
|
||||
int ncpu;
|
||||
size_t len;
|
||||
size_t size;
|
||||
int i;
|
||||
PyObject *py_cputime = NULL;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
// retrieve the number of cpus
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_NCPU;
|
||||
len = sizeof(ncpu);
|
||||
if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
uint64_t cpu_time[CPUSTATES];
|
||||
|
||||
for (i = 0; i < ncpu; i++) {
|
||||
// per-cpu info
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_CP_TIME;
|
||||
mib[2] = i;
|
||||
size = sizeof(cpu_time);
|
||||
if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) {
|
||||
warn("failed to get kern.cptime2");
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
py_cputime = Py_BuildValue(
|
||||
"(ddddd)",
|
||||
(double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
|
||||
(double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
|
||||
(double)cpu_time[CP_SYS] / CLOCKS_PER_SEC,
|
||||
(double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC,
|
||||
(double)cpu_time[CP_INTR] / CLOCKS_PER_SEC);
|
||||
if (!py_cputime)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_cputime))
|
||||
goto error;
|
||||
Py_DECREF(py_cputime);
|
||||
}
|
||||
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_cputime);
|
||||
Py_DECREF(py_retlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
psutil_disk_io_counters(PyObject *self, PyObject *args) {
|
||||
int i, dk_ndrive, mib[3];
|
||||
size_t len;
|
||||
struct io_sysctl *stats = NULL;
|
||||
PyObject *py_disk_info = NULL;
|
||||
PyObject *py_retdict = PyDict_New();
|
||||
|
||||
if (py_retdict == NULL)
|
||||
return NULL;
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_IOSTATS;
|
||||
mib[2] = sizeof(struct io_sysctl);
|
||||
len = 0;
|
||||
if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0) {
|
||||
warn("can't get HW_IOSTATS");
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
dk_ndrive = (int)(len / sizeof(struct io_sysctl));
|
||||
|
||||
stats = malloc(len);
|
||||
if (stats == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
if (sysctl(mib, 3, stats, &len, NULL, 0) < 0 ) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < dk_ndrive; i++) {
|
||||
py_disk_info = Py_BuildValue(
|
||||
"(KKKK)",
|
||||
stats[i].rxfer,
|
||||
stats[i].wxfer,
|
||||
stats[i].rbytes,
|
||||
stats[i].wbytes
|
||||
);
|
||||
if (!py_disk_info)
|
||||
goto error;
|
||||
if (PyDict_SetItemString(py_retdict, stats[i].name, py_disk_info))
|
||||
goto error;
|
||||
Py_DECREF(py_disk_info);
|
||||
}
|
||||
|
||||
free(stats);
|
||||
return py_retdict;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_disk_info);
|
||||
Py_DECREF(py_retdict);
|
||||
if (stats != NULL)
|
||||
free(stats);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
psutil_cpu_stats(PyObject *self, PyObject *args) {
|
||||
size_t size;
|
||||
struct uvmexp_sysctl uv;
|
||||
int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2};
|
||||
|
||||
size = sizeof(uv);
|
||||
if (sysctl(uvmexp_mib, 2, &uv, &size, NULL, 0) < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Py_BuildValue(
|
||||
"IIIIIII",
|
||||
uv.swtch, // ctx switches
|
||||
uv.intrs, // interrupts - XXX always 0, will be determined via /proc
|
||||
uv.softs, // soft interrupts
|
||||
uv.syscalls, // syscalls - XXX always 0
|
||||
uv.traps, // traps
|
||||
uv.faults, // faults
|
||||
uv.forks // forks
|
||||
);
|
||||
}
|
||||
29
third_party/python/psutil/psutil/arch/netbsd/specific.h
vendored
Normal file
29
third_party/python/psutil/psutil/arch/netbsd/specific.h
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
|
||||
* All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
typedef struct kinfo_proc2 kinfo_proc;
|
||||
|
||||
int psutil_kinfo_proc(pid_t pid, kinfo_proc *proc);
|
||||
struct kinfo_file * kinfo_getfile(pid_t pid, int* cnt);
|
||||
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
|
||||
char *psutil_get_cmd_args(pid_t pid, size_t *argsize);
|
||||
|
||||
//
|
||||
PyObject *psutil_get_cmdline(pid_t pid);
|
||||
PyObject *psutil_proc_threads(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_virtual_mem(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_swap_mem(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_proc_connections(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args);
|
||||
PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
|
||||
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
|
||||
PyObject *psutil_proc_cwd(PyObject *self, PyObject *args);
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue