зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1620513 - Upgrade psutil to 5.7.0. r=rstewart
Differential Revision: https://phabricator.services.mozilla.com/D65685 --HG-- rename : third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/METADATA => third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/METADATA rename : third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/WHEEL => third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/WHEEL rename : third_party/python/psutil-cp27-none-win_amd64/psutil-5.4.3.dist-info/top_level.txt => third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/top_level.txt rename : third_party/python/psutil/psutil/tests/runner.py => third_party/python/psutil-cp27-none-win_amd64/psutil/tests/runner.py rename : third_party/python/psutil/psutil/arch/windows/wmi.h => third_party/python/psutil/psutil/arch/windows/net.h rename : third_party/python/psutil/psutil/arch/windows/wmi.h => third_party/python/psutil/psutil/arch/windows/socks.h rename : third_party/python/psutil/scripts/internal/download_exes.py => third_party/python/psutil/scripts/internal/win_download_wheels.py extra : moz-landing-system : lando
This commit is contained in:
Родитель
cae18cfff0
Коммит
f46e46f7fa
|
@ -1,472 +0,0 @@
|
|||
.. image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux%20/%20OSX
|
||||
:target: https://travis-ci.org/giampaolo/psutil
|
||||
:alt: Linux tests (Travis)
|
||||
|
||||
.. 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)
|
||||
|
||||
.. image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master
|
||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||
:alt: Test coverage (coverall.io)
|
||||
|
||||
.. image:: https://readthedocs.org/projects/psutil/badge/?version=latest
|
||||
:target: http://psutil.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
|
||||
:target: https://pypi.python.org/pypi/psutil/
|
||||
:alt: Latest version
|
||||
|
||||
.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/
|
||||
:alt: Github stars
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
||||
:target: https://pypi.python.org/pypi/psutil/
|
||||
:alt: License
|
||||
|
||||
===========
|
||||
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.python.org/pypi?:action=display&name=psutil#downloads>`_
|
||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
|
||||
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
|
||||
|
||||
=======
|
||||
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 UNIX command line tools such as:
|
||||
ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat,
|
||||
iotop, uptime, pidof, tty, taskset, pmap.
|
||||
psutil currently supports the following platforms:
|
||||
|
||||
- **Linux**
|
||||
- **Windows**
|
||||
- **OSX**,
|
||||
- **FreeBSD, OpenBSD**, **NetBSD**
|
||||
- **Sun Solaris**
|
||||
- **AIX**
|
||||
|
||||
...both **32-bit** and **64-bit** architectures, with Python
|
||||
versions from **2.6 to 3.6**.
|
||||
`PyPy <http://pypy.org/>`__ is also known to work.
|
||||
|
||||
====================
|
||||
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
|
||||
=====================
|
||||
|
||||
At the time of writing psutil has roughly
|
||||
`2.9 milion downloads <https://github.com/giampaolo/psutil/issues/1053#issuecomment-340166262>`__
|
||||
per month and there are over
|
||||
`6000 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/facebook/osquery/
|
||||
- https://github.com/nicolargo/glances
|
||||
- https://github.com/google/grr
|
||||
- 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
|
||||
- Node: https://github.com/christkv/node-psutil
|
||||
- Rust: https://github.com/borntyping/rust-psutil
|
||||
- Ruby: https://github.com/spacewander/posixpsutil
|
||||
- Nim: https://github.com/johnscillieri/psutil-nim
|
||||
|
||||
==============
|
||||
Example usages
|
||||
==============
|
||||
|
||||
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)
|
||||
>>>
|
||||
|
||||
Memory
|
||||
======
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> 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
|
||||
|
||||
>>> import psutil
|
||||
>>> 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
|
||||
|
||||
>>> import psutil
|
||||
>>> 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),
|
||||
sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED', pid=None),
|
||||
sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT', pid=None)
|
||||
...]
|
||||
>>>
|
||||
>>> psutil.net_if_addrs()
|
||||
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
|
||||
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
|
||||
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
|
||||
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
|
||||
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
|
||||
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
|
||||
>>>
|
||||
>>> psutil.net_if_stats()
|
||||
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
||||
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
||||
>>>
|
||||
|
||||
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),
|
||||
shwtemp(label='Core 1', current=52.0, high=100.0, critical=100.0),
|
||||
shwtemp(label='Core 2', current=45.0, high=100.0, critical=100.0),
|
||||
shwtemp(label='Core 3', current=47.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.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.parent()
|
||||
<psutil.Process(pid=7054, name='bash') at 140008329539408>
|
||||
>>> p.children()
|
||||
[<psutil.Process(pid=8031, name='python') at 14020832451977>,
|
||||
<psutil.Process(pid=8044, name='python') at 19229444921932>]
|
||||
>>>
|
||||
>>> 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)
|
||||
>>> 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, OSX, 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='/lib/x8664-linux-gnu/libcrypto.so.0.1', rss=34124, rss=32768, size=2134016, pss=15360, shared_clean=24576, shared_dirty=0, private_clean=0, private_dirty=8192, referenced=24576, anonymous=8192, 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/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
|
||||
popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
|
||||
>>>
|
||||
>>> 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'),
|
||||
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED'),
|
||||
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT')]
|
||||
>>>
|
||||
>>> p.num_threads()
|
||||
4
|
||||
>>> p.num_fds()
|
||||
8
|
||||
>>> p.threads()
|
||||
[pthread(id=5234, user_time=22.5, system_time=9.2891),
|
||||
pthread(id=5235, user_time=0.0, system_time=0.0),
|
||||
pthread(id=5236, user_time=0.0, system_time=0.0),
|
||||
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', 'COLORTERM': 'gnome-terminal',
|
||||
...}
|
||||
>>>
|
||||
>>> 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.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
|
||||
root 3 0.0 0.0 0 0 Jun17 00:05 ksoftirqd/0
|
||||
...
|
||||
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(attrs=['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'}
|
||||
|
||||
Other samples
|
||||
=============
|
||||
|
||||
See `doc recipes <http://psutil.readthedocs.io/#recipes>`__.
|
||||
|
||||
======
|
||||
Author
|
||||
======
|
||||
|
||||
psutil was created and is maintained by
|
||||
`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`__.
|
||||
A lot of time and effort went into making psutil as it is right now.
|
||||
If you feel psutil is useful to you or your business and want to support its
|
||||
future development please consider donating me
|
||||
(`Giampaolo <http://grodola.blogspot.com/p/about.html>`__) some money.
|
||||
|
||||
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
||||
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||
:alt: Donate via PayPal
|
||||
|
||||
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <https://www.linkedin.com/in/grodola>`_.
|
||||
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
psutil/__init__.py,sha256=220_B4k7vC9eoVP_OW8SFcaXCSBGpj_nacxvfBQ5O2o,84989
|
||||
psutil/_common.py,sha256=df5J2HqrWvGoFdumxDL1q9fgJOOYyiCmV0EFxb4ghuY,17852
|
||||
psutil/_compat.py,sha256=0VqlfcCGD5tZRBW-mFroguS0J7YNw6y3LjEcX5ChXDc,8170
|
||||
psutil/_exceptions.py,sha256=37eRgLuwTy7X4tjovePfZfYif-veW6LFeRlPqsgnNBU,3009
|
||||
psutil/_psaix.py,sha256=uAqwhQHS0upGc8OIk8Qa5PScCwXNvaMkoIdltZZ0n8A,19376
|
||||
psutil/_psbsd.py,sha256=ewmj2_DfzZpQZEcRvo1xvjVFhQqJidnENLgS8jrBb68,30244
|
||||
psutil/_pslinux.py,sha256=ME3wEgxfOWSFxgKXpTKbFw29ur1toMT4DdkKLJGkaD4,74850
|
||||
psutil/_psosx.py,sha256=X2WzhpuGjffjzFt3B3hphX7piPRCrPsjJrk6p6vu96w,17213
|
||||
psutil/_psposix.py,sha256=AmpZmKnvzCFcf7RpYypiUxOxKoRdXHRy2p9hFEIAJVc,6345
|
||||
psutil/_pssunos.py,sha256=uEsntvZPXplCuP9ER2W1QaGXjOqUZx_qFx2iLeyc5V8,25650
|
||||
psutil/_psutil_windows.pyd,sha256=wbQ_dSXTvdmCyQV02P7uCk95MwDkZ_D1g5r4G7IiYr8,59904
|
||||
psutil/_pswindows.py,sha256=_KYB-Vyhnz2A3l8I7tuXvFSrBPqKIb9slcwh5Azj0QU,33121
|
||||
psutil/tests/__init__.py,sha256=hkGHtLQNHjKrqhuV3Sk0kkHir17Mlam-amZBkLdfGwA,37656
|
||||
psutil/tests/__main__.py,sha256=dssAzXI-sAHkObtruDvc1cYUFNWOi-ZXETQgwaLKJS0,2784
|
||||
psutil/tests/test_aix.py,sha256=_ItFqb-CmYHlnlcduSKbgsPBw_xEIfE5v_pOr_YD8gw,4483
|
||||
psutil/tests/test_bsd.py,sha256=aif308A3TRnPZGY1tmNlH25YCweeSMpwbkah2K13wZs,17785
|
||||
psutil/tests/test_connections.py,sha256=eXOPOkusHO6Xc8gNrDxPBhq1Ni2fYYe0AAzeGU4gijQ,20676
|
||||
psutil/tests/test_contracts.py,sha256=ryPd7QDkQKxh8Mjcl-iPflXw5OTi8TWWLzQjIJ4EW2w,24136
|
||||
psutil/tests/test_linux.py,sha256=_gQBxUSiRSygoGfFXn-2m5XpXJQMQSiurVobrwkaAgc,78746
|
||||
psutil/tests/test_memory_leaks.py,sha256=v-RmU0BAzH05pkQ1dUV1hUXxlMva7943GFvT9Erl6J4,18259
|
||||
psutil/tests/test_misc.py,sha256=4qu61Sdmvzbaz2heOXKlg_PveYrzamBIUJ5QlLIYmSQ,37821
|
||||
psutil/tests/test_osx.py,sha256=UL3sovPp-5f0LIjNqjHu12NnpXF2uuv8Z62wbeAJj2c,9652
|
||||
psutil/tests/test_posix.py,sha256=4gm2VeCYoPYnstn_2GMG18c6xvMV7APXA26W5Dcm99s,16397
|
||||
psutil/tests/test_process.py,sha256=IE-v3DHKIje6Kwnas8kzfsbz15L4-0dpI555lXg7-NE,60495
|
||||
psutil/tests/test_sunos.py,sha256=UNywEx_qlSOyUHV48lMKqmnu8RKPBDCQrO0llulCUHY,1322
|
||||
psutil/tests/test_system.py,sha256=fv3otFKJVOn3VpRrD5IMivbI-hfajL6wmzVQF_JJqDI,34885
|
||||
psutil/tests/test_unicode.py,sha256=M0VTr_kGgmDKiNq6nSvraaw-711pRXe_6R948qHAr8I,12913
|
||||
psutil/tests/test_windows.py,sha256=AG2Feks59VOahEW_hJs_o4f5wt20vS1jxxaUCijcwAQ,32609
|
||||
psutil-5.4.3.dist-info/DESCRIPTION.rst,sha256=oATWrkVX56oC_b77TIXQsrm1CxSgD93PM71km6ud5G4,19853
|
||||
psutil-5.4.3.dist-info/METADATA,sha256=neLhT7NMfWptGzaSxueDDYqVDOR0C9cNvE8pAK14C2c,22835
|
||||
psutil-5.4.3.dist-info/RECORD,,
|
||||
psutil-5.4.3.dist-info/WHEEL,sha256=oT-jJdPOIfRdvpqTJO9X6OjCsyUImH2THoT54KREdwI,106
|
||||
psutil-5.4.3.dist-info/metadata.json,sha256=RqO1wxtF8F5B2HqYztzUkdKh5XmF8Wq_PxB9l571GM0,2492
|
||||
psutil-5.4.3.dist-info/top_level.txt,sha256=gCNhn57wzksDjSAISmgMJ0aiXzQulk0GJhb2-BAyYgw,7
|
|
@ -1 +0,0 @@
|
|||
{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Environment :: Win32 (MS Windows)", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows :: Windows NT/2000", "Operating System :: Microsoft", "Operating System :: OS Independent", "Operating System :: POSIX :: BSD :: FreeBSD", "Operating System :: POSIX :: BSD :: NetBSD", "Operating System :: POSIX :: BSD :: OpenBSD", "Operating System :: POSIX :: BSD", "Operating System :: POSIX :: Linux", "Operating System :: POSIX :: SunOS/Solaris", "Operating System :: POSIX", "Programming Language :: C", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Libraries", "Topic :: System :: Benchmark", "Topic :: System :: Hardware", "Topic :: System :: Monitoring", "Topic :: System :: Networking :: Monitoring", "Topic :: System :: Networking", "Topic :: System :: Operating System", "Topic :: System :: Systems Administration", "Topic :: Utilities"], "extensions": {"python.details": {"contacts": [{"email": "g.rodola@gmail.com", "name": "Giampaolo Rodola", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/giampaolo/psutil"}}}, "extras": ["enum"], "generator": "bdist_wheel (0.30.0)", "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"], "license": "BSD", "metadata_version": "2.0", "name": "psutil", "platform": "Platform Independent", "run_requires": [{"extra": "enum", "requires": ["enum34"]}], "summary": "Cross-platform lib for process and system monitoring in Python.", "test_requires": [{"requires": ["ipaddress", "mock"]}], "version": "5.4.3"}
|
29
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/LICENSE
поставляемый
Normal file
29
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/LICENSE
поставляемый
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.
|
|
@ -1,12 +1,12 @@
|
|||
Metadata-Version: 2.0
|
||||
Metadata-Version: 2.1
|
||||
Name: psutil
|
||||
Version: 5.4.3
|
||||
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
|
||||
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
|
||||
|
@ -16,9 +16,16 @@ 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 NT/2000
|
||||
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
|
||||
|
@ -31,67 +38,108 @@ 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 :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
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'
|
||||
|
||||
.. image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux%20/%20OSX
|
||||
| |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)
|
||||
|
||||
.. image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
|
||||
.. |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)
|
||||
|
||||
.. image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master
|
||||
.. |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)
|
||||
|
||||
.. image:: https://readthedocs.org/projects/psutil/badge/?version=latest
|
||||
.. |doc| image:: https://readthedocs.org/projects/psutil/badge/?version=latest
|
||||
:target: http://psutil.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
|
||||
:target: https://pypi.python.org/pypi/psutil/
|
||||
.. |version| image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
|
||||
:target: https://pypi.org/project/psutil
|
||||
:alt: Latest version
|
||||
|
||||
.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
|
||||
:target: https://github.com/giampaolo/psutil/
|
||||
:alt: Github stars
|
||||
.. |py-versions| image:: https://img.shields.io/pypi/pyversions/psutil.svg
|
||||
:target: https://pypi.org/project/psutil
|
||||
:alt: Supported Python versions
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
||||
:target: https://pypi.python.org/pypi/psutil/
|
||||
.. |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.python.org/pypi?:action=display&name=psutil#downloads>`_
|
||||
- `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/DEVGUIDE.rst>`_
|
||||
- `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
|
||||
=======
|
||||
|
||||
|
@ -100,23 +148,48 @@ 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 UNIX command line tools such as:
|
||||
ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat,
|
||||
iotop, uptime, pidof, tty, taskset, pmap.
|
||||
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**
|
||||
- **OSX**,
|
||||
- **macOS**
|
||||
- **FreeBSD, OpenBSD**, **NetBSD**
|
||||
- **Sun Solaris**
|
||||
- **AIX**
|
||||
|
||||
...both **32-bit** and **64-bit** architectures, with Python
|
||||
versions from **2.6 to 3.6**.
|
||||
`PyPy <http://pypy.org/>`__ is also known to work.
|
||||
...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
|
||||
====================
|
||||
|
||||
|
@ -131,45 +204,49 @@ Example applications
|
|||
Also see `scripts directory <https://github.com/giampaolo/psutil/tree/master/scripts>`__
|
||||
and `doc recipes <http://psutil.readthedocs.io/#recipes/>`__.
|
||||
|
||||
=====================
|
||||
Projects using psutil
|
||||
=====================
|
||||
|
||||
At the time of writing psutil has roughly
|
||||
`2.9 milion downloads <https://github.com/giampaolo/psutil/issues/1053#issuecomment-340166262>`__
|
||||
per month and there are over
|
||||
`6000 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
|
||||
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/google/grr
|
||||
- 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
|
||||
- Node: https://github.com/christkv/node-psutil
|
||||
- Rust: https://github.com/borntyping/rust-psutil
|
||||
- Ruby: https://github.com/spacewander/posixpsutil
|
||||
- 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)
|
||||
>>>
|
||||
|
@ -205,13 +282,14 @@ CPU
|
|||
>>> 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
|
||||
|
||||
>>> import psutil
|
||||
>>> 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()
|
||||
|
@ -219,11 +297,10 @@ Memory
|
|||
>>>
|
||||
|
||||
Disks
|
||||
=====
|
||||
-----
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.disk_partitions()
|
||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
||||
|
@ -236,11 +313,10 @@ Disks
|
|||
>>>
|
||||
|
||||
Network
|
||||
=======
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> 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)}
|
||||
|
@ -248,25 +324,23 @@ Network
|
|||
>>> 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),
|
||||
sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED', pid=None),
|
||||
sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT', pid=None)
|
||||
...]
|
||||
>>>
|
||||
>>> psutil.net_if_addrs()
|
||||
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
|
||||
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
|
||||
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
|
||||
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
|
||||
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
|
||||
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
|
||||
{'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()
|
||||
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
||||
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
||||
{'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
|
||||
|
||||
|
@ -275,10 +349,7 @@ Sensors
|
|||
{'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),
|
||||
shwtemp(label='Core 1', current=52.0, high=100.0, critical=100.0),
|
||||
shwtemp(label='Core 2', current=45.0, high=100.0, critical=100.0),
|
||||
shwtemp(label='Core 3', current=47.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)]}
|
||||
|
@ -288,7 +359,7 @@ Sensors
|
|||
>>>
|
||||
|
||||
Other system info
|
||||
=================
|
||||
-----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -302,7 +373,7 @@ Other system info
|
|||
>>>
|
||||
|
||||
Process management
|
||||
==================
|
||||
------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -314,6 +385,8 @@ Process management
|
|||
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()
|
||||
|
@ -327,11 +400,16 @@ Process management
|
|||
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=7054, name='bash') at 140008329539408>
|
||||
>>> p.children()
|
||||
[<psutil.Process(pid=8031, name='python') at 14020832451977>,
|
||||
<psutil.Process(pid=8044, name='python') at 19229444921932>]
|
||||
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'
|
||||
|
@ -348,7 +426,7 @@ Process management
|
|||
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)
|
||||
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()
|
||||
|
@ -359,14 +437,13 @@ Process management
|
|||
>>>
|
||||
>>> 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, OSX, Win only)
|
||||
>>> 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='/lib/x8664-linux-gnu/libcrypto.so.0.1', rss=34124, rss=32768, size=2134016, pss=15360, shared_clean=24576, shared_dirty=0, private_clean=0, private_dirty=8192, referenced=24576, anonymous=8192, 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),
|
||||
...]
|
||||
|
@ -375,14 +452,12 @@ Process management
|
|||
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/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
|
||||
popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
|
||||
[popenfile(path='/home/giampaolo/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'),
|
||||
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED'),
|
||||
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT')]
|
||||
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
|
||||
|
@ -390,8 +465,6 @@ Process management
|
|||
8
|
||||
>>> p.threads()
|
||||
[pthread(id=5234, user_time=22.5, system_time=9.2891),
|
||||
pthread(id=5235, user_time=0.0, system_time=0.0),
|
||||
pthread(id=5236, user_time=0.0, system_time=0.0),
|
||||
pthread(id=5237, user_time=0.0707, system_time=1.1)]
|
||||
>>>
|
||||
>>> p.num_ctx_switches()
|
||||
|
@ -411,7 +484,7 @@ Process management
|
|||
>>>
|
||||
>>> 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', 'COLORTERM': 'gnome-terminal',
|
||||
'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg',
|
||||
...}
|
||||
>>>
|
||||
>>> p.as_dict()
|
||||
|
@ -422,6 +495,7 @@ Process management
|
|||
>>> p.resume()
|
||||
>>>
|
||||
>>> p.terminate()
|
||||
>>> p.kill()
|
||||
>>> p.wait(timeout=3)
|
||||
0
|
||||
>>>
|
||||
|
@ -429,7 +503,6 @@ Process management
|
|||
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
|
||||
root 3 0.0 0.0 0 0 Jun17 00:05 ksoftirqd/0
|
||||
...
|
||||
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
|
||||
|
@ -437,12 +510,12 @@ Process management
|
|||
>>>
|
||||
|
||||
Further process APIs
|
||||
====================
|
||||
--------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> for proc in psutil.process_iter(attrs=['pid', 'name']):
|
||||
>>> for proc in psutil.process_iter(['pid', 'name']):
|
||||
... print(proc.info)
|
||||
...
|
||||
{'pid': 1, 'name': 'systemd'}
|
||||
|
@ -478,7 +551,7 @@ Popen wrapper:
|
|||
>>>
|
||||
|
||||
Windows services
|
||||
================
|
||||
----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -499,26 +572,11 @@ Windows services
|
|||
'status': 'stopped',
|
||||
'username': 'NT AUTHORITY\\LocalService'}
|
||||
|
||||
Other samples
|
||||
=============
|
||||
|
||||
See `doc recipes <http://psutil.readthedocs.io/#recipes>`__.
|
||||
|
||||
======
|
||||
Author
|
||||
======
|
||||
|
||||
psutil was created and is maintained by
|
||||
`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`__.
|
||||
A lot of time and effort went into making psutil as it is right now.
|
||||
If you feel psutil is useful to you or your business and want to support its
|
||||
future development please consider donating me
|
||||
(`Giampaolo <http://grodola.blogspot.com/p/about.html>`__) some money.
|
||||
|
||||
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
||||
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||
:alt: Donate via PayPal
|
||||
|
||||
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <https://www.linkedin.com/in/grodola>`_.
|
||||
.. _`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
поставляемый
Normal file
33
third_party/python/psutil-cp27-none-win_amd64/psutil-5.7.0.dist-info/RECORD
поставляемый
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,,
|
|
@ -1,5 +1,5 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.30.0)
|
||||
Generator: bdist_wheel (0.34.2)
|
||||
Root-Is-Purelib: false
|
||||
Tag: cp27-cp27m-win_amd64
|
||||
|
|
@ -10,14 +10,14 @@ sensors) in Python. Supported platforms:
|
|||
|
||||
- Linux
|
||||
- Windows
|
||||
- OSX
|
||||
- macOS
|
||||
- FreeBSD
|
||||
- OpenBSD
|
||||
- NetBSD
|
||||
- Sun Solaris
|
||||
- AIX
|
||||
|
||||
Works with Python versions from 2.6 to 3.X.
|
||||
Works with Python versions from 2.6 to 3.4+.
|
||||
"""
|
||||
|
||||
from __future__ import division
|
||||
|
@ -25,37 +25,43 @@ from __future__ import division
|
|||
import collections
|
||||
import contextlib
|
||||
import datetime
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
try:
|
||||
import pwd
|
||||
except ImportError:
|
||||
pwd = None
|
||||
|
||||
from . import _common
|
||||
from ._common import AccessDenied
|
||||
from ._common import deprecated_method
|
||||
from ._common import Error
|
||||
from ._common import memoize
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import TimeoutExpired
|
||||
from ._common import wrap_numbers as _wrap_numbers
|
||||
from ._compat import callable
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import long
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3 as _PY3
|
||||
|
||||
from ._common import STATUS_DEAD
|
||||
from ._common import STATUS_DISK_SLEEP
|
||||
from ._common import STATUS_IDLE # bsd
|
||||
from ._common import STATUS_IDLE
|
||||
from ._common import STATUS_LOCKED
|
||||
from ._common import STATUS_PARKED
|
||||
from ._common import STATUS_RUNNING
|
||||
from ._common import STATUS_SLEEPING
|
||||
from ._common import STATUS_STOPPED
|
||||
from ._common import STATUS_TRACING_STOP
|
||||
from ._common import STATUS_WAITING # bsd
|
||||
from ._common import STATUS_WAITING
|
||||
from ._common import STATUS_WAKING
|
||||
from ._common import STATUS_ZOMBIE
|
||||
|
||||
|
@ -79,19 +85,14 @@ from ._common import AIX
|
|||
from ._common import BSD
|
||||
from ._common import FREEBSD # NOQA
|
||||
from ._common import LINUX
|
||||
from ._common import MACOS
|
||||
from ._common import NETBSD # NOQA
|
||||
from ._common import OPENBSD # NOQA
|
||||
from ._common import OSX
|
||||
from ._common import OSX # deprecated alias
|
||||
from ._common import POSIX # NOQA
|
||||
from ._common import SUNOS
|
||||
from ._common import WINDOWS
|
||||
|
||||
from ._exceptions import AccessDenied
|
||||
from ._exceptions import Error
|
||||
from ._exceptions import NoSuchProcess
|
||||
from ._exceptions import TimeoutExpired
|
||||
from ._exceptions import ZombieProcess
|
||||
|
||||
if LINUX:
|
||||
# This is public API and it will be retrieved from _pslinux.py
|
||||
# via sys.modules.
|
||||
|
@ -151,8 +152,12 @@ elif WINDOWS:
|
|||
from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA
|
||||
from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA
|
||||
from ._pswindows import CONN_DELETE_TCB # NOQA
|
||||
from ._pswindows import IOPRIO_VERYLOW # NOQA
|
||||
from ._pswindows import IOPRIO_LOW # NOQA
|
||||
from ._pswindows import IOPRIO_NORMAL # NOQA
|
||||
from ._pswindows import IOPRIO_HIGH # NOQA
|
||||
|
||||
elif OSX:
|
||||
elif MACOS:
|
||||
from . import _psosx as _psplatform
|
||||
|
||||
elif BSD:
|
||||
|
@ -189,6 +194,7 @@ __all__ = [
|
|||
"STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
|
||||
"STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
|
||||
"STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED",
|
||||
"STATUS_PARKED",
|
||||
|
||||
"CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1",
|
||||
"CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT",
|
||||
|
@ -200,8 +206,8 @@ __all__ = [
|
|||
|
||||
"POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED",
|
||||
|
||||
"BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "OSX", "POSIX", "SUNOS",
|
||||
"WINDOWS", "AIX",
|
||||
"BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "MACOS", "OSX", "POSIX",
|
||||
"SUNOS", "WINDOWS", "AIX",
|
||||
|
||||
# classes
|
||||
"Process", "Popen",
|
||||
|
@ -210,23 +216,26 @@ __all__ = [
|
|||
"pid_exists", "pids", "process_iter", "wait_procs", # proc
|
||||
"virtual_memory", "swap_memory", # memory
|
||||
"cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu
|
||||
"cpu_stats", # "cpu_freq",
|
||||
"cpu_stats", # "cpu_freq", "getloadavg"
|
||||
"net_io_counters", "net_connections", "net_if_addrs", # network
|
||||
"net_if_stats",
|
||||
"disk_io_counters", "disk_partitions", "disk_usage", # disk
|
||||
# "sensors_temperatures", "sensors_battery", "sensors_fans" # sensors
|
||||
"users", "boot_time", # others
|
||||
]
|
||||
|
||||
|
||||
__all__.extend(_psplatform.__extra__all__)
|
||||
__author__ = "Giampaolo Rodola'"
|
||||
__version__ = "5.4.3"
|
||||
__version__ = "5.7.0"
|
||||
version_info = tuple([int(num) for num in __version__.split('.')])
|
||||
|
||||
_timer = getattr(time, 'monotonic', time.time)
|
||||
AF_LINK = _psplatform.AF_LINK
|
||||
POWER_TIME_UNLIMITED = _common.POWER_TIME_UNLIMITED
|
||||
POWER_TIME_UNKNOWN = _common.POWER_TIME_UNKNOWN
|
||||
_TOTAL_PHYMEM = None
|
||||
_timer = getattr(time, 'monotonic', time.time)
|
||||
|
||||
_LOWEST_PID = None
|
||||
|
||||
# Sanity check in case the user messed up with psutil installation
|
||||
# or did something weird with sys.path. In this case we might end
|
||||
|
@ -266,13 +275,9 @@ else:
|
|||
ret = {}
|
||||
for pid in pids():
|
||||
try:
|
||||
proc = _psplatform.Process(pid)
|
||||
ppid = proc.ppid()
|
||||
except (NoSuchProcess, AccessDenied):
|
||||
# Note: AccessDenied is unlikely to happen.
|
||||
ret[pid] = _psplatform.Process(pid).ppid()
|
||||
except (NoSuchProcess, ZombieProcess):
|
||||
pass
|
||||
else:
|
||||
ret[pid] = ppid
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -355,7 +360,7 @@ class Process(object):
|
|||
self._create_time = None
|
||||
self._gone = False
|
||||
self._hash = None
|
||||
self._oneshot_inctx = False
|
||||
self._lock = threading.RLock()
|
||||
# used for caching on Windows only (on POSIX ppid may change)
|
||||
self._ppid = None
|
||||
# platform-specific modules define an _psplatform.Process
|
||||
|
@ -459,9 +464,16 @@ class Process(object):
|
|||
...
|
||||
>>>
|
||||
"""
|
||||
if self._oneshot_inctx:
|
||||
with self._lock:
|
||||
if hasattr(self, "_cache"):
|
||||
# NOOP: this covers the use case where the user enters the
|
||||
# context twice. Since as_dict() internally uses oneshot()
|
||||
# context twice:
|
||||
#
|
||||
# >>> with p.oneshot():
|
||||
# ... with p.oneshot():
|
||||
# ...
|
||||
#
|
||||
# Also, since as_dict() internally uses oneshot()
|
||||
# I expect that the code below will be a pretty common
|
||||
# "mistake" that the user will make, so let's guard
|
||||
# against that:
|
||||
|
@ -471,28 +483,26 @@ class Process(object):
|
|||
# ...
|
||||
yield
|
||||
else:
|
||||
self._oneshot_inctx = True
|
||||
try:
|
||||
# cached in case cpu_percent() is used
|
||||
self.cpu_times.cache_activate()
|
||||
self.cpu_times.cache_activate(self)
|
||||
# cached in case memory_percent() is used
|
||||
self.memory_info.cache_activate()
|
||||
self.memory_info.cache_activate(self)
|
||||
# cached in case parent() is used
|
||||
self.ppid.cache_activate()
|
||||
self.ppid.cache_activate(self)
|
||||
# cached in case username() is used
|
||||
if POSIX:
|
||||
self.uids.cache_activate()
|
||||
self.uids.cache_activate(self)
|
||||
# specific implementation cache
|
||||
self._proc.oneshot_enter()
|
||||
yield
|
||||
finally:
|
||||
self.cpu_times.cache_deactivate()
|
||||
self.memory_info.cache_deactivate()
|
||||
self.ppid.cache_deactivate()
|
||||
self.cpu_times.cache_deactivate(self)
|
||||
self.memory_info.cache_deactivate(self)
|
||||
self.ppid.cache_deactivate(self)
|
||||
if POSIX:
|
||||
self.uids.cache_deactivate()
|
||||
self.uids.cache_deactivate(self)
|
||||
self._proc.oneshot_exit()
|
||||
self._oneshot_inctx = False
|
||||
|
||||
def as_dict(self, attrs=None, ad_value=None):
|
||||
"""Utility method returning process information as a
|
||||
|
@ -543,6 +553,9 @@ class Process(object):
|
|||
checking whether PID has been reused.
|
||||
If no parent is known return None.
|
||||
"""
|
||||
lowest_pid = _LOWEST_PID if _LOWEST_PID is not None else pids()[0]
|
||||
if self.pid == lowest_pid:
|
||||
return None
|
||||
ppid = self.ppid()
|
||||
if ppid is not None:
|
||||
ctime = self.create_time()
|
||||
|
@ -554,6 +567,17 @@ class Process(object):
|
|||
except NoSuchProcess:
|
||||
pass
|
||||
|
||||
def parents(self):
|
||||
"""Return the parents of this process as a list of Process
|
||||
instances. If no parents are known return an empty list.
|
||||
"""
|
||||
parents = []
|
||||
proc = self.parent()
|
||||
while proc is not None:
|
||||
parents.append(proc)
|
||||
proc = proc.parent()
|
||||
return parents
|
||||
|
||||
def is_running(self):
|
||||
"""Return whether this process is running.
|
||||
It also checks if PID has been reused by another process in
|
||||
|
@ -751,7 +775,7 @@ class Process(object):
|
|||
"""
|
||||
return self._proc.io_counters()
|
||||
|
||||
# Linux and Windows >= Vista only
|
||||
# Linux and Windows
|
||||
if hasattr(_psplatform.Process, "ionice_get"):
|
||||
|
||||
def ionice(self, ioclass=None, value=None):
|
||||
|
@ -802,9 +826,6 @@ class Process(object):
|
|||
(and set).
|
||||
(Windows, Linux and BSD only).
|
||||
"""
|
||||
# Automatically remove duplicates both on get and
|
||||
# set (for get it's not really necessary, it's
|
||||
# just for extra safety).
|
||||
if cpus is None:
|
||||
return list(set(self._proc.cpu_affinity_get()))
|
||||
else:
|
||||
|
@ -828,7 +849,7 @@ class Process(object):
|
|||
"""
|
||||
return self._proc.cpu_num()
|
||||
|
||||
# Linux, OSX and Windows only
|
||||
# Linux, macOS, Windows, Solaris, AIX
|
||||
if hasattr(_psplatform.Process, "environ"):
|
||||
|
||||
def environ(self):
|
||||
|
@ -1032,7 +1053,7 @@ class Process(object):
|
|||
namedtuple representing the accumulated process time, in
|
||||
seconds.
|
||||
This is similar to os.times() but per-process.
|
||||
On OSX and Windows children_user and children_system are
|
||||
On macOS and Windows children_user and children_system are
|
||||
always set to 0.
|
||||
"""
|
||||
return self._proc.cpu_times()
|
||||
|
@ -1054,7 +1075,7 @@ class Process(object):
|
|||
|
||||
def memory_full_info(self):
|
||||
"""This method returns the same information as memory_info(),
|
||||
plus, on some platform (Linux, OSX, Windows), also provides
|
||||
plus, on some platform (Linux, macOS, Windows), also provides
|
||||
additional metrics (USS, PSS and swap).
|
||||
The additional metrics provide a better representation of actual
|
||||
process memory usage.
|
||||
|
@ -1098,7 +1119,6 @@ class Process(object):
|
|||
return (value / float(total_phymem)) * 100
|
||||
|
||||
if hasattr(_psplatform.Process, "memory_maps"):
|
||||
# Available everywhere except OpenBSD and NetBSD.
|
||||
def memory_maps(self, grouped=True):
|
||||
"""Return process' mapped memory regions as a list of namedtuples
|
||||
whose fields are variable depending on the platform.
|
||||
|
@ -1170,8 +1190,7 @@ class Process(object):
|
|||
"calling process (os.getpid()) instead of PID 0")
|
||||
try:
|
||||
os.kill(self.pid, sig)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ESRCH:
|
||||
except ProcessLookupError:
|
||||
if OPENBSD and pid_exists(self.pid):
|
||||
# We do this because os.kill() lies in case of
|
||||
# zombie processes.
|
||||
|
@ -1179,9 +1198,8 @@ class Process(object):
|
|||
else:
|
||||
self._gone = True
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
|
||||
@_assert_pid_not_reused
|
||||
def send_signal(self, sig):
|
||||
|
@ -1193,16 +1211,7 @@ class Process(object):
|
|||
if POSIX:
|
||||
self._send_signal(sig)
|
||||
else: # pragma: no cover
|
||||
if sig == signal.SIGTERM:
|
||||
self._proc.kill()
|
||||
# py >= 2.7
|
||||
elif sig in (getattr(signal, "CTRL_C_EVENT", object()),
|
||||
getattr(signal, "CTRL_BREAK_EVENT", object())):
|
||||
self._proc.send_signal(sig)
|
||||
else:
|
||||
raise ValueError(
|
||||
"only SIGTERM, CTRL_C_EVENT and CTRL_BREAK_EVENT signals "
|
||||
"are supported on Windows")
|
||||
|
||||
@_assert_pid_not_reused
|
||||
def suspend(self):
|
||||
|
@ -1250,6 +1259,8 @@ class Process(object):
|
|||
def wait(self, timeout=None):
|
||||
"""Wait for process to terminate and, if process is a children
|
||||
of os.getpid(), also return its exit code, else None.
|
||||
On Windows there's no such limitation (exit code is always
|
||||
returned).
|
||||
|
||||
If the process is already terminated immediately return None
|
||||
instead of raising NoSuchProcess.
|
||||
|
@ -1301,7 +1312,7 @@ class Popen(Process):
|
|||
http://bugs.python.org/issue6973.
|
||||
|
||||
For a complete documentation refer to:
|
||||
http://docs.python.org/library/subprocess.html
|
||||
http://docs.python.org/3/library/subprocess.html
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -1357,7 +1368,7 @@ class Popen(Process):
|
|||
_as_dict_attrnames = set(
|
||||
[x for x in dir(Process) if not x.startswith('_') and x not in
|
||||
['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
|
||||
'is_running', 'as_dict', 'parent', 'children', 'rlimit',
|
||||
'is_running', 'as_dict', 'parent', 'parents', 'children', 'rlimit',
|
||||
'memory_info_ex', 'oneshot']])
|
||||
|
||||
|
||||
|
@ -1368,7 +1379,10 @@ _as_dict_attrnames = set(
|
|||
|
||||
def pids():
|
||||
"""Return a list of current running PIDs."""
|
||||
return _psplatform.pids()
|
||||
global _LOWEST_PID
|
||||
ret = sorted(_psplatform.pids())
|
||||
_LOWEST_PID = ret[0]
|
||||
return ret
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
|
@ -1390,6 +1404,7 @@ def pid_exists(pid):
|
|||
|
||||
|
||||
_pmap = {}
|
||||
_lock = threading.Lock()
|
||||
|
||||
|
||||
def process_iter(attrs=None, ad_value=None):
|
||||
|
@ -1417,21 +1432,26 @@ def process_iter(attrs=None, ad_value=None):
|
|||
proc = Process(pid)
|
||||
if attrs is not None:
|
||||
proc.info = proc.as_dict(attrs=attrs, ad_value=ad_value)
|
||||
with _lock:
|
||||
_pmap[proc.pid] = proc
|
||||
return proc
|
||||
|
||||
def remove(pid):
|
||||
with _lock:
|
||||
_pmap.pop(pid, None)
|
||||
|
||||
a = set(pids())
|
||||
b = set(_pmap.keys())
|
||||
new_pids = a - b
|
||||
gone_pids = b - a
|
||||
|
||||
for pid in gone_pids:
|
||||
remove(pid)
|
||||
for pid, proc in sorted(list(_pmap.items()) +
|
||||
list(dict.fromkeys(new_pids).items())):
|
||||
|
||||
with _lock:
|
||||
ls = sorted(list(_pmap.items()) +
|
||||
list(dict.fromkeys(new_pids).items()))
|
||||
|
||||
for pid, proc in ls:
|
||||
try:
|
||||
if proc is None: # new process
|
||||
yield add(pid)
|
||||
|
@ -1505,6 +1525,7 @@ def wait_procs(procs, timeout=None, callback=None):
|
|||
pass
|
||||
else:
|
||||
if returncode is not None or not proc.is_running():
|
||||
# Set new Process instance attribute.
|
||||
proc.returncode = returncode
|
||||
gone.add(proc)
|
||||
if callback is not None:
|
||||
|
@ -1611,14 +1632,12 @@ try:
|
|||
except Exception:
|
||||
# Don't want to crash at import time.
|
||||
_last_cpu_times = None
|
||||
traceback.print_exc()
|
||||
|
||||
try:
|
||||
_last_per_cpu_times = cpu_times(percpu=True)
|
||||
except Exception:
|
||||
# Don't want to crash at import time.
|
||||
_last_per_cpu_times = None
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
def _cpu_tot_time(times):
|
||||
|
@ -1656,6 +1675,27 @@ def _cpu_busy_time(times):
|
|||
return busy
|
||||
|
||||
|
||||
def _cpu_times_deltas(t1, t2):
|
||||
assert t1._fields == t2._fields, (t1, t2)
|
||||
field_deltas = []
|
||||
for field in _psplatform.scputimes._fields:
|
||||
field_delta = getattr(t2, field) - getattr(t1, field)
|
||||
# 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
|
||||
# https://github.com/giampaolo/psutil/issues/1210
|
||||
# Trim negative deltas to zero to ignore decreasing fields.
|
||||
# top does the same. Reference:
|
||||
# https://gitlab.com/procps-ng/procps/blob/v3.3.12/top/top.c#L5063
|
||||
field_delta = max(0, field_delta)
|
||||
field_deltas.append(field_delta)
|
||||
return _psplatform.scputimes(*field_deltas)
|
||||
|
||||
|
||||
def cpu_percent(interval=None, percpu=False):
|
||||
"""Return a float representing the current system-wide CPU
|
||||
utilization as a percentage.
|
||||
|
@ -1698,18 +1738,11 @@ def cpu_percent(interval=None, percpu=False):
|
|||
raise ValueError("interval is not positive (got %r)" % interval)
|
||||
|
||||
def calculate(t1, t2):
|
||||
t1_all = _cpu_tot_time(t1)
|
||||
t1_busy = _cpu_busy_time(t1)
|
||||
times_delta = _cpu_times_deltas(t1, t2)
|
||||
|
||||
t2_all = _cpu_tot_time(t2)
|
||||
t2_busy = _cpu_busy_time(t2)
|
||||
all_delta = _cpu_tot_time(times_delta)
|
||||
busy_delta = _cpu_busy_time(times_delta)
|
||||
|
||||
# this usually indicates a float precision issue
|
||||
if t2_busy <= t1_busy:
|
||||
return 0.0
|
||||
|
||||
busy_delta = t2_busy - t1_busy
|
||||
all_delta = t2_all - t1_all
|
||||
try:
|
||||
busy_perc = (busy_delta / all_delta) * 100
|
||||
except ZeroDivisionError:
|
||||
|
@ -1778,28 +1811,18 @@ def cpu_times_percent(interval=None, percpu=False):
|
|||
|
||||
def calculate(t1, t2):
|
||||
nums = []
|
||||
all_delta = _cpu_tot_time(t2) - _cpu_tot_time(t1)
|
||||
for field in t1._fields:
|
||||
field_delta = getattr(t2, field) - getattr(t1, field)
|
||||
try:
|
||||
field_perc = (100 * field_delta) / all_delta
|
||||
except ZeroDivisionError:
|
||||
field_perc = 0.0
|
||||
times_delta = _cpu_times_deltas(t1, t2)
|
||||
all_delta = _cpu_tot_time(times_delta)
|
||||
# "scale" is the value to multiply each delta with to get percentages.
|
||||
# We use "max" to avoid division by zero (if all_delta is 0, then all
|
||||
# fields are 0 so percentages will be 0 too. all_delta cannot be a
|
||||
# fraction because cpu times are integers)
|
||||
scale = 100.0 / max(1, all_delta)
|
||||
for field_delta in times_delta:
|
||||
field_perc = field_delta * scale
|
||||
field_perc = round(field_perc, 1)
|
||||
# CPU times are always supposed to increase over time
|
||||
# or at least remain the same and that's because time
|
||||
# cannot go backwards.
|
||||
# Surprisingly sometimes this might not be the case (at
|
||||
# least on Windows and Linux), see:
|
||||
# https://github.com/giampaolo/psutil/issues/392
|
||||
# https://github.com/giampaolo/psutil/issues/645
|
||||
# I really don't know what to do about that except
|
||||
# forcing the value to 0 or 100.
|
||||
if field_perc > 100.0:
|
||||
field_perc = 100.0
|
||||
# `<=` because `-0.0 == 0.0` evaluates to True
|
||||
elif field_perc <= 0.0:
|
||||
field_perc = 0.0
|
||||
# make sure we don't return negative values or values over 100%
|
||||
field_perc = min(max(0.0, field_perc), 100.0)
|
||||
nums.append(field_perc)
|
||||
return _psplatform.scputimes(*nums)
|
||||
|
||||
|
@ -1862,18 +1885,41 @@ if hasattr(_psplatform, "cpu_freq"):
|
|||
return ret[0]
|
||||
else:
|
||||
currs, mins, maxs = 0.0, 0.0, 0.0
|
||||
set_none = False
|
||||
for cpu in ret:
|
||||
currs += cpu.current
|
||||
# On Linux if /proc/cpuinfo is used min/max are set
|
||||
# to None.
|
||||
if LINUX and cpu.min is None:
|
||||
set_none = True
|
||||
continue
|
||||
mins += cpu.min
|
||||
maxs += cpu.max
|
||||
|
||||
current = currs / num_cpus
|
||||
|
||||
if set_none:
|
||||
min_ = max_ = None
|
||||
else:
|
||||
min_ = mins / num_cpus
|
||||
max_ = maxs / num_cpus
|
||||
|
||||
return _common.scpufreq(current, min_, max_)
|
||||
|
||||
__all__.append("cpu_freq")
|
||||
|
||||
|
||||
if hasattr(os, "getloadavg") or hasattr(_psplatform, "getloadavg"):
|
||||
# Perform this hasattr check once on import time to either use the
|
||||
# platform based code or proxy straight from the os module.
|
||||
if hasattr(os, "getloadavg"):
|
||||
getloadavg = os.getloadavg
|
||||
else:
|
||||
getloadavg = _psplatform.getloadavg
|
||||
|
||||
__all__.append("getloadavg")
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- system memory related functions
|
||||
# =====================================================================
|
||||
|
@ -1899,9 +1945,9 @@ def virtual_memory():
|
|||
- used:
|
||||
memory used, calculated differently depending on the platform and
|
||||
designed for informational purposes only:
|
||||
OSX: active + inactive + wired
|
||||
macOS: active + wired
|
||||
BSD: active + wired + cached
|
||||
LINUX: total - free
|
||||
Linux: total - free
|
||||
|
||||
- free:
|
||||
memory not being used at all (zeroed) that is readily available;
|
||||
|
@ -1919,10 +1965,10 @@ def virtual_memory():
|
|||
- buffers (BSD, Linux):
|
||||
cache for things like file system metadata.
|
||||
|
||||
- cached (BSD, OSX):
|
||||
- cached (BSD, macOS):
|
||||
cache for various things.
|
||||
|
||||
- wired (OSX, BSD):
|
||||
- wired (macOS, BSD):
|
||||
memory that is marked to always stay in RAM. It is never moved to disk.
|
||||
|
||||
- shared (BSD):
|
||||
|
@ -2011,7 +2057,8 @@ def disk_io_counters(perdisk=False, nowrap=True):
|
|||
On recent Windows versions 'diskperf -y' command may need to be
|
||||
executed first otherwise this function won't find any disk.
|
||||
"""
|
||||
rawdict = _psplatform.disk_io_counters()
|
||||
kwargs = dict(perdisk=perdisk) if LINUX else {}
|
||||
rawdict = _psplatform.disk_io_counters(**kwargs)
|
||||
if not rawdict:
|
||||
return {} if perdisk else None
|
||||
if nowrap:
|
||||
|
@ -2047,7 +2094,7 @@ def net_io_counters(pernic=False, nowrap=True):
|
|||
- errout: total number of errors while sending
|
||||
- dropin: total number of incoming packets which were dropped
|
||||
- dropout: total number of outgoing packets which were dropped
|
||||
(always 0 on OSX and BSD)
|
||||
(always 0 on macOS and BSD)
|
||||
|
||||
If *pernic* is True return the same information for every
|
||||
network interface installed on the system as a dictionary
|
||||
|
@ -2103,7 +2150,7 @@ def net_connections(kind='inet'):
|
|||
| all | the sum of all the possible families and protocols |
|
||||
+------------+----------------------------------------------------+
|
||||
|
||||
On OSX this function requires root privileges.
|
||||
On macOS this function requires root privileges.
|
||||
"""
|
||||
return _psplatform.net_connections(kind)
|
||||
|
||||
|
@ -2152,7 +2199,7 @@ def net_if_addrs():
|
|||
separator = ":" if POSIX else "-"
|
||||
while addr.count(separator) < 5:
|
||||
addr += "%s00" % separator
|
||||
ret[name].append(_common.snic(fam, addr, mask, broadcast, ptp))
|
||||
ret[name].append(_common.snicaddr(fam, addr, mask, broadcast, ptp))
|
||||
return dict(ret)
|
||||
|
||||
|
||||
|
@ -2176,7 +2223,7 @@ def net_if_stats():
|
|||
# =====================================================================
|
||||
|
||||
|
||||
# Linux
|
||||
# Linux, macOS
|
||||
if hasattr(_psplatform, "sensors_temperatures"):
|
||||
|
||||
def sensors_temperatures(fahrenheit=False):
|
||||
|
@ -2214,7 +2261,7 @@ if hasattr(_psplatform, "sensors_temperatures"):
|
|||
__all__.append("sensors_temperatures")
|
||||
|
||||
|
||||
# Linux
|
||||
# Linux, macOS
|
||||
if hasattr(_psplatform, "sensors_fans"):
|
||||
|
||||
def sensors_fans():
|
||||
|
@ -2227,7 +2274,7 @@ if hasattr(_psplatform, "sensors_fans"):
|
|||
__all__.append("sensors_fans")
|
||||
|
||||
|
||||
# Linux, Windows, FreeBSD, OSX
|
||||
# Linux, Windows, FreeBSD, macOS
|
||||
if hasattr(_psplatform, "sensors_battery"):
|
||||
|
||||
def sensors_battery():
|
||||
|
@ -2294,19 +2341,16 @@ if WINDOWS:
|
|||
|
||||
|
||||
def test(): # pragma: no cover
|
||||
"""List info of all currently running processes emulating ps aux
|
||||
output.
|
||||
"""
|
||||
from ._common import bytes2human
|
||||
from ._compat import get_terminal_size
|
||||
|
||||
today_day = datetime.date.today()
|
||||
templ = "%-10s %5s %4s %7s %7s %-13s %5s %7s %s"
|
||||
attrs = ['pid', 'memory_percent', 'name', 'cpu_times', 'create_time',
|
||||
'memory_info']
|
||||
if POSIX:
|
||||
attrs.append('uids')
|
||||
attrs.append('terminal')
|
||||
print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "TTY", "START", "TIME",
|
||||
"COMMAND"))
|
||||
for p in process_iter(attrs=attrs, ad_value=''):
|
||||
templ = "%-10s %5s %5s %7s %7s %5s %6s %6s %6s %s"
|
||||
attrs = ['pid', 'memory_percent', 'name', 'cmdline', 'cpu_times',
|
||||
'create_time', 'memory_info', 'status', 'nice', 'username']
|
||||
print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "NICE",
|
||||
"STATUS", "START", "TIME", "CMDLINE"))
|
||||
for p in process_iter(attrs, ad_value=None):
|
||||
if p.info['create_time']:
|
||||
ctime = datetime.datetime.fromtimestamp(p.info['create_time'])
|
||||
if ctime.date() == today_day:
|
||||
|
@ -2315,30 +2359,46 @@ def test(): # pragma: no cover
|
|||
ctime = ctime.strftime("%b%d")
|
||||
else:
|
||||
ctime = ''
|
||||
if p.info['cpu_times']:
|
||||
cputime = time.strftime("%M:%S",
|
||||
time.localtime(sum(p.info['cpu_times'])))
|
||||
else:
|
||||
cputime = ''
|
||||
|
||||
user = p.info['username'] or ''
|
||||
if not user and POSIX:
|
||||
try:
|
||||
user = p.username()
|
||||
user = p.uids()[0]
|
||||
except Error:
|
||||
user = ''
|
||||
if WINDOWS and '\\' in user:
|
||||
pass
|
||||
if user and WINDOWS and '\\' in user:
|
||||
user = user.split('\\')[1]
|
||||
vms = p.info['memory_info'] and \
|
||||
int(p.info['memory_info'].vms / 1024) or '?'
|
||||
rss = p.info['memory_info'] and \
|
||||
int(p.info['memory_info'].rss / 1024) or '?'
|
||||
memp = p.info['memory_percent'] and \
|
||||
round(p.info['memory_percent'], 1) or '?'
|
||||
print(templ % (
|
||||
user = user[:9]
|
||||
vms = bytes2human(p.info['memory_info'].vms) if \
|
||||
p.info['memory_info'] is not None else ''
|
||||
rss = bytes2human(p.info['memory_info'].rss) if \
|
||||
p.info['memory_info'] is not None else ''
|
||||
memp = round(p.info['memory_percent'], 1) if \
|
||||
p.info['memory_percent'] is not None else ''
|
||||
nice = int(p.info['nice']) if p.info['nice'] else ''
|
||||
if p.info['cmdline']:
|
||||
cmdline = ' '.join(p.info['cmdline'])
|
||||
else:
|
||||
cmdline = p.info['name']
|
||||
status = p.info['status'][:5] if p.info['status'] else ''
|
||||
|
||||
line = templ % (
|
||||
user[:10],
|
||||
p.info['pid'],
|
||||
memp,
|
||||
vms,
|
||||
rss,
|
||||
p.info.get('terminal', '') or '?',
|
||||
nice,
|
||||
status,
|
||||
ctime,
|
||||
cputime,
|
||||
p.info['name'].strip() or '?'))
|
||||
cmdline)
|
||||
print(line[:get_terminal_size()[0]])
|
||||
|
||||
|
||||
del memoize, memoize_when_activated, division, deprecated_method
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# Note: this module is imported by setup.py so it should not import
|
||||
# psutil or third-party modules.
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import division, print_function
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
|
@ -23,6 +23,7 @@ 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:
|
||||
|
@ -37,14 +38,14 @@ if sys.version_info >= (3, 4):
|
|||
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__ = [
|
||||
# constants
|
||||
'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'OSX', 'POSIX', 'SUNOS',
|
||||
'WINDOWS',
|
||||
'ENCODING', 'ENCODING_ERRS', 'AF_INET6',
|
||||
# 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',
|
||||
|
@ -55,15 +56,20 @@ __all__ = [
|
|||
'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_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', 'snic', 'snicstats', 'sswap', 'suser',
|
||||
'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',
|
||||
]
|
||||
|
||||
|
||||
|
@ -75,12 +81,13 @@ __all__ = [
|
|||
POSIX = os.name == "posix"
|
||||
WINDOWS = os.name == "nt"
|
||||
LINUX = sys.platform.startswith("linux")
|
||||
OSX = sys.platform.startswith("darwin")
|
||||
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") or sys.platform.startswith("solaris")
|
||||
SUNOS = sys.platform.startswith(("sunos", "solaris"))
|
||||
AIX = sys.platform.startswith("aix")
|
||||
|
||||
|
||||
|
@ -99,10 +106,11 @@ STATUS_ZOMBIE = "zombie"
|
|||
STATUS_DEAD = "dead"
|
||||
STATUS_WAKE_KILL = "wake-kill"
|
||||
STATUS_WAKING = "waking"
|
||||
STATUS_IDLE = "idle" # FreeBSD, OSX
|
||||
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"
|
||||
|
@ -182,7 +190,8 @@ suser = namedtuple('suser', ['name', 'terminal', 'host', 'started', 'pid'])
|
|||
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||
'status', 'pid'])
|
||||
# psutil.net_if_addrs()
|
||||
snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast', 'ptp'])
|
||||
snicaddr = namedtuple('snicaddr',
|
||||
['family', 'address', 'netmask', 'broadcast', 'ptp'])
|
||||
# psutil.net_if_stats()
|
||||
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
|
||||
# psutil.cpu_stats()
|
||||
|
@ -195,7 +204,7 @@ shwtemp = namedtuple(
|
|||
'shwtemp', ['label', 'current', 'high', 'critical'])
|
||||
# psutil.sensors_battery()
|
||||
sbattery = namedtuple('sbattery', ['percent', 'secsleft', 'power_plugged'])
|
||||
# psutil.sensors_battery()
|
||||
# psutil.sensors_fans()
|
||||
sfan = namedtuple('sfan', ['label', 'current'])
|
||||
|
||||
# --- for Process methods
|
||||
|
@ -253,7 +262,109 @@ if AF_UNIX is not None:
|
|||
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
})
|
||||
|
||||
del AF_INET, 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
|
||||
|
||||
|
||||
# ===================================================================
|
||||
|
@ -261,15 +372,15 @@ del AF_INET, AF_UNIX, SOCK_STREAM, SOCK_DGRAM
|
|||
# ===================================================================
|
||||
|
||||
|
||||
def usage_percent(used, total, _round=None):
|
||||
def usage_percent(used, total, round_=None):
|
||||
"""Calculate percentage usage of 'used' against 'total'."""
|
||||
try:
|
||||
ret = (used / total) * 100
|
||||
ret = (float(used) / total) * 100
|
||||
except ZeroDivisionError:
|
||||
ret = 0.0 if isinstance(used, float) or isinstance(total, float) else 0
|
||||
if _round is not None:
|
||||
return round(ret, _round)
|
||||
return 0.0
|
||||
else:
|
||||
if round_ is not None:
|
||||
ret = round(ret, round_)
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -324,7 +435,7 @@ def memoize_when_activated(fun):
|
|||
1
|
||||
>>>
|
||||
>>> # activated
|
||||
>>> foo.cache_activate()
|
||||
>>> foo.cache_activate(self)
|
||||
>>> foo()
|
||||
1
|
||||
>>> foo()
|
||||
|
@ -333,26 +444,30 @@ def memoize_when_activated(fun):
|
|||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self):
|
||||
if not wrapper.cache_activated:
|
||||
return fun(self)
|
||||
else:
|
||||
try:
|
||||
ret = cache[fun]
|
||||
# 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:
|
||||
ret = cache[fun] = fun(self)
|
||||
# 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():
|
||||
"""Activate cache."""
|
||||
wrapper.cache_activated = True
|
||||
def cache_activate(proc):
|
||||
"""Activate cache. Expects a Process instance. Cache will be
|
||||
stored as a "_cache" instance attribute."""
|
||||
proc._cache = {}
|
||||
|
||||
def cache_deactivate():
|
||||
def cache_deactivate(proc):
|
||||
"""Deactivate and clear cache."""
|
||||
wrapper.cache_activated = False
|
||||
cache.clear()
|
||||
try:
|
||||
del proc._cache
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
cache = {}
|
||||
wrapper.cache_activated = False
|
||||
wrapper.cache_activate = cache_activate
|
||||
wrapper.cache_deactivate = cache_deactivate
|
||||
return wrapper
|
||||
|
@ -439,7 +554,7 @@ def sockfam_to_enum(num):
|
|||
else: # pragma: no cover
|
||||
try:
|
||||
return socket.AddressFamily(num)
|
||||
except (ValueError, AttributeError):
|
||||
except ValueError:
|
||||
return num
|
||||
|
||||
|
||||
|
@ -451,11 +566,30 @@ def socktype_to_enum(num):
|
|||
return num
|
||||
else: # pragma: no cover
|
||||
try:
|
||||
return socket.AddressType(num)
|
||||
except (ValueError, AttributeError):
|
||||
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.
|
||||
|
@ -468,7 +602,7 @@ def deprecated_method(replacement):
|
|||
|
||||
@functools.wraps(fun)
|
||||
def inner(self, *args, **kwargs):
|
||||
warnings.warn(msg, category=FutureWarning, stacklevel=2)
|
||||
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
|
||||
return getattr(self, replacement)(*args, **kwargs)
|
||||
return inner
|
||||
return outer
|
||||
|
@ -573,3 +707,140 @@ def wrap_numbers(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
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
"""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",
|
||||
"callable", "lru_cache", "which"]
|
||||
"lru_cache", "which", "get_terminal_size",
|
||||
"FileNotFoundError", "PermissionError", "ProcessLookupError",
|
||||
"InterruptedError", "ChildProcessError", "FileExistsError"]
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
|
@ -38,12 +41,84 @@ else:
|
|||
return s
|
||||
|
||||
|
||||
# removed in 3.0, reintroduced in 3.2
|
||||
# --- 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:
|
||||
callable = callable
|
||||
except NameError:
|
||||
def callable(obj):
|
||||
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
||||
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
|
||||
|
@ -247,3 +322,24 @@ except ImportError:
|
|||
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
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
# 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.
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Base exception class. All other psutil exceptions inherit
|
||||
from this one.
|
||||
"""
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
|
||||
class ZombieProcess(NoSuchProcess):
|
||||
"""Exception raised when querying a zombie process. This is
|
||||
raised on OSX, BSD and Solaris only, and not always: depending
|
||||
on the query the OS may be able to succeed anyway.
|
||||
On Linux all zombie processes are querable (hence this is never
|
||||
raised). Windows doesn't have zombie processes.
|
||||
"""
|
||||
|
||||
def __init__(self, pid, name=None, ppid=None, msg=None):
|
||||
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."""
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
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
|
|
@ -6,31 +6,32 @@
|
|||
|
||||
"""AIX platform implementation."""
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_aix as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AF_INET6
|
||||
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 sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
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
|
||||
from ._exceptions import AccessDenied
|
||||
from ._exceptions import NoSuchProcess
|
||||
from ._exceptions import ZombieProcess
|
||||
|
||||
|
||||
__extra__all__ = ["PROCFS_PATH"]
|
||||
|
@ -42,6 +43,8 @@ __extra__all__ = ["PROCFS_PATH"]
|
|||
|
||||
|
||||
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
|
||||
|
@ -93,21 +96,6 @@ pfullmem = pmem
|
|||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
||||
# psutil.virtual_memory()
|
||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||
# psutil.Process.memory_maps(grouped=True)
|
||||
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss', 'anon', 'locked'])
|
||||
# psutil.Process.memory_maps(grouped=False)
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- utils
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def get_procfs_path():
|
||||
"""Return updated psutil.PROCFS_PATH constant."""
|
||||
return sys.modules['psutil'].PROCFS_PATH
|
||||
|
||||
|
||||
# =====================================================================
|
||||
|
@ -117,7 +105,7 @@ def get_procfs_path():
|
|||
|
||||
def virtual_memory():
|
||||
total, avail, free, pinned, inuse = cext.virtual_mem()
|
||||
percent = usage_percent((total - avail), total, _round=1)
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, inuse, free)
|
||||
|
||||
|
||||
|
@ -125,7 +113,7 @@ 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)
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
|
@ -212,6 +200,8 @@ def disk_partitions(all=False):
|
|||
|
||||
|
||||
net_if_addrs = cext_posix.net_if_addrs
|
||||
|
||||
if HAS_NET_IO_COUNTERS:
|
||||
net_io_counters = cext.net_io_counters
|
||||
|
||||
|
||||
|
@ -225,27 +215,17 @@ def net_connections(kind, _pid=-1):
|
|||
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||
families, types = _common.conn_tmap[kind]
|
||||
rawlist = cext.net_connections(_pid)
|
||||
ret = set()
|
||||
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
|
||||
status = TCP_STATUSES[status]
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
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)
|
||||
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():
|
||||
|
@ -269,7 +249,8 @@ def net_if_stats():
|
|||
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||
for x in (stdout, stderr)]
|
||||
if p.returncode == 0:
|
||||
re_result = re.search("Running: (\d+) Mbps.*?(\w+) Duplex", stdout)
|
||||
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)
|
||||
|
@ -327,33 +308,27 @@ 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 EnvironmentError as err:
|
||||
# support for private module import
|
||||
if (NoSuchProcess is None or AccessDenied is None or
|
||||
ZombieProcess is None):
|
||||
raise
|
||||
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 err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
|
||||
__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
|
@ -362,23 +337,19 @@ class Process(object):
|
|||
self._procfs_path = get_procfs_path()
|
||||
|
||||
def oneshot_enter(self):
|
||||
self._proc_name_and_args.cache_activate()
|
||||
self._proc_basic_info.cache_activate()
|
||||
self._proc_cred.cache_activate()
|
||||
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._proc_basic_info.cache_deactivate()
|
||||
self._proc_cred.cache_deactivate()
|
||||
|
||||
@memoize_when_activated
|
||||
def _proc_name_and_args(self):
|
||||
return cext.proc_name_and_args(self.pid, self._procfs_path)
|
||||
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)
|
||||
|
@ -387,14 +358,17 @@ class Process(object):
|
|||
def name(self):
|
||||
if self.pid == 0:
|
||||
return "swapper"
|
||||
# note: this is limited to 15 characters
|
||||
return self._proc_name_and_args()[0].rstrip("\x00")
|
||||
# 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
|
||||
exe = self.cmdline()[0]
|
||||
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):
|
||||
|
@ -416,7 +390,11 @@ class Process(object):
|
|||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
return self._proc_name_and_args()[1].split(' ')
|
||||
return cext.proc_args(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def environ(self):
|
||||
return cext.proc_environ(self.pid)
|
||||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
|
@ -502,11 +480,9 @@ class Process(object):
|
|||
try:
|
||||
result = os.readlink("%s/%s/cwd" % (procfs_path, self.pid))
|
||||
return result.rstrip('/')
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||
return None
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
|
@ -534,7 +510,7 @@ class Process(object):
|
|||
for x in (stdout, stderr)]
|
||||
if "no such process" in stderr.lower():
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
procfiles = re.findall("(\d+): S_IFREG.*\s*.*name:(.*)\n", stdout)
|
||||
procfiles = re.findall(r"(\d+): S_IFREG.*\s*.*name:(.*)\n", stdout)
|
||||
retlist = []
|
||||
for fd, path in procfiles:
|
||||
path = path.strip()
|
||||
|
@ -560,6 +536,7 @@ class Process(object):
|
|||
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:
|
||||
|
|
|
@ -10,26 +10,28 @@ import functools
|
|||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET
|
||||
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 AF_INET6
|
||||
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 sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
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
|
||||
from ._exceptions import AccessDenied
|
||||
from ._exceptions import NoSuchProcess
|
||||
from ._exceptions import ZombieProcess
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
||||
|
@ -103,6 +105,11 @@ 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,
|
||||
|
@ -188,7 +195,7 @@ def virtual_memory():
|
|||
shared = int(line.split()[1]) * 1024
|
||||
avail = inactive + cached + free
|
||||
used = active + wired + cached
|
||||
percent = usage_percent((total - avail), total, _round=1)
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, used, free,
|
||||
active, inactive, buffers, cached, shared, wired)
|
||||
|
||||
|
@ -196,7 +203,7 @@ def virtual_memory():
|
|||
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)
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
|
@ -211,7 +218,7 @@ def cpu_times():
|
|||
return scputimes(user, nice, system, idle, irq)
|
||||
|
||||
|
||||
if hasattr(cext, "per_cpu_times"):
|
||||
if HAS_PER_CPU_TIMES:
|
||||
def per_cpu_times():
|
||||
"""Return system CPU times as a namedtuple"""
|
||||
ret = []
|
||||
|
@ -345,9 +352,15 @@ def net_if_stats():
|
|||
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)
|
||||
|
@ -383,22 +396,8 @@ def net_connections(kind):
|
|||
fd, fam, type, laddr, raddr, status, pid = item
|
||||
# TODO: apply filter at C level
|
||||
if fam in families and type in types:
|
||||
try:
|
||||
status = TCP_STATUSES[status]
|
||||
except KeyError:
|
||||
# XXX: Not sure why this happens. I saw this occurring
|
||||
# with IPv6 sockets opened by 'vim'. Those sockets
|
||||
# have a very short lifetime so maybe the kernel
|
||||
# can't initialize their status?
|
||||
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES, pid)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
@ -426,6 +425,47 @@ if FREEBSD:
|
|||
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
|
||||
|
@ -494,6 +534,14 @@ 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.
|
||||
|
@ -502,19 +550,19 @@ def wrap_exceptions(fun):
|
|||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
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
|
||||
if err.errno == errno.ESRCH:
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
@ -524,30 +572,35 @@ def wrap_exceptions_procfs(inst):
|
|||
"""Same as above, for routines relying on reading /proc fs."""
|
||||
try:
|
||||
yield
|
||||
except EnvironmentError as err:
|
||||
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 err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
if not pid_exists(inst.pid):
|
||||
raise NoSuchProcess(inst.pid, inst._name)
|
||||
else:
|
||||
raise ZombieProcess(inst.pid, inst._name, inst._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(inst.pid, inst._name)
|
||||
raise
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid"]
|
||||
__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."""
|
||||
|
@ -556,10 +609,10 @@ class Process(object):
|
|||
return ret
|
||||
|
||||
def oneshot_enter(self):
|
||||
self.oneshot.cache_activate()
|
||||
self.oneshot.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self.oneshot.cache_deactivate()
|
||||
self.oneshot.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
|
@ -569,6 +622,8 @@ class Process(object):
|
|||
@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:
|
||||
|
@ -584,7 +639,7 @@ class Process(object):
|
|||
# cmdline arg (may return None).
|
||||
cmdline = self.cmdline()
|
||||
if cmdline:
|
||||
return which(cmdline[0])
|
||||
return which(cmdline[0]) or ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
@ -601,10 +656,14 @@ class Process(object):
|
|||
return cext.proc_cmdline(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINVAL:
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
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:
|
||||
|
@ -672,7 +731,7 @@ class Process(object):
|
|||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
if hasattr(cext, "proc_num_threads"):
|
||||
if HAS_PROC_NUM_THREADS:
|
||||
# FreeBSD
|
||||
return cext.proc_num_threads(self.pid)
|
||||
else:
|
||||
|
@ -694,10 +753,7 @@ class Process(object):
|
|||
ntuple = _common.pthread(thread_id, utime, stime)
|
||||
retlist.append(ntuple)
|
||||
if OPENBSD:
|
||||
# On OpenBSD the underlying C function does not raise NSP
|
||||
# in case the process is gone (and the returned list may
|
||||
# incomplete).
|
||||
self.name() # raise NSP if the process disappeared on us
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
|
@ -708,29 +764,16 @@ class Process(object):
|
|||
|
||||
if NETBSD:
|
||||
families, types = conn_tmap[kind]
|
||||
ret = set()
|
||||
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:
|
||||
try:
|
||||
status = TCP_STATUSES[status]
|
||||
except KeyError:
|
||||
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
ret.add(nt)
|
||||
# On NetBSD the underlying C function does not raise NSP
|
||||
# in case the process is gone (and the returned list may
|
||||
# incomplete).
|
||||
self.name() # raise NSP if the process disappeared on us
|
||||
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]
|
||||
|
@ -738,21 +781,13 @@ class Process(object):
|
|||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
status = TCP_STATUSES[status]
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
|
||||
if OPENBSD:
|
||||
# On OpenBSD the underlying C function does not raise NSP
|
||||
# in case the process is gone (and the returned list may
|
||||
# incomplete).
|
||||
self.name() # raise NSP if the process disappeared on us
|
||||
self._assert_alive()
|
||||
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
|
@ -789,10 +824,7 @@ class Process(object):
|
|||
# it into None
|
||||
if OPENBSD and self.pid == 0:
|
||||
return None # ...else it would raise EINVAL
|
||||
elif NETBSD:
|
||||
with wrap_exceptions_procfs(self):
|
||||
return os.readlink("/proc/%s/cwd" % self.pid)
|
||||
elif hasattr(cext, 'proc_open_files'):
|
||||
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
|
||||
|
@ -811,7 +843,7 @@ class Process(object):
|
|||
|
||||
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||
# and kinfo_getvmmap()
|
||||
if hasattr(cext, 'proc_open_files'):
|
||||
if HAS_PROC_OPEN_FILES:
|
||||
@wrap_exceptions
|
||||
def open_files(self):
|
||||
"""Return files opened by process as a list of namedtuples."""
|
||||
|
@ -822,15 +854,13 @@ class Process(object):
|
|||
|
||||
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||
# and kinfo_getvmmap()
|
||||
if hasattr(cext, 'proc_num_fds'):
|
||||
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:
|
||||
# On NetBSD the underlying C function does not raise NSP
|
||||
# in case the process is gone.
|
||||
self.name() # raise NSP if the process disappeared on us
|
||||
self._assert_alive()
|
||||
return ret
|
||||
else:
|
||||
num_fds = _not_implemented
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -2,30 +2,29 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""OSX platform implementation."""
|
||||
"""macOS platform implementation."""
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
from socket import AF_INET
|
||||
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 AF_INET6
|
||||
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 sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
from ._common import usage_percent
|
||||
from ._exceptions import AccessDenied
|
||||
from ._exceptions import NoSuchProcess
|
||||
from ._exceptions import ZombieProcess
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
@ -103,13 +102,6 @@ svmem = namedtuple(
|
|||
pmem = namedtuple('pmem', ['rss', 'vms', 'pfaults', 'pageins'])
|
||||
# psutil.Process.memory_full_info()
|
||||
pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', ))
|
||||
# psutil.Process.memory_maps(grouped=True)
|
||||
pmmap_grouped = namedtuple(
|
||||
'pmmap_grouped',
|
||||
'path rss private swapped dirtied ref_count shadow_depth')
|
||||
# psutil.Process.memory_maps(grouped=False)
|
||||
pmmap_ext = namedtuple(
|
||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
|
@ -119,10 +111,17 @@ pmmap_ext = namedtuple(
|
|||
|
||||
def virtual_memory():
|
||||
"""System virtual memory as a namedtuple."""
|
||||
total, active, inactive, wired, free = cext.virtual_mem()
|
||||
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 + inactive + wired
|
||||
percent = usage_percent((total - avail), total, _round=1)
|
||||
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)
|
||||
|
||||
|
@ -130,7 +129,7 @@ def virtual_memory():
|
|||
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)
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, sin, sout)
|
||||
|
||||
|
||||
|
@ -174,7 +173,7 @@ def cpu_stats():
|
|||
|
||||
def cpu_freq():
|
||||
"""Return CPU frequency.
|
||||
On OSX per-cpu frequency is not supported.
|
||||
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
|
||||
"""
|
||||
|
@ -213,8 +212,7 @@ def disk_partitions(all=False):
|
|||
|
||||
|
||||
def sensors_battery():
|
||||
"""Return battery information.
|
||||
"""
|
||||
"""Return battery information."""
|
||||
try:
|
||||
percent, minsleft, power_plugged = cext.sensors_battery()
|
||||
except NotImplementedError:
|
||||
|
@ -241,7 +239,7 @@ net_if_addrs = cext_posix.net_if_addrs
|
|||
|
||||
def net_connections(kind='inet'):
|
||||
"""System-wide network connections."""
|
||||
# Note: on OSX this will fail with AccessDenied unless
|
||||
# Note: on macOS this will fail with AccessDenied unless
|
||||
# the process is owned by root.
|
||||
ret = []
|
||||
for pid in pids():
|
||||
|
@ -262,9 +260,15 @@ def net_if_stats():
|
|||
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)
|
||||
|
@ -304,16 +308,16 @@ def users():
|
|||
def pids():
|
||||
ls = cext.pids()
|
||||
if 0 not in ls:
|
||||
# On certain OSX versions pids() C doesn't return PID 0 but
|
||||
# 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.append(0)
|
||||
ls.insert(0, 0)
|
||||
except NoSuchProcess:
|
||||
pass
|
||||
except AccessDenied:
|
||||
ls.append(0)
|
||||
ls.insert(0, 0)
|
||||
return ls
|
||||
|
||||
|
||||
|
@ -328,12 +332,12 @@ def wrap_exceptions(fun):
|
|||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ESRCH:
|
||||
except ProcessLookupError:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
except cext.ZombieProcessError:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
return wrapper
|
||||
|
||||
|
||||
|
@ -366,13 +370,14 @@ def catch_zombie(proc):
|
|||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid"]
|
||||
__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.
|
||||
|
@ -380,6 +385,7 @@ class Process(object):
|
|||
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.
|
||||
|
@ -389,12 +395,12 @@ class Process(object):
|
|||
return ret
|
||||
|
||||
def oneshot_enter(self):
|
||||
self._get_kinfo_proc.cache_activate()
|
||||
self._get_pidtaskinfo.cache_activate()
|
||||
self._get_kinfo_proc.cache_activate(self)
|
||||
self._get_pidtaskinfo.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self._get_kinfo_proc.cache_deactivate()
|
||||
self._get_pidtaskinfo.cache_deactivate()
|
||||
self._get_kinfo_proc.cache_deactivate(self)
|
||||
self._get_pidtaskinfo.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
|
@ -516,15 +522,8 @@ class Process(object):
|
|||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
status = TCP_STATUSES[status]
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
return ret
|
||||
|
||||
|
@ -557,15 +556,9 @@ class Process(object):
|
|||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
with catch_zombie(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
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_maps(self):
|
||||
with catch_zombie(self):
|
||||
return cext.proc_memory_maps(self.pid)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
"""Routines common to all posix systems."""
|
||||
|
||||
import errno
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
|
@ -12,10 +11,15 @@ 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
|
||||
from ._exceptions import TimeoutExpired
|
||||
|
||||
|
||||
__all__ = ['pid_exists', 'wait_pid', 'disk_usage', 'get_terminal_map']
|
||||
|
@ -32,19 +36,13 @@ def pid_exists(pid):
|
|||
return True
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ESRCH:
|
||||
# ESRCH == No such process
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
elif err.errno == errno.EPERM:
|
||||
except PermissionError:
|
||||
# EPERM clearly means there's a process to deny access to
|
||||
return True
|
||||
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.
|
||||
raise err
|
||||
# (EINVAL, EPERM, ESRCH)
|
||||
else:
|
||||
return True
|
||||
|
||||
|
@ -80,11 +78,9 @@ def wait_pid(pid, timeout=None, proc_name=None):
|
|||
while True:
|
||||
try:
|
||||
retpid, status = waitcall()
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINTR:
|
||||
except InterruptedError:
|
||||
delay = check_timeout(delay)
|
||||
continue
|
||||
elif err.errno == errno.ECHILD:
|
||||
except ChildProcessError:
|
||||
# This has two meanings:
|
||||
# - pid is not a child of os.getpid() in which case
|
||||
# we keep polling until it's gone
|
||||
|
@ -96,8 +92,6 @@ def wait_pid(pid, timeout=None, proc_name=None):
|
|||
delay = check_timeout(delay)
|
||||
else:
|
||||
return
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
if retpid == 0:
|
||||
# WNOHANG was used, pid is still running
|
||||
|
@ -156,7 +150,7 @@ def disk_usage(path):
|
|||
# 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)
|
||||
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:
|
||||
|
@ -176,7 +170,6 @@ def get_terminal_map():
|
|||
assert name not in ret, name
|
||||
try:
|
||||
ret[os.stat(name).st_rdev] = name
|
||||
except OSError as err:
|
||||
if err.errno != errno.ENOENT:
|
||||
raise
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return ret
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"""Sun OS Solaris platform implementation."""
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import socket
|
||||
import subprocess
|
||||
|
@ -16,17 +17,22 @@ 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
|
||||
from ._exceptions import AccessDenied
|
||||
from ._exceptions import NoSuchProcess
|
||||
from ._exceptions import ZombieProcess
|
||||
|
||||
|
||||
__extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"]
|
||||
|
@ -79,7 +85,11 @@ proc_info_map = dict(
|
|||
nice=4,
|
||||
num_threads=5,
|
||||
status=6,
|
||||
ttynr=7)
|
||||
ttynr=7,
|
||||
uid=8,
|
||||
euid=9,
|
||||
gid=10,
|
||||
egid=11)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
|
@ -105,16 +115,6 @@ pmmap_ext = namedtuple(
|
|||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- utils
|
||||
# =====================================================================
|
||||
|
||||
|
||||
def get_procfs_path():
|
||||
"""Return updated psutil.PROCFS_PATH constant."""
|
||||
return sys.modules['psutil'].PROCFS_PATH
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- memory
|
||||
# =====================================================================
|
||||
|
@ -127,7 +127,7 @@ def virtual_memory():
|
|||
# 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)
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return svmem(total, avail, percent, used, free)
|
||||
|
||||
|
||||
|
@ -159,7 +159,7 @@ def swap_memory():
|
|||
total += int(int(t) * 512)
|
||||
free += int(int(f) * 512)
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent,
|
||||
sin * PAGE_SIZE, sout * PAGE_SIZE)
|
||||
|
||||
|
@ -226,8 +226,13 @@ def disk_partitions(all=False):
|
|||
# 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
|
||||
|
@ -262,6 +267,7 @@ def net_connections(kind, _pid=-1):
|
|||
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)
|
||||
|
@ -337,26 +343,26 @@ 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 EnvironmentError as err:
|
||||
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
|
||||
# ENOENT (no such file or directory) gets raised on open().
|
||||
# ESRCH (no such process) can get raised on read() if
|
||||
# process is gone in meantime.
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
@ -364,7 +370,7 @@ def wrap_exceptions(fun):
|
|||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
|
||||
__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
|
@ -372,26 +378,38 @@ class Process(object):
|
|||
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._proc_basic_info.cache_activate()
|
||||
self._proc_cred.cache_activate()
|
||||
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._proc_basic_info.cache_deactivate()
|
||||
self._proc_cred.cache_deactivate()
|
||||
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)
|
||||
|
@ -432,27 +450,10 @@ class Process(object):
|
|||
|
||||
@wrap_exceptions
|
||||
def nice_get(self):
|
||||
# Note #1: for some reason getpriority(3) return ESRCH (no such
|
||||
# process) for certain low-pid processes, no matter what (even
|
||||
# as root).
|
||||
# The process actually exists though, as it has a name,
|
||||
# creation time, etc.
|
||||
# The best thing we can do here appears to be raising AD.
|
||||
# Note: tested on Solaris 11; on Open Solaris 5 everything is
|
||||
# fine.
|
||||
#
|
||||
# Note #2: we also can get niceness from /proc/pid/psinfo
|
||||
# but it's wrong, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1082
|
||||
try:
|
||||
return cext_posix.getpriority(self.pid)
|
||||
except EnvironmentError as err:
|
||||
# 48 is 'operation not supported' but errno does not expose
|
||||
# it. It occurs for low system pids.
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH, 48):
|
||||
if pid_exists(self.pid):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
# 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):
|
||||
|
@ -471,12 +472,22 @@ class Process(object):
|
|||
|
||||
@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
|
||||
|
@ -512,14 +523,11 @@ class Process(object):
|
|||
try:
|
||||
return os.readlink(
|
||||
'%s/%d/path/%d' % (procfs_path, self.pid, x))
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
if hit_enoent:
|
||||
# raise NSP if the process disappeared on us
|
||||
os.stat('%s/%s' % (procfs_path, self.pid))
|
||||
self._assert_alive()
|
||||
|
||||
@wrap_exceptions
|
||||
def cwd(self):
|
||||
|
@ -530,11 +538,9 @@ class Process(object):
|
|||
procfs_path = self._procfs_path
|
||||
try:
|
||||
return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid))
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||
return None
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
|
@ -581,8 +587,7 @@ class Process(object):
|
|||
nt = _common.pthread(tid, utime, stime)
|
||||
ret.append(nt)
|
||||
if hit_enoent:
|
||||
# raise NSP if the process disappeared on us
|
||||
os.stat('%s/%s' % (procfs_path, self.pid))
|
||||
self._assert_alive()
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
|
@ -596,18 +601,14 @@ class Process(object):
|
|||
if os.path.islink(path):
|
||||
try:
|
||||
file = os.readlink(path)
|
||||
except OSError as err:
|
||||
# ENOENT == file which is gone in the meantime
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
if isfile_strict(file):
|
||||
retlist.append(_common.popenfile(file, int(fd)))
|
||||
if hit_enoent:
|
||||
# raise NSP if the process disappeared on us
|
||||
os.stat('%s/%s' % (procfs_path, self.pid))
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
def _get_unix_sockets(self, pid):
|
||||
|
@ -707,8 +708,7 @@ class Process(object):
|
|||
raise
|
||||
retlist.append((addr, perm, name, rss, anon, locked))
|
||||
if hit_enoent:
|
||||
# raise NSP if the process disappeared on us
|
||||
os.stat('%s/%s' % (procfs_path, self.pid))
|
||||
self._assert_alive()
|
||||
return retlist
|
||||
|
||||
@wrap_exceptions
|
||||
|
|
Двоичные данные
third_party/python/psutil-cp27-none-win_amd64/psutil/_psutil_windows.pyd
поставляемый
Двоичные данные
third_party/python/psutil-cp27-none-win_amd64/psutil/_psutil_windows.pyd
поставляемый
Двоичный файл не отображается.
|
@ -8,10 +8,37 @@ import contextlib
|
|||
import errno
|
||||
import functools
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
from ._common import AccessDenied
|
||||
from ._common import conn_tmap
|
||||
from ._common import conn_to_ntuple
|
||||
from ._common import debug
|
||||
from ._common import ENCODING
|
||||
from ._common import ENCODING_ERRS
|
||||
from ._common import isfile_strict
|
||||
from ._common import memoize
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import parse_environ_block
|
||||
from ._common import TimeoutExpired
|
||||
from ._common import usage_percent
|
||||
from ._compat import long
|
||||
from ._compat import lru_cache
|
||||
from ._compat import PY3
|
||||
from ._compat import unicode
|
||||
from ._compat import xrange
|
||||
from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS
|
||||
from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS
|
||||
from ._psutil_windows import HIGH_PRIORITY_CLASS
|
||||
from ._psutil_windows import IDLE_PRIORITY_CLASS
|
||||
from ._psutil_windows import NORMAL_PRIORITY_CLASS
|
||||
from ._psutil_windows import REALTIME_PRIORITY_CLASS
|
||||
|
||||
try:
|
||||
from . import _psutil_windows as cext
|
||||
except ImportError as err:
|
||||
|
@ -21,41 +48,13 @@ except ImportError as err:
|
|||
# 1) we are on an old Windows version
|
||||
# 2) psutil was installed via pip + wheel
|
||||
# See: https://github.com/giampaolo/psutil/issues/811
|
||||
# It must be noted that psutil can still (kind of) work
|
||||
# on outdated systems if compiled / installed from sources,
|
||||
# but if we get here it means this this was a wheel (or exe).
|
||||
msg = "this Windows version is too old (< Windows Vista); "
|
||||
msg += "psutil 3.4.2 is the latest version which supports Windows "
|
||||
msg += "2000, XP and 2003 server; it may be possible that psutil "
|
||||
msg += "will work if compiled from sources though"
|
||||
msg += "2000, XP and 2003 server"
|
||||
raise RuntimeError(msg)
|
||||
else:
|
||||
raise
|
||||
|
||||
from ._common import conn_tmap
|
||||
from ._common import ENCODING
|
||||
from ._common import ENCODING_ERRS
|
||||
from ._common import isfile_strict
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import parse_environ_block
|
||||
from ._common import sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
from ._common import usage_percent
|
||||
from ._compat import long
|
||||
from ._compat import lru_cache
|
||||
from ._compat import PY3
|
||||
from ._compat import unicode
|
||||
from ._compat import xrange
|
||||
from ._exceptions import AccessDenied
|
||||
from ._exceptions import NoSuchProcess
|
||||
from ._exceptions import TimeoutExpired
|
||||
from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS
|
||||
from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS
|
||||
from ._psutil_windows import HIGH_PRIORITY_CLASS
|
||||
from ._psutil_windows import IDLE_PRIORITY_CLASS
|
||||
from ._psutil_windows import NORMAL_PRIORITY_CLASS
|
||||
from ._psutil_windows import REALTIME_PRIORITY_CLASS
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
import enum
|
||||
else:
|
||||
|
@ -65,11 +64,14 @@ else:
|
|||
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
|
||||
__extra__all__ = [
|
||||
"win_service_iter", "win_service_get",
|
||||
# Process priority
|
||||
"ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
|
||||
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
|
||||
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
|
||||
"CONN_DELETE_TCB",
|
||||
"AF_LINK",
|
||||
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", "NORMAL_PRIORITY_CLASS",
|
||||
"REALTIME_PRIORITY_CLASS",
|
||||
# IO priority
|
||||
"IOPRIO_VERYLOW", "IOPRIO_LOW", "IOPRIO_NORMAL", "IOPRIO_HIGH",
|
||||
# others
|
||||
"CONN_DELETE_TCB", "AF_LINK",
|
||||
]
|
||||
|
||||
|
||||
|
@ -78,12 +80,8 @@ __extra__all__ = [
|
|||
# =====================================================================
|
||||
|
||||
CONN_DELETE_TCB = "DELETE_TCB"
|
||||
WAIT_TIMEOUT = 0x00000102 # 258 in decimal
|
||||
ACCESS_DENIED_ERRSET = frozenset([errno.EPERM, errno.EACCES,
|
||||
cext.ERROR_ACCESS_DENIED])
|
||||
NO_SUCH_SERVICE_ERRSET = frozenset([cext.ERROR_INVALID_NAME,
|
||||
cext.ERROR_SERVICE_DOES_NOT_EXIST])
|
||||
|
||||
ERROR_PARTIAL_COPY = 299
|
||||
PYPY = '__pypy__' in sys.builtin_module_names
|
||||
|
||||
if enum is None:
|
||||
AF_LINK = -1
|
||||
|
@ -118,6 +116,19 @@ if enum is not None:
|
|||
|
||||
globals().update(Priority.__members__)
|
||||
|
||||
if enum is None:
|
||||
IOPRIO_VERYLOW = 0
|
||||
IOPRIO_LOW = 1
|
||||
IOPRIO_NORMAL = 2
|
||||
IOPRIO_HIGH = 3
|
||||
else:
|
||||
class IOPriority(enum.IntEnum):
|
||||
IOPRIO_VERYLOW = 0
|
||||
IOPRIO_LOW = 1
|
||||
IOPRIO_NORMAL = 2
|
||||
IOPRIO_HIGH = 3
|
||||
globals().update(IOPriority.__members__)
|
||||
|
||||
pinfo_map = dict(
|
||||
num_handles=0,
|
||||
ctx_switches=1,
|
||||
|
@ -187,7 +198,8 @@ def convert_dos_path(s):
|
|||
"""
|
||||
rawdrive = '\\'.join(s.split('\\')[:3])
|
||||
driveletter = cext.win32_QueryDosDevice(rawdrive)
|
||||
return os.path.join(driveletter, s[len(rawdrive):])
|
||||
remainder = s[len(rawdrive):]
|
||||
return os.path.join(driveletter, remainder)
|
||||
|
||||
|
||||
def py2_strencode(s):
|
||||
|
@ -200,7 +212,12 @@ def py2_strencode(s):
|
|||
if isinstance(s, str):
|
||||
return s
|
||||
else:
|
||||
return s.encode(ENCODING, errors=ENCODING_ERRS)
|
||||
return s.encode(ENCODING, ENCODING_ERRS)
|
||||
|
||||
|
||||
@memoize
|
||||
def getpagesize():
|
||||
return cext.getpagesize()
|
||||
|
||||
|
||||
# =====================================================================
|
||||
|
@ -217,7 +234,7 @@ def virtual_memory():
|
|||
avail = availphys
|
||||
free = availphys
|
||||
used = total - avail
|
||||
percent = usage_percent((total - avail), total, _round=1)
|
||||
percent = usage_percent((total - avail), total, round_=1)
|
||||
return svmem(total, avail, percent, used, free)
|
||||
|
||||
|
||||
|
@ -227,7 +244,7 @@ def swap_memory():
|
|||
total = mem[2]
|
||||
free = mem[3]
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sswap(total, used, free, percent, 0, 0)
|
||||
|
||||
|
||||
|
@ -247,7 +264,7 @@ def disk_usage(path):
|
|||
path = path.decode(ENCODING, errors="strict")
|
||||
total, free = cext.disk_usage(path)
|
||||
used = total - free
|
||||
percent = usage_percent(used, total, _round=1)
|
||||
percent = usage_percent(used, total, round_=1)
|
||||
return _common.sdiskusage(total, used, free, percent)
|
||||
|
||||
|
||||
|
@ -288,7 +305,7 @@ def cpu_count_logical():
|
|||
|
||||
|
||||
def cpu_count_physical():
|
||||
"""Return the number of physical CPUs in the system."""
|
||||
"""Return the number of physical CPU cores in the system."""
|
||||
return cext.cpu_count_phys()
|
||||
|
||||
|
||||
|
@ -309,6 +326,23 @@ def cpu_freq():
|
|||
return [_common.scpufreq(float(curr), min_, float(max_))]
|
||||
|
||||
|
||||
_loadavg_inititialized = False
|
||||
|
||||
|
||||
def getloadavg():
|
||||
"""Return the number of processes in the system run queue averaged
|
||||
over the last 1, 5, and 15 minutes respectively as a tuple"""
|
||||
global _loadavg_inititialized
|
||||
|
||||
if not _loadavg_inititialized:
|
||||
cext.init_loadavg_counter()
|
||||
_loadavg_inititialized = True
|
||||
|
||||
# Drop to 2 decimal points which is what Linux does
|
||||
raw_loads = cext.getloadavg()
|
||||
return tuple([round(load, 2) for load in raw_loads])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- network
|
||||
# =====================================================================
|
||||
|
@ -326,17 +360,8 @@ def net_connections(kind, _pid=-1):
|
|||
ret = set()
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status, pid = item
|
||||
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)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status, TCP_STATUSES,
|
||||
pid=pid if _pid == -1 else None)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
@ -501,14 +526,14 @@ class WindowsService(object):
|
|||
"""
|
||||
try:
|
||||
yield
|
||||
except WindowsError as err:
|
||||
if err.errno in ACCESS_DENIED_ERRSET:
|
||||
except OSError as err:
|
||||
if is_permission_err(err):
|
||||
raise AccessDenied(
|
||||
pid=None, name=self._name,
|
||||
msg="service %r is not querable (not enough privileges)" %
|
||||
self._name)
|
||||
elif err.errno in NO_SUCH_SERVICE_ERRSET or \
|
||||
err.winerror in NO_SUCH_SERVICE_ERRSET:
|
||||
elif err.winerror in (cext.ERROR_INVALID_NAME,
|
||||
cext.ERROR_SERVICE_DOES_NOT_EXIST):
|
||||
raise NoSuchProcess(
|
||||
pid=None, name=self._name,
|
||||
msg="service %r does not exist)" % self._name)
|
||||
|
@ -625,27 +650,68 @@ pid_exists = cext.pid_exists
|
|||
ppid_map = cext.ppid_map # used internally by Process.children()
|
||||
|
||||
|
||||
def is_permission_err(exc):
|
||||
"""Return True if this is a permission error."""
|
||||
assert isinstance(exc, OSError), exc
|
||||
# On Python 2 OSError doesn't always have 'winerror'. Sometimes
|
||||
# it does, in which case the original exception was WindowsError
|
||||
# (which is a subclass of OSError).
|
||||
return exc.errno in (errno.EPERM, errno.EACCES) or \
|
||||
getattr(exc, "winerror", -1) in (cext.ERROR_ACCESS_DENIED,
|
||||
cext.ERROR_PRIVILEGE_NOT_HELD)
|
||||
|
||||
|
||||
def convert_oserror(exc, pid=None, name=None):
|
||||
"""Convert OSError into NoSuchProcess or AccessDenied."""
|
||||
assert isinstance(exc, OSError), exc
|
||||
if is_permission_err(exc):
|
||||
return AccessDenied(pid=pid, name=name)
|
||||
if exc.errno == errno.ESRCH:
|
||||
return NoSuchProcess(pid=pid, name=name)
|
||||
raise exc
|
||||
|
||||
|
||||
def wrap_exceptions(fun):
|
||||
"""Decorator which translates bare OSError and WindowsError
|
||||
exceptions into NoSuchProcess and AccessDenied.
|
||||
"""
|
||||
"""Decorator which converts OSError into NoSuchProcess or AccessDenied."""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_ERRSET:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
if err.errno == errno.ESRCH:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise convert_oserror(err, pid=self.pid, name=self._name)
|
||||
return wrapper
|
||||
|
||||
|
||||
def retry_error_partial_copy(fun):
|
||||
"""Workaround for https://github.com/giampaolo/psutil/issues/875.
|
||||
See: https://stackoverflow.com/questions/4457745#4457745
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
delay = 0.0001
|
||||
times = 33
|
||||
for x in range(times): # retries for roughly 1 second
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except WindowsError as _:
|
||||
err = _
|
||||
if err.winerror == ERROR_PARTIAL_COPY:
|
||||
time.sleep(delay)
|
||||
delay = min(delay * 2, 0.04)
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
msg = "%s retried %s times, converted to AccessDenied as it's " \
|
||||
"still returning %r" % (fun, times, err)
|
||||
raise AccessDenied(pid=self.pid, name=self._name, msg=msg)
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
__slots__ = ["pid", "_name", "_ppid"]
|
||||
__slots__ = ["pid", "_name", "_ppid", "_cache"]
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
|
@ -655,13 +721,15 @@ class Process(object):
|
|||
# --- oneshot() stuff
|
||||
|
||||
def oneshot_enter(self):
|
||||
self.oneshot_info.cache_activate()
|
||||
self._proc_info.cache_activate(self)
|
||||
self.exe.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self.oneshot_info.cache_deactivate()
|
||||
self._proc_info.cache_deactivate(self)
|
||||
self.exe.cache_deactivate(self)
|
||||
|
||||
@memoize_when_activated
|
||||
def oneshot_info(self):
|
||||
def _proc_info(self):
|
||||
"""Return multiple information about this process as a
|
||||
raw tuple.
|
||||
"""
|
||||
|
@ -669,7 +737,6 @@ class Process(object):
|
|||
assert len(ret) == len(pinfo_map)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
"""Return process name, which on Windows is always the final
|
||||
part of the executable.
|
||||
|
@ -678,37 +745,53 @@ class Process(object):
|
|||
# and process-hacker.
|
||||
if self.pid == 0:
|
||||
return "System Idle Process"
|
||||
elif self.pid == 4:
|
||||
if self.pid == 4:
|
||||
return "System"
|
||||
else:
|
||||
try:
|
||||
# Note: this will fail with AD for most PIDs owned
|
||||
# by another user but it's faster.
|
||||
return py2_strencode(os.path.basename(self.exe()))
|
||||
except AccessDenied:
|
||||
return py2_strencode(cext.proc_name(self.pid))
|
||||
return os.path.basename(self.exe())
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def exe(self):
|
||||
# Note: os.path.exists(path) may return False even if the file
|
||||
# is there, see:
|
||||
# http://stackoverflow.com/questions/3112546/os-path-exists-lies
|
||||
|
||||
# see https://github.com/giampaolo/psutil/issues/414
|
||||
# see https://github.com/giampaolo/psutil/issues/528
|
||||
if self.pid in (0, 4):
|
||||
if PYPY:
|
||||
try:
|
||||
exe = cext.proc_exe(self.pid)
|
||||
except WindowsError as err:
|
||||
# 24 = ERROR_TOO_MANY_OPEN_FILES. Not sure why this happens
|
||||
# (perhaps PyPy's JIT delaying garbage collection of files?).
|
||||
if err.errno == 24:
|
||||
debug("%r forced into AccessDenied" % err)
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
return py2_strencode(convert_dos_path(cext.proc_exe(self.pid)))
|
||||
raise
|
||||
else:
|
||||
exe = cext.proc_exe(self.pid)
|
||||
if not PY3:
|
||||
exe = py2_strencode(exe)
|
||||
if exe.startswith('\\'):
|
||||
return convert_dos_path(exe)
|
||||
return exe # May be "Registry", "MemCompression", ...
|
||||
|
||||
@wrap_exceptions
|
||||
@retry_error_partial_copy
|
||||
def cmdline(self):
|
||||
ret = cext.proc_cmdline(self.pid)
|
||||
if cext.WINVER >= cext.WINDOWS_8_1:
|
||||
# PEB method detects cmdline changes but requires more
|
||||
# privileges: https://github.com/giampaolo/psutil/pull/1398
|
||||
try:
|
||||
ret = cext.proc_cmdline(self.pid, use_peb=True)
|
||||
except OSError as err:
|
||||
if is_permission_err(err):
|
||||
ret = cext.proc_cmdline(self.pid, use_peb=False)
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
ret = cext.proc_cmdline(self.pid, use_peb=True)
|
||||
if PY3:
|
||||
return ret
|
||||
else:
|
||||
return [py2_strencode(s) for s in ret]
|
||||
|
||||
@wrap_exceptions
|
||||
@retry_error_partial_copy
|
||||
def environ(self):
|
||||
ustr = cext.proc_environ(self.pid)
|
||||
if ustr and not PY3:
|
||||
|
@ -725,10 +808,10 @@ class Process(object):
|
|||
try:
|
||||
return cext.proc_memory_info(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_ERRSET:
|
||||
if is_permission_err(err):
|
||||
# TODO: the C ext can probably be refactored in order
|
||||
# to get this from cext.proc_info()
|
||||
info = self.oneshot_info()
|
||||
info = self._proc_info()
|
||||
return (
|
||||
info[pinfo_map['num_page_faults']],
|
||||
info[pinfo_map['peak_wset']],
|
||||
|
@ -757,6 +840,7 @@ class Process(object):
|
|||
def memory_full_info(self):
|
||||
basic_mem = self.memory_info()
|
||||
uss = cext.proc_memory_uss(self.pid)
|
||||
uss *= getpagesize()
|
||||
return pfullmem(*basic_mem + (uss, ))
|
||||
|
||||
def memory_maps(self):
|
||||
|
@ -765,16 +849,11 @@ class Process(object):
|
|||
except OSError as err:
|
||||
# XXX - can't use wrap_exceptions decorator as we're
|
||||
# returning a generator; probably needs refactoring.
|
||||
if err.errno in ACCESS_DENIED_ERRSET:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
if err.errno == errno.ESRCH:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
raise
|
||||
raise convert_oserror(err, self.pid, self._name)
|
||||
else:
|
||||
for addr, perm, path, rss in raw:
|
||||
path = convert_dos_path(path)
|
||||
if not PY3:
|
||||
assert isinstance(path, unicode), type(path)
|
||||
path = py2_strencode(path)
|
||||
addr = hex(addr)
|
||||
yield (addr, perm, path, rss)
|
||||
|
@ -785,25 +864,59 @@ class Process(object):
|
|||
|
||||
@wrap_exceptions
|
||||
def send_signal(self, sig):
|
||||
if sig == signal.SIGTERM:
|
||||
cext.proc_kill(self.pid)
|
||||
# py >= 2.7
|
||||
elif sig in (getattr(signal, "CTRL_C_EVENT", object()),
|
||||
getattr(signal, "CTRL_BREAK_EVENT", object())):
|
||||
os.kill(self.pid, sig)
|
||||
else:
|
||||
raise ValueError(
|
||||
"only SIGTERM, CTRL_C_EVENT and CTRL_BREAK_EVENT signals "
|
||||
"are supported on Windows")
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
if timeout is None:
|
||||
cext_timeout = cext.INFINITE
|
||||
else:
|
||||
# WaitForSingleObject() expects time in milliseconds
|
||||
# WaitForSingleObject() expects time in milliseconds.
|
||||
cext_timeout = int(timeout * 1000)
|
||||
|
||||
timer = getattr(time, 'monotonic', time.time)
|
||||
stop_at = timer() + timeout if timeout is not None else None
|
||||
|
||||
try:
|
||||
# Exit code is supposed to come from GetExitCodeProcess().
|
||||
# May also be None if OpenProcess() failed with
|
||||
# ERROR_INVALID_PARAMETER, meaning PID is already gone.
|
||||
exit_code = cext.proc_wait(self.pid, cext_timeout)
|
||||
except cext.TimeoutExpired:
|
||||
# WaitForSingleObject() returned WAIT_TIMEOUT. Just raise.
|
||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||
except cext.TimeoutAbandoned:
|
||||
# WaitForSingleObject() returned WAIT_ABANDONED, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1224
|
||||
# We'll just rely on the internal polling and return None
|
||||
# when the PID disappears. Subprocess module does the same
|
||||
# (return None):
|
||||
# https://github.com/python/cpython/blob/
|
||||
# be50a7b627d0aa37e08fa8e2d5568891f19903ce/
|
||||
# Lib/subprocess.py#L1193-L1194
|
||||
exit_code = None
|
||||
|
||||
# At this point WaitForSingleObject() returned WAIT_OBJECT_0,
|
||||
# meaning the process is gone. Stupidly there are cases where
|
||||
# its PID may still stick around so we do a further internal
|
||||
# polling.
|
||||
delay = 0.0001
|
||||
while True:
|
||||
ret = cext.proc_wait(self.pid, cext_timeout)
|
||||
if ret == WAIT_TIMEOUT:
|
||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||
if pid_exists(self.pid):
|
||||
if timeout is None:
|
||||
continue
|
||||
else:
|
||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||
return ret
|
||||
if not pid_exists(self.pid):
|
||||
return exit_code
|
||||
if stop_at and timer() >= stop_at:
|
||||
raise TimeoutExpired(timeout, pid=self.pid, name=self._name)
|
||||
time.sleep(delay)
|
||||
delay = min(delay * 2, 0.04) # incremental delay
|
||||
|
||||
@wrap_exceptions
|
||||
def username(self):
|
||||
|
@ -814,19 +927,19 @@ class Process(object):
|
|||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
# special case for kernel process PIDs; return system boot time
|
||||
if self.pid in (0, 4):
|
||||
return boot_time()
|
||||
# Note: proc_times() not put under oneshot() 'cause create_time()
|
||||
# is already cached by the main Process class.
|
||||
try:
|
||||
return cext.proc_create_time(self.pid)
|
||||
user, system, created = cext.proc_times(self.pid)
|
||||
return created
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_ERRSET:
|
||||
return self.oneshot_info()[pinfo_map['create_time']]
|
||||
if is_permission_err(err):
|
||||
return self._proc_info()[pinfo_map['create_time']]
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return self.oneshot_info()[pinfo_map['num_threads']]
|
||||
return self._proc_info()[pinfo_map['num_threads']]
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
|
@ -840,26 +953,26 @@ class Process(object):
|
|||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
try:
|
||||
user, system = cext.proc_cpu_times(self.pid)
|
||||
user, system, created = cext.proc_times(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_ERRSET:
|
||||
info = self.oneshot_info()
|
||||
if not is_permission_err(err):
|
||||
raise
|
||||
info = self._proc_info()
|
||||
user = info[pinfo_map['user_time']]
|
||||
system = info[pinfo_map['kernel_time']]
|
||||
else:
|
||||
raise
|
||||
# Children user/system times are not retrievable (set to 0).
|
||||
return _common.pcputimes(user, system, 0.0, 0.0)
|
||||
|
||||
@wrap_exceptions
|
||||
def suspend(self):
|
||||
return cext.proc_suspend(self.pid)
|
||||
cext.proc_suspend_or_resume(self.pid, True)
|
||||
|
||||
@wrap_exceptions
|
||||
def resume(self):
|
||||
return cext.proc_resume(self.pid)
|
||||
cext.proc_suspend_or_resume(self.pid, False)
|
||||
|
||||
@wrap_exceptions
|
||||
@retry_error_partial_copy
|
||||
def cwd(self):
|
||||
if self.pid in (0, 4):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
|
@ -902,29 +1015,30 @@ class Process(object):
|
|||
def nice_set(self, value):
|
||||
return cext.proc_priority_set(self.pid, value)
|
||||
|
||||
# available on Windows >= Vista
|
||||
if hasattr(cext, "proc_io_priority_get"):
|
||||
@wrap_exceptions
|
||||
def ionice_get(self):
|
||||
return cext.proc_io_priority_get(self.pid)
|
||||
ret = cext.proc_io_priority_get(self.pid)
|
||||
if enum is not None:
|
||||
ret = IOPriority(ret)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def ionice_set(self, value, _):
|
||||
if _:
|
||||
raise TypeError("set_proc_ionice() on Windows takes only "
|
||||
"1 argument (2 given)")
|
||||
if value not in (2, 1, 0):
|
||||
raise ValueError("value must be 2 (normal), 1 (low) or 0 "
|
||||
"(very low); got %r" % value)
|
||||
return cext.proc_io_priority_set(self.pid, value)
|
||||
def ionice_set(self, ioclass, value):
|
||||
if value:
|
||||
raise TypeError("value argument not accepted on Windows")
|
||||
if ioclass not in (IOPRIO_VERYLOW, IOPRIO_LOW, IOPRIO_NORMAL,
|
||||
IOPRIO_HIGH):
|
||||
raise ValueError("%s is not a valid priority" % ioclass)
|
||||
cext.proc_io_priority_set(self.pid, ioclass)
|
||||
|
||||
@wrap_exceptions
|
||||
def io_counters(self):
|
||||
try:
|
||||
ret = cext.proc_io_counters(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_ERRSET:
|
||||
info = self.oneshot_info()
|
||||
if not is_permission_err(err):
|
||||
raise
|
||||
info = self._proc_info()
|
||||
ret = (
|
||||
info[pinfo_map['io_rcount']],
|
||||
info[pinfo_map['io_wcount']],
|
||||
|
@ -933,8 +1047,6 @@ class Process(object):
|
|||
info[pinfo_map['io_count_others']],
|
||||
info[pinfo_map['io_bytes_others']],
|
||||
)
|
||||
else:
|
||||
raise
|
||||
return pio(*ret)
|
||||
|
||||
@wrap_exceptions
|
||||
|
@ -982,12 +1094,12 @@ class Process(object):
|
|||
try:
|
||||
return cext.proc_num_handles(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno in ACCESS_DENIED_ERRSET:
|
||||
return self.oneshot_info()[pinfo_map['num_handles']]
|
||||
if is_permission_err(err):
|
||||
return self._proc_info()[pinfo_map['num_handles']]
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
ctx_switches = self.oneshot_info()[pinfo_map['ctx_switches']]
|
||||
ctx_switches = self._proc_info()[pinfo_map['ctx_switches']]
|
||||
# only voluntary ctx switches are supported
|
||||
return _common.pctxsw(ctx_switches, 0)
|
||||
|
|
|
@ -32,15 +32,18 @@ import traceback
|
|||
import warnings
|
||||
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 OSX
|
||||
from psutil import AIX
|
||||
from psutil import MACOS
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
from psutil._common import supports_ipv6
|
||||
from psutil._compat import ChildProcessError
|
||||
from psutil._compat import FileExistsError
|
||||
from psutil._compat import FileNotFoundError
|
||||
from psutil._compat import PY3
|
||||
from psutil._compat import u
|
||||
from psutil._compat import unicode
|
||||
|
@ -54,6 +57,8 @@ else:
|
|||
try:
|
||||
from unittest import mock # py3
|
||||
except ImportError:
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
import mock # NOQA - requires "pip install mock"
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
|
@ -66,8 +71,8 @@ __all__ = [
|
|||
# constants
|
||||
'APPVEYOR', 'DEVNULL', 'GLOBAL_TIMEOUT', 'MEMORY_TOLERANCE', 'NO_RETRIES',
|
||||
'PYPY', 'PYTHON_EXE', 'ROOT_DIR', 'SCRIPTS_DIR', 'TESTFILE_PREFIX',
|
||||
'TESTFN', 'TESTFN_UNICODE', 'TOX', 'TRAVIS', 'VALID_PROC_STATUSES',
|
||||
'VERBOSITY',
|
||||
'TESTFN', 'TESTFN_UNICODE', 'TOX', 'TRAVIS', 'CIRRUS', 'CI_TESTING',
|
||||
'VALID_PROC_STATUSES',
|
||||
"HAS_CPU_AFFINITY", "HAS_CPU_FREQ", "HAS_ENVIRON", "HAS_PROC_IO_COUNTERS",
|
||||
"HAS_IONICE", "HAS_MEMORY_MAPS", "HAS_PROC_CPU_NUM", "HAS_RLIMIT",
|
||||
"HAS_SENSORS_BATTERY", "HAS_BATTERY", "HAS_SENSORS_FANS",
|
||||
|
@ -79,8 +84,7 @@ __all__ = [
|
|||
'ThreadTask'
|
||||
# test utils
|
||||
'unittest', 'skip_on_access_denied', 'skip_on_not_implemented',
|
||||
'retry_before_failing', 'run_test_module_by_name', 'get_suite',
|
||||
'run_suite',
|
||||
'retry_on_failure',
|
||||
# install utils
|
||||
'install_pip', 'install_test_deps',
|
||||
# fs utils
|
||||
|
@ -91,7 +95,7 @@ __all__ = [
|
|||
# sync primitives
|
||||
'call_until', 'wait_for_pid', 'wait_for_file',
|
||||
# network
|
||||
'check_connection_ntuple', 'check_net_address',
|
||||
'check_net_address',
|
||||
'get_free_port', 'unix_socket_path', 'bind_socket', 'bind_unix_socket',
|
||||
'tcp_socketpair', 'unix_socketpair', 'create_sockets',
|
||||
# compat
|
||||
|
@ -109,23 +113,20 @@ __all__ = [
|
|||
|
||||
TOX = os.getenv('TOX') or '' in ('1', 'true')
|
||||
PYPY = '__pypy__' in sys.builtin_module_names
|
||||
WIN_VISTA = (6, 0, 0) if WINDOWS else None
|
||||
# whether we're running this test suite on Travis (https://travis-ci.org/)
|
||||
# whether we're running this test suite on a Continuous Integration service
|
||||
TRAVIS = bool(os.environ.get('TRAVIS'))
|
||||
# whether we're running this test suite on Appveyor for Windows
|
||||
# (http://www.appveyor.com/)
|
||||
APPVEYOR = bool(os.environ.get('APPVEYOR'))
|
||||
CIRRUS = bool(os.environ.get('CIRRUS'))
|
||||
CI_TESTING = TRAVIS or APPVEYOR or CIRRUS
|
||||
|
||||
# --- configurable defaults
|
||||
|
||||
# how many times retry_before_failing() decorator will retry
|
||||
# how many times retry_on_failure() decorator will retry
|
||||
NO_RETRIES = 10
|
||||
# bytes tolerance for system-wide memory related tests
|
||||
MEMORY_TOLERANCE = 500 * 1024 # 500KB
|
||||
# the timeout used in functions which have to wait
|
||||
GLOBAL_TIMEOUT = 3
|
||||
# test output verbosity
|
||||
VERBOSITY = 1 if os.getenv('SILENT') or TOX else 2
|
||||
GLOBAL_TIMEOUT = 5
|
||||
# be more tolerant if we're on travis / appveyor in order to avoid
|
||||
# false positives
|
||||
if TRAVIS or APPVEYOR:
|
||||
|
@ -135,34 +136,49 @@ if TRAVIS or APPVEYOR:
|
|||
# --- files
|
||||
|
||||
TESTFILE_PREFIX = '$testfn'
|
||||
if os.name == 'java':
|
||||
# Jython disallows @ in module names
|
||||
TESTFILE_PREFIX = '$psutil-test-'
|
||||
else:
|
||||
TESTFILE_PREFIX = '@psutil-test-'
|
||||
TESTFN = os.path.join(os.path.realpath(os.getcwd()), TESTFILE_PREFIX)
|
||||
# Disambiguate TESTFN for parallel testing, while letting it remain a valid
|
||||
# module name.
|
||||
TESTFN = TESTFN + str(os.getpid())
|
||||
|
||||
_TESTFN = TESTFN + '-internal'
|
||||
TESTFN_UNICODE = TESTFN + u("-ƒőő")
|
||||
ASCII_FS = sys.getfilesystemencoding().lower() in ('ascii', 'us-ascii')
|
||||
|
||||
# --- paths
|
||||
|
||||
ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
ROOT_DIR = os.path.realpath(
|
||||
os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
SCRIPTS_DIR = os.path.join(ROOT_DIR, 'scripts')
|
||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||
HERE = os.path.realpath(os.path.dirname(__file__))
|
||||
|
||||
# --- support
|
||||
|
||||
HAS_CONNECTIONS_UNIX = POSIX and not SUNOS
|
||||
HAS_CPU_AFFINITY = hasattr(psutil.Process, "cpu_affinity")
|
||||
HAS_CPU_FREQ = hasattr(psutil, "cpu_freq")
|
||||
HAS_CONNECTIONS_UNIX = POSIX and not SUNOS
|
||||
HAS_GETLOADAVG = hasattr(psutil, "getloadavg")
|
||||
HAS_ENVIRON = hasattr(psutil.Process, "environ")
|
||||
HAS_PROC_IO_COUNTERS = hasattr(psutil.Process, "io_counters")
|
||||
HAS_IONICE = hasattr(psutil.Process, "ionice")
|
||||
HAS_MEMORY_FULL_INFO = 'uss' in psutil.Process().memory_full_info()._fields
|
||||
HAS_MEMORY_MAPS = hasattr(psutil.Process, "memory_maps")
|
||||
HAS_NET_IO_COUNTERS = hasattr(psutil, "net_io_counters")
|
||||
HAS_PROC_CPU_NUM = hasattr(psutil.Process, "cpu_num")
|
||||
HAS_PROC_IO_COUNTERS = hasattr(psutil.Process, "io_counters")
|
||||
HAS_RLIMIT = hasattr(psutil.Process, "rlimit")
|
||||
HAS_THREADS = hasattr(psutil.Process, "threads")
|
||||
HAS_SENSORS_BATTERY = hasattr(psutil, "sensors_battery")
|
||||
HAS_BATTERY = HAS_SENSORS_BATTERY and psutil.sensors_battery()
|
||||
try:
|
||||
HAS_BATTERY = HAS_SENSORS_BATTERY and bool(psutil.sensors_battery())
|
||||
except Exception:
|
||||
HAS_BATTERY = True
|
||||
HAS_SENSORS_FANS = hasattr(psutil, "sensors_fans")
|
||||
HAS_SENSORS_TEMPERATURES = hasattr(psutil, "sensors_temperatures")
|
||||
HAS_THREADS = hasattr(psutil.Process, "threads")
|
||||
SKIP_SYSCONS = (MACOS or AIX) and os.getuid() != 0
|
||||
|
||||
# --- misc
|
||||
|
||||
|
@ -177,7 +193,7 @@ def _get_py_exe():
|
|||
else:
|
||||
return exe
|
||||
|
||||
if OSX:
|
||||
if MACOS:
|
||||
exe = \
|
||||
attempt(sys.executable) or \
|
||||
attempt(os.path.realpath(sys.executable)) or \
|
||||
|
@ -197,7 +213,6 @@ DEVNULL = open(os.devnull, 'r+')
|
|||
VALID_PROC_STATUSES = [getattr(psutil, x) for x in dir(psutil)
|
||||
if x.startswith('STATUS_')]
|
||||
AF_UNIX = getattr(socket, "AF_UNIX", object())
|
||||
SOCK_SEQPACKET = getattr(socket, "SOCK_SEQPACKET", object())
|
||||
|
||||
_subprocesses_started = set()
|
||||
_pids_started = set()
|
||||
|
@ -205,7 +220,7 @@ _testfiles_created = set()
|
|||
|
||||
|
||||
@atexit.register
|
||||
def _cleanup_files():
|
||||
def cleanup_test_files():
|
||||
DEVNULL.close()
|
||||
for name in os.listdir(u('.')):
|
||||
if isinstance(name, unicode):
|
||||
|
@ -226,7 +241,7 @@ def _cleanup_files():
|
|||
|
||||
# this is executed first
|
||||
@atexit.register
|
||||
def _cleanup_procs():
|
||||
def cleanup_test_procs():
|
||||
reap_children(recursive=True)
|
||||
|
||||
|
||||
|
@ -283,7 +298,7 @@ class ThreadTask(threading.Thread):
|
|||
# ===================================================================
|
||||
|
||||
|
||||
def _cleanup_on_err(fun):
|
||||
def _reap_children_on_err(fun):
|
||||
@functools.wraps(fun)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
|
@ -294,7 +309,7 @@ def _cleanup_on_err(fun):
|
|||
return wrapper
|
||||
|
||||
|
||||
@_cleanup_on_err
|
||||
@_reap_children_on_err
|
||||
def get_test_subprocess(cmd=None, **kwds):
|
||||
"""Creates a python subprocess which does nothing for 60 secs and
|
||||
return it as subprocess.Popen instance.
|
||||
|
@ -309,8 +324,11 @@ def get_test_subprocess(cmd=None, **kwds):
|
|||
kwds.setdefault("cwd", os.getcwd())
|
||||
kwds.setdefault("env", os.environ)
|
||||
if WINDOWS:
|
||||
# Prevents the subprocess to open error dialogs.
|
||||
kwds.setdefault("creationflags", 0x8000000) # CREATE_NO_WINDOW
|
||||
# Prevents the subprocess to open error dialogs. This will also
|
||||
# cause stderr to be suppressed, which is suboptimal in order
|
||||
# to debug broken tests.
|
||||
CREATE_NO_WINDOW = 0x8000000
|
||||
kwds.setdefault("creationflags", CREATE_NO_WINDOW)
|
||||
if cmd is None:
|
||||
safe_rmpath(_TESTFN)
|
||||
pyline = "from time import sleep;" \
|
||||
|
@ -327,7 +345,7 @@ def get_test_subprocess(cmd=None, **kwds):
|
|||
return sproc
|
||||
|
||||
|
||||
@_cleanup_on_err
|
||||
@_reap_children_on_err
|
||||
def create_proc_children_pair():
|
||||
"""Create a subprocess which creates another one as in:
|
||||
A (us) -> B (child) -> C (grandchild).
|
||||
|
@ -343,8 +361,8 @@ def create_proc_children_pair():
|
|||
s += "f.write(str(os.getpid()));"
|
||||
s += "f.close();"
|
||||
s += "time.sleep(60);"
|
||||
subprocess.Popen(['%s', '-c', s])
|
||||
time.sleep(60)
|
||||
p = subprocess.Popen([r'%s', '-c', s])
|
||||
p.wait()
|
||||
""" % (_TESTFN2, PYTHON_EXE))
|
||||
# On Windows if we create a subprocess with CREATE_NO_WINDOW flag
|
||||
# set (which is the default) a "conhost.exe" extra process will be
|
||||
|
@ -355,7 +373,7 @@ def create_proc_children_pair():
|
|||
subp = pyrun(s)
|
||||
child1 = psutil.Process(subp.pid)
|
||||
data = wait_for_file(_TESTFN2, delete=False, empty=False)
|
||||
os.remove(_TESTFN2)
|
||||
safe_rmpath(_TESTFN2)
|
||||
child2_pid = int(data)
|
||||
_pids_started.add(child2_pid)
|
||||
child2 = psutil.Process(child2_pid)
|
||||
|
@ -365,7 +383,7 @@ def create_proc_children_pair():
|
|||
def create_zombie_proc():
|
||||
"""Create a zombie process and return its PID."""
|
||||
assert psutil.POSIX
|
||||
unix_file = tempfile.mktemp(prefix=TESTFILE_PREFIX) if OSX else TESTFN
|
||||
unix_file = tempfile.mktemp(prefix=TESTFILE_PREFIX) if MACOS else TESTFN
|
||||
src = textwrap.dedent("""\
|
||||
import os, sys, time, socket, contextlib
|
||||
child_pid = os.fork()
|
||||
|
@ -385,7 +403,7 @@ def create_zombie_proc():
|
|||
with contextlib.closing(socket.socket(socket.AF_UNIX)) as sock:
|
||||
sock.settimeout(GLOBAL_TIMEOUT)
|
||||
sock.bind(unix_file)
|
||||
sock.listen(1)
|
||||
sock.listen(5)
|
||||
pyrun(src)
|
||||
conn, _ = sock.accept()
|
||||
try:
|
||||
|
@ -399,7 +417,7 @@ def create_zombie_proc():
|
|||
conn.close()
|
||||
|
||||
|
||||
@_cleanup_on_err
|
||||
@_reap_children_on_err
|
||||
def pyrun(src, **kwds):
|
||||
"""Run python 'src' code string in a separate interpreter.
|
||||
Returns a subprocess.Popen instance.
|
||||
|
@ -416,7 +434,7 @@ def pyrun(src, **kwds):
|
|||
return subp
|
||||
|
||||
|
||||
@_cleanup_on_err
|
||||
@_reap_children_on_err
|
||||
def sh(cmd, **kwds):
|
||||
"""run cmd in a subprocess and return its output.
|
||||
raises RuntimeError on error.
|
||||
|
@ -431,6 +449,9 @@ def sh(cmd, **kwds):
|
|||
kwds.setdefault("creationflags", flags)
|
||||
p = subprocess.Popen(cmd, **kwds)
|
||||
_subprocesses_started.add(p)
|
||||
if PY3:
|
||||
stdout, stderr = p.communicate(timeout=GLOBAL_TIMEOUT)
|
||||
else:
|
||||
stdout, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError(stderr)
|
||||
|
@ -480,7 +501,9 @@ def reap_children(recursive=False):
|
|||
try:
|
||||
subp.terminate()
|
||||
except OSError as err:
|
||||
if err.errno != errno.ESRCH:
|
||||
if WINDOWS and err.winerror == 6: # "invalid handle"
|
||||
pass
|
||||
elif err.errno != errno.ESRCH:
|
||||
raise
|
||||
if subp.stdout:
|
||||
subp.stdout.close()
|
||||
|
@ -494,9 +517,8 @@ def reap_children(recursive=False):
|
|||
# Wait for the process to terminate, to avoid zombies.
|
||||
try:
|
||||
subp.wait()
|
||||
except OSError as err:
|
||||
if err.errno != errno.ECHILD:
|
||||
raise
|
||||
except ChildProcessError:
|
||||
pass
|
||||
|
||||
# Terminate started pids.
|
||||
while _pids_started:
|
||||
|
@ -588,7 +610,7 @@ class retry(object):
|
|||
timeout=None,
|
||||
retries=None,
|
||||
interval=0.001,
|
||||
logfun=lambda s: print(s, file=sys.stderr),
|
||||
logfun=None,
|
||||
):
|
||||
if timeout and retries:
|
||||
raise ValueError("timeout and retries args are mutually exclusive")
|
||||
|
@ -621,7 +643,7 @@ class retry(object):
|
|||
for _ in self:
|
||||
try:
|
||||
return fun(*args, **kwargs)
|
||||
except self.exception as _:
|
||||
except self.exception as _: # NOQA
|
||||
exc = _
|
||||
if self.logfun is not None:
|
||||
self.logfun(exc)
|
||||
|
@ -659,7 +681,7 @@ def wait_for_file(fname, delete=True, empty=False):
|
|||
if not empty:
|
||||
assert data
|
||||
if delete:
|
||||
os.remove(fname)
|
||||
safe_rmpath(fname)
|
||||
return data
|
||||
|
||||
|
||||
|
@ -681,24 +703,43 @@ def call_until(fun, expr):
|
|||
|
||||
def safe_rmpath(path):
|
||||
"Convenience function for removing temporary test files or dirs"
|
||||
def retry_fun(fun):
|
||||
# On Windows it could happen that the file or directory has
|
||||
# open handles or references preventing the delete operation
|
||||
# to succeed immediately, so we retry for a while. See:
|
||||
# https://bugs.python.org/issue33240
|
||||
stop_at = time.time() + 1
|
||||
while time.time() < stop_at:
|
||||
try:
|
||||
return fun()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except WindowsError as _:
|
||||
err = _
|
||||
warn("ignoring %s" % (str(err)))
|
||||
time.sleep(0.01)
|
||||
raise err
|
||||
|
||||
try:
|
||||
st = os.stat(path)
|
||||
if stat.S_ISDIR(st.st_mode):
|
||||
os.rmdir(path)
|
||||
fun = functools.partial(shutil.rmtree, path)
|
||||
else:
|
||||
os.remove(path)
|
||||
except OSError as err:
|
||||
if err.errno != errno.ENOENT:
|
||||
raise
|
||||
fun = functools.partial(os.remove, path)
|
||||
if POSIX:
|
||||
fun()
|
||||
else:
|
||||
retry_fun(fun)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
def safe_mkdir(dir):
|
||||
"Convenience function for creating a directory"
|
||||
try:
|
||||
os.mkdir(dir)
|
||||
except OSError as err:
|
||||
if err.errno != errno.EEXIST:
|
||||
raise
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
|
@ -757,9 +798,11 @@ class TestCase(unittest.TestCase):
|
|||
# Print a full path representation of the single unit tests
|
||||
# being run.
|
||||
def __str__(self):
|
||||
fqmod = self.__class__.__module__
|
||||
if not fqmod.startswith('psutil.'):
|
||||
fqmod = 'psutil.tests.' + fqmod
|
||||
return "%s.%s.%s" % (
|
||||
self.__class__.__module__, self.__class__.__name__,
|
||||
self._testMethodName)
|
||||
fqmod, self.__class__.__name__, self._testMethodName)
|
||||
|
||||
# assertRaisesRegexp renamed to assertRaisesRegex in 3.3;
|
||||
# add support for the new name.
|
||||
|
@ -771,52 +814,15 @@ class TestCase(unittest.TestCase):
|
|||
unittest.TestCase = TestCase
|
||||
|
||||
|
||||
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():
|
||||
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"))]
|
||||
suite = unittest.TestSuite()
|
||||
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))
|
||||
return suite
|
||||
|
||||
|
||||
def run_suite():
|
||||
_setup_tests()
|
||||
result = unittest.TextTestRunner(verbosity=VERBOSITY).run(get_suite())
|
||||
success = result.wasSuccessful()
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
|
||||
def run_test_module_by_name(name):
|
||||
# testmodules = [os.path.splitext(x)[0] for x in os.listdir(HERE)
|
||||
# if x.endswith('.py') and x.startswith('test_')]
|
||||
_setup_tests()
|
||||
name = os.path.splitext(os.path.basename(name))[0]
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(name))
|
||||
result = unittest.TextTestRunner(verbosity=VERBOSITY).run(suite)
|
||||
success = result.wasSuccessful()
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
|
||||
def retry_before_failing(retries=NO_RETRIES):
|
||||
def retry_on_failure(retries=NO_RETRIES):
|
||||
"""Decorator which runs a test function and retries N times before
|
||||
actually failing.
|
||||
"""
|
||||
return retry(exception=AssertionError, timeout=None, retries=retries)
|
||||
def logfun(exc):
|
||||
print("%r, retrying" % exc, file=sys.stderr)
|
||||
|
||||
return retry(exception=AssertionError, timeout=None, retries=retries,
|
||||
logfun=logfun)
|
||||
|
||||
|
||||
def skip_on_access_denied(only_if=None):
|
||||
|
@ -861,7 +867,6 @@ def skip_on_not_implemented(only_if=None):
|
|||
def get_free_port(host='127.0.0.1'):
|
||||
"""Return an unused TCP port."""
|
||||
with contextlib.closing(socket.socket()) as sock:
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.bind((host, 0))
|
||||
return sock.getsockname()[1]
|
||||
|
||||
|
@ -888,10 +893,11 @@ def bind_socket(family=AF_INET, type=SOCK_STREAM, addr=None):
|
|||
addr = ("", 0)
|
||||
sock = socket.socket(family, type)
|
||||
try:
|
||||
if os.name not in ('nt', 'cygwin'):
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.bind(addr)
|
||||
if type == socket.SOCK_STREAM:
|
||||
sock.listen(10)
|
||||
sock.listen(5)
|
||||
return sock
|
||||
except Exception:
|
||||
sock.close()
|
||||
|
@ -906,7 +912,7 @@ def bind_unix_socket(name, type=socket.SOCK_STREAM):
|
|||
try:
|
||||
sock.bind(name)
|
||||
if type == socket.SOCK_STREAM:
|
||||
sock.listen(10)
|
||||
sock.listen(5)
|
||||
except Exception:
|
||||
sock.close()
|
||||
raise
|
||||
|
@ -919,7 +925,7 @@ def tcp_socketpair(family, addr=("", 0)):
|
|||
"""
|
||||
with contextlib.closing(socket.socket(family, SOCK_STREAM)) as ll:
|
||||
ll.bind(addr)
|
||||
ll.listen(10)
|
||||
ll.listen(5)
|
||||
addr = ll.getsockname()
|
||||
c = socket.socket(family, SOCK_STREAM)
|
||||
try:
|
||||
|
@ -1015,77 +1021,6 @@ def check_net_address(addr, family):
|
|||
raise ValueError("unknown family %r", family)
|
||||
|
||||
|
||||
def check_connection_ntuple(conn):
|
||||
"""Check validity of a connection namedtuple."""
|
||||
# check ntuple
|
||||
assert len(conn) in (6, 7), conn
|
||||
has_pid = len(conn) == 7
|
||||
has_fd = getattr(conn, 'fd', -1) != -1
|
||||
assert conn[0] == conn.fd
|
||||
assert conn[1] == conn.family
|
||||
assert conn[2] == conn.type
|
||||
assert conn[3] == conn.laddr
|
||||
assert conn[4] == conn.raddr
|
||||
assert conn[5] == conn.status
|
||||
if has_pid:
|
||||
assert conn[6] == conn.pid
|
||||
|
||||
# check fd
|
||||
if has_fd:
|
||||
assert conn.fd >= 0, conn
|
||||
if hasattr(socket, 'fromfd') and not WINDOWS:
|
||||
try:
|
||||
dupsock = socket.fromfd(conn.fd, conn.family, conn.type)
|
||||
except (socket.error, OSError) as err:
|
||||
if err.args[0] != errno.EBADF:
|
||||
raise
|
||||
else:
|
||||
with contextlib.closing(dupsock):
|
||||
assert dupsock.family == conn.family
|
||||
assert dupsock.type == conn.type
|
||||
|
||||
# check family
|
||||
assert conn.family in (AF_INET, AF_INET6, AF_UNIX), repr(conn.family)
|
||||
if conn.family in (AF_INET, AF_INET6):
|
||||
# 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()
|
||||
if conn.family == AF_INET:
|
||||
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:
|
||||
assert conn.status == psutil.CONN_NONE, conn.status
|
||||
|
||||
# check type (SOCK_SEQPACKET may happen in case of AF_UNIX socks)
|
||||
assert conn.type in (SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET), \
|
||||
repr(conn.type)
|
||||
if conn.type == SOCK_DGRAM:
|
||||
assert conn.status == psutil.CONN_NONE, conn.status
|
||||
|
||||
# check laddr (IP address and port sanity)
|
||||
for addr in (conn.laddr, conn.raddr):
|
||||
if conn.family in (AF_INET, AF_INET6):
|
||||
assert isinstance(addr, tuple), addr
|
||||
if not addr:
|
||||
continue
|
||||
assert isinstance(addr.port, int), addr.port
|
||||
assert 0 <= addr.port <= 65535, addr.port
|
||||
check_net_address(addr.ip, conn.family)
|
||||
elif conn.family == AF_UNIX:
|
||||
assert isinstance(addr, str), addr
|
||||
|
||||
# check status
|
||||
assert isinstance(conn.status, str), conn
|
||||
valids = [getattr(psutil, x) for x in dir(psutil) if x.startswith('CONN_')]
|
||||
assert conn.status in valids, conn
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- compatibility
|
||||
# ===================================================================
|
||||
|
@ -1149,11 +1084,12 @@ if POSIX:
|
|||
by this process, copies it in another location and loads it
|
||||
in memory via ctypes. Return the new absolutized path.
|
||||
"""
|
||||
exe = 'pypy' if PYPY else 'python'
|
||||
ext = ".so"
|
||||
dst = tempfile.mktemp(prefix=dst_prefix, suffix=ext)
|
||||
libs = [x.path for x in psutil.Process().memory_maps() if
|
||||
os.path.splitext(x.path)[1] == ext and
|
||||
'python' in x.path.lower()]
|
||||
exe in x.path.lower()]
|
||||
src = random.choice(libs)
|
||||
shutil.copyfile(src, dst)
|
||||
try:
|
||||
|
@ -1174,9 +1110,12 @@ else:
|
|||
ext = ".dll"
|
||||
dst = tempfile.mktemp(prefix=dst_prefix, suffix=ext)
|
||||
libs = [x.path for x in psutil.Process().memory_maps() if
|
||||
os.path.splitext(x.path)[1].lower() == ext and
|
||||
x.path.lower().endswith(ext) and
|
||||
'python' in os.path.basename(x.path).lower() and
|
||||
'wow64' not in x.path.lower()]
|
||||
if PYPY and not libs:
|
||||
libs = [x.path for x in psutil.Process().memory_maps() if
|
||||
'pypy' in os.path.basename(x.path).lower()]
|
||||
src = random.choice(libs)
|
||||
shutil.copyfile(src, dst)
|
||||
cfile = None
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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
|
||||
|
@ -6,91 +6,8 @@
|
|||
|
||||
"""
|
||||
Run unit tests. This is invoked by:
|
||||
|
||||
$ python -m psutil.tests
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import optparse
|
||||
import os
|
||||
import ssl
|
||||
import sys
|
||||
import tempfile
|
||||
try:
|
||||
from urllib.request import urlopen # py3
|
||||
except ImportError:
|
||||
from urllib2 import urlopen
|
||||
|
||||
from psutil.tests import PYTHON_EXE
|
||||
from psutil.tests import run_suite
|
||||
|
||||
|
||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||
GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
|
||||
TEST_DEPS = []
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
TEST_DEPS.extend(["ipaddress", "unittest2", "argparse", "mock==1.0.1"])
|
||||
elif sys.version_info[:2] == (2, 7) or sys.version_info[:2] <= (3, 2):
|
||||
TEST_DEPS.extend(["ipaddress", "mock"])
|
||||
elif sys.version_info[:2] == (3, 3):
|
||||
TEST_DEPS.extend(["ipaddress"])
|
||||
|
||||
|
||||
def install_pip():
|
||||
try:
|
||||
import pip # NOQA
|
||||
except ImportError:
|
||||
f = tempfile.NamedTemporaryFile(suffix='.py')
|
||||
with contextlib.closing(f):
|
||||
print("downloading %s to %s" % (GET_PIP_URL, f.name))
|
||||
if hasattr(ssl, '_create_unverified_context'):
|
||||
ctx = ssl._create_unverified_context()
|
||||
else:
|
||||
ctx = None
|
||||
kwargs = dict(context=ctx) if ctx else {}
|
||||
req = urlopen(GET_PIP_URL, **kwargs)
|
||||
data = req.read()
|
||||
f.write(data)
|
||||
f.flush()
|
||||
|
||||
print("installing pip")
|
||||
code = os.system('%s %s --user' % (PYTHON_EXE, f.name))
|
||||
return code
|
||||
|
||||
|
||||
def install_test_deps(deps=None):
|
||||
"""Install test dependencies via pip."""
|
||||
if deps is None:
|
||||
deps = TEST_DEPS
|
||||
deps = set(deps)
|
||||
if deps:
|
||||
is_venv = hasattr(sys, 'real_prefix')
|
||||
opts = "--user" if not is_venv else ""
|
||||
install_pip()
|
||||
code = os.system('%s -m pip install %s --upgrade %s' % (
|
||||
PYTHON_EXE, opts, " ".join(deps)))
|
||||
return code
|
||||
|
||||
|
||||
def main():
|
||||
usage = "%s -m psutil.tests [opts]" % PYTHON_EXE
|
||||
parser = optparse.OptionParser(usage=usage, description="run unit tests")
|
||||
parser.add_option("-i", "--install-deps",
|
||||
action="store_true", default=False,
|
||||
help="don't print status messages to stdout")
|
||||
|
||||
opts, args = parser.parse_args()
|
||||
if opts.install_deps:
|
||||
install_pip()
|
||||
install_test_deps()
|
||||
else:
|
||||
for dep in TEST_DEPS:
|
||||
try:
|
||||
__import__(dep.split("==")[0])
|
||||
except ImportError:
|
||||
sys.exit("%r lib is not installed; run %s -m psutil.tests "
|
||||
"--install-deps" % (dep, PYTHON_EXE))
|
||||
run_suite()
|
||||
|
||||
|
||||
from .runner import main
|
||||
main()
|
||||
|
|
|
@ -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()
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'
|
||||
# Copyright (c) 2017, Arnon Yaari
|
||||
|
@ -11,7 +11,6 @@
|
|||
import re
|
||||
|
||||
from psutil import AIX
|
||||
from psutil.tests import run_test_module_by_name
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
import psutil
|
||||
|
@ -22,9 +21,9 @@ class AIXSpecificTestCase(unittest.TestCase):
|
|||
|
||||
def test_virtual_memory(self):
|
||||
out = sh('/usr/bin/svmon -O unit=KB')
|
||||
re_pattern = "memory\s*"
|
||||
re_pattern = r"memory\s*"
|
||||
for field in ("size inuse free pin virtual available mmode").split():
|
||||
re_pattern += "(?P<%s>\S+)\s+" % (field,)
|
||||
re_pattern += r"(?P<%s>\S+)\s+" % (field,)
|
||||
matchobj = re.search(re_pattern, out)
|
||||
|
||||
self.assertIsNotNone(
|
||||
|
@ -56,10 +55,10 @@ class AIXSpecificTestCase(unittest.TestCase):
|
|||
# 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("(?P<space>\S+)\s+"
|
||||
"(?P<vol>\S+)\s+"
|
||||
"(?P<vg>\S+)\s+"
|
||||
"(?P<size>\d+)MB", out)
|
||||
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")
|
||||
|
@ -74,11 +73,11 @@ class AIXSpecificTestCase(unittest.TestCase):
|
|||
def test_cpu_stats(self):
|
||||
out = sh('/usr/bin/mpstat -a')
|
||||
|
||||
re_pattern = "ALL\s*"
|
||||
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 += "(?P<%s>\S+)\s+" % (field,)
|
||||
re_pattern += r"(?P<%s>\S+)\s+" % (field,)
|
||||
matchobj = re.search(re_pattern, out)
|
||||
|
||||
self.assertIsNotNone(
|
||||
|
@ -106,7 +105,7 @@ class AIXSpecificTestCase(unittest.TestCase):
|
|||
|
||||
def test_cpu_count_logical(self):
|
||||
out = sh('/usr/bin/mpstat -a')
|
||||
mpstat_lcpu = int(re.search("lcpu=(\d+)", out).group(1))
|
||||
mpstat_lcpu = int(re.search(r"lcpu=(\d+)", out).group(1))
|
||||
psutil_lcpu = psutil.cpu_count(logical=True)
|
||||
self.assertEqual(mpstat_lcpu, psutil_lcpu)
|
||||
|
||||
|
@ -118,4 +117,5 @@ class AIXSpecificTestCase(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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
|
||||
|
@ -24,8 +24,7 @@ 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_before_failing
|
||||
from psutil.tests import run_test_module_by_name
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
from psutil.tests import which
|
||||
|
@ -73,7 +72,7 @@ def muse(field):
|
|||
|
||||
|
||||
@unittest.skipIf(not BSD, "BSD only")
|
||||
class BSDSpecificTestCase(unittest.TestCase):
|
||||
class BSDTestCase(unittest.TestCase):
|
||||
"""Generic tests common to all BSD variants."""
|
||||
|
||||
@classmethod
|
||||
|
@ -149,7 +148,7 @@ class BSDSpecificTestCase(unittest.TestCase):
|
|||
|
||||
|
||||
@unittest.skipIf(not FREEBSD, "FREEBSD only")
|
||||
class FreeBSDSpecificTestCase(unittest.TestCase):
|
||||
class FreeBSDProcessTestCase(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
@ -159,8 +158,8 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
|
||||
@retry_before_failing()
|
||||
def test_proc_memory_maps(self):
|
||||
@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:]
|
||||
|
@ -174,17 +173,17 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
if not map.path.startswith('['):
|
||||
self.assertEqual(fields[10], map.path)
|
||||
|
||||
def test_proc_exe(self):
|
||||
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_proc_cmdline(self):
|
||||
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_proc_uids_gids(self):
|
||||
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)
|
||||
|
@ -197,8 +196,8 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
self.assertEqual(gids.effective, int(egid))
|
||||
self.assertEqual(gids.saved, int(sgid))
|
||||
|
||||
@retry_before_failing()
|
||||
def test_proc_ctx_switches(self):
|
||||
@retry_on_failure()
|
||||
def test_ctx_switches(self):
|
||||
tested = []
|
||||
out = sh('procstat -r %s' % self.pid)
|
||||
p = psutil.Process(self.pid)
|
||||
|
@ -217,8 +216,8 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
if len(tested) != 2:
|
||||
raise RuntimeError("couldn't find lines match in procstat out")
|
||||
|
||||
@retry_before_failing()
|
||||
def test_proc_cpu_times(self):
|
||||
@retry_on_failure()
|
||||
def test_cpu_times(self):
|
||||
tested = []
|
||||
out = sh('procstat -r %s' % self.pid)
|
||||
p = psutil.Process(self.pid)
|
||||
|
@ -237,39 +236,76 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
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_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@retry_on_failure()
|
||||
def test_vmem_buffers(self):
|
||||
syst = sysctl("vfs.bufspace")
|
||||
self.assertAlmostEqual(psutil.virtual_memory().buffers, syst,
|
||||
|
@ -283,42 +319,42 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
self.assertEqual(psutil.virtual_memory().total, num)
|
||||
|
||||
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||
@retry_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@retry_on_failure()
|
||||
def test_muse_vmem_buffers(self):
|
||||
num = muse('Buffer')
|
||||
self.assertAlmostEqual(psutil.virtual_memory().buffers, num,
|
||||
|
@ -336,14 +372,33 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
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=1000)
|
||||
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):
|
||||
|
@ -397,6 +452,26 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
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
|
||||
|
@ -404,7 +479,7 @@ class FreeBSDSpecificTestCase(unittest.TestCase):
|
|||
|
||||
|
||||
@unittest.skipIf(not OPENBSD, "OPENBSD only")
|
||||
class OpenBSDSpecificTestCase(unittest.TestCase):
|
||||
class OpenBSDTestCase(unittest.TestCase):
|
||||
|
||||
def test_boot_time(self):
|
||||
s = sysctl('kern.boottime')
|
||||
|
@ -419,11 +494,11 @@ class OpenBSDSpecificTestCase(unittest.TestCase):
|
|||
|
||||
|
||||
@unittest.skipIf(not NETBSD, "NETBSD only")
|
||||
class NetBSDSpecificTestCase(unittest.TestCase):
|
||||
class NetBSDTestCase(unittest.TestCase):
|
||||
|
||||
@staticmethod
|
||||
def parse_meminfo(look_for):
|
||||
with open('/proc/meminfo', 'rb') as f:
|
||||
with open('/proc/meminfo', 'rt') as f:
|
||||
for line in f:
|
||||
if line.startswith(look_for):
|
||||
return int(line.split()[1]) * 1024
|
||||
|
@ -486,4 +561,5 @@ class NetBSDSpecificTestCase(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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
|
||||
|
@ -6,6 +6,8 @@
|
|||
|
||||
"""Tests for net_connections() and Process.connections() APIs."""
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
import os
|
||||
import socket
|
||||
import textwrap
|
||||
|
@ -18,9 +20,9 @@ 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 OSX
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil import WINDOWS
|
||||
|
@ -29,15 +31,17 @@ 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_connection_ntuple
|
||||
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 run_test_module_by_name
|
||||
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
|
||||
|
@ -48,29 +52,147 @@ from psutil.tests import wait_for_file
|
|||
|
||||
|
||||
thisproc = psutil.Process()
|
||||
SOCK_SEQPACKET = getattr(socket, "SOCK_SEQPACKET", object())
|
||||
|
||||
|
||||
class Base(object):
|
||||
|
||||
def setUp(self):
|
||||
if not NETBSD:
|
||||
# NetBSD opens a UNIX socket to /var/log/run.
|
||||
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 NETBSD:
|
||||
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:
|
||||
if NETBSD or FREEBSD:
|
||||
# NetBSD opens a UNIX socket to /var/log/run
|
||||
# so there may be more connections.
|
||||
return smap[sock.fileno()]
|
||||
|
@ -80,14 +202,13 @@ class Base(object):
|
|||
self.assertEqual(smap[sock.fileno()].fd, sock.fileno())
|
||||
return cons[0]
|
||||
|
||||
def check_socket(self, sock, conn=None):
|
||||
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).
|
||||
"""
|
||||
if conn is None:
|
||||
conn = self.get_conn_from_sock(sock)
|
||||
check_connection_ntuple(conn)
|
||||
self.check_connection_ntuple(conn)
|
||||
|
||||
# fd, family, type
|
||||
if conn.fd != -1:
|
||||
|
@ -113,38 +234,9 @@ class Base(object):
|
|||
# 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)
|
||||
self.compare_procsys_connections(os.getpid(), cons, kind='all')
|
||||
return conn
|
||||
|
||||
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 OSX, system-wide connections are retrieved by iterating
|
||||
# over all processes
|
||||
if OSX:
|
||||
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)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- Test unconnected sockets
|
||||
# =====================================================================
|
||||
|
||||
|
||||
class TestUnconnectedSockets(Base, unittest.TestCase):
|
||||
"""Tests sockets which are open but not connected to anything."""
|
||||
|
||||
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:
|
||||
|
@ -192,12 +284,7 @@ class TestUnconnectedSockets(Base, unittest.TestCase):
|
|||
self.assertEqual(conn.status, psutil.CONN_NONE)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- Test connected sockets
|
||||
# =====================================================================
|
||||
|
||||
|
||||
class TestConnectedSocketPairs(Base, unittest.TestCase):
|
||||
class TestConnectedSocket(Base, unittest.TestCase):
|
||||
"""Test socket pairs which are are actually connected to
|
||||
each other.
|
||||
"""
|
||||
|
@ -232,11 +319,14 @@ class TestConnectedSocketPairs(Base, unittest.TestCase):
|
|||
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:
|
||||
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']
|
||||
self.assertEqual(len(cons), 2)
|
||||
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, "")
|
||||
|
@ -257,12 +347,58 @@ class TestConnectedSocketPairs(Base, unittest.TestCase):
|
|||
server.close()
|
||||
client.close()
|
||||
|
||||
@skip_on_access_denied(only_if=OSX)
|
||||
|
||||
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")
|
||||
check_connection_ntuple(conn)
|
||||
self.check_connection_ntuple(conn)
|
||||
self.assertEqual(conn.family, family)
|
||||
self.assertEqual(conn.type, type)
|
||||
self.assertEqual(conn.laddr, laddr)
|
||||
|
@ -284,7 +420,7 @@ class TestConnectedSocketPairs(Base, unittest.TestCase):
|
|||
import socket, time
|
||||
s = socket.socket($family, socket.SOCK_STREAM)
|
||||
s.bind(('$addr', 0))
|
||||
s.listen(1)
|
||||
s.listen(5)
|
||||
with open('$testfn', 'w') as f:
|
||||
f.write(str(s.getsockname()[:2]))
|
||||
time.sleep(60)
|
||||
|
@ -352,13 +488,8 @@ class TestConnectedSocketPairs(Base, unittest.TestCase):
|
|||
psutil.CONN_NONE,
|
||||
("all", "inet", "inet6", "udp", "udp6"))
|
||||
|
||||
# err
|
||||
self.assertRaises(ValueError, p.connections, kind='???')
|
||||
|
||||
def test_multi_sockets_filtering(self):
|
||||
with create_sockets() as socks:
|
||||
cons = thisproc.connections(kind='all')
|
||||
self.assertEqual(len(cons), len(socks))
|
||||
def test_count(self):
|
||||
with create_sockets():
|
||||
# tcp
|
||||
cons = thisproc.connections(kind='tcp')
|
||||
self.assertEqual(len(cons), 2 if supports_ipv6() else 1)
|
||||
|
@ -406,8 +537,9 @@ class TestConnectedSocketPairs(Base, unittest.TestCase):
|
|||
for conn in cons:
|
||||
self.assertEqual(conn.family, AF_INET6)
|
||||
self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM))
|
||||
# unix
|
||||
if HAS_CONNECTIONS_UNIX:
|
||||
# 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:
|
||||
|
@ -415,23 +547,17 @@ class TestConnectedSocketPairs(Base, unittest.TestCase):
|
|||
self.assertIn(conn.type, (SOCK_STREAM, SOCK_DGRAM))
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- Miscellaneous tests
|
||||
# =====================================================================
|
||||
|
||||
|
||||
@unittest.skipIf(SKIP_SYSCONS, "requires root")
|
||||
class TestSystemWideConnections(Base, unittest.TestCase):
|
||||
"""Tests for net_connections()."""
|
||||
|
||||
@skip_on_access_denied()
|
||||
def test_it(self):
|
||||
def check(cons, families, types_):
|
||||
AF_UNIX = getattr(socket, 'AF_UNIX', object())
|
||||
for conn in cons:
|
||||
self.assertIn(conn.family, families, msg=conn)
|
||||
if conn.family != AF_UNIX:
|
||||
self.assertIn(conn.type, types_, msg=conn)
|
||||
check_connection_ntuple(conn)
|
||||
self.check_connection_ntuple(conn)
|
||||
|
||||
with create_sockets():
|
||||
from psutil._common import conn_tmap
|
||||
|
@ -444,18 +570,8 @@ class TestSystemWideConnections(Base, unittest.TestCase):
|
|||
self.assertEqual(len(cons), len(set(cons)))
|
||||
check(cons, families, types_)
|
||||
|
||||
self.assertRaises(ValueError, psutil.net_connections, kind='???')
|
||||
|
||||
@skip_on_access_denied()
|
||||
def test_multi_socks(self):
|
||||
with create_sockets() as socks:
|
||||
cons = [x for x in psutil.net_connections(kind='all')
|
||||
if x.pid == os.getpid()]
|
||||
self.assertEqual(len(cons), len(socks))
|
||||
|
||||
@skip_on_access_denied()
|
||||
# See: https://travis-ci.org/giampaolo/psutil/jobs/237566297
|
||||
@unittest.skipIf(OSX and TRAVIS, "unreliable on OSX + TRAVIS")
|
||||
@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()
|
||||
|
@ -473,7 +589,7 @@ class TestSystemWideConnections(Base, unittest.TestCase):
|
|||
import time, os
|
||||
from psutil.tests import create_sockets
|
||||
with create_sockets():
|
||||
with open('%s', 'w') as f:
|
||||
with open(r'%s', 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
time.sleep(60)
|
||||
""" % fname)
|
||||
|
@ -495,11 +611,6 @@ class TestSystemWideConnections(Base, unittest.TestCase):
|
|||
self.assertEqual(len(p.connections('all')), expected)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- Miscellaneous tests
|
||||
# =====================================================================
|
||||
|
||||
|
||||
class TestMisc(unittest.TestCase):
|
||||
|
||||
def test_connection_constants(self):
|
||||
|
@ -522,4 +633,5 @@ class TestMisc(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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
|
||||
|
@ -14,35 +14,32 @@ import os
|
|||
import stat
|
||||
import time
|
||||
import traceback
|
||||
import warnings
|
||||
from contextlib import closing
|
||||
|
||||
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 callable
|
||||
from psutil._compat import long
|
||||
from psutil.tests import bind_unix_socket
|
||||
from psutil.tests import check_connection_ntuple
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import enum
|
||||
from psutil.tests import get_kernel_version
|
||||
from psutil.tests import HAS_CONNECTIONS_UNIX
|
||||
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 run_test_module_by_name
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import SKIP_SYSCONS
|
||||
from psutil.tests import TESTFN
|
||||
from psutil.tests import unittest
|
||||
from psutil.tests import unix_socket_path
|
||||
from psutil.tests import VALID_PROC_STATUSES
|
||||
from psutil.tests import warn
|
||||
import psutil
|
||||
|
@ -52,19 +49,10 @@ import psutil
|
|||
# --- APIs availability
|
||||
# ===================================================================
|
||||
|
||||
# Make sure code reflects what doc promises in terms of APIs
|
||||
# availability.
|
||||
|
||||
class TestAvailability(unittest.TestCase):
|
||||
"""Make sure code reflects what doc promises in terms of APIs
|
||||
availability.
|
||||
"""
|
||||
|
||||
def test_cpu_affinity(self):
|
||||
hasit = LINUX or WINDOWS or FREEBSD
|
||||
self.assertEqual(hasattr(psutil.Process, "cpu_affinity"), hasit)
|
||||
|
||||
def test_win_service(self):
|
||||
self.assertEqual(hasattr(psutil, "win_service_iter"), WINDOWS)
|
||||
self.assertEqual(hasattr(psutil, "win_service_get"), WINDOWS)
|
||||
class TestAvailConstantsAPIs(unittest.TestCase):
|
||||
|
||||
def test_PROCFS_PATH(self):
|
||||
self.assertEqual(hasattr(psutil, "PROCFS_PATH"),
|
||||
|
@ -79,13 +67,20 @@ class TestAvailability(unittest.TestCase):
|
|||
ae(hasattr(psutil, "NORMAL_PRIORITY_CLASS"), WINDOWS)
|
||||
ae(hasattr(psutil, "REALTIME_PRIORITY_CLASS"), WINDOWS)
|
||||
|
||||
def test_linux_ioprio(self):
|
||||
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)
|
||||
|
@ -110,78 +105,77 @@ class TestAvailability(unittest.TestCase):
|
|||
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 OSX or WINDOWS)
|
||||
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)
|
||||
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 OSX)
|
||||
LINUX or WINDOWS or FREEBSD or MACOS)
|
||||
|
||||
def test_proc_environ(self):
|
||||
|
||||
class TestAvailProcessAPIs(unittest.TestCase):
|
||||
|
||||
def test_environ(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "environ"),
|
||||
LINUX or OSX or WINDOWS)
|
||||
LINUX or MACOS or WINDOWS or AIX or SUNOS)
|
||||
|
||||
def test_proc_uids(self):
|
||||
def test_uids(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "uids"), POSIX)
|
||||
|
||||
def test_proc_gids(self):
|
||||
def test_gids(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "uids"), POSIX)
|
||||
|
||||
def test_proc_terminal(self):
|
||||
def test_terminal(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "terminal"), POSIX)
|
||||
|
||||
def test_proc_ionice(self):
|
||||
def test_ionice(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "ionice"), LINUX or WINDOWS)
|
||||
|
||||
def test_proc_rlimit(self):
|
||||
def test_rlimit(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "rlimit"), LINUX)
|
||||
|
||||
def test_proc_io_counters(self):
|
||||
def test_io_counters(self):
|
||||
hasit = hasattr(psutil.Process, "io_counters")
|
||||
self.assertEqual(hasit, False if OSX or SUNOS else True)
|
||||
self.assertEqual(hasit, False if MACOS or SUNOS else True)
|
||||
|
||||
def test_proc_num_fds(self):
|
||||
def test_num_fds(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "num_fds"), POSIX)
|
||||
|
||||
def test_proc_num_handles(self):
|
||||
def test_num_handles(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "num_handles"), WINDOWS)
|
||||
|
||||
def test_proc_cpu_affinity(self):
|
||||
def test_cpu_affinity(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "cpu_affinity"),
|
||||
LINUX or WINDOWS or FREEBSD)
|
||||
|
||||
def test_proc_cpu_num(self):
|
||||
def test_cpu_num(self):
|
||||
self.assertEqual(hasattr(psutil.Process, "cpu_num"),
|
||||
LINUX or FREEBSD or SUNOS)
|
||||
|
||||
def test_proc_memory_maps(self):
|
||||
def test_memory_maps(self):
|
||||
hasit = hasattr(psutil.Process, "memory_maps")
|
||||
self.assertEqual(hasit, False if OPENBSD or NETBSD or AIX else True)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# --- Test deprecations
|
||||
# ===================================================================
|
||||
|
||||
|
||||
class TestDeprecations(unittest.TestCase):
|
||||
|
||||
def test_memory_info_ex(self):
|
||||
with warnings.catch_warnings(record=True) as ws:
|
||||
psutil.Process().memory_info_ex()
|
||||
w = ws[0]
|
||||
self.assertIsInstance(w.category(), FutureWarning)
|
||||
self.assertIn("memory_info_ex() is deprecated", str(w.message))
|
||||
self.assertIn("use memory_info() instead", str(w.message))
|
||||
self.assertEqual(
|
||||
hasit, False if OPENBSD or NETBSD or AIX or MACOS else True)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
|
@ -189,7 +183,7 @@ class TestDeprecations(unittest.TestCase):
|
|||
# ===================================================================
|
||||
|
||||
|
||||
class TestSystem(unittest.TestCase):
|
||||
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
|
||||
|
@ -202,18 +196,40 @@ class TestSystem(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
safe_rmpath(TESTFN)
|
||||
|
||||
def test_cpu_times(self):
|
||||
# Duplicate of test_system.py. Keep it anyway.
|
||||
ret = psutil.cpu_times()
|
||||
assert is_namedtuple(ret)
|
||||
for n in ret:
|
||||
self.assertIsInstance(n, float)
|
||||
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_io_counters(self):
|
||||
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 in psutil.disk_io_counters(perdisk=True):
|
||||
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.
|
||||
|
@ -223,31 +239,40 @@ class TestSystem(unittest.TestCase):
|
|||
self.assertIsInstance(disk.fstype, str)
|
||||
self.assertIsInstance(disk.opts, str)
|
||||
|
||||
@unittest.skipIf(not POSIX, 'POSIX only')
|
||||
@unittest.skipIf(not HAS_CONNECTIONS_UNIX, "can't list UNIX sockets")
|
||||
@skip_on_access_denied(only_if=OSX)
|
||||
@unittest.skipIf(SKIP_SYSCONS, "requires root")
|
||||
def test_net_connections(self):
|
||||
with unix_socket_path() as name:
|
||||
with closing(bind_unix_socket(name)):
|
||||
cons = psutil.net_connections(kind='unix')
|
||||
assert cons
|
||||
for conn in cons:
|
||||
self.assertIsInstance(conn.laddr, str)
|
||||
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, _ in psutil.net_if_stats().items():
|
||||
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():
|
||||
|
@ -260,6 +285,7 @@ class TestSystem(unittest.TestCase):
|
|||
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):
|
||||
|
@ -268,6 +294,13 @@ class TestSystem(unittest.TestCase):
|
|||
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.
|
||||
|
@ -288,21 +321,11 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
some sanity checks against Process API's returned values.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
if POSIX:
|
||||
import pwd
|
||||
import grp
|
||||
users = pwd.getpwall()
|
||||
groups = grp.getgrall()
|
||||
self.all_uids = set([x.pw_uid for x in users])
|
||||
self.all_usernames = set([x.pw_name for x in users])
|
||||
self.all_gids = set([x.gr_gid for x in groups])
|
||||
|
||||
def test_fetch_all(self):
|
||||
valid_procs = 0
|
||||
def get_attr_names(self):
|
||||
excluded_names = set([
|
||||
'send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
|
||||
'as_dict', 'parent', 'children', 'memory_info_ex', 'oneshot',
|
||||
'as_dict', 'parent', 'parents', 'children', 'memory_info_ex',
|
||||
'oneshot',
|
||||
])
|
||||
if LINUX and not HAS_RLIMIT:
|
||||
excluded_names.add('rlimit')
|
||||
|
@ -313,14 +336,16 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
if name in excluded_names:
|
||||
continue
|
||||
attrs.append(name)
|
||||
return attrs
|
||||
|
||||
default = object()
|
||||
failures = []
|
||||
def iter_procs(self):
|
||||
attrs = self.get_attr_names()
|
||||
for p in psutil.process_iter():
|
||||
with p.oneshot():
|
||||
for name in attrs:
|
||||
ret = default
|
||||
try:
|
||||
yield (p, name)
|
||||
|
||||
def call_meth(self, p, name):
|
||||
args = ()
|
||||
kwargs = {}
|
||||
attr = getattr(p, name, None)
|
||||
|
@ -329,10 +354,18 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
args = (psutil.RLIMIT_NOFILE,)
|
||||
elif name == 'memory_maps':
|
||||
kwargs = {'grouped': False}
|
||||
ret = attr(*args, **kwargs)
|
||||
return attr(*args, **kwargs)
|
||||
else:
|
||||
ret = attr
|
||||
valid_procs += 1
|
||||
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)
|
||||
|
@ -345,7 +378,7 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
self.assertEqual(err.name, p.name())
|
||||
assert str(err)
|
||||
assert err.msg
|
||||
except Exception as err:
|
||||
except Exception:
|
||||
s = '\n' + '=' * 70 + '\n'
|
||||
s += "FAIL: test_%s (proc=%s" % (name, p)
|
||||
if ret != default:
|
||||
|
@ -358,6 +391,7 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
failures.append(s)
|
||||
break
|
||||
else:
|
||||
valid_procs += 1
|
||||
if ret not in (0, 0.0, [], None, '', {}):
|
||||
assert ret, ret
|
||||
meth = getattr(self, name)
|
||||
|
@ -380,13 +414,15 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
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 OSX
|
||||
# XXX may fail on MACOS
|
||||
assert os.access(ret, os.X_OK)
|
||||
|
||||
def pid(self, ret, proc):
|
||||
|
@ -424,7 +460,6 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
for uid in ret:
|
||||
self.assertIsInstance(uid, int)
|
||||
self.assertGreaterEqual(uid, 0)
|
||||
self.assertIn(uid, self.all_uids)
|
||||
|
||||
def gids(self, ret, proc):
|
||||
assert is_namedtuple(ret)
|
||||
|
@ -432,15 +467,12 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
# gid == 30 (nodoby); not sure why.
|
||||
for gid in ret:
|
||||
self.assertIsInstance(gid, int)
|
||||
if not OSX and not NETBSD:
|
||||
if not MACOS and not NETBSD:
|
||||
self.assertGreaterEqual(gid, 0)
|
||||
self.assertIn(gid, self.all_gids)
|
||||
|
||||
def username(self, ret, proc):
|
||||
self.assertIsInstance(ret, str)
|
||||
assert ret
|
||||
if POSIX:
|
||||
self.assertIn(ret, self.all_usernames)
|
||||
|
||||
def status(self, ret, proc):
|
||||
self.assertIsInstance(ret, str)
|
||||
|
@ -456,16 +488,20 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
self.assertGreaterEqual(field, 0)
|
||||
|
||||
def ionice(self, ret, proc):
|
||||
if POSIX:
|
||||
assert is_namedtuple(ret)
|
||||
for field in ret:
|
||||
self.assertIsInstance(field, int)
|
||||
if LINUX:
|
||||
self.assertIsInstance(ret.ioclass, int)
|
||||
self.assertIsInstance(ret.value, int)
|
||||
self.assertGreaterEqual(ret.ioclass, 0)
|
||||
self.assertGreaterEqual(ret.value, 0)
|
||||
else:
|
||||
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, (0, 1, 2))
|
||||
self.assertIn(ret, choices)
|
||||
|
||||
def num_threads(self, ret, proc):
|
||||
self.assertIsInstance(ret, int)
|
||||
|
@ -506,13 +542,7 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
for value in ret:
|
||||
self.assertIsInstance(value, (int, long))
|
||||
self.assertGreaterEqual(value, 0)
|
||||
if POSIX and not AIX and ret.vms != 0:
|
||||
# VMS is always supposed to be the highest
|
||||
for name in ret._fields:
|
||||
if name != 'vms':
|
||||
value = getattr(ret, name)
|
||||
self.assertGreater(ret.vms, value, msg=ret)
|
||||
elif WINDOWS:
|
||||
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)
|
||||
|
@ -525,6 +555,10 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
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:
|
||||
|
@ -555,9 +589,10 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
self.assertGreaterEqual(ret, 0)
|
||||
|
||||
def connections(self, ret, proc):
|
||||
with create_sockets():
|
||||
self.assertEqual(len(ret), len(set(ret)))
|
||||
for conn in ret:
|
||||
check_connection_ntuple(conn)
|
||||
assert is_namedtuple(conn)
|
||||
|
||||
def cwd(self, ret, proc):
|
||||
if ret: # 'ret' can be None or empty
|
||||
|
@ -609,8 +644,11 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
# commented as on Linux we might get
|
||||
# '/foo/bar (deleted)'
|
||||
# assert os.path.exists(nt.path), nt.path
|
||||
elif fname in ('addr', 'perms'):
|
||||
assert value
|
||||
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)
|
||||
|
@ -648,4 +686,5 @@ class TestFetchAllProcesses(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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
|
||||
|
@ -11,10 +11,11 @@ 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 errno
|
||||
import functools
|
||||
import gc
|
||||
import os
|
||||
|
@ -24,13 +25,17 @@ 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 OSX
|
||||
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
|
||||
|
@ -38,14 +43,15 @@ 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 run_test_module_by_name
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import skip_on_access_denied
|
||||
from psutil.tests import TESTFN
|
||||
|
@ -53,14 +59,14 @@ from psutil.tests import TRAVIS
|
|||
from psutil.tests import unittest
|
||||
|
||||
|
||||
# configurable opts
|
||||
LOOPS = 1000
|
||||
MEMORY_TOLERANCE = 4096
|
||||
RETRY_FOR = 3
|
||||
SKIP_PYTHON_IMPL = True
|
||||
|
||||
SKIP_PYTHON_IMPL = True if TRAVIS else False
|
||||
cext = psutil._psplatform.cext
|
||||
thisproc = psutil.Process()
|
||||
SKIP_PYTHON_IMPL = True if TRAVIS else False
|
||||
|
||||
|
||||
# ===================================================================
|
||||
|
@ -73,25 +79,7 @@ def skip_if_linux():
|
|||
"worthless on LINUX (pure python)")
|
||||
|
||||
|
||||
def bytes2human(n):
|
||||
"""
|
||||
http://code.activestate.com/recipes/578019
|
||||
>>> bytes2human(10000)
|
||||
'9.8K'
|
||||
>>> bytes2human(100001221)
|
||||
'95.4M'
|
||||
"""
|
||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
||||
prefix = {}
|
||||
for i, s in enumerate(symbols):
|
||||
prefix[s] = 1 << (i + 1) * 10
|
||||
for s in reversed(symbols):
|
||||
if n >= prefix[s]:
|
||||
value = float(n) / prefix[s]
|
||||
return '%.2f%s' % (value, s)
|
||||
return "%sB" % n
|
||||
|
||||
|
||||
@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
|
||||
|
@ -176,7 +164,7 @@ class TestMemLeak(unittest.TestCase):
|
|||
def _get_mem():
|
||||
# By using USS memory it seems it's less likely to bump
|
||||
# into false positives.
|
||||
if LINUX or WINDOWS or OSX:
|
||||
if LINUX or WINDOWS or MACOS:
|
||||
return thisproc.memory_full_info().uss
|
||||
else:
|
||||
return thisproc.memory_info().rss
|
||||
|
@ -200,8 +188,8 @@ class TestProcessObjectLeaks(TestMemLeak):
|
|||
skip = set((
|
||||
"pid", "as_dict", "children", "cpu_affinity", "cpu_percent",
|
||||
"ionice", "is_running", "kill", "memory_info_ex", "memory_percent",
|
||||
"nice", "oneshot", "parent", "rlimit", "send_signal", "suspend",
|
||||
"terminate", "wait"))
|
||||
"nice", "oneshot", "parent", "parents", "rlimit", "send_signal",
|
||||
"suspend", "terminate", "wait"))
|
||||
for name in dir(psutil.Process):
|
||||
if name.startswith('_'):
|
||||
continue
|
||||
|
@ -344,8 +332,6 @@ class TestProcessObjectLeaks(TestMemLeak):
|
|||
with open(TESTFN, 'w'):
|
||||
self.execute(self.proc.open_files)
|
||||
|
||||
# OSX implementation is unbelievably slow
|
||||
@unittest.skipIf(OSX, "too slow on OSX")
|
||||
@unittest.skipIf(not HAS_MEMORY_MAPS, "not supported")
|
||||
@skip_if_linux()
|
||||
def test_memory_maps(self):
|
||||
|
@ -384,6 +370,16 @@ class TestProcessObjectLeaks(TestMemLeak):
|
|||
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.
|
||||
|
@ -432,9 +428,8 @@ class TestTerminatedProcessLeaks(TestProcessObjectLeaks):
|
|||
def call():
|
||||
try:
|
||||
return cext.proc_info(self.proc.pid)
|
||||
except OSError as err:
|
||||
if err.errno != errno.ESRCH:
|
||||
raise
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
|
||||
self.execute(call)
|
||||
|
||||
|
@ -476,6 +471,7 @@ class TestModuleFunctionsLeaks(TestMemLeak):
|
|||
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)
|
||||
|
||||
|
@ -484,14 +480,17 @@ class TestModuleFunctionsLeaks(TestMemLeak):
|
|||
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)")
|
||||
@unittest.skipIf(SUNOS, "worthless on SUNOS (uses a subprocess)")
|
||||
def test_swap_memory(self):
|
||||
self.execute(psutil.swap_memory)
|
||||
|
||||
|
@ -524,13 +523,15 @@ class TestModuleFunctionsLeaks(TestMemLeak):
|
|||
|
||||
# --- 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)
|
||||
|
||||
@unittest.skipIf(LINUX,
|
||||
"worthless on Linux (pure python)")
|
||||
@unittest.skipIf(OSX and os.getuid() != 0, "need root access")
|
||||
@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)
|
||||
|
@ -567,7 +568,6 @@ class TestModuleFunctionsLeaks(TestMemLeak):
|
|||
def test_boot_time(self):
|
||||
self.execute(psutil.boot_time)
|
||||
|
||||
# XXX - on Windows this produces a false positive
|
||||
@unittest.skipIf(WINDOWS, "XXX produces a false positive on Windows")
|
||||
def test_users(self):
|
||||
self.execute(psutil.users)
|
||||
|
@ -596,4 +596,5 @@ class TestModuleFunctionsLeaks(TestMemLeak):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
|
@ -19,19 +19,24 @@ import pickle
|
|||
import socket
|
||||
import stat
|
||||
|
||||
from psutil import FREEBSD
|
||||
from psutil import LINUX
|
||||
from psutil import NETBSD
|
||||
from psutil import POSIX
|
||||
from psutil import WINDOWS
|
||||
from psutil._common import memoize
|
||||
from psutil._common import memoize_when_activated
|
||||
from psutil._common import supports_ipv6
|
||||
from psutil._common import wrap_numbers
|
||||
from psutil._common import open_text
|
||||
from psutil._common import open_binary
|
||||
from psutil._compat import PY3
|
||||
from psutil.tests import APPVEYOR
|
||||
from psutil.tests import bind_socket
|
||||
from psutil.tests import bind_unix_socket
|
||||
from psutil.tests import call_until
|
||||
from psutil.tests import chdir
|
||||
from psutil.tests import CI_TESTING
|
||||
from psutil.tests import create_proc_children_pair
|
||||
from psutil.tests import create_sockets
|
||||
from psutil.tests import create_zombie_proc
|
||||
|
@ -40,8 +45,8 @@ from psutil.tests import get_free_port
|
|||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import HAS_BATTERY
|
||||
from psutil.tests import HAS_CONNECTIONS_UNIX
|
||||
from psutil.tests import HAS_MEMORY_FULL_INFO
|
||||
from psutil.tests import HAS_MEMORY_MAPS
|
||||
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
|
||||
|
@ -53,7 +58,7 @@ from psutil.tests import reap_children
|
|||
from psutil.tests import reload_module
|
||||
from psutil.tests import retry
|
||||
from psutil.tests import ROOT_DIR
|
||||
from psutil.tests import run_test_module_by_name
|
||||
from psutil.tests import safe_mkdir
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import SCRIPTS_DIR
|
||||
from psutil.tests import sh
|
||||
|
@ -177,7 +182,8 @@ class TestMisc(unittest.TestCase):
|
|||
for name in dir_psutil:
|
||||
if name in ('callable', 'error', 'namedtuple', 'tests',
|
||||
'long', 'test', 'NUM_CPUS', 'BOOT_TIME',
|
||||
'TOTAL_PHYMEM'):
|
||||
'TOTAL_PHYMEM', 'PermissionError',
|
||||
'ProcessLookupError'):
|
||||
continue
|
||||
if not name.startswith('_'):
|
||||
try:
|
||||
|
@ -258,14 +264,14 @@ class TestMisc(unittest.TestCase):
|
|||
|
||||
# activate
|
||||
calls = []
|
||||
f.foo.cache_activate()
|
||||
f.foo.cache_activate(f)
|
||||
f.foo()
|
||||
f.foo()
|
||||
self.assertEqual(len(calls), 1)
|
||||
|
||||
# deactivate
|
||||
calls = []
|
||||
f.foo.cache_deactivate()
|
||||
f.foo.cache_deactivate(f)
|
||||
f.foo()
|
||||
f.foo()
|
||||
self.assertEqual(len(calls), 2)
|
||||
|
@ -617,10 +623,10 @@ class TestWrapNumbers(unittest.TestCase):
|
|||
wrap_numbers.cache_clear('disk_io')
|
||||
wrap_numbers.cache_clear('?!?')
|
||||
|
||||
@unittest.skipIf(
|
||||
not psutil.disk_io_counters() or not psutil.net_io_counters(),
|
||||
"no disks or NICs available")
|
||||
@unittest.skipIf(not HAS_NET_IO_COUNTERS, 'not supported')
|
||||
def test_cache_clear_public_apis(self):
|
||||
if not psutil.disk_io_counters() or not psutil.net_io_counters():
|
||||
return self.skipTest("no disks or NICs available")
|
||||
psutil.disk_io_counters()
|
||||
psutil.net_io_counters()
|
||||
caches = wrap_numbers.cache_info()
|
||||
|
@ -708,9 +714,7 @@ class TestScripts(unittest.TestCase):
|
|||
def test_procinfo(self):
|
||||
self.assert_stdout('procinfo.py', str(os.getpid()))
|
||||
|
||||
# can't find users on APPVEYOR or TRAVIS
|
||||
@unittest.skipIf(APPVEYOR or TRAVIS and not psutil.users(),
|
||||
"unreliable on APPVEYOR or TRAVIS")
|
||||
@unittest.skipIf(CI_TESTING and not psutil.users(), "no users")
|
||||
def test_who(self):
|
||||
self.assert_stdout('who.py')
|
||||
|
||||
|
@ -732,8 +736,9 @@ class TestScripts(unittest.TestCase):
|
|||
def test_pmap(self):
|
||||
self.assert_stdout('pmap.py', str(os.getpid()))
|
||||
|
||||
@unittest.skipIf(not HAS_MEMORY_FULL_INFO, "not supported")
|
||||
def test_procsmem(self):
|
||||
if 'uss' not in psutil.Process().memory_full_info()._fields:
|
||||
raise self.skipTest("not supported")
|
||||
self.assert_stdout('procsmem.py', stderr=DEVNULL)
|
||||
|
||||
def test_killall(self):
|
||||
|
@ -762,11 +767,15 @@ class TestScripts(unittest.TestCase):
|
|||
@unittest.skipIf(not HAS_SENSORS_TEMPERATURES, "not supported")
|
||||
@unittest.skipIf(TRAVIS, "unreliable on TRAVIS")
|
||||
def test_temperatures(self):
|
||||
if not psutil.sensors_temperatures():
|
||||
self.skipTest("no temperatures")
|
||||
self.assert_stdout('temperatures.py')
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_FANS, "not supported")
|
||||
@unittest.skipIf(TRAVIS, "unreliable on TRAVIS")
|
||||
def test_fans(self):
|
||||
if not psutil.sensors_fans():
|
||||
self.skipTest("no fans")
|
||||
self.assert_stdout('fans.py')
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_BATTERY, "not supported")
|
||||
|
@ -895,6 +904,20 @@ class TestFSTestUtils(unittest.TestCase):
|
|||
|
||||
tearDown = setUp
|
||||
|
||||
def test_open_text(self):
|
||||
with open_text(__file__) as f:
|
||||
self.assertEqual(f.mode, 'rt')
|
||||
|
||||
def test_open_binary(self):
|
||||
with open_binary(__file__) as f:
|
||||
self.assertEqual(f.mode, 'rb')
|
||||
|
||||
def test_safe_mkdir(self):
|
||||
safe_mkdir(TESTFN)
|
||||
assert os.path.isdir(TESTFN)
|
||||
safe_mkdir(TESTFN)
|
||||
assert os.path.isdir(TESTFN)
|
||||
|
||||
def test_safe_rmpath(self):
|
||||
# test file is removed
|
||||
open(TESTFN, 'w').close()
|
||||
|
@ -994,6 +1017,8 @@ class TestNetUtils(unittest.TestCase):
|
|||
self.assertNotEqual(client.getsockname(), addr)
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
@unittest.skipIf(NETBSD or FREEBSD,
|
||||
"/var/run/log UNIX socket opened by default")
|
||||
def test_unix_socketpair(self):
|
||||
p = psutil.Process()
|
||||
num_fds = p.num_fds()
|
||||
|
@ -1036,4 +1061,5 @@ class TestOtherUtils(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,29 +1,28 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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.
|
||||
|
||||
"""OSX specific tests."""
|
||||
"""MACOS specific tests."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
import psutil
|
||||
from psutil import OSX
|
||||
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_before_failing
|
||||
from psutil.tests import run_test_module_by_name
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
|
||||
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE") if OSX else None
|
||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE") if MACOS else None
|
||||
|
||||
|
||||
def sysctl(cmdline):
|
||||
|
@ -76,7 +75,7 @@ def human2bytes(s):
|
|||
return int(num * prefix[letter])
|
||||
|
||||
|
||||
@unittest.skipIf(not OSX, "OSX only")
|
||||
@unittest.skipIf(not MACOS, "MACOS only")
|
||||
class TestProcess(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
|
@ -101,7 +100,7 @@ class TestProcess(unittest.TestCase):
|
|||
time.strftime("%Y", time.localtime(start_psutil)))
|
||||
|
||||
|
||||
@unittest.skipIf(not OSX, "OSX only")
|
||||
@unittest.skipIf(not MACOS, "MACOS only")
|
||||
class TestZombieProcessAPIs(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
|
@ -158,11 +157,8 @@ class TestZombieProcessAPIs(unittest.TestCase):
|
|||
self.assertRaises((psutil.ZombieProcess, psutil.AccessDenied),
|
||||
self.p.threads)
|
||||
|
||||
def test_memory_maps(self):
|
||||
self.assertRaises(psutil.ZombieProcess, self.p.memory_maps)
|
||||
|
||||
|
||||
@unittest.skipIf(not OSX, "OSX only")
|
||||
@unittest.skipIf(not MACOS, "MACOS only")
|
||||
class TestSystemAPIs(unittest.TestCase):
|
||||
|
||||
# --- disk
|
||||
|
@ -219,31 +215,25 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
sysctl_hwphymem = sysctl('sysctl hw.memsize')
|
||||
self.assertEqual(sysctl_hwphymem, psutil.virtual_memory().total)
|
||||
|
||||
@retry_before_failing()
|
||||
@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_before_failing()
|
||||
def test_vmem_available(self):
|
||||
vmstat_val = vm_stat("inactive") + vm_stat("free")
|
||||
psutil_val = psutil.virtual_memory().available
|
||||
self.assertAlmostEqual(psutil_val, vmstat_val, delta=MEMORY_TOLERANCE)
|
||||
|
||||
@retry_before_failing()
|
||||
@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_before_failing()
|
||||
@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_before_failing()
|
||||
@retry_on_failure()
|
||||
def test_vmem_wired(self):
|
||||
vmstat_val = vm_stat("wired")
|
||||
psutil_val = psutil.virtual_memory().wired
|
||||
|
@ -251,13 +241,13 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
|
||||
# --- swap mem
|
||||
|
||||
@retry_before_failing()
|
||||
@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_before_failing()
|
||||
@retry_on_failure()
|
||||
def test_swapmem_sout(self):
|
||||
vmstat_val = vm_stat("Pageout")
|
||||
psutil_val = psutil.swap_memory().sout
|
||||
|
@ -291,7 +281,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||
def test_sensors_battery(self):
|
||||
out = sh("pmset -g batt")
|
||||
percent = re.search("(\d+)%", out).group(1)
|
||||
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()
|
||||
|
@ -300,4 +290,5 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
|
@ -12,27 +12,24 @@ import errno
|
|||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
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 OSX
|
||||
from psutil import POSIX
|
||||
from psutil import SUNOS
|
||||
from psutil._compat import callable
|
||||
from psutil._compat import PY3
|
||||
from psutil.tests import APPVEYOR
|
||||
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_before_failing
|
||||
from psutil.tests import run_test_module_by_name
|
||||
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
|
||||
|
@ -41,23 +38,53 @@ from psutil.tests import wait_for_pid
|
|||
from psutil.tests import which
|
||||
|
||||
|
||||
def ps(cmd):
|
||||
"""Expects a ps command with a -o argument and parse the result
|
||||
returning only the value of interest.
|
||||
def ps(fmt, pid=None):
|
||||
"""
|
||||
if not LINUX:
|
||||
cmd = cmd.replace(" --no-headers ", " ")
|
||||
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:
|
||||
cmd = cmd.replace("-o start", "-o stime")
|
||||
if AIX:
|
||||
cmd = cmd.replace("-o rss", "-o rssize")
|
||||
fmt_map = set(('command', 'comm', 'start', 'stime'))
|
||||
fmt = fmt_map.get(fmt, fmt)
|
||||
|
||||
cmd.extend(['-o', fmt])
|
||||
|
||||
output = sh(cmd)
|
||||
if not LINUX:
|
||||
output = output.split('\n')[1].strip()
|
||||
|
||||
if LINUX:
|
||||
output = output.splitlines()
|
||||
else:
|
||||
output = output.splitlines()[1:]
|
||||
|
||||
all_output = []
|
||||
for line in output:
|
||||
line = line.strip()
|
||||
|
||||
try:
|
||||
return int(output)
|
||||
line = int(line)
|
||||
except ValueError:
|
||||
return output
|
||||
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.
|
||||
|
@ -75,14 +102,28 @@ def ps_name(pid):
|
|||
field = "command"
|
||||
if SUNOS:
|
||||
field = "comm"
|
||||
return ps("ps --no-headers -o %s -p %s" % (field, pid)).split(' ')[0]
|
||||
return ps(field, pid).split()[0]
|
||||
|
||||
|
||||
def ps_args(pid):
|
||||
field = "command"
|
||||
if AIX or SUNOS:
|
||||
field = "args"
|
||||
return ps("ps --no-headers -o %s -p %s" % (field, pid))
|
||||
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")
|
||||
|
@ -100,22 +141,22 @@ class TestProcess(unittest.TestCase):
|
|||
reap_children()
|
||||
|
||||
def test_ppid(self):
|
||||
ppid_ps = ps("ps --no-headers -o ppid -p %s" % self.pid)
|
||||
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("ps --no-headers -o uid -p %s" % self.pid)
|
||||
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("ps --no-headers -o rgid -p %s" % self.pid)
|
||||
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("ps --no-headers -o user -p %s" % self.pid)
|
||||
username_ps = ps('user', self.pid)
|
||||
username_psutil = psutil.Process(self.pid).username()
|
||||
self.assertEqual(username_ps, username_psutil)
|
||||
|
||||
|
@ -129,22 +170,22 @@ class TestProcess(unittest.TestCase):
|
|||
assert fun.called
|
||||
|
||||
@skip_on_access_denied()
|
||||
@retry_before_failing()
|
||||
@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("ps --no-headers -o rss -p %s" % self.pid)
|
||||
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_before_failing()
|
||||
@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("ps --no-headers -o vsz -p %s" % self.pid)
|
||||
vsz_ps = ps_vsz(self.pid)
|
||||
vsz_psutil = psutil.Process(self.pid).memory_info()[1] / 1024
|
||||
self.assertEqual(vsz_ps, vsz_psutil)
|
||||
|
||||
|
@ -153,10 +194,13 @@ class TestProcess(unittest.TestCase):
|
|||
# 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 OSX this may
|
||||
# ...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):
|
||||
|
@ -195,9 +239,9 @@ class TestProcess(unittest.TestCase):
|
|||
p = psutil.Process()
|
||||
self.assertRaises(psutil.NoSuchProcess, p.name)
|
||||
|
||||
@unittest.skipIf(OSX or BSD, 'ps -o start not available')
|
||||
@unittest.skipIf(MACOS or BSD, 'ps -o start not available')
|
||||
def test_create_time(self):
|
||||
time_ps = ps("ps --no-headers -o start -p %s" % self.pid).split(' ')[0]
|
||||
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")
|
||||
|
@ -236,7 +280,7 @@ class TestProcess(unittest.TestCase):
|
|||
@unittest.skipIf(SUNOS, "not reliable on SUNOS")
|
||||
@unittest.skipIf(AIX, "not reliable on AIX")
|
||||
def test_nice(self):
|
||||
ps_nice = ps("ps --no-headers -o nice -p %s" % self.pid)
|
||||
ps_nice = ps('nice', self.pid)
|
||||
psutil_nice = psutil.Process().nice()
|
||||
self.assertEqual(ps_nice, psutil_nice)
|
||||
|
||||
|
@ -257,7 +301,7 @@ class TestProcess(unittest.TestCase):
|
|||
failures = []
|
||||
ignored_names = ['terminate', 'kill', 'suspend', 'resume', 'nice',
|
||||
'send_signal', 'wait', 'children', 'as_dict',
|
||||
'memory_info_ex']
|
||||
'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):
|
||||
|
@ -286,40 +330,29 @@ class TestProcess(unittest.TestCase):
|
|||
class TestSystemAPIs(unittest.TestCase):
|
||||
"""Test some system APIs."""
|
||||
|
||||
@retry_before_failing()
|
||||
@retry_on_failure()
|
||||
def test_pids(self):
|
||||
# Note: this test might fail if the OS is starting/killing
|
||||
# other processes in the meantime
|
||||
if SUNOS or AIX:
|
||||
cmd = ["ps", "-A", "-o", "pid"]
|
||||
else:
|
||||
cmd = ["ps", "ax", "-o", "pid"]
|
||||
p = get_test_subprocess(cmd, stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].strip()
|
||||
assert p.poll() == 0
|
||||
if PY3:
|
||||
output = str(output, sys.stdout.encoding)
|
||||
pids_ps = []
|
||||
for line in output.split('\n')[1:]:
|
||||
if line:
|
||||
pid = int(line.split()[0].strip())
|
||||
pids_ps.append(pid)
|
||||
# remove ps subprocess pid which is supposed to be dead in meantime
|
||||
pids_ps.remove(p.pid)
|
||||
pids_ps = sorted(ps("pid"))
|
||||
pids_psutil = psutil.pids()
|
||||
pids_ps.sort()
|
||||
pids_psutil.sort()
|
||||
|
||||
# on OSX and OPENBSD ps doesn't show pid 0
|
||||
if OSX or OPENBSD and 0 not in pids_ps:
|
||||
# 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)
|
||||
self.assertEqual(pids_ps, pids_psutil)
|
||||
|
||||
# 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():
|
||||
|
@ -331,13 +364,13 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
"couldn't find %s nic in 'ifconfig -a' output\n%s" % (
|
||||
nic, output))
|
||||
|
||||
# can't find users on APPVEYOR or TRAVIS
|
||||
@unittest.skipIf(APPVEYOR or TRAVIS and not psutil.users(),
|
||||
"unreliable on APPVEYOR or TRAVIS")
|
||||
@retry_before_failing()
|
||||
@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()))
|
||||
|
@ -416,4 +449,5 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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
|
||||
|
@ -25,23 +25,25 @@ import psutil
|
|||
from psutil import AIX
|
||||
from psutil import BSD
|
||||
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._common import open_text
|
||||
from psutil._compat import long
|
||||
from psutil._compat import PY3
|
||||
from psutil.tests import APPVEYOR
|
||||
from psutil.tests import call_until
|
||||
from psutil.tests import CIRRUS
|
||||
from psutil.tests import copyload_shared_lib
|
||||
from psutil.tests import create_exe
|
||||
from psutil.tests import create_proc_children_pair
|
||||
from psutil.tests import create_zombie_proc
|
||||
from psutil.tests import enum
|
||||
from psutil.tests import get_test_subprocess
|
||||
from psutil.tests import get_winver
|
||||
from psutil.tests import HAS_CPU_AFFINITY
|
||||
from psutil.tests import HAS_ENVIRON
|
||||
from psutil.tests import HAS_IONICE
|
||||
|
@ -54,8 +56,7 @@ from psutil.tests import mock
|
|||
from psutil.tests import PYPY
|
||||
from psutil.tests import PYTHON_EXE
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import retry_before_failing
|
||||
from psutil.tests import run_test_module_by_name
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import skip_on_access_denied
|
||||
|
@ -66,7 +67,6 @@ from psutil.tests import ThreadTask
|
|||
from psutil.tests import TRAVIS
|
||||
from psutil.tests import unittest
|
||||
from psutil.tests import wait_for_pid
|
||||
from psutil.tests import WIN_VISTA
|
||||
|
||||
|
||||
# ===================================================================
|
||||
|
@ -238,10 +238,6 @@ class TestProcess(unittest.TestCase):
|
|||
percent = p.cpu_percent(interval=None)
|
||||
self.assertIsInstance(percent, float)
|
||||
self.assertGreaterEqual(percent, 0.0)
|
||||
if not POSIX:
|
||||
self.assertLessEqual(percent, 100.0)
|
||||
else:
|
||||
self.assertGreaterEqual(percent, 0.0)
|
||||
with self.assertRaises(ValueError):
|
||||
p.cpu_percent(interval=-1)
|
||||
|
||||
|
@ -256,6 +252,8 @@ class TestProcess(unittest.TestCase):
|
|||
assert (times.user > 0.0) or (times.system > 0.0), times
|
||||
assert (times.children_user >= 0.0), times
|
||||
assert (times.children_system >= 0.0), times
|
||||
if LINUX:
|
||||
assert times.iowait >= 0.0, times
|
||||
# make sure returned values can be pretty printed with strftime
|
||||
for name in times._fields:
|
||||
time.strftime("%H:%M:%S", time.localtime(getattr(times, name)))
|
||||
|
@ -300,7 +298,7 @@ class TestProcess(unittest.TestCase):
|
|||
time.strftime("%Y %m %d %H:%M:%S", time.localtime(p.create_time()))
|
||||
|
||||
@unittest.skipIf(not POSIX, 'POSIX only')
|
||||
@unittest.skipIf(TRAVIS, 'not reliable on TRAVIS')
|
||||
@unittest.skipIf(TRAVIS or CIRRUS, 'not reliable on TRAVIS/CIRRUS')
|
||||
def test_terminal(self):
|
||||
terminal = psutil.Process().terminal()
|
||||
if sys.stdin.isatty() or sys.stdout.isatty():
|
||||
|
@ -313,7 +311,6 @@ class TestProcess(unittest.TestCase):
|
|||
@skip_on_not_implemented(only_if=LINUX)
|
||||
def test_io_counters(self):
|
||||
p = psutil.Process()
|
||||
|
||||
# test reads
|
||||
io1 = p.io_counters()
|
||||
with open(PYTHON_EXE, 'rb') as f:
|
||||
|
@ -354,74 +351,77 @@ class TestProcess(unittest.TestCase):
|
|||
self.assertGreaterEqual(io2[i], 0)
|
||||
|
||||
@unittest.skipIf(not HAS_IONICE, "not supported")
|
||||
@unittest.skipIf(WINDOWS and get_winver() < WIN_VISTA, 'not supported')
|
||||
def test_ionice(self):
|
||||
if LINUX:
|
||||
from psutil import (IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT,
|
||||
IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE)
|
||||
self.assertEqual(IOPRIO_CLASS_NONE, 0)
|
||||
self.assertEqual(IOPRIO_CLASS_RT, 1)
|
||||
self.assertEqual(IOPRIO_CLASS_BE, 2)
|
||||
self.assertEqual(IOPRIO_CLASS_IDLE, 3)
|
||||
@unittest.skipIf(not LINUX, "linux only")
|
||||
def test_ionice_linux(self):
|
||||
p = psutil.Process()
|
||||
self.assertEqual(p.ionice()[0], psutil.IOPRIO_CLASS_NONE)
|
||||
self.assertEqual(psutil.IOPRIO_CLASS_NONE, 0)
|
||||
self.assertEqual(psutil.IOPRIO_CLASS_RT, 1) # high
|
||||
self.assertEqual(psutil.IOPRIO_CLASS_BE, 2) # normal
|
||||
self.assertEqual(psutil.IOPRIO_CLASS_IDLE, 3) # low
|
||||
try:
|
||||
p.ionice(2)
|
||||
ioclass, value = p.ionice()
|
||||
if enum is not None:
|
||||
self.assertIsInstance(ioclass, enum.IntEnum)
|
||||
self.assertEqual(ioclass, 2)
|
||||
self.assertEqual(value, 4)
|
||||
#
|
||||
p.ionice(3)
|
||||
ioclass, value = p.ionice()
|
||||
self.assertEqual(ioclass, 3)
|
||||
self.assertEqual(value, 0)
|
||||
#
|
||||
p.ionice(2, 0)
|
||||
ioclass, value = p.ionice()
|
||||
self.assertEqual(ioclass, 2)
|
||||
self.assertEqual(value, 0)
|
||||
p.ionice(2, 7)
|
||||
ioclass, value = p.ionice()
|
||||
self.assertEqual(ioclass, 2)
|
||||
self.assertEqual(value, 7)
|
||||
finally:
|
||||
p.ionice(IOPRIO_CLASS_NONE)
|
||||
else:
|
||||
p = psutil.Process()
|
||||
original = p.ionice()
|
||||
self.assertIsInstance(original, int)
|
||||
try:
|
||||
value = 0 # very low
|
||||
if original == value:
|
||||
value = 1 # low
|
||||
p.ionice(value)
|
||||
self.assertEqual(p.ionice(), value)
|
||||
finally:
|
||||
p.ionice(original)
|
||||
|
||||
@unittest.skipIf(not HAS_IONICE, "not supported")
|
||||
@unittest.skipIf(WINDOWS and get_winver() < WIN_VISTA, 'not supported')
|
||||
def test_ionice_errs(self):
|
||||
sproc = get_test_subprocess()
|
||||
p = psutil.Process(sproc.pid)
|
||||
if LINUX:
|
||||
self.assertRaises(ValueError, p.ionice, 2, 10)
|
||||
self.assertRaises(ValueError, p.ionice, 2, -1)
|
||||
self.assertRaises(ValueError, p.ionice, 4)
|
||||
self.assertRaises(TypeError, p.ionice, 2, "foo")
|
||||
# low
|
||||
p.ionice(psutil.IOPRIO_CLASS_IDLE)
|
||||
self.assertEqual(tuple(p.ionice()), (psutil.IOPRIO_CLASS_IDLE, 0))
|
||||
with self.assertRaises(ValueError): # accepts no value
|
||||
p.ionice(psutil.IOPRIO_CLASS_IDLE, value=7)
|
||||
# normal
|
||||
p.ionice(psutil.IOPRIO_CLASS_BE)
|
||||
self.assertEqual(tuple(p.ionice()), (psutil.IOPRIO_CLASS_BE, 0))
|
||||
p.ionice(psutil.IOPRIO_CLASS_BE, value=7)
|
||||
self.assertEqual(tuple(p.ionice()), (psutil.IOPRIO_CLASS_BE, 7))
|
||||
with self.assertRaises(ValueError):
|
||||
p.ionice(psutil.IOPRIO_CLASS_BE, value=8)
|
||||
# high
|
||||
if os.getuid() == 0: # root
|
||||
p.ionice(psutil.IOPRIO_CLASS_RT)
|
||||
self.assertEqual(tuple(p.ionice()),
|
||||
(psutil.IOPRIO_CLASS_RT, 0))
|
||||
p.ionice(psutil.IOPRIO_CLASS_RT, value=7)
|
||||
self.assertEqual(tuple(p.ionice()),
|
||||
(psutil.IOPRIO_CLASS_RT, 7))
|
||||
with self.assertRaises(ValueError):
|
||||
p.ionice(psutil.IOPRIO_CLASS_IDLE, value=8)
|
||||
# errs
|
||||
self.assertRaisesRegex(
|
||||
ValueError, "can't specify value with IOPRIO_CLASS_NONE",
|
||||
ValueError, "ioclass accepts no value",
|
||||
p.ionice, psutil.IOPRIO_CLASS_NONE, 1)
|
||||
self.assertRaisesRegex(
|
||||
ValueError, "can't specify value with IOPRIO_CLASS_IDLE",
|
||||
ValueError, "ioclass accepts no value",
|
||||
p.ionice, psutil.IOPRIO_CLASS_IDLE, 1)
|
||||
self.assertRaisesRegex(
|
||||
ValueError, "'ioclass' argument must be specified",
|
||||
p.ionice, value=1)
|
||||
finally:
|
||||
p.ionice(psutil.IOPRIO_CLASS_BE)
|
||||
|
||||
@unittest.skipIf(not HAS_IONICE, "not supported")
|
||||
@unittest.skipIf(not WINDOWS, 'not supported on this win version')
|
||||
def test_ionice_win(self):
|
||||
p = psutil.Process()
|
||||
self.assertEqual(p.ionice(), psutil.IOPRIO_NORMAL)
|
||||
try:
|
||||
# base
|
||||
p.ionice(psutil.IOPRIO_VERYLOW)
|
||||
self.assertEqual(p.ionice(), psutil.IOPRIO_VERYLOW)
|
||||
p.ionice(psutil.IOPRIO_LOW)
|
||||
self.assertEqual(p.ionice(), psutil.IOPRIO_LOW)
|
||||
try:
|
||||
p.ionice(psutil.IOPRIO_HIGH)
|
||||
except psutil.AccessDenied:
|
||||
pass
|
||||
else:
|
||||
self.assertRaises(ValueError, p.ionice, 3)
|
||||
self.assertRaises(TypeError, p.ionice, 2, 1)
|
||||
self.assertEqual(p.ionice(), psutil.IOPRIO_HIGH)
|
||||
# errs
|
||||
self.assertRaisesRegex(
|
||||
TypeError, "value argument not accepted on Windows",
|
||||
p.ionice, psutil.IOPRIO_NORMAL, value=1)
|
||||
self.assertRaisesRegex(
|
||||
ValueError, "is not a valid priority",
|
||||
p.ionice, psutil.IOPRIO_HIGH + 1)
|
||||
finally:
|
||||
p.ionice(psutil.IOPRIO_NORMAL)
|
||||
self.assertEqual(p.ionice(), psutil.IOPRIO_NORMAL)
|
||||
|
||||
@unittest.skipIf(not HAS_RLIMIT, "not supported")
|
||||
def test_rlimit_get(self):
|
||||
|
@ -508,7 +508,7 @@ class TestProcess(unittest.TestCase):
|
|||
def test_num_threads(self):
|
||||
# on certain platforms such as Linux we might test for exact
|
||||
# thread number, since we always have with 1 thread per process,
|
||||
# but this does not apply across all platforms (OSX, Windows)
|
||||
# but this does not apply across all platforms (MACOS, Windows)
|
||||
p = psutil.Process()
|
||||
if OPENBSD:
|
||||
try:
|
||||
|
@ -542,17 +542,14 @@ class TestProcess(unittest.TestCase):
|
|||
with ThreadTask():
|
||||
step2 = p.threads()
|
||||
self.assertEqual(len(step2), len(step1) + 1)
|
||||
# on Linux, first thread id is supposed to be this process
|
||||
if LINUX:
|
||||
self.assertEqual(step2[0].id, os.getpid())
|
||||
athread = step2[0]
|
||||
# test named tuple
|
||||
self.assertEqual(athread.id, athread[0])
|
||||
self.assertEqual(athread.user_time, athread[1])
|
||||
self.assertEqual(athread.system_time, athread[2])
|
||||
|
||||
@retry_before_failing()
|
||||
@skip_on_access_denied(only_if=OSX)
|
||||
@retry_on_failure()
|
||||
@skip_on_access_denied(only_if=MACOS)
|
||||
@unittest.skipIf(not HAS_THREADS, 'not supported')
|
||||
def test_threads_2(self):
|
||||
sproc = get_test_subprocess()
|
||||
|
@ -606,8 +603,10 @@ class TestProcess(unittest.TestCase):
|
|||
for name in mem._fields:
|
||||
value = getattr(mem, name)
|
||||
self.assertGreaterEqual(value, 0, msg=(name, value))
|
||||
if name == 'vms' and OSX or LINUX:
|
||||
continue
|
||||
self.assertLessEqual(value, total, msg=(name, value, total))
|
||||
if LINUX or WINDOWS or OSX:
|
||||
if LINUX or WINDOWS or MACOS:
|
||||
self.assertGreaterEqual(mem.uss, 0)
|
||||
if LINUX:
|
||||
self.assertGreaterEqual(mem.pss, 0)
|
||||
|
@ -633,7 +632,7 @@ class TestProcess(unittest.TestCase):
|
|||
raise
|
||||
else:
|
||||
# https://github.com/giampaolo/psutil/issues/759
|
||||
with open('/proc/self/smaps') as f:
|
||||
with open_text('/proc/self/smaps') as f:
|
||||
data = f.read()
|
||||
if "%s (deleted)" % nt.path not in data:
|
||||
raise
|
||||
|
@ -666,16 +665,10 @@ class TestProcess(unittest.TestCase):
|
|||
|
||||
def test_memory_percent(self):
|
||||
p = psutil.Process()
|
||||
ret = p.memory_percent()
|
||||
assert 0 <= ret <= 100, ret
|
||||
ret = p.memory_percent(memtype='vms')
|
||||
assert 0 <= ret <= 100, ret
|
||||
assert 0 <= ret <= 100, ret
|
||||
p.memory_percent()
|
||||
self.assertRaises(ValueError, p.memory_percent, memtype="?!?")
|
||||
if LINUX or OSX or WINDOWS:
|
||||
ret = p.memory_percent(memtype='uss')
|
||||
assert 0 <= ret <= 100, ret
|
||||
assert 0 <= ret <= 100, ret
|
||||
if LINUX or MACOS or WINDOWS:
|
||||
p.memory_percent(memtype='uss')
|
||||
|
||||
def test_is_running(self):
|
||||
sproc = get_test_subprocess()
|
||||
|
@ -709,7 +702,7 @@ class TestProcess(unittest.TestCase):
|
|||
self.assertEqual(exe.replace(ver, ''),
|
||||
PYTHON_EXE.replace(ver, ''))
|
||||
except AssertionError:
|
||||
# Tipically OSX. Really not sure what to do here.
|
||||
# Tipically MACOS. Really not sure what to do here.
|
||||
pass
|
||||
|
||||
out = sh([exe, "-c", "import os; print('hey')"])
|
||||
|
@ -733,15 +726,34 @@ class TestProcess(unittest.TestCase):
|
|||
else:
|
||||
raise
|
||||
|
||||
@unittest.skipIf(PYPY, "broken on PYPY")
|
||||
def test_long_cmdline(self):
|
||||
create_exe(TESTFN)
|
||||
self.addCleanup(safe_rmpath, TESTFN)
|
||||
cmdline = [TESTFN] + (["0123456789"] * 20)
|
||||
sproc = get_test_subprocess(cmdline)
|
||||
p = psutil.Process(sproc.pid)
|
||||
self.assertEqual(p.cmdline(), cmdline)
|
||||
|
||||
def test_name(self):
|
||||
sproc = get_test_subprocess(PYTHON_EXE)
|
||||
name = psutil.Process(sproc.pid).name().lower()
|
||||
pyexe = os.path.basename(os.path.realpath(sys.executable)).lower()
|
||||
assert pyexe.startswith(name), (pyexe, name)
|
||||
|
||||
@unittest.skipIf(PYPY, "unreliable on PYPY")
|
||||
def test_long_name(self):
|
||||
long_name = TESTFN + ("0123456789" * 2)
|
||||
create_exe(long_name)
|
||||
self.addCleanup(safe_rmpath, long_name)
|
||||
sproc = get_test_subprocess(long_name)
|
||||
p = psutil.Process(sproc.pid)
|
||||
self.assertEqual(p.name(), os.path.basename(long_name))
|
||||
|
||||
# XXX
|
||||
@unittest.skipIf(SUNOS, "broken on SUNOS")
|
||||
@unittest.skipIf(AIX, "broken on AIX")
|
||||
@unittest.skipIf(PYPY, "broken on PYPY")
|
||||
def test_prog_w_funky_name(self):
|
||||
# Test that name(), exe() and cmdline() correctly handle programs
|
||||
# with funky chars such as spaces and ")", see:
|
||||
|
@ -829,8 +841,8 @@ class TestProcess(unittest.TestCase):
|
|||
self.assertEqual(
|
||||
os.getpriority(os.PRIO_PROCESS, os.getpid()), p.nice())
|
||||
# XXX - going back to previous nice value raises
|
||||
# AccessDenied on OSX
|
||||
if not OSX:
|
||||
# AccessDenied on MACOS
|
||||
if not MACOS:
|
||||
p.nice(0)
|
||||
self.assertEqual(p.nice(), 0)
|
||||
except psutil.AccessDenied:
|
||||
|
@ -908,6 +920,7 @@ class TestProcess(unittest.TestCase):
|
|||
self.assertRaises(TypeError, p.cpu_affinity, 1)
|
||||
p.cpu_affinity(initial)
|
||||
# it should work with all iterables, not only lists
|
||||
if not TRAVIS:
|
||||
p.cpu_affinity(set(all_cpus))
|
||||
p.cpu_affinity(tuple(all_cpus))
|
||||
|
||||
|
@ -929,6 +942,8 @@ class TestProcess(unittest.TestCase):
|
|||
self.addCleanup(p.cpu_affinity, initial)
|
||||
|
||||
# All possible CPU set combinations.
|
||||
if len(initial) > 12:
|
||||
initial = initial[:12] # ...otherwise it will take forever
|
||||
combos = []
|
||||
for l in range(0, len(initial) + 1):
|
||||
for subset in itertools.combinations(initial, l):
|
||||
|
@ -953,13 +968,12 @@ class TestProcess(unittest.TestCase):
|
|||
f.flush()
|
||||
# give the kernel some time to see the new file
|
||||
files = call_until(p.open_files, "len(ret) != %i" % len(files))
|
||||
filenames = [os.path.normcase(x.path) for x in files]
|
||||
self.assertIn(os.path.normcase(TESTFN), filenames)
|
||||
if LINUX:
|
||||
for file in files:
|
||||
if file.path == TESTFN:
|
||||
if LINUX:
|
||||
self.assertEqual(file.position, 1024)
|
||||
break
|
||||
else:
|
||||
self.fail("no file found; files=%s" % repr(files))
|
||||
for file in files:
|
||||
assert os.path.isfile(file.path), file
|
||||
|
||||
|
@ -969,12 +983,12 @@ class TestProcess(unittest.TestCase):
|
|||
p = psutil.Process(sproc.pid)
|
||||
|
||||
for x in range(100):
|
||||
filenames = [x.path for x in p.open_files()]
|
||||
filenames = [os.path.normcase(x.path) for x in p.open_files()]
|
||||
if TESTFN in filenames:
|
||||
break
|
||||
time.sleep(.01)
|
||||
else:
|
||||
self.assertIn(TESTFN, filenames)
|
||||
self.assertIn(os.path.normcase(TESTFN), filenames)
|
||||
for file in filenames:
|
||||
assert os.path.isfile(file), file
|
||||
|
||||
|
@ -984,14 +998,16 @@ class TestProcess(unittest.TestCase):
|
|||
@unittest.skipIf(APPVEYOR, "unreliable on APPVEYOR")
|
||||
def test_open_files_2(self):
|
||||
# test fd and path fields
|
||||
normcase = os.path.normcase
|
||||
with open(TESTFN, 'w') as fileobj:
|
||||
p = psutil.Process()
|
||||
for file in p.open_files():
|
||||
if file.path == fileobj.name or file.fd == fileobj.fileno():
|
||||
if normcase(file.path) == normcase(fileobj.name) or \
|
||||
file.fd == fileobj.fileno():
|
||||
break
|
||||
else:
|
||||
self.fail("no file found; files=%s" % repr(p.open_files()))
|
||||
self.assertEqual(file.path, fileobj.name)
|
||||
self.assertEqual(normcase(file.path), normcase(fileobj.name))
|
||||
if WINDOWS:
|
||||
self.assertEqual(file.fd, -1)
|
||||
else:
|
||||
|
@ -1054,6 +1070,14 @@ class TestProcess(unittest.TestCase):
|
|||
p = psutil.Process(sproc.pid)
|
||||
self.assertEqual(p.parent().pid, this_parent)
|
||||
|
||||
lowest_pid = psutil.pids()[0]
|
||||
self.assertIsNone(psutil.Process(lowest_pid).parent())
|
||||
|
||||
def test_parent_multi(self):
|
||||
p1, p2 = create_proc_children_pair()
|
||||
self.assertEqual(p2.parent(), p1)
|
||||
self.assertEqual(p1.parent(), psutil.Process())
|
||||
|
||||
def test_parent_disappeared(self):
|
||||
# Emulate a case where the parent process disappeared.
|
||||
sproc = get_test_subprocess()
|
||||
|
@ -1062,7 +1086,16 @@ class TestProcess(unittest.TestCase):
|
|||
side_effect=psutil.NoSuchProcess(0, 'foo')):
|
||||
self.assertIsNone(p.parent())
|
||||
|
||||
@retry_on_failure()
|
||||
def test_parents(self):
|
||||
assert psutil.Process().parents()
|
||||
p1, p2 = create_proc_children_pair()
|
||||
self.assertEqual(p1.parents()[0], psutil.Process())
|
||||
self.assertEqual(p2.parents()[0], p1)
|
||||
self.assertEqual(p2.parents()[1], psutil.Process())
|
||||
|
||||
def test_children(self):
|
||||
reap_children(recursive=True)
|
||||
p = psutil.Process()
|
||||
self.assertEqual(p.children(), [])
|
||||
self.assertEqual(p.children(recursive=True), [])
|
||||
|
@ -1108,6 +1141,19 @@ class TestProcess(unittest.TestCase):
|
|||
else:
|
||||
self.assertEqual(len(c), len(set(c)))
|
||||
|
||||
def test_parents_and_children(self):
|
||||
p1, p2 = create_proc_children_pair()
|
||||
me = psutil.Process()
|
||||
# forward
|
||||
children = me.children(recursive=True)
|
||||
self.assertEqual(len(children), 2)
|
||||
self.assertEqual(children[0], p1)
|
||||
self.assertEqual(children[1], p2)
|
||||
# backward
|
||||
parents = p2.parents()
|
||||
self.assertEqual(parents[0], p1)
|
||||
self.assertEqual(parents[1], me)
|
||||
|
||||
def test_suspend_resume(self):
|
||||
sproc = get_test_subprocess()
|
||||
p = psutil.Process(sproc.pid)
|
||||
|
@ -1202,6 +1248,21 @@ class TestProcess(unittest.TestCase):
|
|||
p.cpu_times()
|
||||
self.assertEqual(m.call_count, 2)
|
||||
|
||||
def test_oneshot_cache(self):
|
||||
# Make sure oneshot() cache is nonglobal. Instead it's
|
||||
# supposed to be bound to the Process instance, see:
|
||||
# https://github.com/giampaolo/psutil/issues/1373
|
||||
p1, p2 = create_proc_children_pair()
|
||||
p1_ppid = p1.ppid()
|
||||
p2_ppid = p2.ppid()
|
||||
self.assertNotEqual(p1_ppid, p2_ppid)
|
||||
with p1.oneshot():
|
||||
self.assertEqual(p1.ppid(), p1_ppid)
|
||||
self.assertEqual(p2.ppid(), p2_ppid)
|
||||
with p2.oneshot():
|
||||
self.assertEqual(p1.ppid(), p1_ppid)
|
||||
self.assertEqual(p2.ppid(), p2_ppid)
|
||||
|
||||
def test_halfway_terminated_process(self):
|
||||
# Test that NoSuchProcess exception gets raised in case the
|
||||
# process dies after we create the Process object.
|
||||
|
@ -1216,9 +1277,13 @@ class TestProcess(unittest.TestCase):
|
|||
p.wait()
|
||||
if WINDOWS:
|
||||
call_until(psutil.pids, "%s not in ret" % p.pid)
|
||||
self.assertFalse(p.is_running())
|
||||
# self.assertFalse(p.pid in psutil.pids(), msg="retcode = %s" %
|
||||
# retcode)
|
||||
assert not p.is_running()
|
||||
|
||||
if WINDOWS:
|
||||
with self.assertRaises(psutil.NoSuchProcess):
|
||||
p.send_signal(signal.CTRL_C_EVENT)
|
||||
with self.assertRaises(psutil.NoSuchProcess):
|
||||
p.send_signal(signal.CTRL_BREAK_EVENT)
|
||||
|
||||
excluded_names = ['pid', 'is_running', 'wait', 'create_time',
|
||||
'oneshot', 'memory_info_ex']
|
||||
|
@ -1262,6 +1327,16 @@ class TestProcess(unittest.TestCase):
|
|||
except NotImplementedError:
|
||||
pass
|
||||
else:
|
||||
# NtQuerySystemInformation succeeds if process is gone.
|
||||
if WINDOWS and name in ('exe', 'name'):
|
||||
normcase = os.path.normcase
|
||||
if name == 'exe':
|
||||
self.assertEqual(normcase(ret), normcase(PYTHON_EXE))
|
||||
else:
|
||||
self.assertEqual(
|
||||
normcase(ret),
|
||||
normcase(os.path.basename(PYTHON_EXE)))
|
||||
continue
|
||||
self.fail(
|
||||
"NoSuchProcess exception not raised for %r, retval=%s" % (
|
||||
name, ret))
|
||||
|
@ -1320,7 +1395,7 @@ class TestProcess(unittest.TestCase):
|
|||
succeed_or_zombie_p_exc(zproc.kill)
|
||||
|
||||
# ...its parent should 'see' it
|
||||
# edit: not true on BSD and OSX
|
||||
# edit: not true on BSD and MACOS
|
||||
# descendants = [x.pid for x in psutil.Process().children(
|
||||
# recursive=True)]
|
||||
# self.assertIn(zpid, descendants)
|
||||
|
@ -1330,9 +1405,9 @@ class TestProcess(unittest.TestCase):
|
|||
# self.assertEqual(zpid.ppid(), os.getpid())
|
||||
# ...and all other APIs should be able to deal with it
|
||||
self.assertTrue(psutil.pid_exists(zpid))
|
||||
if not TRAVIS and OSX:
|
||||
if not TRAVIS and MACOS:
|
||||
# For some reason this started failing all of the sudden.
|
||||
# Maybe they upgraded OSX version?
|
||||
# Maybe they upgraded MACOS version?
|
||||
# https://travis-ci.org/giampaolo/psutil/jobs/310896404
|
||||
self.assertIn(zpid, psutil.pids())
|
||||
self.assertIn(zpid, [x.pid for x in psutil.process_iter()])
|
||||
|
@ -1405,12 +1480,14 @@ class TestProcess(unittest.TestCase):
|
|||
d.pop("PSUTIL_TESTING", None)
|
||||
d.pop("PLAT", None)
|
||||
d.pop("HOME", None)
|
||||
if OSX:
|
||||
if MACOS:
|
||||
d.pop("__CF_USER_TEXT_ENCODING", None)
|
||||
d.pop("VERSIONER_PYTHON_PREFER_32_BIT", None)
|
||||
d.pop("VERSIONER_PYTHON_VERSION", None)
|
||||
return dict(
|
||||
[(k.rstrip("\r\n"), v.rstrip("\r\n")) for k, v in d.items()])
|
||||
[(k.replace("\r", "").replace("\n", ""),
|
||||
v.replace("\r", "").replace("\n", ""))
|
||||
for k, v in d.items()])
|
||||
|
||||
self.maxDiff = None
|
||||
p = psutil.Process()
|
||||
|
@ -1562,4 +1639,5 @@ class TestPopen(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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
|
||||
|
@ -10,7 +10,6 @@ import os
|
|||
|
||||
import psutil
|
||||
from psutil import SUNOS
|
||||
from psutil.tests import run_test_module_by_name
|
||||
from psutil.tests import sh
|
||||
from psutil.tests import unittest
|
||||
|
||||
|
@ -42,4 +41,5 @@ class SunOSSpecificTestCase(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/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
|
||||
|
@ -23,28 +23,31 @@ 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 FileNotFoundError
|
||||
from psutil._compat import long
|
||||
from psutil.tests import APPVEYOR
|
||||
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_before_failing
|
||||
from psutil.tests import run_test_module_by_name
|
||||
from psutil.tests import retry_on_failure
|
||||
from psutil.tests import safe_rmpath
|
||||
from psutil.tests import TESTFN
|
||||
from psutil.tests import TESTFN_UNICODE
|
||||
|
@ -57,8 +60,7 @@ from psutil.tests import unittest
|
|||
# ===================================================================
|
||||
|
||||
|
||||
class TestSystemAPIs(unittest.TestCase):
|
||||
"""Tests for system-related APIs."""
|
||||
class TestProcessAPIs(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
safe_rmpath(TESTFN)
|
||||
|
@ -83,7 +85,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
with self.assertRaises(psutil.AccessDenied):
|
||||
list(psutil.process_iter())
|
||||
|
||||
def test_prcess_iter_w_params(self):
|
||||
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):
|
||||
|
@ -103,6 +105,8 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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)
|
||||
|
@ -124,7 +128,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
for p in alive:
|
||||
self.assertFalse(hasattr(p, 'returncode'))
|
||||
|
||||
@retry_before_failing(30)
|
||||
@retry_on_failure(30)
|
||||
def test(procs, callback):
|
||||
gone, alive = psutil.wait_procs(procs, timeout=0.03,
|
||||
callback=callback)
|
||||
|
@ -143,7 +147,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
for p in alive:
|
||||
self.assertFalse(hasattr(p, 'returncode'))
|
||||
|
||||
@retry_before_failing(30)
|
||||
@retry_on_failure(30)
|
||||
def test(procs, callback):
|
||||
gone, alive = psutil.wait_procs(procs, timeout=0.03,
|
||||
callback=callback)
|
||||
|
@ -158,6 +162,8 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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()
|
||||
|
@ -167,12 +173,67 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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
|
||||
|
@ -181,6 +242,55 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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
|
||||
|
@ -215,50 +325,12 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
assert mem.sin >= 0, mem
|
||||
assert mem.sout >= 0, mem
|
||||
|
||||
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)
|
||||
class TestCpuAPIs(unittest.TestCase):
|
||||
|
||||
def test_pids(self):
|
||||
plist = [x.pid for x in psutil.process_iter()]
|
||||
pidlist = psutil.pids()
|
||||
self.assertEqual(plist.sort(), pidlist.sort())
|
||||
# make sure every pid is unique
|
||||
self.assertEqual(len(pidlist), len(set(pidlist)))
|
||||
|
||||
def test_test(self):
|
||||
# test for psutil.test() function
|
||||
stdout = sys.stdout
|
||||
sys.stdout = DEVNULL
|
||||
try:
|
||||
psutil.test()
|
||||
finally:
|
||||
sys.stdout = stdout
|
||||
|
||||
def test_cpu_count(self):
|
||||
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)
|
||||
#
|
||||
|
@ -267,7 +339,15 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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)
|
||||
|
||||
|
@ -315,11 +395,12 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
def test_cpu_times_time_increases(self):
|
||||
# Make sure time increases between calls.
|
||||
t1 = sum(psutil.cpu_times())
|
||||
time.sleep(0.1)
|
||||
stop_at = time.time() + 1
|
||||
while time.time() < stop_at:
|
||||
t2 = sum(psutil.cpu_times())
|
||||
difference = t2 - t1
|
||||
if not difference >= 0.05:
|
||||
self.fail("difference %s" % difference)
|
||||
if t2 > t1:
|
||||
return
|
||||
self.fail("time remained the same")
|
||||
|
||||
def test_per_cpu_times(self):
|
||||
# Check type, value >= 0, str().
|
||||
|
@ -358,17 +439,16 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
# Simulate some work load then make sure time have increased
|
||||
# between calls.
|
||||
tot1 = psutil.cpu_times(percpu=True)
|
||||
stop_at = time.time() + 0.1
|
||||
giveup_at = time.time() + 1
|
||||
while True:
|
||||
if time.time() >= stop_at:
|
||||
break
|
||||
if time.time() >= giveup_at:
|
||||
return self.fail("timeout")
|
||||
tot2 = psutil.cpu_times(percpu=True)
|
||||
for t1, t2 in zip(tot1, tot2):
|
||||
t1, t2 = sum(t1), sum(t2)
|
||||
t1, t2 = psutil._cpu_busy_time(t1), psutil._cpu_busy_time(t2)
|
||||
difference = t2 - t1
|
||||
if difference >= 0.05:
|
||||
return
|
||||
self.fail()
|
||||
|
||||
def test_cpu_times_comparison(self):
|
||||
# Make sure the sum of all per cpu times is almost equal to
|
||||
|
@ -440,6 +520,55 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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'))
|
||||
|
@ -463,9 +592,8 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
# if path does not exist OSError ENOENT is expected across
|
||||
# all platforms
|
||||
fname = tempfile.mktemp()
|
||||
with self.assertRaises(OSError) as exc:
|
||||
with self.assertRaises(FileNotFoundError):
|
||||
psutil.disk_usage(fname)
|
||||
self.assertEqual(exc.exception.errno, errno.ENOENT)
|
||||
|
||||
def test_disk_usage_unicode(self):
|
||||
# See: https://github.com/giampaolo/psutil/issues/416
|
||||
|
@ -496,33 +624,26 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
# we cannot make any assumption about this, see:
|
||||
# http://goo.gl/p9c43
|
||||
disk.device
|
||||
if SUNOS or TRAVIS:
|
||||
# on solaris apparently mount points can also be files
|
||||
# on modern systems mount points can also be files
|
||||
assert os.path.exists(disk.mountpoint), disk
|
||||
else:
|
||||
assert os.path.isdir(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:
|
||||
if not WINDOWS and disk.mountpoint:
|
||||
try:
|
||||
os.stat(disk.mountpoint)
|
||||
except OSError as err:
|
||||
if TRAVIS and OSX and err.errno == errno.EIO:
|
||||
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:
|
||||
if SUNOS or TRAVIS:
|
||||
# on solaris apparently mount points can also be files
|
||||
assert os.path.exists(disk.mountpoint), disk
|
||||
else:
|
||||
assert os.path.isdir(disk.mountpoint), disk
|
||||
self.assertIsInstance(disk.fstype, str)
|
||||
self.assertIsInstance(disk.opts, str)
|
||||
|
||||
|
@ -534,10 +655,55 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
|
||||
mount = find_mount_point(__file__)
|
||||
mounts = [x.mountpoint.lower() for x in
|
||||
psutil.disk_partitions(all=True)]
|
||||
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)
|
||||
|
@ -566,6 +732,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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
|
||||
|
@ -627,7 +794,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
elif addr.ptp:
|
||||
self.assertIsNone(addr.broadcast)
|
||||
|
||||
if BSD or OSX or SUNOS:
|
||||
if BSD or MACOS or SUNOS:
|
||||
if hasattr(socket, "AF_LINK"):
|
||||
self.assertEqual(psutil.AF_LINK, socket.AF_LINK)
|
||||
elif LINUX:
|
||||
|
@ -668,144 +835,18 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
self.assertGreaterEqual(speed, 0)
|
||||
self.assertGreaterEqual(mtu, 0)
|
||||
|
||||
@unittest.skipIf(LINUX and not os.path.exists('/proc/diskstats'),
|
||||
'/proc/diskstats not available on this linux version')
|
||||
@unittest.skipIf(APPVEYOR and psutil.disk_io_counters() is None,
|
||||
"unreliable on APPVEYOR") # 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])
|
||||
if LINUX and key[-1].isdigit():
|
||||
# if 'sda1' is listed 'sda' shouldn't, see:
|
||||
# https://github.com/giampaolo/psutil/issues/338
|
||||
while key[-1].isdigit():
|
||||
key = key[:-1]
|
||||
self.assertNotIn(key, ret.keys())
|
||||
|
||||
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), {})
|
||||
@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
|
||||
|
||||
# can't find users on APPVEYOR or TRAVIS
|
||||
@unittest.skipIf(APPVEYOR or TRAVIS and not psutil.users(),
|
||||
"unreliable on APPVEYOR or TRAVIS")
|
||||
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)
|
||||
|
||||
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'))
|
||||
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:
|
||||
return
|
||||
|
||||
assert ls, ls
|
||||
check_ls([psutil.cpu_freq(percpu=False)])
|
||||
|
||||
if LINUX:
|
||||
self.assertEqual(len(ls), psutil.cpu_count())
|
||||
|
||||
def test_os_constants(self):
|
||||
names = ["POSIX", "WINDOWS", "LINUX", "OSX", "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.OSX
|
||||
names.remove("OSX")
|
||||
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 TestSensorsAPIs(unittest.TestCase):
|
||||
|
||||
@unittest.skipIf(not HAS_SENSORS_TEMPERATURES, "not supported")
|
||||
def test_sensors_temperatures(self):
|
||||
|
@ -859,4 +900,5 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
|
@ -9,7 +9,32 @@
|
|||
Notes about unicode handling in psutil
|
||||
======================================
|
||||
|
||||
In psutil these are the APIs returning or dealing with a string
|
||||
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()
|
||||
|
@ -46,10 +71,6 @@ etc.) and make sure that:
|
|||
|
||||
* psutil never crashes with UnicodeDecodeError
|
||||
* the returned path matches
|
||||
|
||||
For a detailed explanation of how psutil handles unicode see:
|
||||
- https://github.com/giampaolo/psutil/issues/1040
|
||||
- http://psutil.readthedocs.io/#unicode
|
||||
"""
|
||||
|
||||
import os
|
||||
|
@ -58,13 +79,14 @@ import warnings
|
|||
from contextlib import closing
|
||||
|
||||
from psutil import BSD
|
||||
from psutil import MACOS
|
||||
from psutil import OPENBSD
|
||||
from psutil import OSX
|
||||
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
|
||||
|
@ -74,9 +96,8 @@ 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 mock
|
||||
from psutil.tests import PYPY
|
||||
from psutil.tests import reap_children
|
||||
from psutil.tests import run_test_module_by_name
|
||||
from psutil.tests import safe_mkdir
|
||||
from psutil.tests import safe_rmpath as _safe_rmpath
|
||||
from psutil.tests import skip_on_access_denied
|
||||
|
@ -87,7 +108,6 @@ from psutil.tests import TRAVIS
|
|||
from psutil.tests import unittest
|
||||
from psutil.tests import unix_socket_path
|
||||
import psutil
|
||||
import psutil.tests
|
||||
|
||||
|
||||
def safe_rmpath(path):
|
||||
|
@ -166,19 +186,11 @@ class _BaseFSAPIsTests(object):
|
|||
exe = p.exe()
|
||||
self.assertIsInstance(exe, str)
|
||||
if self.expect_exact_path_match():
|
||||
self.assertEqual(exe, self.funky_name)
|
||||
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])
|
||||
if WINDOWS:
|
||||
# On Windows name() is determined from exe() first, because
|
||||
# it's faster; we want to overcome the internal optimization
|
||||
# and test name() instead of exe().
|
||||
with mock.patch("psutil._psplatform.cext.proc_exe",
|
||||
side_effect=psutil.AccessDenied(os.getpid())) as m:
|
||||
name = psutil.Process(subp.pid).name()
|
||||
assert m.called
|
||||
else:
|
||||
name = psutil.Process(subp.pid).name()
|
||||
self.assertIsInstance(name, str)
|
||||
if self.expect_exact_path_match():
|
||||
|
@ -204,6 +216,7 @@ class _BaseFSAPIsTests(object):
|
|||
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())
|
||||
|
@ -233,7 +246,7 @@ class _BaseFSAPIsTests(object):
|
|||
conn = psutil.Process().connections('unix')[0]
|
||||
self.assertIsInstance(conn.laddr, str)
|
||||
# AF_UNIX addr not set on OpenBSD
|
||||
if not OPENBSD:
|
||||
if not OPENBSD and not CIRRUS: # XXX
|
||||
self.assertEqual(conn.laddr, name)
|
||||
|
||||
@unittest.skipIf(not POSIX, "POSIX only")
|
||||
|
@ -271,6 +284,8 @@ class _BaseFSAPIsTests(object):
|
|||
|
||||
@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.
|
||||
|
@ -286,7 +301,9 @@ class _BaseFSAPIsTests(object):
|
|||
self.assertIsInstance(path, str)
|
||||
|
||||
|
||||
@unittest.skipIf(OSX and TRAVIS, "unreliable on TRAVIS") # TODO
|
||||
# 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")
|
||||
|
@ -298,16 +315,15 @@ class TestFSAPIs(_BaseFSAPIsTests, unittest.TestCase):
|
|||
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.
|
||||
if PY3:
|
||||
return True
|
||||
else:
|
||||
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(OSX and TRAVIS, "unreliable on TRAVIS") # TODO
|
||||
@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):
|
||||
|
@ -320,19 +336,6 @@ class TestFSAPIsWithInvalidPath(_BaseFSAPIsTests, unittest.TestCase):
|
|||
return True
|
||||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestWinProcessName(unittest.TestCase):
|
||||
|
||||
def test_name_type(self):
|
||||
# On Windows name() is determined from exe() first, because
|
||||
# it's faster; we want to overcome the internal optimization
|
||||
# and test name() instead of exe().
|
||||
with mock.patch("psutil._psplatform.cext.proc_exe",
|
||||
side_effect=psutil.AccessDenied(os.getpid())) as m:
|
||||
self.assertIsInstance(psutil.Process().name(), str)
|
||||
assert m.called
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Non fs APIs
|
||||
# ===================================================================
|
||||
|
@ -345,6 +348,7 @@ class TestNonFSAPIS(unittest.TestCase):
|
|||
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
|
||||
|
@ -364,4 +368,5 @@ class TestNonFSAPIS(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__file__)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*
|
||||
|
||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||
|
@ -21,27 +21,26 @@ import warnings
|
|||
|
||||
import psutil
|
||||
from psutil import WINDOWS
|
||||
from psutil._compat import callable
|
||||
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_before_failing
|
||||
from psutil.tests import run_test_module_by_name
|
||||
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")
|
||||
try:
|
||||
import win32api # requires "pip install pypiwin32"
|
||||
import win32con
|
||||
import win32process
|
||||
import wmi # requires "pip install wmi" / "make setup-dev-env"
|
||||
except ImportError:
|
||||
if os.name == 'nt':
|
||||
raise
|
||||
|
||||
|
||||
cext = psutil._psplatform.cext
|
||||
|
@ -64,13 +63,57 @@ def wrap_exceptions(fun):
|
|||
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 TestSystemAPIs(unittest.TestCase):
|
||||
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')
|
||||
|
@ -82,23 +125,6 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
self.fail(
|
||||
"%r nic wasn't found in 'ipconfig /all' output" % nic)
|
||||
|
||||
@unittest.skipIf('NUMBER_OF_PROCESSORS' not in os.environ,
|
||||
'NUMBER_OF_PROCESSORS env var is not available')
|
||||
def test_cpu_count(self):
|
||||
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
|
||||
self.assertEqual(num_cpus, psutil.cpu_count())
|
||||
|
||||
def test_cpu_count_2(self):
|
||||
sys_value = win32api.GetSystemInfo()[5]
|
||||
psutil_value = psutil.cpu_count()
|
||||
self.assertEqual(sys_value, psutil_value)
|
||||
|
||||
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)
|
||||
|
||||
def test_total_phymem(self):
|
||||
w = wmi.WMI().Win32_ComputerSystem()[0]
|
||||
self.assertEqual(int(w.TotalPhysicalMemory),
|
||||
|
@ -117,7 +143,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
|
||||
# Note: this test is not very reliable
|
||||
@unittest.skipIf(APPVEYOR, "test not relieable on appveyor")
|
||||
@retry_before_failing()
|
||||
@retry_on_failure()
|
||||
def test_pids(self):
|
||||
# Note: this test might fail if the OS is starting/killing
|
||||
# other processes in the meantime
|
||||
|
@ -126,7 +152,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
psutil_pids = set(psutil.pids())
|
||||
self.assertEqual(wmi_pids, psutil_pids)
|
||||
|
||||
@retry_before_failing()
|
||||
@retry_on_failure()
|
||||
def test_disks(self):
|
||||
ps_parts = psutil.disk_partitions(all=True)
|
||||
wmi_parts = wmi.WMI().Win32_LogicalDisk()
|
||||
|
@ -136,14 +162,13 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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 OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
# usually this is the floppy
|
||||
break
|
||||
else:
|
||||
raise
|
||||
self.assertEqual(usage.total, int(wmi_part.Size))
|
||||
wmi_free = int(wmi_part.FreeSpace)
|
||||
self.assertEqual(usage.free, wmi_free)
|
||||
|
@ -157,6 +182,8 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
|
||||
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,
|
||||
|
@ -190,7 +217,6 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
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())
|
||||
# Wmic time is 2-3 secs lower for some reason; that's OK.
|
||||
self.assertLessEqual(diff, 3)
|
||||
|
||||
def test_boot_time_fluctuation(self):
|
||||
|
@ -211,7 +237,7 @@ class TestSystemAPIs(unittest.TestCase):
|
|||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestSensorsBattery(unittest.TestCase):
|
||||
class TestSensorsBattery(TestCase):
|
||||
|
||||
def test_has_battery(self):
|
||||
if win32api.GetPwrCapabilities()['SystemBatteriesPresent']:
|
||||
|
@ -272,7 +298,7 @@ class TestSensorsBattery(unittest.TestCase):
|
|||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestProcess(unittest.TestCase):
|
||||
class TestProcess(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
@ -307,13 +333,6 @@ class TestProcess(unittest.TestCase):
|
|||
p = psutil.Process(self.pid)
|
||||
self.assertRaises(ValueError, p.send_signal, signal.SIGINT)
|
||||
|
||||
def test_exe(self):
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
self.assertEqual(os.path.basename(p.exe()), p.name())
|
||||
except psutil.Error:
|
||||
pass
|
||||
|
||||
def test_num_handles_increment(self):
|
||||
p = psutil.Process(os.getpid())
|
||||
before = p.num_handles()
|
||||
|
@ -360,15 +379,6 @@ class TestProcess(unittest.TestCase):
|
|||
if failures:
|
||||
self.fail('\n' + '\n'.join(failures))
|
||||
|
||||
def test_name_always_available(self):
|
||||
# On Windows name() is never supposed to raise AccessDenied,
|
||||
# see https://github.com/giampaolo/psutil/issues/627
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
p.name()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
@unittest.skipIf(not sys.version_info >= (2, 7),
|
||||
"CTRL_* signals not supported")
|
||||
def test_ctrl_signals(self):
|
||||
|
@ -382,16 +392,6 @@ class TestProcess(unittest.TestCase):
|
|||
self.assertRaises(psutil.NoSuchProcess,
|
||||
p.send_signal, signal.CTRL_BREAK_EVENT)
|
||||
|
||||
def test_compare_name_exe(self):
|
||||
for p in psutil.process_iter():
|
||||
try:
|
||||
a = os.path.basename(p.exe())
|
||||
b = p.name()
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
else:
|
||||
self.assertEqual(a, b)
|
||||
|
||||
def test_username(self):
|
||||
self.assertEqual(psutil.Process().username(),
|
||||
win32api.GetUserNameEx(win32con.NameSamCompatible))
|
||||
|
@ -497,19 +497,36 @@ class TestProcess(unittest.TestCase):
|
|||
import ctypes.wintypes
|
||||
PROCESS_QUERY_INFORMATION = 0x400
|
||||
handle = ctypes.windll.kernel32.OpenProcess(
|
||||
PROCESS_QUERY_INFORMATION, 0, os.getpid())
|
||||
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().num_handles()
|
||||
ctypes.windll.kernel32.CloseHandle(handle)
|
||||
self.assertEqual(psutil_value, sys_value + 1)
|
||||
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(unittest.TestCase):
|
||||
class TestProcessWMI(TestCase):
|
||||
"""Compare Process API results with WMI."""
|
||||
|
||||
@classmethod
|
||||
|
@ -575,7 +592,7 @@ class TestProcessWMI(unittest.TestCase):
|
|||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestDualProcessImplementation(unittest.TestCase):
|
||||
class TestDualProcessImplementation(TestCase):
|
||||
"""
|
||||
Certain APIs on Windows have 2 internal implementations, one
|
||||
based on documented Windows APIs, another one based
|
||||
|
@ -593,16 +610,6 @@ class TestDualProcessImplementation(unittest.TestCase):
|
|||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
reap_children()
|
||||
# ---
|
||||
# same tests as above but mimicks the AccessDenied failure of
|
||||
# the first (fast) method failing with AD.
|
||||
|
||||
def test_name(self):
|
||||
name = psutil.Process(self.pid).name()
|
||||
with mock.patch("psutil._psplatform.cext.proc_exe",
|
||||
side_effect=psutil.AccessDenied(os.getpid())) as fun:
|
||||
self.assertEqual(psutil.Process(self.pid).name(), name)
|
||||
assert fun.called
|
||||
|
||||
def test_memory_info(self):
|
||||
mem_1 = psutil.Process(self.pid).memory_info()
|
||||
|
@ -618,14 +625,14 @@ class TestDualProcessImplementation(unittest.TestCase):
|
|||
|
||||
def test_create_time(self):
|
||||
ctime = psutil.Process(self.pid).create_time()
|
||||
with mock.patch("psutil._psplatform.cext.proc_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_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
|
||||
|
@ -652,9 +659,23 @@ class TestDualProcessImplementation(unittest.TestCase):
|
|||
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(unittest.TestCase):
|
||||
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
|
||||
|
@ -738,9 +759,10 @@ class RemoteProcessTestCase(unittest.TestCase):
|
|||
|
||||
def test_environ_64(self):
|
||||
p = psutil.Process(self.proc64.pid)
|
||||
e = p.environ()
|
||||
self.assertIn("THINK_OF_A_NUMBER", e)
|
||||
self.assertEquals(e["THINK_OF_A_NUMBER"], str(os.getpid()))
|
||||
try:
|
||||
p.environ()
|
||||
except psutil.AccessDenied:
|
||||
pass
|
||||
|
||||
|
||||
# ===================================================================
|
||||
|
@ -749,7 +771,7 @@ class RemoteProcessTestCase(unittest.TestCase):
|
|||
|
||||
|
||||
@unittest.skipIf(not WINDOWS, "WINDOWS only")
|
||||
class TestServices(unittest.TestCase):
|
||||
class TestServices(TestCase):
|
||||
|
||||
def test_win_service_iter(self):
|
||||
valid_statuses = set([
|
||||
|
@ -800,16 +822,22 @@ class TestServices(unittest.TestCase):
|
|||
self.assertEqual(serv, s)
|
||||
|
||||
def test_win_service_get(self):
|
||||
name = next(psutil.win_service_iter()).name()
|
||||
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)
|
||||
exc = WindowsError(
|
||||
psutil._psplatform.cext.ERROR_SERVICE_DOES_NOT_EXIST, "")
|
||||
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)
|
||||
|
@ -818,8 +846,11 @@ class TestServices(unittest.TestCase):
|
|||
self.assertRaises(psutil.NoSuchProcess, service.username)
|
||||
|
||||
# test AccessDenied
|
||||
exc = WindowsError(
|
||||
psutil._psplatform.cext.ERROR_ACCESS_DENIED, "")
|
||||
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)
|
||||
|
@ -835,4 +866,5 @@ class TestServices(unittest.TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_test_module_by_name(__file__)
|
||||
from psutil.tests.runner import run
|
||||
run(__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
|
|
@ -57,7 +57,7 @@ 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.
|
||||
1329, 1276, 1494, 1528.
|
||||
|
||||
N: Alex Manuskin
|
||||
W: https://github.com/amanusk
|
||||
|
@ -621,4 +621,46 @@ I: 1491
|
|||
N: Kamil Rytarowski
|
||||
W: https://github.com/krytarowski
|
||||
C: Poland
|
||||
I: 1526
|
||||
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
|
||||
|
|
|
@ -1,5 +1,116 @@
|
|||
*Bug tracker at https://github.com/giampaolo/psutil/issues*
|
||||
|
||||
5.7.0
|
||||
=====
|
||||
|
||||
2020-12-18
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- 1637_: [SunOS] add partial support for old SunOS 5.10 Update 0 to 3.
|
||||
- 1648_: [Linux] sensors_temperatures() looks into an additional /sys/device/
|
||||
directory for additional data. (patch by Javad Karabi)
|
||||
- 1652_: [Windows] dropped support for Windows XP and Windows Server 2003.
|
||||
Minimum supported Windows version now is Windows Vista.
|
||||
- 1671_: [FreeBSD] add CI testing/service for FreeBSD (Cirrus CI).
|
||||
- 1677_: [Windows] process exe() will succeed for all process PIDs (instead of
|
||||
raising AccessDenied).
|
||||
- 1679_: [Windows] net_connections() and Process.connections() are 10% faster.
|
||||
- 1682_: [PyPy] added CI / test integration for PyPy via Travis.
|
||||
- 1686_: [Windows] added support for PyPy on Windows.
|
||||
- 1693_: [Windows] boot_time(), Process.create_time() and users()'s login time
|
||||
now have 1 micro second precision (before the precision was of 1 second).
|
||||
|
||||
**Bug fixes**
|
||||
|
||||
- 1538_: [NetBSD] process cwd() may return ENOENT instead of NoSuchProcess.
|
||||
- 1627_: [Linux] Process.memory_maps() can raise KeyError.
|
||||
- 1642_: [SunOS] querying basic info for PID 0 results in FileNotFoundError.
|
||||
- 1646_: [FreeBSD] many Process methods may cause a segfault on FreeBSD 12.0
|
||||
due to a backward incompatible change in a C type introduced in 12.0.
|
||||
- 1656_: [Windows] Process.memory_full_info() raises AccessDenied even for the
|
||||
current user and os.getpid().
|
||||
- 1660_: [Windows] Process.open_files() complete rewrite + check of errors.
|
||||
- 1662_: [Windows] process exe() may raise WinError 0.
|
||||
- 1665_: [Linux] disk_io_counters() does not take into account extra fields
|
||||
added to recent kernels. (patch by Mike Hommey)
|
||||
- 1672_: use the right C type when dealing with PIDs (int or long). Thus far
|
||||
(long) was almost always assumed, which is wrong on most platforms.
|
||||
- 1673_: [OpenBSD] Process connections(), num_fds() and threads() returned
|
||||
improper exception if process is gone.
|
||||
- 1674_: [SunOS] disk_partitions() may raise OSError.
|
||||
- 1684_: [Linux] disk_io_counters() may raise ValueError on systems not
|
||||
having /proc/diskstats.
|
||||
- 1695_: [Linux] could not compile on kernels <= 2.6.13 due to
|
||||
PSUTIL_HAVE_IOPRIO not being defined. (patch by Anselm Kruis)
|
||||
|
||||
5.6.7
|
||||
=====
|
||||
|
||||
2019-11-26
|
||||
|
||||
**Bug fixes**
|
||||
|
||||
- 1630_: [Windows] can't compile source distribution due to C syntax error.
|
||||
|
||||
5.6.6
|
||||
=====
|
||||
|
||||
2019-11-25
|
||||
|
||||
**Bug fixes**
|
||||
|
||||
- 1179_: [Linux] Process cmdline() now takes into account misbehaving processes
|
||||
renaming the command line and using inappropriate chars to separate args.
|
||||
- 1616_: use of Py_DECREF instead of Py_CLEAR will result in double free and
|
||||
segfault
|
||||
(`CVE-2019-18874 <https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18874>`__).
|
||||
(patch by Riccardo Schirone)
|
||||
- 1619_: [OpenBSD] compilation fails due to C syntax error. (patch by Nathan
|
||||
Houghton)
|
||||
|
||||
5.6.5
|
||||
=====
|
||||
|
||||
2019-11-06
|
||||
|
||||
**Bug fixes**
|
||||
|
||||
- 1615_: remove pyproject.toml as it was causing installation issues.
|
||||
|
||||
5.6.4
|
||||
=====
|
||||
|
||||
2019-11-04
|
||||
|
||||
**Enhancements**
|
||||
|
||||
- 1527_: [Linux] added Process.cpu_times().iowait counter, which is the time
|
||||
spent waiting for blocking I/O to complete.
|
||||
- 1565_: add PEP 517/8 build backend and requirements specification for better
|
||||
pip integration. (patch by Bernát Gábor)
|
||||
|
||||
**Bug fixes**
|
||||
|
||||
- 875_: [Windows] Process' cmdline(), environ() or cwd() may occasionally fail
|
||||
with ERROR_PARTIAL_COPY which now gets translated to AccessDenied.
|
||||
- 1126_: [Linux] cpu_affinity() segfaults on CentOS 5 / manylinux.
|
||||
cpu_affinity() support for CentOS 5 was removed.
|
||||
- 1528_: [AIX] compilation error on AIX 7.2 due to 32 vs 64 bit differences.
|
||||
(patch by Arnon Yaari)
|
||||
- 1535_: 'type' and 'family' fields returned by net_connections() are not
|
||||
always turned into enums.
|
||||
- 1536_: [NetBSD] process cmdline() erroneously raise ZombieProcess error if
|
||||
cmdline has non encodable chars.
|
||||
- 1546_: usage percent may be rounded to 0 on Python 2.
|
||||
- 1552_: [Windows] getloadavg() math for calculating 5 and 15 mins values is
|
||||
incorrect.
|
||||
- 1568_: [Linux] use CC compiler env var if defined.
|
||||
- 1570_: [Windows] `NtWow64*` syscalls fail to raise the proper error code
|
||||
- 1585_: [OSX] calling close() (in C) on possible negative integers. (patch
|
||||
by Athos Ribeiro)
|
||||
- 1606_: [SunOS] compilation fails on SunOS 5.10. (patch by vser1)
|
||||
|
||||
5.6.3
|
||||
=====
|
||||
|
||||
|
@ -3528,3 +3639,503 @@ DeprecationWarning.
|
|||
.. _1498: https://github.com/giampaolo/psutil/issues/1498
|
||||
.. _1499: https://github.com/giampaolo/psutil/issues/1499
|
||||
.. _1500: https://github.com/giampaolo/psutil/issues/1500
|
||||
.. _1501: https://github.com/giampaolo/psutil/issues/1501
|
||||
.. _1502: https://github.com/giampaolo/psutil/issues/1502
|
||||
.. _1503: https://github.com/giampaolo/psutil/issues/1503
|
||||
.. _1504: https://github.com/giampaolo/psutil/issues/1504
|
||||
.. _1505: https://github.com/giampaolo/psutil/issues/1505
|
||||
.. _1506: https://github.com/giampaolo/psutil/issues/1506
|
||||
.. _1507: https://github.com/giampaolo/psutil/issues/1507
|
||||
.. _1508: https://github.com/giampaolo/psutil/issues/1508
|
||||
.. _1509: https://github.com/giampaolo/psutil/issues/1509
|
||||
.. _1510: https://github.com/giampaolo/psutil/issues/1510
|
||||
.. _1511: https://github.com/giampaolo/psutil/issues/1511
|
||||
.. _1512: https://github.com/giampaolo/psutil/issues/1512
|
||||
.. _1513: https://github.com/giampaolo/psutil/issues/1513
|
||||
.. _1514: https://github.com/giampaolo/psutil/issues/1514
|
||||
.. _1515: https://github.com/giampaolo/psutil/issues/1515
|
||||
.. _1516: https://github.com/giampaolo/psutil/issues/1516
|
||||
.. _1517: https://github.com/giampaolo/psutil/issues/1517
|
||||
.. _1518: https://github.com/giampaolo/psutil/issues/1518
|
||||
.. _1519: https://github.com/giampaolo/psutil/issues/1519
|
||||
.. _1520: https://github.com/giampaolo/psutil/issues/1520
|
||||
.. _1521: https://github.com/giampaolo/psutil/issues/1521
|
||||
.. _1522: https://github.com/giampaolo/psutil/issues/1522
|
||||
.. _1523: https://github.com/giampaolo/psutil/issues/1523
|
||||
.. _1524: https://github.com/giampaolo/psutil/issues/1524
|
||||
.. _1525: https://github.com/giampaolo/psutil/issues/1525
|
||||
.. _1526: https://github.com/giampaolo/psutil/issues/1526
|
||||
.. _1527: https://github.com/giampaolo/psutil/issues/1527
|
||||
.. _1528: https://github.com/giampaolo/psutil/issues/1528
|
||||
.. _1529: https://github.com/giampaolo/psutil/issues/1529
|
||||
.. _1530: https://github.com/giampaolo/psutil/issues/1530
|
||||
.. _1531: https://github.com/giampaolo/psutil/issues/1531
|
||||
.. _1532: https://github.com/giampaolo/psutil/issues/1532
|
||||
.. _1533: https://github.com/giampaolo/psutil/issues/1533
|
||||
.. _1534: https://github.com/giampaolo/psutil/issues/1534
|
||||
.. _1535: https://github.com/giampaolo/psutil/issues/1535
|
||||
.. _1536: https://github.com/giampaolo/psutil/issues/1536
|
||||
.. _1537: https://github.com/giampaolo/psutil/issues/1537
|
||||
.. _1538: https://github.com/giampaolo/psutil/issues/1538
|
||||
.. _1539: https://github.com/giampaolo/psutil/issues/1539
|
||||
.. _1540: https://github.com/giampaolo/psutil/issues/1540
|
||||
.. _1541: https://github.com/giampaolo/psutil/issues/1541
|
||||
.. _1542: https://github.com/giampaolo/psutil/issues/1542
|
||||
.. _1543: https://github.com/giampaolo/psutil/issues/1543
|
||||
.. _1544: https://github.com/giampaolo/psutil/issues/1544
|
||||
.. _1545: https://github.com/giampaolo/psutil/issues/1545
|
||||
.. _1546: https://github.com/giampaolo/psutil/issues/1546
|
||||
.. _1547: https://github.com/giampaolo/psutil/issues/1547
|
||||
.. _1548: https://github.com/giampaolo/psutil/issues/1548
|
||||
.. _1549: https://github.com/giampaolo/psutil/issues/1549
|
||||
.. _1550: https://github.com/giampaolo/psutil/issues/1550
|
||||
.. _1551: https://github.com/giampaolo/psutil/issues/1551
|
||||
.. _1552: https://github.com/giampaolo/psutil/issues/1552
|
||||
.. _1553: https://github.com/giampaolo/psutil/issues/1553
|
||||
.. _1554: https://github.com/giampaolo/psutil/issues/1554
|
||||
.. _1555: https://github.com/giampaolo/psutil/issues/1555
|
||||
.. _1556: https://github.com/giampaolo/psutil/issues/1556
|
||||
.. _1557: https://github.com/giampaolo/psutil/issues/1557
|
||||
.. _1558: https://github.com/giampaolo/psutil/issues/1558
|
||||
.. _1559: https://github.com/giampaolo/psutil/issues/1559
|
||||
.. _1560: https://github.com/giampaolo/psutil/issues/1560
|
||||
.. _1561: https://github.com/giampaolo/psutil/issues/1561
|
||||
.. _1562: https://github.com/giampaolo/psutil/issues/1562
|
||||
.. _1563: https://github.com/giampaolo/psutil/issues/1563
|
||||
.. _1564: https://github.com/giampaolo/psutil/issues/1564
|
||||
.. _1565: https://github.com/giampaolo/psutil/issues/1565
|
||||
.. _1566: https://github.com/giampaolo/psutil/issues/1566
|
||||
.. _1567: https://github.com/giampaolo/psutil/issues/1567
|
||||
.. _1568: https://github.com/giampaolo/psutil/issues/1568
|
||||
.. _1569: https://github.com/giampaolo/psutil/issues/1569
|
||||
.. _1570: https://github.com/giampaolo/psutil/issues/1570
|
||||
.. _1571: https://github.com/giampaolo/psutil/issues/1571
|
||||
.. _1572: https://github.com/giampaolo/psutil/issues/1572
|
||||
.. _1573: https://github.com/giampaolo/psutil/issues/1573
|
||||
.. _1574: https://github.com/giampaolo/psutil/issues/1574
|
||||
.. _1575: https://github.com/giampaolo/psutil/issues/1575
|
||||
.. _1576: https://github.com/giampaolo/psutil/issues/1576
|
||||
.. _1577: https://github.com/giampaolo/psutil/issues/1577
|
||||
.. _1578: https://github.com/giampaolo/psutil/issues/1578
|
||||
.. _1579: https://github.com/giampaolo/psutil/issues/1579
|
||||
.. _1580: https://github.com/giampaolo/psutil/issues/1580
|
||||
.. _1581: https://github.com/giampaolo/psutil/issues/1581
|
||||
.. _1582: https://github.com/giampaolo/psutil/issues/1582
|
||||
.. _1583: https://github.com/giampaolo/psutil/issues/1583
|
||||
.. _1584: https://github.com/giampaolo/psutil/issues/1584
|
||||
.. _1585: https://github.com/giampaolo/psutil/issues/1585
|
||||
.. _1586: https://github.com/giampaolo/psutil/issues/1586
|
||||
.. _1587: https://github.com/giampaolo/psutil/issues/1587
|
||||
.. _1588: https://github.com/giampaolo/psutil/issues/1588
|
||||
.. _1589: https://github.com/giampaolo/psutil/issues/1589
|
||||
.. _1590: https://github.com/giampaolo/psutil/issues/1590
|
||||
.. _1591: https://github.com/giampaolo/psutil/issues/1591
|
||||
.. _1592: https://github.com/giampaolo/psutil/issues/1592
|
||||
.. _1593: https://github.com/giampaolo/psutil/issues/1593
|
||||
.. _1594: https://github.com/giampaolo/psutil/issues/1594
|
||||
.. _1595: https://github.com/giampaolo/psutil/issues/1595
|
||||
.. _1596: https://github.com/giampaolo/psutil/issues/1596
|
||||
.. _1597: https://github.com/giampaolo/psutil/issues/1597
|
||||
.. _1598: https://github.com/giampaolo/psutil/issues/1598
|
||||
.. _1599: https://github.com/giampaolo/psutil/issues/1599
|
||||
.. _1600: https://github.com/giampaolo/psutil/issues/1600
|
||||
.. _1601: https://github.com/giampaolo/psutil/issues/1601
|
||||
.. _1602: https://github.com/giampaolo/psutil/issues/1602
|
||||
.. _1603: https://github.com/giampaolo/psutil/issues/1603
|
||||
.. _1604: https://github.com/giampaolo/psutil/issues/1604
|
||||
.. _1605: https://github.com/giampaolo/psutil/issues/1605
|
||||
.. _1606: https://github.com/giampaolo/psutil/issues/1606
|
||||
.. _1607: https://github.com/giampaolo/psutil/issues/1607
|
||||
.. _1608: https://github.com/giampaolo/psutil/issues/1608
|
||||
.. _1609: https://github.com/giampaolo/psutil/issues/1609
|
||||
.. _1610: https://github.com/giampaolo/psutil/issues/1610
|
||||
.. _1611: https://github.com/giampaolo/psutil/issues/1611
|
||||
.. _1612: https://github.com/giampaolo/psutil/issues/1612
|
||||
.. _1613: https://github.com/giampaolo/psutil/issues/1613
|
||||
.. _1614: https://github.com/giampaolo/psutil/issues/1614
|
||||
.. _1615: https://github.com/giampaolo/psutil/issues/1615
|
||||
.. _1616: https://github.com/giampaolo/psutil/issues/1616
|
||||
.. _1617: https://github.com/giampaolo/psutil/issues/1617
|
||||
.. _1618: https://github.com/giampaolo/psutil/issues/1618
|
||||
.. _1619: https://github.com/giampaolo/psutil/issues/1619
|
||||
.. _1620: https://github.com/giampaolo/psutil/issues/1620
|
||||
.. _1621: https://github.com/giampaolo/psutil/issues/1621
|
||||
.. _1622: https://github.com/giampaolo/psutil/issues/1622
|
||||
.. _1623: https://github.com/giampaolo/psutil/issues/1623
|
||||
.. _1624: https://github.com/giampaolo/psutil/issues/1624
|
||||
.. _1625: https://github.com/giampaolo/psutil/issues/1625
|
||||
.. _1626: https://github.com/giampaolo/psutil/issues/1626
|
||||
.. _1627: https://github.com/giampaolo/psutil/issues/1627
|
||||
.. _1628: https://github.com/giampaolo/psutil/issues/1628
|
||||
.. _1629: https://github.com/giampaolo/psutil/issues/1629
|
||||
.. _1630: https://github.com/giampaolo/psutil/issues/1630
|
||||
.. _1631: https://github.com/giampaolo/psutil/issues/1631
|
||||
.. _1632: https://github.com/giampaolo/psutil/issues/1632
|
||||
.. _1633: https://github.com/giampaolo/psutil/issues/1633
|
||||
.. _1634: https://github.com/giampaolo/psutil/issues/1634
|
||||
.. _1635: https://github.com/giampaolo/psutil/issues/1635
|
||||
.. _1636: https://github.com/giampaolo/psutil/issues/1636
|
||||
.. _1637: https://github.com/giampaolo/psutil/issues/1637
|
||||
.. _1638: https://github.com/giampaolo/psutil/issues/1638
|
||||
.. _1639: https://github.com/giampaolo/psutil/issues/1639
|
||||
.. _1640: https://github.com/giampaolo/psutil/issues/1640
|
||||
.. _1641: https://github.com/giampaolo/psutil/issues/1641
|
||||
.. _1642: https://github.com/giampaolo/psutil/issues/1642
|
||||
.. _1643: https://github.com/giampaolo/psutil/issues/1643
|
||||
.. _1644: https://github.com/giampaolo/psutil/issues/1644
|
||||
.. _1645: https://github.com/giampaolo/psutil/issues/1645
|
||||
.. _1646: https://github.com/giampaolo/psutil/issues/1646
|
||||
.. _1647: https://github.com/giampaolo/psutil/issues/1647
|
||||
.. _1648: https://github.com/giampaolo/psutil/issues/1648
|
||||
.. _1649: https://github.com/giampaolo/psutil/issues/1649
|
||||
.. _1650: https://github.com/giampaolo/psutil/issues/1650
|
||||
.. _1651: https://github.com/giampaolo/psutil/issues/1651
|
||||
.. _1652: https://github.com/giampaolo/psutil/issues/1652
|
||||
.. _1653: https://github.com/giampaolo/psutil/issues/1653
|
||||
.. _1654: https://github.com/giampaolo/psutil/issues/1654
|
||||
.. _1655: https://github.com/giampaolo/psutil/issues/1655
|
||||
.. _1656: https://github.com/giampaolo/psutil/issues/1656
|
||||
.. _1657: https://github.com/giampaolo/psutil/issues/1657
|
||||
.. _1658: https://github.com/giampaolo/psutil/issues/1658
|
||||
.. _1659: https://github.com/giampaolo/psutil/issues/1659
|
||||
.. _1660: https://github.com/giampaolo/psutil/issues/1660
|
||||
.. _1661: https://github.com/giampaolo/psutil/issues/1661
|
||||
.. _1662: https://github.com/giampaolo/psutil/issues/1662
|
||||
.. _1663: https://github.com/giampaolo/psutil/issues/1663
|
||||
.. _1664: https://github.com/giampaolo/psutil/issues/1664
|
||||
.. _1665: https://github.com/giampaolo/psutil/issues/1665
|
||||
.. _1666: https://github.com/giampaolo/psutil/issues/1666
|
||||
.. _1667: https://github.com/giampaolo/psutil/issues/1667
|
||||
.. _1668: https://github.com/giampaolo/psutil/issues/1668
|
||||
.. _1669: https://github.com/giampaolo/psutil/issues/1669
|
||||
.. _1670: https://github.com/giampaolo/psutil/issues/1670
|
||||
.. _1671: https://github.com/giampaolo/psutil/issues/1671
|
||||
.. _1672: https://github.com/giampaolo/psutil/issues/1672
|
||||
.. _1673: https://github.com/giampaolo/psutil/issues/1673
|
||||
.. _1674: https://github.com/giampaolo/psutil/issues/1674
|
||||
.. _1675: https://github.com/giampaolo/psutil/issues/1675
|
||||
.. _1676: https://github.com/giampaolo/psutil/issues/1676
|
||||
.. _1677: https://github.com/giampaolo/psutil/issues/1677
|
||||
.. _1678: https://github.com/giampaolo/psutil/issues/1678
|
||||
.. _1679: https://github.com/giampaolo/psutil/issues/1679
|
||||
.. _1680: https://github.com/giampaolo/psutil/issues/1680
|
||||
.. _1681: https://github.com/giampaolo/psutil/issues/1681
|
||||
.. _1682: https://github.com/giampaolo/psutil/issues/1682
|
||||
.. _1683: https://github.com/giampaolo/psutil/issues/1683
|
||||
.. _1684: https://github.com/giampaolo/psutil/issues/1684
|
||||
.. _1685: https://github.com/giampaolo/psutil/issues/1685
|
||||
.. _1686: https://github.com/giampaolo/psutil/issues/1686
|
||||
.. _1687: https://github.com/giampaolo/psutil/issues/1687
|
||||
.. _1688: https://github.com/giampaolo/psutil/issues/1688
|
||||
.. _1689: https://github.com/giampaolo/psutil/issues/1689
|
||||
.. _1690: https://github.com/giampaolo/psutil/issues/1690
|
||||
.. _1691: https://github.com/giampaolo/psutil/issues/1691
|
||||
.. _1692: https://github.com/giampaolo/psutil/issues/1692
|
||||
.. _1693: https://github.com/giampaolo/psutil/issues/1693
|
||||
.. _1694: https://github.com/giampaolo/psutil/issues/1694
|
||||
.. _1695: https://github.com/giampaolo/psutil/issues/1695
|
||||
.. _1696: https://github.com/giampaolo/psutil/issues/1696
|
||||
.. _1697: https://github.com/giampaolo/psutil/issues/1697
|
||||
.. _1698: https://github.com/giampaolo/psutil/issues/1698
|
||||
.. _1699: https://github.com/giampaolo/psutil/issues/1699
|
||||
.. _1700: https://github.com/giampaolo/psutil/issues/1700
|
||||
.. _1701: https://github.com/giampaolo/psutil/issues/1701
|
||||
.. _1702: https://github.com/giampaolo/psutil/issues/1702
|
||||
.. _1703: https://github.com/giampaolo/psutil/issues/1703
|
||||
.. _1704: https://github.com/giampaolo/psutil/issues/1704
|
||||
.. _1705: https://github.com/giampaolo/psutil/issues/1705
|
||||
.. _1706: https://github.com/giampaolo/psutil/issues/1706
|
||||
.. _1707: https://github.com/giampaolo/psutil/issues/1707
|
||||
.. _1708: https://github.com/giampaolo/psutil/issues/1708
|
||||
.. _1709: https://github.com/giampaolo/psutil/issues/1709
|
||||
.. _1710: https://github.com/giampaolo/psutil/issues/1710
|
||||
.. _1711: https://github.com/giampaolo/psutil/issues/1711
|
||||
.. _1712: https://github.com/giampaolo/psutil/issues/1712
|
||||
.. _1713: https://github.com/giampaolo/psutil/issues/1713
|
||||
.. _1714: https://github.com/giampaolo/psutil/issues/1714
|
||||
.. _1715: https://github.com/giampaolo/psutil/issues/1715
|
||||
.. _1716: https://github.com/giampaolo/psutil/issues/1716
|
||||
.. _1717: https://github.com/giampaolo/psutil/issues/1717
|
||||
.. _1718: https://github.com/giampaolo/psutil/issues/1718
|
||||
.. _1719: https://github.com/giampaolo/psutil/issues/1719
|
||||
.. _1720: https://github.com/giampaolo/psutil/issues/1720
|
||||
.. _1721: https://github.com/giampaolo/psutil/issues/1721
|
||||
.. _1722: https://github.com/giampaolo/psutil/issues/1722
|
||||
.. _1723: https://github.com/giampaolo/psutil/issues/1723
|
||||
.. _1724: https://github.com/giampaolo/psutil/issues/1724
|
||||
.. _1725: https://github.com/giampaolo/psutil/issues/1725
|
||||
.. _1726: https://github.com/giampaolo/psutil/issues/1726
|
||||
.. _1727: https://github.com/giampaolo/psutil/issues/1727
|
||||
.. _1728: https://github.com/giampaolo/psutil/issues/1728
|
||||
.. _1729: https://github.com/giampaolo/psutil/issues/1729
|
||||
.. _1730: https://github.com/giampaolo/psutil/issues/1730
|
||||
.. _1731: https://github.com/giampaolo/psutil/issues/1731
|
||||
.. _1732: https://github.com/giampaolo/psutil/issues/1732
|
||||
.. _1733: https://github.com/giampaolo/psutil/issues/1733
|
||||
.. _1734: https://github.com/giampaolo/psutil/issues/1734
|
||||
.. _1735: https://github.com/giampaolo/psutil/issues/1735
|
||||
.. _1736: https://github.com/giampaolo/psutil/issues/1736
|
||||
.. _1737: https://github.com/giampaolo/psutil/issues/1737
|
||||
.. _1738: https://github.com/giampaolo/psutil/issues/1738
|
||||
.. _1739: https://github.com/giampaolo/psutil/issues/1739
|
||||
.. _1740: https://github.com/giampaolo/psutil/issues/1740
|
||||
.. _1741: https://github.com/giampaolo/psutil/issues/1741
|
||||
.. _1742: https://github.com/giampaolo/psutil/issues/1742
|
||||
.. _1743: https://github.com/giampaolo/psutil/issues/1743
|
||||
.. _1744: https://github.com/giampaolo/psutil/issues/1744
|
||||
.. _1745: https://github.com/giampaolo/psutil/issues/1745
|
||||
.. _1746: https://github.com/giampaolo/psutil/issues/1746
|
||||
.. _1747: https://github.com/giampaolo/psutil/issues/1747
|
||||
.. _1748: https://github.com/giampaolo/psutil/issues/1748
|
||||
.. _1749: https://github.com/giampaolo/psutil/issues/1749
|
||||
.. _1750: https://github.com/giampaolo/psutil/issues/1750
|
||||
.. _1751: https://github.com/giampaolo/psutil/issues/1751
|
||||
.. _1752: https://github.com/giampaolo/psutil/issues/1752
|
||||
.. _1753: https://github.com/giampaolo/psutil/issues/1753
|
||||
.. _1754: https://github.com/giampaolo/psutil/issues/1754
|
||||
.. _1755: https://github.com/giampaolo/psutil/issues/1755
|
||||
.. _1756: https://github.com/giampaolo/psutil/issues/1756
|
||||
.. _1757: https://github.com/giampaolo/psutil/issues/1757
|
||||
.. _1758: https://github.com/giampaolo/psutil/issues/1758
|
||||
.. _1759: https://github.com/giampaolo/psutil/issues/1759
|
||||
.. _1760: https://github.com/giampaolo/psutil/issues/1760
|
||||
.. _1761: https://github.com/giampaolo/psutil/issues/1761
|
||||
.. _1762: https://github.com/giampaolo/psutil/issues/1762
|
||||
.. _1763: https://github.com/giampaolo/psutil/issues/1763
|
||||
.. _1764: https://github.com/giampaolo/psutil/issues/1764
|
||||
.. _1765: https://github.com/giampaolo/psutil/issues/1765
|
||||
.. _1766: https://github.com/giampaolo/psutil/issues/1766
|
||||
.. _1767: https://github.com/giampaolo/psutil/issues/1767
|
||||
.. _1768: https://github.com/giampaolo/psutil/issues/1768
|
||||
.. _1769: https://github.com/giampaolo/psutil/issues/1769
|
||||
.. _1770: https://github.com/giampaolo/psutil/issues/1770
|
||||
.. _1771: https://github.com/giampaolo/psutil/issues/1771
|
||||
.. _1772: https://github.com/giampaolo/psutil/issues/1772
|
||||
.. _1773: https://github.com/giampaolo/psutil/issues/1773
|
||||
.. _1774: https://github.com/giampaolo/psutil/issues/1774
|
||||
.. _1775: https://github.com/giampaolo/psutil/issues/1775
|
||||
.. _1776: https://github.com/giampaolo/psutil/issues/1776
|
||||
.. _1777: https://github.com/giampaolo/psutil/issues/1777
|
||||
.. _1778: https://github.com/giampaolo/psutil/issues/1778
|
||||
.. _1779: https://github.com/giampaolo/psutil/issues/1779
|
||||
.. _1780: https://github.com/giampaolo/psutil/issues/1780
|
||||
.. _1781: https://github.com/giampaolo/psutil/issues/1781
|
||||
.. _1782: https://github.com/giampaolo/psutil/issues/1782
|
||||
.. _1783: https://github.com/giampaolo/psutil/issues/1783
|
||||
.. _1784: https://github.com/giampaolo/psutil/issues/1784
|
||||
.. _1785: https://github.com/giampaolo/psutil/issues/1785
|
||||
.. _1786: https://github.com/giampaolo/psutil/issues/1786
|
||||
.. _1787: https://github.com/giampaolo/psutil/issues/1787
|
||||
.. _1788: https://github.com/giampaolo/psutil/issues/1788
|
||||
.. _1789: https://github.com/giampaolo/psutil/issues/1789
|
||||
.. _1790: https://github.com/giampaolo/psutil/issues/1790
|
||||
.. _1791: https://github.com/giampaolo/psutil/issues/1791
|
||||
.. _1792: https://github.com/giampaolo/psutil/issues/1792
|
||||
.. _1793: https://github.com/giampaolo/psutil/issues/1793
|
||||
.. _1794: https://github.com/giampaolo/psutil/issues/1794
|
||||
.. _1795: https://github.com/giampaolo/psutil/issues/1795
|
||||
.. _1796: https://github.com/giampaolo/psutil/issues/1796
|
||||
.. _1797: https://github.com/giampaolo/psutil/issues/1797
|
||||
.. _1798: https://github.com/giampaolo/psutil/issues/1798
|
||||
.. _1799: https://github.com/giampaolo/psutil/issues/1799
|
||||
.. _1800: https://github.com/giampaolo/psutil/issues/1800
|
||||
.. _1801: https://github.com/giampaolo/psutil/issues/1801
|
||||
.. _1802: https://github.com/giampaolo/psutil/issues/1802
|
||||
.. _1803: https://github.com/giampaolo/psutil/issues/1803
|
||||
.. _1804: https://github.com/giampaolo/psutil/issues/1804
|
||||
.. _1805: https://github.com/giampaolo/psutil/issues/1805
|
||||
.. _1806: https://github.com/giampaolo/psutil/issues/1806
|
||||
.. _1807: https://github.com/giampaolo/psutil/issues/1807
|
||||
.. _1808: https://github.com/giampaolo/psutil/issues/1808
|
||||
.. _1809: https://github.com/giampaolo/psutil/issues/1809
|
||||
.. _1810: https://github.com/giampaolo/psutil/issues/1810
|
||||
.. _1811: https://github.com/giampaolo/psutil/issues/1811
|
||||
.. _1812: https://github.com/giampaolo/psutil/issues/1812
|
||||
.. _1813: https://github.com/giampaolo/psutil/issues/1813
|
||||
.. _1814: https://github.com/giampaolo/psutil/issues/1814
|
||||
.. _1815: https://github.com/giampaolo/psutil/issues/1815
|
||||
.. _1816: https://github.com/giampaolo/psutil/issues/1816
|
||||
.. _1817: https://github.com/giampaolo/psutil/issues/1817
|
||||
.. _1818: https://github.com/giampaolo/psutil/issues/1818
|
||||
.. _1819: https://github.com/giampaolo/psutil/issues/1819
|
||||
.. _1820: https://github.com/giampaolo/psutil/issues/1820
|
||||
.. _1821: https://github.com/giampaolo/psutil/issues/1821
|
||||
.. _1822: https://github.com/giampaolo/psutil/issues/1822
|
||||
.. _1823: https://github.com/giampaolo/psutil/issues/1823
|
||||
.. _1824: https://github.com/giampaolo/psutil/issues/1824
|
||||
.. _1825: https://github.com/giampaolo/psutil/issues/1825
|
||||
.. _1826: https://github.com/giampaolo/psutil/issues/1826
|
||||
.. _1827: https://github.com/giampaolo/psutil/issues/1827
|
||||
.. _1828: https://github.com/giampaolo/psutil/issues/1828
|
||||
.. _1829: https://github.com/giampaolo/psutil/issues/1829
|
||||
.. _1830: https://github.com/giampaolo/psutil/issues/1830
|
||||
.. _1831: https://github.com/giampaolo/psutil/issues/1831
|
||||
.. _1832: https://github.com/giampaolo/psutil/issues/1832
|
||||
.. _1833: https://github.com/giampaolo/psutil/issues/1833
|
||||
.. _1834: https://github.com/giampaolo/psutil/issues/1834
|
||||
.. _1835: https://github.com/giampaolo/psutil/issues/1835
|
||||
.. _1836: https://github.com/giampaolo/psutil/issues/1836
|
||||
.. _1837: https://github.com/giampaolo/psutil/issues/1837
|
||||
.. _1838: https://github.com/giampaolo/psutil/issues/1838
|
||||
.. _1839: https://github.com/giampaolo/psutil/issues/1839
|
||||
.. _1840: https://github.com/giampaolo/psutil/issues/1840
|
||||
.. _1841: https://github.com/giampaolo/psutil/issues/1841
|
||||
.. _1842: https://github.com/giampaolo/psutil/issues/1842
|
||||
.. _1843: https://github.com/giampaolo/psutil/issues/1843
|
||||
.. _1844: https://github.com/giampaolo/psutil/issues/1844
|
||||
.. _1845: https://github.com/giampaolo/psutil/issues/1845
|
||||
.. _1846: https://github.com/giampaolo/psutil/issues/1846
|
||||
.. _1847: https://github.com/giampaolo/psutil/issues/1847
|
||||
.. _1848: https://github.com/giampaolo/psutil/issues/1848
|
||||
.. _1849: https://github.com/giampaolo/psutil/issues/1849
|
||||
.. _1850: https://github.com/giampaolo/psutil/issues/1850
|
||||
.. _1851: https://github.com/giampaolo/psutil/issues/1851
|
||||
.. _1852: https://github.com/giampaolo/psutil/issues/1852
|
||||
.. _1853: https://github.com/giampaolo/psutil/issues/1853
|
||||
.. _1854: https://github.com/giampaolo/psutil/issues/1854
|
||||
.. _1855: https://github.com/giampaolo/psutil/issues/1855
|
||||
.. _1856: https://github.com/giampaolo/psutil/issues/1856
|
||||
.. _1857: https://github.com/giampaolo/psutil/issues/1857
|
||||
.. _1858: https://github.com/giampaolo/psutil/issues/1858
|
||||
.. _1859: https://github.com/giampaolo/psutil/issues/1859
|
||||
.. _1860: https://github.com/giampaolo/psutil/issues/1860
|
||||
.. _1861: https://github.com/giampaolo/psutil/issues/1861
|
||||
.. _1862: https://github.com/giampaolo/psutil/issues/1862
|
||||
.. _1863: https://github.com/giampaolo/psutil/issues/1863
|
||||
.. _1864: https://github.com/giampaolo/psutil/issues/1864
|
||||
.. _1865: https://github.com/giampaolo/psutil/issues/1865
|
||||
.. _1866: https://github.com/giampaolo/psutil/issues/1866
|
||||
.. _1867: https://github.com/giampaolo/psutil/issues/1867
|
||||
.. _1868: https://github.com/giampaolo/psutil/issues/1868
|
||||
.. _1869: https://github.com/giampaolo/psutil/issues/1869
|
||||
.. _1870: https://github.com/giampaolo/psutil/issues/1870
|
||||
.. _1871: https://github.com/giampaolo/psutil/issues/1871
|
||||
.. _1872: https://github.com/giampaolo/psutil/issues/1872
|
||||
.. _1873: https://github.com/giampaolo/psutil/issues/1873
|
||||
.. _1874: https://github.com/giampaolo/psutil/issues/1874
|
||||
.. _1875: https://github.com/giampaolo/psutil/issues/1875
|
||||
.. _1876: https://github.com/giampaolo/psutil/issues/1876
|
||||
.. _1877: https://github.com/giampaolo/psutil/issues/1877
|
||||
.. _1878: https://github.com/giampaolo/psutil/issues/1878
|
||||
.. _1879: https://github.com/giampaolo/psutil/issues/1879
|
||||
.. _1880: https://github.com/giampaolo/psutil/issues/1880
|
||||
.. _1881: https://github.com/giampaolo/psutil/issues/1881
|
||||
.. _1882: https://github.com/giampaolo/psutil/issues/1882
|
||||
.. _1883: https://github.com/giampaolo/psutil/issues/1883
|
||||
.. _1884: https://github.com/giampaolo/psutil/issues/1884
|
||||
.. _1885: https://github.com/giampaolo/psutil/issues/1885
|
||||
.. _1886: https://github.com/giampaolo/psutil/issues/1886
|
||||
.. _1887: https://github.com/giampaolo/psutil/issues/1887
|
||||
.. _1888: https://github.com/giampaolo/psutil/issues/1888
|
||||
.. _1889: https://github.com/giampaolo/psutil/issues/1889
|
||||
.. _1890: https://github.com/giampaolo/psutil/issues/1890
|
||||
.. _1891: https://github.com/giampaolo/psutil/issues/1891
|
||||
.. _1892: https://github.com/giampaolo/psutil/issues/1892
|
||||
.. _1893: https://github.com/giampaolo/psutil/issues/1893
|
||||
.. _1894: https://github.com/giampaolo/psutil/issues/1894
|
||||
.. _1895: https://github.com/giampaolo/psutil/issues/1895
|
||||
.. _1896: https://github.com/giampaolo/psutil/issues/1896
|
||||
.. _1897: https://github.com/giampaolo/psutil/issues/1897
|
||||
.. _1898: https://github.com/giampaolo/psutil/issues/1898
|
||||
.. _1899: https://github.com/giampaolo/psutil/issues/1899
|
||||
.. _1900: https://github.com/giampaolo/psutil/issues/1900
|
||||
.. _1901: https://github.com/giampaolo/psutil/issues/1901
|
||||
.. _1902: https://github.com/giampaolo/psutil/issues/1902
|
||||
.. _1903: https://github.com/giampaolo/psutil/issues/1903
|
||||
.. _1904: https://github.com/giampaolo/psutil/issues/1904
|
||||
.. _1905: https://github.com/giampaolo/psutil/issues/1905
|
||||
.. _1906: https://github.com/giampaolo/psutil/issues/1906
|
||||
.. _1907: https://github.com/giampaolo/psutil/issues/1907
|
||||
.. _1908: https://github.com/giampaolo/psutil/issues/1908
|
||||
.. _1909: https://github.com/giampaolo/psutil/issues/1909
|
||||
.. _1910: https://github.com/giampaolo/psutil/issues/1910
|
||||
.. _1911: https://github.com/giampaolo/psutil/issues/1911
|
||||
.. _1912: https://github.com/giampaolo/psutil/issues/1912
|
||||
.. _1913: https://github.com/giampaolo/psutil/issues/1913
|
||||
.. _1914: https://github.com/giampaolo/psutil/issues/1914
|
||||
.. _1915: https://github.com/giampaolo/psutil/issues/1915
|
||||
.. _1916: https://github.com/giampaolo/psutil/issues/1916
|
||||
.. _1917: https://github.com/giampaolo/psutil/issues/1917
|
||||
.. _1918: https://github.com/giampaolo/psutil/issues/1918
|
||||
.. _1919: https://github.com/giampaolo/psutil/issues/1919
|
||||
.. _1920: https://github.com/giampaolo/psutil/issues/1920
|
||||
.. _1921: https://github.com/giampaolo/psutil/issues/1921
|
||||
.. _1922: https://github.com/giampaolo/psutil/issues/1922
|
||||
.. _1923: https://github.com/giampaolo/psutil/issues/1923
|
||||
.. _1924: https://github.com/giampaolo/psutil/issues/1924
|
||||
.. _1925: https://github.com/giampaolo/psutil/issues/1925
|
||||
.. _1926: https://github.com/giampaolo/psutil/issues/1926
|
||||
.. _1927: https://github.com/giampaolo/psutil/issues/1927
|
||||
.. _1928: https://github.com/giampaolo/psutil/issues/1928
|
||||
.. _1929: https://github.com/giampaolo/psutil/issues/1929
|
||||
.. _1930: https://github.com/giampaolo/psutil/issues/1930
|
||||
.. _1931: https://github.com/giampaolo/psutil/issues/1931
|
||||
.. _1932: https://github.com/giampaolo/psutil/issues/1932
|
||||
.. _1933: https://github.com/giampaolo/psutil/issues/1933
|
||||
.. _1934: https://github.com/giampaolo/psutil/issues/1934
|
||||
.. _1935: https://github.com/giampaolo/psutil/issues/1935
|
||||
.. _1936: https://github.com/giampaolo/psutil/issues/1936
|
||||
.. _1937: https://github.com/giampaolo/psutil/issues/1937
|
||||
.. _1938: https://github.com/giampaolo/psutil/issues/1938
|
||||
.. _1939: https://github.com/giampaolo/psutil/issues/1939
|
||||
.. _1940: https://github.com/giampaolo/psutil/issues/1940
|
||||
.. _1941: https://github.com/giampaolo/psutil/issues/1941
|
||||
.. _1942: https://github.com/giampaolo/psutil/issues/1942
|
||||
.. _1943: https://github.com/giampaolo/psutil/issues/1943
|
||||
.. _1944: https://github.com/giampaolo/psutil/issues/1944
|
||||
.. _1945: https://github.com/giampaolo/psutil/issues/1945
|
||||
.. _1946: https://github.com/giampaolo/psutil/issues/1946
|
||||
.. _1947: https://github.com/giampaolo/psutil/issues/1947
|
||||
.. _1948: https://github.com/giampaolo/psutil/issues/1948
|
||||
.. _1949: https://github.com/giampaolo/psutil/issues/1949
|
||||
.. _1950: https://github.com/giampaolo/psutil/issues/1950
|
||||
.. _1951: https://github.com/giampaolo/psutil/issues/1951
|
||||
.. _1952: https://github.com/giampaolo/psutil/issues/1952
|
||||
.. _1953: https://github.com/giampaolo/psutil/issues/1953
|
||||
.. _1954: https://github.com/giampaolo/psutil/issues/1954
|
||||
.. _1955: https://github.com/giampaolo/psutil/issues/1955
|
||||
.. _1956: https://github.com/giampaolo/psutil/issues/1956
|
||||
.. _1957: https://github.com/giampaolo/psutil/issues/1957
|
||||
.. _1958: https://github.com/giampaolo/psutil/issues/1958
|
||||
.. _1959: https://github.com/giampaolo/psutil/issues/1959
|
||||
.. _1960: https://github.com/giampaolo/psutil/issues/1960
|
||||
.. _1961: https://github.com/giampaolo/psutil/issues/1961
|
||||
.. _1962: https://github.com/giampaolo/psutil/issues/1962
|
||||
.. _1963: https://github.com/giampaolo/psutil/issues/1963
|
||||
.. _1964: https://github.com/giampaolo/psutil/issues/1964
|
||||
.. _1965: https://github.com/giampaolo/psutil/issues/1965
|
||||
.. _1966: https://github.com/giampaolo/psutil/issues/1966
|
||||
.. _1967: https://github.com/giampaolo/psutil/issues/1967
|
||||
.. _1968: https://github.com/giampaolo/psutil/issues/1968
|
||||
.. _1969: https://github.com/giampaolo/psutil/issues/1969
|
||||
.. _1970: https://github.com/giampaolo/psutil/issues/1970
|
||||
.. _1971: https://github.com/giampaolo/psutil/issues/1971
|
||||
.. _1972: https://github.com/giampaolo/psutil/issues/1972
|
||||
.. _1973: https://github.com/giampaolo/psutil/issues/1973
|
||||
.. _1974: https://github.com/giampaolo/psutil/issues/1974
|
||||
.. _1975: https://github.com/giampaolo/psutil/issues/1975
|
||||
.. _1976: https://github.com/giampaolo/psutil/issues/1976
|
||||
.. _1977: https://github.com/giampaolo/psutil/issues/1977
|
||||
.. _1978: https://github.com/giampaolo/psutil/issues/1978
|
||||
.. _1979: https://github.com/giampaolo/psutil/issues/1979
|
||||
.. _1980: https://github.com/giampaolo/psutil/issues/1980
|
||||
.. _1981: https://github.com/giampaolo/psutil/issues/1981
|
||||
.. _1982: https://github.com/giampaolo/psutil/issues/1982
|
||||
.. _1983: https://github.com/giampaolo/psutil/issues/1983
|
||||
.. _1984: https://github.com/giampaolo/psutil/issues/1984
|
||||
.. _1985: https://github.com/giampaolo/psutil/issues/1985
|
||||
.. _1986: https://github.com/giampaolo/psutil/issues/1986
|
||||
.. _1987: https://github.com/giampaolo/psutil/issues/1987
|
||||
.. _1988: https://github.com/giampaolo/psutil/issues/1988
|
||||
.. _1989: https://github.com/giampaolo/psutil/issues/1989
|
||||
.. _1990: https://github.com/giampaolo/psutil/issues/1990
|
||||
.. _1991: https://github.com/giampaolo/psutil/issues/1991
|
||||
.. _1992: https://github.com/giampaolo/psutil/issues/1992
|
||||
.. _1993: https://github.com/giampaolo/psutil/issues/1993
|
||||
.. _1994: https://github.com/giampaolo/psutil/issues/1994
|
||||
.. _1995: https://github.com/giampaolo/psutil/issues/1995
|
||||
.. _1996: https://github.com/giampaolo/psutil/issues/1996
|
||||
.. _1997: https://github.com/giampaolo/psutil/issues/1997
|
||||
.. _1998: https://github.com/giampaolo/psutil/issues/1998
|
||||
.. _1999: https://github.com/giampaolo/psutil/issues/1999
|
||||
.. _2000: https://github.com/giampaolo/psutil/issues/2000
|
||||
|
|
|
@ -93,7 +93,7 @@ OpenBSD
|
|||
::
|
||||
|
||||
export PKG_PATH=http://ftp.eu.openbsd.org/pub/OpenBSD/`uname -r`/packages/`uname -m`/
|
||||
pkg_add -v python3 gcc
|
||||
pkg_add -v python gcc
|
||||
python3 -m pip install psutil
|
||||
|
||||
NetBSD
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
include .cirrus.yml
|
||||
include .coveragerc
|
||||
include .gitignore
|
||||
include CREDITS
|
||||
|
@ -64,19 +65,25 @@ 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/global.c
|
||||
include psutil/arch/windows/global.h
|
||||
include psutil/arch/windows/inet_ntop.c
|
||||
include psutil/arch/windows/inet_ntop.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
|
||||
|
@ -108,14 +115,15 @@ 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/download_exes.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/scriptutils.py
|
||||
include scripts/internal/win_download_wheels.py
|
||||
include scripts/internal/winmake.py
|
||||
include scripts/iotop.py
|
||||
include scripts/killall.py
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# You can set the variables below from the command line.
|
||||
|
||||
PYTHON = python3
|
||||
TSCRIPT = psutil/tests/__main__.py
|
||||
TSCRIPT = psutil/tests/runner.py
|
||||
ARGS =
|
||||
# List of nice-to-have dev libs.
|
||||
DEPS = \
|
||||
|
@ -11,20 +11,22 @@ DEPS = \
|
|||
check-manifest \
|
||||
coverage \
|
||||
flake8 \
|
||||
pyperf \
|
||||
requests \
|
||||
setuptools \
|
||||
twine \
|
||||
virtualenv \
|
||||
wheel
|
||||
PY2_DEPS = \
|
||||
futures \
|
||||
ipaddress \
|
||||
mock==1.0.1 \
|
||||
perf \
|
||||
requests \
|
||||
setuptools \
|
||||
sphinx \
|
||||
twine \
|
||||
unittest2 \
|
||||
virtualenv \
|
||||
wheel
|
||||
|
||||
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')"`
|
||||
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
|
||||
|
@ -54,8 +56,7 @@ clean: ## Remove all build files.
|
|||
build/ \
|
||||
dist/ \
|
||||
docs/_build/ \
|
||||
htmlcov/ \
|
||||
tmp/
|
||||
htmlcov/
|
||||
|
||||
_:
|
||||
|
||||
|
@ -67,13 +68,11 @@ build: _ ## Compile without installing.
|
|||
@# "import psutil" when using the interactive interpreter from within
|
||||
@# this directory.
|
||||
PYTHONWARNINGS=all $(PYTHON) setup.py build_ext -i
|
||||
rm -rf tmp
|
||||
$(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)
|
||||
rm -rf tmp
|
||||
|
||||
uninstall: ## Uninstall this package via pip.
|
||||
cd ..; $(PYTHON) -m pip uninstall -y -v psutil || true
|
||||
|
@ -101,8 +100,8 @@ install-pip: ## Install pip (no-op if already installed).
|
|||
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 pip
|
||||
$(PYTHON) -m pip install $(INSTALL_OPTS) --upgrade $(DEPS)
|
||||
$(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
|
||||
|
@ -154,7 +153,7 @@ test-by-name: ## e.g. make test-by-name ARGS=psutil.tests.test_system.TestSyste
|
|||
|
||||
test-failed: ## Re-run tests which failed on last run
|
||||
${MAKE} install
|
||||
$(TEST_PREFIX) $(PYTHON) -c "import psutil.tests.runner as r; r.run(last_failed=True)"
|
||||
$(TEST_PREFIX) $(PYTHON) $(TSCRIPT) --last-failed
|
||||
|
||||
test-coverage: ## Run test coverage.
|
||||
${MAKE} install
|
||||
|
@ -170,8 +169,18 @@ test-coverage: ## Run test coverage.
|
|||
# Linters
|
||||
# ===================================================================
|
||||
|
||||
flake8: ## flake8 linter.
|
||||
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8
|
||||
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
|
||||
|
@ -197,7 +206,7 @@ wheel: ## Generate wheel.
|
|||
$(PYTHON) setup.py bdist_wheel
|
||||
|
||||
win-download-wheels: ## Download wheels hosted on appveyor.
|
||||
$(TEST_PREFIX) $(PYTHON) scripts/internal/download_exes.py --user giampaolo --project psutil
|
||||
$(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
|
||||
|
@ -254,10 +263,12 @@ print-timeline: ## Print releases' timeline.
|
|||
@$(PYTHON) scripts/internal/print_timeline.py
|
||||
|
||||
print-access-denied: ## Print AD exceptions
|
||||
@$(PYTHON) scripts/internal/print_access_denied.py
|
||||
${MAKE} install
|
||||
@$(TEST_PREFIX) $(PYTHON) scripts/internal/print_access_denied.py
|
||||
|
||||
print-api-speed: ## Benchmark all API calls
|
||||
@$(PYTHON) scripts/internal/print_api_speed.py $(ARGS)
|
||||
${MAKE} install
|
||||
@$(TEST_PREFIX) $(PYTHON) scripts/internal/print_api_speed.py $(ARGS)
|
||||
|
||||
# ===================================================================
|
||||
# Misc
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Metadata-Version: 1.2
|
||||
Name: psutil
|
||||
Version: 5.6.3
|
||||
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
|
||||
|
@ -8,7 +8,7 @@ Author-email: g.rodola@gmail.com
|
|||
License: BSD
|
||||
Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
||||
| |version| |py-versions| |packages| |license|
|
||||
| |travis| |appveyor| |doc| |twitter| |tidelift|
|
||||
| |travis| |appveyor| |cirrus| |doc| |twitter| |tidelift|
|
||||
|
||||
.. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pepy.tech/project/psutil
|
||||
|
@ -30,14 +30,18 @@ Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
|||
: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%20/%20osx
|
||||
.. |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
|
||||
.. |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)
|
||||
|
@ -104,30 +108,36 @@ Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
|||
- **Sun Solaris**
|
||||
- **AIX**
|
||||
|
||||
...both **32-bit** and **64-bit** architectures. Supported Python versions are **2.6**, **2.7** and **3.4+**. `PyPy <http://pypy.org/>`__ is also known to work.
|
||||
...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.
|
||||
|
||||
Professional support
|
||||
====================
|
||||
psutil for enterprise
|
||||
=====================
|
||||
|
||||
.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png
|
||||
:width: 100
|
||||
: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 100
|
||||
:widths: 10 150
|
||||
|
||||
* - |tideliftlogo|
|
||||
- Professional support for psutil is available as part of the
|
||||
`Tidelift Subscription`_.
|
||||
Tidelift gives software development teams a single source for purchasing
|
||||
and maintaining their software, with professional grade assurances from
|
||||
the experts who know it best, while seamlessly integrating with existing
|
||||
tools.
|
||||
By subscribing you will help me (`Giampaolo Rodola`_) support psutil
|
||||
future development. Alternatively consider making a small `donation`_.
|
||||
- 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>`__.
|
||||
|
||||
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
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
|
||||
====================
|
||||
|
@ -170,9 +180,7 @@ Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
|||
|
||||
- Go: https://github.com/shirou/gopsutil
|
||||
- C: https://github.com/hamon-in/cpslib
|
||||
- Node: https://github.com/christkv/node-psutil
|
||||
- Rust: https://github.com/borntyping/rust-psutil
|
||||
- Ruby: https://github.com/spacewander/posixpsutil
|
||||
- Nim: https://github.com/johnscillieri/psutil-nim
|
||||
|
||||
|
||||
|
@ -367,7 +375,7 @@ Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
|||
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)
|
||||
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()
|
||||
|
@ -393,8 +401,8 @@ Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
|||
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/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
|
||||
popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
|
||||
[popenfile(path='/home/giampaolo/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'),
|
||||
|
@ -436,6 +444,7 @@ Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
|||
>>> p.resume()
|
||||
>>>
|
||||
>>> p.terminate()
|
||||
>>> p.kill()
|
||||
>>> p.wait(timeout=3)
|
||||
0
|
||||
>>>
|
||||
|
@ -455,7 +464,7 @@ Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
|||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> for proc in psutil.process_iter(attrs=['pid', 'name']):
|
||||
>>> for proc in psutil.process_iter(['pid', 'name']):
|
||||
... print(proc.info)
|
||||
...
|
||||
{'pid': 1, 'name': 'systemd'}
|
||||
|
@ -515,6 +524,9 @@ Description: | |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
|||
|
||||
.. _`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
|
||||
|
@ -526,9 +538,16 @@ 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 NT/2000
|
||||
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
|
||||
|
@ -547,8 +566,10 @@ 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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
| |downloads| |stars| |forks| |contributors| |coverage| |quality|
|
||||
| |version| |py-versions| |packages| |license|
|
||||
| |travis| |appveyor| |doc| |twitter| |tidelift|
|
||||
| |travis| |appveyor| |cirrus| |doc| |twitter| |tidelift|
|
||||
|
||||
.. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||
:target: https://pepy.tech/project/psutil
|
||||
|
@ -22,14 +22,18 @@
|
|||
: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%20/%20osx
|
||||
.. |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
|
||||
.. |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)
|
||||
|
@ -96,30 +100,36 @@ psutil currently supports the following platforms:
|
|||
- **Sun Solaris**
|
||||
- **AIX**
|
||||
|
||||
...both **32-bit** and **64-bit** architectures. Supported Python versions are **2.6**, **2.7** and **3.4+**. `PyPy <http://pypy.org/>`__ is also known to work.
|
||||
...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.
|
||||
|
||||
Professional support
|
||||
====================
|
||||
psutil for enterprise
|
||||
=====================
|
||||
|
||||
.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png
|
||||
:width: 100
|
||||
: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 100
|
||||
:widths: 10 150
|
||||
|
||||
* - |tideliftlogo|
|
||||
- Professional support for psutil is available as part of the
|
||||
`Tidelift Subscription`_.
|
||||
Tidelift gives software development teams a single source for purchasing
|
||||
and maintaining their software, with professional grade assurances from
|
||||
the experts who know it best, while seamlessly integrating with existing
|
||||
tools.
|
||||
By subscribing you will help me (`Giampaolo Rodola`_) support psutil
|
||||
future development. Alternatively consider making a small `donation`_.
|
||||
- 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>`__.
|
||||
|
||||
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
|
||||
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
|
||||
====================
|
||||
|
@ -162,9 +172,7 @@ Portings
|
|||
|
||||
- Go: https://github.com/shirou/gopsutil
|
||||
- C: https://github.com/hamon-in/cpslib
|
||||
- Node: https://github.com/christkv/node-psutil
|
||||
- Rust: https://github.com/borntyping/rust-psutil
|
||||
- Ruby: https://github.com/spacewander/posixpsutil
|
||||
- Nim: https://github.com/johnscillieri/psutil-nim
|
||||
|
||||
|
||||
|
@ -359,7 +367,7 @@ Process management
|
|||
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)
|
||||
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()
|
||||
|
@ -385,8 +393,8 @@ Process management
|
|||
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/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
|
||||
popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
|
||||
[popenfile(path='/home/giampaolo/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'),
|
||||
|
@ -428,6 +436,7 @@ Process management
|
|||
>>> p.resume()
|
||||
>>>
|
||||
>>> p.terminate()
|
||||
>>> p.kill()
|
||||
>>> p.wait(timeout=3)
|
||||
0
|
||||
>>>
|
||||
|
@ -447,7 +456,7 @@ Further process APIs
|
|||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> for proc in psutil.process_iter(attrs=['pid', 'name']):
|
||||
>>> for proc in psutil.process_iter(['pid', 'name']):
|
||||
... print(proc.info)
|
||||
...
|
||||
{'pid': 1, 'name': 'systemd'}
|
||||
|
@ -507,3 +516,6 @@ Windows services
|
|||
|
||||
.. _`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
|
||||
|
||||
|
|
|
@ -1,24 +1,13 @@
|
|||
Setup and running tests
|
||||
=======================
|
||||
Build, setup and running tests
|
||||
===============================
|
||||
|
||||
If you plan on hacking on psutil this is what you're supposed to do first:
|
||||
|
||||
- clone the GIT repository:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git clone git@github.com:giampaolo/psutil.git
|
||||
|
||||
- install test deps and GIT hooks:
|
||||
Make sure to `install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`__
|
||||
a C compiler first, then:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone git@github.com:giampaolo/psutil.git
|
||||
make setup-dev-env
|
||||
|
||||
- run tests:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make test
|
||||
|
||||
- bear in mind that ``make``(see `Makefile`_) is the designated tool to run
|
||||
|
@ -47,7 +36,7 @@ Some useful make commands:
|
|||
make test # run unit tests
|
||||
make test-memleaks # run memory leak tests
|
||||
make test-coverage # run test coverage
|
||||
make flake8 # run PEP8 linter
|
||||
make lint # run Python (PEP8) and C linters
|
||||
|
||||
There are some differences between ``make`` on UNIX and Windows.
|
||||
For instance, to run a specific Python version. On UNIX:
|
||||
|
@ -60,13 +49,7 @@ On Windows:
|
|||
|
||||
.. code-block:: bat
|
||||
|
||||
set PYTHON=C:\python35\python.exe && make test
|
||||
|
||||
...or:
|
||||
|
||||
.. code-block:: bat
|
||||
|
||||
make -p 35 test
|
||||
make -p C:\python35\python.exe test
|
||||
|
||||
If you want to modify psutil and run a script on the fly which uses it do
|
||||
(on UNIX):
|
||||
|
@ -121,6 +104,7 @@ Make a pull request
|
|||
- commit your changes: ``git commit -am 'add some feature'``
|
||||
- push to the branch: ``git push origin new-feature``
|
||||
- create a new pull request by via github web interface
|
||||
- remember to update `HISTORY.rst`_ and `CREDITS`_ files.
|
||||
|
||||
Continuous integration
|
||||
======================
|
||||
|
@ -141,14 +125,18 @@ Both services run psutil test suite against all supported python version
|
|||
(2.6 - 3.6).
|
||||
Two icons in the home page (README) always show the build status:
|
||||
|
||||
.. image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux%20/%20macOS
|
||||
.. 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 and macOS tests (Travis)
|
||||
:alt: Linux, macOS and PyPy3 tests (Travis)
|
||||
|
||||
.. 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)
|
||||
|
||||
.. 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)
|
||||
|
||||
BSD, AIX and Solaris are currently tested manually.
|
||||
|
||||
Test coverage
|
||||
|
@ -200,3 +188,5 @@ These are notes for myself (Giampaolo):
|
|||
.. _`RsT syntax`: http://docutils.sourceforge.net/docs/user/rst/quickref.htm
|
||||
.. _`sphinx`: http://sphinx-doc.org
|
||||
.. _`Travis`: https://travis-ci.org/giampaolo/psuti
|
||||
.. _`HISTORY.rst`: https://github.com/giampaolo/psutil/blob/master/HISTORY.rst
|
||||
.. _`CREDITS`: https://github.com/giampaolo/psutil/blob/master/CREDITS
|
||||
|
|
|
@ -158,10 +158,11 @@ BUGFIXES
|
|||
|
||||
- #600: windows / open_files(): support network file handles.
|
||||
|
||||
REJECTED
|
||||
========
|
||||
REJECTED IDEAS
|
||||
==============
|
||||
|
||||
- #550: threads per core
|
||||
- #1667: process_iter(new_only=True)
|
||||
|
||||
INCONSISTENCIES
|
||||
===============
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
PYTHON = python
|
||||
PYTHON = python3
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = $(PYTHON) -m sphinx
|
||||
PAPER =
|
||||
|
@ -15,6 +15,9 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
|||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
DEPS = sphinx
|
||||
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
|
@ -224,3 +227,7 @@ dummy:
|
|||
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
|
||||
@echo
|
||||
@echo "Build finished. Dummy builder generates no files."
|
||||
|
||||
.PHONY: setup-dev-env
|
||||
setup-dev-env: ## Install GIT hooks, pip, test deps (also upgrades them).
|
||||
$(PYTHON) -m pip install --user --upgrade --trusted-host files.pythonhosted.org $(DEPS)
|
||||
|
|
|
@ -19,6 +19,26 @@
|
|||
padding-left: 20px !important;
|
||||
}
|
||||
|
||||
.rst-content ul p {
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.document td {
|
||||
padding-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.document th {
|
||||
padding-top: 0px !important;
|
||||
padding-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.document th p {
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.document th p {
|
||||
}
|
||||
|
||||
.function .descclassname {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ Quick links
|
|||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`__
|
||||
- `Forum <http://groups.google.com/group/psutil/topics>`__
|
||||
- `Download <https://pypi.org/project/psutil/#files>`__
|
||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
|
||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst>`_
|
||||
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`__
|
||||
|
||||
About
|
||||
|
@ -42,21 +42,45 @@ Supported Python versions are **2.6**, **2.7** and **3.4+**.
|
|||
|
||||
The psutil documentation you're reading is distributed as a single HTML page.
|
||||
|
||||
|
||||
Professional support
|
||||
--------------------
|
||||
|
||||
.. image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png
|
||||
:width: 80px
|
||||
:align: left
|
||||
|
||||
Professional support for psutil is available as part of the `Tidelift Subscription`_.
|
||||
Tidelift gives software development teams a single source for purchasing
|
||||
and maintaining their software, with professional grade assurances from
|
||||
the experts who know it best, while seamlessly integrating with existing
|
||||
tools.
|
||||
By subscribing you will help me (`Giampaolo Rodola`_) support psutil
|
||||
future development. Alternatively consider making a small `donation`_.
|
||||
To report a security vulnerability, please use the `Tidelift security
|
||||
contact`_. Tidelift will coordinate the fix and disclosure.
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
The easiest way to install psutil is via ``pip``::
|
||||
Linux Ubuntu / Debian::
|
||||
|
||||
pip install psutil
|
||||
sudo apt-get install gcc python3-dev
|
||||
sudo pip3 install psutil
|
||||
|
||||
On UNIX this requires a C compiler (e.g. gcc) installed. On Windows pip will
|
||||
automatically retrieve a pre-compiled wheel version from
|
||||
`PyPI repository <https://pypi.org/project/psutil>`__.
|
||||
Alternatively, see more detailed
|
||||
Linux Redhat::
|
||||
|
||||
sudo yum install gcc python3-devel
|
||||
sudo pip3 install psutil
|
||||
|
||||
Windows::
|
||||
|
||||
pip3 install psutil
|
||||
|
||||
For other platforms see more detailed
|
||||
`install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
||||
instructions.
|
||||
|
||||
|
||||
System related functions
|
||||
========================
|
||||
|
||||
|
@ -78,7 +102,8 @@ CPU
|
|||
|
||||
- **nice** *(UNIX)*: time spent by niced (prioritized) processes executing in
|
||||
user mode; on Linux this also includes **guest_nice** time
|
||||
- **iowait** *(Linux)*: time spent waiting for I/O to complete
|
||||
- **iowait** *(Linux)*: time spent waiting for I/O to complete. This is *not*
|
||||
accounted in **idle** time counter.
|
||||
- **irq** *(Linux, BSD)*: time spent for servicing hardware interrupts
|
||||
- **softirq** *(Linux)*: time spent for servicing software interrupts
|
||||
- **steal** *(Linux 2.6.11+)*: time spent by other operating systems running
|
||||
|
@ -161,8 +186,10 @@ CPU
|
|||
|
||||
Return the number of logical CPUs in the system (same as `os.cpu_count`_
|
||||
in Python 3.4) or ``None`` if undetermined.
|
||||
If *logical* is ``False`` return the number of physical cores only (hyper
|
||||
thread CPUs are excluded) or ``None`` if undetermined.
|
||||
*logical* cores means the number of physical cores multiplied by the number
|
||||
of threads that can run on each core (this is known as Hyper Threading).
|
||||
If *logical* is ``False`` return the number of physical cores only (Hyper
|
||||
Thread CPUs are excluded) or ``None`` if undetermined.
|
||||
On OpenBSD and NetBSD ``psutil.cpu_count(logical=False)`` always return
|
||||
``None``.
|
||||
Example on a system having 2 physical hyper-thread CPU cores:
|
||||
|
@ -241,19 +268,27 @@ CPU
|
|||
.. function:: getloadavg()
|
||||
|
||||
Return the average system load over the last 1, 5 and 15 minutes as a tuple.
|
||||
The load represents how many processes are waiting to be run by the
|
||||
operating system.
|
||||
On UNIX systems this relies on `os.getloadavg`_. On Windows this is
|
||||
emulated by using a Windows API that spawns a thread which updates the
|
||||
average every 5 seconds, mimicking the UNIX behavior. Thus, the first time
|
||||
this is called and for the next 5 seconds it will return a meaningless
|
||||
``(0.0, 0.0, 0.0)`` tuple. Example:
|
||||
The load represents the processes which are in a runnable state, either
|
||||
using the CPU or waiting to use the CPU (e.g. waiting for disk I/O).
|
||||
On UNIX systems this relies on `os.getloadavg`_. On Windows this is emulated
|
||||
by using a Windows API that spawns a thread which keeps running in
|
||||
background and updates the load average every 5 seconds, mimicking the UNIX
|
||||
behavior. Thus, the first time this is called and for the next 5 seconds
|
||||
it will return a meaningless ``(0.0, 0.0, 0.0)`` tuple.
|
||||
The numbers returned only make sense if related to the number of CPU cores
|
||||
installed on the system. So, for instance, `3.14` on a system with 10 CPU
|
||||
cores means that the system load was 31.4% percent over the last N minutes.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import psutil
|
||||
>>> psutil.getloadavg()
|
||||
(3.14, 3.89, 4.67)
|
||||
>>> psutil.cpu_count()
|
||||
10
|
||||
>>> # percentage representation
|
||||
>>> [x / psutil.cpu_count() * 100 for x in psutil.getloadavg()]
|
||||
[31.4, 38.9, 46.7]
|
||||
|
||||
Availability: Unix, Windows
|
||||
|
||||
|
@ -267,7 +302,7 @@ Memory
|
|||
Return statistics about system memory usage as a named tuple including the
|
||||
following fields, expressed in bytes. Main metrics:
|
||||
|
||||
- **total**: total physical memory.
|
||||
- **total**: total physical memory (exclusive swap).
|
||||
- **available**: the memory that can be given instantly to processes without
|
||||
the system going into swap.
|
||||
This is calculated by summing different memory values depending on the
|
||||
|
@ -353,7 +388,7 @@ Disks
|
|||
mount point and filesystem type, similarly to "df" command on UNIX. If *all*
|
||||
parameter is ``False`` it tries to distinguish and return physical devices
|
||||
only (e.g. hard disks, cd-rom drives, USB keys) and ignore all others
|
||||
(e.g. memory partitions such as /dev/shm).
|
||||
(e.g. pseudo, memory, duplicate, inaccessible filesystems).
|
||||
Note that this may not be fully reliable on all systems (e.g. on BSD this
|
||||
parameter is ignored).
|
||||
Named tuple's **fstype** field is a string which varies depending on the
|
||||
|
@ -513,7 +548,8 @@ Network
|
|||
to obtain a usable socket object.
|
||||
On Windows and SunOS this is always set to ``-1``.
|
||||
- **family**: the address family, either `AF_INET`_, `AF_INET6`_ or `AF_UNIX`_.
|
||||
- **type**: the address type, either `SOCK_STREAM`_ or `SOCK_DGRAM`_.
|
||||
- **type**: the address type, either `SOCK_STREAM`_, `SOCK_DGRAM`_ or
|
||||
`SOCK_SEQPACKET`_.
|
||||
- **laddr**: the local address as a ``(ip, port)`` named tuple or a ``path``
|
||||
in case of AF_UNIX sockets. For UNIX sockets see notes below.
|
||||
- **raddr**: the remote address as a ``(ip, port)`` named tuple or an
|
||||
|
@ -825,38 +861,24 @@ Functions
|
|||
|
||||
Return an iterator yielding a :class:`Process` class instance for all running
|
||||
processes on the local machine.
|
||||
Every instance is only created once and then cached into an internal table
|
||||
which is updated every time an element is yielded.
|
||||
Cached :class:`Process` instances are checked for identity so that you're
|
||||
safe in case a PID has been reused by another process, in which case the
|
||||
cached instance is updated.
|
||||
This is preferred over :func:`psutil.pids()` for iterating over processes.
|
||||
Sorting order in which processes are returned is based on their PID.
|
||||
This should be preferred over :func:`psutil.pids()` to iterate over processes
|
||||
as it's safe from race condition.
|
||||
|
||||
Every :class:`Process` instance is only created once, and then cached for the
|
||||
next time :func:`psutil.process_iter()` is called (if PID is still alive).
|
||||
Also it makes sure process PIDs are not reused.
|
||||
|
||||
*attrs* and *ad_value* have the same meaning as in :meth:`Process.as_dict()`.
|
||||
If *attrs* is specified :meth:`Process.as_dict()` is called internally and
|
||||
the resulting dict is stored as a ``info`` attribute which is attached to the
|
||||
returned :class:`Process` instances.
|
||||
If *attrs* is specified :meth:`Process.as_dict()` result will be stored as a
|
||||
``info`` attribute attached to the returned :class:`Process` instances.
|
||||
If *attrs* is an empty list it will retrieve all process info (slow).
|
||||
Example usage::
|
||||
|
||||
Sorting order in which processes are returned is based on their PID.
|
||||
|
||||
Example::
|
||||
|
||||
>>> import psutil
|
||||
>>> for proc in psutil.process_iter():
|
||||
... try:
|
||||
... pinfo = proc.as_dict(attrs=['pid', 'name', 'username'])
|
||||
... except psutil.NoSuchProcess:
|
||||
... pass
|
||||
... else:
|
||||
... print(pinfo)
|
||||
...
|
||||
{'name': 'systemd', 'pid': 1, 'username': 'root'}
|
||||
{'name': 'kthreadd', 'pid': 2, 'username': 'root'}
|
||||
{'name': 'ksoftirqd/0', 'pid': 3, 'username': 'root'}
|
||||
...
|
||||
|
||||
More compact version using *attrs* parameter::
|
||||
|
||||
>>> import psutil
|
||||
>>> for proc in psutil.process_iter(attrs=['pid', 'name', 'username']):
|
||||
>>> for proc in psutil.process_iter(['pid', 'name', 'username']):
|
||||
... print(proc.info)
|
||||
...
|
||||
{'name': 'systemd', 'pid': 1, 'username': 'root'}
|
||||
|
@ -864,27 +886,16 @@ Functions
|
|||
{'name': 'ksoftirqd/0', 'pid': 3, 'username': 'root'}
|
||||
...
|
||||
|
||||
Example of a dict comprehensions to create a ``{pid: info, ...}`` data
|
||||
structure::
|
||||
A dict comprehensions to create a ``{pid: info, ...}`` data structure::
|
||||
|
||||
>>> import psutil
|
||||
>>> procs = {p.pid: p.info for p in psutil.process_iter(attrs=['name', 'username'])}
|
||||
>>> procs = {p.pid: p.info for p in psutil.process_iter(['name', 'username'])}
|
||||
>>> procs
|
||||
{1: {'name': 'systemd', 'username': 'root'},
|
||||
2: {'name': 'kthreadd', 'username': 'root'},
|
||||
3: {'name': 'ksoftirqd/0', 'username': 'root'},
|
||||
...}
|
||||
|
||||
Example showing how to filter processes by name::
|
||||
|
||||
>>> import psutil
|
||||
>>> [p.info for p in psutil.process_iter(attrs=['pid', 'name']) if 'python' in p.info['name']]
|
||||
[{'name': 'python3', 'pid': 21947},
|
||||
{'name': 'python', 'pid': 23835}]
|
||||
|
||||
See also `process filtering <#filtering-and-sorting-processes>`__ section for
|
||||
more examples.
|
||||
|
||||
.. versionchanged::
|
||||
5.3.0 added "attrs" and "ad_value" parameters.
|
||||
|
||||
|
@ -898,11 +909,11 @@ Functions
|
|||
Convenience function which waits for a list of :class:`Process` instances to
|
||||
terminate. Return a ``(gone, alive)`` tuple indicating which processes are
|
||||
gone and which ones are still alive. The *gone* ones will have a new
|
||||
*returncode* attribute indicating process exit status (will be ``None`` for
|
||||
processes which are not our children).
|
||||
*returncode* attribute indicating process exit status as returned by
|
||||
:meth:`Process.wait`.
|
||||
``callback`` is a function which gets called when one of the processes being
|
||||
waited on is terminated and a :class:`Process` instance is passed as callback
|
||||
argument).
|
||||
argument (the instance will also have a *returncode* attribute set).
|
||||
This function will return as soon as all processes terminate or when
|
||||
*timeout* (seconds) occurs.
|
||||
Differently from :meth:`Process.wait` it will not raise
|
||||
|
@ -1069,9 +1080,9 @@ Process class
|
|||
+------------------------------+-------------------------------+------------------------------+------------------------------+--------------------------+--------------------------+
|
||||
| :meth:`gids` | | :meth:`name` | :meth:`num_ctx_switches` | :meth:`terminal` | :meth:`terminal` |
|
||||
+------------------------------+-------------------------------+------------------------------+------------------------------+--------------------------+--------------------------+
|
||||
| :meth:`num_ctx_switches` | | :meth:`ppid` | :meth:`ppid` | | |
|
||||
| :meth:`num_ctx_switches` | :meth:`exe` | :meth:`ppid` | :meth:`ppid` | | |
|
||||
+------------------------------+-------------------------------+------------------------------+------------------------------+--------------------------+--------------------------+
|
||||
| :meth:`num_threads` | | :meth:`status` | :meth:`status` | :meth:`gids` | :meth:`gids` |
|
||||
| :meth:`num_threads` | :meth:`name` | :meth:`status` | :meth:`status` | :meth:`gids` | :meth:`gids` |
|
||||
+------------------------------+-------------------------------+------------------------------+------------------------------+--------------------------+--------------------------+
|
||||
| :meth:`uids` | | :meth:`terminal` | :meth:`terminal` | :meth:`uids` | :meth:`uids` |
|
||||
+------------------------------+-------------------------------+------------------------------+------------------------------+--------------------------+--------------------------+
|
||||
|
@ -1205,6 +1216,8 @@ Process class
|
|||
|
||||
The process current working directory as an absolute path.
|
||||
|
||||
.. versionchanged:: 5.6.4 added support for NetBSD
|
||||
|
||||
.. method:: username()
|
||||
|
||||
The name of the user that owns the process. On UNIX this is calculated by
|
||||
|
@ -1287,13 +1300,15 @@ Process class
|
|||
Here's an example on how to set the highest I/O priority depending on what
|
||||
platform you're on::
|
||||
|
||||
import psutil
|
||||
p = psutil.Process()
|
||||
if psutil.LINUX
|
||||
p.ionice(psutil.IOPRIO_CLASS_RT, value=7)
|
||||
else: # Windows
|
||||
p.ionice(psutil.IOPRIO_HIGH)
|
||||
p.ionice() # get
|
||||
>>> import psutil
|
||||
>>> p = psutil.Process()
|
||||
>>> if psutil.LINUX:
|
||||
... p.ionice(psutil.IOPRIO_CLASS_RT, value=7)
|
||||
... else:
|
||||
... p.ionice(psutil.IOPRIO_HIGH)
|
||||
...
|
||||
>>> p.ionice() # get
|
||||
pionice(ioclass=<IOPriority.IOPRIO_CLASS_RT: 1>, value=7)
|
||||
|
||||
Availability: Linux, Windows Vista+
|
||||
|
||||
|
@ -1401,16 +1416,33 @@ Process class
|
|||
|
||||
.. method:: cpu_times()
|
||||
|
||||
Return a `(user, system, children_user, children_system)` named tuple
|
||||
representing the accumulated process time, in seconds (see
|
||||
`explanation <http://stackoverflow.com/questions/556405/>`__).
|
||||
On Windows and macOS only *user* and *system* are filled, the others are
|
||||
set to ``0``.
|
||||
Return a named tuple representing the accumulated process times, in seconds
|
||||
(see `explanation <http://stackoverflow.com/questions/556405/>`__).
|
||||
This is similar to `os.times`_ but can be used for any process PID.
|
||||
|
||||
- **user**: time spent in user mode.
|
||||
- **system**: time spent in kernel mode.
|
||||
- **children_user**: user time of all child processes (always ``0`` on
|
||||
Windows and macOS).
|
||||
- **system_user**: user time of all child processes (always ``0`` on
|
||||
Windows and macOS).
|
||||
- **iowait**: (Linux) time spent waiting for blocking I/O to complete.
|
||||
This value is excluded from `user` and `system` times count (because the
|
||||
CPU is not doing any work).
|
||||
|
||||
>>> import psutil
|
||||
>>> p = psutil.Process()
|
||||
>>> p.cpu_times()
|
||||
pcputimes(user=0.03, system=0.67, children_user=0.0, children_system=0.0, iowait=0.08)
|
||||
>>> sum(p.cpu_times()[:2]) # cumulative, excluding children and iowait
|
||||
0.70
|
||||
|
||||
.. versionchanged::
|
||||
4.1.0 return two extra fields: *children_user* and *children_system*.
|
||||
|
||||
.. versionchanged::
|
||||
5.6.4 added *iowait* on Linux.
|
||||
|
||||
.. method:: cpu_percent(interval=None)
|
||||
|
||||
Return a float representing the process CPU utilization as a percentage
|
||||
|
@ -1752,13 +1784,12 @@ Process class
|
|||
on Windows this method is not reliable due to some limitations of the
|
||||
underlying Windows API which may hang when retrieving certain file
|
||||
handles.
|
||||
In order to work around that psutil spawns a thread for each handle and
|
||||
kills it if it's not responding after 100ms.
|
||||
In order to work around that psutil spawns a thread to determine the file
|
||||
handle name and kills it if it's not responding after 100ms.
|
||||
That implies that this method on Windows is not guaranteed to enumerate
|
||||
all regular file handles (see
|
||||
`issue 597 <https://github.com/giampaolo/psutil/pull/597>`_).
|
||||
Also, it will only list files living in the C:\\ drive (see
|
||||
`issue 1020 <https://github.com/giampaolo/psutil/pull/1020>`_).
|
||||
Tools like ProcessHacker has the same limitation.
|
||||
|
||||
.. warning::
|
||||
on BSD this method can return files with a null path ("") due to a
|
||||
|
@ -1782,7 +1813,8 @@ Process class
|
|||
always set to ``-1``.
|
||||
- **family**: the address family, either `AF_INET`_, `AF_INET6`_ or
|
||||
`AF_UNIX`_.
|
||||
- **type**: the address type, either `SOCK_STREAM`_ or `SOCK_DGRAM`_.
|
||||
- **type**: the address type, either `SOCK_STREAM`_, `SOCK_DGRAM`_ or
|
||||
`SOCK_SEQPACKET`_. .
|
||||
- **laddr**: the local address as a ``(ip, port)`` named tuple or a ``path``
|
||||
in case of AF_UNIX sockets. For UNIX sockets see notes below.
|
||||
- **raddr**: the remote address as a ``(ip, port)`` named tuple or an
|
||||
|
@ -2189,7 +2221,7 @@ Process priority constants
|
|||
.. data:: IOPRIO_NORMAL
|
||||
.. data:: IOPRIO_HIGH
|
||||
|
||||
A set of integers representing the I/O priority of a process on Linux.
|
||||
A set of integers representing the I/O priority of a process on Windows.
|
||||
They can be used in conjunction with :meth:`psutil.Process.ionice()` to get
|
||||
or set process I/O priority.
|
||||
|
||||
|
@ -2291,46 +2323,6 @@ Hardware constants
|
|||
>>> if psutil.version_info >= (4, 5):
|
||||
... pass
|
||||
|
||||
----
|
||||
|
||||
Unicode
|
||||
=======
|
||||
|
||||
Starting from version 5.3.0 psutil adds unicode support, see `issue #1040`_.
|
||||
The notes below apply to *any* API returning a string such as
|
||||
:meth:`Process.exe` or :meth:`Process.cwd`, including non-filesystem related
|
||||
methods such as :meth:`Process.username` or :meth:`WindowsService.description`:
|
||||
|
||||
* 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:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> unicode(p.exe(), sys.getdefaultencoding(), errors="replace")
|
||||
|
||||
Example which filters processes with a funky name working with both Python 2
|
||||
and 3::
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
import psutil, sys
|
||||
|
||||
PY3 = sys.version_info[0] == 2
|
||||
LOOKFOR = u"ƒőő"
|
||||
for proc in psutil.process_iter(attrs=['name']):
|
||||
name = proc.info['name']
|
||||
if not PY3:
|
||||
name = unicode(name, sys.getdefaultencoding(), errors="replace")
|
||||
if LOOKFOR == name:
|
||||
print("process %s found" % p)
|
||||
|
||||
Recipes
|
||||
=======
|
||||
|
||||
|
@ -2346,7 +2338,7 @@ Check string against :meth:`Process.name()`:
|
|||
def find_procs_by_name(name):
|
||||
"Return a list of processes matching 'name'."
|
||||
ls = []
|
||||
for p in psutil.process_iter(attrs=['name']):
|
||||
for p in psutil.process_iter(['name']):
|
||||
if p.info['name'] == name:
|
||||
ls.append(p)
|
||||
return ls
|
||||
|
@ -2362,7 +2354,7 @@ A bit more advanced, check string against :meth:`Process.name()`,
|
|||
def find_procs_by_name(name):
|
||||
"Return a list of processes matching 'name'."
|
||||
ls = []
|
||||
for p in psutil.process_iter(attrs=["name", "exe", "cmdline"]):
|
||||
for p in psutil.process_iter(["name", "exe", "cmdline"]):
|
||||
if name == p.info['name'] or \
|
||||
p.info['exe'] and os.path.basename(p.info['exe']) == name or \
|
||||
p.info['cmdline'] and p.info['cmdline'][0] == name:
|
||||
|
@ -2396,83 +2388,34 @@ Kill process tree
|
|||
callback=on_terminate)
|
||||
return (gone, alive)
|
||||
|
||||
Terminate my children
|
||||
---------------------
|
||||
|
||||
This may be useful in unit tests whenever sub-processes are started.
|
||||
This will help ensure that no extra children (zombies) stick around to hog
|
||||
resources.
|
||||
|
||||
::
|
||||
|
||||
import psutil
|
||||
|
||||
def reap_children(timeout=3):
|
||||
"Tries hard to terminate and ultimately kill all the children of this process."
|
||||
def on_terminate(proc):
|
||||
print("process {} terminated with exit code {}".format(proc, proc.returncode))
|
||||
|
||||
procs = psutil.Process().children()
|
||||
# send SIGTERM
|
||||
for p in procs:
|
||||
try:
|
||||
p.terminate()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
gone, alive = psutil.wait_procs(procs, timeout=timeout, callback=on_terminate)
|
||||
if alive:
|
||||
# send SIGKILL
|
||||
for p in alive:
|
||||
print("process {} survived SIGTERM; trying SIGKILL" % p)
|
||||
try:
|
||||
p.kill()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
gone, alive = psutil.wait_procs(alive, timeout=timeout, callback=on_terminate)
|
||||
if alive:
|
||||
# give up
|
||||
for p in alive:
|
||||
print("process {} survived SIGKILL; giving up" % p)
|
||||
|
||||
Filtering and sorting processes
|
||||
-------------------------------
|
||||
|
||||
This is a collection of one-liners showing how to use :func:`process_iter()` in
|
||||
order to filter for processes and sort them.
|
||||
|
||||
Setup::
|
||||
A collection of code samples showing how to use :func:`process_iter()` to filter processes and sort them. Setup::
|
||||
|
||||
>>> import psutil
|
||||
>>> from pprint import pprint as pp
|
||||
|
||||
Processes having "python" in their name::
|
||||
|
||||
>>> pp([p.info for p in psutil.process_iter(attrs=['pid', 'name']) if 'python' in p.info['name']])
|
||||
[{'name': 'python3', 'pid': 21947},
|
||||
{'name': 'python', 'pid': 23835}]
|
||||
|
||||
Processes owned by user::
|
||||
|
||||
>>> import getpass
|
||||
>>> pp([(p.pid, p.info['name']) for p in psutil.process_iter(attrs=['name', 'username']) if p.info['username'] == getpass.getuser()])
|
||||
>>> pp([(p.pid, p.info['name']) for p in psutil.process_iter(['name', 'username']) if p.info['username'] == getpass.getuser()])
|
||||
(16832, 'bash'),
|
||||
(19772, 'ssh'),
|
||||
(20492, 'python')]
|
||||
|
||||
Processes actively running::
|
||||
|
||||
>>> pp([(p.pid, p.info) for p in psutil.process_iter(attrs=['name', 'status']) if p.info['status'] == psutil.STATUS_RUNNING])
|
||||
>>> pp([(p.pid, p.info) for p in psutil.process_iter(['name', 'status']) if p.info['status'] == psutil.STATUS_RUNNING])
|
||||
[(1150, {'name': 'Xorg', 'status': 'running'}),
|
||||
(1776, {'name': 'unity-panel-service', 'status': 'running'}),
|
||||
(20492, {'name': 'python', 'status': 'running'})]
|
||||
|
||||
Processes using log files::
|
||||
|
||||
>>> import os
|
||||
>>> import psutil
|
||||
>>> for p in psutil.process_iter(attrs=['name', 'open_files']):
|
||||
>>> for p in psutil.process_iter(['name', 'open_files']):
|
||||
... for file in p.info['open_files'] or []:
|
||||
... if os.path.splitext(file.path)[1] == '.log':
|
||||
... if file.path.endswith('.log'):
|
||||
... print("%-5s %-10s %s" % (p.pid, p.info['name'][:10], file.path))
|
||||
...
|
||||
1510 upstart /home/giampaolo/.cache/upstart/unity-settings-daemon.log
|
||||
|
@ -2481,39 +2424,18 @@ Processes using log files::
|
|||
|
||||
Processes consuming more than 500M of memory::
|
||||
|
||||
>>> pp([(p.pid, p.info['name'], p.info['memory_info'].rss) for p in psutil.process_iter(attrs=['name', 'memory_info']) if p.info['memory_info'].rss > 500 * 1024 * 1024])
|
||||
>>> pp([(p.pid, p.info['name'], p.info['memory_info'].rss) for p in psutil.process_iter(['name', 'memory_info']) if p.info['memory_info'].rss > 500 * 1024 * 1024])
|
||||
[(2650, 'chrome', 532324352),
|
||||
(3038, 'chrome', 1120088064),
|
||||
(21915, 'sublime_text', 615407616)]
|
||||
|
||||
Top 3 most memory consuming processes::
|
||||
|
||||
>>> pp([(p.pid, p.info) for p in sorted(psutil.process_iter(attrs=['name', 'memory_percent']), key=lambda p: p.info['memory_percent'])][-3:])
|
||||
[(21915, {'memory_percent': 3.6815453247662737, 'name': 'sublime_text'}),
|
||||
(3038, {'memory_percent': 6.732935429979187, 'name': 'chrome'}),
|
||||
(3249, {'memory_percent': 8.994554843376399, 'name': 'chrome'})]
|
||||
|
||||
Top 3 processes which consumed the most CPU time::
|
||||
|
||||
>>> pp([(p.pid, p.info['name'], sum(p.info['cpu_times'])) for p in sorted(psutil.process_iter(attrs=['name', 'cpu_times']), key=lambda p: sum(p.info['cpu_times'][:2]))][-3:])
|
||||
>>> pp([(p.pid, p.info['name'], sum(p.info['cpu_times'])) for p in sorted(psutil.process_iter(['name', 'cpu_times']), key=lambda p: sum(p.info['cpu_times'][:2]))][-3:])
|
||||
[(2721, 'chrome', 10219.73),
|
||||
(1150, 'Xorg', 11116.989999999998),
|
||||
(2650, 'chrome', 18451.97)]
|
||||
|
||||
Top 3 processes which caused the most I/O::
|
||||
|
||||
>>> pp([(p.pid, p.info['name']) for p in sorted(psutil.process_iter(attrs=['name', 'io_counters']), key=lambda p: p.info['io_counters'] and p.info['io_counters'][:2])][-3:])
|
||||
[(21915, 'sublime_text'),
|
||||
(1871, 'pulseaudio'),
|
||||
(1510, 'upstart')]
|
||||
|
||||
Top 3 processes opening more file descriptors::
|
||||
|
||||
>>> pp([(p.pid, p.info) for p in sorted(psutil.process_iter(attrs=['name', 'num_fds']), key=lambda p: p.info['num_fds'])][-3:])
|
||||
[(21915, {'name': 'sublime_text', 'num_fds': 105}),
|
||||
(2721, {'name': 'chrome', 'num_fds': 185}),
|
||||
(2650, {'name': 'chrome', 'num_fds': 354})]
|
||||
|
||||
Bytes conversion
|
||||
----------------
|
||||
|
||||
|
@ -2546,28 +2468,6 @@ Bytes conversion
|
|||
100399730688
|
||||
93.5G
|
||||
|
||||
Supported platforms
|
||||
===================
|
||||
|
||||
These are the platforms I develop and test on:
|
||||
|
||||
* Linux Ubuntu 16.04
|
||||
* MacOS 10.11 El Captain
|
||||
* Windows 10
|
||||
* Solaris 10
|
||||
* FreeBSD 11
|
||||
* OpenBSD 6.4
|
||||
* NetBSD 8.0
|
||||
* AIX 6.1 TL8 (maintainer `Arnon Yaari <https://github.com/wiggin15>`__)
|
||||
|
||||
Earlier versions are supposed to work but are not tested.
|
||||
For Linux, Windows and MacOS we have continuos integration. Other platforms
|
||||
are tested manually from time to time.
|
||||
Oldest supported Windows version is Windows XP, which can be compiled from
|
||||
sources. Latest wheel supporting Windows XP is
|
||||
`psutil 2.1.3 <https://pypi.org/project/psutil/2.1.3/#files>`__.
|
||||
Supported Python versions are 3.4+, 2.7 and 2.6.
|
||||
|
||||
FAQs
|
||||
====
|
||||
|
||||
|
@ -2576,7 +2476,7 @@ FAQs
|
|||
especially on macOS (see `issue #883`_) and Windows.
|
||||
Unfortunately there's not much you can do about this except running the
|
||||
Python process with higher privileges.
|
||||
On Unix you may run the the Python process as root or use the SUID bit
|
||||
On Unix you may run the Python process as root or use the SUID bit
|
||||
(this is the trick used by tools such as ``ps`` and ``netstat``).
|
||||
On Windows you may run the Python process as NT AUTHORITY\\SYSTEM or install
|
||||
the Python script as a Windows service (this is the trick used by tools
|
||||
|
@ -2585,25 +2485,58 @@ FAQs
|
|||
Running tests
|
||||
=============
|
||||
|
||||
There are two ways of running tests. If psutil is already installed use::
|
||||
::
|
||||
|
||||
$ python -m psutil.tests
|
||||
|
||||
You can use this method as a quick way to make sure psutil fully works on your
|
||||
platform. If you have a copy of the source code you can also use::
|
||||
|
||||
$ make test
|
||||
$ python3 -m psutil.tests
|
||||
|
||||
Development guide
|
||||
=================
|
||||
|
||||
If you plan on hacking on psutil (e.g. want to add a new feature or fix a bug)
|
||||
If you want to hacking on psutil (e.g. want to add a new feature or fix a bug)
|
||||
take a look at the `development guide`_.
|
||||
|
||||
Platforms support history
|
||||
=========================
|
||||
|
||||
* psutil 5.7.0 (2020-02): drop Windows XP & Server 2003 support
|
||||
* psutil 5.7.0 (2020-02): **PyPy** on Windows
|
||||
* psutil 5.4.0 (2017-11): **AIX**
|
||||
* psutil 3.4.1 (2016-01): **NetBSD**
|
||||
* psutil 3.3.0 (2015-11): **OpenBSD**
|
||||
* psutil 1.0.0 (2013-07): **Solaris**
|
||||
* psutil 0.1.1 (2009-03): **FreeBSD**
|
||||
* psutil 0.1.0 (2009-01): **Linux, Windows, macOS**
|
||||
|
||||
Supported Python versions are 2.6, 2.7, 3.4+ and PyPy3.
|
||||
|
||||
Timeline
|
||||
========
|
||||
|
||||
- 2019-0426:
|
||||
- 2020-02-18:
|
||||
`5.7.0 <https://pypi.org/project/psutil/5.7.0/#files>`__ -
|
||||
`what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#570>`__ -
|
||||
`diff <https://github.com/giampaolo/psutil/compare/release-5.6.7...release-5.7.0#files_bucket>`__
|
||||
- 2019-11-26:
|
||||
`5.6.7 <https://pypi.org/project/psutil/5.6.7/#files>`__ -
|
||||
`what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#567>`__ -
|
||||
`diff <https://github.com/giampaolo/psutil/compare/release-5.6.6...release-5.6.7#files_bucket>`__
|
||||
- 2019-11-25:
|
||||
`5.6.6 <https://pypi.org/project/psutil/5.6.6/#files>`__ -
|
||||
`what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#566>`__ -
|
||||
`diff <https://github.com/giampaolo/psutil/compare/release-5.6.5...release-5.6.6#files_bucket>`__
|
||||
- 2019-11-06:
|
||||
`5.6.5 <https://pypi.org/project/psutil/5.6.5/#files>`__ -
|
||||
`what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#565>`__ -
|
||||
`diff <https://github.com/giampaolo/psutil/compare/release-5.6.4...release-5.6.5#files_bucket>`__
|
||||
- 2019-11-04:
|
||||
`5.6.4 <https://pypi.org/project/psutil/5.6.4/#files>`__ -
|
||||
`what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#564>`__ -
|
||||
`diff <https://github.com/giampaolo/psutil/compare/release-5.6.3...release-5.6.4#files_bucket>`__
|
||||
- 2019-06-11:
|
||||
`5.6.3 <https://pypi.org/project/psutil/5.6.3/#files>`__ -
|
||||
`what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#563>`__ -
|
||||
`diff <https://github.com/giampaolo/psutil/compare/release-5.6.2...release-5.6.3#files_bucket>`__
|
||||
- 2019-04-26:
|
||||
`5.6.2 <https://pypi.org/project/psutil/5.6.2/#files>`__ -
|
||||
`what's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst#562>`__ -
|
||||
`diff <https://github.com/giampaolo/psutil/compare/release-5.6.1...release-5.6.2#files_bucket>`__
|
||||
|
@ -2902,13 +2835,15 @@ Timeline
|
|||
.. _`BPO-6973`: https://bugs.python.org/issue6973
|
||||
.. _`CPU affinity`: https://www.linuxjournal.com/article/6799?page=0,0
|
||||
.. _`cpu_distribution.py`: https://github.com/giampaolo/psutil/blob/master/scripts/cpu_distribution.py
|
||||
.. _`development guide`: https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst
|
||||
.. _`development guide`: https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst
|
||||
.. _`disk_usage.py`: https://github.com/giampaolo/psutil/blob/master/scripts/disk_usage.py
|
||||
.. _`donation`: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||
.. _`enums`: https://docs.python.org/3/library/enum.html#module-enum
|
||||
.. _`fans.py`: https://github.com/giampaolo/psutil/blob/master/scripts/fans.py
|
||||
.. _`GetDriveType`: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getdrivetypea
|
||||
.. _`getfsstat`: http://www.manpagez.com/man/2/getfsstat/
|
||||
.. _`GetPriorityClass`: https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getpriorityclass
|
||||
.. _`Giampaolo Rodola`: http://grodola.blogspot.com/p/about.html
|
||||
.. _`hash`: https://docs.python.org/3/library/functions.html#hash
|
||||
.. _`ifconfig.py`: https://github.com/giampaolo/psutil/blob/master/scripts/ifconfig.py
|
||||
.. _`ioprio_get`: https://linux.die.net/man/2/ioprio_get
|
||||
|
@ -2919,7 +2854,7 @@ Timeline
|
|||
.. _`issue #883`: https://github.com/giampaolo/psutil/issues/883
|
||||
.. _`man prlimit`: https://linux.die.net/man/2/prlimit
|
||||
.. _`meminfo.py`: https://github.com/giampaolo/psutil/blob/master/scripts/meminfo.py
|
||||
.. _`netstat.py`: https://github.com/giampaolo/psutil/blob/master/scripts/netstat.py.
|
||||
.. _`netstat.py`: https://github.com/giampaolo/psutil/blob/master/scripts/netstat.py
|
||||
.. _`nettop.py`: https://github.com/giampaolo/psutil/blob/master/scripts/nettop.py
|
||||
.. _`open`: https://docs.python.org/3/library/functions.html#open
|
||||
.. _`os.cpu_count`: https://docs.python.org/3/library/os.html#os.cpu_count
|
||||
|
@ -2944,8 +2879,11 @@ Timeline
|
|||
.. _`shutil.disk_usage`: https://docs.python.org/3/library/shutil.html#shutil.disk_usage.
|
||||
.. _`signal module`: https://docs.python.org//library/signal.html
|
||||
.. _`SOCK_DGRAM`: https://docs.python.org/3/library/socket.html#socket.SOCK_DGRAM
|
||||
.. _`SOCK_SEQPACKET`: https://docs.python.org/3/library/socket.html#socket.SOCK_SEQPACKET
|
||||
.. _`SOCK_STREAM`: https://docs.python.org/3/library/socket.html#socket.SOCK_STREAM
|
||||
.. _`socket.fromfd`: https://docs.python.org/3/library/socket.html#socket.fromfd
|
||||
.. _`subprocess.Popen`: https://docs.python.org/3/library/subprocess.html#subprocess.Popen
|
||||
.. _`temperatures.py`: https://github.com/giampaolo/psutil/blob/master/scripts/temperatures.py
|
||||
.. _`TerminateProcess`: https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-terminateprocess
|
||||
.. _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
|
||||
|
|
|
@ -20,15 +20,15 @@ rem set PYTHON=C:\Python34\python.exe & set TSCRIPT=foo.py & make.bat test
|
|||
rem ==========================================================================
|
||||
|
||||
if "%PYTHON%" == "" (
|
||||
if exist "C:\Python37\python.exe" (
|
||||
set PYTHON=C:\Python37\python.exe
|
||||
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\__main__.py
|
||||
set TSCRIPT=psutil\tests\runner.py
|
||||
)
|
||||
|
||||
rem Needed to locate the .pypirc file and upload exes on PyPI.
|
||||
|
|
|
@ -25,7 +25,6 @@ from __future__ import division
|
|||
import collections
|
||||
import contextlib
|
||||
import datetime
|
||||
import errno
|
||||
import functools
|
||||
import os
|
||||
import signal
|
||||
|
@ -39,11 +38,18 @@ except ImportError:
|
|||
pwd = None
|
||||
|
||||
from . import _common
|
||||
from ._common import AccessDenied
|
||||
from ._common import deprecated_method
|
||||
from ._common import Error
|
||||
from ._common import memoize
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import TimeoutExpired
|
||||
from ._common import wrap_numbers as _wrap_numbers
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import long
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3 as _PY3
|
||||
|
||||
from ._common import STATUS_DEAD
|
||||
|
@ -221,7 +227,7 @@ __all__ = [
|
|||
|
||||
__all__.extend(_psplatform.__extra__all__)
|
||||
__author__ = "Giampaolo Rodola'"
|
||||
__version__ = "5.6.3"
|
||||
__version__ = "5.7.0"
|
||||
version_info = tuple([int(num) for num in __version__.split('.')])
|
||||
|
||||
_timer = getattr(time, 'monotonic', time.time)
|
||||
|
@ -253,112 +259,6 @@ if (int(__version__.replace('.', '')) !=
|
|||
raise ImportError(msg)
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- Exceptions
|
||||
# =====================================================================
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Base exception class. All other psutil exceptions inherit
|
||||
from this one.
|
||||
"""
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
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."""
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
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
|
||||
|
||||
|
||||
# Push exception classes into platform specific module namespace.
|
||||
_psplatform.NoSuchProcess = NoSuchProcess
|
||||
_psplatform.ZombieProcess = ZombieProcess
|
||||
_psplatform.AccessDenied = AccessDenied
|
||||
_psplatform.TimeoutExpired = TimeoutExpired
|
||||
if POSIX:
|
||||
from . import _psposix
|
||||
_psposix.TimeoutExpired = TimeoutExpired
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- Utils
|
||||
# =====================================================================
|
||||
|
@ -875,7 +775,7 @@ class Process(object):
|
|||
"""
|
||||
return self._proc.io_counters()
|
||||
|
||||
# Linux and Windows >= Vista only
|
||||
# Linux and Windows
|
||||
if hasattr(_psplatform.Process, "ionice_get"):
|
||||
|
||||
def ionice(self, ioclass=None, value=None):
|
||||
|
@ -1290,8 +1190,7 @@ class Process(object):
|
|||
"calling process (os.getpid()) instead of PID 0")
|
||||
try:
|
||||
os.kill(self.pid, sig)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ESRCH:
|
||||
except ProcessLookupError:
|
||||
if OPENBSD and pid_exists(self.pid):
|
||||
# We do this because os.kill() lies in case of
|
||||
# zombie processes.
|
||||
|
@ -1299,9 +1198,8 @@ class Process(object):
|
|||
else:
|
||||
self._gone = True
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
|
||||
@_assert_pid_not_reused
|
||||
def send_signal(self, sig):
|
||||
|
@ -1313,16 +1211,7 @@ class Process(object):
|
|||
if POSIX:
|
||||
self._send_signal(sig)
|
||||
else: # pragma: no cover
|
||||
if sig == signal.SIGTERM:
|
||||
self._proc.kill()
|
||||
# py >= 2.7
|
||||
elif sig in (getattr(signal, "CTRL_C_EVENT", object()),
|
||||
getattr(signal, "CTRL_BREAK_EVENT", object())):
|
||||
self._proc.send_signal(sig)
|
||||
else:
|
||||
raise ValueError(
|
||||
"only SIGTERM, CTRL_C_EVENT and CTRL_BREAK_EVENT signals "
|
||||
"are supported on Windows")
|
||||
|
||||
@_assert_pid_not_reused
|
||||
def suspend(self):
|
||||
|
@ -1370,6 +1259,8 @@ class Process(object):
|
|||
def wait(self, timeout=None):
|
||||
"""Wait for process to terminate and, if process is a children
|
||||
of os.getpid(), also return its exit code, else None.
|
||||
On Windows there's no such limitation (exit code is always
|
||||
returned).
|
||||
|
||||
If the process is already terminated immediately return None
|
||||
instead of raising NoSuchProcess.
|
||||
|
@ -1634,6 +1525,7 @@ def wait_procs(procs, timeout=None, callback=None):
|
|||
pass
|
||||
else:
|
||||
if returncode is not None or not proc.is_running():
|
||||
# Set new Process instance attribute.
|
||||
proc.returncode = returncode
|
||||
gone.add(proc)
|
||||
if callback is not None:
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# Note: this module is imported by setup.py so it should not import
|
||||
# psutil or third-party modules.
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import division, print_function
|
||||
|
||||
import contextlib
|
||||
import errno
|
||||
|
@ -23,6 +23,7 @@ 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:
|
||||
|
@ -37,14 +38,14 @@ if sys.version_info >= (3, 4):
|
|||
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__ = [
|
||||
# constants
|
||||
# OS constants
|
||||
'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'MACOS', 'OSX', 'POSIX',
|
||||
'SUNOS', 'WINDOWS',
|
||||
'ENCODING', 'ENCODING_ERRS', 'AF_INET6',
|
||||
# connection constants
|
||||
'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED',
|
||||
'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN',
|
||||
|
@ -56,6 +57,8 @@ __all__ = [
|
|||
'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',
|
||||
|
@ -64,7 +67,9 @@ __all__ = [
|
|||
'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',
|
||||
'bytes2human', 'conn_to_ntuple', 'debug',
|
||||
# shell utils
|
||||
'hilite', 'term_supports_colors', 'print_color',
|
||||
]
|
||||
|
||||
|
||||
|
@ -257,7 +262,109 @@ if AF_UNIX is not None:
|
|||
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||
})
|
||||
|
||||
del AF_INET, 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
|
||||
|
||||
|
||||
# ===================================================================
|
||||
|
@ -268,12 +375,12 @@ del AF_INET, AF_UNIX, SOCK_STREAM, SOCK_DGRAM
|
|||
def usage_percent(used, total, round_=None):
|
||||
"""Calculate percentage usage of 'used' against 'total'."""
|
||||
try:
|
||||
ret = (used / total) * 100
|
||||
ret = (float(used) / total) * 100
|
||||
except ZeroDivisionError:
|
||||
ret = 0.0 if isinstance(used, float) or isinstance(total, float) else 0
|
||||
if round_ is not None:
|
||||
return round(ret, round_)
|
||||
return 0.0
|
||||
else:
|
||||
if round_ is not None:
|
||||
ret = round(ret, round_)
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -447,7 +554,7 @@ def sockfam_to_enum(num):
|
|||
else: # pragma: no cover
|
||||
try:
|
||||
return socket.AddressFamily(num)
|
||||
except (ValueError, AttributeError):
|
||||
except ValueError:
|
||||
return num
|
||||
|
||||
|
||||
|
@ -459,11 +566,30 @@ def socktype_to_enum(num):
|
|||
return num
|
||||
else: # pragma: no cover
|
||||
try:
|
||||
return socket.AddressType(num)
|
||||
except (ValueError, AttributeError):
|
||||
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.
|
||||
|
@ -632,3 +758,89 @@ if PY3:
|
|||
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
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
"""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"]
|
||||
"lru_cache", "which", "get_terminal_size",
|
||||
"FileNotFoundError", "PermissionError", "ProcessLookupError",
|
||||
"InterruptedError", "ChildProcessError", "FileExistsError"]
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
|
@ -38,6 +41,86 @@ else:
|
|||
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
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
"""AIX platform implementation."""
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import glob
|
||||
import os
|
||||
|
@ -14,21 +13,24 @@ import re
|
|||
import subprocess
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET
|
||||
|
||||
from . import _common
|
||||
from . import _psposix
|
||||
from . import _psutil_aix as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AF_INET6
|
||||
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 sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
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
|
||||
|
||||
|
||||
|
@ -80,13 +82,6 @@ proc_info_map = dict(
|
|||
status=6,
|
||||
ttynr=7)
|
||||
|
||||
# These objects get set on "import psutil" from the __init__.py
|
||||
# file, see: https://github.com/giampaolo/psutil/issues/1402
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
|
@ -220,27 +215,17 @@ def net_connections(kind, _pid=-1):
|
|||
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||
families, types = _common.conn_tmap[kind]
|
||||
rawlist = cext.net_connections(_pid)
|
||||
ret = set()
|
||||
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
|
||||
status = TCP_STATUSES[status]
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
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)
|
||||
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():
|
||||
|
@ -327,22 +312,16 @@ def wrap_exceptions(fun):
|
|||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except EnvironmentError as err:
|
||||
# support for private module import
|
||||
if (NoSuchProcess is None or AccessDenied is None or
|
||||
ZombieProcess is None):
|
||||
raise
|
||||
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 err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
||||
|
@ -501,11 +480,9 @@ class Process(object):
|
|||
try:
|
||||
result = os.readlink("%s/%s/cwd" % (procfs_path, self.pid))
|
||||
return result.rstrip('/')
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||
return None
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
|
|
|
@ -10,25 +10,29 @@ import functools
|
|||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import namedtuple
|
||||
from socket import AF_INET
|
||||
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 AF_INET6
|
||||
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 sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
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__ = []
|
||||
|
||||
|
||||
|
@ -134,13 +138,6 @@ kinfo_proc_map = dict(
|
|||
name=24,
|
||||
)
|
||||
|
||||
# These objects get set on "import psutil" from the __init__.py
|
||||
# file, see: https://github.com/giampaolo/psutil/issues/1402
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
|
@ -399,22 +396,8 @@ def net_connections(kind):
|
|||
fd, fam, type, laddr, raddr, status, pid = item
|
||||
# TODO: apply filter at C level
|
||||
if fam in families and type in types:
|
||||
try:
|
||||
status = TCP_STATUSES[status]
|
||||
except KeyError:
|
||||
# XXX: Not sure why this happens. I saw this occurring
|
||||
# with IPv6 sockets opened by 'vim'. Those sockets
|
||||
# have a very short lifetime so maybe the kernel
|
||||
# can't initialize their status?
|
||||
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES, pid)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
@ -551,6 +534,14 @@ 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.
|
||||
|
@ -559,19 +550,19 @@ def wrap_exceptions(fun):
|
|||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
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
|
||||
if err.errno == errno.ESRCH:
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
@ -581,18 +572,16 @@ def wrap_exceptions_procfs(inst):
|
|||
"""Same as above, for routines relying on reading /proc fs."""
|
||||
try:
|
||||
yield
|
||||
except EnvironmentError as err:
|
||||
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 err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
if not pid_exists(inst.pid):
|
||||
raise NoSuchProcess(inst.pid, inst._name)
|
||||
else:
|
||||
raise ZombieProcess(inst.pid, inst._name, inst._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(inst.pid, inst._name)
|
||||
raise
|
||||
|
||||
|
||||
class Process(object):
|
||||
|
@ -633,6 +622,8 @@ class Process(object):
|
|||
@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:
|
||||
|
@ -648,7 +639,7 @@ class Process(object):
|
|||
# cmdline arg (may return None).
|
||||
cmdline = self.cmdline()
|
||||
if cmdline:
|
||||
return which(cmdline[0])
|
||||
return which(cmdline[0]) or ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
@ -665,10 +656,14 @@ class Process(object):
|
|||
return cext.proc_cmdline(self.pid)
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINVAL:
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
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:
|
||||
|
@ -769,25 +764,15 @@ class Process(object):
|
|||
|
||||
if NETBSD:
|
||||
families, types = conn_tmap[kind]
|
||||
ret = set()
|
||||
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:
|
||||
try:
|
||||
status = TCP_STATUSES[status]
|
||||
except KeyError:
|
||||
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
ret.add(nt)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
self._assert_alive()
|
||||
return list(ret)
|
||||
|
||||
|
@ -796,18 +781,13 @@ class Process(object):
|
|||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
status = TCP_STATUSES[status]
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
|
||||
if OPENBSD:
|
||||
self._assert_alive()
|
||||
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
|
@ -844,10 +824,7 @@ class Process(object):
|
|||
# it into None
|
||||
if OPENBSD and self.pid == 0:
|
||||
return None # ...else it would raise EINVAL
|
||||
elif NETBSD:
|
||||
with wrap_exceptions_procfs(self):
|
||||
return os.readlink("/proc/%s/cwd" % self.pid)
|
||||
elif HAS_PROC_OPEN_FILES:
|
||||
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
|
||||
|
|
|
@ -25,6 +25,8 @@ from . import _common
|
|||
from . import _psposix
|
||||
from . import _psutil_linux as cext
|
||||
from . import _psutil_posix as cext_posix
|
||||
from ._common import AccessDenied
|
||||
from ._common import debug
|
||||
from ._common import decode
|
||||
from ._common import get_procfs_path
|
||||
from ._common import isfile_strict
|
||||
|
@ -33,14 +35,19 @@ 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 open_binary
|
||||
from ._common import open_text
|
||||
from ._common import parse_environ_block
|
||||
from ._common import path_exists_strict
|
||||
from ._common import supports_ipv6
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import b
|
||||
from ._compat import basestring
|
||||
from ._compat import FileNotFoundError
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
from ._compat import PY3
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
|
@ -70,6 +77,7 @@ POWER_SUPPLY_PATH = "/sys/class/power_supply"
|
|||
HAS_SMAPS = os.path.exists('/proc/%s/smaps' % os.getpid())
|
||||
HAS_PRLIMIT = hasattr(cext, "linux_prlimit")
|
||||
HAS_PROC_IO_PRIORITY = hasattr(cext, "proc_ioprio_get")
|
||||
HAS_CPU_AFFINITY = hasattr(cext, "proc_cpu_affinity_get")
|
||||
_DEFAULT = object()
|
||||
|
||||
# RLIMIT_* constants, not guaranteed to be present on all kernels
|
||||
|
@ -157,13 +165,6 @@ TCP_STATUSES = {
|
|||
"0B": _common.CONN_CLOSING
|
||||
}
|
||||
|
||||
# These objects get set on "import psutil" from the __init__.py
|
||||
# file, see: https://github.com/giampaolo/psutil/issues/1402
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
|
@ -200,6 +201,10 @@ pmmap_ext = namedtuple(
|
|||
pio = namedtuple('pio', ['read_count', 'write_count',
|
||||
'read_bytes', 'write_bytes',
|
||||
'read_chars', 'write_chars'])
|
||||
# psutil.Process.cpu_times()
|
||||
pcputimes = namedtuple('pcputimes',
|
||||
['user', 'system', 'children_user', 'children_system',
|
||||
'iowait'])
|
||||
|
||||
|
||||
# =====================================================================
|
||||
|
@ -747,6 +752,8 @@ class Connections:
|
|||
"""
|
||||
|
||||
def __init__(self):
|
||||
# The string represents the basename of the corresponding
|
||||
# /proc/net/{proto_name} file.
|
||||
tcp4 = ("tcp", socket.AF_INET, socket.SOCK_STREAM)
|
||||
tcp6 = ("tcp6", socket.AF_INET6, socket.SOCK_STREAM)
|
||||
udp4 = ("udp", socket.AF_INET, socket.SOCK_DGRAM)
|
||||
|
@ -772,16 +779,15 @@ class Connections:
|
|||
for fd in os.listdir("%s/%s/fd" % (self._procfs_path, pid)):
|
||||
try:
|
||||
inode = readlink("%s/%s/fd/%s" % (self._procfs_path, pid, fd))
|
||||
except OSError as err:
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# ENOENT == file which is gone in the meantime;
|
||||
# os.stat('/proc/%s' % self.pid) will be done later
|
||||
# to force NSP (if it's the case)
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
continue
|
||||
elif err.errno == errno.EINVAL:
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINVAL:
|
||||
# not a link
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
if inode.startswith('socket:['):
|
||||
|
@ -795,7 +801,7 @@ class Connections:
|
|||
for pid in pids():
|
||||
try:
|
||||
inodes.update(self.get_proc_inodes(pid))
|
||||
except OSError as err:
|
||||
except (FileNotFoundError, ProcessLookupError, PermissionError):
|
||||
# os.listdir() is gonna raise a lot of access denied
|
||||
# exceptions in case of unprivileged user; that's fine
|
||||
# as we'll just end up returning a connection with PID
|
||||
|
@ -803,9 +809,7 @@ class Connections:
|
|||
# Both netstat -an and lsof does the same so it's
|
||||
# unlikely we can do any better.
|
||||
# ENOENT just means a PID disappeared on us.
|
||||
if err.errno not in (
|
||||
errno.ENOENT, errno.ESRCH, errno.EPERM, errno.EACCES):
|
||||
raise
|
||||
continue
|
||||
return inodes
|
||||
|
||||
@staticmethod
|
||||
|
@ -933,7 +937,7 @@ class Connections:
|
|||
path = tokens[-1]
|
||||
else:
|
||||
path = ""
|
||||
type_ = int(type_)
|
||||
type_ = _common.socktype_to_enum(int(type_))
|
||||
# XXX: determining the remote endpoint of a
|
||||
# UNIX socket on Linux is not possible, see:
|
||||
# https://serverfault.com/questions/252723/
|
||||
|
@ -954,15 +958,14 @@ class Connections:
|
|||
else:
|
||||
inodes = self.get_all_inodes()
|
||||
ret = set()
|
||||
for f, family, type_ in self.tmap[kind]:
|
||||
for proto_name, family, type_ in self.tmap[kind]:
|
||||
path = "%s/net/%s" % (self._procfs_path, proto_name)
|
||||
if family in (socket.AF_INET, socket.AF_INET6):
|
||||
ls = self.process_inet(
|
||||
"%s/net/%s" % (self._procfs_path, f),
|
||||
family, type_, inodes, filter_pid=pid)
|
||||
path, family, type_, inodes, filter_pid=pid)
|
||||
else:
|
||||
ls = self.process_unix(
|
||||
"%s/net/%s" % (self._procfs_path, f),
|
||||
family, inodes, filter_pid=pid)
|
||||
path, family, inodes, filter_pid=pid)
|
||||
for fd, family, type_, laddr, raddr, status, bound_pid in ls:
|
||||
if pid:
|
||||
conn = _common.pconn(fd, family, type_, laddr, raddr,
|
||||
|
@ -1065,6 +1068,7 @@ def disk_io_counters(perdisk=False):
|
|||
# "3 1 hda1 8 8 8 8"
|
||||
# 4.18+ has 4 fields added:
|
||||
# "3 0 hda 8 8 8 8 8 8 8 8 8 8 8 0 0 0 0"
|
||||
# 5.5 has 2 more fields.
|
||||
# See:
|
||||
# https://www.kernel.org/doc/Documentation/iostats.txt
|
||||
# https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats
|
||||
|
@ -1079,7 +1083,7 @@ def disk_io_counters(perdisk=False):
|
|||
reads = int(fields[2])
|
||||
(reads_merged, rbytes, rtime, writes, writes_merged,
|
||||
wbytes, wtime, _, busy_time, _) = map(int, fields[4:14])
|
||||
elif flen == 14 or flen == 18:
|
||||
elif flen == 14 or flen >= 18:
|
||||
# Linux 2.6+, line referring to a disk
|
||||
name = fields[2]
|
||||
(reads, reads_merged, rbytes, rtime, writes, writes_merged,
|
||||
|
@ -1103,7 +1107,7 @@ def disk_io_counters(perdisk=False):
|
|||
fields = f.read().strip().split()
|
||||
name = os.path.basename(root)
|
||||
(reads, reads_merged, rbytes, rtime, writes, writes_merged,
|
||||
wbytes, wtime, _, busy_time, _) = map(int, fields)
|
||||
wbytes, wtime, _, busy_time) = map(int, fields[:10])
|
||||
yield (name, reads, writes, rbytes, wbytes, rtime,
|
||||
wtime, reads_merged, writes_merged, busy_time)
|
||||
|
||||
|
@ -1174,6 +1178,7 @@ def disk_partitions(all=False):
|
|||
continue
|
||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||
retlist.append(ntuple)
|
||||
|
||||
return retlist
|
||||
|
||||
|
||||
|
@ -1201,6 +1206,8 @@ def sensors_temperatures():
|
|||
# https://github.com/giampaolo/psutil/issues/971
|
||||
# https://github.com/nicolargo/glances/issues/1060
|
||||
basenames.extend(glob.glob('/sys/class/hwmon/hwmon*/device/temp*_*'))
|
||||
basenames.extend(glob.glob(
|
||||
'/sys/devices/platform/coretemp.*/hwmon/hwmon*/temp*_*'))
|
||||
basenames = sorted(set([x.split('_')[0] for x in basenames]))
|
||||
|
||||
for base in basenames:
|
||||
|
@ -1209,7 +1216,7 @@ def sensors_temperatures():
|
|||
current = float(cat(path)) / 1000.0
|
||||
path = os.path.join(os.path.dirname(base), 'name')
|
||||
unit_name = cat(path, binary=False)
|
||||
except (IOError, OSError, ValueError) as err:
|
||||
except (IOError, OSError, ValueError):
|
||||
# A lot of things can go wrong here, so let's just skip the
|
||||
# whole entry. Sure thing is Linux's /sys/class/hwmon really
|
||||
# is a stinky broken mess.
|
||||
|
@ -1218,8 +1225,6 @@ def sensors_temperatures():
|
|||
# https://github.com/giampaolo/psutil/issues/1129
|
||||
# https://github.com/giampaolo/psutil/issues/1245
|
||||
# https://github.com/giampaolo/psutil/issues/1323
|
||||
warnings.warn("ignoring %r for file %r" % (err, path),
|
||||
RuntimeWarning)
|
||||
continue
|
||||
|
||||
high = cat(base + '_max', fallback=None)
|
||||
|
@ -1251,8 +1256,7 @@ def sensors_temperatures():
|
|||
path = os.path.join(base, 'type')
|
||||
unit_name = cat(path, binary=False)
|
||||
except (IOError, OSError, ValueError) as err:
|
||||
warnings.warn("ignoring %r for file %r" % (err, path),
|
||||
RuntimeWarning)
|
||||
debug("ignoring %r for file %r" % (err, path))
|
||||
continue
|
||||
|
||||
trip_paths = glob.glob(base + '/trip_point*')
|
||||
|
@ -1490,11 +1494,10 @@ def ppid_map():
|
|||
try:
|
||||
with open_binary("%s/%s/stat" % (procfs_path, pid)) as f:
|
||||
data = f.read()
|
||||
except EnvironmentError as err:
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# Note: we should be able to access /stat for all processes
|
||||
# aka it's unlikely we'll bump into EPERM, which is good.
|
||||
if err.errno not in (errno.ENOENT, errno.ESRCH):
|
||||
raise
|
||||
pass
|
||||
else:
|
||||
rpar = data.rfind(b')')
|
||||
dset = data[rpar + 2:].split()
|
||||
|
@ -1511,16 +1514,12 @@ def wrap_exceptions(fun):
|
|||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except EnvironmentError as err:
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
# ESRCH (no such process) can be raised on read() if
|
||||
# process is gone in the meantime.
|
||||
if err.errno == errno.ESRCH:
|
||||
except ProcessLookupError:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
# ENOENT (no such file or directory) can be raised on open().
|
||||
if err.errno == errno.ENOENT and not os.path.exists("%s/%s" % (
|
||||
self._procfs_path, self.pid)):
|
||||
except FileNotFoundError:
|
||||
if not os.path.exists("%s/%s" % (self._procfs_path, self.pid)):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
# Note: zombies will keep existing under /proc until they're
|
||||
# gone so there's no way to distinguish them in here.
|
||||
|
@ -1576,6 +1575,7 @@ class Process(object):
|
|||
ret['children_stime'] = fields[14]
|
||||
ret['create_time'] = fields[19]
|
||||
ret['cpu_num'] = fields[36]
|
||||
ret['blkio_ticks'] = fields[39] # aka 'delayacct_blkio_ticks'
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -1617,8 +1617,7 @@ class Process(object):
|
|||
def exe(self):
|
||||
try:
|
||||
return readlink("%s/%s/exe" % (self._procfs_path, self.pid))
|
||||
except OSError as err:
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# no such file error; might be raised also if the
|
||||
# path actually exists for system processes with
|
||||
# low pids (about 0-20)
|
||||
|
@ -1629,9 +1628,8 @@ class Process(object):
|
|||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def cmdline(self):
|
||||
|
@ -1650,7 +1648,13 @@ class Process(object):
|
|||
sep = '\x00' if data.endswith('\x00') else ' '
|
||||
if data.endswith(sep):
|
||||
data = data[:-1]
|
||||
return data.split(sep)
|
||||
cmdline = data.split(sep)
|
||||
# Sometimes last char is a null byte '\0' but the args are
|
||||
# separated by spaces, see: https://github.com/giampaolo/psutil/
|
||||
# issues/1179#issuecomment-552984549
|
||||
if sep == '\x00' and len(cmdline) == 1 and ' ' in data:
|
||||
cmdline = data.split(' ')
|
||||
return cmdline
|
||||
|
||||
@wrap_exceptions
|
||||
def environ(self):
|
||||
|
@ -1707,7 +1711,8 @@ class Process(object):
|
|||
stime = float(values['stime']) / CLOCK_TICKS
|
||||
children_utime = float(values['children_utime']) / CLOCK_TICKS
|
||||
children_stime = float(values['children_stime']) / CLOCK_TICKS
|
||||
return _common.pcputimes(utime, stime, children_utime, children_stime)
|
||||
iowait = float(values['blkio_ticks']) / CLOCK_TICKS
|
||||
return pcputimes(utime, stime, children_utime, children_stime, iowait)
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_num(self):
|
||||
|
@ -1839,7 +1844,7 @@ class Process(object):
|
|||
path = path[:-10]
|
||||
ls.append((
|
||||
decode(addr), decode(perms), path,
|
||||
data[b'Rss:'],
|
||||
data.get(b'Rss:', 0),
|
||||
data.get(b'Size:', 0),
|
||||
data.get(b'Pss:', 0),
|
||||
data.get(b'Shared_Clean:', 0),
|
||||
|
@ -1856,14 +1861,12 @@ class Process(object):
|
|||
def cwd(self):
|
||||
try:
|
||||
return readlink("%s/%s/cwd" % (self._procfs_path, self.pid))
|
||||
except OSError as err:
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# https://github.com/giampaolo/psutil/issues/986
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self,
|
||||
|
@ -1899,13 +1902,11 @@ class Process(object):
|
|||
try:
|
||||
with open_binary(fname) as f:
|
||||
st = f.read().strip()
|
||||
except IOError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
# no such file or directory; it means thread
|
||||
# disappeared on us
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
# ignore the first two values ("pid (exe)")
|
||||
st = st[st.find(b')') + 2:]
|
||||
values = st.split(b' ')
|
||||
|
@ -1930,6 +1931,9 @@ class Process(object):
|
|||
def nice_set(self, value):
|
||||
return cext_posix.setpriority(self.pid, value)
|
||||
|
||||
# starting from CentOS 6.
|
||||
if HAS_CPU_AFFINITY:
|
||||
|
||||
@wrap_exceptions
|
||||
def cpu_affinity_get(self):
|
||||
return cext.proc_cpu_affinity_get(self.pid)
|
||||
|
@ -2029,15 +2033,14 @@ class Process(object):
|
|||
file = "%s/%s/fd/%s" % (self._procfs_path, self.pid, fd)
|
||||
try:
|
||||
path = readlink(file)
|
||||
except OSError as err:
|
||||
except (FileNotFoundError, ProcessLookupError):
|
||||
# ENOENT == file which is gone in the meantime
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
hit_enoent = True
|
||||
continue
|
||||
elif err.errno == errno.EINVAL:
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINVAL:
|
||||
# not a link
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
# If path is not an absolute there's no way to tell
|
||||
|
@ -2052,13 +2055,10 @@ class Process(object):
|
|||
with open_binary(file) as f:
|
||||
pos = int(f.readline().split()[1])
|
||||
flags = int(f.readline().split()[1], 8)
|
||||
except IOError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
# fd gone in the meantime; process may
|
||||
# still be alive
|
||||
hit_enoent = True
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
mode = file_flags_to_mode(flags)
|
||||
ntuple = popenfile(
|
||||
|
|
|
@ -8,21 +8,23 @@ import contextlib
|
|||
import errno
|
||||
import functools
|
||||
import os
|
||||
from socket import AF_INET
|
||||
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 AF_INET6
|
||||
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 sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
from ._common import usage_percent
|
||||
from ._common import ZombieProcess
|
||||
from ._compat import PermissionError
|
||||
from ._compat import ProcessLookupError
|
||||
|
||||
|
||||
__extra__all__ = []
|
||||
|
@ -84,13 +86,6 @@ pidtaskinfo_map = dict(
|
|||
volctxsw=7,
|
||||
)
|
||||
|
||||
# These objects get set on "import psutil" from the __init__.py
|
||||
# file, see: https://github.com/giampaolo/psutil/issues/1402
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
|
@ -337,12 +332,10 @@ def wrap_exceptions(fun):
|
|||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ESRCH:
|
||||
except ProcessLookupError:
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
except PermissionError:
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
except cext.ZombieProcessError:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
return wrapper
|
||||
|
@ -529,15 +522,8 @@ class Process(object):
|
|||
ret = []
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status = item
|
||||
status = TCP_STATUSES[status]
|
||||
fam = sockfam_to_enum(fam)
|
||||
type = socktype_to_enum(type)
|
||||
if fam in (AF_INET, AF_INET6):
|
||||
if laddr:
|
||||
laddr = _common.addr(*laddr)
|
||||
if raddr:
|
||||
raddr = _common.addr(*raddr)
|
||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status,
|
||||
TCP_STATUSES)
|
||||
ret.append(nt)
|
||||
return ret
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
"""Routines common to all posix systems."""
|
||||
|
||||
import errno
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
|
@ -12,7 +11,13 @@ 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
|
||||
|
||||
|
@ -20,11 +25,6 @@ from ._compat import unicode
|
|||
__all__ = ['pid_exists', 'wait_pid', 'disk_usage', 'get_terminal_map']
|
||||
|
||||
|
||||
# This object gets set on "import psutil" from the __init__.py
|
||||
# file, see: https://github.com/giampaolo/psutil/issues/1402
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
def pid_exists(pid):
|
||||
"""Check whether pid exists in the current process table."""
|
||||
if pid == 0:
|
||||
|
@ -36,19 +36,13 @@ def pid_exists(pid):
|
|||
return True
|
||||
try:
|
||||
os.kill(pid, 0)
|
||||
except OSError as err:
|
||||
if err.errno == errno.ESRCH:
|
||||
# ESRCH == No such process
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
elif err.errno == errno.EPERM:
|
||||
except PermissionError:
|
||||
# EPERM clearly means there's a process to deny access to
|
||||
return True
|
||||
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.
|
||||
raise err
|
||||
# (EINVAL, EPERM, ESRCH)
|
||||
else:
|
||||
return True
|
||||
|
||||
|
@ -84,11 +78,9 @@ def wait_pid(pid, timeout=None, proc_name=None):
|
|||
while True:
|
||||
try:
|
||||
retpid, status = waitcall()
|
||||
except OSError as err:
|
||||
if err.errno == errno.EINTR:
|
||||
except InterruptedError:
|
||||
delay = check_timeout(delay)
|
||||
continue
|
||||
elif err.errno == errno.ECHILD:
|
||||
except ChildProcessError:
|
||||
# This has two meanings:
|
||||
# - pid is not a child of os.getpid() in which case
|
||||
# we keep polling until it's gone
|
||||
|
@ -100,8 +92,6 @@ def wait_pid(pid, timeout=None, proc_name=None):
|
|||
delay = check_timeout(delay)
|
||||
else:
|
||||
return
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
if retpid == 0:
|
||||
# WNOHANG was used, pid is still running
|
||||
|
@ -180,7 +170,6 @@ def get_terminal_map():
|
|||
assert name not in ret, name
|
||||
try:
|
||||
ret[os.stat(name).st_rdev] = name
|
||||
except OSError as err:
|
||||
if err.errno != errno.ENOENT:
|
||||
raise
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return ret
|
||||
|
|
|
@ -17,14 +17,21 @@ 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
|
||||
|
||||
|
||||
|
@ -84,13 +91,6 @@ proc_info_map = dict(
|
|||
gid=10,
|
||||
egid=11)
|
||||
|
||||
# These objects get set on "import psutil" from the __init__.py
|
||||
# file, see: https://github.com/giampaolo/psutil/issues/1402
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
|
@ -226,8 +226,13 @@ def disk_partitions(all=False):
|
|||
# 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
|
||||
|
@ -262,6 +267,7 @@ def net_connections(kind, _pid=-1):
|
|||
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)
|
||||
|
@ -341,22 +347,22 @@ def wrap_exceptions(fun):
|
|||
def wrapper(self, *args, **kwargs):
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except EnvironmentError as err:
|
||||
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
|
||||
# ENOENT (no such file or directory) gets raised on open().
|
||||
# ESRCH (no such process) can get raised on read() if
|
||||
# process is gone in meantime.
|
||||
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||
if not pid_exists(self.pid):
|
||||
raise NoSuchProcess(self.pid, self._name)
|
||||
else:
|
||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||
if err.errno in (errno.EPERM, errno.EACCES):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
|
@ -396,6 +402,9 @@ class Process(object):
|
|||
@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
|
||||
|
@ -514,11 +523,9 @@ class Process(object):
|
|||
try:
|
||||
return os.readlink(
|
||||
'%s/%d/path/%d' % (procfs_path, self.pid, x))
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
if hit_enoent:
|
||||
self._assert_alive()
|
||||
|
||||
|
@ -531,11 +538,9 @@ class Process(object):
|
|||
procfs_path = self._procfs_path
|
||||
try:
|
||||
return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid))
|
||||
except OSError as err:
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||
return None
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def memory_info(self):
|
||||
|
@ -596,12 +601,9 @@ class Process(object):
|
|||
if os.path.islink(path):
|
||||
try:
|
||||
file = os.readlink(path)
|
||||
except OSError as err:
|
||||
# ENOENT == file which is gone in the meantime
|
||||
if err.errno == errno.ENOENT:
|
||||
except FileNotFoundError:
|
||||
hit_enoent = True
|
||||
continue
|
||||
raise
|
||||
else:
|
||||
if isfile_strict(file):
|
||||
retlist.append(_common.popenfile(file, int(fd)))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* - psutil.Process.io_counters read count is always 0
|
||||
* - psutil.Process.io_counters may not be available on older AIX versions
|
||||
* - psutil.Process.threads may not be available on older AIX versions
|
||||
# - psutil.net_io_counters may not be available on older AIX versions
|
||||
* - psutil.net_io_counters may not be available on older AIX versions
|
||||
* - reading basic process info may fail or return incorrect values when
|
||||
* process is starting (see IBM APAR IV58499 - fixed in newer AIX versions)
|
||||
* - sockets and pipes may not be counted in num_fds (fixed in newer AIX
|
||||
|
@ -29,7 +29,6 @@
|
|||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <sys/limits.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/procfs.h>
|
||||
|
@ -51,11 +50,11 @@
|
|||
#include <libperfstat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "_psutil_common.h"
|
||||
#include "_psutil_posix.h"
|
||||
#include "arch/aix/ifaddrs.h"
|
||||
#include "arch/aix/net_connections.h"
|
||||
#include "arch/aix/common.h"
|
||||
#include "_psutil_common.h"
|
||||
#include "_psutil_posix.h"
|
||||
|
||||
|
||||
#define TV2DOUBLE(t) (((t).tv_nsec * 0.000000001) + (t).tv_sec)
|
||||
|
@ -180,7 +179,7 @@ psutil_proc_args(PyObject *self, PyObject *args) {
|
|||
}
|
||||
|
||||
procbuf.pi_pid = pid;
|
||||
ret = getargs(&procbuf, sizeof(struct procinfo), argbuf, ARG_MAX);
|
||||
ret = getargs(&procbuf, sizeof(procbuf), argbuf, ARG_MAX);
|
||||
if (ret == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
|
@ -241,7 +240,7 @@ psutil_proc_environ(PyObject *self, PyObject *args) {
|
|||
}
|
||||
|
||||
procbuf.pi_pid = pid;
|
||||
ret = getevars(&procbuf, sizeof(struct procinfo), envbuf, ARG_MAX);
|
||||
ret = getevars(&procbuf, sizeof(procbuf), envbuf, ARG_MAX);
|
||||
if (ret == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
|
@ -265,8 +264,8 @@ psutil_proc_environ(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyDict_SetItem(py_retdict, py_key, py_val))
|
||||
goto error;
|
||||
Py_DECREF(py_key);
|
||||
Py_DECREF(py_val);
|
||||
Py_CLEAR(py_key);
|
||||
Py_CLEAR(py_val);
|
||||
}
|
||||
curvar = strchr(curvar, '\0') + 1;
|
||||
}
|
||||
|
@ -462,7 +461,7 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) {
|
|||
|
||||
/* finished iteration without finding requested pid */
|
||||
free(processes);
|
||||
return NoSuchProcess("");
|
||||
return NoSuchProcess("psutil_read_process_table (no PID found)");
|
||||
}
|
||||
|
||||
|
||||
|
@ -510,10 +509,10 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_username);
|
||||
Py_DECREF(py_tty);
|
||||
Py_DECREF(py_hostname);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_username);
|
||||
Py_CLEAR(py_tty);
|
||||
Py_CLEAR(py_hostname);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
endutxent();
|
||||
|
||||
|
@ -570,9 +569,9 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_dev);
|
||||
Py_DECREF(py_mountp);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_dev);
|
||||
Py_CLEAR(py_mountp);
|
||||
Py_CLEAR(py_tuple);
|
||||
mt = getmntent(file);
|
||||
}
|
||||
endmntent(file);
|
||||
|
|
|
@ -51,13 +51,10 @@
|
|||
#include <netinet/tcp_var.h> // for struct xtcpcb
|
||||
#include <netinet/tcp_fsm.h> // for TCP connection states
|
||||
#include <arpa/inet.h> // for inet_ntop()
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <net/if.h> // net io counters
|
||||
#include <net/if_dl.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h> // process open files/connections
|
||||
#include <sys/un.h>
|
||||
|
||||
|
@ -99,7 +96,6 @@
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
// convert a timeval struct to a double
|
||||
#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
|
||||
|
||||
|
@ -129,32 +125,22 @@ psutil_pids(PyObject *self, PyObject *args) {
|
|||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
// TODO: RuntimeError is inappropriate here; we could return the
|
||||
// original error instead.
|
||||
if (psutil_get_proc_list(&proclist, &num_processes) != 0) {
|
||||
if (errno != 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"failed to retrieve process list");
|
||||
}
|
||||
if (psutil_get_proc_list(&proclist, &num_processes) != 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (num_processes > 0) {
|
||||
orig_address = proclist; // save so we can free it after we're done
|
||||
for (idx = 0; idx < num_processes; idx++) {
|
||||
#ifdef PSUTIL_FREEBSD
|
||||
py_pid = Py_BuildValue("i", proclist->ki_pid);
|
||||
py_pid = PyLong_FromPid(proclist->ki_pid);
|
||||
#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
|
||||
py_pid = Py_BuildValue("i", proclist->p_pid);
|
||||
py_pid = PyLong_FromPid(proclist->p_pid);
|
||||
#endif
|
||||
if (!py_pid)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_pid))
|
||||
goto error;
|
||||
Py_DECREF(py_pid);
|
||||
Py_CLEAR(py_pid);
|
||||
proclist++;
|
||||
}
|
||||
free(orig_address);
|
||||
|
@ -194,7 +180,7 @@ psutil_boot_time(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
long rss;
|
||||
long vms;
|
||||
long memtext;
|
||||
|
@ -205,9 +191,10 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
|
|||
long pagesize = sysconf(_SC_PAGESIZE);
|
||||
char str[1000];
|
||||
PyObject *py_name;
|
||||
PyObject *py_ppid;
|
||||
PyObject *py_retlist;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (psutil_kinfo_proc(pid, &kp) == -1)
|
||||
return NULL;
|
||||
|
@ -269,12 +256,25 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
|
|||
oncpu = -1;
|
||||
#endif
|
||||
|
||||
#ifdef PSUTIL_FREEBSD
|
||||
py_ppid = PyLong_FromPid(kp.ki_ppid);
|
||||
#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
|
||||
py_ppid = PyLong_FromPid(kp.p_ppid);
|
||||
#else
|
||||
py_ppid = Py_BuildfValue(-1);
|
||||
#endif
|
||||
if (! py_ppid)
|
||||
return NULL;
|
||||
|
||||
// Return a single big tuple with all process info.
|
||||
py_retlist = Py_BuildValue(
|
||||
"(lillllllidllllddddlllllbO)",
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 1200031
|
||||
"(OillllllLdllllddddlllllbO)",
|
||||
#else
|
||||
"(OillllllidllllddddlllllbO)",
|
||||
#endif
|
||||
#ifdef PSUTIL_FREEBSD
|
||||
//
|
||||
(long)kp.ki_ppid, // (long) ppid
|
||||
py_ppid, // (pid_t) ppid
|
||||
(int)kp.ki_stat, // (int) status
|
||||
// UIDs
|
||||
(long)kp.ki_ruid, // (long) real uid
|
||||
|
@ -285,7 +285,7 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
|
|||
(long)kp.ki_groups[0], // (long) effective gid
|
||||
(long)kp.ki_svuid, // (long) saved gid
|
||||
//
|
||||
kp.ki_tdev, // (int) tty nr
|
||||
kp.ki_tdev, // (int or long long) tty nr
|
||||
PSUTIL_TV2DOUBLE(kp.ki_start), // (double) create time
|
||||
// ctx switches
|
||||
kp.ki_rusage.ru_nvcsw, // (long) ctx switches (voluntary)
|
||||
|
@ -307,8 +307,7 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
|
|||
// others
|
||||
oncpu, // (int) the CPU we are on
|
||||
#elif defined(PSUTIL_OPENBSD) || defined(PSUTIL_NETBSD)
|
||||
//
|
||||
(long)kp.p_ppid, // (long) ppid
|
||||
py_ppid, // (pid_t) ppid
|
||||
(int)kp.p_stat, // (int) status
|
||||
// UIDs
|
||||
(long)kp.p_ruid, // (long) real uid
|
||||
|
@ -347,6 +346,7 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
|
|||
);
|
||||
|
||||
Py_DECREF(py_name);
|
||||
Py_DECREF(py_ppid);
|
||||
return py_retlist;
|
||||
}
|
||||
|
||||
|
@ -356,11 +356,11 @@ psutil_proc_oneshot_info(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_name(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
kinfo_proc kp;
|
||||
char str[1000];
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (psutil_kinfo_proc(pid, &kp) == -1)
|
||||
return NULL;
|
||||
|
@ -379,10 +379,10 @@ psutil_proc_name(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_cmdline(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
PyObject *py_retlist = NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
py_retlist = psutil_get_cmdline(pid);
|
||||
if (py_retlist == NULL)
|
||||
|
@ -452,7 +452,7 @@ psutil_cpu_times(PyObject *self, PyObject *args) {
|
|||
#if (defined(__FreeBSD_version) && __FreeBSD_version >= 800000) || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
|
||||
static PyObject *
|
||||
psutil_proc_open_files(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int i;
|
||||
int cnt;
|
||||
int regular;
|
||||
|
@ -467,7 +467,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
|
|||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
goto error;
|
||||
if (psutil_kinfo_proc(pid, &kipp) == -1)
|
||||
goto error;
|
||||
|
@ -475,7 +475,9 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
|
|||
errno = 0;
|
||||
freep = kinfo_getfile(pid, &cnt);
|
||||
if (freep == NULL) {
|
||||
#if !defined(PSUTIL_OPENBSD)
|
||||
psutil_raise_for_pid(pid, "kinfo_getfile()");
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -507,8 +509,8 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_path);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_path);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
}
|
||||
free(freep);
|
||||
|
@ -670,9 +672,9 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_dev);
|
||||
Py_DECREF(py_mountp);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_dev);
|
||||
Py_CLEAR(py_mountp);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
|
||||
free(fs);
|
||||
|
@ -765,7 +767,7 @@ psutil_net_io_counters(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info))
|
||||
goto error;
|
||||
Py_DECREF(py_ifc_info);
|
||||
Py_CLEAR(py_ifc_info);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
|
@ -794,6 +796,7 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
PyObject *py_tty = NULL;
|
||||
PyObject *py_hostname = NULL;
|
||||
PyObject *py_tuple = NULL;
|
||||
PyObject *py_pid = NULL;
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
@ -802,7 +805,9 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
struct utmp ut;
|
||||
FILE *fp;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
fp = fopen(_PATH_UTMP, "r");
|
||||
Py_END_ALLOW_THREADS
|
||||
if (fp == NULL) {
|
||||
PyErr_SetFromErrnoWithFilename(PyExc_OSError, _PATH_UTMP);
|
||||
goto error;
|
||||
|
@ -829,7 +834,7 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
#ifdef PSUTIL_OPENBSD
|
||||
-1 // process id (set to None later)
|
||||
#else
|
||||
ut.ut_pid // process id
|
||||
ut.ut_pid // TODO: use PyLong_FromPid
|
||||
#endif
|
||||
);
|
||||
if (!py_tuple) {
|
||||
|
@ -840,10 +845,10 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
fclose(fp);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(py_username);
|
||||
Py_DECREF(py_tty);
|
||||
Py_DECREF(py_hostname);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_username);
|
||||
Py_CLEAR(py_tty);
|
||||
Py_CLEAR(py_hostname);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
@ -862,17 +867,21 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
py_hostname = PyUnicode_DecodeFSDefault(utx->ut_host);
|
||||
if (! py_hostname)
|
||||
goto error;
|
||||
#ifdef PSUTIL_OPENBSD
|
||||
py_pid = Py_BuildValue("i", -1); // set to None later
|
||||
#else
|
||||
py_pid = PyLong_FromPid(utx->ut_pid);
|
||||
#endif
|
||||
if (! py_pid)
|
||||
goto error;
|
||||
|
||||
py_tuple = Py_BuildValue(
|
||||
"(OOOfi)",
|
||||
"(OOOfO)",
|
||||
py_username, // username
|
||||
py_tty, // tty
|
||||
py_hostname, // hostname
|
||||
(float)utx->ut_tv.tv_sec, // start time
|
||||
#ifdef PSUTIL_OPENBSD
|
||||
-1 // process id (set to None later)
|
||||
#else
|
||||
utx->ut_pid // process id
|
||||
#endif
|
||||
py_pid // process id
|
||||
);
|
||||
|
||||
if (!py_tuple) {
|
||||
|
@ -883,10 +892,11 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
endutxent();
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(py_username);
|
||||
Py_DECREF(py_tty);
|
||||
Py_DECREF(py_hostname);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_username);
|
||||
Py_CLEAR(py_tty);
|
||||
Py_CLEAR(py_hostname);
|
||||
Py_CLEAR(py_tuple);
|
||||
Py_CLEAR(py_pid);
|
||||
}
|
||||
|
||||
endutxent();
|
||||
|
@ -898,6 +908,7 @@ error:
|
|||
Py_XDECREF(py_tty);
|
||||
Py_XDECREF(py_hostname);
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_XDECREF(py_pid);
|
||||
Py_DECREF(py_retlist);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -906,8 +917,7 @@ error:
|
|||
/*
|
||||
* define the psutil C module methods and initialize the module.
|
||||
*/
|
||||
static PyMethodDef
|
||||
PsutilMethods[] = {
|
||||
static PyMethodDef mod_methods[] = {
|
||||
// --- per-process functions
|
||||
|
||||
{"proc_oneshot_info", psutil_proc_oneshot_info, METH_VARARGS,
|
||||
|
@ -921,9 +931,9 @@ PsutilMethods[] = {
|
|||
#if defined(PSUTIL_FREEBSD) || defined(PSUTIL_OPENBSD)
|
||||
{"proc_connections", psutil_proc_connections, METH_VARARGS,
|
||||
"Return connections opened by process"},
|
||||
#endif
|
||||
{"proc_cwd", psutil_proc_cwd, METH_VARARGS,
|
||||
"Return process current working directory."},
|
||||
#endif
|
||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 || PSUTIL_OPENBSD || defined(PSUTIL_NETBSD)
|
||||
{"proc_num_fds", psutil_proc_num_fds, METH_VARARGS,
|
||||
"Return the number of file descriptors opened by this process"},
|
||||
|
@ -994,109 +1004,99 @@ PsutilMethods[] = {
|
|||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
struct module_state {
|
||||
PyObject *error;
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
|
||||
#else
|
||||
#define GETSTATE(m) (&_state)
|
||||
#endif
|
||||
#define INITERR return NULL
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
static int
|
||||
psutil_bsd_traverse(PyObject *m, visitproc visit, void *arg) {
|
||||
Py_VISIT(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
psutil_bsd_clear(PyObject *m) {
|
||||
Py_CLEAR(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct PyModuleDef
|
||||
moduledef = {
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"psutil_bsd",
|
||||
"_psutil_bsd",
|
||||
NULL,
|
||||
-1,
|
||||
mod_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof(struct module_state),
|
||||
PsutilMethods,
|
||||
NULL,
|
||||
psutil_bsd_traverse,
|
||||
psutil_bsd_clear,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
|
||||
PyMODINIT_FUNC PyInit__psutil_bsd(void)
|
||||
|
||||
#else
|
||||
#define INITERROR return
|
||||
PyObject *PyInit__psutil_bsd(void)
|
||||
#else /* PY_MAJOR_VERSION */
|
||||
#define INITERR return
|
||||
|
||||
void init_psutil_bsd(void)
|
||||
#endif
|
||||
#endif /* PY_MAJOR_VERSION */
|
||||
{
|
||||
PyObject *v;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *module = PyModule_Create(&moduledef);
|
||||
PyObject *mod = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods);
|
||||
PyObject *mod = Py_InitModule("_psutil_bsd", mod_methods);
|
||||
#endif
|
||||
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
|
||||
if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) INITERR;
|
||||
// process status constants
|
||||
|
||||
#ifdef PSUTIL_FREEBSD
|
||||
PyModule_AddIntConstant(module, "SIDL", SIDL);
|
||||
PyModule_AddIntConstant(module, "SRUN", SRUN);
|
||||
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
|
||||
PyModule_AddIntConstant(module, "SSTOP", SSTOP);
|
||||
PyModule_AddIntConstant(module, "SZOMB", SZOMB);
|
||||
PyModule_AddIntConstant(module, "SWAIT", SWAIT);
|
||||
PyModule_AddIntConstant(module, "SLOCK", SLOCK);
|
||||
if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SWAIT", SWAIT)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SLOCK", SLOCK)) INITERR;
|
||||
#elif PSUTIL_OPENBSD
|
||||
PyModule_AddIntConstant(module, "SIDL", SIDL);
|
||||
PyModule_AddIntConstant(module, "SRUN", SRUN);
|
||||
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
|
||||
PyModule_AddIntConstant(module, "SSTOP", SSTOP);
|
||||
PyModule_AddIntConstant(module, "SZOMB", SZOMB); // unused
|
||||
PyModule_AddIntConstant(module, "SDEAD", SDEAD);
|
||||
PyModule_AddIntConstant(module, "SONPROC", SONPROC);
|
||||
if (PyModule_AddIntConstant(mod, "SIDL", SIDL)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SRUN", SRUN)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB)) INITERR; // unused
|
||||
if (PyModule_AddIntConstant(mod, "SDEAD", SDEAD)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SONPROC", SONPROC)) INITERR;
|
||||
#elif defined(PSUTIL_NETBSD)
|
||||
PyModule_AddIntConstant(module, "SIDL", LSIDL);
|
||||
PyModule_AddIntConstant(module, "SRUN", LSRUN);
|
||||
PyModule_AddIntConstant(module, "SSLEEP", LSSLEEP);
|
||||
PyModule_AddIntConstant(module, "SSTOP", LSSTOP);
|
||||
PyModule_AddIntConstant(module, "SZOMB", LSZOMB);
|
||||
PyModule_AddIntConstant(module, "SDEAD", LSDEAD);
|
||||
PyModule_AddIntConstant(module, "SONPROC", LSONPROC);
|
||||
if (PyModule_AddIntConstant(mod, "SIDL", LSIDL)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SRUN", LSRUN)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SSLEEP", LSSLEEP)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SSTOP", LSSTOP)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SZOMB", LSZOMB)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SDEAD", LSDEAD)) INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SONPROC", LSONPROC)) INITERR;
|
||||
// unique to NetBSD
|
||||
PyModule_AddIntConstant(module, "SSUSPENDED", LSSUSPENDED);
|
||||
if (PyModule_AddIntConstant(mod, "SSUSPENDED", LSSUSPENDED)) INITERR;
|
||||
#endif
|
||||
|
||||
// connection status constants
|
||||
PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED);
|
||||
PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING);
|
||||
PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT);
|
||||
PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN);
|
||||
PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED);
|
||||
PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT);
|
||||
PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED);
|
||||
PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1);
|
||||
PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2);
|
||||
PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK);
|
||||
PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_CLOSED", TCPS_CLOSED))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_CLOSING", TCPS_CLOSING))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_LISTEN", TCPS_LISTEN))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_ESTABLISHED", TCPS_ESTABLISHED))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_SYN_SENT", TCPS_SYN_SENT))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_LAST_ACK", TCPS_LAST_ACK))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_TIME_WAIT", TCPS_TIME_WAIT))
|
||||
INITERR;
|
||||
// PSUTIL_CONN_NONE
|
||||
PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", 128);
|
||||
if (PyModule_AddIntConstant(mod, "PSUTIL_CONN_NONE", 128)) INITERR;
|
||||
|
||||
psutil_setup();
|
||||
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return module;
|
||||
return mod;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -7,52 +7,64 @@
|
|||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "_psutil_common.h"
|
||||
|
||||
// Global vars.
|
||||
// ====================================================================
|
||||
// --- Global vars
|
||||
// ====================================================================
|
||||
|
||||
int PSUTIL_DEBUG = 0;
|
||||
int PSUTIL_TESTING = 0;
|
||||
// PSUTIL_CONN_NONE
|
||||
|
||||
|
||||
/*
|
||||
* Backport of unicode FS APIs from Python 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
|
||||
*/
|
||||
#if PY_MAJOR_VERSION < 3
|
||||
// ====================================================================
|
||||
// --- Backward compatibility with missing Python.h APIs
|
||||
// ====================================================================
|
||||
|
||||
// PyPy on Windows
|
||||
#if defined(PSUTIL_WINDOWS) && \
|
||||
defined(PYPY_VERSION) && \
|
||||
!defined(PyErr_SetFromWindowsErrWithFilename)
|
||||
PyObject *
|
||||
PyUnicode_DecodeFSDefault(char *s) {
|
||||
return PyString_FromString(s);
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
PyUnicode_DecodeFSDefaultAndSize(char *s, Py_ssize_t size) {
|
||||
return PyString_FromStringAndSize(s, size);
|
||||
else {
|
||||
py_exc = PyObject_CallFunction(PyExc_OSError, "(iss)", winerr,
|
||||
strerror(winerr), filename);
|
||||
}
|
||||
#endif
|
||||
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;
|
||||
|
||||
/*
|
||||
* Set OSError(errno=ESRCH, strerror="No such process") Python exception.
|
||||
* If msg != "" the exception message will change in accordance.
|
||||
*/
|
||||
PyObject *
|
||||
NoSuchProcess(const char *msg) {
|
||||
PyObject *exc;
|
||||
exc = PyObject_CallFunction(
|
||||
PyExc_OSError, "(is)", ESRCH, strlen(msg) ? msg : strerror(ESRCH));
|
||||
PyErr_SetObject(PyExc_OSError, exc);
|
||||
Py_XDECREF(exc);
|
||||
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.
|
||||
|
@ -61,7 +73,7 @@ PyObject *
|
|||
PyErr_SetFromOSErrnoWithSyscall(const char *syscall) {
|
||||
char fullmsg[1024];
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef PSUTIL_WINDOWS
|
||||
sprintf(fullmsg, "(originated from %s)", syscall);
|
||||
PyErr_SetFromWindowsErrWithFilename(GetLastError(), fullmsg);
|
||||
#else
|
||||
|
@ -76,20 +88,43 @@ PyErr_SetFromOSErrnoWithSyscall(const char *syscall) {
|
|||
|
||||
|
||||
/*
|
||||
* Set OSError(errno=EACCES, strerror="Permission denied") Python exception.
|
||||
* If msg != "" the exception message will change in accordance.
|
||||
* Set OSError(errno=ESRCH, strerror="No such process (originated from")
|
||||
* Python exception.
|
||||
*/
|
||||
PyObject *
|
||||
AccessDenied(const char *msg) {
|
||||
NoSuchProcess(const char *syscall) {
|
||||
PyObject *exc;
|
||||
exc = PyObject_CallFunction(
|
||||
PyExc_OSError, "(is)", EACCES, strlen(msg) ? msg : strerror(EACCES));
|
||||
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
|
||||
|
@ -130,3 +165,239 @@ psutil_setup(void) {
|
|||
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
|
||||
|
|
|
@ -4,28 +4,136 @@
|
|||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef PSUTIL_PSUTIL_COMMON_H
|
||||
#define PSUTIL_PSUTIL_COMMON_H
|
||||
|
||||
#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
|
||||
PyObject* PyUnicode_DecodeFSDefault(char *s);
|
||||
PyObject* PyUnicode_DecodeFSDefaultAndSize(char *s, Py_ssize_t size);
|
||||
// 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);
|
||||
|
||||
#endif // PSUTIL_PSUTIL_COMMON_H
|
||||
// ====================================================================
|
||||
// --- 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
|
||||
|
|
|
@ -54,6 +54,11 @@ static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
|
|||
#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"
|
||||
|
||||
|
@ -92,9 +97,9 @@ ioprio_set(int which, int who, int ioprio) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_ioprio_get(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int ioprio, ioclass, iodata;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
|
||||
if (ioprio == -1)
|
||||
|
@ -112,12 +117,14 @@ psutil_proc_ioprio_get(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_ioprio_set(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int ioprio, ioclass, iodata;
|
||||
int retval;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata))
|
||||
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)
|
||||
|
@ -135,15 +142,17 @@ psutil_proc_ioprio_set(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_linux_prlimit(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
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, "li|OO", &pid, &resource, &py_soft, &py_hard))
|
||||
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) {
|
||||
|
@ -195,7 +204,7 @@ static PyObject *
|
|||
psutil_disk_partitions(PyObject *self, PyObject *args) {
|
||||
FILE *file = NULL;
|
||||
struct mntent *entry;
|
||||
const char *mtab_path;
|
||||
char *mtab_path;
|
||||
PyObject *py_dev = NULL;
|
||||
PyObject *py_mountp = NULL;
|
||||
PyObject *py_tuple = NULL;
|
||||
|
@ -236,9 +245,9 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_dev);
|
||||
Py_DECREF(py_mountp);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_dev);
|
||||
Py_CLEAR(py_mountp);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
endmntent(file);
|
||||
return py_retlist;
|
||||
|
@ -279,21 +288,18 @@ psutil_linux_sysinfo(PyObject *self, PyObject *args) {
|
|||
|
||||
/*
|
||||
* Return process CPU affinity as a Python list
|
||||
* The dual implementation exists because of:
|
||||
* https://github.com/giampaolo/psutil/issues/536
|
||||
*/
|
||||
|
||||
#ifdef CPU_ALLOC
|
||||
#ifdef PSUTIL_HAVE_CPU_AFFINITY
|
||||
|
||||
static PyObject *
|
||||
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
|
||||
int cpu, ncpus, count, cpucount_s;
|
||||
long pid;
|
||||
pid_t pid;
|
||||
size_t setsize;
|
||||
cpu_set_t *mask = NULL;
|
||||
PyObject *py_list = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "l", &pid))
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
ncpus = NCPUS_START;
|
||||
while (1) {
|
||||
|
@ -347,50 +353,8 @@ error:
|
|||
Py_XDECREF(py_list);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
/*
|
||||
* Alternative implementation in case CPU_ALLOC is not defined.
|
||||
*/
|
||||
static PyObject *
|
||||
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
|
||||
cpu_set_t cpuset;
|
||||
unsigned int len = sizeof(cpu_set_t);
|
||||
long pid;
|
||||
int i;
|
||||
PyObject* py_retlist = NULL;
|
||||
PyObject *py_cpu_num = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "l", &pid))
|
||||
return NULL;
|
||||
CPU_ZERO(&cpuset);
|
||||
if (sched_getaffinity(pid, len, &cpuset) < 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
|
||||
py_retlist = PyList_New(0);
|
||||
if (py_retlist == NULL)
|
||||
goto error;
|
||||
for (i = 0; i < CPU_SETSIZE; ++i) {
|
||||
if (CPU_ISSET(i, &cpuset)) {
|
||||
py_cpu_num = Py_BuildValue("i", i);
|
||||
if (py_cpu_num == NULL)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_cpu_num))
|
||||
goto error;
|
||||
Py_DECREF(py_cpu_num);
|
||||
}
|
||||
}
|
||||
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_cpu_num);
|
||||
Py_XDECREF(py_retlist);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set process CPU affinity; expects a bitmask
|
||||
*/
|
||||
|
@ -398,12 +362,12 @@ static PyObject *
|
|||
psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
|
||||
cpu_set_t cpu_set;
|
||||
size_t len;
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int i, seq_len;
|
||||
PyObject *py_cpu_set;
|
||||
PyObject *py_cpu_seq = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set))
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O", &pid, &py_cpu_set))
|
||||
return NULL;
|
||||
|
||||
if (!PySequence_Check(py_cpu_set)) {
|
||||
|
@ -432,7 +396,6 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
|
|||
CPU_SET(value, &cpu_set);
|
||||
}
|
||||
|
||||
|
||||
len = sizeof(cpu_set);
|
||||
if (sched_setaffinity(pid, len, &cpu_set)) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
|
@ -447,6 +410,7 @@ error:
|
|||
Py_DECREF(py_cpu_seq);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* PSUTIL_HAVE_CPU_AFFINITY */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -481,8 +445,9 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
py_hostname = PyUnicode_DecodeFSDefault(ut->ut_host);
|
||||
if (! py_hostname)
|
||||
goto error;
|
||||
|
||||
py_tuple = Py_BuildValue(
|
||||
"(OOOfOi)",
|
||||
"OOOfO" _Py_PARSE_PID,
|
||||
py_username, // username
|
||||
py_tty, // tty
|
||||
py_hostname, // hostname
|
||||
|
@ -494,10 +459,10 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_username);
|
||||
Py_DECREF(py_tty);
|
||||
Py_DECREF(py_hostname);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_username);
|
||||
Py_CLEAR(py_tty);
|
||||
Py_CLEAR(py_hostname);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
endutent();
|
||||
return py_retlist;
|
||||
|
@ -577,10 +542,10 @@ error:
|
|||
|
||||
|
||||
/*
|
||||
* Define the psutil C module methods and initialize the module.
|
||||
* Module init.
|
||||
*/
|
||||
static PyMethodDef
|
||||
PsutilMethods[] = {
|
||||
|
||||
static PyMethodDef mod_methods[] = {
|
||||
// --- per-process functions
|
||||
|
||||
#if PSUTIL_HAVE_IOPRIO
|
||||
|
@ -589,10 +554,12 @@ PsutilMethods[] = {
|
|||
{"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
|
||||
|
||||
|
@ -612,7 +579,6 @@ PsutilMethods[] = {
|
|||
{"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"},
|
||||
|
@ -620,75 +586,51 @@ PsutilMethods[] = {
|
|||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
struct module_state {
|
||||
PyObject *error;
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
|
||||
#else
|
||||
#define GETSTATE(m) (&_state)
|
||||
#endif
|
||||
#define INITERR return NULL
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
static int
|
||||
psutil_linux_traverse(PyObject *m, visitproc visit, void *arg) {
|
||||
Py_VISIT(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
psutil_linux_clear(PyObject *m) {
|
||||
Py_CLEAR(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct PyModuleDef
|
||||
moduledef = {
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"psutil_linux",
|
||||
"_psutil_linux",
|
||||
NULL,
|
||||
-1,
|
||||
mod_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof(struct module_state),
|
||||
PsutilMethods,
|
||||
NULL,
|
||||
psutil_linux_traverse,
|
||||
psutil_linux_clear,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
|
||||
PyMODINIT_FUNC PyInit__psutil_linux(void)
|
||||
|
||||
#else
|
||||
#define INITERROR return
|
||||
PyObject *PyInit__psutil_linux(void)
|
||||
#else /* PY_MAJOR_VERSION */
|
||||
#define INITERR return
|
||||
|
||||
void init_psutil_linux(void)
|
||||
#endif
|
||||
#endif /* PY_MAJOR_VERSION */
|
||||
{
|
||||
PyObject *v;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *module = PyModule_Create(&moduledef);
|
||||
PyObject *mod = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
|
||||
PyObject *mod = Py_InitModule("_psutil_linux", mod_methods);
|
||||
#endif
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
|
||||
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
|
||||
if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) INITERR;
|
||||
#if PSUTIL_HAVE_PRLIMIT
|
||||
PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_DATA", RLIMIT_DATA);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_FSIZE", RLIMIT_FSIZE);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_LOCKS", RLIMIT_LOCKS);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_NOFILE", RLIMIT_NOFILE);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS);
|
||||
PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK);
|
||||
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)) {
|
||||
|
@ -699,32 +641,33 @@ void init_psutil_linux(void)
|
|||
v = PyLong_FromLong((long) RLIM_INFINITY);
|
||||
}
|
||||
if (v) {
|
||||
PyModule_AddObject(module, "RLIM_INFINITY", v);
|
||||
PyModule_AddObject(mod, "RLIM_INFINITY", v);
|
||||
}
|
||||
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE);
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE)) INITERR;
|
||||
#endif
|
||||
#ifdef RLIMIT_NICE
|
||||
PyModule_AddIntConstant(module, "RLIMIT_NICE", RLIMIT_NICE);
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_NICE", RLIMIT_NICE)) INITERR;
|
||||
#endif
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
PyModule_AddIntConstant(module, "RLIMIT_RTPRIO", RLIMIT_RTPRIO);
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_RTPRIO", RLIMIT_RTPRIO)) INITERR;
|
||||
#endif
|
||||
#ifdef RLIMIT_RTTIME
|
||||
PyModule_AddIntConstant(module, "RLIMIT_RTTIME", RLIMIT_RTTIME);
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_RTTIME", RLIMIT_RTTIME)) INITERR;
|
||||
#endif
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
PyModule_AddIntConstant(module, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING);
|
||||
if (PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING))
|
||||
INITERR;
|
||||
#endif
|
||||
#endif
|
||||
PyModule_AddIntConstant(module, "DUPLEX_HALF", DUPLEX_HALF);
|
||||
PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL);
|
||||
PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN);
|
||||
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 (module == NULL)
|
||||
INITERROR;
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return module;
|
||||
return mod;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -88,15 +88,15 @@ psutil_sys_vminfo(vm_statistics_data_t *vmstat) {
|
|||
* https://github.com/giampaolo/psutil/issues/1291#issuecomment-396062519
|
||||
*/
|
||||
int
|
||||
psutil_task_for_pid(long pid, mach_port_t *task)
|
||||
psutil_task_for_pid(pid_t pid, mach_port_t *task)
|
||||
{
|
||||
// See: https://github.com/giampaolo/psutil/issues/1181
|
||||
kern_return_t err = KERN_SUCCESS;
|
||||
|
||||
err = task_for_pid(mach_task_self(), (pid_t)pid, task);
|
||||
err = task_for_pid(mach_task_self(), pid, task);
|
||||
if (err != KERN_SUCCESS) {
|
||||
if (psutil_pid_exists(pid) == 0)
|
||||
NoSuchProcess("task_for_pid() failed");
|
||||
NoSuchProcess("task_for_pid");
|
||||
else if (psutil_is_zombie(pid) == 1)
|
||||
PyErr_SetString(ZombieProcessError, "task_for_pid() failed");
|
||||
else {
|
||||
|
@ -104,7 +104,7 @@ psutil_task_for_pid(long pid, mach_port_t *task)
|
|||
"task_for_pid() failed (pid=%ld, err=%i, errno=%i, msg='%s'); "
|
||||
"setting AccessDenied()",
|
||||
pid, err, errno, mach_error_string(err));
|
||||
AccessDenied("task_for_pid() failed");
|
||||
AccessDenied("task_for_pid");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -133,12 +133,12 @@ psutil_pids(PyObject *self, PyObject *args) {
|
|||
// save the address of proclist so we can free it later
|
||||
orig_address = proclist;
|
||||
for (idx = 0; idx < num_processes; idx++) {
|
||||
py_pid = Py_BuildValue("i", proclist->kp_proc.p_pid);
|
||||
py_pid = PyLong_FromPid(proclist->kp_proc.p_pid);
|
||||
if (! py_pid)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_pid))
|
||||
goto error;
|
||||
Py_DECREF(py_pid);
|
||||
Py_CLEAR(py_pid);
|
||||
proclist++;
|
||||
}
|
||||
free(orig_address);
|
||||
|
@ -164,12 +164,12 @@ error:
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
struct kinfo_proc kp;
|
||||
PyObject *py_name;
|
||||
PyObject *py_retlist;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (psutil_get_kinfo_proc(pid, &kp) == -1)
|
||||
return NULL;
|
||||
|
@ -183,8 +183,8 @@ psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args) {
|
|||
}
|
||||
|
||||
py_retlist = Py_BuildValue(
|
||||
"lllllllidiO",
|
||||
(long)kp.kp_eproc.e_ppid, // (long) ppid
|
||||
_Py_PARSE_PID "llllllidiO",
|
||||
kp.kp_eproc.e_ppid, // (pid_t) ppid
|
||||
(long)kp.kp_eproc.e_pcred.p_ruid, // (long) real uid
|
||||
(long)kp.kp_eproc.e_ucred.cr_uid, // (long) effective uid
|
||||
(long)kp.kp_eproc.e_pcred.p_svuid, // (long) saved uid
|
||||
|
@ -215,10 +215,10 @@ psutil_proc_kinfo_oneshot(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_pidtaskinfo_oneshot(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
struct proc_taskinfo pti;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (psutil_proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)) <= 0)
|
||||
return NULL;
|
||||
|
@ -250,10 +250,10 @@ psutil_proc_pidtaskinfo_oneshot(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_name(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
struct kinfo_proc kp;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (psutil_get_kinfo_proc(pid, &kp) == -1)
|
||||
return NULL;
|
||||
|
@ -267,10 +267,10 @@ psutil_proc_name(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_cwd(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
struct proc_vnodepathinfo pathinfo;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
if (psutil_proc_pidinfo(
|
||||
|
@ -288,17 +288,17 @@ psutil_proc_cwd(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_exe(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
char buf[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
errno = 0;
|
||||
ret = proc_pidpath((pid_t)pid, &buf, sizeof(buf));
|
||||
ret = proc_pidpath(pid, &buf, sizeof(buf));
|
||||
if (ret == 0) {
|
||||
if (pid == 0)
|
||||
AccessDenied("");
|
||||
AccessDenied("automatically set for PID 0");
|
||||
else
|
||||
psutil_raise_for_pid(pid, "proc_pidpath()");
|
||||
return NULL;
|
||||
|
@ -312,10 +312,10 @@ psutil_proc_exe(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_cmdline(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
PyObject *py_retlist = NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
// get the commandline, defined in arch/osx/process_info.c
|
||||
|
@ -329,10 +329,10 @@ psutil_proc_cmdline(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_environ(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
PyObject *py_retdict = NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
// get the environment block, defined in arch/osx/process_info.c
|
||||
|
@ -422,7 +422,7 @@ psutil_in_shared_region(mach_vm_address_t addr, cpu_type_t type) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_memory_uss(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
size_t len;
|
||||
cpu_type_t cpu_type;
|
||||
size_t private_pages = 0;
|
||||
|
@ -435,7 +435,7 @@ psutil_proc_memory_uss(PyObject *self, PyObject *args) {
|
|||
vm_region_top_info_data_t info;
|
||||
mach_port_t object_name;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
if (psutil_task_for_pid(pid, &task) != 0)
|
||||
|
@ -653,7 +653,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_cputime))
|
||||
goto error;
|
||||
Py_DECREF(py_cputime);
|
||||
Py_CLEAR(py_cputime);
|
||||
}
|
||||
|
||||
ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array,
|
||||
|
@ -841,9 +841,9 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_dev);
|
||||
Py_DECREF(py_mountp);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_dev);
|
||||
Py_CLEAR(py_mountp);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
|
||||
free(fs);
|
||||
|
@ -865,7 +865,7 @@ error:
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_threads(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int err, ret;
|
||||
kern_return_t kr;
|
||||
unsigned int info_count = TASK_BASIC_INFO_COUNT;
|
||||
|
@ -882,7 +882,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
goto error;
|
||||
|
||||
if (psutil_task_for_pid(pid, &task) != 0)
|
||||
|
@ -894,7 +894,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
if (err != KERN_SUCCESS) {
|
||||
// errcode 4 is "invalid argument" (access denied)
|
||||
if (err == 4) {
|
||||
AccessDenied("");
|
||||
AccessDenied("task_info");
|
||||
}
|
||||
else {
|
||||
// otherwise throw a runtime error with appropriate error code
|
||||
|
@ -911,7 +911,6 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
}
|
||||
|
||||
for (j = 0; j < thread_count; j++) {
|
||||
py_tuple = NULL;
|
||||
thread_info_count = THREAD_INFO_MAX;
|
||||
kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
|
||||
(thread_info_t)thinfo_basic, &thread_info_count);
|
||||
|
@ -934,7 +933,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
|
||||
ret = vm_deallocate(task, (vm_address_t)thread_list,
|
||||
|
@ -969,7 +968,7 @@ error:
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_open_files(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int pidinfo_result;
|
||||
int iterations;
|
||||
int i;
|
||||
|
@ -986,7 +985,7 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
|
|||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
goto error;
|
||||
|
||||
pidinfo_result = psutil_proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
|
||||
|
@ -1043,10 +1042,8 @@ psutil_proc_open_files(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
py_tuple = NULL;
|
||||
Py_DECREF(py_path);
|
||||
py_path = NULL;
|
||||
Py_CLEAR(py_tuple);
|
||||
Py_CLEAR(py_path);
|
||||
// --- /construct python list
|
||||
}
|
||||
}
|
||||
|
@ -1073,7 +1070,7 @@ error:
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_connections(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int pidinfo_result;
|
||||
int iterations;
|
||||
int i;
|
||||
|
@ -1093,8 +1090,10 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
|
|||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
|
||||
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");
|
||||
|
@ -1127,7 +1126,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
|
|||
|
||||
if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET) {
|
||||
errno = 0;
|
||||
nb = proc_pidfdinfo((pid_t)pid, fdp_pointer->proc_fd,
|
||||
nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd,
|
||||
PROC_PIDFDSOCKETINFO, &si, sizeof(si));
|
||||
|
||||
// --- errors checking
|
||||
|
@ -1226,7 +1225,7 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
else if (family == AF_UNIX) {
|
||||
py_laddr = PyUnicode_DecodeFSDefault(
|
||||
|
@ -1248,9 +1247,9 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_DECREF(py_laddr);
|
||||
Py_DECREF(py_raddr);
|
||||
Py_CLEAR(py_tuple);
|
||||
Py_CLEAR(py_laddr);
|
||||
Py_CLEAR(py_raddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1275,22 +1274,22 @@ error:
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_proc_num_fds(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int pidinfo_result;
|
||||
int num;
|
||||
struct proc_fdinfo *fds_pointer;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
pidinfo_result = proc_pidinfo((pid_t)pid, PROC_PIDLISTFDS, 0, NULL, 0);
|
||||
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
|
||||
if (pidinfo_result <= 0)
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
|
||||
fds_pointer = malloc(pidinfo_result);
|
||||
if (fds_pointer == NULL)
|
||||
return PyErr_NoMemory();
|
||||
pidinfo_result = proc_pidinfo((pid_t)pid, PROC_PIDLISTFDS, 0, fds_pointer,
|
||||
pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
|
||||
pidinfo_result);
|
||||
if (pidinfo_result <= 0) {
|
||||
free(fds_pointer);
|
||||
|
@ -1370,7 +1369,7 @@ psutil_net_io_counters(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info))
|
||||
goto error;
|
||||
Py_DECREF(py_ifc_info);
|
||||
Py_CLEAR(py_ifc_info);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
|
@ -1543,7 +1542,7 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyDict_SetItemString(py_retdict, disk_name, py_disk_info))
|
||||
goto error;
|
||||
Py_DECREF(py_disk_info);
|
||||
Py_CLEAR(py_disk_info);
|
||||
|
||||
CFRelease(parent_dict);
|
||||
IOObjectRelease(parent);
|
||||
|
@ -1605,10 +1604,10 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
endutxent();
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(py_username);
|
||||
Py_DECREF(py_tty);
|
||||
Py_DECREF(py_hostname);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_username);
|
||||
Py_CLEAR(py_tty);
|
||||
Py_CLEAR(py_hostname);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
|
||||
endutxent();
|
||||
|
@ -1745,8 +1744,7 @@ error:
|
|||
/*
|
||||
* define the psutil C module methods and initialize the module.
|
||||
*/
|
||||
static PyMethodDef
|
||||
PsutilMethods[] = {
|
||||
static PyMethodDef mod_methods[] = {
|
||||
// --- per-process functions
|
||||
|
||||
{"proc_kinfo_oneshot", psutil_proc_kinfo_oneshot, METH_VARARGS,
|
||||
|
@ -1816,96 +1814,93 @@ PsutilMethods[] = {
|
|||
};
|
||||
|
||||
|
||||
struct module_state {
|
||||
PyObject *error;
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
|
||||
#else
|
||||
#define GETSTATE(m) (&_state)
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
static int
|
||||
psutil_osx_traverse(PyObject *m, visitproc visit, void *arg) {
|
||||
Py_VISIT(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
psutil_osx_clear(PyObject *m) {
|
||||
Py_CLEAR(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define INITERR return NULL
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"psutil_osx",
|
||||
"_psutil_osx",
|
||||
NULL,
|
||||
-1,
|
||||
mod_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof(struct module_state),
|
||||
PsutilMethods,
|
||||
NULL,
|
||||
psutil_osx_traverse,
|
||||
psutil_osx_clear,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
PyObject *PyInit__psutil_osx(void)
|
||||
#else /* PY_MAJOR_VERSION */
|
||||
#define INITERR return
|
||||
|
||||
PyMODINIT_FUNC PyInit__psutil_osx(void)
|
||||
|
||||
#else
|
||||
#define INITERROR return
|
||||
|
||||
void
|
||||
init_psutil_osx(void)
|
||||
#endif
|
||||
void init_psutil_osx(void)
|
||||
#endif /* PY_MAJOR_VERSION */
|
||||
{
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *module = PyModule_Create(&moduledef);
|
||||
PyObject *mod = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods);
|
||||
PyObject *mod = Py_InitModule("_psutil_osx", mod_methods);
|
||||
#endif
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
|
||||
if (psutil_setup() != 0)
|
||||
INITERROR;
|
||||
INITERR;
|
||||
|
||||
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
|
||||
if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION))
|
||||
INITERR;
|
||||
// process status constants, defined in:
|
||||
// http://fxr.watson.org/fxr/source/bsd/sys/proc.h?v=xnu-792.6.70#L149
|
||||
PyModule_AddIntConstant(module, "SIDL", SIDL);
|
||||
PyModule_AddIntConstant(module, "SRUN", SRUN);
|
||||
PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
|
||||
PyModule_AddIntConstant(module, "SSTOP", SSTOP);
|
||||
PyModule_AddIntConstant(module, "SZOMB", SZOMB);
|
||||
if (PyModule_AddIntConstant(mod, "SIDL", SIDL))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SRUN", SRUN))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SSLEEP", SSLEEP))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SSTOP", SSTOP))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "SZOMB", SZOMB))
|
||||
INITERR;
|
||||
// connection status constants
|
||||
PyModule_AddIntConstant(module, "TCPS_CLOSED", TCPS_CLOSED);
|
||||
PyModule_AddIntConstant(module, "TCPS_CLOSING", TCPS_CLOSING);
|
||||
PyModule_AddIntConstant(module, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT);
|
||||
PyModule_AddIntConstant(module, "TCPS_LISTEN", TCPS_LISTEN);
|
||||
PyModule_AddIntConstant(module, "TCPS_ESTABLISHED", TCPS_ESTABLISHED);
|
||||
PyModule_AddIntConstant(module, "TCPS_SYN_SENT", TCPS_SYN_SENT);
|
||||
PyModule_AddIntConstant(module, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED);
|
||||
PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1);
|
||||
PyModule_AddIntConstant(module, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2);
|
||||
PyModule_AddIntConstant(module, "TCPS_LAST_ACK", TCPS_LAST_ACK);
|
||||
PyModule_AddIntConstant(module, "TCPS_TIME_WAIT", TCPS_TIME_WAIT);
|
||||
PyModule_AddIntConstant(module, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE);
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_CLOSED", TCPS_CLOSED))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_CLOSING", TCPS_CLOSING))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_CLOSE_WAIT", TCPS_CLOSE_WAIT))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_LISTEN", TCPS_LISTEN))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_ESTABLISHED", TCPS_ESTABLISHED))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_SYN_SENT", TCPS_SYN_SENT))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_SYN_RECEIVED", TCPS_SYN_RECEIVED))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_1", TCPS_FIN_WAIT_1))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_FIN_WAIT_2", TCPS_FIN_WAIT_2))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_LAST_ACK", TCPS_LAST_ACK))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "TCPS_TIME_WAIT", TCPS_TIME_WAIT))
|
||||
INITERR;
|
||||
if (PyModule_AddIntConstant(mod, "PSUTIL_CONN_NONE", PSUTIL_CONN_NONE))
|
||||
INITERR;
|
||||
|
||||
// Exception.
|
||||
ZombieProcessError = PyErr_NewException(
|
||||
"_psutil_osx.ZombieProcessError", NULL, NULL);
|
||||
if (ZombieProcessError == NULL)
|
||||
INITERR;
|
||||
Py_INCREF(ZombieProcessError);
|
||||
PyModule_AddObject(module, "ZombieProcessError", ZombieProcessError);
|
||||
if (PyModule_AddObject(mod, "ZombieProcessError", ZombieProcessError)) {
|
||||
Py_DECREF(ZombieProcessError);
|
||||
INITERR;
|
||||
}
|
||||
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return module;
|
||||
return mod;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
* -1: error (Python exception is set)
|
||||
*/
|
||||
int
|
||||
psutil_pid_exists(long pid) {
|
||||
psutil_pid_exists(pid_t pid) {
|
||||
int ret;
|
||||
|
||||
// No negative PID exists, plus -1 is an alias for sending signal
|
||||
|
@ -71,12 +71,7 @@ psutil_pid_exists(long pid) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(PSUTIL_OSX)
|
||||
ret = kill((pid_t)pid , 0);
|
||||
#else
|
||||
ret = kill(pid , 0);
|
||||
#endif
|
||||
|
||||
if (ret == 0)
|
||||
return 1;
|
||||
else {
|
||||
|
@ -111,23 +106,14 @@ psutil_pid_exists(long pid) {
|
|||
* If none of this is true we giveup and raise RuntimeError(msg).
|
||||
* This will always set a Python exception and return NULL.
|
||||
*/
|
||||
int
|
||||
psutil_raise_for_pid(long pid, char *syscall_name) {
|
||||
// Set exception to AccessDenied if pid exists else NoSuchProcess.
|
||||
if (errno != 0) {
|
||||
// Unlikely we get here.
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return 0;
|
||||
}
|
||||
else if (psutil_pid_exists(pid) == 0) {
|
||||
psutil_debug("%s syscall failed and PID %i no longer exists; "
|
||||
"assume NoSuchProcess", syscall_name, pid);
|
||||
NoSuchProcess("");
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_RuntimeError, "%s syscall failed", syscall_name);
|
||||
}
|
||||
return 0;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -136,11 +122,11 @@ psutil_raise_for_pid(long pid, char *syscall_name) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_posix_getpriority(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int priority;
|
||||
errno = 0;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
#ifdef PSUTIL_OSX
|
||||
|
@ -159,11 +145,11 @@ psutil_posix_getpriority(PyObject *self, PyObject *args) {
|
|||
*/
|
||||
static PyObject *
|
||||
psutil_posix_setpriority(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int priority;
|
||||
int retval;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "li", &pid, &priority))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID "i", &pid, &priority))
|
||||
return NULL;
|
||||
|
||||
#ifdef PSUTIL_OSX
|
||||
|
@ -324,11 +310,11 @@ psutil_net_if_addrs(PyObject* self, PyObject* args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_DECREF(py_address);
|
||||
Py_DECREF(py_netmask);
|
||||
Py_DECREF(py_broadcast);
|
||||
Py_DECREF(py_ptp);
|
||||
Py_CLEAR(py_tuple);
|
||||
Py_CLEAR(py_address);
|
||||
Py_CLEAR(py_netmask);
|
||||
Py_CLEAR(py_broadcast);
|
||||
Py_CLEAR(py_ptp);
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
|
@ -354,7 +340,7 @@ error:
|
|||
static PyObject *
|
||||
psutil_net_if_mtu(PyObject *self, PyObject *args) {
|
||||
char *nic_name;
|
||||
int sock = 0;
|
||||
int sock = -1;
|
||||
int ret;
|
||||
#ifdef PSUTIL_SUNOS10
|
||||
struct lifreq lifr;
|
||||
|
@ -387,7 +373,7 @@ psutil_net_if_mtu(PyObject *self, PyObject *args) {
|
|||
#endif
|
||||
|
||||
error:
|
||||
if (sock != 0)
|
||||
if (sock != -1)
|
||||
close(sock);
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
|
@ -401,7 +387,7 @@ error:
|
|||
static PyObject *
|
||||
psutil_net_if_flags(PyObject *self, PyObject *args) {
|
||||
char *nic_name;
|
||||
int sock = 0;
|
||||
int sock = -1;
|
||||
int ret;
|
||||
struct ifreq ifr;
|
||||
|
||||
|
@ -424,7 +410,7 @@ psutil_net_if_flags(PyObject *self, PyObject *args) {
|
|||
return Py_BuildValue("O", Py_False);
|
||||
|
||||
error:
|
||||
if (sock != 0)
|
||||
if (sock != -1)
|
||||
close(sock);
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
|
@ -579,7 +565,7 @@ int psutil_get_nic_speed(int ifm_active) {
|
|||
static PyObject *
|
||||
psutil_net_if_duplex_speed(PyObject *self, PyObject *args) {
|
||||
char *nic_name;
|
||||
int sock = 0;
|
||||
int sock = -1;
|
||||
int ret;
|
||||
int duplex;
|
||||
int speed;
|
||||
|
@ -591,7 +577,7 @@ psutil_net_if_duplex_speed(PyObject *self, PyObject *args) {
|
|||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == -1)
|
||||
goto error;
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||
|
||||
// speed / duplex
|
||||
|
@ -614,20 +600,19 @@ psutil_net_if_duplex_speed(PyObject *self, PyObject *args) {
|
|||
|
||||
close(sock);
|
||||
return Py_BuildValue("[ii]", duplex, speed);
|
||||
|
||||
error:
|
||||
if (sock != 0)
|
||||
close(sock);
|
||||
return PyErr_SetFromErrno(PyExc_OSError);
|
||||
}
|
||||
#endif // net_if_stats() macOS/BSD implementation
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* define the psutil C module methods and initialize the module.
|
||||
*/
|
||||
static PyMethodDef
|
||||
PsutilMethods[] = {
|
||||
static PyMethodDef mod_methods[] = {
|
||||
{"getpriority", psutil_posix_getpriority, METH_VARARGS,
|
||||
"Return process priority"},
|
||||
{"setpriority", psutil_posix_setpriority, METH_VARARGS,
|
||||
|
@ -645,71 +630,48 @@ PsutilMethods[] = {
|
|||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
struct module_state {
|
||||
PyObject *error;
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
|
||||
#else
|
||||
#define GETSTATE(m) (&_state)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
|
||||
static int
|
||||
psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) {
|
||||
Py_VISIT(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
psutil_posix_clear(PyObject *m) {
|
||||
Py_CLEAR(GETSTATE(m)->error);
|
||||
return 0;
|
||||
}
|
||||
#define INITERR return NULL
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"psutil_posix",
|
||||
"_psutil_posix",
|
||||
NULL,
|
||||
-1,
|
||||
mod_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof(struct module_state),
|
||||
PsutilMethods,
|
||||
NULL,
|
||||
psutil_posix_traverse,
|
||||
psutil_posix_clear,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
|
||||
PyMODINIT_FUNC PyInit__psutil_posix(void)
|
||||
|
||||
#else
|
||||
#define INITERROR return
|
||||
PyObject *PyInit__psutil_posix(void)
|
||||
#else /* PY_MAJOR_VERSION */
|
||||
#define INITERR return
|
||||
|
||||
void init_psutil_posix(void)
|
||||
#endif
|
||||
#endif /* PY_MAJOR_VERSION */
|
||||
{
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *module = PyModule_Create(&moduledef);
|
||||
PyObject *mod = PyModule_Create(&moduledef);
|
||||
#else
|
||||
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
|
||||
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 defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS) || defined(PSUTIL_AIX)
|
||||
PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
|
||||
#endif
|
||||
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
if (mod == NULL)
|
||||
INITERR;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return module;
|
||||
return mod;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
int psutil_pid_exists(long pid);
|
||||
void psutil_raise_for_pid(long pid, char *msg);
|
||||
int psutil_pid_exists(pid_t pid);
|
||||
void psutil_raise_for_pid(pid_t pid, char *msg);
|
||||
|
|
|
@ -12,12 +12,8 @@
|
|||
/* fix compilation issue on SunOS 5.10, see:
|
||||
* https://github.com/giampaolo/psutil/issues/421
|
||||
* https://github.com/giampaolo/psutil/issues/1077
|
||||
* http://us-east.manta.joyent.com/jmc/public/opensolaris/ARChive/PSARC/2010/111/materials/s10ceval.txt
|
||||
*
|
||||
* Because LEGACY_MIB_SIZE defined in the same file there is no way to make autoconfiguration =\
|
||||
*/
|
||||
|
||||
#define NEW_MIB_COMPLIANT 1
|
||||
#define _STRUCTURED_PROC 1
|
||||
|
||||
#include <Python.h>
|
||||
|
@ -44,6 +40,14 @@
|
|||
#include <sys/tihdr.h>
|
||||
#include <stropts.h>
|
||||
#include <inet/tcp.h>
|
||||
#ifndef NEW_MIB_COMPLIANT
|
||||
/*
|
||||
* Solaris introduced NEW_MIB_COMPLIANT macro with Update 4.
|
||||
* See https://github.com/giampaolo/psutil/issues/421
|
||||
* Prior to Update 4, one has to include mib2 by hand.
|
||||
*/
|
||||
#include <inet/mib2.h>
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <math.h> // fabs()
|
||||
|
@ -271,7 +275,7 @@ psutil_proc_environ(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
|
||||
if (! info.pr_envp) {
|
||||
AccessDenied("");
|
||||
AccessDenied("/proc/pid/psinfo struct not set");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -300,8 +304,8 @@ psutil_proc_environ(PyObject *self, PyObject *args) {
|
|||
if (PyDict_SetItem(py_retdict, py_envname, py_envval) < 0)
|
||||
goto error;
|
||||
|
||||
Py_DECREF(py_envname);
|
||||
Py_DECREF(py_envval);
|
||||
Py_CLEAR(py_envname);
|
||||
Py_CLEAR(py_envval);
|
||||
}
|
||||
|
||||
psutil_free_cstrings_array(env, env_count);
|
||||
|
@ -655,10 +659,10 @@ psutil_users(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_username);
|
||||
Py_DECREF(py_tty);
|
||||
Py_DECREF(py_hostname);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_username);
|
||||
Py_CLEAR(py_tty);
|
||||
Py_CLEAR(py_hostname);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
endutxent();
|
||||
|
||||
|
@ -714,9 +718,9 @@ psutil_disk_partitions(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_dev);
|
||||
Py_DECREF(py_mountp);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_dev);
|
||||
Py_CLEAR(py_mountp);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
fclose(file);
|
||||
return py_retlist;
|
||||
|
@ -767,8 +771,7 @@ psutil_per_cpu_times(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_cputime))
|
||||
goto error;
|
||||
Py_DECREF(py_cputime);
|
||||
py_cputime = NULL;
|
||||
Py_CLEAR(py_cputime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -824,7 +827,7 @@ psutil_disk_io_counters(PyObject *self, PyObject *args) {
|
|||
if (PyDict_SetItemString(py_retdict, ksp->ks_name,
|
||||
py_disk_info))
|
||||
goto error;
|
||||
Py_DECREF(py_disk_info);
|
||||
Py_CLEAR(py_disk_info);
|
||||
}
|
||||
}
|
||||
ksp = ksp->ks_next;
|
||||
|
@ -959,8 +962,8 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_path);
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_path);
|
||||
Py_CLEAR(py_tuple);
|
||||
|
||||
// increment pointer
|
||||
p += 1;
|
||||
|
@ -1075,7 +1078,7 @@ psutil_net_io_counters(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info))
|
||||
goto error;
|
||||
Py_DECREF(py_ifc_info);
|
||||
Py_CLEAR(py_ifc_info);
|
||||
goto next;
|
||||
|
||||
next:
|
||||
|
@ -1120,7 +1123,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
|
|||
mib2_udp6Entry_t ude6;
|
||||
#endif
|
||||
char buf[512];
|
||||
int i, flags, getcode, num_ent, state;
|
||||
int i, flags, getcode, num_ent, state, ret;
|
||||
char lip[INET6_ADDRSTRLEN], rip[INET6_ADDRSTRLEN];
|
||||
int lport, rport;
|
||||
int processed_pid;
|
||||
|
@ -1147,7 +1150,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
}
|
||||
|
||||
int ret = ioctl(sd, I_PUSH, "tcp");
|
||||
ret = ioctl(sd, I_PUSH, "tcp");
|
||||
if (ret == -1) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
|
@ -1273,7 +1276,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
}
|
||||
#if defined(AF_INET6)
|
||||
|
@ -1316,7 +1319,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1355,7 +1358,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
}
|
||||
#if defined(AF_INET6)
|
||||
|
@ -1388,7 +1391,7 @@ psutil_net_connections(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1561,7 +1564,7 @@ psutil_net_if_stats(PyObject* self, PyObject* args) {
|
|||
goto error;
|
||||
if (PyDict_SetItemString(py_retdict, ksp->ks_name, py_ifc_info))
|
||||
goto error;
|
||||
Py_DECREF(py_ifc_info);
|
||||
Py_CLEAR(py_ifc_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1748,7 +1751,14 @@ void init_psutil_sunos(void)
|
|||
PyModule_AddIntConstant(module, "SSTOP", SSTOP);
|
||||
PyModule_AddIntConstant(module, "SIDL", SIDL);
|
||||
PyModule_AddIntConstant(module, "SONPROC", SONPROC);
|
||||
#ifdef SWAIT
|
||||
PyModule_AddIntConstant(module, "SWAIT", SWAIT);
|
||||
#else
|
||||
/* sys/proc.h started defining SWAIT somewhere
|
||||
* after Update 3 and prior to Update 5 included.
|
||||
*/
|
||||
PyModule_AddIntConstant(module, "SWAIT", 0);
|
||||
#endif
|
||||
|
||||
PyModule_AddIntConstant(module, "PRNODEV", PRNODEV); // for process tty
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,39 +8,24 @@ import contextlib
|
|||
import errno
|
||||
import functools
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
from collections import namedtuple
|
||||
|
||||
from . import _common
|
||||
try:
|
||||
from . import _psutil_windows as cext
|
||||
except ImportError as err:
|
||||
if str(err).lower().startswith("dll load failed") and \
|
||||
sys.getwindowsversion()[0] < 6:
|
||||
# We may get here if:
|
||||
# 1) we are on an old Windows version
|
||||
# 2) psutil was installed via pip + wheel
|
||||
# See: https://github.com/giampaolo/psutil/issues/811
|
||||
# It must be noted that psutil can still (kind of) work
|
||||
# on outdated systems if compiled / installed from sources,
|
||||
# but if we get here it means this this was a wheel (or exe).
|
||||
msg = "this Windows version is too old (< Windows Vista); "
|
||||
msg += "psutil 3.4.2 is the latest version which supports Windows "
|
||||
msg += "2000, XP and 2003 server"
|
||||
raise RuntimeError(msg)
|
||||
else:
|
||||
raise
|
||||
|
||||
from ._common import AccessDenied
|
||||
from ._common import conn_tmap
|
||||
from ._common import conn_to_ntuple
|
||||
from ._common import debug
|
||||
from ._common import ENCODING
|
||||
from ._common import ENCODING_ERRS
|
||||
from ._common import isfile_strict
|
||||
from ._common import memoize
|
||||
from ._common import memoize_when_activated
|
||||
from ._common import NoSuchProcess
|
||||
from ._common import parse_environ_block
|
||||
from ._common import sockfam_to_enum
|
||||
from ._common import socktype_to_enum
|
||||
from ._common import TimeoutExpired
|
||||
from ._common import usage_percent
|
||||
from ._compat import long
|
||||
from ._compat import lru_cache
|
||||
|
@ -54,6 +39,22 @@ from ._psutil_windows import IDLE_PRIORITY_CLASS
|
|||
from ._psutil_windows import NORMAL_PRIORITY_CLASS
|
||||
from ._psutil_windows import REALTIME_PRIORITY_CLASS
|
||||
|
||||
try:
|
||||
from . import _psutil_windows as cext
|
||||
except ImportError as err:
|
||||
if str(err).lower().startswith("dll load failed") and \
|
||||
sys.getwindowsversion()[0] < 6:
|
||||
# We may get here if:
|
||||
# 1) we are on an old Windows version
|
||||
# 2) psutil was installed via pip + wheel
|
||||
# See: https://github.com/giampaolo/psutil/issues/811
|
||||
msg = "this Windows version is too old (< Windows Vista); "
|
||||
msg += "psutil 3.4.2 is the latest version which supports Windows "
|
||||
msg += "2000, XP and 2003 server"
|
||||
raise RuntimeError(msg)
|
||||
else:
|
||||
raise
|
||||
|
||||
if sys.version_info >= (3, 4):
|
||||
import enum
|
||||
else:
|
||||
|
@ -79,9 +80,8 @@ __extra__all__ = [
|
|||
# =====================================================================
|
||||
|
||||
CONN_DELETE_TCB = "DELETE_TCB"
|
||||
HAS_PROC_IO_PRIORITY = hasattr(cext, "proc_io_priority_get")
|
||||
HAS_GETLOADAVG = hasattr(cext, "getloadavg")
|
||||
|
||||
ERROR_PARTIAL_COPY = 299
|
||||
PYPY = '__pypy__' in sys.builtin_module_names
|
||||
|
||||
if enum is None:
|
||||
AF_LINK = -1
|
||||
|
@ -154,35 +154,6 @@ pinfo_map = dict(
|
|||
mem_private=21,
|
||||
)
|
||||
|
||||
# These objects get set on "import psutil" from the __init__.py
|
||||
# file, see: https://github.com/giampaolo/psutil/issues/1402
|
||||
NoSuchProcess = None
|
||||
ZombieProcess = None
|
||||
AccessDenied = None
|
||||
TimeoutExpired = None
|
||||
|
||||
# More values at: https://stackoverflow.com/a/20804735/376587
|
||||
WIN_10 = (10, 0)
|
||||
WIN_8 = (6, 2)
|
||||
WIN_7 = (6, 1)
|
||||
WIN_SERVER_2008 = (6, 0)
|
||||
WIN_VISTA = (6, 0)
|
||||
WIN_SERVER_2003 = (5, 2)
|
||||
WIN_XP = (5, 1)
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def get_winver():
|
||||
"""Usage:
|
||||
>>> if get_winver() <= WIN_VISTA:
|
||||
... ...
|
||||
"""
|
||||
wv = sys.getwindowsversion()
|
||||
return (wv.major, wv.minor)
|
||||
|
||||
|
||||
IS_WIN_XP = get_winver() < WIN_VISTA
|
||||
|
||||
|
||||
# =====================================================================
|
||||
# --- named tuples
|
||||
|
@ -227,7 +198,8 @@ def convert_dos_path(s):
|
|||
"""
|
||||
rawdrive = '\\'.join(s.split('\\')[:3])
|
||||
driveletter = cext.win32_QueryDosDevice(rawdrive)
|
||||
return os.path.join(driveletter, s[len(rawdrive):])
|
||||
remainder = s[len(rawdrive):]
|
||||
return os.path.join(driveletter, remainder)
|
||||
|
||||
|
||||
def py2_strencode(s):
|
||||
|
@ -354,9 +326,9 @@ def cpu_freq():
|
|||
return [_common.scpufreq(float(curr), min_, float(max_))]
|
||||
|
||||
|
||||
if HAS_GETLOADAVG:
|
||||
_loadavg_inititialized = False
|
||||
|
||||
|
||||
def getloadavg():
|
||||
"""Return the number of processes in the system run queue averaged
|
||||
over the last 1, 5, and 15 minutes respectively as a tuple"""
|
||||
|
@ -388,17 +360,8 @@ def net_connections(kind, _pid=-1):
|
|||
ret = set()
|
||||
for item in rawlist:
|
||||
fd, fam, type, laddr, raddr, status, pid = item
|
||||
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)
|
||||
nt = conn_to_ntuple(fd, fam, type, laddr, raddr, status, TCP_STATUSES,
|
||||
pid=pid if _pid == -1 else None)
|
||||
ret.add(nt)
|
||||
return list(ret)
|
||||
|
||||
|
@ -719,6 +682,32 @@ def wrap_exceptions(fun):
|
|||
return wrapper
|
||||
|
||||
|
||||
def retry_error_partial_copy(fun):
|
||||
"""Workaround for https://github.com/giampaolo/psutil/issues/875.
|
||||
See: https://stackoverflow.com/questions/4457745#4457745
|
||||
"""
|
||||
@functools.wraps(fun)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
delay = 0.0001
|
||||
times = 33
|
||||
for x in range(times): # retries for roughly 1 second
|
||||
try:
|
||||
return fun(self, *args, **kwargs)
|
||||
except WindowsError as _:
|
||||
err = _
|
||||
if err.winerror == ERROR_PARTIAL_COPY:
|
||||
time.sleep(delay)
|
||||
delay = min(delay * 2, 0.04)
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
msg = "%s retried %s times, converted to AccessDenied as it's " \
|
||||
"still returning %r" % (fun, times, err)
|
||||
raise AccessDenied(pid=self.pid, name=self._name, msg=msg)
|
||||
return wrapper
|
||||
|
||||
|
||||
class Process(object):
|
||||
"""Wrapper class around underlying C implementation."""
|
||||
|
||||
|
@ -732,14 +721,15 @@ class Process(object):
|
|||
# --- oneshot() stuff
|
||||
|
||||
def oneshot_enter(self):
|
||||
self.oneshot_info.cache_activate(self)
|
||||
self._proc_info.cache_activate(self)
|
||||
self.exe.cache_activate(self)
|
||||
|
||||
def oneshot_exit(self):
|
||||
self.oneshot_info.cache_deactivate(self)
|
||||
self._proc_info.cache_deactivate(self)
|
||||
self.exe.cache_deactivate(self)
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def oneshot_info(self):
|
||||
def _proc_info(self):
|
||||
"""Return multiple information about this process as a
|
||||
raw tuple.
|
||||
"""
|
||||
|
@ -747,7 +737,6 @@ class Process(object):
|
|||
assert len(ret) == len(pinfo_map)
|
||||
return ret
|
||||
|
||||
@wrap_exceptions
|
||||
def name(self):
|
||||
"""Return process name, which on Windows is always the final
|
||||
part of the executable.
|
||||
|
@ -756,32 +745,33 @@ class Process(object):
|
|||
# and process-hacker.
|
||||
if self.pid == 0:
|
||||
return "System Idle Process"
|
||||
elif self.pid == 4:
|
||||
if self.pid == 4:
|
||||
return "System"
|
||||
else:
|
||||
try:
|
||||
# Note: this will fail with AD for most PIDs owned
|
||||
# by another user but it's faster.
|
||||
return py2_strencode(os.path.basename(self.exe()))
|
||||
except AccessDenied:
|
||||
return py2_strencode(cext.proc_name(self.pid))
|
||||
return os.path.basename(self.exe())
|
||||
|
||||
@wrap_exceptions
|
||||
@memoize_when_activated
|
||||
def exe(self):
|
||||
# Dual implementation, see:
|
||||
# https://github.com/giampaolo/psutil/pull/1413
|
||||
if not IS_WIN_XP:
|
||||
if PYPY:
|
||||
try:
|
||||
exe = cext.proc_exe(self.pid)
|
||||
else:
|
||||
if self.pid in (0, 4):
|
||||
# https://github.com/giampaolo/psutil/issues/414
|
||||
# https://github.com/giampaolo/psutil/issues/528
|
||||
except WindowsError as err:
|
||||
# 24 = ERROR_TOO_MANY_OPEN_FILES. Not sure why this happens
|
||||
# (perhaps PyPy's JIT delaying garbage collection of files?).
|
||||
if err.errno == 24:
|
||||
debug("%r forced into AccessDenied" % err)
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
raise
|
||||
else:
|
||||
exe = cext.proc_exe(self.pid)
|
||||
exe = convert_dos_path(exe)
|
||||
return py2_strencode(exe)
|
||||
if not PY3:
|
||||
exe = py2_strencode(exe)
|
||||
if exe.startswith('\\'):
|
||||
return convert_dos_path(exe)
|
||||
return exe # May be "Registry", "MemCompression", ...
|
||||
|
||||
@wrap_exceptions
|
||||
@retry_error_partial_copy
|
||||
def cmdline(self):
|
||||
if cext.WINVER >= cext.WINDOWS_8_1:
|
||||
# PEB method detects cmdline changes but requires more
|
||||
|
@ -801,6 +791,7 @@ class Process(object):
|
|||
return [py2_strencode(s) for s in ret]
|
||||
|
||||
@wrap_exceptions
|
||||
@retry_error_partial_copy
|
||||
def environ(self):
|
||||
ustr = cext.proc_environ(self.pid)
|
||||
if ustr and not PY3:
|
||||
|
@ -820,7 +811,7 @@ class Process(object):
|
|||
if is_permission_err(err):
|
||||
# TODO: the C ext can probably be refactored in order
|
||||
# to get this from cext.proc_info()
|
||||
info = self.oneshot_info()
|
||||
info = self._proc_info()
|
||||
return (
|
||||
info[pinfo_map['num_page_faults']],
|
||||
info[pinfo_map['peak_wset']],
|
||||
|
@ -863,7 +854,6 @@ class Process(object):
|
|||
for addr, perm, path, rss in raw:
|
||||
path = convert_dos_path(path)
|
||||
if not PY3:
|
||||
assert isinstance(path, unicode), type(path)
|
||||
path = py2_strencode(path)
|
||||
addr = hex(addr)
|
||||
yield (addr, perm, path, rss)
|
||||
|
@ -874,7 +864,16 @@ class Process(object):
|
|||
|
||||
@wrap_exceptions
|
||||
def send_signal(self, sig):
|
||||
if sig == signal.SIGTERM:
|
||||
cext.proc_kill(self.pid)
|
||||
# py >= 2.7
|
||||
elif sig in (getattr(signal, "CTRL_C_EVENT", object()),
|
||||
getattr(signal, "CTRL_BREAK_EVENT", object())):
|
||||
os.kill(self.pid, sig)
|
||||
else:
|
||||
raise ValueError(
|
||||
"only SIGTERM, CTRL_C_EVENT and CTRL_BREAK_EVENT signals "
|
||||
"are supported on Windows")
|
||||
|
||||
@wrap_exceptions
|
||||
def wait(self, timeout=None):
|
||||
|
@ -928,19 +927,19 @@ class Process(object):
|
|||
|
||||
@wrap_exceptions
|
||||
def create_time(self):
|
||||
# special case for kernel process PIDs; return system boot time
|
||||
if self.pid in (0, 4):
|
||||
return boot_time()
|
||||
# Note: proc_times() not put under oneshot() 'cause create_time()
|
||||
# is already cached by the main Process class.
|
||||
try:
|
||||
return cext.proc_create_time(self.pid)
|
||||
user, system, created = cext.proc_times(self.pid)
|
||||
return created
|
||||
except OSError as err:
|
||||
if is_permission_err(err):
|
||||
return self.oneshot_info()[pinfo_map['create_time']]
|
||||
return self._proc_info()[pinfo_map['create_time']]
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def num_threads(self):
|
||||
return self.oneshot_info()[pinfo_map['num_threads']]
|
||||
return self._proc_info()[pinfo_map['num_threads']]
|
||||
|
||||
@wrap_exceptions
|
||||
def threads(self):
|
||||
|
@ -954,11 +953,11 @@ class Process(object):
|
|||
@wrap_exceptions
|
||||
def cpu_times(self):
|
||||
try:
|
||||
user, system = cext.proc_cpu_times(self.pid)
|
||||
user, system, created = cext.proc_times(self.pid)
|
||||
except OSError as err:
|
||||
if not is_permission_err(err):
|
||||
raise
|
||||
info = self.oneshot_info()
|
||||
info = self._proc_info()
|
||||
user = info[pinfo_map['user_time']]
|
||||
system = info[pinfo_map['kernel_time']]
|
||||
# Children user/system times are not retrievable (set to 0).
|
||||
|
@ -973,6 +972,7 @@ class Process(object):
|
|||
cext.proc_suspend_or_resume(self.pid, False)
|
||||
|
||||
@wrap_exceptions
|
||||
@retry_error_partial_copy
|
||||
def cwd(self):
|
||||
if self.pid in (0, 4):
|
||||
raise AccessDenied(self.pid, self._name)
|
||||
|
@ -1015,8 +1015,6 @@ class Process(object):
|
|||
def nice_set(self, value):
|
||||
return cext.proc_priority_set(self.pid, value)
|
||||
|
||||
# available on Windows >= Vista
|
||||
if HAS_PROC_IO_PRIORITY:
|
||||
@wrap_exceptions
|
||||
def ionice_get(self):
|
||||
ret = cext.proc_io_priority_get(self.pid)
|
||||
|
@ -1040,7 +1038,7 @@ class Process(object):
|
|||
except OSError as err:
|
||||
if not is_permission_err(err):
|
||||
raise
|
||||
info = self.oneshot_info()
|
||||
info = self._proc_info()
|
||||
ret = (
|
||||
info[pinfo_map['io_rcount']],
|
||||
info[pinfo_map['io_wcount']],
|
||||
|
@ -1097,11 +1095,11 @@ class Process(object):
|
|||
return cext.proc_num_handles(self.pid)
|
||||
except OSError as err:
|
||||
if is_permission_err(err):
|
||||
return self.oneshot_info()[pinfo_map['num_handles']]
|
||||
return self._proc_info()[pinfo_map['num_handles']]
|
||||
raise
|
||||
|
||||
@wrap_exceptions
|
||||
def num_ctx_switches(self):
|
||||
ctx_switches = self.oneshot_info()[pinfo_map['ctx_switches']]
|
||||
ctx_switches = self._proc_info()[pinfo_map['ctx_switches']]
|
||||
# only voluntary ctx switches are supported
|
||||
return _common.pctxsw(ctx_switches, 0)
|
||||
|
|
|
@ -31,5 +31,4 @@ struct ifaddrs {
|
|||
|
||||
extern int getifaddrs(struct ifaddrs **);
|
||||
extern void freeifaddrs(struct ifaddrs *);
|
||||
|
||||
#endif
|
|
@ -179,7 +179,7 @@ psutil_search_tcplist(char *buf, struct kinfo_file *kif) {
|
|||
PyObject *
|
||||
psutil_proc_connections(PyObject *self, PyObject *args) {
|
||||
// Return connections opened by process.
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int i;
|
||||
int cnt;
|
||||
struct kinfo_file *freep = NULL;
|
||||
|
@ -202,8 +202,11 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
|
|||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
|
||||
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;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "../../_psutil_common.h"
|
||||
#include "../../_psutil_posix.h"
|
||||
|
||||
|
||||
#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
|
||||
#define PSUTIL_BT2MSEC(bt) (bt.sec * 1000 + (((uint64_t) 1000000000 * (uint32_t) \
|
||||
(bt.frac >> 32) ) >> 32 ) / 1000000)
|
||||
|
@ -43,7 +44,7 @@
|
|||
|
||||
|
||||
int
|
||||
psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) {
|
||||
psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) {
|
||||
// Fills a kinfo_proc struct based on process pid.
|
||||
int mib[4];
|
||||
size_t size;
|
||||
|
@ -60,7 +61,7 @@ psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc) {
|
|||
|
||||
// sysctl stores 0 in the size if we can't find the process information.
|
||||
if (size == 0) {
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -87,81 +88,42 @@ psutil_get_proc_list(struct 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.
|
||||
// this list. On success returns 0, else 1 with exception set.
|
||||
int err;
|
||||
struct kinfo_proc *result;
|
||||
int done;
|
||||
struct kinfo_proc *buf = NULL;
|
||||
int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
|
||||
size_t length;
|
||||
size_t length = 0;
|
||||
|
||||
assert(procList != NULL);
|
||||
assert(*procList == NULL);
|
||||
assert(procCount != NULL);
|
||||
|
||||
*procCount = 0;
|
||||
|
||||
/*
|
||||
* We start by calling sysctl with result == NULL and length == 0.
|
||||
* That will succeed, and set length to the appropriate length.
|
||||
* We then allocate a buffer of that size and call sysctl again
|
||||
* with that buffer. If that succeeds, we're done. If that fails
|
||||
* with ENOMEM, we have to throw away our buffer and loop. Note
|
||||
* that the loop causes use to call sysctl with NULL again; this
|
||||
* is necessary because the ENOMEM failure case sets length to
|
||||
* the amount of data returned, not the amount of data that
|
||||
* could have been returned.
|
||||
*/
|
||||
result = NULL;
|
||||
done = 0;
|
||||
do {
|
||||
assert(result == NULL);
|
||||
// Call sysctl with a NULL buffer.
|
||||
length = 0;
|
||||
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1,
|
||||
NULL, &length, NULL, 0);
|
||||
if (err == -1)
|
||||
err = errno;
|
||||
// Call sysctl with a NULL buffer in order to get buffer length.
|
||||
err = sysctl(name, 3, NULL, &length, NULL, 0);
|
||||
if (err == -1) {
|
||||
PyErr_SetFromOSErrnoWithSyscall("sysctl (null buffer)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allocate an appropriately sized buffer based on the results
|
||||
// from the previous call.
|
||||
if (err == 0) {
|
||||
result = malloc(length);
|
||||
if (result == NULL)
|
||||
err = ENOMEM;
|
||||
buf = malloc(length);
|
||||
if (buf == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Call sysctl again with the new buffer. If we get an ENOMEM
|
||||
// error, toss away our buffer and start again.
|
||||
if (err == 0) {
|
||||
err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1,
|
||||
result, &length, NULL, 0);
|
||||
if (err == -1)
|
||||
err = errno;
|
||||
if (err == 0) {
|
||||
done = 1;
|
||||
}
|
||||
else if (err == ENOMEM) {
|
||||
assert(result != NULL);
|
||||
free(result);
|
||||
result = NULL;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
} while (err == 0 && ! done);
|
||||
|
||||
// Clean up and establish post conditions.
|
||||
if (err != 0 && result != NULL) {
|
||||
free(result);
|
||||
result = NULL;
|
||||
// Call sysctl again with the new buffer.
|
||||
err = sysctl(name, 3, buf, &length, NULL, 0);
|
||||
if (err == -1) {
|
||||
PyErr_SetFromOSErrnoWithSyscall("sysctl");
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*procList = result;
|
||||
*procList = buf;
|
||||
*procCount = length / sizeof(struct kinfo_proc);
|
||||
|
||||
assert((err == 0) == (*procList != NULL));
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -179,7 +141,7 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
|
|||
* 1 for insufficient privileges.
|
||||
*/
|
||||
static char
|
||||
*psutil_get_cmd_args(long pid, size_t *argsize) {
|
||||
*psutil_get_cmd_args(pid_t pid, size_t *argsize) {
|
||||
int mib[4];
|
||||
int argmax;
|
||||
size_t size = sizeof(argmax);
|
||||
|
@ -221,7 +183,7 @@ static char
|
|||
|
||||
// returns the command line as a python list object
|
||||
PyObject *
|
||||
psutil_get_cmdline(long pid) {
|
||||
psutil_get_cmdline(pid_t pid) {
|
||||
char *argstr = NULL;
|
||||
size_t pos = 0;
|
||||
size_t argsize = 0;
|
||||
|
@ -268,14 +230,14 @@ error:
|
|||
*/
|
||||
PyObject *
|
||||
psutil_proc_exe(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
char pathname[PATH_MAX];
|
||||
int error;
|
||||
int mib[4];
|
||||
int ret;
|
||||
size_t size;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
|
@ -300,7 +262,7 @@ psutil_proc_exe(PyObject *self, PyObject *args) {
|
|||
if (ret == -1)
|
||||
return NULL;
|
||||
else if (ret == 0)
|
||||
return NoSuchProcess("");
|
||||
return NoSuchProcess("psutil_pid_exists");
|
||||
else
|
||||
strcpy(pathname, "");
|
||||
}
|
||||
|
@ -312,9 +274,9 @@ psutil_proc_exe(PyObject *self, PyObject *args) {
|
|||
PyObject *
|
||||
psutil_proc_num_threads(PyObject *self, PyObject *args) {
|
||||
// Return number of threads used by process as a Python integer.
|
||||
long pid;
|
||||
pid_t pid;
|
||||
struct kinfo_proc kp;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (psutil_kinfo_proc(pid, &kp) == -1)
|
||||
return NULL;
|
||||
|
@ -329,7 +291,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
// Thanks to Robert N. M. Watson:
|
||||
// http://code.metager.de/source/xref/freebsd/usr.bin/procstat/
|
||||
// procstat_threads.c
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int mib[4];
|
||||
struct kinfo_proc *kip = NULL;
|
||||
struct kinfo_proc *kipp = NULL;
|
||||
|
@ -341,7 +303,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
goto error;
|
||||
|
||||
// we need to re-query for thread information, so don't use *kipp
|
||||
|
@ -357,7 +319,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
}
|
||||
if (size == 0) {
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -373,7 +335,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
}
|
||||
if (size == 0) {
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -558,7 +520,7 @@ psutil_swap_mem(PyObject *self, PyObject *args) {
|
|||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
|
||||
PyObject *
|
||||
psutil_proc_cwd(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
struct kinfo_file *freep = NULL;
|
||||
struct kinfo_file *kif;
|
||||
struct kinfo_proc kipp;
|
||||
|
@ -566,7 +528,7 @@ psutil_proc_cwd(PyObject *self, PyObject *args) {
|
|||
|
||||
int i, cnt;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
goto error;
|
||||
if (psutil_kinfo_proc(pid, &kipp) == -1)
|
||||
goto error;
|
||||
|
@ -609,13 +571,13 @@ error:
|
|||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
|
||||
PyObject *
|
||||
psutil_proc_num_fds(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int cnt;
|
||||
|
||||
struct kinfo_file *freep;
|
||||
struct kinfo_proc kipp;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (psutil_kinfo_proc(pid, &kipp) == -1)
|
||||
return NULL;
|
||||
|
@ -768,7 +730,7 @@ PyObject *
|
|||
psutil_proc_memory_maps(PyObject *self, PyObject *args) {
|
||||
// Return a list of tuples for every process memory maps.
|
||||
// 'procstat' cmdline utility has been used as an example.
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int ptrwidth;
|
||||
int i, cnt;
|
||||
char addr[1000];
|
||||
|
@ -784,7 +746,7 @@ psutil_proc_memory_maps(PyObject *self, PyObject *args) {
|
|||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
goto error;
|
||||
if (psutil_kinfo_proc(pid, &kp) == -1)
|
||||
goto error;
|
||||
|
@ -884,14 +846,14 @@ psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args) {
|
|||
// Get process CPU affinity.
|
||||
// Reference:
|
||||
// http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int ret;
|
||||
int i;
|
||||
cpuset_t mask;
|
||||
PyObject* py_retlist;
|
||||
PyObject* py_cpu_num;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &pid))
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
ret = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, pid,
|
||||
sizeof(mask), &mask);
|
||||
|
@ -926,7 +888,7 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
|
|||
// Set process CPU affinity.
|
||||
// Reference:
|
||||
// http://sources.freebsd.org/RELENG_9/src/usr.bin/cpuset/cpuset.c
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int i;
|
||||
int seq_len;
|
||||
int ret;
|
||||
|
@ -934,7 +896,7 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
|
|||
PyObject *py_cpu_set;
|
||||
PyObject *py_cpu_seq = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "lO", &pid, &py_cpu_set))
|
||||
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O", &pid, &py_cpu_set))
|
||||
return NULL;
|
||||
|
||||
py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer");
|
||||
|
|
|
@ -203,19 +203,20 @@ int psutil_gather_inet(int proto, PyObject *py_retlist) {
|
|||
if (!py_raddr)
|
||||
goto error;
|
||||
py_tuple = Py_BuildValue(
|
||||
"(iiiNNii)",
|
||||
"iiiNNi" _Py_PARSE_PID,
|
||||
xf->xf_fd, // fd
|
||||
family, // family
|
||||
type, // type
|
||||
py_laddr, // laddr
|
||||
py_raddr, // raddr
|
||||
status, // status
|
||||
xf->xf_pid); // pid
|
||||
xf->xf_pid // pid
|
||||
);
|
||||
if (!py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_DECREF(py_tuple);
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
|
|
@ -37,9 +37,10 @@
|
|||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "specific.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)
|
||||
|
@ -71,7 +72,7 @@ psutil_kinfo_proc(pid_t pid, kinfo_proc *proc) {
|
|||
}
|
||||
// sysctl stores 0 in the size if we can't find the process information.
|
||||
if (size == 0) {
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -111,6 +112,47 @@ kinfo_getfile(pid_t pid, int* cnt) {
|
|||
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
|
||||
|
@ -156,7 +198,7 @@ psutil_proc_exe(PyObject *self, PyObject *args) {
|
|||
if (ret == -1)
|
||||
return NULL;
|
||||
else if (ret == 0)
|
||||
return NoSuchProcess("");
|
||||
return NoSuchProcess("psutil_pid_exists");
|
||||
else
|
||||
strcpy(pathname, "");
|
||||
}
|
||||
|
@ -208,7 +250,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
}
|
||||
if (size == 0) {
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -225,7 +267,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
goto error;
|
||||
}
|
||||
if (size == 0) {
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -281,14 +323,14 @@ psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) {
|
|||
if (kd == NULL) {
|
||||
PyErr_Format(
|
||||
PyExc_RuntimeError, "kvm_openfiles() syscall failed: %s", errbuf);
|
||||
return errno;
|
||||
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 errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*procCount = (size_t)cnt;
|
||||
|
@ -298,7 +340,7 @@ psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) {
|
|||
if ((*procList = malloc(mlen)) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
kvm_close(kd);
|
||||
return errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(*procList, result, mlen);
|
||||
|
|
|
@ -26,3 +26,4 @@ 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);
|
||||
|
|
|
@ -46,6 +46,21 @@
|
|||
// Utility functions
|
||||
// ============================================================================
|
||||
|
||||
|
||||
static void
|
||||
convert_kvm_err(const char *syscall, char *errbuf) {
|
||||
char fullmsg[8192];
|
||||
|
||||
sprintf(fullmsg, "(originated from %s: %s)", syscall, errbuf);
|
||||
if (strstr(errbuf, "Permission denied") != NULL)
|
||||
AccessDenied(fullmsg);
|
||||
else if (strstr(errbuf, "Operation not permitted") != NULL)
|
||||
AccessDenied(fullmsg);
|
||||
else
|
||||
PyErr_Format(PyExc_RuntimeError, fullmsg);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) {
|
||||
// Fills a kinfo_proc struct based on process pid.
|
||||
|
@ -67,7 +82,7 @@ psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) {
|
|||
}
|
||||
// sysctl stores 0 in the size if we can't find the process information.
|
||||
if (size == 0) {
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl (size = 0)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -75,7 +90,7 @@ psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) {
|
|||
|
||||
|
||||
struct kinfo_file *
|
||||
kinfo_getfile(long pid, int* cnt) {
|
||||
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];
|
||||
|
@ -84,7 +99,7 @@ kinfo_getfile(long pid, int* cnt) {
|
|||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_FILE;
|
||||
mib[2] = KERN_FILE_BYPID;
|
||||
mib[3] = (int) pid;
|
||||
mib[3] = pid;
|
||||
mib[4] = sizeof(struct kinfo_file);
|
||||
mib[5] = 0;
|
||||
|
||||
|
@ -133,16 +148,16 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
|
|||
assert(procCount != NULL);
|
||||
|
||||
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
|
||||
|
||||
if (kd == NULL) {
|
||||
return errno;
|
||||
if (! kd) {
|
||||
convert_kvm_err("kvm_openfiles", errbuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt);
|
||||
if (result == NULL) {
|
||||
PyErr_Format(PyExc_RuntimeError, "kvm_getprocs syscall failed");
|
||||
kvm_close(kd);
|
||||
err(1, NULL);
|
||||
return errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*procCount = (size_t)cnt;
|
||||
|
@ -150,9 +165,9 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
|
|||
size_t mlen = cnt * sizeof(struct kinfo_proc);
|
||||
|
||||
if ((*procList = malloc(mlen)) == NULL) {
|
||||
PyErr_NoMemory();
|
||||
kvm_close(kd);
|
||||
err(1, NULL);
|
||||
return errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(*procList, result, mlen);
|
||||
|
@ -163,8 +178,8 @@ psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
|
|||
}
|
||||
|
||||
|
||||
char **
|
||||
_psutil_get_argv(long pid) {
|
||||
static char **
|
||||
_psutil_get_argv(pid_t pid) {
|
||||
static char **argv;
|
||||
int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
|
||||
size_t argv_size = 128;
|
||||
|
@ -189,7 +204,7 @@ _psutil_get_argv(long pid) {
|
|||
|
||||
// returns the command line as a python list object
|
||||
PyObject *
|
||||
psutil_get_cmdline(long pid) {
|
||||
psutil_get_cmdline(pid_t pid) {
|
||||
static char **argv;
|
||||
char **p;
|
||||
PyObject *py_arg = NULL;
|
||||
|
@ -226,7 +241,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
// https://github.com/janmojzis/pstree/blob/master/proc_kvm.c
|
||||
// Note: this requires root access, else it will fail trying
|
||||
// to access /dev/kmem.
|
||||
long pid;
|
||||
pid_t pid;
|
||||
kvm_t *kd = NULL;
|
||||
int nentries, i;
|
||||
char errbuf[4096];
|
||||
|
@ -236,15 +251,12 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
goto error;
|
||||
|
||||
kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
|
||||
if (! kd) {
|
||||
if (strstr(errbuf, "Permission denied") != NULL)
|
||||
AccessDenied("");
|
||||
else
|
||||
PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() syscall failed");
|
||||
convert_kvm_err("kvm_openfiles()", errbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -253,7 +265,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
sizeof(*kp), &nentries);
|
||||
if (! kp) {
|
||||
if (strstr(errbuf, "Permission denied") != NULL)
|
||||
AccessDenied("");
|
||||
AccessDenied("kvm_getprocs");
|
||||
else
|
||||
PyErr_Format(PyExc_RuntimeError, "kvm_getprocs() syscall failed");
|
||||
goto error;
|
||||
|
@ -264,7 +276,7 @@ psutil_proc_threads(PyObject *self, PyObject *args) {
|
|||
continue;
|
||||
if (kp[i].p_pid == pid) {
|
||||
py_tuple = Py_BuildValue(
|
||||
"Idd",
|
||||
_Py_PARSE_PID "dd",
|
||||
kp[i].p_tid,
|
||||
PSUTIL_KPT2DOUBLE(kp[i].p_uutime),
|
||||
PSUTIL_KPT2DOUBLE(kp[i].p_ustime));
|
||||
|
@ -390,25 +402,23 @@ error:
|
|||
|
||||
PyObject *
|
||||
psutil_proc_num_fds(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int cnt;
|
||||
|
||||
struct kinfo_file *freep;
|
||||
struct kinfo_proc kipp;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
|
||||
if (psutil_kinfo_proc(pid, &kipp) == -1)
|
||||
return NULL;
|
||||
|
||||
errno = 0;
|
||||
freep = kinfo_getfile(pid, &cnt);
|
||||
if (freep == NULL) {
|
||||
psutil_raise_for_pid(pid, "kinfo_getfile()");
|
||||
if (freep == NULL)
|
||||
return NULL;
|
||||
}
|
||||
free(freep);
|
||||
|
||||
free(freep);
|
||||
return Py_BuildValue("i", cnt);
|
||||
}
|
||||
|
||||
|
@ -418,12 +428,12 @@ psutil_proc_cwd(PyObject *self, PyObject *args) {
|
|||
// Reference:
|
||||
// https://github.com/openbsd/src/blob/
|
||||
// 588f7f8c69786211f2d16865c552afb91b1c7cba/bin/ps/print.c#L191
|
||||
long pid;
|
||||
pid_t pid;
|
||||
struct kinfo_proc kp;
|
||||
char path[MAXPATHLEN];
|
||||
size_t pathlen = sizeof path;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (psutil_kinfo_proc(pid, &kp) == -1)
|
||||
return NULL;
|
||||
|
@ -482,7 +492,7 @@ psutil_inet6_addrstr(struct in6_addr *p)
|
|||
*/
|
||||
PyObject *
|
||||
psutil_proc_connections(PyObject *self, PyObject *args) {
|
||||
long pid;
|
||||
pid_t pid;
|
||||
int i;
|
||||
int cnt;
|
||||
struct kinfo_file *freep = NULL;
|
||||
|
@ -499,17 +509,16 @@ psutil_proc_connections(PyObject *self, PyObject *args) {
|
|||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
typedef struct kinfo_proc kinfo_proc;
|
||||
|
||||
int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc);
|
||||
struct kinfo_file * kinfo_getfile(long pid, int* cnt);
|
||||
struct kinfo_file * kinfo_getfile(pid_t pid, int* cnt);
|
||||
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
|
||||
char **_psutil_get_argv(long pid);
|
||||
PyObject * psutil_get_cmdline(long pid);
|
||||
char **_psutil_get_argv(pid_t pid);
|
||||
PyObject * psutil_get_cmdline(pid_t pid);
|
||||
|
||||
//
|
||||
PyObject *psutil_proc_threads(PyObject *self, PyObject *args);
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
#include <sys/sysctl.h>
|
||||
#include <libproc.h>
|
||||
|
||||
#include "process_info.h"
|
||||
#include "../../_psutil_common.h"
|
||||
#include "../../_psutil_posix.h"
|
||||
#include "process_info.h"
|
||||
|
||||
/*
|
||||
* Returns a list of all BSD processes on the system. This routine
|
||||
|
@ -119,7 +119,7 @@ psutil_get_argmax() {
|
|||
|
||||
// Return 1 if pid refers to a zombie process else 0.
|
||||
int
|
||||
psutil_is_zombie(long pid) {
|
||||
psutil_is_zombie(pid_t pid) {
|
||||
struct kinfo_proc kp;
|
||||
|
||||
if (psutil_get_kinfo_proc(pid, &kp) == -1)
|
||||
|
@ -131,7 +131,7 @@ psutil_is_zombie(long pid) {
|
|||
|
||||
// return process args as a python list
|
||||
PyObject *
|
||||
psutil_get_cmdline(long pid) {
|
||||
psutil_get_cmdline(pid_t pid) {
|
||||
int mib[3];
|
||||
int nargs;
|
||||
size_t len;
|
||||
|
@ -162,12 +162,12 @@ psutil_get_cmdline(long pid) {
|
|||
// read argument space
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = (pid_t)pid;
|
||||
mib[2] = pid;
|
||||
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
|
||||
// In case of zombie process we'll get EINVAL. We translate it
|
||||
// to NSP and _psosx.py will translate it to ZP.
|
||||
if ((errno == EINVAL) && (psutil_pid_exists(pid)))
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl");
|
||||
else
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
|
@ -225,7 +225,7 @@ error:
|
|||
|
||||
// return process environment as a python string
|
||||
PyObject *
|
||||
psutil_get_environ(long pid) {
|
||||
psutil_get_environ(pid_t pid) {
|
||||
int mib[3];
|
||||
int nargs;
|
||||
char *procargs = NULL;
|
||||
|
@ -254,12 +254,12 @@ psutil_get_environ(long pid) {
|
|||
// read argument space
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROCARGS2;
|
||||
mib[2] = (pid_t)pid;
|
||||
mib[2] = pid;
|
||||
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
|
||||
// In case of zombie process we'll get EINVAL. We translate it
|
||||
// to NSP and _psosx.py will translate it to ZP.
|
||||
if ((errno == EINVAL) && (psutil_pid_exists(pid)))
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl");
|
||||
else
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto error;
|
||||
|
@ -339,13 +339,13 @@ error:
|
|||
|
||||
|
||||
int
|
||||
psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp) {
|
||||
psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp) {
|
||||
int mib[4];
|
||||
size_t len;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = (pid_t)pid;
|
||||
mib[3] = pid;
|
||||
|
||||
// fetch the info with sysctl()
|
||||
len = sizeof(struct kinfo_proc);
|
||||
|
@ -359,7 +359,7 @@ psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp) {
|
|||
|
||||
// sysctl succeeds but len is zero, happens when process has gone away
|
||||
if (len == 0) {
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("sysctl (len == 0)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -371,9 +371,9 @@ psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp) {
|
|||
* Returns 0 on failure (and Python exception gets already set).
|
||||
*/
|
||||
int
|
||||
psutil_proc_pidinfo(long pid, int flavor, uint64_t arg, void *pti, int size) {
|
||||
psutil_proc_pidinfo(pid_t pid, int flavor, uint64_t arg, void *pti, int size) {
|
||||
errno = 0;
|
||||
int ret = proc_pidinfo((int)pid, flavor, arg, pti, size);
|
||||
int ret = proc_pidinfo(pid, flavor, arg, pti, size);
|
||||
if ((ret <= 0) || ((unsigned long)ret < sizeof(pti))) {
|
||||
psutil_raise_for_pid(pid, "proc_pidinfo()");
|
||||
return 0;
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
typedef struct kinfo_proc kinfo_proc;
|
||||
|
||||
int psutil_get_argmax(void);
|
||||
int psutil_is_zombie(long pid);
|
||||
int psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp);
|
||||
int psutil_is_zombie(pid_t pid);
|
||||
int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp);
|
||||
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
|
||||
int psutil_proc_pidinfo(
|
||||
long pid, int flavor, uint64_t arg, void *pti, int size);
|
||||
PyObject* psutil_get_cmdline(long pid);
|
||||
PyObject* psutil_get_environ(long pid);
|
||||
pid_t pid, int flavor, uint64_t arg, void *pti, int size);
|
||||
PyObject* psutil_get_cmdline(pid_t pid);
|
||||
PyObject* psutil_get_environ(pid_t pid);
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* Functions specific for Process.environ().
|
||||
*/
|
||||
|
||||
#define NEW_MIB_COMPLIANT 1
|
||||
#define _STRUCTURED_PROC 1
|
||||
|
||||
#include <Python.h>
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
* 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>
|
||||
#include <windows.h>
|
||||
#include <PowrProf.h>
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
|
||||
|
||||
/*
|
||||
* Return the number of logical, active CPUs. Return 0 if undetermined.
|
||||
* See discussion at: https://bugs.python.org/issue33166#msg314631
|
||||
*/
|
||||
static unsigned int
|
||||
psutil_get_num_cpus(int fail_on_err) {
|
||||
unsigned int ncpus = 0;
|
||||
|
||||
// Minimum requirement: Windows 7
|
||||
if (GetActiveProcessorCount != NULL) {
|
||||
ncpus = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
|
||||
if ((ncpus == 0) && (fail_on_err == 1)) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
psutil_debug("GetActiveProcessorCount() not available; "
|
||||
"using GetSystemInfo()");
|
||||
ncpus = (unsigned int)PSUTIL_SYSTEM_INFO.dwNumberOfProcessors;
|
||||
if ((ncpus <= 0) && (fail_on_err == 1)) {
|
||||
PyErr_SetString(
|
||||
PyExc_RuntimeError,
|
||||
"GetSystemInfo() failed to retrieve CPU count");
|
||||
}
|
||||
}
|
||||
return ncpus;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Retrieves system CPU timing information as a (user, system, idle)
|
||||
* tuple. On a multiprocessor system, the values returned are the
|
||||
* sum of the designated times across all processors.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_cpu_times(PyObject *self, PyObject *args) {
|
||||
double idle, kernel, user, system;
|
||||
FILETIME idle_time, kernel_time, user_time;
|
||||
|
||||
if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idle = (double)((HI_T * idle_time.dwHighDateTime) + \
|
||||
(LO_T * idle_time.dwLowDateTime));
|
||||
user = (double)((HI_T * user_time.dwHighDateTime) + \
|
||||
(LO_T * user_time.dwLowDateTime));
|
||||
kernel = (double)((HI_T * kernel_time.dwHighDateTime) + \
|
||||
(LO_T * kernel_time.dwLowDateTime));
|
||||
|
||||
// Kernel time includes idle time.
|
||||
// We return only busy kernel time subtracting idle time from
|
||||
// kernel time.
|
||||
system = (kernel - idle);
|
||||
return Py_BuildValue("(ddd)", user, system, idle);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Same as above but for all system CPUs.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_per_cpu_times(PyObject *self, PyObject *args) {
|
||||
double idle, kernel, systemt, user, interrupt, dpc;
|
||||
NTSTATUS status;
|
||||
_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
|
||||
UINT i;
|
||||
unsigned int ncpus;
|
||||
PyObject *py_tuple = NULL;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
// retrieves number of processors
|
||||
ncpus = psutil_get_num_cpus(1);
|
||||
if (ncpus == 0)
|
||||
goto error;
|
||||
|
||||
// allocates an array of _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
|
||||
// structures, one per processor
|
||||
sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \
|
||||
malloc(ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
|
||||
if (sppi == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
|
||||
// gets cpu time informations
|
||||
status = NtQuerySystemInformation(
|
||||
SystemProcessorPerformanceInformation,
|
||||
sppi,
|
||||
ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
|
||||
NULL);
|
||||
if (! NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(
|
||||
status,
|
||||
"NtQuerySystemInformation(SystemProcessorPerformanceInformation)"
|
||||
);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// computes system global times summing each
|
||||
// processor value
|
||||
idle = user = kernel = interrupt = dpc = 0;
|
||||
for (i = 0; i < ncpus; i++) {
|
||||
py_tuple = NULL;
|
||||
user = (double)((HI_T * sppi[i].UserTime.HighPart) +
|
||||
(LO_T * sppi[i].UserTime.LowPart));
|
||||
idle = (double)((HI_T * sppi[i].IdleTime.HighPart) +
|
||||
(LO_T * sppi[i].IdleTime.LowPart));
|
||||
kernel = (double)((HI_T * sppi[i].KernelTime.HighPart) +
|
||||
(LO_T * sppi[i].KernelTime.LowPart));
|
||||
interrupt = (double)((HI_T * sppi[i].InterruptTime.HighPart) +
|
||||
(LO_T * sppi[i].InterruptTime.LowPart));
|
||||
dpc = (double)((HI_T * sppi[i].DpcTime.HighPart) +
|
||||
(LO_T * sppi[i].DpcTime.LowPart));
|
||||
|
||||
// kernel time includes idle time on windows
|
||||
// we return only busy kernel time subtracting
|
||||
// idle time from kernel time
|
||||
systemt = kernel - idle;
|
||||
py_tuple = Py_BuildValue(
|
||||
"(ddddd)",
|
||||
user,
|
||||
systemt,
|
||||
idle,
|
||||
interrupt,
|
||||
dpc
|
||||
);
|
||||
if (!py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_CLEAR(py_tuple);
|
||||
}
|
||||
|
||||
free(sppi);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_DECREF(py_retlist);
|
||||
if (sppi)
|
||||
free(sppi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the number of active, logical CPUs.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_cpu_count_logical(PyObject *self, PyObject *args) {
|
||||
unsigned int ncpus;
|
||||
|
||||
ncpus = psutil_get_num_cpus(0);
|
||||
if (ncpus != 0)
|
||||
return Py_BuildValue("I", ncpus);
|
||||
else
|
||||
Py_RETURN_NONE; // mimick os.cpu_count()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the number of physical CPU cores (hyper-thread CPUs count
|
||||
* is excluded).
|
||||
*/
|
||||
PyObject *
|
||||
psutil_cpu_count_phys(PyObject *self, PyObject *args) {
|
||||
DWORD rc;
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX buffer = NULL;
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX ptr = NULL;
|
||||
DWORD length = 0;
|
||||
DWORD offset = 0;
|
||||
DWORD ncpus = 0;
|
||||
DWORD prev_processor_info_size = 0;
|
||||
|
||||
// GetLogicalProcessorInformationEx() is available from Windows 7
|
||||
// onward. Differently from GetLogicalProcessorInformation()
|
||||
// it supports process groups, meaning this is able to report more
|
||||
// than 64 CPUs. See:
|
||||
// https://bugs.python.org/issue33166
|
||||
if (GetLogicalProcessorInformationEx == NULL) {
|
||||
psutil_debug("Win < 7; cpu_count_phys() forced to None");
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
rc = GetLogicalProcessorInformationEx(
|
||||
RelationAll, buffer, &length);
|
||||
if (rc == FALSE) {
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
buffer = \
|
||||
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)malloc(length);
|
||||
if (NULL == buffer) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
psutil_debug("GetLogicalProcessorInformationEx() returned ",
|
||||
GetLastError());
|
||||
goto return_none;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = buffer;
|
||||
while (offset < length) {
|
||||
// Advance ptr by the size of the previous
|
||||
// SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX struct.
|
||||
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) \
|
||||
(((char*)ptr) + prev_processor_info_size);
|
||||
|
||||
if (ptr->Relationship == RelationProcessorCore) {
|
||||
ncpus += 1;
|
||||
}
|
||||
|
||||
// When offset == length, we've reached the last processor
|
||||
// info struct in the buffer.
|
||||
offset += ptr->Size;
|
||||
prev_processor_info_size = ptr->Size;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
if (ncpus != 0) {
|
||||
return Py_BuildValue("I", ncpus);
|
||||
}
|
||||
else {
|
||||
psutil_debug("GetLogicalProcessorInformationEx() count was 0");
|
||||
Py_RETURN_NONE; // mimick os.cpu_count()
|
||||
}
|
||||
|
||||
return_none:
|
||||
if (buffer != NULL)
|
||||
free(buffer);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return CPU statistics.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_cpu_stats(PyObject *self, PyObject *args) {
|
||||
NTSTATUS status;
|
||||
_SYSTEM_PERFORMANCE_INFORMATION *spi = NULL;
|
||||
_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
|
||||
_SYSTEM_INTERRUPT_INFORMATION *InterruptInformation = NULL;
|
||||
unsigned int ncpus;
|
||||
UINT i;
|
||||
ULONG64 dpcs = 0;
|
||||
ULONG interrupts = 0;
|
||||
|
||||
// retrieves number of processors
|
||||
ncpus = psutil_get_num_cpus(1);
|
||||
if (ncpus == 0)
|
||||
goto error;
|
||||
|
||||
// get syscalls / ctx switches
|
||||
spi = (_SYSTEM_PERFORMANCE_INFORMATION *) \
|
||||
malloc(ncpus * sizeof(_SYSTEM_PERFORMANCE_INFORMATION));
|
||||
if (spi == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
status = NtQuerySystemInformation(
|
||||
SystemPerformanceInformation,
|
||||
spi,
|
||||
ncpus * sizeof(_SYSTEM_PERFORMANCE_INFORMATION),
|
||||
NULL);
|
||||
if (! NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(
|
||||
status, "NtQuerySystemInformation(SystemPerformanceInformation)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// get DPCs
|
||||
InterruptInformation = \
|
||||
malloc(sizeof(_SYSTEM_INTERRUPT_INFORMATION) * ncpus);
|
||||
if (InterruptInformation == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
|
||||
status = NtQuerySystemInformation(
|
||||
SystemInterruptInformation,
|
||||
InterruptInformation,
|
||||
ncpus * sizeof(SYSTEM_INTERRUPT_INFORMATION),
|
||||
NULL);
|
||||
if (! NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(
|
||||
status, "NtQuerySystemInformation(SystemInterruptInformation)");
|
||||
goto error;
|
||||
}
|
||||
for (i = 0; i < ncpus; i++) {
|
||||
dpcs += InterruptInformation[i].DpcCount;
|
||||
}
|
||||
|
||||
// get interrupts
|
||||
sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \
|
||||
malloc(ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
|
||||
if (sppi == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
|
||||
status = NtQuerySystemInformation(
|
||||
SystemProcessorPerformanceInformation,
|
||||
sppi,
|
||||
ncpus * sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
|
||||
NULL);
|
||||
if (! NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(
|
||||
status,
|
||||
"NtQuerySystemInformation(SystemProcessorPerformanceInformation)");
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < ncpus; i++) {
|
||||
interrupts += sppi[i].InterruptCount;
|
||||
}
|
||||
|
||||
// done
|
||||
free(spi);
|
||||
free(InterruptInformation);
|
||||
free(sppi);
|
||||
return Py_BuildValue(
|
||||
"kkkk",
|
||||
spi->ContextSwitches,
|
||||
interrupts,
|
||||
(unsigned long)dpcs,
|
||||
spi->SystemCalls
|
||||
);
|
||||
|
||||
error:
|
||||
if (spi)
|
||||
free(spi);
|
||||
if (InterruptInformation)
|
||||
free(InterruptInformation);
|
||||
if (sppi)
|
||||
free(sppi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return CPU frequency.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_cpu_freq(PyObject *self, PyObject *args) {
|
||||
PROCESSOR_POWER_INFORMATION *ppi;
|
||||
NTSTATUS ret;
|
||||
ULONG size;
|
||||
LPBYTE pBuffer = NULL;
|
||||
ULONG current;
|
||||
ULONG max;
|
||||
unsigned int ncpus;
|
||||
|
||||
// Get the number of CPUs.
|
||||
ncpus = psutil_get_num_cpus(1);
|
||||
if (ncpus == 0)
|
||||
return NULL;
|
||||
|
||||
// Allocate size.
|
||||
size = ncpus * sizeof(PROCESSOR_POWER_INFORMATION);
|
||||
pBuffer = (BYTE*)LocalAlloc(LPTR, size);
|
||||
if (! pBuffer) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Syscall.
|
||||
ret = CallNtPowerInformation(
|
||||
ProcessorInformation, NULL, 0, pBuffer, size);
|
||||
if (ret != 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"CallNtPowerInformation syscall failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Results.
|
||||
ppi = (PROCESSOR_POWER_INFORMATION *)pBuffer;
|
||||
max = ppi->MaxMhz;
|
||||
current = ppi->CurrentMhz;
|
||||
LocalFree(pBuffer);
|
||||
|
||||
return Py_BuildValue("kk", current, max);
|
||||
|
||||
error:
|
||||
if (pBuffer != NULL)
|
||||
LocalFree(pBuffer);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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_cpu_count_logical(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_cpu_count_phys(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_cpu_freq(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_cpu_stats(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_cpu_times(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args);
|
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
* 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>
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
|
||||
|
||||
#ifndef _ARRAYSIZE
|
||||
#define _ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
static char *psutil_get_drive_type(int type) {
|
||||
switch (type) {
|
||||
case DRIVE_FIXED:
|
||||
return "fixed";
|
||||
case DRIVE_CDROM:
|
||||
return "cdrom";
|
||||
case DRIVE_REMOVABLE:
|
||||
return "removable";
|
||||
case DRIVE_UNKNOWN:
|
||||
return "unknown";
|
||||
case DRIVE_NO_ROOT_DIR:
|
||||
return "unmounted";
|
||||
case DRIVE_REMOTE:
|
||||
return "remote";
|
||||
case DRIVE_RAMDISK:
|
||||
return "ramdisk";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return path's disk total and free as a Python tuple.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_disk_usage(PyObject *self, PyObject *args) {
|
||||
BOOL retval;
|
||||
ULARGE_INTEGER _, total, free;
|
||||
char *path;
|
||||
|
||||
if (PyArg_ParseTuple(args, "u", &path)) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
retval = GetDiskFreeSpaceExW((LPCWSTR)path, &_, &total, &free);
|
||||
Py_END_ALLOW_THREADS
|
||||
goto return_;
|
||||
}
|
||||
|
||||
// on Python 2 we also want to accept plain strings other
|
||||
// than Unicode
|
||||
#if PY_MAJOR_VERSION <= 2
|
||||
PyErr_Clear(); // drop the argument parsing error
|
||||
if (PyArg_ParseTuple(args, "s", &path)) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
retval = GetDiskFreeSpaceEx(path, &_, &total, &free);
|
||||
Py_END_ALLOW_THREADS
|
||||
goto return_;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
||||
return_:
|
||||
if (retval == 0)
|
||||
return PyErr_SetFromWindowsErrWithFilename(0, path);
|
||||
else
|
||||
return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a Python dict of tuples for disk I/O information. This may
|
||||
* require running "diskperf -y" command first.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_disk_io_counters(PyObject *self, PyObject *args) {
|
||||
DISK_PERFORMANCE diskPerformance;
|
||||
DWORD dwSize;
|
||||
HANDLE hDevice = NULL;
|
||||
char szDevice[MAX_PATH];
|
||||
char szDeviceDisplay[MAX_PATH];
|
||||
int devNum;
|
||||
int i;
|
||||
DWORD ioctrlSize;
|
||||
BOOL ret;
|
||||
PyObject *py_retdict = PyDict_New();
|
||||
PyObject *py_tuple = NULL;
|
||||
|
||||
if (py_retdict == NULL)
|
||||
return NULL;
|
||||
// Apparently there's no way to figure out how many times we have
|
||||
// to iterate in order to find valid drives.
|
||||
// Let's assume 32, which is higher than 26, the number of letters
|
||||
// in the alphabet (from A:\ to Z:\).
|
||||
for (devNum = 0; devNum <= 32; ++devNum) {
|
||||
py_tuple = NULL;
|
||||
sprintf_s(szDevice, MAX_PATH, "\\\\.\\PhysicalDrive%d", devNum);
|
||||
hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hDevice == INVALID_HANDLE_VALUE)
|
||||
continue;
|
||||
|
||||
// DeviceIoControl() sucks!
|
||||
i = 0;
|
||||
ioctrlSize = sizeof(diskPerformance);
|
||||
while (1) {
|
||||
i += 1;
|
||||
ret = DeviceIoControl(
|
||||
hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &diskPerformance,
|
||||
ioctrlSize, &dwSize, NULL);
|
||||
if (ret != 0)
|
||||
break; // OK!
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
// Retry with a bigger buffer (+ limit for retries).
|
||||
if (i <= 1024) {
|
||||
ioctrlSize *= 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (GetLastError() == ERROR_INVALID_FUNCTION) {
|
||||
// This happens on AppVeyor:
|
||||
// https://ci.appveyor.com/project/giampaolo/psutil/build/
|
||||
// 1364/job/ascpdi271b06jle3
|
||||
// Assume it means we're dealing with some exotic disk
|
||||
// and go on.
|
||||
psutil_debug("DeviceIoControl -> ERROR_INVALID_FUNCTION; "
|
||||
"ignore PhysicalDrive%i", devNum);
|
||||
goto next;
|
||||
}
|
||||
else if (GetLastError() == ERROR_NOT_SUPPORTED) {
|
||||
// Again, let's assume we're dealing with some exotic disk.
|
||||
psutil_debug("DeviceIoControl -> ERROR_NOT_SUPPORTED; "
|
||||
"ignore PhysicalDrive%i", devNum);
|
||||
goto next;
|
||||
}
|
||||
// XXX: it seems we should also catch ERROR_INVALID_PARAMETER:
|
||||
// https://sites.ualberta.ca/dept/aict/uts/software/openbsd/
|
||||
// ports/4.1/i386/openafs/w-openafs-1.4.14-transarc/
|
||||
// openafs-1.4.14/src/usd/usd_nt.c
|
||||
|
||||
// XXX: we can also bump into ERROR_MORE_DATA in which case
|
||||
// (quoting doc) we're supposed to retry with a bigger buffer
|
||||
// and specify a new "starting point", whatever it means.
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
sprintf_s(szDeviceDisplay, MAX_PATH, "PhysicalDrive%i", devNum);
|
||||
py_tuple = Py_BuildValue(
|
||||
"(IILLKK)",
|
||||
diskPerformance.ReadCount,
|
||||
diskPerformance.WriteCount,
|
||||
diskPerformance.BytesRead,
|
||||
diskPerformance.BytesWritten,
|
||||
// convert to ms:
|
||||
// https://github.com/giampaolo/psutil/issues/1012
|
||||
(unsigned long long)
|
||||
(diskPerformance.ReadTime.QuadPart) / 10000000,
|
||||
(unsigned long long)
|
||||
(diskPerformance.WriteTime.QuadPart) / 10000000);
|
||||
if (!py_tuple)
|
||||
goto error;
|
||||
if (PyDict_SetItemString(py_retdict, szDeviceDisplay, py_tuple))
|
||||
goto error;
|
||||
Py_CLEAR(py_tuple);
|
||||
|
||||
next:
|
||||
CloseHandle(hDevice);
|
||||
}
|
||||
|
||||
return py_retdict;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_DECREF(py_retdict);
|
||||
if (hDevice != NULL)
|
||||
CloseHandle(hDevice);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return disk partitions as a list of tuples such as
|
||||
* (drive_letter, drive_letter, type, "")
|
||||
*/
|
||||
PyObject *
|
||||
psutil_disk_partitions(PyObject *self, PyObject *args) {
|
||||
DWORD num_bytes;
|
||||
char drive_strings[255];
|
||||
char *drive_letter = drive_strings;
|
||||
char mp_buf[MAX_PATH];
|
||||
char mp_path[MAX_PATH];
|
||||
int all;
|
||||
int type;
|
||||
int ret;
|
||||
unsigned int old_mode = 0;
|
||||
char opts[20];
|
||||
HANDLE mp_h;
|
||||
BOOL mp_flag= TRUE;
|
||||
LPTSTR fs_type[MAX_PATH + 1] = { 0 };
|
||||
DWORD pflags = 0;
|
||||
PyObject *py_all;
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
PyObject *py_tuple = NULL;
|
||||
|
||||
if (py_retlist == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// avoid to visualize a message box in case something goes wrong
|
||||
// see https://github.com/giampaolo/psutil/issues/264
|
||||
old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
|
||||
if (! PyArg_ParseTuple(args, "O", &py_all))
|
||||
goto error;
|
||||
all = PyObject_IsTrue(py_all);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
num_bytes = GetLogicalDriveStrings(254, drive_letter);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (num_bytes == 0) {
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (*drive_letter != 0) {
|
||||
py_tuple = NULL;
|
||||
opts[0] = 0;
|
||||
fs_type[0] = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
type = GetDriveType(drive_letter);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
// by default we only show hard drives and cd-roms
|
||||
if (all == 0) {
|
||||
if ((type == DRIVE_UNKNOWN) ||
|
||||
(type == DRIVE_NO_ROOT_DIR) ||
|
||||
(type == DRIVE_REMOTE) ||
|
||||
(type == DRIVE_RAMDISK)) {
|
||||
goto next;
|
||||
}
|
||||
// floppy disk: skip it by default as it introduces a
|
||||
// considerable slowdown.
|
||||
if ((type == DRIVE_REMOVABLE) &&
|
||||
(strcmp(drive_letter, "A:\\") == 0)) {
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
ret = GetVolumeInformation(
|
||||
(LPCTSTR)drive_letter, NULL, _ARRAYSIZE(drive_letter),
|
||||
NULL, NULL, &pflags, (LPTSTR)fs_type, _ARRAYSIZE(fs_type));
|
||||
if (ret == 0) {
|
||||
// We might get here in case of a floppy hard drive, in
|
||||
// which case the error is (21, "device not ready").
|
||||
// Let's pretend it didn't happen as we already have
|
||||
// the drive name and type ('removable').
|
||||
strcat_s(opts, _countof(opts), "");
|
||||
SetLastError(0);
|
||||
}
|
||||
else {
|
||||
if (pflags & FILE_READ_ONLY_VOLUME)
|
||||
strcat_s(opts, _countof(opts), "ro");
|
||||
else
|
||||
strcat_s(opts, _countof(opts), "rw");
|
||||
if (pflags & FILE_VOLUME_IS_COMPRESSED)
|
||||
strcat_s(opts, _countof(opts), ",compressed");
|
||||
|
||||
// Check for mount points on this volume and add/get info
|
||||
// (checks first to know if we can even have mount points)
|
||||
if (pflags & FILE_SUPPORTS_REPARSE_POINTS) {
|
||||
mp_h = FindFirstVolumeMountPoint(
|
||||
drive_letter, mp_buf, MAX_PATH);
|
||||
if (mp_h != INVALID_HANDLE_VALUE) {
|
||||
while (mp_flag) {
|
||||
|
||||
// Append full mount path with drive letter
|
||||
strcpy_s(mp_path, _countof(mp_path), drive_letter);
|
||||
strcat_s(mp_path, _countof(mp_path), mp_buf);
|
||||
|
||||
py_tuple = Py_BuildValue(
|
||||
"(ssss)",
|
||||
drive_letter,
|
||||
mp_path,
|
||||
fs_type, // Typically NTFS
|
||||
opts);
|
||||
|
||||
if (!py_tuple ||
|
||||
PyList_Append(py_retlist, py_tuple) == -1) {
|
||||
FindVolumeMountPointClose(mp_h);
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_CLEAR(py_tuple);
|
||||
|
||||
// Continue looking for more mount points
|
||||
mp_flag = FindNextVolumeMountPoint(
|
||||
mp_h, mp_buf, MAX_PATH);
|
||||
}
|
||||
FindVolumeMountPointClose(mp_h);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(opts) > 0)
|
||||
strcat_s(opts, _countof(opts), ",");
|
||||
strcat_s(opts, _countof(opts), psutil_get_drive_type(type));
|
||||
|
||||
py_tuple = Py_BuildValue(
|
||||
"(ssss)",
|
||||
drive_letter,
|
||||
drive_letter,
|
||||
fs_type, // either FAT, FAT32, NTFS, HPFS, CDFS, UDF or NWFS
|
||||
opts);
|
||||
if (!py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_CLEAR(py_tuple);
|
||||
goto next;
|
||||
|
||||
next:
|
||||
drive_letter = strchr(drive_letter, 0) + 1;
|
||||
}
|
||||
|
||||
SetErrorMode(old_mode);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
SetErrorMode(old_mode);
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_DECREF(py_retlist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Accept a filename's drive in native format like "\Device\HarddiskVolume1\"
|
||||
and return the corresponding drive letter (e.g. "C:\\").
|
||||
If no match is found return an empty string.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_win32_QueryDosDevice(PyObject *self, PyObject *args) {
|
||||
LPCTSTR lpDevicePath;
|
||||
TCHAR d = TEXT('A');
|
||||
TCHAR szBuff[5];
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &lpDevicePath))
|
||||
return NULL;
|
||||
|
||||
while (d <= TEXT('Z')) {
|
||||
TCHAR szDeviceName[3] = {d, TEXT(':'), TEXT('\0')};
|
||||
TCHAR szTarget[512] = {0};
|
||||
if (QueryDosDevice(szDeviceName, szTarget, 511) != 0) {
|
||||
if (_tcscmp(lpDevicePath, szTarget) == 0) {
|
||||
_stprintf_s(szBuff, _countof(szBuff), TEXT("%c:"), d);
|
||||
return Py_BuildValue("s", szBuff);
|
||||
}
|
||||
}
|
||||
d++;
|
||||
}
|
||||
return Py_BuildValue("s", "");
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
PyObject *psutil_disk_io_counters(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_disk_partitions(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_disk_usage(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_win32_QueryDosDevice(PyObject *self, PyObject *args);
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* This code is executed on import. It loads private/undocumented
|
||||
* Windows APIs and sets Windows version constants so that they are
|
||||
* available globally.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <Python.h>
|
||||
#include "ntextapi.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
// Needed to make these globally visible.
|
||||
int PSUTIL_WINVER;
|
||||
SYSTEM_INFO PSUTIL_SYSTEM_INFO;
|
||||
|
||||
#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 = psutil_RtlNtStatusToDosErrorNoTeb(Status);
|
||||
// if (GetLastError() != 0)
|
||||
// err = GetLastError();
|
||||
sprintf(fullmsg, "(originated from %s)", syscall);
|
||||
return PyErr_SetFromWindowsErrWithFilename(err, fullmsg);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
psutil_loadlibs() {
|
||||
/*
|
||||
* Mandatory.
|
||||
*/
|
||||
psutil_NtQuerySystemInformation = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "NtQuerySystemInformation");
|
||||
if (psutil_NtQuerySystemInformation == NULL)
|
||||
return 1;
|
||||
|
||||
psutil_NtQueryInformationProcess = psutil_GetProcAddress(
|
||||
"ntdll.dll", "NtQueryInformationProcess");
|
||||
if (! psutil_NtQueryInformationProcess)
|
||||
return 1;
|
||||
|
||||
psutil_NtSetInformationProcess = psutil_GetProcAddress(
|
||||
"ntdll.dll", "NtSetInformationProcess");
|
||||
if (! psutil_NtSetInformationProcess)
|
||||
return 1;
|
||||
|
||||
psutil_WinStationQueryInformationW = psutil_GetProcAddressFromLib(
|
||||
"winsta.dll", "WinStationQueryInformationW");
|
||||
if (! psutil_WinStationQueryInformationW)
|
||||
return 1;
|
||||
|
||||
psutil_NtQueryObject = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "NtQueryObject");
|
||||
if (! psutil_NtQueryObject)
|
||||
return 1;
|
||||
|
||||
psutil_rtlIpv4AddressToStringA = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "RtlIpv4AddressToStringA");
|
||||
if (! psutil_rtlIpv4AddressToStringA)
|
||||
return 1;
|
||||
|
||||
// minimum requirement: Win XP SP3
|
||||
psutil_GetExtendedTcpTable = psutil_GetProcAddressFromLib(
|
||||
"iphlpapi.dll", "GetExtendedTcpTable");
|
||||
if (! psutil_GetExtendedTcpTable)
|
||||
return 1;
|
||||
|
||||
// minimum requirement: Win XP SP3
|
||||
psutil_GetExtendedUdpTable = psutil_GetProcAddressFromLib(
|
||||
"iphlpapi.dll", "GetExtendedUdpTable");
|
||||
if (! psutil_GetExtendedUdpTable)
|
||||
return 1;
|
||||
|
||||
psutil_RtlGetVersion = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "RtlGetVersion");
|
||||
if (! psutil_RtlGetVersion)
|
||||
return 1;
|
||||
|
||||
psutil_NtSuspendProcess = psutil_GetProcAddressFromLib(
|
||||
"ntdll", "NtSuspendProcess");
|
||||
if (! psutil_NtSuspendProcess)
|
||||
return 1;
|
||||
|
||||
psutil_NtResumeProcess = psutil_GetProcAddressFromLib(
|
||||
"ntdll", "NtResumeProcess");
|
||||
if (! psutil_NtResumeProcess)
|
||||
return 1;
|
||||
|
||||
psutil_NtQueryVirtualMemory = psutil_GetProcAddressFromLib(
|
||||
"ntdll", "NtQueryVirtualMemory");
|
||||
if (! psutil_NtQueryVirtualMemory)
|
||||
return 1;
|
||||
|
||||
psutil_RtlNtStatusToDosErrorNoTeb = psutil_GetProcAddressFromLib(
|
||||
"ntdll", "RtlNtStatusToDosErrorNoTeb");
|
||||
if (! psutil_RtlNtStatusToDosErrorNoTeb)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Optional.
|
||||
*/
|
||||
// not available on Wine
|
||||
psutil_rtlIpv6AddressToStringA = psutil_GetProcAddressFromLib(
|
||||
"ntdll.dll", "RtlIpv6AddressToStringA");
|
||||
|
||||
// minimum requirement: Win Vista
|
||||
psutil_GetTickCount64 = psutil_GetProcAddress(
|
||||
"kernel32", "GetTickCount64");
|
||||
|
||||
// minimum requirement: Win 7
|
||||
psutil_GetActiveProcessorCount = psutil_GetProcAddress(
|
||||
"kernel32", "GetActiveProcessorCount");
|
||||
|
||||
// minumum requirement: Win 7
|
||||
psutil_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));
|
||||
psutil_RtlGetVersion((PRTL_OSVERSIONINFOW)&versionInfo);
|
||||
maj = versionInfo.dwMajorVersion;
|
||||
min = versionInfo.dwMinorVersion;
|
||||
if (maj == 5 && min == 1)
|
||||
PSUTIL_WINVER = PSUTIL_WINDOWS_XP;
|
||||
else if (maj == 5 && min == 2)
|
||||
PSUTIL_WINVER = PSUTIL_WINDOWS_SERVER_2003;
|
||||
else 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;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
psutil_load_sysinfo() {
|
||||
GetSystemInfo(&PSUTIL_SYSTEM_INFO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_load_globals() {
|
||||
if (psutil_loadlibs() != 0)
|
||||
return 1;
|
||||
if (psutil_set_winver() != 0)
|
||||
return 1;
|
||||
if (psutil_load_sysinfo() != 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
|
||||
* List of constants and objects that are globally available.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "ntextapi.h"
|
||||
|
||||
extern int PSUTIL_WINVER;
|
||||
extern SYSTEM_INFO PSUTIL_SYSTEM_INFO;
|
||||
#define PSUTIL_WINDOWS_XP 51
|
||||
#define PSUTIL_WINDOWS_SERVER_2003 52
|
||||
#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
|
||||
|
||||
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);
|
||||
|
||||
_NtQuerySystemInformation \
|
||||
psutil_NtQuerySystemInformation;
|
||||
|
||||
_NtQueryInformationProcess \
|
||||
psutil_NtQueryInformationProcess;
|
||||
|
||||
_NtSetInformationProcess
|
||||
psutil_NtSetInformationProcess;
|
||||
|
||||
_WinStationQueryInformationW \
|
||||
psutil_WinStationQueryInformationW;
|
||||
|
||||
_RtlIpv4AddressToStringA \
|
||||
psutil_rtlIpv4AddressToStringA;
|
||||
|
||||
_RtlIpv6AddressToStringA \
|
||||
psutil_rtlIpv6AddressToStringA;
|
||||
|
||||
_GetExtendedTcpTable \
|
||||
psutil_GetExtendedTcpTable;
|
||||
|
||||
_GetExtendedUdpTable \
|
||||
psutil_GetExtendedUdpTable;
|
||||
|
||||
_GetActiveProcessorCount \
|
||||
psutil_GetActiveProcessorCount;
|
||||
|
||||
_GetTickCount64 \
|
||||
psutil_GetTickCount64;
|
||||
|
||||
_NtQueryObject \
|
||||
psutil_NtQueryObject;
|
||||
|
||||
_GetLogicalProcessorInformationEx \
|
||||
psutil_GetLogicalProcessorInformationEx;
|
||||
|
||||
_RtlGetVersion \
|
||||
psutil_RtlGetVersion;
|
||||
|
||||
_NtSuspendProcess \
|
||||
psutil_NtSuspendProcess;
|
||||
|
||||
_NtResumeProcess \
|
||||
psutil_NtResumeProcess;
|
||||
|
||||
_NtQueryVirtualMemory \
|
||||
psutil_NtQueryVirtualMemory;
|
||||
|
||||
_RtlNtStatusToDosErrorNoTeb \
|
||||
psutil_RtlNtStatusToDosErrorNoTeb;
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola', Jeff Tang. 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 "inet_ntop.h"
|
||||
|
||||
// From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/
|
||||
PCSTR WSAAPI
|
||||
inet_ntop(INT family, PVOID pAddr, PSTR stringBuf, size_t strBufSize) {
|
||||
DWORD dwAddressLength = 0;
|
||||
struct sockaddr_storage srcaddr;
|
||||
struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr;
|
||||
struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr;
|
||||
|
||||
memset(&srcaddr, 0, sizeof(struct sockaddr_storage));
|
||||
srcaddr.ss_family = family;
|
||||
|
||||
if (family == AF_INET) {
|
||||
dwAddressLength = sizeof(struct sockaddr_in);
|
||||
memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr));
|
||||
}
|
||||
else if (family == AF_INET6) {
|
||||
dwAddressLength = sizeof(struct sockaddr_in6);
|
||||
memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr));
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_ValueError, "invalid family");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (WSAAddressToStringA(
|
||||
(LPSOCKADDR) &srcaddr,
|
||||
dwAddressLength,
|
||||
0,
|
||||
stringBuf,
|
||||
(LPDWORD) &strBufSize) != 0)
|
||||
{
|
||||
PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
|
||||
return NULL;
|
||||
}
|
||||
return stringBuf;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Giampaolo Rodola', Jeff Tang. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
// because of WSAAddressToStringA
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
PCSTR WSAAPI
|
||||
inet_ntop(
|
||||
__in INT Family,
|
||||
__in const VOID * pAddr,
|
||||
__out_ecount(StringBufSize) PSTR pStringBuf,
|
||||
__in size_t StringBufSize
|
||||
);
|
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Fixes clash between winsock2.h and windows.h
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
#include <wchar.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
|
||||
|
||||
static PIP_ADAPTER_ADDRESSES
|
||||
psutil_get_nic_addresses() {
|
||||
// allocate a 15 KB buffer to start with
|
||||
int outBufLen = 15000;
|
||||
DWORD dwRetVal = 0;
|
||||
ULONG attempts = 0;
|
||||
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
||||
|
||||
do {
|
||||
pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
|
||||
if (pAddresses == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dwRetVal = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, pAddresses,
|
||||
&outBufLen);
|
||||
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
|
||||
free(pAddresses);
|
||||
pAddresses = NULL;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
|
||||
attempts++;
|
||||
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (attempts < 3));
|
||||
|
||||
if (dwRetVal != NO_ERROR) {
|
||||
PyErr_SetString(
|
||||
PyExc_RuntimeError, "GetAdaptersAddresses() syscall failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pAddresses;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a Python list of named tuples with overall network I/O information
|
||||
*/
|
||||
PyObject *
|
||||
psutil_net_io_counters(PyObject *self, PyObject *args) {
|
||||
DWORD dwRetVal = 0;
|
||||
MIB_IF_ROW2 *pIfRow = NULL;
|
||||
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
|
||||
PyObject *py_retdict = PyDict_New();
|
||||
PyObject *py_nic_info = NULL;
|
||||
PyObject *py_nic_name = NULL;
|
||||
|
||||
if (py_retdict == NULL)
|
||||
return NULL;
|
||||
pAddresses = psutil_get_nic_addresses();
|
||||
if (pAddresses == NULL)
|
||||
goto error;
|
||||
pCurrAddresses = pAddresses;
|
||||
|
||||
while (pCurrAddresses) {
|
||||
py_nic_name = NULL;
|
||||
py_nic_info = NULL;
|
||||
|
||||
pIfRow = (MIB_IF_ROW2 *) malloc(sizeof(MIB_IF_ROW2));
|
||||
if (pIfRow == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
|
||||
SecureZeroMemory((PVOID)pIfRow, sizeof(MIB_IF_ROW2));
|
||||
pIfRow->InterfaceIndex = pCurrAddresses->IfIndex;
|
||||
dwRetVal = GetIfEntry2(pIfRow);
|
||||
if (dwRetVal != NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"GetIfEntry() or GetIfEntry2() syscalls failed.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
py_nic_info = Py_BuildValue(
|
||||
"(KKKKKKKK)",
|
||||
pIfRow->OutOctets,
|
||||
pIfRow->InOctets,
|
||||
(pIfRow->OutUcastPkts + pIfRow->OutNUcastPkts),
|
||||
(pIfRow->InUcastPkts + pIfRow->InNUcastPkts),
|
||||
pIfRow->InErrors,
|
||||
pIfRow->OutErrors,
|
||||
pIfRow->InDiscards,
|
||||
pIfRow->OutDiscards);
|
||||
if (!py_nic_info)
|
||||
goto error;
|
||||
|
||||
py_nic_name = PyUnicode_FromWideChar(
|
||||
pCurrAddresses->FriendlyName,
|
||||
wcslen(pCurrAddresses->FriendlyName));
|
||||
|
||||
if (py_nic_name == NULL)
|
||||
goto error;
|
||||
if (PyDict_SetItem(py_retdict, py_nic_name, py_nic_info))
|
||||
goto error;
|
||||
Py_CLEAR(py_nic_name);
|
||||
Py_CLEAR(py_nic_info);
|
||||
|
||||
free(pIfRow);
|
||||
pCurrAddresses = pCurrAddresses->Next;
|
||||
}
|
||||
|
||||
free(pAddresses);
|
||||
return py_retdict;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_nic_name);
|
||||
Py_XDECREF(py_nic_info);
|
||||
Py_DECREF(py_retdict);
|
||||
if (pAddresses != NULL)
|
||||
free(pAddresses);
|
||||
if (pIfRow != NULL)
|
||||
free(pIfRow);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return NICs addresses.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_net_if_addrs(PyObject *self, PyObject *args) {
|
||||
unsigned int i = 0;
|
||||
ULONG family;
|
||||
PCTSTR intRet;
|
||||
PCTSTR netmaskIntRet;
|
||||
char *ptr;
|
||||
char buff_addr[1024];
|
||||
char buff_macaddr[1024];
|
||||
char buff_netmask[1024];
|
||||
DWORD dwRetVal = 0;
|
||||
ULONG converted_netmask;
|
||||
UINT netmask_bits;
|
||||
struct in_addr in_netmask;
|
||||
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
|
||||
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
|
||||
|
||||
PyObject *py_retlist = PyList_New(0);
|
||||
PyObject *py_tuple = NULL;
|
||||
PyObject *py_address = NULL;
|
||||
PyObject *py_mac_address = NULL;
|
||||
PyObject *py_nic_name = NULL;
|
||||
PyObject *py_netmask = NULL;
|
||||
|
||||
if (py_retlist == NULL)
|
||||
return NULL;
|
||||
|
||||
pAddresses = psutil_get_nic_addresses();
|
||||
if (pAddresses == NULL)
|
||||
goto error;
|
||||
pCurrAddresses = pAddresses;
|
||||
|
||||
while (pCurrAddresses) {
|
||||
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
||||
|
||||
netmaskIntRet = NULL;
|
||||
py_nic_name = NULL;
|
||||
py_nic_name = PyUnicode_FromWideChar(
|
||||
pCurrAddresses->FriendlyName,
|
||||
wcslen(pCurrAddresses->FriendlyName));
|
||||
if (py_nic_name == NULL)
|
||||
goto error;
|
||||
|
||||
// MAC address
|
||||
if (pCurrAddresses->PhysicalAddressLength != 0) {
|
||||
ptr = buff_macaddr;
|
||||
*ptr = '\0';
|
||||
for (i = 0; i < (int) pCurrAddresses->PhysicalAddressLength; i++) {
|
||||
if (i == (pCurrAddresses->PhysicalAddressLength - 1)) {
|
||||
sprintf_s(ptr, _countof(buff_macaddr), "%.2X\n",
|
||||
(int)pCurrAddresses->PhysicalAddress[i]);
|
||||
}
|
||||
else {
|
||||
sprintf_s(ptr, _countof(buff_macaddr), "%.2X-",
|
||||
(int)pCurrAddresses->PhysicalAddress[i]);
|
||||
}
|
||||
ptr += 3;
|
||||
}
|
||||
*--ptr = '\0';
|
||||
|
||||
py_mac_address = Py_BuildValue("s", buff_macaddr);
|
||||
if (py_mac_address == NULL)
|
||||
goto error;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
Py_INCREF(Py_None);
|
||||
Py_INCREF(Py_None);
|
||||
py_tuple = Py_BuildValue(
|
||||
"(OiOOOO)",
|
||||
py_nic_name,
|
||||
-1, // this will be converted later to AF_LINK
|
||||
py_mac_address,
|
||||
Py_None, // netmask (not supported)
|
||||
Py_None, // broadcast (not supported)
|
||||
Py_None // ptp (not supported on Windows)
|
||||
);
|
||||
if (! py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_CLEAR(py_tuple);
|
||||
Py_CLEAR(py_mac_address);
|
||||
}
|
||||
|
||||
// find out the IP address associated with the NIC
|
||||
if (pUnicast != NULL) {
|
||||
for (i = 0; pUnicast != NULL; i++) {
|
||||
family = pUnicast->Address.lpSockaddr->sa_family;
|
||||
if (family == AF_INET) {
|
||||
struct sockaddr_in *sa_in = (struct sockaddr_in *)
|
||||
pUnicast->Address.lpSockaddr;
|
||||
intRet = inet_ntop(AF_INET, &(sa_in->sin_addr), buff_addr,
|
||||
sizeof(buff_addr));
|
||||
if (!intRet)
|
||||
goto error;
|
||||
netmask_bits = pUnicast->OnLinkPrefixLength;
|
||||
dwRetVal = ConvertLengthToIpv4Mask(
|
||||
netmask_bits, &converted_netmask);
|
||||
if (dwRetVal == NO_ERROR) {
|
||||
in_netmask.s_addr = converted_netmask;
|
||||
netmaskIntRet = inet_ntop(
|
||||
AF_INET, &in_netmask, buff_netmask,
|
||||
sizeof(buff_netmask));
|
||||
if (!netmaskIntRet)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (family == AF_INET6) {
|
||||
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)
|
||||
pUnicast->Address.lpSockaddr;
|
||||
intRet = inet_ntop(AF_INET6, &(sa_in6->sin6_addr),
|
||||
buff_addr, sizeof(buff_addr));
|
||||
if (!intRet)
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
// we should never get here
|
||||
pUnicast = pUnicast->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
py_address = PyUnicode_FromString(buff_addr);
|
||||
#else
|
||||
py_address = PyString_FromString(buff_addr);
|
||||
#endif
|
||||
if (py_address == NULL)
|
||||
goto error;
|
||||
|
||||
if (netmaskIntRet != NULL) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
py_netmask = PyUnicode_FromString(buff_netmask);
|
||||
#else
|
||||
py_netmask = PyString_FromString(buff_netmask);
|
||||
#endif
|
||||
} else {
|
||||
Py_INCREF(Py_None);
|
||||
py_netmask = Py_None;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
Py_INCREF(Py_None);
|
||||
py_tuple = Py_BuildValue(
|
||||
"(OiOOOO)",
|
||||
py_nic_name,
|
||||
family,
|
||||
py_address,
|
||||
py_netmask,
|
||||
Py_None, // broadcast (not supported)
|
||||
Py_None // ptp (not supported on Windows)
|
||||
);
|
||||
|
||||
if (! py_tuple)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_tuple))
|
||||
goto error;
|
||||
Py_CLEAR(py_tuple);
|
||||
Py_CLEAR(py_address);
|
||||
Py_CLEAR(py_netmask);
|
||||
|
||||
pUnicast = pUnicast->Next;
|
||||
}
|
||||
}
|
||||
Py_CLEAR(py_nic_name);
|
||||
pCurrAddresses = pCurrAddresses->Next;
|
||||
}
|
||||
|
||||
free(pAddresses);
|
||||
return py_retlist;
|
||||
|
||||
error:
|
||||
if (pAddresses)
|
||||
free(pAddresses);
|
||||
Py_DECREF(py_retlist);
|
||||
Py_XDECREF(py_tuple);
|
||||
Py_XDECREF(py_address);
|
||||
Py_XDECREF(py_nic_name);
|
||||
Py_XDECREF(py_netmask);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Provides stats about NIC interfaces installed on the system.
|
||||
* TODO: get 'duplex' (currently it's hard coded to '2', aka
|
||||
'full duplex')
|
||||
*/
|
||||
PyObject *
|
||||
psutil_net_if_stats(PyObject *self, PyObject *args) {
|
||||
int i;
|
||||
DWORD dwSize = 0;
|
||||
DWORD dwRetVal = 0;
|
||||
MIB_IFTABLE *pIfTable;
|
||||
MIB_IFROW *pIfRow;
|
||||
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
||||
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
|
||||
char descr[MAX_PATH];
|
||||
int ifname_found;
|
||||
|
||||
PyObject *py_nic_name = NULL;
|
||||
PyObject *py_retdict = PyDict_New();
|
||||
PyObject *py_ifc_info = NULL;
|
||||
PyObject *py_is_up = NULL;
|
||||
|
||||
if (py_retdict == NULL)
|
||||
return NULL;
|
||||
|
||||
pAddresses = psutil_get_nic_addresses();
|
||||
if (pAddresses == NULL)
|
||||
goto error;
|
||||
|
||||
pIfTable = (MIB_IFTABLE *) malloc(sizeof (MIB_IFTABLE));
|
||||
if (pIfTable == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
dwSize = sizeof(MIB_IFTABLE);
|
||||
if (GetIfTable(pIfTable, &dwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
free(pIfTable);
|
||||
pIfTable = (MIB_IFTABLE *) malloc(dwSize);
|
||||
if (pIfTable == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
// Make a second call to GetIfTable to get the actual
|
||||
// data we want.
|
||||
if ((dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE)) != NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "GetIfTable() syscall failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < (int) pIfTable->dwNumEntries; i++) {
|
||||
pIfRow = (MIB_IFROW *) & pIfTable->table[i];
|
||||
|
||||
// GetIfTable is not able to give us NIC with "friendly names"
|
||||
// so we determine them via GetAdapterAddresses() which
|
||||
// provides friendly names *and* descriptions and find the
|
||||
// ones that match.
|
||||
ifname_found = 0;
|
||||
pCurrAddresses = pAddresses;
|
||||
while (pCurrAddresses) {
|
||||
sprintf_s(descr, MAX_PATH, "%wS", pCurrAddresses->Description);
|
||||
if (lstrcmp(descr, pIfRow->bDescr) == 0) {
|
||||
py_nic_name = PyUnicode_FromWideChar(
|
||||
pCurrAddresses->FriendlyName,
|
||||
wcslen(pCurrAddresses->FriendlyName));
|
||||
if (py_nic_name == NULL)
|
||||
goto error;
|
||||
ifname_found = 1;
|
||||
break;
|
||||
}
|
||||
pCurrAddresses = pCurrAddresses->Next;
|
||||
}
|
||||
if (ifname_found == 0) {
|
||||
// Name not found means GetAdapterAddresses() doesn't list
|
||||
// this NIC, only GetIfTable, meaning it's not really a NIC
|
||||
// interface so we skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
// is up?
|
||||
if ((pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED ||
|
||||
pIfRow->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL) &&
|
||||
pIfRow->dwAdminStatus == 1 ) {
|
||||
py_is_up = Py_True;
|
||||
}
|
||||
else {
|
||||
py_is_up = Py_False;
|
||||
}
|
||||
Py_INCREF(py_is_up);
|
||||
|
||||
py_ifc_info = Py_BuildValue(
|
||||
"(Oikk)",
|
||||
py_is_up,
|
||||
2, // there's no way to know duplex so let's assume 'full'
|
||||
pIfRow->dwSpeed / 1000000, // expressed in bytes, we want Mb
|
||||
pIfRow->dwMtu
|
||||
);
|
||||
if (!py_ifc_info)
|
||||
goto error;
|
||||
if (PyDict_SetItem(py_retdict, py_nic_name, py_ifc_info))
|
||||
goto error;
|
||||
Py_CLEAR(py_nic_name);
|
||||
Py_CLEAR(py_ifc_info);
|
||||
}
|
||||
|
||||
free(pIfTable);
|
||||
free(pAddresses);
|
||||
return py_retdict;
|
||||
|
||||
error:
|
||||
Py_XDECREF(py_is_up);
|
||||
Py_XDECREF(py_ifc_info);
|
||||
Py_XDECREF(py_nic_name);
|
||||
Py_DECREF(py_retdict);
|
||||
if (pIfTable != NULL)
|
||||
free(pIfTable);
|
||||
if (pAddresses != NULL)
|
||||
free(pAddresses);
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
PyObject *psutil_net_if_addrs(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_net_if_stats(PyObject *self, PyObject *args);
|
||||
PyObject *psutil_net_io_counters(PyObject *self, PyObject *args);
|
|
@ -2,7 +2,9 @@
|
|||
* 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.
|
||||
* Define Windows structs and constants which are considered private.
|
||||
*/
|
||||
|
||||
#if !defined(__NTEXTAPI_H__)
|
||||
#define __NTEXTAPI_H__
|
||||
#include <winternl.h>
|
||||
|
@ -10,74 +12,92 @@
|
|||
|
||||
typedef LONG NTSTATUS;
|
||||
|
||||
#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
|
||||
#define STATUS_BUFFER_TOO_SMALL 0xC0000023L
|
||||
#define SystemExtendedHandleInformation 64
|
||||
#define MemoryWorkingSetInformation 0x1
|
||||
// https://github.com/ajkhoury/TestDll/blob/master/nt_ddk.h
|
||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
|
||||
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
|
||||
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
|
||||
#define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L)
|
||||
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* Enums.
|
||||
* ================================================================
|
||||
*/
|
||||
// ================================================================
|
||||
// Enums
|
||||
// ================================================================
|
||||
|
||||
typedef enum _PROCESSINFOCLASS2 {
|
||||
_ProcessBasicInformation,
|
||||
ProcessQuotaLimits,
|
||||
ProcessIoCounters,
|
||||
ProcessVmCounters,
|
||||
ProcessTimes,
|
||||
ProcessBasePriority,
|
||||
ProcessRaisePriority,
|
||||
_ProcessDebugPort,
|
||||
ProcessExceptionPort,
|
||||
ProcessAccessToken,
|
||||
ProcessLdtInformation,
|
||||
ProcessLdtSize,
|
||||
ProcessDefaultHardErrorMode,
|
||||
ProcessIoPortHandlers,
|
||||
ProcessPooledUsageAndLimits,
|
||||
ProcessWorkingSetWatch,
|
||||
ProcessUserModeIOPL,
|
||||
ProcessEnableAlignmentFaultFixup,
|
||||
ProcessPriorityClass,
|
||||
ProcessWx86Information,
|
||||
ProcessHandleCount,
|
||||
ProcessAffinityMask,
|
||||
ProcessPriorityBoost,
|
||||
ProcessDeviceMap,
|
||||
ProcessSessionInformation,
|
||||
ProcessForegroundInformation,
|
||||
_ProcessWow64Information,
|
||||
/* added after XP+ */
|
||||
_ProcessImageFileName,
|
||||
ProcessLUIDDeviceMapsEnabled,
|
||||
_ProcessBreakOnTermination,
|
||||
ProcessDebugObjectHandle,
|
||||
ProcessDebugFlags,
|
||||
ProcessHandleTracing,
|
||||
ProcessIoPriority,
|
||||
ProcessExecuteFlags,
|
||||
ProcessResourceManagement,
|
||||
ProcessCookie,
|
||||
ProcessImageInformation,
|
||||
MaxProcessInfoClass
|
||||
} PROCESSINFOCLASS2;
|
||||
#undef SystemExtendedHandleInformation
|
||||
#define SystemExtendedHandleInformation 64
|
||||
#undef MemoryWorkingSetInformation
|
||||
#define MemoryWorkingSetInformation 0x1
|
||||
#undef ObjectNameInformation
|
||||
#define ObjectNameInformation 1
|
||||
#undef ProcessIoPriority
|
||||
#define ProcessIoPriority 33
|
||||
#undef ProcessWow64Information
|
||||
#define ProcessWow64Information 26
|
||||
#undef SystemProcessIdInformation
|
||||
#define SystemProcessIdInformation 88
|
||||
|
||||
#define PROCESSINFOCLASS PROCESSINFOCLASS2
|
||||
#define ProcessBasicInformation _ProcessBasicInformation
|
||||
#define ProcessWow64Information _ProcessWow64Information
|
||||
#define ProcessDebugPort _ProcessDebugPort
|
||||
#define ProcessImageFileName _ProcessImageFileName
|
||||
#define ProcessBreakOnTermination _ProcessBreakOnTermination
|
||||
// process suspend() / resume()
|
||||
typedef enum _KTHREAD_STATE {
|
||||
Initialized,
|
||||
Ready,
|
||||
Running,
|
||||
Standby,
|
||||
Terminated,
|
||||
Waiting,
|
||||
Transition,
|
||||
DeferredReady,
|
||||
GateWait,
|
||||
MaximumThreadState
|
||||
} KTHREAD_STATE, *PKTHREAD_STATE;
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* Structs.
|
||||
* ================================================================
|
||||
*/
|
||||
typedef enum _KWAIT_REASON {
|
||||
Executive,
|
||||
FreePage,
|
||||
PageIn,
|
||||
PoolAllocation,
|
||||
DelayExecution,
|
||||
Suspended,
|
||||
UserRequest,
|
||||
WrExecutive,
|
||||
WrFreePage,
|
||||
WrPageIn,
|
||||
WrPoolAllocation,
|
||||
WrDelayExecution,
|
||||
WrSuspended,
|
||||
WrUserRequest,
|
||||
WrEventPair,
|
||||
WrQueue,
|
||||
WrLpcReceive,
|
||||
WrLpcReply,
|
||||
WrVirtualMemory,
|
||||
WrPageOut,
|
||||
WrRendezvous,
|
||||
WrKeyedEvent,
|
||||
WrTerminated,
|
||||
WrProcessInSwap,
|
||||
WrCpuRateControl,
|
||||
WrCalloutStack,
|
||||
WrKernel,
|
||||
WrResource,
|
||||
WrPushLock,
|
||||
WrMutex,
|
||||
WrQuantumEnd,
|
||||
WrDispatchInt,
|
||||
WrPreempted,
|
||||
WrYieldExecution,
|
||||
WrFastMutex,
|
||||
WrGuardedMutex,
|
||||
WrRundown,
|
||||
WrAlertByThreadId,
|
||||
WrDeferredPreempt,
|
||||
MaximumWaitReason
|
||||
} KWAIT_REASON, *PKWAIT_REASON;
|
||||
|
||||
// ================================================================
|
||||
// Structs.
|
||||
// ================================================================
|
||||
|
||||
// cpu_stats(), per_cpu_times()
|
||||
typedef struct {
|
||||
LARGE_INTEGER IdleTime;
|
||||
LARGE_INTEGER KernelTime;
|
||||
|
@ -87,6 +107,7 @@ typedef struct {
|
|||
ULONG InterruptCount;
|
||||
} _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
|
||||
|
||||
// cpu_stats()
|
||||
typedef struct {
|
||||
LARGE_INTEGER IdleProcessTime;
|
||||
LARGE_INTEGER IoReadTransferCount;
|
||||
|
@ -164,6 +185,7 @@ typedef struct {
|
|||
ULONG SystemCalls;
|
||||
} _SYSTEM_PERFORMANCE_INFORMATION;
|
||||
|
||||
// cpu_stats()
|
||||
typedef struct {
|
||||
ULONG ContextSwitches;
|
||||
ULONG DpcCount;
|
||||
|
@ -173,62 +195,6 @@ typedef struct {
|
|||
ULONG ApcBypassCount;
|
||||
} _SYSTEM_INTERRUPT_INFORMATION;
|
||||
|
||||
typedef enum _KTHREAD_STATE {
|
||||
Initialized,
|
||||
Ready,
|
||||
Running,
|
||||
Standby,
|
||||
Terminated,
|
||||
Waiting,
|
||||
Transition,
|
||||
DeferredReady,
|
||||
GateWait,
|
||||
MaximumThreadState
|
||||
} KTHREAD_STATE, *PKTHREAD_STATE;
|
||||
|
||||
typedef enum _KWAIT_REASON {
|
||||
Executive,
|
||||
FreePage,
|
||||
PageIn,
|
||||
PoolAllocation,
|
||||
DelayExecution,
|
||||
Suspended,
|
||||
UserRequest,
|
||||
WrExecutive,
|
||||
WrFreePage,
|
||||
WrPageIn,
|
||||
WrPoolAllocation,
|
||||
WrDelayExecution,
|
||||
WrSuspended,
|
||||
WrUserRequest,
|
||||
WrEventPair,
|
||||
WrQueue,
|
||||
WrLpcReceive,
|
||||
WrLpcReply,
|
||||
WrVirtualMemory,
|
||||
WrPageOut,
|
||||
WrRendezvous,
|
||||
WrKeyedEvent,
|
||||
WrTerminated,
|
||||
WrProcessInSwap,
|
||||
WrCpuRateControl,
|
||||
WrCalloutStack,
|
||||
WrKernel,
|
||||
WrResource,
|
||||
WrPushLock,
|
||||
WrMutex,
|
||||
WrQuantumEnd,
|
||||
WrDispatchInt,
|
||||
WrPreempted,
|
||||
WrYieldExecution,
|
||||
WrFastMutex,
|
||||
WrGuardedMutex,
|
||||
WrRundown,
|
||||
WrAlertByThreadId,
|
||||
WrDeferredPreempt,
|
||||
MaximumWaitReason
|
||||
} KWAIT_REASON, *PKWAIT_REASON;
|
||||
|
||||
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
|
||||
PVOID Object;
|
||||
HANDLE UniqueProcessId;
|
||||
|
@ -271,19 +237,6 @@ typedef struct _SYSTEM_THREAD_INFORMATION2 {
|
|||
#define SYSTEM_THREAD_INFORMATION SYSTEM_THREAD_INFORMATION2
|
||||
#define PSYSTEM_THREAD_INFORMATION PSYSTEM_THREAD_INFORMATION2
|
||||
|
||||
typedef struct _TEB *PTEB;
|
||||
|
||||
typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
|
||||
SYSTEM_THREAD_INFORMATION ThreadInfo;
|
||||
PVOID StackBase;
|
||||
PVOID StackLimit;
|
||||
PVOID Win32StartAddress;
|
||||
PTEB TebBase;
|
||||
ULONG_PTR Reserved2;
|
||||
ULONG_PTR Reserved3;
|
||||
ULONG_PTR Reserved4;
|
||||
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
|
||||
|
||||
typedef struct _SYSTEM_PROCESS_INFORMATION2 {
|
||||
ULONG NextEntryOffset;
|
||||
ULONG NumberOfThreads;
|
||||
|
@ -324,6 +277,7 @@ typedef struct _SYSTEM_PROCESS_INFORMATION2 {
|
|||
#define SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION2
|
||||
#define PSYSTEM_PROCESS_INFORMATION PSYSTEM_PROCESS_INFORMATION2
|
||||
|
||||
// cpu_freq()
|
||||
typedef struct _PROCESSOR_POWER_INFORMATION {
|
||||
ULONG Number;
|
||||
ULONG MaxMhz;
|
||||
|
@ -342,7 +296,7 @@ typedef struct in6_addr {
|
|||
} IN6_ADDR, *PIN6_ADDR, FAR *LPIN6_ADDR;
|
||||
#endif
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/aa813741(VS.85).aspx
|
||||
// PEB / cmdline(), cwd(), environ()
|
||||
typedef struct {
|
||||
BYTE Reserved1[16];
|
||||
PVOID Reserved2[5];
|
||||
|
@ -354,6 +308,7 @@ typedef struct {
|
|||
LPCWSTR env;
|
||||
} RTL_USER_PROCESS_PARAMETERS_, *PRTL_USER_PROCESS_PARAMETERS_;
|
||||
|
||||
// users()
|
||||
typedef struct _WINSTATION_INFO {
|
||||
BYTE Reserved1[72];
|
||||
ULONG SessionId;
|
||||
|
@ -366,6 +321,7 @@ typedef struct _WINSTATION_INFO {
|
|||
FILETIME CurrentTime;
|
||||
} WINSTATION_INFO, *PWINSTATION_INFO;
|
||||
|
||||
// cpu_count_phys()
|
||||
#if (_WIN32_WINNT < 0x0601) // Windows < 7 (Vista and XP)
|
||||
typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
|
||||
|
@ -377,9 +333,11 @@ typedef struct _SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX {
|
|||
CACHE_RELATIONSHIP Cache;
|
||||
GROUP_RELATIONSHIP Group;
|
||||
} DUMMYUNIONNAME;
|
||||
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, *PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
|
||||
} SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, \
|
||||
*PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX;
|
||||
#endif
|
||||
|
||||
// memory_uss()
|
||||
typedef struct _MEMORY_WORKING_SET_BLOCK {
|
||||
ULONG_PTR Protection : 5;
|
||||
ULONG_PTR ShareCount : 3;
|
||||
|
@ -392,11 +350,13 @@ typedef struct _MEMORY_WORKING_SET_BLOCK {
|
|||
#endif
|
||||
} MEMORY_WORKING_SET_BLOCK, *PMEMORY_WORKING_SET_BLOCK;
|
||||
|
||||
// memory_uss()
|
||||
typedef struct _MEMORY_WORKING_SET_INFORMATION {
|
||||
ULONG_PTR NumberOfEntries;
|
||||
MEMORY_WORKING_SET_BLOCK WorkingSetInfo[1];
|
||||
} MEMORY_WORKING_SET_INFORMATION, *PMEMORY_WORKING_SET_INFORMATION;
|
||||
|
||||
// memory_uss()
|
||||
typedef struct _PSUTIL_PROCESS_WS_COUNTERS {
|
||||
SIZE_T NumberOfPages;
|
||||
SIZE_T NumberOfPrivatePages;
|
||||
|
@ -404,18 +364,122 @@ typedef struct _PSUTIL_PROCESS_WS_COUNTERS {
|
|||
SIZE_T NumberOfShareablePages;
|
||||
} PSUTIL_PROCESS_WS_COUNTERS, *PPSUTIL_PROCESS_WS_COUNTERS;
|
||||
|
||||
/*
|
||||
* ================================================================
|
||||
* Type defs for modules loaded at runtime.
|
||||
* ================================================================
|
||||
*/
|
||||
// exe()
|
||||
typedef struct _SYSTEM_PROCESS_ID_INFORMATION {
|
||||
HANDLE ProcessId;
|
||||
UNICODE_STRING ImageName;
|
||||
} SYSTEM_PROCESS_ID_INFORMATION, *PSYSTEM_PROCESS_ID_INFORMATION;
|
||||
|
||||
typedef BOOL (WINAPI *_GetLogicalProcessorInformationEx)(
|
||||
// ====================================================================
|
||||
// PEB structs for cmdline(), cwd(), environ()
|
||||
// ====================================================================
|
||||
|
||||
#ifdef _WIN64
|
||||
typedef struct {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[21];
|
||||
PVOID LoaderData;
|
||||
PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters;
|
||||
// more fields...
|
||||
} PEB_;
|
||||
|
||||
// When we are a 64 bit process accessing a 32 bit (WoW64)
|
||||
// process we need to use the 32 bit structure layout.
|
||||
typedef struct {
|
||||
USHORT Length;
|
||||
USHORT MaxLength;
|
||||
DWORD Buffer;
|
||||
} UNICODE_STRING32;
|
||||
|
||||
typedef struct {
|
||||
BYTE Reserved1[16];
|
||||
DWORD Reserved2[5];
|
||||
UNICODE_STRING32 CurrentDirectoryPath;
|
||||
DWORD CurrentDirectoryHandle;
|
||||
UNICODE_STRING32 DllPath;
|
||||
UNICODE_STRING32 ImagePathName;
|
||||
UNICODE_STRING32 CommandLine;
|
||||
DWORD env;
|
||||
} RTL_USER_PROCESS_PARAMETERS32;
|
||||
|
||||
typedef struct {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[1];
|
||||
DWORD Reserved3[2];
|
||||
DWORD Ldr;
|
||||
DWORD ProcessParameters;
|
||||
// more fields...
|
||||
} PEB32;
|
||||
#else // ! _WIN64
|
||||
typedef struct {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[1];
|
||||
PVOID Reserved3[2];
|
||||
PVOID Ldr;
|
||||
PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters;
|
||||
// more fields...
|
||||
} PEB_;
|
||||
|
||||
// When we are a 32 bit (WoW64) process accessing a 64 bit process
|
||||
// we need to use the 64 bit structure layout and a special function
|
||||
// to read its memory.
|
||||
typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)(
|
||||
HANDLE ProcessHandle,
|
||||
PVOID64 BaseAddress,
|
||||
PVOID Buffer,
|
||||
ULONG64 Size,
|
||||
PULONG64 NumberOfBytesRead);
|
||||
|
||||
typedef struct {
|
||||
PVOID Reserved1[2];
|
||||
PVOID64 PebBaseAddress;
|
||||
PVOID Reserved2[4];
|
||||
PVOID UniqueProcessId[2];
|
||||
PVOID Reserved3[2];
|
||||
} PROCESS_BASIC_INFORMATION64;
|
||||
|
||||
typedef struct {
|
||||
USHORT Length;
|
||||
USHORT MaxLength;
|
||||
PVOID64 Buffer;
|
||||
} UNICODE_STRING64;
|
||||
|
||||
typedef struct {
|
||||
BYTE Reserved1[16];
|
||||
PVOID64 Reserved2[5];
|
||||
UNICODE_STRING64 CurrentDirectoryPath;
|
||||
PVOID64 CurrentDirectoryHandle;
|
||||
UNICODE_STRING64 DllPath;
|
||||
UNICODE_STRING64 ImagePathName;
|
||||
UNICODE_STRING64 CommandLine;
|
||||
PVOID64 env;
|
||||
} RTL_USER_PROCESS_PARAMETERS64;
|
||||
|
||||
typedef struct {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[21];
|
||||
PVOID64 LoaderData;
|
||||
PVOID64 ProcessParameters;
|
||||
// more fields...
|
||||
} PEB64;
|
||||
#endif // _WIN64
|
||||
|
||||
// ================================================================
|
||||
// Type defs for modules loaded at runtime.
|
||||
// ================================================================
|
||||
|
||||
BOOL (WINAPI *_GetLogicalProcessorInformationEx) (
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP relationship,
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
|
||||
PDWORD ReturnLength);
|
||||
|
||||
typedef BOOLEAN (WINAPI * _WinStationQueryInformationW)(
|
||||
#define GetLogicalProcessorInformationEx _GetLogicalProcessorInformationEx
|
||||
|
||||
BOOLEAN (WINAPI * _WinStationQueryInformationW) (
|
||||
HANDLE ServerHandle,
|
||||
ULONG SessionId,
|
||||
WINSTATIONINFOCLASS WinStationInformationClass,
|
||||
|
@ -423,34 +487,46 @@ typedef BOOLEAN (WINAPI * _WinStationQueryInformationW)(
|
|||
ULONG WinStationInformationLength,
|
||||
PULONG pReturnLength);
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
|
||||
#define WinStationQueryInformationW _WinStationQueryInformationW
|
||||
|
||||
NTSTATUS (NTAPI *_NtQueryInformationProcess) (
|
||||
HANDLE ProcessHandle,
|
||||
DWORD ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
DWORD ProcessInformationLength,
|
||||
PDWORD ReturnLength);
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtQuerySystemInformation)(
|
||||
#define NtQueryInformationProcess _NtQueryInformationProcess
|
||||
|
||||
NTSTATUS (NTAPI *_NtQuerySystemInformation) (
|
||||
ULONG SystemInformationClass,
|
||||
PVOID SystemInformation,
|
||||
ULONG SystemInformationLength,
|
||||
PULONG ReturnLength);
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
|
||||
#define NtQuerySystemInformation _NtQuerySystemInformation
|
||||
|
||||
NTSTATUS (NTAPI *_NtSetInformationProcess) (
|
||||
HANDLE ProcessHandle,
|
||||
DWORD ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
DWORD ProcessInformationLength);
|
||||
|
||||
typedef PSTR (NTAPI * _RtlIpv4AddressToStringA)(
|
||||
#define NtSetInformationProcess _NtSetInformationProcess
|
||||
|
||||
PSTR (NTAPI * _RtlIpv4AddressToStringA) (
|
||||
struct in_addr *Addr,
|
||||
PSTR S);
|
||||
|
||||
typedef PSTR (NTAPI * _RtlIpv6AddressToStringA)(
|
||||
#define RtlIpv4AddressToStringA _RtlIpv4AddressToStringA
|
||||
|
||||
PSTR (NTAPI * _RtlIpv6AddressToStringA) (
|
||||
struct in6_addr *Addr,
|
||||
PSTR P);
|
||||
|
||||
typedef DWORD (WINAPI * _GetExtendedTcpTable)(
|
||||
#define RtlIpv6AddressToStringA _RtlIpv6AddressToStringA
|
||||
|
||||
DWORD (WINAPI * _GetExtendedTcpTable) (
|
||||
PVOID pTcpTable,
|
||||
PDWORD pdwSize,
|
||||
BOOL bOrder,
|
||||
|
@ -458,7 +534,9 @@ typedef DWORD (WINAPI * _GetExtendedTcpTable)(
|
|||
TCP_TABLE_CLASS TableClass,
|
||||
ULONG Reserved);
|
||||
|
||||
typedef DWORD (WINAPI * _GetExtendedUdpTable)(
|
||||
#define GetExtendedTcpTable _GetExtendedTcpTable
|
||||
|
||||
DWORD (WINAPI * _GetExtendedUdpTable) (
|
||||
PVOID pUdpTable,
|
||||
PDWORD pdwSize,
|
||||
BOOL bOrder,
|
||||
|
@ -466,32 +544,46 @@ typedef DWORD (WINAPI * _GetExtendedUdpTable)(
|
|||
UDP_TABLE_CLASS TableClass,
|
||||
ULONG Reserved);
|
||||
|
||||
typedef DWORD (CALLBACK *_GetActiveProcessorCount)(
|
||||
#define GetExtendedUdpTable _GetExtendedUdpTable
|
||||
|
||||
DWORD (CALLBACK *_GetActiveProcessorCount) (
|
||||
WORD GroupNumber);
|
||||
|
||||
typedef ULONGLONG (CALLBACK *_GetTickCount64)(
|
||||
#define GetActiveProcessorCount _GetActiveProcessorCount
|
||||
|
||||
ULONGLONG (CALLBACK *_GetTickCount64) (
|
||||
void);
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtQueryObject)(
|
||||
#define GetTickCount64 _GetTickCount64
|
||||
|
||||
NTSTATUS (NTAPI *_NtQueryObject) (
|
||||
HANDLE Handle,
|
||||
OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
||||
PVOID ObjectInformation,
|
||||
ULONG ObjectInformationLength,
|
||||
PULONG ReturnLength);
|
||||
|
||||
typedef NTSTATUS (WINAPI *_RtlGetVersion) (
|
||||
#define NtQueryObject _NtQueryObject
|
||||
|
||||
NTSTATUS (WINAPI *_RtlGetVersion) (
|
||||
PRTL_OSVERSIONINFOW lpVersionInformation
|
||||
);
|
||||
|
||||
typedef NTSTATUS (WINAPI *_NtResumeProcess) (
|
||||
#define RtlGetVersion _RtlGetVersion
|
||||
|
||||
NTSTATUS (WINAPI *_NtResumeProcess) (
|
||||
HANDLE hProcess
|
||||
);
|
||||
|
||||
typedef NTSTATUS (WINAPI *_NtSuspendProcess) (
|
||||
#define NtResumeProcess _NtResumeProcess
|
||||
|
||||
NTSTATUS (WINAPI *_NtSuspendProcess) (
|
||||
HANDLE hProcess
|
||||
);
|
||||
|
||||
typedef NTSTATUS (NTAPI *_NtQueryVirtualMemory) (
|
||||
#define NtSuspendProcess _NtSuspendProcess
|
||||
|
||||
NTSTATUS (NTAPI *_NtQueryVirtualMemory) (
|
||||
HANDLE ProcessHandle,
|
||||
PVOID BaseAddress,
|
||||
int MemoryInformationClass,
|
||||
|
@ -500,8 +592,12 @@ typedef NTSTATUS (NTAPI *_NtQueryVirtualMemory) (
|
|||
PSIZE_T ReturnLength
|
||||
);
|
||||
|
||||
typedef ULONG (WINAPI *_RtlNtStatusToDosErrorNoTeb) (
|
||||
#define NtQueryVirtualMemory _NtQueryVirtualMemory
|
||||
|
||||
ULONG (WINAPI *_RtlNtStatusToDosErrorNoTeb) (
|
||||
NTSTATUS status
|
||||
);
|
||||
|
||||
#define RtlNtStatusToDosErrorNoTeb _RtlNtStatusToDosErrorNoTeb
|
||||
|
||||
#endif // __NTEXTAPI_H__
|
||||
|
|
|
@ -2,512 +2,291 @@
|
|||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module retrieves handles opened by a process.
|
||||
* We use NtQuerySystemInformation to enumerate them and NtQueryObject
|
||||
* to obtain the corresponding file name.
|
||||
* Since NtQueryObject hangs for certain handle types we call it in a
|
||||
* separate thread which gets killed if it doesn't complete within 100ms.
|
||||
* This is a limitation of the Windows API and ProcessHacker uses the
|
||||
* same trick: https://github.com/giampaolo/psutil/pull/597
|
||||
*
|
||||
* CREDITS: original implementation was written by Jeff Tang.
|
||||
* It was then rewritten by Giampaolo Rodola many years later.
|
||||
* Utility functions for getting the file handles and names were re-adapted
|
||||
* from the excellent ProcessHacker.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <Psapi.h>
|
||||
#include <Python.h>
|
||||
#include "ntextapi.h"
|
||||
#include "global.h"
|
||||
#include "process_handles.h"
|
||||
#include "process_info.h"
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
|
||||
CRITICAL_SECTION g_cs;
|
||||
BOOL g_initialized = FALSE;
|
||||
NTSTATUS g_status;
|
||||
HANDLE g_hFile = NULL;
|
||||
HANDLE g_hEvtStart = NULL;
|
||||
HANDLE g_hEvtFinish = NULL;
|
||||
HANDLE g_hThread = NULL;
|
||||
PUNICODE_STRING g_pNameBuffer = NULL;
|
||||
ULONG g_dwSize = 0;
|
||||
ULONG g_dwLength = 0;
|
||||
#include "process_utils.h"
|
||||
|
||||
|
||||
#define ObjectNameInformation 1
|
||||
#define NTQO_TIMEOUT 100
|
||||
#define THREAD_TIMEOUT 100 // ms
|
||||
// Global object shared between the 2 threads.
|
||||
PUNICODE_STRING globalFileName = NULL;
|
||||
|
||||
|
||||
static VOID
|
||||
psutil_get_open_files_init(BOOL threaded) {
|
||||
if (g_initialized == TRUE)
|
||||
return;
|
||||
static int
|
||||
psutil_enum_handles(PSYSTEM_HANDLE_INFORMATION_EX *handles) {
|
||||
static ULONG initialBufferSize = 0x10000;
|
||||
NTSTATUS status;
|
||||
PVOID buffer;
|
||||
ULONG bufferSize;
|
||||
|
||||
// Create events for signalling work between threads
|
||||
if (threaded == TRUE) {
|
||||
g_hEvtStart = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
g_hEvtFinish = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
InitializeCriticalSection(&g_cs);
|
||||
bufferSize = initialBufferSize;
|
||||
buffer = MALLOC_ZERO(bufferSize);
|
||||
if (buffer == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_initialized = TRUE;
|
||||
while ((status = NtQuerySystemInformation(
|
||||
SystemExtendedHandleInformation,
|
||||
buffer,
|
||||
bufferSize,
|
||||
NULL
|
||||
)) == STATUS_INFO_LENGTH_MISMATCH)
|
||||
{
|
||||
FREE(buffer);
|
||||
bufferSize *= 2;
|
||||
|
||||
// Fail if we're resizing the buffer to something very large.
|
||||
if (bufferSize > 256 * 1024 * 1024) {
|
||||
PyErr_SetString(
|
||||
PyExc_RuntimeError,
|
||||
"SystemExtendedHandleInformation buffer too big");
|
||||
return 1;
|
||||
}
|
||||
|
||||
buffer = MALLOC_ZERO(bufferSize);
|
||||
if (buffer == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (! NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(status, "NtQuerySystemInformation");
|
||||
FREE(buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*handles = (PSYSTEM_HANDLE_INFORMATION_EX)buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI
|
||||
psutil_wait_thread(LPVOID lpvParam) {
|
||||
// Loop infinitely waiting for work
|
||||
while (TRUE) {
|
||||
WaitForSingleObject(g_hEvtStart, INFINITE);
|
||||
static int
|
||||
psutil_get_filename(LPVOID lpvParam) {
|
||||
HANDLE hFile = *((HANDLE*)lpvParam);
|
||||
NTSTATUS status;
|
||||
ULONG bufferSize;
|
||||
ULONG attempts = 8;
|
||||
|
||||
// TODO: return code not checked
|
||||
g_status = psutil_NtQueryObject(
|
||||
g_hFile,
|
||||
bufferSize = 0x200;
|
||||
globalFileName = MALLOC_ZERO(bufferSize);
|
||||
if (globalFileName == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
// Note: also this is supposed to hang, hence why we do it in here.
|
||||
if (GetFileType(hFile) != FILE_TYPE_DISK) {
|
||||
SetLastError(0);
|
||||
globalFileName->Length = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// A loop is needed because the I/O subsystem likes to give us the
|
||||
// wrong return lengths...
|
||||
do {
|
||||
status = NtQueryObject(
|
||||
hFile,
|
||||
ObjectNameInformation,
|
||||
g_pNameBuffer,
|
||||
g_dwSize,
|
||||
&g_dwLength);
|
||||
SetEvent(g_hEvtFinish);
|
||||
globalFileName,
|
||||
bufferSize,
|
||||
&bufferSize
|
||||
);
|
||||
if (status == STATUS_BUFFER_OVERFLOW ||
|
||||
status == STATUS_INFO_LENGTH_MISMATCH ||
|
||||
status == STATUS_BUFFER_TOO_SMALL)
|
||||
{
|
||||
FREE(globalFileName);
|
||||
globalFileName = MALLOC_ZERO(bufferSize);
|
||||
if (globalFileName == NULL) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (--attempts);
|
||||
|
||||
if (! NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(status, "NtQuerySystemInformation");
|
||||
FREE(globalFileName);
|
||||
globalFileName = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (globalFileName != NULL) {
|
||||
FREE(globalFileName);
|
||||
globalFileName = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static DWORD
|
||||
psutil_create_thread() {
|
||||
DWORD dwWait = 0;
|
||||
psutil_threaded_get_filename(HANDLE hFile) {
|
||||
DWORD dwWait;
|
||||
HANDLE hThread;
|
||||
DWORD threadRetValue;
|
||||
|
||||
if (g_hThread == NULL)
|
||||
g_hThread = CreateThread(
|
||||
NULL,
|
||||
0,
|
||||
psutil_wait_thread,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
if (g_hThread == NULL)
|
||||
return GetLastError();
|
||||
hThread = CreateThread(
|
||||
NULL, 0, (LPTHREAD_START_ROUTINE)psutil_get_filename, &hFile, 0, NULL);
|
||||
if (hThread == NULL) {
|
||||
PyErr_SetFromOSErrnoWithSyscall("CreateThread");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Signal the worker thread to start
|
||||
SetEvent(g_hEvtStart);
|
||||
// Wait for the worker thread to finish.
|
||||
dwWait = WaitForSingleObject(hThread, THREAD_TIMEOUT);
|
||||
|
||||
// Wait for the worker thread to finish
|
||||
dwWait = WaitForSingleObject(g_hEvtFinish, NTQO_TIMEOUT);
|
||||
|
||||
// If the thread hangs, kill it and cleanup
|
||||
// If the thread hangs, kill it and cleanup.
|
||||
if (dwWait == WAIT_TIMEOUT) {
|
||||
SuspendThread(g_hThread);
|
||||
TerminateThread(g_hThread, 1);
|
||||
WaitForSingleObject(g_hThread, INFINITE);
|
||||
CloseHandle(g_hThread);
|
||||
|
||||
g_hThread = NULL;
|
||||
psutil_debug(
|
||||
"get handle name thread timed out after %i ms", THREAD_TIMEOUT);
|
||||
if (TerminateThread(hThread, 0) == 0) {
|
||||
PyErr_SetFromOSErrnoWithSyscall("TerminateThread");
|
||||
CloseHandle(hThread);
|
||||
return 1;
|
||||
}
|
||||
CloseHandle(hThread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dwWait;
|
||||
if (dwWait == WAIT_FAILED) {
|
||||
psutil_debug("WaitForSingleObject -> WAIT_FAILED");
|
||||
if (TerminateThread(hThread, 0) == 0) {
|
||||
PyErr_SetFromOSErrnoWithSyscall(
|
||||
"WaitForSingleObject -> WAIT_FAILED -> TerminateThread");
|
||||
CloseHandle(hThread);
|
||||
return 1;
|
||||
}
|
||||
PyErr_SetFromOSErrnoWithSyscall("WaitForSingleObject");
|
||||
CloseHandle(hThread);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (GetExitCodeThread(hThread, &threadRetValue) == 0) {
|
||||
if (TerminateThread(hThread, 0) == 0) {
|
||||
PyErr_SetFromOSErrnoWithSyscall(
|
||||
"GetExitCodeThread (failed) -> TerminateThread");
|
||||
CloseHandle(hThread);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CloseHandle(hThread);
|
||||
PyErr_SetFromOSErrnoWithSyscall("GetExitCodeThread");
|
||||
return 1;
|
||||
}
|
||||
CloseHandle(hThread);
|
||||
return threadRetValue;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
|
||||
NTSTATUS status;
|
||||
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
||||
DWORD dwInfoSize = 0x10000;
|
||||
DWORD dwRet = 0;
|
||||
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
|
||||
DWORD i = 0;
|
||||
BOOLEAN error = FALSE;
|
||||
DWORD dwWait = 0;
|
||||
PyObject* py_retlist = NULL;
|
||||
PyObject* py_path = NULL;
|
||||
|
||||
if (g_initialized == FALSE)
|
||||
psutil_get_open_files_init(TRUE);
|
||||
|
||||
// Due to the use of global variables, ensure only 1 call
|
||||
// to psutil_get_open_files() is running
|
||||
EnterCriticalSection(&g_cs);
|
||||
|
||||
if (g_hEvtStart == NULL ||
|
||||
g_hEvtFinish == NULL)
|
||||
|
||||
{
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Py_BuildValue raises an exception if NULL is returned
|
||||
py_retlist = PyList_New(0);
|
||||
if (py_retlist == NULL) {
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
do {
|
||||
if (pHandleInfo != NULL) {
|
||||
HeapFree(GetProcessHeap(), 0, pHandleInfo);
|
||||
pHandleInfo = NULL;
|
||||
}
|
||||
|
||||
// NtQuerySystemInformation won't give us the correct buffer size,
|
||||
// so we guess by doubling the buffer size.
|
||||
dwInfoSize *= 2;
|
||||
pHandleInfo = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
dwInfoSize);
|
||||
|
||||
if (pHandleInfo == NULL) {
|
||||
PyErr_NoMemory();
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
} while ((status = psutil_NtQuerySystemInformation(
|
||||
SystemExtendedHandleInformation,
|
||||
pHandleInfo,
|
||||
dwInfoSize,
|
||||
&dwRet)) == STATUS_INFO_LENGTH_MISMATCH);
|
||||
|
||||
// NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH
|
||||
if (! NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(
|
||||
status, "NtQuerySystemInformation(SystemExtendedHandleInformation)");
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < pHandleInfo->NumberOfHandles; i++) {
|
||||
hHandle = &pHandleInfo->Handles[i];
|
||||
|
||||
// Check if this hHandle belongs to the PID the user specified.
|
||||
if (hHandle->UniqueProcessId != (ULONG_PTR)dwPid)
|
||||
goto loop_cleanup;
|
||||
|
||||
if (!DuplicateHandle(hProcess,
|
||||
(HANDLE)hHandle->HandleValue,
|
||||
GetCurrentProcess(),
|
||||
&g_hFile,
|
||||
0,
|
||||
TRUE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
/*
|
||||
printf("[%d] DuplicateHandle (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
// Guess buffer size is MAX_PATH + 1
|
||||
g_dwLength = (MAX_PATH+1) * sizeof(WCHAR);
|
||||
|
||||
do {
|
||||
// Release any previously allocated buffer
|
||||
if (g_pNameBuffer != NULL) {
|
||||
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
|
||||
g_pNameBuffer = NULL;
|
||||
g_dwSize = 0;
|
||||
}
|
||||
|
||||
// NtQueryObject puts the required buffer size in g_dwLength
|
||||
// WinXP edge case puts g_dwLength == 0, just skip this handle
|
||||
if (g_dwLength == 0)
|
||||
goto loop_cleanup;
|
||||
|
||||
g_dwSize = g_dwLength;
|
||||
if (g_dwSize > 0) {
|
||||
g_pNameBuffer = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
g_dwSize);
|
||||
|
||||
if (g_pNameBuffer == NULL)
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
dwWait = psutil_create_thread();
|
||||
|
||||
// If the call does not return, skip this handle
|
||||
if (dwWait != WAIT_OBJECT_0)
|
||||
goto loop_cleanup;
|
||||
|
||||
} while (g_status == STATUS_INFO_LENGTH_MISMATCH);
|
||||
|
||||
// NtQueryObject stopped returning STATUS_INFO_LENGTH_MISMATCH
|
||||
if (!NT_SUCCESS(g_status))
|
||||
goto loop_cleanup;
|
||||
|
||||
// Convert to PyUnicode and append it to the return list
|
||||
if (g_pNameBuffer->Length > 0) {
|
||||
/*
|
||||
printf("[%d] Filename (%#x) %#d bytes: %S\n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
g_pNameBuffer->Length,
|
||||
g_pNameBuffer->Buffer);
|
||||
*/
|
||||
|
||||
py_path = PyUnicode_FromWideChar(g_pNameBuffer->Buffer,
|
||||
g_pNameBuffer->Length/2);
|
||||
if (py_path == NULL) {
|
||||
/*
|
||||
printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
error = TRUE;
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
if (PyList_Append(py_retlist, py_path)) {
|
||||
/*
|
||||
printf("[%d] PyList_Append (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
error = TRUE;
|
||||
goto loop_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
loop_cleanup:
|
||||
Py_XDECREF(py_path);
|
||||
py_path = NULL;
|
||||
|
||||
if (g_pNameBuffer != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
|
||||
g_pNameBuffer = NULL;
|
||||
g_dwSize = 0;
|
||||
g_dwLength = 0;
|
||||
|
||||
if (g_hFile != NULL)
|
||||
CloseHandle(g_hFile);
|
||||
g_hFile = NULL;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (g_pNameBuffer != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
|
||||
g_pNameBuffer = NULL;
|
||||
g_dwSize = 0;
|
||||
g_dwLength = 0;
|
||||
|
||||
if (g_hFile != NULL)
|
||||
CloseHandle(g_hFile);
|
||||
g_hFile = NULL;
|
||||
|
||||
if (pHandleInfo != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, pHandleInfo);
|
||||
pHandleInfo = NULL;
|
||||
|
||||
if (error) {
|
||||
Py_XDECREF(py_retlist);
|
||||
py_retlist = NULL;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&g_cs);
|
||||
|
||||
return py_retlist;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) {
|
||||
NTSTATUS status;
|
||||
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
||||
DWORD dwInfoSize = 0x10000;
|
||||
DWORD dwRet = 0;
|
||||
PyObject *
|
||||
psutil_get_open_files(DWORD dwPid, HANDLE hProcess) {
|
||||
PSYSTEM_HANDLE_INFORMATION_EX handlesList = NULL;
|
||||
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
|
||||
HANDLE hFile = NULL;
|
||||
HANDLE hMap = NULL;
|
||||
DWORD i = 0;
|
||||
BOOLEAN error = FALSE;
|
||||
PyObject* py_retlist = NULL;
|
||||
ULONG i = 0;
|
||||
BOOLEAN errorOccurred = FALSE;
|
||||
PyObject* py_path = NULL;
|
||||
ULONG dwSize = 0;
|
||||
LPVOID pMem = NULL;
|
||||
wchar_t pszFilename[MAX_PATH+1];
|
||||
PyObject* py_retlist = PyList_New(0);;
|
||||
|
||||
if (g_initialized == FALSE)
|
||||
psutil_get_open_files_init(FALSE);
|
||||
if (!py_retlist)
|
||||
return NULL;
|
||||
|
||||
// Py_BuildValue raises an exception if NULL is returned
|
||||
py_retlist = PyList_New(0);
|
||||
if (py_retlist == NULL) {
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
// Due to the use of global variables, ensure only 1 call
|
||||
// to psutil_get_open_files() is running.
|
||||
EnterCriticalSection(&PSUTIL_CRITICAL_SECTION);
|
||||
|
||||
do {
|
||||
if (pHandleInfo != NULL) {
|
||||
HeapFree(GetProcessHeap(), 0, pHandleInfo);
|
||||
pHandleInfo = NULL;
|
||||
}
|
||||
if (psutil_enum_handles(&handlesList) != 0)
|
||||
goto error;
|
||||
|
||||
// NtQuerySystemInformation won't give us the correct buffer size,
|
||||
// so we guess by doubling the buffer size.
|
||||
dwInfoSize *= 2;
|
||||
pHandleInfo = HeapAlloc(GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
dwInfoSize);
|
||||
|
||||
if (pHandleInfo == NULL) {
|
||||
PyErr_NoMemory();
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
} while ((status = psutil_NtQuerySystemInformation(
|
||||
SystemExtendedHandleInformation,
|
||||
pHandleInfo,
|
||||
dwInfoSize,
|
||||
&dwRet)) == STATUS_INFO_LENGTH_MISMATCH);
|
||||
|
||||
// NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH
|
||||
if (! NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(
|
||||
status, "NtQuerySystemInformation(SystemExtendedHandleInformation)");
|
||||
error = TRUE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < pHandleInfo->NumberOfHandles; i++) {
|
||||
hHandle = &pHandleInfo->Handles[i];
|
||||
|
||||
// Check if this hHandle belongs to the PID the user specified.
|
||||
if (hHandle->UniqueProcessId != (ULONG_PTR)dwPid)
|
||||
goto loop_cleanup;
|
||||
|
||||
if (!DuplicateHandle(hProcess,
|
||||
(HANDLE)hHandle->HandleValue,
|
||||
for (i = 0; i < handlesList->NumberOfHandles; i++) {
|
||||
hHandle = &handlesList->Handles[i];
|
||||
if ((ULONG_PTR)hHandle->UniqueProcessId != dwPid)
|
||||
continue;
|
||||
if (! DuplicateHandle(
|
||||
hProcess,
|
||||
hHandle->HandleValue,
|
||||
GetCurrentProcess(),
|
||||
&hFile,
|
||||
0,
|
||||
TRUE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
/*
|
||||
printf("[%d] DuplicateHandle (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
// Will fail if not a regular file; just skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMap == NULL) {
|
||||
/*
|
||||
printf("[%d] CreateFileMapping (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
// This will set *globalFileName* global variable.
|
||||
if (psutil_threaded_get_filename(hFile) != 0)
|
||||
goto error;
|
||||
|
||||
if (globalFileName->Length > 0) {
|
||||
py_path = PyUnicode_FromWideChar(globalFileName->Buffer,
|
||||
wcslen(globalFileName->Buffer));
|
||||
if (! py_path)
|
||||
goto error;
|
||||
if (PyList_Append(py_retlist, py_path))
|
||||
goto error;
|
||||
Py_CLEAR(py_path); // also sets to NULL
|
||||
}
|
||||
|
||||
pMem = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 1);
|
||||
|
||||
if (pMem == NULL) {
|
||||
/*
|
||||
printf("[%d] MapViewOfFile (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
// Loop cleanup section.
|
||||
if (globalFileName != NULL) {
|
||||
FREE(globalFileName);
|
||||
globalFileName = NULL;
|
||||
}
|
||||
|
||||
dwSize = GetMappedFileName(
|
||||
GetCurrentProcess(), pMem, (LPSTR)pszFilename, MAX_PATH);
|
||||
if (dwSize == 0) {
|
||||
/*
|
||||
printf("[%d] GetMappedFileName (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
pszFilename[dwSize] = '\0';
|
||||
/*
|
||||
printf("[%d] Filename (%#x) %#d bytes: %S\n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
dwSize,
|
||||
pszFilename);
|
||||
*/
|
||||
|
||||
py_path = PyUnicode_FromWideChar(pszFilename, dwSize);
|
||||
if (py_path == NULL) {
|
||||
/*
|
||||
printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
error = TRUE;
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
if (PyList_Append(py_retlist, py_path)) {
|
||||
/*
|
||||
printf("[%d] PyList_Append (%#x): %#x \n",
|
||||
dwPid,
|
||||
hHandle->HandleValue,
|
||||
GetLastError());
|
||||
*/
|
||||
error = TRUE;
|
||||
goto loop_cleanup;
|
||||
}
|
||||
|
||||
loop_cleanup:
|
||||
Py_XDECREF(py_path);
|
||||
py_path = NULL;
|
||||
|
||||
if (pMem != NULL)
|
||||
UnmapViewOfFile(pMem);
|
||||
pMem = NULL;
|
||||
|
||||
if (hMap != NULL)
|
||||
CloseHandle(hMap);
|
||||
hMap = NULL;
|
||||
|
||||
if (hFile != NULL)
|
||||
CloseHandle(hFile);
|
||||
hFile = NULL;
|
||||
|
||||
dwSize = 0;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (pMem != NULL)
|
||||
UnmapViewOfFile(pMem);
|
||||
pMem = NULL;
|
||||
goto exit;
|
||||
|
||||
if (hMap != NULL)
|
||||
CloseHandle(hMap);
|
||||
hMap = NULL;
|
||||
|
||||
if (hFile != NULL)
|
||||
CloseHandle(hFile);
|
||||
hFile = NULL;
|
||||
|
||||
if (pHandleInfo != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, pHandleInfo);
|
||||
pHandleInfo = NULL;
|
||||
|
||||
if (error) {
|
||||
error:
|
||||
Py_XDECREF(py_retlist);
|
||||
py_retlist = NULL;
|
||||
}
|
||||
errorOccurred = TRUE;
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if (hFile != NULL)
|
||||
CloseHandle(hFile);
|
||||
if (globalFileName != NULL) {
|
||||
FREE(globalFileName);
|
||||
globalFileName = NULL;
|
||||
}
|
||||
if (py_path != NULL)
|
||||
Py_DECREF(py_path);
|
||||
if (handlesList != NULL)
|
||||
FREE(handlesList);
|
||||
|
||||
LeaveCriticalSection(&PSUTIL_CRITICAL_SECTION);
|
||||
if (errorOccurred == TRUE)
|
||||
return NULL;
|
||||
return py_retlist;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The public function.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_get_open_files(long dwPid, HANDLE hProcess) {
|
||||
// Threaded version only works for Vista+
|
||||
if (PSUTIL_WINVER >= PSUTIL_WINDOWS_VISTA)
|
||||
return psutil_get_open_files_ntqueryobject(dwPid, hProcess);
|
||||
else
|
||||
return psutil_get_open_files_getmappedfilename(dwPid, hProcess);
|
||||
}
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
|
||||
PyObject* psutil_get_open_files(long pid, HANDLE processHandle);
|
||||
PyObject* psutil_get_open_files(DWORD pid, HANDLE hProcess);
|
||||
|
|
|
@ -9,408 +9,26 @@
|
|||
|
||||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
#include <Psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#include "ntextapi.h"
|
||||
#include "global.h"
|
||||
#include "security.h"
|
||||
#include "process_info.h"
|
||||
#include "../../_psutil_common.h"
|
||||
#include "process_info.h"
|
||||
#include "process_utils.h"
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// Helper structures to access the memory correctly.
|
||||
// Some of these might also be defined in the winternl.h header file
|
||||
// but unfortunately not in a usable way.
|
||||
// ====================================================================
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/aa813706(v=vs.85).aspx
|
||||
#ifdef _WIN64
|
||||
typedef struct {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[21];
|
||||
PVOID LoaderData;
|
||||
PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters;
|
||||
/* More fields ... */
|
||||
} PEB_;
|
||||
#else
|
||||
typedef struct {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[1];
|
||||
PVOID Reserved3[2];
|
||||
PVOID Ldr;
|
||||
PRTL_USER_PROCESS_PARAMETERS_ ProcessParameters;
|
||||
/* More fields ... */
|
||||
} PEB_;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN64
|
||||
/* When we are a 64 bit process accessing a 32 bit (WoW64) process we need to
|
||||
use the 32 bit structure layout. */
|
||||
typedef struct {
|
||||
USHORT Length;
|
||||
USHORT MaxLength;
|
||||
DWORD Buffer;
|
||||
} UNICODE_STRING32;
|
||||
|
||||
typedef struct {
|
||||
BYTE Reserved1[16];
|
||||
DWORD Reserved2[5];
|
||||
UNICODE_STRING32 CurrentDirectoryPath;
|
||||
DWORD CurrentDirectoryHandle;
|
||||
UNICODE_STRING32 DllPath;
|
||||
UNICODE_STRING32 ImagePathName;
|
||||
UNICODE_STRING32 CommandLine;
|
||||
DWORD env;
|
||||
} RTL_USER_PROCESS_PARAMETERS32;
|
||||
|
||||
typedef struct {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[1];
|
||||
DWORD Reserved3[2];
|
||||
DWORD Ldr;
|
||||
DWORD ProcessParameters;
|
||||
/* More fields ... */
|
||||
} PEB32;
|
||||
#else
|
||||
/* When we are a 32 bit (WoW64) process accessing a 64 bit process we need to
|
||||
use the 64 bit structure layout and a special function to read its memory.
|
||||
*/
|
||||
typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)(
|
||||
#ifndef _WIN64
|
||||
typedef NTSTATUS (NTAPI *__NtQueryInformationProcess)(
|
||||
HANDLE ProcessHandle,
|
||||
PVOID64 BaseAddress,
|
||||
PVOID Buffer,
|
||||
ULONG64 Size,
|
||||
PULONG64 NumberOfBytesRead);
|
||||
|
||||
typedef struct {
|
||||
PVOID Reserved1[2];
|
||||
PVOID64 PebBaseAddress;
|
||||
PVOID Reserved2[4];
|
||||
PVOID UniqueProcessId[2];
|
||||
PVOID Reserved3[2];
|
||||
} PROCESS_BASIC_INFORMATION64;
|
||||
|
||||
typedef struct {
|
||||
USHORT Length;
|
||||
USHORT MaxLength;
|
||||
PVOID64 Buffer;
|
||||
} UNICODE_STRING64;
|
||||
|
||||
typedef struct {
|
||||
BYTE Reserved1[16];
|
||||
PVOID64 Reserved2[5];
|
||||
UNICODE_STRING64 CurrentDirectoryPath;
|
||||
PVOID64 CurrentDirectoryHandle;
|
||||
UNICODE_STRING64 DllPath;
|
||||
UNICODE_STRING64 ImagePathName;
|
||||
UNICODE_STRING64 CommandLine;
|
||||
PVOID64 env;
|
||||
} RTL_USER_PROCESS_PARAMETERS64;
|
||||
|
||||
typedef struct {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[21];
|
||||
PVOID64 LoaderData;
|
||||
PVOID64 ProcessParameters;
|
||||
/* More fields ... */
|
||||
} PEB64;
|
||||
DWORD ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
DWORD ProcessInformationLength,
|
||||
PDWORD ReturnLength);
|
||||
#endif
|
||||
|
||||
|
||||
#define PSUTIL_FIRST_PROCESS(Processes) ( \
|
||||
(PSYSTEM_PROCESS_INFORMATION)(Processes))
|
||||
#define PSUTIL_NEXT_PROCESS(Process) ( \
|
||||
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \
|
||||
(PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \
|
||||
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : NULL)
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// Process and PIDs utiilties.
|
||||
// ====================================================================
|
||||
|
||||
|
||||
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
|
||||
|
||||
/*
|
||||
* Return 1 if PID exists, 0 if not, -1 on error.
|
||||
* Given a pointer into a process's memory, figure out how much
|
||||
* data can be read from it.
|
||||
*/
|
||||
int
|
||||
psutil_pid_in_pids(DWORD pid) {
|
||||
DWORD *proclist = NULL;
|
||||
DWORD numberOfReturnedPIDs;
|
||||
DWORD i;
|
||||
|
||||
proclist = psutil_get_pids(&numberOfReturnedPIDs);
|
||||
if (proclist == NULL)
|
||||
return -1;
|
||||
for (i = 0; i < numberOfReturnedPIDs; i++) {
|
||||
if (proclist[i] == pid) {
|
||||
free(proclist);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
free(proclist);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a process HANDLE checks whether it's actually running.
|
||||
* Returns:
|
||||
* - 1: running
|
||||
* - 0: not running
|
||||
* - -1: WindowsError
|
||||
* - -2: AssertionError
|
||||
*/
|
||||
int
|
||||
psutil_is_phandle_running(HANDLE hProcess, DWORD pid) {
|
||||
DWORD processExitCode = 0;
|
||||
|
||||
if (hProcess == NULL) {
|
||||
if (GetLastError() == ERROR_INVALID_PARAMETER) {
|
||||
// Yeah, this is the actual error code in case of
|
||||
// "no such process".
|
||||
if (! psutil_assert_pid_not_exists(
|
||||
pid, "iphr: OpenProcess() -> ERROR_INVALID_PARAMETER")) {
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (GetExitCodeProcess(hProcess, &processExitCode)) {
|
||||
// XXX - maybe STILL_ACTIVE is not fully reliable as per:
|
||||
// http://stackoverflow.com/questions/1591342/#comment47830782_1591379
|
||||
if (processExitCode == STILL_ACTIVE) {
|
||||
if (! psutil_assert_pid_exists(
|
||||
pid, "iphr: GetExitCodeProcess() -> STILL_ACTIVE")) {
|
||||
return -2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
// We can't be sure so we look into pids.
|
||||
if (psutil_pid_in_pids(pid) == 1) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
CloseHandle(hProcess);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(hProcess);
|
||||
if (! psutil_assert_pid_not_exists( pid, "iphr: exit fun")) {
|
||||
return -2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a process HANDLE checks whether it's actually running and if
|
||||
* it does return it, else return NULL with the proper Python exception
|
||||
* set.
|
||||
*/
|
||||
HANDLE
|
||||
psutil_check_phandle(HANDLE hProcess, DWORD pid) {
|
||||
int ret = psutil_is_phandle_running(hProcess, pid);
|
||||
if (ret == 1) {
|
||||
return hProcess;
|
||||
}
|
||||
else if (ret == 0) {
|
||||
return NoSuchProcess("");
|
||||
}
|
||||
else if (ret == -1) {
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED)
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
else
|
||||
return PyErr_SetFromOSErrnoWithSyscall("OpenProcess");
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A wrapper around OpenProcess setting NSP exception if process
|
||||
* no longer exists.
|
||||
* "pid" is the process pid, "dwDesiredAccess" is the first argument
|
||||
* exptected by OpenProcess.
|
||||
* Return a process handle or NULL.
|
||||
*/
|
||||
HANDLE
|
||||
psutil_handle_from_pid(DWORD pid, DWORD access) {
|
||||
HANDLE hProcess;
|
||||
|
||||
if (pid == 0) {
|
||||
// otherwise we'd get NoSuchProcess
|
||||
return AccessDenied("");
|
||||
}
|
||||
// needed for GetExitCodeProcess
|
||||
access |= PROCESS_QUERY_LIMITED_INFORMATION;
|
||||
hProcess = OpenProcess(access, FALSE, pid);
|
||||
return psutil_check_phandle(hProcess, pid);
|
||||
}
|
||||
|
||||
|
||||
DWORD *
|
||||
psutil_get_pids(DWORD *numberOfReturnedPIDs) {
|
||||
// Win32 SDK says the only way to know if our process array
|
||||
// wasn't large enough is to check the returned size and make
|
||||
// sure that it doesn't match the size of the array.
|
||||
// If it does we allocate a larger array and try again
|
||||
|
||||
// Stores the actual array
|
||||
DWORD *procArray = NULL;
|
||||
DWORD procArrayByteSz;
|
||||
int procArraySz = 0;
|
||||
|
||||
// Stores the byte size of the returned array from enumprocesses
|
||||
DWORD enumReturnSz = 0;
|
||||
|
||||
do {
|
||||
procArraySz += 1024;
|
||||
if (procArray != NULL)
|
||||
free(procArray);
|
||||
procArrayByteSz = procArraySz * sizeof(DWORD);
|
||||
procArray = malloc(procArrayByteSz);
|
||||
if (procArray == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) {
|
||||
free(procArray);
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return NULL;
|
||||
}
|
||||
} while (enumReturnSz == procArraySz * sizeof(DWORD));
|
||||
|
||||
// The number of elements is the returned size / size of each element
|
||||
*numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD);
|
||||
|
||||
return procArray;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_assert_pid_exists(DWORD pid, char *err) {
|
||||
if (PSUTIL_TESTING) {
|
||||
if (psutil_pid_in_pids(pid) == 0) {
|
||||
PyErr_SetString(PyExc_AssertionError, err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
psutil_assert_pid_not_exists(DWORD pid, char *err) {
|
||||
if (PSUTIL_TESTING) {
|
||||
if (psutil_pid_in_pids(pid) == 1) {
|
||||
PyErr_SetString(PyExc_AssertionError, err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/* Check for PID existance by using OpenProcess() + GetExitCodeProcess.
|
||||
/* Returns:
|
||||
* 1: pid exists
|
||||
* 0: it doesn't
|
||||
* -1: error
|
||||
*/
|
||||
int
|
||||
psutil_pid_is_running(DWORD pid) {
|
||||
HANDLE hProcess;
|
||||
DWORD exitCode;
|
||||
DWORD err;
|
||||
|
||||
// Special case for PID 0 System Idle Process
|
||||
if (pid == 0)
|
||||
return 1;
|
||||
if (pid < 0)
|
||||
return 0;
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
||||
FALSE, pid);
|
||||
if (NULL == hProcess) {
|
||||
err = GetLastError();
|
||||
// Yeah, this is the actual error code in case of "no such process".
|
||||
if (err == ERROR_INVALID_PARAMETER) {
|
||||
if (! psutil_assert_pid_not_exists(
|
||||
pid, "pir: OpenProcess() -> INVALID_PARAMETER")) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// Access denied obviously means there's a process to deny access to.
|
||||
else if (err == ERROR_ACCESS_DENIED) {
|
||||
if (! psutil_assert_pid_exists(
|
||||
pid, "pir: OpenProcess() ACCESS_DENIED")) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// Be strict and raise an exception; the caller is supposed
|
||||
// to take -1 into account.
|
||||
else {
|
||||
PyErr_SetFromOSErrnoWithSyscall("OpenProcess(PROCESS_VM_READ)");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetExitCodeProcess(hProcess, &exitCode)) {
|
||||
CloseHandle(hProcess);
|
||||
// XXX - maybe STILL_ACTIVE is not fully reliable as per:
|
||||
// http://stackoverflow.com/questions/1591342/#comment47830782_1591379
|
||||
if (exitCode == STILL_ACTIVE) {
|
||||
if (! psutil_assert_pid_exists(
|
||||
pid, "pir: GetExitCodeProcess() -> STILL_ACTIVE")) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// We can't be sure so we look into pids.
|
||||
else {
|
||||
return psutil_pid_in_pids(pid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = GetLastError();
|
||||
CloseHandle(hProcess);
|
||||
// Same as for OpenProcess, assume access denied means there's
|
||||
// a process to deny access to.
|
||||
if (err == ERROR_ACCESS_DENIED) {
|
||||
if (! psutil_assert_pid_exists(
|
||||
pid, "pir: GetExitCodeProcess() -> ERROR_ACCESS_DENIED")) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
PyErr_SetFromOSErrnoWithSyscall("GetExitCodeProcess");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Given a pointer into a process's memory, figure out how much data can be
|
||||
* read from it. */
|
||||
static int
|
||||
psutil_get_process_region_size(HANDLE hProcess, LPCVOID src, SIZE_T *psize) {
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
|
@ -431,14 +49,16 @@ enum psutil_process_data_kind {
|
|||
KIND_ENVIRON,
|
||||
};
|
||||
|
||||
/* Get data from the process with the given pid. The data is returned in the
|
||||
pdata output member as a nul terminated string which must be freed on
|
||||
success.
|
||||
|
||||
On success 0 is returned. On error the output parameter is not touched, -1
|
||||
is returned, and an appropriate Python exception is set. */
|
||||
/*
|
||||
* Get data from the process with the given pid. The data is returned
|
||||
* in the pdata output member as a nul terminated string which must be
|
||||
* freed on success.
|
||||
* On success 0 is returned. On error the output parameter is not touched,
|
||||
* -1 is returned, and an appropriate Python exception is set.
|
||||
*/
|
||||
static int
|
||||
psutil_get_process_data(long pid,
|
||||
psutil_get_process_data(DWORD pid,
|
||||
enum psutil_process_data_kind kind,
|
||||
WCHAR **pdata,
|
||||
SIZE_T *psize) {
|
||||
|
@ -466,14 +86,13 @@ psutil_get_process_data(long pid,
|
|||
http://stackoverflow.com/a/14012919
|
||||
http://www.drdobbs.com/embracing-64-bit-windows/184401966
|
||||
*/
|
||||
_NtQueryInformationProcess NtQueryInformationProcess = NULL;
|
||||
SIZE_T size = 0;
|
||||
#ifndef _WIN64
|
||||
static _NtQueryInformationProcess NtWow64QueryInformationProcess64 = NULL;
|
||||
static __NtQueryInformationProcess NtWow64QueryInformationProcess64 = NULL;
|
||||
static _NtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = NULL;
|
||||
#endif
|
||||
HANDLE hProcess = NULL;
|
||||
LPCVOID src;
|
||||
SIZE_T size;
|
||||
WCHAR *buffer = NULL;
|
||||
#ifdef _WIN64
|
||||
LPVOID ppeb32 = NULL;
|
||||
|
@ -492,7 +111,7 @@ psutil_get_process_data(long pid,
|
|||
#ifdef _WIN64
|
||||
/* 64 bit case. Check if the target is a 32 bit process running in WoW64
|
||||
* mode. */
|
||||
status = psutil_NtQueryInformationProcess(
|
||||
status = NtQueryInformationProcess(
|
||||
hProcess,
|
||||
ProcessWow64Information,
|
||||
&ppeb32,
|
||||
|
@ -512,7 +131,9 @@ psutil_get_process_data(long pid,
|
|||
|
||||
// read PEB
|
||||
if (!ReadProcessMemory(hProcess, ppeb32, &peb32, sizeof(peb32), NULL)) {
|
||||
PyErr_SetFromOSErrnoWithSyscall("ReadProcessMemory");
|
||||
// May fail with ERROR_PARTIAL_COPY, see:
|
||||
// https://github.com/giampaolo/psutil/issues/875
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -521,9 +142,11 @@ psutil_get_process_data(long pid,
|
|||
UlongToPtr(peb32.ProcessParameters),
|
||||
&procParameters32,
|
||||
sizeof(procParameters32),
|
||||
NULL)) {
|
||||
PyErr_SetFromOSErrnoWithSyscall(
|
||||
"ReadProcessMemory(ProcessParameters)");
|
||||
NULL))
|
||||
{
|
||||
// May fail with ERROR_PARTIAL_COPY, see:
|
||||
// https://github.com/giampaolo/psutil/issues/875
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -576,41 +199,44 @@ psutil_get_process_data(long pid,
|
|||
}
|
||||
}
|
||||
|
||||
if (! NT_SUCCESS(
|
||||
NtWow64QueryInformationProcess64(
|
||||
status = NtWow64QueryInformationProcess64(
|
||||
hProcess,
|
||||
ProcessBasicInformation,
|
||||
&pbi64,
|
||||
sizeof(pbi64),
|
||||
NULL)))
|
||||
{
|
||||
PyErr_SetFromOSErrnoWithSyscall(
|
||||
"NtWow64QueryInformationProcess64(ProcessBasicInformation)");
|
||||
NULL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(
|
||||
status,
|
||||
"NtWow64QueryInformationProcess64(ProcessBasicInformation)"
|
||||
);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// read peb
|
||||
if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
|
||||
status = NtWow64ReadVirtualMemory64(
|
||||
hProcess,
|
||||
pbi64.PebBaseAddress,
|
||||
&peb64,
|
||||
sizeof(peb64),
|
||||
NULL)))
|
||||
{
|
||||
PyErr_SetFromOSErrnoWithSyscall("NtWow64ReadVirtualMemory64");
|
||||
NULL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(status, "NtWow64ReadVirtualMemory64");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// read process parameters
|
||||
if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
|
||||
status = NtWow64ReadVirtualMemory64(
|
||||
hProcess,
|
||||
peb64.ProcessParameters,
|
||||
&procParameters64,
|
||||
sizeof(procParameters64),
|
||||
NULL)))
|
||||
{
|
||||
PyErr_SetFromOSErrnoWithSyscall(
|
||||
"NtWow64ReadVirtualMemory64(ProcessParameters)");
|
||||
NULL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(
|
||||
status,
|
||||
"NtWow64ReadVirtualMemory64(ProcessParameters)"
|
||||
);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -635,7 +261,7 @@ psutil_get_process_data(long pid,
|
|||
PEB_ peb;
|
||||
RTL_USER_PROCESS_PARAMETERS_ procParameters;
|
||||
|
||||
status = psutil_NtQueryInformationProcess(
|
||||
status = NtQueryInformationProcess(
|
||||
hProcess,
|
||||
ProcessBasicInformation,
|
||||
&pbi,
|
||||
|
@ -654,8 +280,11 @@ psutil_get_process_data(long pid,
|
|||
pbi.PebBaseAddress,
|
||||
&peb,
|
||||
sizeof(peb),
|
||||
NULL)) {
|
||||
PyErr_SetFromOSErrnoWithSyscall("ReadProcessMemory");
|
||||
NULL))
|
||||
{
|
||||
// May fail with ERROR_PARTIAL_COPY, see:
|
||||
// https://github.com/giampaolo/psutil/issues/875
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -664,9 +293,11 @@ psutil_get_process_data(long pid,
|
|||
peb.ProcessParameters,
|
||||
&procParameters,
|
||||
sizeof(procParameters),
|
||||
NULL)) {
|
||||
PyErr_SetFromOSErrnoWithSyscall(
|
||||
"ReadProcessMemory(ProcessParameters)");
|
||||
NULL))
|
||||
{
|
||||
// May fail with ERROR_PARTIAL_COPY, see:
|
||||
// https://github.com/giampaolo/psutil/issues/875
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -705,20 +336,22 @@ psutil_get_process_data(long pid,
|
|||
|
||||
#ifndef _WIN64
|
||||
if (weAreWow64 && !theyAreWow64) {
|
||||
if (! NT_SUCCESS(NtWow64ReadVirtualMemory64(
|
||||
status = NtWow64ReadVirtualMemory64(
|
||||
hProcess,
|
||||
src64,
|
||||
buffer,
|
||||
size,
|
||||
NULL)))
|
||||
{
|
||||
PyErr_SetFromOSErrnoWithSyscall("NtWow64ReadVirtualMemory64");
|
||||
NULL);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
psutil_SetFromNTStatusErr(status, "NtWow64ReadVirtualMemory64");
|
||||
goto error;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (!ReadProcessMemory(hProcess, src, buffer, size, NULL)) {
|
||||
PyErr_SetFromOSErrnoWithSyscall("ReadProcessMemory");
|
||||
// May fail with ERROR_PARTIAL_COPY, see:
|
||||
// https://github.com/giampaolo/psutil/issues/875
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -744,8 +377,8 @@ error:
|
|||
* AccessDenied. Requires Windows 8.1+.
|
||||
*/
|
||||
static int
|
||||
psutil_cmdline_query_proc(long pid, WCHAR **pdata, SIZE_T *psize) {
|
||||
HANDLE hProcess;
|
||||
psutil_cmdline_query_proc(DWORD pid, WCHAR **pdata, SIZE_T *psize) {
|
||||
HANDLE hProcess = NULL;
|
||||
ULONG bufLen = 0;
|
||||
NTSTATUS status;
|
||||
char * buffer = NULL;
|
||||
|
@ -765,16 +398,15 @@ psutil_cmdline_query_proc(long pid, WCHAR **pdata, SIZE_T *psize) {
|
|||
goto error;
|
||||
|
||||
// get the right buf size
|
||||
status = psutil_NtQueryInformationProcess(
|
||||
status = NtQueryInformationProcess(
|
||||
hProcess,
|
||||
ProcessCommandLineInformation,
|
||||
NULL,
|
||||
0,
|
||||
&bufLen);
|
||||
|
||||
// 0xC0000225 == STATUS_NOT_FOUND, see:
|
||||
// https://github.com/giampaolo/psutil/issues/1501
|
||||
if (status == 0xC0000225) {
|
||||
if (status == STATUS_NOT_FOUND) {
|
||||
AccessDenied("NtQueryInformationProcess(ProcessBasicInformation) -> "
|
||||
"STATUS_NOT_FOUND translated into PermissionError");
|
||||
goto error;
|
||||
|
@ -796,7 +428,7 @@ psutil_cmdline_query_proc(long pid, WCHAR **pdata, SIZE_T *psize) {
|
|||
}
|
||||
|
||||
// get the cmdline
|
||||
status = psutil_NtQueryInformationProcess(
|
||||
status = NtQueryInformationProcess(
|
||||
hProcess,
|
||||
ProcessCommandLineInformation,
|
||||
buffer,
|
||||
|
@ -838,7 +470,7 @@ error:
|
|||
* with given pid or NULL on error.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_get_cmdline(long pid, int use_peb) {
|
||||
psutil_get_cmdline(DWORD pid, int use_peb) {
|
||||
PyObject *ret = NULL;
|
||||
WCHAR *data = NULL;
|
||||
SIZE_T size;
|
||||
|
@ -899,7 +531,7 @@ out:
|
|||
|
||||
|
||||
PyObject *
|
||||
psutil_get_cwd(long pid) {
|
||||
psutil_get_cwd(DWORD pid) {
|
||||
PyObject *ret = NULL;
|
||||
WCHAR *data = NULL;
|
||||
SIZE_T size;
|
||||
|
@ -923,7 +555,7 @@ out:
|
|||
* process with given pid or NULL on error.
|
||||
*/
|
||||
PyObject *
|
||||
psutil_get_environ(long pid) {
|
||||
psutil_get_environ(DWORD pid) {
|
||||
PyObject *ret = NULL;
|
||||
WCHAR *data = NULL;
|
||||
SIZE_T size;
|
||||
|
@ -943,10 +575,11 @@ out:
|
|||
|
||||
/*
|
||||
* Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure
|
||||
* fills the structure with various process information by using
|
||||
* NtQuerySystemInformation.
|
||||
* fills the structure with various process information in one shot
|
||||
* by using NtQuerySystemInformation.
|
||||
* We use this as a fallback when faster functions fail with access
|
||||
* denied. This is slower because it iterates over all processes.
|
||||
* denied. This is slower because it iterates over all processes
|
||||
* but it doesn't require any privilege (also work for PID 0).
|
||||
* On success return 1, else 0 with Python exception already set.
|
||||
*/
|
||||
int
|
||||
|
@ -966,7 +599,7 @@ psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
|
|||
}
|
||||
|
||||
while (TRUE) {
|
||||
status = psutil_NtQuerySystemInformation(
|
||||
status = NtQuerySystemInformation(
|
||||
SystemProcessInformation,
|
||||
buffer,
|
||||
bufferSize,
|
||||
|
@ -997,14 +630,14 @@ psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
|
|||
|
||||
process = PSUTIL_FIRST_PROCESS(buffer);
|
||||
do {
|
||||
if (process->UniqueProcessId == (HANDLE)pid) {
|
||||
if ((ULONG_PTR)process->UniqueProcessId == pid) {
|
||||
*retProcess = process;
|
||||
*retBuffer = buffer;
|
||||
return 1;
|
||||
}
|
||||
} while ((process = PSUTIL_NEXT_PROCESS(process)));
|
||||
|
||||
NoSuchProcess("");
|
||||
NoSuchProcess("NtQuerySystemInformation (no PID found)");
|
||||
goto error;
|
||||
|
||||
error:
|
||||
|
@ -1012,3 +645,89 @@ error:
|
|||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get various process information by using NtQuerySystemInformation.
|
||||
* We use this as a fallback when faster functions fail with access
|
||||
* denied. This is slower because it iterates over all processes.
|
||||
* Returned tuple includes the following process info:
|
||||
*
|
||||
* - num_threads()
|
||||
* - ctx_switches()
|
||||
* - num_handles() (fallback)
|
||||
* - cpu_times() (fallback)
|
||||
* - create_time() (fallback)
|
||||
* - io_counters() (fallback)
|
||||
* - memory_info() (fallback)
|
||||
*/
|
||||
PyObject *
|
||||
psutil_proc_info(PyObject *self, PyObject *args) {
|
||||
DWORD pid;
|
||||
PSYSTEM_PROCESS_INFORMATION process;
|
||||
PVOID buffer;
|
||||
ULONG i;
|
||||
ULONG ctx_switches = 0;
|
||||
double user_time;
|
||||
double kernel_time;
|
||||
double create_time;
|
||||
PyObject *py_retlist;
|
||||
|
||||
if (! PyArg_ParseTuple(args, _Py_PARSE_PID, &pid))
|
||||
return NULL;
|
||||
if (! psutil_get_proc_info(pid, &process, &buffer))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < process->NumberOfThreads; i++)
|
||||
ctx_switches += process->Threads[i].ContextSwitches;
|
||||
user_time = (double)process->UserTime.HighPart * HI_T + \
|
||||
(double)process->UserTime.LowPart * LO_T;
|
||||
kernel_time = (double)process->KernelTime.HighPart * HI_T + \
|
||||
(double)process->KernelTime.LowPart * LO_T;
|
||||
|
||||
// Convert the LARGE_INTEGER union to a Unix time.
|
||||
// It's the best I could find by googling and borrowing code here
|
||||
// and there. The time returned has a precision of 1 second.
|
||||
if (0 == pid || 4 == pid) {
|
||||
// the python module will translate this into BOOT_TIME later
|
||||
create_time = 0;
|
||||
}
|
||||
else {
|
||||
create_time = psutil_LargeIntegerToUnixTime(process->CreateTime);
|
||||
}
|
||||
|
||||
py_retlist = Py_BuildValue(
|
||||
#if defined(_WIN64)
|
||||
"kkdddiKKKKKK" "kKKKKKKKKK",
|
||||
#else
|
||||
"kkdddiKKKKKK" "kIIIIIIIII",
|
||||
#endif
|
||||
process->HandleCount, // num handles
|
||||
ctx_switches, // num ctx switches
|
||||
user_time, // cpu user time
|
||||
kernel_time, // cpu kernel time
|
||||
create_time, // create time
|
||||
(int)process->NumberOfThreads, // num threads
|
||||
// IO counters
|
||||
process->ReadOperationCount.QuadPart, // io rcount
|
||||
process->WriteOperationCount.QuadPart, // io wcount
|
||||
process->ReadTransferCount.QuadPart, // io rbytes
|
||||
process->WriteTransferCount.QuadPart, // io wbytes
|
||||
process->OtherOperationCount.QuadPart, // io others count
|
||||
process->OtherTransferCount.QuadPart, // io others bytes
|
||||
// memory
|
||||
process->PageFaultCount, // num page faults
|
||||
process->PeakWorkingSetSize, // peak wset
|
||||
process->WorkingSetSize, // wset
|
||||
process->QuotaPeakPagedPoolUsage, // peak paged pool
|
||||
process->QuotaPagedPoolUsage, // paged pool
|
||||
process->QuotaPeakNonPagedPoolUsage, // peak non paged pool
|
||||
process->QuotaNonPagedPoolUsage, // non paged pool
|
||||
process->PagefileUsage, // pagefile
|
||||
process->PeakPagefileUsage, // peak pagefile
|
||||
process->PrivatePageCount // private
|
||||
);
|
||||
|
||||
free(buffer);
|
||||
return py_retlist;
|
||||
}
|
||||
|
|
|
@ -4,28 +4,18 @@
|
|||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#if !defined(__PROCESS_INFO_H)
|
||||
#define __PROCESS_INFO_H
|
||||
|
||||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
#include "security.h"
|
||||
#include "ntextapi.h"
|
||||
|
||||
#define HANDLE_TO_PYNUM(handle) PyLong_FromUnsignedLong((unsigned long) handle)
|
||||
#define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj))
|
||||
#define PSUTIL_FIRST_PROCESS(Processes) ( \
|
||||
(PSYSTEM_PROCESS_INFORMATION)(Processes))
|
||||
#define PSUTIL_NEXT_PROCESS(Process) ( \
|
||||
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \
|
||||
(PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \
|
||||
((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : NULL)
|
||||
|
||||
DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs);
|
||||
HANDLE psutil_handle_from_pid(DWORD pid, DWORD dwDesiredAccess);
|
||||
int psutil_pid_is_running(DWORD pid);
|
||||
int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
|
||||
PVOID *retBuffer);
|
||||
|
||||
int psutil_assert_pid_exists(DWORD pid, char *err);
|
||||
int psutil_assert_pid_not_exists(DWORD pid, char *err);
|
||||
|
||||
PyObject* psutil_get_cmdline(long pid, int use_peb);
|
||||
PyObject* psutil_get_cwd(long pid);
|
||||
PyObject* psutil_get_environ(long pid);
|
||||
|
||||
#endif
|
||||
PyObject* psutil_get_cmdline(DWORD pid, int use_peb);
|
||||
PyObject* psutil_get_cwd(DWORD pid);
|
||||
PyObject* psutil_get_environ(DWORD pid);
|
||||
PyObject* psutil_proc_info(PyObject *self, PyObject *args);
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Helper process functions.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
#include <Psapi.h> // EnumProcesses
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
#include "process_utils.h"
|
||||
|
||||
|
||||
DWORD *
|
||||
psutil_get_pids(DWORD *numberOfReturnedPIDs) {
|
||||
// Win32 SDK says the only way to know if our process array
|
||||
// wasn't large enough is to check the returned size and make
|
||||
// sure that it doesn't match the size of the array.
|
||||
// If it does we allocate a larger array and try again
|
||||
|
||||
// Stores the actual array
|
||||
DWORD *procArray = NULL;
|
||||
DWORD procArrayByteSz;
|
||||
int procArraySz = 0;
|
||||
|
||||
// Stores the byte size of the returned array from enumprocesses
|
||||
DWORD enumReturnSz = 0;
|
||||
|
||||
do {
|
||||
procArraySz += 1024;
|
||||
if (procArray != NULL)
|
||||
free(procArray);
|
||||
procArrayByteSz = procArraySz * sizeof(DWORD);
|
||||
procArray = malloc(procArrayByteSz);
|
||||
if (procArray == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
if (! EnumProcesses(procArray, procArrayByteSz, &enumReturnSz)) {
|
||||
free(procArray);
|
||||
PyErr_SetFromWindowsErr(0);
|
||||
return NULL;
|
||||
}
|
||||
} while (enumReturnSz == procArraySz * sizeof(DWORD));
|
||||
|
||||
// The number of elements is the returned size / size of each element
|
||||
*numberOfReturnedPIDs = enumReturnSz / sizeof(DWORD);
|
||||
|
||||
return procArray;
|
||||
}
|
||||
|
||||
|
||||
// Return 1 if PID exists, 0 if not, -1 on error.
|
||||
int
|
||||
psutil_pid_in_pids(DWORD pid) {
|
||||
DWORD *proclist = NULL;
|
||||
DWORD numberOfReturnedPIDs;
|
||||
DWORD i;
|
||||
|
||||
proclist = psutil_get_pids(&numberOfReturnedPIDs);
|
||||
if (proclist == NULL)
|
||||
return -1;
|
||||
for (i = 0; i < numberOfReturnedPIDs; i++) {
|
||||
if (proclist[i] == pid) {
|
||||
free(proclist);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
free(proclist);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Given a process handle checks whether it's actually running. If it
|
||||
// does return the handle, else return NULL with Python exception set.
|
||||
// This is needed because OpenProcess API sucks.
|
||||
HANDLE
|
||||
psutil_check_phandle(HANDLE hProcess, DWORD pid) {
|
||||
DWORD exitCode;
|
||||
|
||||
if (hProcess == NULL) {
|
||||
if (GetLastError() == ERROR_INVALID_PARAMETER) {
|
||||
// Yeah, this is the actual error code in case of
|
||||
// "no such process".
|
||||
NoSuchProcess("OpenProcess");
|
||||
return NULL;
|
||||
}
|
||||
PyErr_SetFromOSErrnoWithSyscall("OpenProcess");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (GetExitCodeProcess(hProcess, &exitCode)) {
|
||||
// XXX - maybe STILL_ACTIVE is not fully reliable as per:
|
||||
// http://stackoverflow.com/questions/1591342/#comment47830782_1591379
|
||||
if (exitCode == STILL_ACTIVE) {
|
||||
return hProcess;
|
||||
}
|
||||
if (psutil_pid_in_pids(pid) == 1) {
|
||||
return hProcess;
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
NoSuchProcess("GetExitCodeProcess != STILL_ACTIVE");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_ACCESS_DENIED) {
|
||||
psutil_debug("GetExitCodeProcess -> ERROR_ACCESS_DENIED (ignored)");
|
||||
SetLastError(0);
|
||||
return hProcess;
|
||||
}
|
||||
PyErr_SetFromOSErrnoWithSyscall("GetExitCodeProcess");
|
||||
CloseHandle(hProcess);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// A wrapper around OpenProcess setting NSP exception if process no
|
||||
// longer exists. *pid* is the process PID, *access* is the first
|
||||
// argument to OpenProcess.
|
||||
// Return a process handle or NULL with exception set.
|
||||
HANDLE
|
||||
psutil_handle_from_pid(DWORD pid, DWORD access) {
|
||||
HANDLE hProcess;
|
||||
|
||||
if (pid == 0) {
|
||||
// otherwise we'd get NoSuchProcess
|
||||
return AccessDenied("automatically set for PID 0");
|
||||
}
|
||||
|
||||
hProcess = OpenProcess(access, FALSE, pid);
|
||||
|
||||
if ((hProcess == NULL) && (GetLastError() == ERROR_ACCESS_DENIED)) {
|
||||
PyErr_SetFromOSErrnoWithSyscall("OpenProcess");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hProcess = psutil_check_phandle(hProcess, pid);
|
||||
return hProcess;
|
||||
}
|
||||
|
||||
|
||||
// Check for PID existance. Return 1 if pid exists, 0 if not, -1 on error.
|
||||
int
|
||||
psutil_pid_is_running(DWORD pid) {
|
||||
HANDLE hProcess;
|
||||
|
||||
// Special case for PID 0 System Idle Process
|
||||
if (pid == 0)
|
||||
return 1;
|
||||
if (pid < 0)
|
||||
return 0;
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
||||
|
||||
// Access denied means there's a process to deny access to.
|
||||
if ((hProcess == NULL) && (GetLastError() == ERROR_ACCESS_DENIED))
|
||||
return 1;
|
||||
|
||||
hProcess = psutil_check_phandle(hProcess, pid);
|
||||
if (hProcess != NULL) {
|
||||
CloseHandle(hProcess);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CloseHandle(hProcess);
|
||||
PyErr_Clear();
|
||||
return psutil_pid_in_pids(pid);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs);
|
||||
HANDLE psutil_handle_from_pid(DWORD pid, DWORD dwDesiredAccess);
|
||||
int psutil_pid_is_running(DWORD pid);
|
||||
int psutil_assert_pid_exists(DWORD pid, char *err);
|
||||
int psutil_assert_pid_not_exists(DWORD pid, char *err);
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <windows.h>
|
||||
#include <Python.h>
|
||||
|
||||
#include "../../_psutil_common.h"
|
||||
|
||||
|
||||
|
@ -119,7 +120,6 @@ psutil_print_err() {
|
|||
int
|
||||
psutil_set_se_debug() {
|
||||
HANDLE hToken;
|
||||
int err = 1;
|
||||
|
||||
if ((hToken = psutil_get_thisproc_token()) == NULL) {
|
||||
// "return 1;" to get an exception
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче