summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
authorimasaki@google.com <imasaki@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-07 01:56:56 +0000
committerimasaki@google.com <imasaki@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-07 01:56:56 +0000
commit81b941e97497d337f742aa7b499435709e769bc2 (patch)
tree295240e93e7c6ae02b8dd4fa083c43318f654395 /third_party
parentc1795d643965e35276dfef1fa390df9bbdb11289 (diff)
downloadchromium_src-81b941e97497d337f742aa7b499435709e769bc2.zip
chromium_src-81b941e97497d337f742aa7b499435709e769bc2.tar.gz
chromium_src-81b941e97497d337f742aa7b499435709e769bc2.tar.bz2
Update third_party/psutil and fix the licence issue with it.
BUG=98456 TEST=None Review URL: http://codereview.chromium.org/8159001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@104425 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
-rw-r--r--third_party/psutil/CREDITS24
-rw-r--r--third_party/psutil/HISTORY95
-rw-r--r--third_party/psutil/MANIFEST.in1
-rw-r--r--third_party/psutil/README22
-rw-r--r--third_party/psutil/README.chromium4
-rw-r--r--third_party/psutil/docs/BUILDING.txt37
-rwxr-xr-xthird_party/psutil/docs/class_diagram.pngbin0 -> 66252 bytes
-rw-r--r--third_party/psutil/docs/documentation.html220
-rw-r--r--third_party/psutil/docs/index.html140
-rw-r--r--third_party/psutil/examples/disk_usage.py43
-rw-r--r--third_party/psutil/examples/iotop.py136
-rw-r--r--third_party/psutil/examples/killall.py33
-rw-r--r--third_party/psutil/examples/process_detail.py122
-rw-r--r--third_party/psutil/psutil/__init__.py531
-rw-r--r--third_party/psutil/psutil/_common.py69
-rw-r--r--third_party/psutil/psutil/_compat.py154
-rw-r--r--third_party/psutil/psutil/_psbsd.py183
-rwxr-xr-x[-rw-r--r--]third_party/psutil/psutil/_pslinux.py672
-rw-r--r--third_party/psutil/psutil/_psmswindows.py222
-rw-r--r--third_party/psutil/psutil/_psosx.py188
-rw-r--r--third_party/psutil/psutil/_psposix.py92
-rw-r--r--third_party/psutil/psutil/_psutil_bsd.c667
-rw-r--r--third_party/psutil/psutil/_psutil_bsd.h20
-rw-r--r--third_party/psutil/psutil/_psutil_common.c39
-rw-r--r--third_party/psutil/psutil/_psutil_common.h13
-rw-r--r--third_party/psutil/psutil/_psutil_linux.c211
-rw-r--r--third_party/psutil/psutil/_psutil_linux.h16
-rw-r--r--third_party/psutil/psutil/_psutil_mswindows.c1046
-rw-r--r--third_party/psutil/psutil/_psutil_mswindows.h28
-rw-r--r--third_party/psutil/psutil/_psutil_osx.c1161
-rw-r--r--third_party/psutil/psutil/_psutil_osx.h22
-rw-r--r--third_party/psutil/psutil/_psutil_posix.c134
-rw-r--r--third_party/psutil/psutil/_psutil_posix.h15
-rw-r--r--third_party/psutil/psutil/arch/bsd/process_info.c28
-rw-r--r--third_party/psutil/psutil/arch/bsd/process_info.h7
-rw-r--r--third_party/psutil/psutil/arch/mswindows/ntextapi.h183
-rw-r--r--third_party/psutil/psutil/arch/mswindows/process_handles.c9
-rw-r--r--third_party/psutil/psutil/arch/mswindows/process_handles.h8
-rw-r--r--third_party/psutil/psutil/arch/mswindows/process_info.c169
-rw-r--r--third_party/psutil/psutil/arch/mswindows/process_info.h9
-rw-r--r--third_party/psutil/psutil/arch/mswindows/security.c17
-rw-r--r--third_party/psutil/psutil/arch/mswindows/security.h6
-rw-r--r--third_party/psutil/psutil/arch/osx/process_info.c249
-rw-r--r--third_party/psutil/psutil/arch/osx/process_info.h11
-rw-r--r--third_party/psutil/psutil/compat.py111
-rw-r--r--third_party/psutil/psutil/error.py26
-rw-r--r--third_party/psutil/setup.py89
-rw-r--r--third_party/psutil/test/_bsd.py67
-rw-r--r--third_party/psutil/test/_linux.py37
-rw-r--r--third_party/psutil/test/_osx.py43
-rwxr-xr-x[-rw-r--r--]third_party/psutil/test/_posix.py49
-rw-r--r--third_party/psutil/test/_windows.py35
-rw-r--r--third_party/psutil/test/test_memory_leaks.py181
-rw-r--r--third_party/psutil/test/test_psutil.py1265
54 files changed, 6608 insertions, 2351 deletions
diff --git a/third_party/psutil/CREDITS b/third_party/psutil/CREDITS
index 1ac44fb..b39f05b 100644
--- a/third_party/psutil/CREDITS
+++ b/third_party/psutil/CREDITS
@@ -28,6 +28,10 @@ W: http://www.jayloden.com
Contributors
============
+N: Jeremy Whitlock
+E: jcscoobyrs@gmail.com
+I: 125, 150, 174, 206
+
N: wj32
E: wj32.64@gmail.com
D: process username() and get_connections() on Windows
@@ -46,3 +50,23 @@ N: cjgohlke
E: cjgohlke@gmail.com
D: Windows 64 bit support
I: 107
+
+N: Jeffery Kline
+E: jeffery.kline@gmail.com
+I: 130
+
+N: Grabriel Monnerat
+E: gabrielmonnerat@gmail.com
+I: 146
+
+N: Philip Roberts
+E: philip.roberts@gmail.com
+I: 168
+
+N: jcscoobyrs
+E: jcscoobyrs@gmail.com
+I: 125
+
+N: Sandro Tosi
+E: sandro.tosi@gmail.com
+I: 200, 201
diff --git a/third_party/psutil/HISTORY b/third_party/psutil/HISTORY
index 3e4ce96..40ea22e 100644
--- a/third_party/psutil/HISTORY
+++ b/third_party/psutil/HISTORY
@@ -1,5 +1,100 @@
Bug tracker at http://code.google.com/p/psutil/issues
+0.3.1 - XXXX-XX-XX
+------------------
+
+NEW FEATURES
+
+ * Issue 150: network I/O counters. (OSX patch by Jeremy Whitlock)
+ * Issue 198: Process.wait(timeout=0) can now be used to make wait() return
+ immediately.
+ * Issue 206: disk I/O counters. (OSX patch by Jeremy Whitlock)
+
+BUGFIXES
+
+ * Issue 135: (OS X) psutil cannot create Process object
+ * Issue 144: (Linux) no longer support 0 special PID.
+ * Issue 188: (Linux) psutil import error on Linux ARM architectures.
+ * Issue 197: (Linux) Process.get_connections() is broken on platforms not
+ supporting IPv6.
+ * Issue 200: (Linux) psutil.NUM_CPUS not working on armel and sparc
+ architectures and causing crash on module import.
+ * Issue 201: (Linux) Process.get_connections() is broken on big-endian
+ architectures.
+ * Issue 211: Process instance can unexpectedly raise NoSuchProcess if tested
+ for equality with another object.
+
+
+0.3.0 - 2011-07-08
+------------------
+
+NEW FEATURES
+
+ * Issue 125: system per-cpu percentage utilization and times.
+ * Issue 163: per-process associated terminal (TTY).
+ * Issue 171: added get_phymem() and get_virtmem() functions returning system
+ memory information (total, used, free) and memory percent usage.
+ total_* avail_* and used_* memory functions are deprecated.
+ * Issue 172: disk usage statistics.
+ * Issue 174: mounted disk partitions.
+ * Issue 179: setuptools is now used in setup.py
+
+BUGFIXES
+
+ * Issue 159: SetSeDebug() does not close handles or unset impersonation on
+ return.
+ * Issue 164: wait function raises a TimeoutException when a process returns
+ -1 (Windows).
+ * Issue 165: process.status raises an unhandled exception.
+ * Issue 166: get_memory_info() leaks handles hogging system resources.
+ * Issue 168: psutil.cpu_percent() returns erroneous results when used in
+ non-blocking mode. (patch by Philip Roberts)
+ * Issue 178: OSX - Process.get_threads() leaks memory
+ * Issue 180: Windows - Process's get_num_threads() and get_threads() methods
+ can raise NoSuchProcess exception while process still exists.
+
+
+0.2.1 - 2011-03-20
+------------------
+
+NEW FEATURES
+
+ * Issue 64: per-process I/O counters.
+ * Issue 116: per-process wait() (wait for process to terminate and return its
+ exit code).
+ * Issue 134: per-process get_threads() returning information (id, user and
+ kernel times) about threads opened by process.
+ * Issue 136: process executable path on FreeBSD is now determined by asking
+ the kernel instead of guessing it from cmdline[0].
+ * Issue 137: per-process real, effective and saved user and group ids.
+ * Issue 140: system boot time.
+ * Issue 142: per-process get and set niceness (priority).
+ * Issue 143: per-process status.
+ * Issue 147: per-process I/O nice (priority) - Linux only.
+ * Issue 148: psutil.Popen class which tidies up subprocess.Popen and
+ psutil.Process in a unique interface.
+ * Issue 152: (OSX) get_process_open_files() implementation has been rewritten
+ in C and no longer relies on lsof resulting in a 3x speedup.
+ * Issue 153: (OSX) get_process_connection() implementation has been rewritten
+ in C and no longer relies on lsof resulting in a 3x speedup.
+
+BUGFIXES
+
+ * Issue 83: process cmdline is empty on OSX 64-bit.
+ * Issue 130: a race condition can cause IOError exception be raised on
+ Linux if process disappears between open() and subsequent read() calls.
+ * Issue 145: WindowsError was raised instead of psutil.AccessDenied when using
+ process resume() or suspend() on Windows.
+ * Issue 146: 'exe' property on Linux can raise TypeError if path contains NULL
+ bytes.
+ * Issue 151: exe and getcwd() for PID 0 on Linux return inconsistent data.
+
+API CHANGES
+
+ * Process "uid" and "gid" properties are deprecated in favor of "uids" and
+ "gids" properties.
+
+
0.2.0 - 2010-11-13
------------------
diff --git a/third_party/psutil/MANIFEST.in b/third_party/psutil/MANIFEST.in
index 1fc8328..2018576 100644
--- a/third_party/psutil/MANIFEST.in
+++ b/third_party/psutil/MANIFEST.in
@@ -7,3 +7,4 @@ include setup.py
recursive-include docs *.html *.dia *.png
recursive-include psutil *.py *.c *.h
recursive-include test *.py
+recursive-include examples *.py
diff --git a/third_party/psutil/README b/third_party/psutil/README
index feffe98..18ca454 100644
--- a/third_party/psutil/README
+++ b/third_party/psutil/README
@@ -19,7 +19,7 @@ The easiest way to install psutil from sources is using easy_install.
Get the latest easy_install version from http://pypi.python.org/pypi/setuptools
and just run:
- > python easy_install psutil
+ > easy_install psutil
This should get the most updated psutil version from the Python pypi repository,
unpack it, compile it and install it automatically.
@@ -80,11 +80,11 @@ commands:
to build only:
- > ./setup.py build
+ > python setup.py build
to install and build:
- > ./setup.py install
+ > python setup.py install
NOTE: due to developer's hardware limitations psutil has only been compiled and
tested on OS X 10.4.11 so may or may not work on other versions.
@@ -99,20 +99,22 @@ the standard distutils commands:
build only:
- > ./setup.py build
+ > python setup.py build
install and build:
- > ./setup.py install
+ > python setup.py install
Installing on Linux
===================
-Standard distutils installation steps should apply here. At the current time
-the Linux port of psutil does not require any C modules, so can be installed
-without need for a compiler using disutils:
+gcc is required and so the python headers. They can easily be installed by using
+the distro package manager. For example, on Ubuntu:
-install/build:
+ > sudo apt-get install python-dev
+
+Once done, you can install/build psutil with:
+
+ > python setup.py install
- > ./setup.py install
diff --git a/third_party/psutil/README.chromium b/third_party/psutil/README.chromium
index 25e7e23..7e0dd2f 100644
--- a/third_party/psutil/README.chromium
+++ b/third_party/psutil/README.chromium
@@ -1,9 +1,10 @@
Name: Python process utilities
Short Name: psutil
URL: http://code.google.com/p/psutil/
-Version: 0.2.0
+Version: 0.3.1
License: BSD
License File: LICENSE
+Security Critical: Yes
Description:
psutil is a module providing an interface for retrieving information
@@ -11,7 +12,6 @@ on running processes and system utilization (CPU, memory) in a portable
way by using Python, implementing many functionalities offered by
command line tools like ps, top, kill, lsof and netstat.
-
Local Modifications:
None
diff --git a/third_party/psutil/docs/BUILDING.txt b/third_party/psutil/docs/BUILDING.txt
new file mode 100644
index 0000000..14dc8a1
--- /dev/null
+++ b/third_party/psutil/docs/BUILDING.txt
@@ -0,0 +1,37 @@
+_OS X_
+INSTALL FROM SOURCE
+ python setup.py install
+
+
+CREATE AN INSTALLER PACKAGE
+ #NOTE: this requires bdist_mkpkg utility to create the binary installer
+ # http://pypi.python.org/pypi/bdist_mpkg/
+ #
+ # --open opens the installer after build
+ bdist_mpkg --license LICENSE --readme HISTORY
+
+ # build for older Python
+ /Library/Frameworks/Python.framework/Versions/2.5/bin/bdist_mpkg
+
+
+CREATE A DMG OF THE INSTALLER
+ # fill in directory/filenames as appropriate for srcfolder, volname
+ # and the output dmg file
+ hdiutil create -fs HFS+ -srcfolder psutil-0.1.1-py2.6-macosx10.4.mpkg -volname psutil-0.1.1 psutil-0.1.1-py2.6-macosx10.4.dmg
+
+
+UPLOAD TO GOOGLE CODE
+ # fill in summary and file name
+ googlecode_upload.py -s "Python 2.6 OS X Installer/Binary distribution" -p psutil dist/psutil-0.1.1-py2.6-macosx10.4.dmg
+
+
+__WINDOWS__
+INSTALL FROM SOURCE
+
+ # if Visual studio
+ python setup.py install
+
+ # mingw
+ python setup.py build -c mingw32
+
+
diff --git a/third_party/psutil/docs/class_diagram.png b/third_party/psutil/docs/class_diagram.png
new file mode 100755
index 0000000..22a035e
--- /dev/null
+++ b/third_party/psutil/docs/class_diagram.png
Binary files differ
diff --git a/third_party/psutil/docs/documentation.html b/third_party/psutil/docs/documentation.html
index 990913e..35adcb9 100644
--- a/third_party/psutil/docs/documentation.html
+++ b/third_party/psutil/docs/documentation.html
@@ -1,77 +1,167 @@
-<html>
- <head>
- <title>Documentation</title>
- </head>
- <body>
-
-<style>
-.
-</style>
+<!-- saved from url=(0066)http://code.google.com/p/psutil/wiki/DocumentationDev?show=content -->
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>DocumentationDev</title>
+ <script src="./documentation_files/googleapis.client__plusone.js"></script></head>
+ <body>
+
- <div id="wikicontent">
- <table width="100%" border="0" cellspacing="0" cellpadding="0">
- <tr>
- <td class="vt" id="wikimaincol" width="100%">
- <div id="wikiheader" style="margin-bottom:1em">
- </div>
- <h1><a name="API_Reference"></a>API Reference<a href="#API_Reference" class="section_anchor"></a></h1><h2><a name="Exceptions"></a>Exceptions<a href="#Exceptions" class="section_anchor"></a></h2><p>psutil.<strong>NoSuchProcess</strong><font size="3"><strong><tt>(</tt></strong></font><i>pid, name=None, msg=None</i><font size="3"><strong><tt>)</tt></strong></font> <blockquote>Raised when no process with the given PID was found in the current process list or when a process no longer exists (zombie).
-</blockquote></p><blockquote><i>Changed in 0.2.0: <tt>pid</tt>, <tt>name</tt> and <tt>msg</tt> arguments were added </i>
-</blockquote><p>psutil.<strong>AccessDenied</a></strong><font size="3"><strong><tt>(</tt></strong></font><i>pid=None, name=None, msg=None</i><font size="3"><strong><tt>)</tt></strong></font> <blockquote>Raised when permission to perform an action is denied.
-</blockquote></p><blockquote><i>Changed in 0.2.0: <tt>pid</tt>, <tt>name</tt> and <tt>msg</tt> arguments were added </i>
-</blockquote><hr/><h2><a name="Classes"></a>Classes<a href="#Classes" class="section_anchor"></a></h2><p>psutil.<strong>Process</strong><font size="3"><strong><tt>(</tt></strong></font><i>pid</i><font size="3"><strong><tt>)</tt></strong></font> </p><blockquote>A class which represents an OS process.
-</blockquote><ul><li><strong>pid</strong><br>The process pid. </li></ul><ul><li><strong>ppid</strong><br>The process parent pid. </li></ul><ul><li><strong>parent</strong><br>Return the parent process as a <tt>Process</tt> object. If no ppid is known then return <tt>None</tt>. </li></ul><ul><li><strong>name</strong><br>The process name. </li></ul><ul><li><strong>exe</strong><br>The process executable as an absolute path name. </li></ul><blockquote><i>New in 0.2.0</i>
-</blockquote><ul><li><strong>cmdline</strong><br>The command line process has been called with. </li></ul><ul><li><strong>path</strong><br>The process path. </li></ul><blockquote><i>Deprecated in 0.2.0</i>
-</blockquote><ul><li><strong>create_time</strong><br> The process creation time as a floating point number expressed in seconds since the epoch, in <a href="http://en.wikipedia.org/wiki/Coordinated_Universal_Time" rel="nofollow">UTC</a>. </li></ul><ul><li><strong>uid</strong><br>The real user id of the current process. Where uid doesn&#x27;t make sense (<i>Windows</i>) always return <tt>-1</tt>. </li></ul><ul><li><strong>gid</strong><br>The real group id of the current process. Where gid doesn&#x27;t make sense (<i>Windows</i>) always return <tt>-1</tt>. </li></ul><ul><li><strong>username</strong><br>The name of the user that owns the process. </li></ul><blockquote><i>Changed in 2.0: Windows implementation has been rewritten in C for performace and <a href="http://sourceforge.net/projects/pywin32/" rel="nofollow">pywin32</a> extension is no longer required.</i>
-</blockquote><ul><li><strong>getcwd</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return a string representing the process current working directory. </li></ul><ul><li><strong>get_num_threads</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return the number of threads used by this process. </li></ul><blockquote><i>New in 0.2.0</i>
-</blockquote><ul><li><strong>get_cpu_times</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return a tuple whose values are process CPU user and system times which means the amount of time expressed in seconds that a process has spent in <a href="http://stackoverflow.com/questions/556405/what-do-real-user-and-sys-mean-in-the-output-of-time1" rel="nofollow">user/system mode</a>. </li></ul><ul><li><strong>cpu_percent</strong><font size="3"><strong><tt>(</tt></strong></font><i>interval=0.1</i><font size="3"><strong><tt>)</tt></strong></font><br>Return a float representing the process CPU utilization as a percentage. When interval is &gt; 0.0 compares process times to system CPU times elapsed before and after the interval (blocking). When interval is 0.0 or None compares process times to system CPU times elapsed since last call, returning immediately. In this case is recommended for accuracy that this function be called with at least 0.1 seconds between calls. </li></ul><blockquote><i>Changed in 0.2.0: interval parameter was added</i>
-</blockquote><ul><li><strong>get_memory_info</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return a tuple representing <a href="http://en.wikipedia.org/wiki/Resident_Set_Size" rel="nofollow">RSS</a> (Resident Set Size) and VMS (Virtual Memory Size) in bytes.<br>On UNIX RSS and VMS are the same values shown by ps. On Windows RSS and VMS refer to &quot;Mem Usage&quot; and &quot;VM Size&quot; columns of taskmgr.exe. </li></ul><ul><li><strong>get_memory_percent</strong><font size="3"><strong><tt>()</tt></strong></font><br>Compare physical system memory to process resident memory and calculate process memory utilization as a percentage. </li></ul><ul><li><strong>get_children</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return the children of this process as a list of <tt>Process</tt> objects. </li></ul><blockquote><i>New in 0.2.0</i>
-</blockquote><ul><li><strong>get_open_files</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return files opened by process as a list of <a href="http://docs.python.org/library/collections.html?highlight=namedtuple#collections.namedtuple" rel="nofollow">namedtuples</a> including file absolute path name and file descriptor. On <strong>OSX</strong> and <strong>FreeBSD</strong> this is done by parsing <a href="http://en.wikipedia.org/wiki/Lsof" rel="nofollow">lsof</a> command output. If lsof is not installed on the system <a href="http://docs.python.org/library/exceptions.html?highlight=notimplementederror#exceptions.NotImplementedError" rel="nofollow">NotImplementedError</a> exception is raised. Example: </li><pre class="prettyprint">&gt;&gt;&gt; import psutil, os
-&gt;&gt;&gt; f = open(&#x27;file.ext&#x27;, &#x27;w&#x27;)
-&gt;&gt;&gt; psutil.Process(os.getpid()).get_open_files()
-[openfile(path=&#x27;/home/giampaolo/svn/psutil/file.ext&#x27;, fd=3)]</pre></ul><blockquote><i>New in 0.2.0</i>
-</blockquote><ul><li><strong>get_connections</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return all TCP and UPD connections opened by process as a list of <a href="http://docs.python.org/library/collections.html?highlight=namedtuple#collections.namedtuple" rel="nofollow">namedtuples</a>. Every namedtuple provides 6 attributes:<br></br> </li><ul><li><strong>fd</strong>: the socket file descriptor. This can be passed to <a href="http://docs.python.org/library/socket.html#socket.fromfd" rel="nofollow">socket.fromfd</a> to obtain a usable socket object. This is only available on UNIX; on Windows <tt>-1</tt> is always returned.<br> </li><li><strong>family</strong>: the address family, either <a href="http://docs.python.org/library/socket.html#socket.AF_INET" rel="nofollow">AF_INET</a> or <a href="http://docs.python.org/library/socket.html#socket.AF_INET6" rel="nofollow">AF_INET6</a> <br> </li><li><strong>type</strong>: the address type, either <a href="http://docs.python.org/library/socket.html#socket.SOCK_STREAM" rel="nofollow">SOCK_STREAM</a> or <a href="http://docs.python.org/library/socket.html#socket.SOCK_DGRAM" rel="nofollow">SOCK_DGRAM</a> <br> </li><li><strong>local_address</strong>: the local address as a <tt>(ip, port)</tt> tuple. <br> </li><li><strong>remote_address</strong>: the remote address as a <tt>(ip, port)</tt> tuple. When the remote endpoint is not connected the tuple is empty. <br> </li><li><strong>status</strong>: a string representing the TCP connections status. String values are supposed to match Linux&#x27;s <a href="http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h" rel="nofollow">tcp_states.h</a> header file across all platforms. For UDP sockets this is always going to be an empty string.<br> </li></ul></ul><blockquote>Example:
+<div>
+<table>
+ <tbody><tr>
+
+
+ <td style="vertical-align:top; padding-left:5px">
+
+ <div id="wikicontent">
+ <div class="vt" id="wikimaincol">
+ <h1><a name="API_Reference"></a>API Reference<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#API_Reference" class="section_anchor"></a></h1><h2><a name="Exceptions"></a>Exceptions<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#Exceptions" class="section_anchor"></a></h2><p>psutil.<strong>NoSuchProcess</strong><font size="3"><strong><tt>(</tt></strong></font><i>pid, name=None, msg=None</i><font size="3"><strong><tt>)</tt></strong></font> </p><blockquote>Raised when no process with the given PID is found in the current process list or when a process no longer exists (zombie).
+</blockquote><p></p><p>psutil.<strong>AccessDenied</strong><font size="3"><strong><tt>(</tt></strong></font><i>pid=None, name=None, msg=None</i><font size="3"><strong><tt>)</tt></strong></font> </p><blockquote>Raised when permission to perform an action is denied.
+</blockquote><p></p><p>psutil.<strong>TimeoutExpired</strong><font size="3"><strong><tt>(</tt></strong></font><i>pid=None, name=None</i><font size="3"><strong><tt>)</tt></strong></font> </p><blockquote>Raised on <tt>Process.wait(timeout)</tt> if timeout expires and process is still alive.
+</blockquote><p></p><blockquote><i><strong>New in 0.2.1</strong></i>
+</blockquote><hr><h2><a name="Classes"></a>Classes<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#Classes" class="section_anchor"></a></h2><p>psutil.<strong>Process</strong><font size="3"><strong><tt>(</tt></strong></font><i>pid</i><font size="3"><strong><tt>)</tt></strong></font> </p><blockquote>A class which represents an OS process.
+</blockquote><ul><li><strong>pid</strong><br>The process pid. </li></ul><ul><li><strong>ppid</strong><br>The process parent pid. </li></ul><ul><li><strong>parent</strong><br>Return the parent process as a <tt>Process</tt> object. If no ppid is known then return <tt>None</tt>. </li></ul><ul><li><strong>name</strong><br>The process name. </li></ul><ul><li><strong>exe</strong><br>The process executable as an absolute path name. </li></ul><ul><li><strong>cmdline</strong><br>The command line process has been called with. </li></ul><ul><li><strong>create_time</strong><br> The process creation time as a floating point number expressed in seconds since the epoch, in <a href="http://en.wikipedia.org/wiki/Coordinated_Universal_Time" rel="nofollow">UTC</a>. </li><pre class="prettyprint">&gt;&gt;&gt; import os, psutil, datetime
+&gt;&gt;&gt; p = psutil.Process(os.getpid())
+&gt;&gt;&gt; p.create_time
+1307289803.47
+&gt;&gt;&gt; datetime.datetime.fromtimestamp(p.create_time).strftime("%Y-%M-%d %H:%M")
+'2011-03-05 18:03'</pre></ul><ul><li><strong>uids</strong><br>The <i>real</i>, <i>effective</i> and <i>saved</i> user ids of the current process as a nameduple. This is the same as <a href="http://docs.python.org/library/os.html#os.getresuid" rel="nofollow">os.getresuid()</a> but per-process. </li></ul><blockquote><i><strong>New in 0.2.1</strong></i><br><strong><i>Availability:</i></strong><i> UNIX</i>
+</blockquote><ul><li><strong>gids</strong><br>The <i>real</i>, <i>effective</i> and <i>saved</i> group ids of the current process as a nameduple. This is the same as <a href="http://docs.python.org/library/os.html#os.getresgid" rel="nofollow">os.getresgid()</a> but per-process. </li></ul><blockquote><i><strong>New in 0.2.1</strong></i><br><i><strong>Availability:</strong> UNIX</i>
+</blockquote><ul><li><strong>username</strong><br>The name of the user that owns the process. On UNIX this is calculated by using <i>real</i> process uid. </li></ul><blockquote><i><strong>Changed in 2.0:</strong> Windows implementation has been rewritten in C for performace and <a href="http://sourceforge.net/projects/pywin32/" rel="nofollow">pywin32</a> extension is no longer required.</i>
+</blockquote><ul><li><strong>terminal</strong><br>The terminal associated with this process, if any, else None. This is similar to "tty" command but per-process. </li></ul><blockquote><i><strong>New in 0.3.0</strong></i><br><i><strong>Availability:</strong> UNIX</i>
+</blockquote><ul><li><strong>status</strong><br>The current process status. The return value is one of the <tt>STATUS_*</tt> constants, which is an integer that can be used in conjunction with str() to obtain a human-readable form of the current process status. Example: </li><pre class="prettyprint">&gt;&gt;&gt; import psutil, os
+&gt;&gt;&gt; p = psutil.Process(os.getpid())
+&gt;&gt;&gt; p.status
+0
+&gt;&gt;&gt; p.status == psutil.STATUS_RUNNING
+True
+&gt;&gt;&gt; str(p.status)
+'running'
+&gt;&gt;&gt;</pre></ul><blockquote><i><strong>New in 2.1</strong></i>
+</blockquote><ul><li><strong>nice</strong><br>Get or set process <a href="http://blogs.techrepublic.com.com/opensource/?p=140" rel="nofollow">niceness</a> (priority). On UNIX this is a number which usually goes from -20 to 20. The higher the nice value, the lower the priority of the process. </li><pre class="prettyprint">&gt;&gt;&gt; p = psutil.Process(os.getpid())
+&gt;&gt;&gt; p.nice
+0
+&gt;&gt;&gt; p.nice = 10 # set/change process priority
+&gt;&gt;&gt; p.nice
+10</pre></ul><blockquote>On Windows this is available as well by using <a href="http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx" rel="nofollow">GetPriorityClass</a> and <a href="http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx" rel="nofollow">SetPriorityClass</a>. <tt>psutil.*_PRIORITY_CLASS</tt> constants (explained <a href="http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx" rel="nofollow">here</a>) can be used in conjunction. Example which increases process priority:
+</blockquote><blockquote><pre class="prettyprint">&gt;&gt; p.nice = psutil.HIGH_PRIORITY_CLASS</pre>
+</blockquote><blockquote><i><strong>New in 2.1</strong></i>
+</blockquote><ul><li><strong>getcwd</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return a string representing the process current working directory. </li></ul><blockquote><i><strong>Availability:</strong> Windows, Linux</i>
+</blockquote><ul><li><strong>get_io_counters</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return process I/O statistics as a namedtuple including the number of read and write operations performed by the process and the amount of bytes read and written. For linux refer to <a href="http://www.mjmwired.net/kernel/Documentation/filesystems/proc.txt#1304" rel="nofollow">/proc filesysem documentation</a>. On BSD there's apparently no way to retrieve bytes counters, hence <tt>-1</tt> is returned for <tt>read_bytes</tt> and <tt>write_bytes</tt> fields. OSX is not supported. </li><pre class="prettyprint">&gt;&gt;&gt; p.get_io_counters()
+io(read_count=454556, write_count=3456, read_bytes=110592, write_bytes=0)</pre></ul><blockquote><i><strong>New in 2.1</strong></i><br><i><strong>Availability:</strong> Linux, Windows, FreeBSD</i>
+</blockquote><ul><li><strong>get_ionice</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return <a href="http://friedcpu.wordpress.com/2007/07/17/why-arent-you-using-ionice-yet/" rel="nofollow">process I/O niceness</a> (priority) as a namedtuple including priority class and priority data. See <tt>set_ionice</tt> below for more information. </li></ul><blockquote><i><strong>New in 2.1</strong></i><br><i><strong>Availability:</strong> Linux</i>
+</blockquote><ul><li><strong>set_ionice</strong><font size="3"><strong><tt>(</tt></strong></font><i>ioclass, value=None</i><font size="3"><strong><tt>)</tt></strong></font><br>Change <a href="http://friedcpu.wordpress.com/2007/07/17/why-arent-you-using-ionice-yet/" rel="nofollow">process I/O niceness</a> (priority). <i>ioclass</i> is one of the <strong><tt>IOPRIO_CLASS_*</tt></strong> constants. <i>value</i> is a number which goes from 0 to 7. The higher <i>value</i> value, the lower the I/O priority of the process. For further information refer to <a href="http://linux.die.net/man/1/ionice" rel="nofollow">ionice</a> command line utility or <a href="http://linux.die.net/man/2/ioprio_set" rel="nofollow">ioprio_set</a> system call. The example below sets IDLE priority class for the current process, meaning it will only get I/O time when no other process needs the disk: </li><pre class="prettyprint">&gt;&gt;&gt; import psutil, os
+&gt;&gt;&gt; p = psutil.Process(os.getpid())
+&gt;&gt;&gt; p.set_ionice(psutil.IOPRIO_CLASS_IDLE)
+&gt;&gt;&gt;</pre></ul><blockquote><i><strong>New in 2.1</strong></i><br><i><strong>Availability:</strong> Linux</i>
+</blockquote><ul><li><strong>get_num_threads</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return the number of threads used by this process. </li></ul><ul><li><strong>get_threads</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return threads opened by process as a list of namedtuples including thread id and thread CPU times (user/system). </li></ul><blockquote><i><strong>New in 0.2.1</strong></i>
+</blockquote><ul><li><strong>get_cpu_times</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return a tuple whose values are process CPU user and system times which means the amount of time expressed in seconds that a process has spent in <a href="http://stackoverflow.com/questions/556405/what-do-real-user-and-sys-mean-in-the-output-of-time1" rel="nofollow">user/system mode</a>. </li></ul><ul><li><strong>get_cpu_percent</strong><font size="3"><strong><tt>(</tt></strong></font><i>interval=0.1</i><font size="3"><strong><tt>)</tt></strong></font><br>Return a float representing the process CPU utilization as a percentage. When interval is &gt; 0.0 compares process times to system CPU times elapsed before and after the interval (blocking). When interval is 0.0 or None compares process times to system CPU times elapsed since last call, returning immediately. In this case is recommended for accuracy that this function be called with at least 0.1 seconds between calls. </li></ul><blockquote><i><strong>Changed in 0.2.0:</strong> interval parameter was added</i>
+</blockquote><ul><li><strong>get_memory_info</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return a tuple representing <a href="http://en.wikipedia.org/wiki/Resident_Set_Size" rel="nofollow">RSS</a> (Resident Set Size) and VMS (Virtual Memory Size) in bytes.<br>On UNIX RSS and VMS are the same values shown by ps. On Windows RSS and VMS refer to "Mem Usage" and "VM Size" columns of taskmgr.exe. </li></ul><ul><li><strong>get_memory_percent</strong><font size="3"><strong><tt>()</tt></strong></font><br>Compare physical system memory to process resident memory and calculate process memory utilization as a percentage. </li></ul><ul><li><strong>get_children</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return the children of this process as a list of <tt>Process</tt> objects. </li></ul><ul><li><strong>get_open_files</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return files opened by process as a list of <a href="http://docs.python.org/library/collections.html?highlight=namedtuple#collections.namedtuple" rel="nofollow">namedtuples</a> including file absolute path name and file descriptor. On <strong>FreeBSD</strong> this is done by parsing <a href="http://en.wikipedia.org/wiki/Lsof" rel="nofollow">lsof</a> command output. If lsof is not installed on the system <a href="http://docs.python.org/library/exceptions.html?highlight=notimplementederror#exceptions.NotImplementedError" rel="nofollow">NotImplementedError</a> exception is raised. Example: </li><pre class="prettyprint">&gt;&gt;&gt; import psutil, os
+&gt;&gt;&gt; f = open('file.ext', 'w')
+&gt;&gt;&gt; p = psutil.Process(os.getpid())
+&gt;&gt;&gt; p.get_open_files()
+[openfile(path='/home/giampaolo/svn/psutil/file.ext', fd=3)]</pre></ul><blockquote><i><strong>Changed in 0.2.1:</strong> OSX implementation rewritten in C; no longer requiring lsof.</i>
+</blockquote><ul><li><strong>get_connections</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return all TCP and UPD connections opened by process as a list of <a href="http://docs.python.org/library/collections.html?highlight=namedtuple#collections.namedtuple" rel="nofollow">namedtuples</a>. Every namedtuple provides 6 attributes:<br><br> </li><ul><li><strong>fd</strong>: the socket file descriptor. This can be passed to <a href="http://docs.python.org/library/socket.html#socket.fromfd" rel="nofollow">socket.fromfd</a> to obtain a usable socket object. This is only available on UNIX; on Windows <tt>-1</tt> is always returned.<br> </li><li><strong>family</strong>: the address family, either <a href="http://docs.python.org/library/socket.html#socket.AF_INET" rel="nofollow">AF_INET</a> or <a href="http://docs.python.org/library/socket.html#socket.AF_INET6" rel="nofollow">AF_INET6</a> <br> </li><li><strong>type</strong>: the address type, either <a href="http://docs.python.org/library/socket.html#socket.SOCK_STREAM" rel="nofollow">SOCK_STREAM</a> or <a href="http://docs.python.org/library/socket.html#socket.SOCK_DGRAM" rel="nofollow">SOCK_DGRAM</a> <br> </li><li><strong>local_address</strong>: the local address as a <tt>(ip, port)</tt> tuple. <br> </li><li><strong>remote_address</strong>: the remote address as a <tt>(ip, port)</tt> tuple. When the remote endpoint is not connected the tuple is empty. <br> </li><li><strong>status</strong>: a string representing the TCP connections status. String values are supposed to match Linux's <a href="http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h" rel="nofollow">tcp_states.h</a> header file across all platforms. For UDP sockets this is always going to be an empty string.<br> </li></ul></ul><blockquote>Example:
<pre class="prettyprint">&gt;&gt;&gt; p = psutil.Process(1694)
&gt;&gt;&gt; p.name
-&#x27;firefox&#x27;
+'firefox'
&gt;&gt;&gt; p.get_connections()
-[connection(fd=115, family=2, type=1, local_address=(&#x27;10.0.0.1&#x27;, 48776), remote_address=(&#x27;93.186.135.91&#x27;, 80), status=&#x27;ESTABLISHED&#x27;),
- connection(fd=117, family=2, type=1, local_address=(&#x27;10.0.0.1&#x27;, 43761), remote_address=(&#x27;72.14.234.100&#x27;, 80), status=&#x27;CLOSING&#x27;),
- connection(fd=119, family=2, type=1, local_address=(&#x27;10.0.0.1&#x27;, 60759), remote_address=(&#x27;72.14.234.104&#x27;, 80), status=&#x27;ESTABLISHED&#x27;),
- connection(fd=123, family=2, type=1, local_address=(&#x27;10.0.0.1&#x27;, 51314), remote_address=(&#x27;72.14.234.83&#x27;, 443), status=&#x27;SYN_SENT&#x27;)]</pre>On <strong>OSX</strong> and <strong>FreeBSD</strong> this is implemented by parsing <a href="http://en.wikipedia.org/wiki/Lsof" rel="nofollow">lsof</a> command output. If lsof is not installed on the system <a href="http://docs.python.org/library/exceptions.html?highlight=notimplementederror#exceptions.NotImplementedError" rel="nofollow">NotImplementedError</a> exception is raised. For third party processes (different than <tt>os.getpid()</tt>) results can differ depending on user privileges.<br>
-</blockquote><blockquote><i>New in 0.2.0</i>
-</blockquote><ul><li><strong>is_running</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return whether the current process is running in the current process list. </li></ul><ul><li><strong>suspend</strong><font size="3"><strong><tt>()</tt></strong></font><br>Suspend process execution. </li></ul><ul><li><strong>resume</strong><font size="3"><strong><tt>()</tt></strong></font><br>Resume process execution. </li></ul><ul><li><strong>terminate</strong><font size="3"><strong><tt>()</tt></strong></font><br>Terminate the process with <tt>SIGTERM</tt> signal. On Windows this is an alias for <tt>kill()</tt>. </li></ul><blockquote><i>New in 0.2.0</i>
-</blockquote><ul><li><strong>send_signal</strong><font size="3"><strong><tt>(</tt></strong></font><i>signal</i><font size="3"><strong><tt>)</tt></strong></font><br>Send a signal to process (see <a href="http://docs.python.org/library/signal.html" rel="nofollow">signal module</a> constants). On Windows only <tt>SIGTERM</tt> is valid and is treated as an alias for <tt>kill()</tt>. </li></ul><blockquote><i>New in 0.2.0</i>
-</blockquote><ul><li><strong>kill</strong><font size="3"><strong><tt>()</tt></strong></font><br>Kill the current process by using <tt>SIGKILL</tt> signal. </li></ul><blockquote><i>Changed in 0.2.0: no longer accepts <tt>sig</tt> keyword argument - use <tt>send_signal()</tt> instead. </i>
-</blockquote><hr/><h2><a name="Functions"></a>Functions<a href="#Functions" class="section_anchor"></a></h2><p>psutil.<strong>get_pid_list</strong><font size="3"><strong><tt>()</tt></strong></font><br> <blockquote>Return a list of current running PIDs.
-</blockquote></p><p>psutil.<strong>pid_exists</strong><font size="3"><strong><tt>(</tt></strong></font><i>pid</i><font size="3"><strong><tt>)</tt></strong></font><br> <blockquote>Check whether the given PID exists in the current process list.
-</blockquote></p><p>psutil.<strong>process_iter</strong><font size="3"><strong><tt>()</tt></strong></font><br> <blockquote>Return an iterator yielding a Process class instances for all running processes on the local machine.
-</blockquote></p><hr/><h2><a name="System_related_objects"></a>System related objects<a href="#System_related_objects" class="section_anchor"></a></h2><p>psutil.<strong>cpu_percent</strong><font size="3"><strong><tt>(</tt></strong></font><i>interval=0.1</i><font size="3"><strong><tt>)</tt></strong></font><br> <blockquote>Return a float representing the current system-wide CPU utilization as a percentage. When interval is &gt; 0.0 compares system CPU times elapsed before and after the interval (blocking). When interval is 0.0 or None compares system CPU times elapsed since last call or module import, returning immediately. In this case is recommended for accuracy that this function be called with at least 0.1 seconds between calls.
-</blockquote></p><blockquote><i>Changed in 0.2.0: interval parameter was added</i>
-</blockquote><p>psutil.<strong>cpu_times</strong><font size="3"><strong><tt>()</tt></strong></font><br> <blockquote>Return system CPU times as a <tt>CPUTimes</tt> class object. Every CPU time is accessible in form of a <tt>CPUTimes</tt> attribute and represents the time CPU has spent in the given mode.<br>The attributes availability varies depending on the platform. Here follows a list of all available attributes:
-</blockquote></p><blockquote>- <strong>user</strong><br>
-- <strong>system</strong><br>
-- <strong>idle</strong><br>
-- <strong>nice</strong> <i>(UNIX)</i><br>
-- <strong>iowait</strong> <i>(Linux)</i><br>
-- <strong>irq</strong> <i>(Linux, FreeBSD)</i><br>
-- <strong>softirq</strong> <i>(Linux)</i><br>
-</blockquote><p>psutil.<strong>TOTAL_PHYMEM</strong><br> psutil.<strong>avail_phymem</strong><font size="3"><strong><tt>()</tt></strong></font><br> psutil.<strong>used_phymem</strong><font size="3"><strong><tt>()</tt></strong></font><br> <blockquote>Return the amount of total, available and used physical memory on the system, in bytes.
-</blockquote></p><p>psutil.<strong>cached_phymem</strong><font size="3"><strong><tt>()</tt></strong></font><br> <blockquote>Return the amount of cached memory on the system, in bytes. This reflects the &quot;cached&quot; column of free command line utility on Linux.
-</blockquote></p><blockquote><i>New in 0.2.0</i><br><i>Availability: <strong>Linux</strong></i>
-</blockquote><p>psutil.<strong>phymem_buffers</strong><font size="3"><strong><tt>()</tt></strong></font><br> <blockquote>Return the amount of physical memory buffers used by the kernel in bytes. This reflects the &quot;buffers&quot; column of free command line utility on Linux.
-</blockquote></p><blockquote><i>New in 0.2.0</i><br><i>Availability: <strong>Linux</strong></i>
-</blockquote><p>psutil.<strong>total_virtmem</strong><font size="3"><strong><tt>()</tt></strong></font><br> psutil.<strong>avail_virtmem</strong><font size="3"><strong><tt>()</tt></strong></font><br> psutil.<strong>used_virtmem</strong><font size="3"><strong><tt>()</tt></strong></font><br> <blockquote>Return the amount of total, available and used virtual memory on the system, in bytes.<br>On Linux they match the values returned by <tt>free</tt> command line utility. On OS X and FreeBSD they represent the same values as returned by <tt>sysctl vm.vmtotal</tt>. On Windows they are determined by reading the <tt>*PageFile</tt> values of <a href="http://msdn.microsoft.com/en-us/library/aa366770(VS.85).aspx" rel="nofollow">MEMORYSTATUSEX</a> structure.
-</blockquote></p>
- </td>
- </tr>
- </table>
+[connection(fd=115, family=2, type=1, local_address=('10.0.0.1', 48776), remote_address=('93.186.135.91', 80), status='ESTABLISHED'),
+ connection(fd=117, family=2, type=1, local_address=('10.0.0.1', 43761), remote_address=('72.14.234.100', 80), status='CLOSING'),
+ connection(fd=119, family=2, type=1, local_address=('10.0.0.1', 60759), remote_address=('72.14.234.104', 80), status='ESTABLISHED'),
+ connection(fd=123, family=2, type=1, local_address=('10.0.0.1', 51314), remote_address=('72.14.234.83', 443), status='SYN_SENT')]</pre>On <strong>FreeBSD</strong> this is implemented by parsing <a href="http://en.wikipedia.org/wiki/Lsof" rel="nofollow">lsof</a> command output. If lsof is not installed on the system <a href="http://docs.python.org/library/exceptions.html?highlight=notimplementederror#exceptions.NotImplementedError" rel="nofollow">NotImplementedError</a> exception is raised and for third party processes (different than <tt>os.getpid()</tt>) results can differ depending on user privileges.<br>
+</blockquote><blockquote><i><strong>Changed in 0.2.1:</strong> OSX implementation rewritten in C; no longer requiring lsof.</i>
+</blockquote><ul><li><strong>is_running</strong><font size="3"><strong><tt>()</tt></strong></font><br>Return whether the current process is running in the current process list. </li></ul><ul><li><strong>send_signal</strong><font size="3"><strong><tt>(</tt></strong></font><i>signal</i><font size="3"><strong><tt>)</tt></strong></font><br>Send a signal to process (see <a href="http://docs.python.org/library/signal.html" rel="nofollow">signal module</a> constants). On Windows only <tt>SIGTERM</tt> is valid and is treated as an alias for <tt>kill()</tt>. </li></ul><ul><li><strong>suspend</strong><font size="3"><strong><tt>()</tt></strong></font><br>Suspend process execution with <tt>SIGSTOP</tt> signal. On Windows this is done by suspending all process threads execution. </li></ul><ul><li><strong>resume</strong><font size="3"><strong><tt>()</tt></strong></font><br>Resume process execution with <tt>SIGCONT</tt> signal. On Windows this is done by resuming all process threads execution. </li></ul><ul><li><strong>terminate</strong><font size="3"><strong><tt>()</tt></strong></font><br>Terminate the process with <tt>SIGTERM</tt> signal. On Windows this is an alias for <tt>kill()</tt>. </li></ul><ul><li><strong>kill</strong><font size="3"><strong><tt>()</tt></strong></font><br>Kill the current process by using <tt>SIGKILL</tt> signal. </li></ul><blockquote><i><strong>Changed in 0.2.0:</strong> no longer accepts <tt>sig</tt> keyword argument - use <tt>send_signal()</tt> instead. </i>
+</blockquote><ul><li><strong>wait</strong><font size="3"><strong><tt>(</tt></strong></font><i>timeout=None</i><font size="3"><strong><tt>)</tt></strong></font><br>Wait for process termination and if the process is a children of the current one also return the exit code, else <tt>None</tt>. On Windows there's no such limitation (exit code is always returned). If the process is already terminated does not raise <tt>NoSuchProcess</tt> exception but just return <tt>None</tt> immediately. If <i>timeout</i> is specified and process is still alive raises <tt>TimeoutExpired</tt> exception. </li></ul><blockquote><i><strong>New in 0.2.1</strong></i>
+</blockquote><p><br><br> psutil.<strong>Popen</strong><font size="3"><strong><tt>(</tt></strong></font><tt>*args, **kwargs</tt><font size="3"><strong><tt>)</tt></strong></font> </p><blockquote>A more convenient interface to stdlib <a href="http://docs.python.org/library/subprocess.html#subprocess.Popen" rel="nofollow">subprocess.Popen</a>. It starts a sub process and deals with it exactly as when using subprocess.Popen class but in addition also provides all the properties and methods of psutil.Process class in a unique interface. For method names common to both classes such as <i>kill()</i> and <i>terminate()</i>, psutil.Process implementation takes precedence. For a complete documentation refers to <a href="http://docs.python.org/library/subprocess.html" rel="nofollow">subprocess module documentation</a>.
+<pre class="prettyprint">&gt;&gt;&gt; import psutil
+&gt;&gt;&gt; from subprocess import PIPE
+&gt;&gt;&gt; p = psutil.Popen(["/usr/bin/python", "-c", "print 'hi'"], stdout=PIPE)
+&gt;&gt;&gt; p.name
+'python'
+&gt;&gt;&gt; p.uids
+user(real=1000, effective=1000, saved=1000)
+&gt;&gt;&gt; p.username
+'giampaolo'
+&gt;&gt;&gt; p.communicate()
+('hi\n', None)
+&gt;&gt;&gt; p.wait(timeout=2)
+0
+&gt;&gt;&gt;</pre></blockquote><blockquote><i><strong>New in 0.2.1</strong></i>
+</blockquote><hr><h2><a name="Functions"></a>Functions<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#Functions" class="section_anchor"></a></h2><p>psutil.<strong>get_pid_list</strong><font size="3"><strong><tt>()</tt></strong></font><br> </p><blockquote>Return a list of current running PIDs.
+</blockquote><p></p><p>psutil.<strong>pid_exists</strong><font size="3"><strong><tt>(</tt></strong></font><i>pid</i><font size="3"><strong><tt>)</tt></strong></font><br> </p><blockquote>Check whether the given PID exists in the current process list. This is faster than doing <tt>pid in psutil.get_pid_list()</tt> and should be preferred.
+</blockquote><p></p><p>psutil.<strong>process_iter</strong><font size="3"><strong><tt>()</tt></strong></font><br> </p><blockquote>Return an iterator yielding a Process class instances for all running processes on the local machine. This should be preferred over doing <tt>for pid in psutil.get_pid_list(): psutil.Process(pid)</tt> as it safe from race conditions.
+</blockquote><p></p><hr><h2><a name="System_related_functions"></a>System related functions<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#System_related_functions" class="section_anchor"></a></h2><h3><a name="CPU"></a>CPU<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#CPU" class="section_anchor"></a></h3><p>psutil.<strong>cpu_percent</strong><font size="3"><strong><tt>(</tt></strong></font><i>interval=0.1, percpu=False</i><font size="3"><strong><tt>)</tt></strong></font><br> </p><blockquote>Return a float representing the current system-wide CPU utilization as a percentage. When interval is &gt; 0.0 compares system CPU times elapsed before and after the interval (blocking). When interval is 0.0 or None compares system CPU times elapsed since last call or module import, returning immediately. In this case is recommended for accuracy that this function be called with at least 0.1 seconds between calls.<br>When <i>percpu</i> is True returns a list of floats representing the utilization as a percentage for each CPU. First element of the list refers to first CPU, second element to second CPU and so on. The order of the list is consistent across calls.
+</blockquote><p></p><pre class="prettyprint">&gt;&gt;&gt; # blocking, system-wide
+&gt;&gt;&gt; psutil.cpu_percent(interval=1)
+2.0
+&gt;&gt;&gt;
+&gt;&gt;&gt; # blocking, per-cpu
+&gt;&gt;&gt; psutil.cpu_percent(interval=1, percpu=True)
+[2.0, 1.0]
+&gt;&gt;&gt;
+&gt;&gt;&gt; # non-blocking (percentage since last call)
+&gt;&gt;&gt; psutil.cpu_percent(interval=0)
+2.9
+&gt;&gt;&gt;</pre><blockquote><i><strong>Changed in 0.2.0:</strong> interval parameter was added</i><br><i><strong>Changed in 0.3.0:</strong> percpu parameter was added</i>
+</blockquote><p>psutil.<strong>cpu_times</strong><font size="3"><strong><tt>(</tt></strong></font><i>percpu=False</i><font size="3"><strong><tt>)</tt></strong></font><br> </p><blockquote>Return system CPU times as a namedtuple. Every attribute represents the time CPU has spent in the given mode.<br>The attributes availability varies depending on the platform. Here follows a list of all available attributes:
+</blockquote><blockquote>- user<br>
+- system<br>
+- idle<br>
+- nice <i>(UNIX)</i><br>
+- iowait <i>(Linux)</i><br>
+- irq <i>(Linux, FreeBSD)</i><br>
+- softirq <i>(Linux)</i>
+</blockquote><p></p><blockquote>When <i>percpu</i> is True return a list of nameduples for each CPU. First element of the list refers to first CPU, second element to second CPU and so on. The order of the list is consistent across calls.
+</blockquote><blockquote><i><strong>Changed in 0.3.0:</strong> percpu parameter was added</i>
+</blockquote><hr><h3><a name="Memory"></a>Memory<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#Memory" class="section_anchor"></a></h3><p>psutil.<strong>phymem_usage</strong><font size="3"><strong><tt>()</tt></strong></font><br> </p><blockquote>Return the amount of total, used and free physical memory on the system in bytes plus the percentage usage.
+<p></p><pre class="prettyprint">&gt;&gt;&gt; psutil.phymem_usage()
+usage(total=4153868288, used=2854199296, free=1299668992, percent=34.6)</pre><i><strong>New in 0.3.0</strong></i>
+</blockquote><p>psutil.<strong>virtmem_usage</strong><font size="3"><strong><tt>()</tt></strong></font><br> </p><blockquote>Return the amount of total, used and free virtual memory on the system in bytes plus the percentage usage.<br>On Linux they match the values returned by <tt>free</tt> command line utility. On OS X and FreeBSD they represent the same values as returned by <tt>sysctl vm.vmtotal</tt>. On Windows they are determined by reading the <tt>*PageFile</tt> values of <a href="http://msdn.microsoft.com/en-us/library/aa366770(VS.85).aspx" rel="nofollow">MEMORYSTATUSEX</a> structure.
+<p></p><pre class="prettyprint">&gt;&gt;&gt; psutil.virtmem_usage()
+usage(total=2097147904, used=4096, free=2097143808, percent=0.0)</pre><i><strong>New in 0.3.0</strong></i>
+</blockquote><p>psutil.<strong>cached_phymem</strong><font size="3"><strong><tt>()</tt></strong></font><br> psutil.<strong>phymem_buffers</strong><font size="3"><strong><tt>()</tt></strong></font><br> </p><blockquote>Return the amount of cached memory and physical memory buffers on the system, in bytes. Thet reflects the "cached" and "buffers" columns of free command line utility on Linux.
+</blockquote><p></p><blockquote><i><strong>Availability:</strong> Linux</i>
+</blockquote><p>psutil.<strong>avail_phymem</strong><font size="3"><strong><tt>()</tt></strong></font><br> psutil.<strong>used_phymem</strong><font size="3"><strong><tt>()</tt></strong></font><br> psutil.<strong>total_virtmem</strong><font size="3"><strong><tt>()</tt></strong></font><br> psutil.<strong>avail_virtmem</strong><font size="3"><strong><tt>()</tt></strong></font><br> psutil.<strong>used_virtmem</strong><font size="3"><strong><tt>()</tt></strong></font><br> </p><blockquote>These functions are deprecated by <i>psutil.phymem_usage()</i> and <i>psutil.virtmem_usage()</i>. Use them instead.
+</blockquote><p></p><blockquote><i><strong>Deprecated in 0.3.0</strong></i>
+</blockquote><hr><h3><a name="Disk"></a>Disk<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#Disk" class="section_anchor"></a></h3><p>psutil.<strong>disk_partitions</strong><font size="3"><strong><tt>(</tt></strong></font><i>all=False</i><font size="3"><strong><tt>)</tt></strong></font><br> </p><blockquote>Return all mounted disk partitions as a list of namedtuples including device, mount point and filesystem type, similarly to "df" command on posix. <br>If <i>all</i> parameter is False return physical devices only (e.g. hard disks, cd-rom drives, USB keys) and ignore all others (e.g. memory partitions such as <a href="http://www.cyberciti.biz/tips/what-is-devshm-and-its-practical-usage.html" rel="nofollow">/dev/shm</a>).<br> Namedtuple's 'fstype' field is a string which varies depending on the platform. <br>On Linux it can be one of the values found in /proc/filesystems (e.g. 'ext3' for an ext3 hard drive o 'iso9660' for the CD-ROM drive). <br>On Windows it is determined via <a href="http://msdn.microsoft.com/en-us/library/aa364939(v=vs.85).aspx" rel="nofollow">GetDriveType</a> and can be either "removable", "fixed", "remote", "cdrom", "unmounted" or "ramdisk". <br>On OSX and FreeBSD it is retrieved via <a href="http://www.manpagez.com/man/2/getfsstat/" rel="nofollow">getfsstat(2)</a>. <br>See <a href="http://psutil.googlecode.com/svn/trunk/examples/disk_usage.py" rel="nofollow">examples/disk_usage.py</a> script providing an example usage.
+<p></p><pre class="prettyprint">&gt;&gt;&gt; psutil.get_partitions()
+[partition(device='/dev/sda3', mountpoint='/', fstype='ext4'),
+ partition(device='/dev/sda7', mountpoint='/home', fstype='ext4')]
+&gt;&gt;&gt;</pre></blockquote><blockquote><i><strong>New in 0.3.0</strong></i>
+</blockquote><p>psutil.<strong>disk_usage</strong><font size="3"><strong><tt>(</tt></strong></font><i>path</i><font size="3"><strong><tt>)</tt></strong></font><br> </p><blockquote>Return disk usage statistics about the given <i>path</i> as a namedtuple including total, used and free space expressed in bytes plus the percentage usage. OSError is raised if path does not exist. See <a href="http://psutil.googlecode.com/svn/trunk/examples/disk_usage.py" rel="nofollow">examples/disk_usage.py</a> script providing an example usage.
+<p></p><pre class="prettyprint">&gt;&gt;&gt; psutil.disk_usage('/')
+usage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)</pre></blockquote><blockquote><i><strong>New in 0.3.0</strong></i>
+</blockquote><hr><h2><a name="Constants"></a>Constants<a href="http://code.google.com/p/psutil/wiki/DocumentationDev?show=content#Constants" class="section_anchor"></a></h2><p>psutil.<strong>TOTAL_PHYMEM</strong><br> </p><blockquote>The amount of total physical memory on the system, in bytes.
+</blockquote><p></p><p>psutil.<strong>NUM_CPUS</strong><br> </p><blockquote>The number of CPUs on the system. This is preferable than using <tt>os.environ['NUMBER_OF_PROCESSORS']</tt> as it is more accurate and always available.
+</blockquote><p></p><p>psutil.<strong>BOOT_TIME</strong><br> </p><blockquote>A number indicating the system boot time expressed in seconds since the epoch.
+</blockquote><p></p><blockquote><i><strong>New in 0.2.1</strong></i>
+</blockquote><p>psutil.<strong>ABOVE_NORMAL_PRIORITY_CLASS</strong><br> psutil.<strong>BELOW_NORMAL_PRIORITY_CLASS</strong><br> psutil.<strong>HIGH_PRIORITY_CLASS</strong><br> psutil.<strong>IDLE_PRIORITY_CLASS</strong><br> psutil.<strong>NORMAL_PRIORITY_CLASS</strong><br> psutil.<strong>REALTIME_PRIORITY_CLASS</strong><br> </p><blockquote>A set of integers representing the priority of a process on Windows (see <a href="http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx" rel="nofollow">MSDN documentation</a>). They can be used in conjunction with <tt>psutil.Process.nice</tt> to get or set process priority.
+</blockquote><p></p><blockquote><i><strong>New in 0.2.1</strong></i><br><i><strong>Availability:</strong> Windows</i>
+</blockquote><p>psutil.<strong>IOPRIO_CLASS_NONE</strong><br> psutil.<strong>IOPRIO_CLASS_RT</strong><br> psutil.<strong>IOPRIO_CLASS_BE</strong><br> psutil.<strong>IOPRIO_CLASS_IDLE</strong><br> </p><blockquote>A set of integers representing the I/O priority of a process on Linux. They can be used in conjunction with <tt>psutil.Process.get_ionice()</tt> and <tt>psutil.Process.set_ionice()</tt> to get or set process I/O priority. For further information refer to <a href="http://linux.die.net/man/1/ionice" rel="nofollow">ionice</a> command line utility or <a href="http://linux.die.net/man/2/ioprio_get" rel="nofollow">ioprio_get</a> system call.
+</blockquote><p></p><blockquote><i><strong>New in 0.2.1</strong></i><br><i><strong>Availability:</strong> Linux</i>
+</blockquote><p>psutil.<strong>STATUS_RUNNING</strong><br> psutil.<strong>STATUS_SLEEPING</strong><br> psutil.<strong>STATUS_DISK_SLEEP</strong><br> psutil.<strong>STATUS_STOPPED</strong><br> psutil.<strong>STATUS_TRACING_STOP</strong><br> psutil.<strong>STATUS_ZOMBIE</strong><br> psutil.<strong>STATUS_DEAD</strong><br> psutil.<strong>STATUS_WAKE_KILL</strong><br> psutil.<strong>STATUS_WAKING</strong><br> psutil.<strong>STATUS_IDLE</strong><br> psutil.<strong>STATUS_LOCKED</strong><br> psutil.<strong>STATUS_WAITING</strong><br> </p><blockquote>A set of integers representing the status of a process. To be used in conjunction with <tt>psutil.Process.status</tt> property. If used with str() return a human-readable status string.
+</blockquote><p></p><blockquote><i><strong>New in 0.2.1</strong></i><br><i><strong>
+</strong></i></blockquote>
+ </div>
</div>
+ </td></tr><tr>
+</tr></tbody></table>
+ </div>
+
+
+
+
+<script type="text/javascript" src="./documentation_files/dit_scripts.js"></script>
+
+
+<script type="text/javascript" src="./documentation_files/plusone.js">
+</script>
+
- </body>
-</html>
+</body></html> \ No newline at end of file
diff --git a/third_party/psutil/docs/index.html b/third_party/psutil/docs/index.html
index 8395837..4ac43f4 100644
--- a/third_party/psutil/docs/index.html
+++ b/third_party/psutil/docs/index.html
@@ -1,26 +1,50 @@
-
-
-
<html>
<head>
- <title>psutil</title>
+ <title>Home</title>
</head>
<body>
- <div id="wikicontent">
- <table width="100%" border="0" cellspacing="0" cellpadding="0">
- <tr>
- <td class="vt" id="wikimaincol" width="100%">
+<div>
+<table>
+ <tr>
- <div id="wikiheader" style="margin-bottom:1em">
+ <td style="vertical-align:top; padding-left:5px">
- </div>
- <h1><a name="Summary"></a>Summary<a href="#Summary" class="section_anchor"></a></h1><p>psutil is a module providing an interface for retrieving information on running processes and system utilization (CPU, memory) in a portable way by using Python, implementing many functionalities offered by command line tools like <strong>ps</strong>, <strong>top</strong>, <strong>kill</strong> and Windows <strong>task manager</strong>. </p><p>It currently supports <strong>Linux</strong>, <strong>OS X</strong>, <strong>FreeBSD</strong> and <strong>Windows</strong> with Python versions from <strong>2.4</strong> to <strong>3.1</strong> by using a unique code base. </p><h1><a name="Example_usage"></a>Example usage<a href="#Example_usage" class="section_anchor"></a></h1><h3><a name="process_management"></a>process management<a href="#process_management" class="section_anchor"></a></h3><pre class="prettyprint">&gt;&gt;&gt; import psutil
+ <div id="wikicontent">
+ <div class="vt" id="wikimaincol">
+ <h1><a name="Summary"></a>Summary<a href="#Summary" class="section_anchor"></a></h1><p>psutil is a module providing an interface for retrieving information on all running processes and system utilization (CPU, disk, memory) in a portable way by using <strong>Python</strong>, implementing many functionalities offered by command line tools such as: </p><ul><li>ps </li><li>top </li><li>df </li><li>kill </li><li>free </li><li>lsof </li><li>netstat </li><li>nice </li><li>ionice </li><li>uptime </li><li>tty </li></ul><p>It currently supports <strong>Linux</strong>, <strong>Windows</strong>, <strong>OSX</strong> and <strong>FreeBSD</strong> both <strong>32-bit</strong> and <strong>64-bit</strong> with Python versions from <strong>2.4</strong> to <strong>3.3</strong> by using a single code base. </p><p><a href="http://code.google.com/p/psutil/#Donate" rel="nofollow"></a> </p><h1><a name="Example_usages"></a>Example usages<a href="#Example_usages" class="section_anchor"></a></h1><h3><a name="CPU"></a>CPU<a href="#CPU" class="section_anchor"></a></h3><pre class="prettyprint">&gt;&gt;&gt; import psutil
+&gt;&gt;&gt; psutil.cpu_times()
+cputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.509, irq=0.0, softirq=19.422)
+&gt;&gt;&gt;
+&gt;&gt;&gt; for x in range(3):
+... psutil.cpu_percent(interval=1)
+...
+4.0
+5.9
+3.8
+&gt;&gt;&gt;
+&gt;&gt;&gt; for x in range(3):
+... psutil.cpu_percent(interval=1, percpu=True)
+...
+[4.0, 34.2]
+[7.0, 8.5]
+[1.2, 9.0]
+&gt;&gt;&gt;</pre><h3><a name="Memory"></a>Memory<a href="#Memory" class="section_anchor"></a></h3><pre class="prettyprint">&gt;&gt;&gt; psutil.phymem_usage()
+usage(total=4153868288, used=2854199296, free=1299668992, percent=34.6)
+&gt;&gt;&gt; psutil.virtmem_usage()
+usage(total=2097147904, used=4096, free=2097143808, percent=0.0)
+&gt;&gt;&gt;</pre><h3><a name="Disks"></a>Disks<a href="#Disks" class="section_anchor"></a></h3><pre class="prettyprint">&gt;&gt;&gt; psutil.get_partitions()
+[partition(device=&#x27;/dev/sda3&#x27;, mountpoint=&#x27;/&#x27;, fstype=&#x27;ext4&#x27;),
+ partition(device=&#x27;/dev/sda7&#x27;, mountpoint=&#x27;/home&#x27;, fstype=&#x27;ext4&#x27;)]
+&gt;&gt;&gt;
+&gt;&gt;&gt; psutil.disk_usage(&#x27;/&#x27;)
+usage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
+&gt;&gt;&gt;</pre><h3><a name="Process_management"></a>Process management<a href="#Process_management" class="section_anchor"></a></h3><pre class="prettyprint">&gt;&gt;&gt; import psutil
&gt;&gt;&gt; psutil.get_pid_list()
[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,
@@ -28,72 +52,74 @@
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]
+&gt;&gt;&gt;
&gt;&gt;&gt; p = psutil.Process(7055)
&gt;&gt;&gt; p.name
&#x27;python&#x27;
-&gt;&gt;&gt; p.path
-&#x27;/usr/bin&#x27;
+&gt;&gt;&gt; p.exe
+&#x27;/usr/bin/python&#x27;
&gt;&gt;&gt; p.cmdline
-[&#x27;/usr/bin/python&#x27;, &#x27;-O&#x27;, &#x27;run.py&#x27;]
-&gt;&gt;&gt; p.uid
-1000
-&gt;&gt;&gt; p.gid
-1000
+[&#x27;/usr/bin/python&#x27;, &#x27;main.py&#x27;]
+&gt;&gt;&gt; str(p.status)
+&#x27;running&#x27;
+&gt;&gt;&gt;
+&gt;&gt;&gt; p.uids
+user(real=1000, effective=1000, saved=1000)
+&gt;&gt;&gt; p.gids
+group(real=1000, effective=1000, saved=1000)
&gt;&gt;&gt; p.username
-&#x27;jake&#x27;
+&#x27;giampaolo&#x27;
&gt;&gt;&gt; p.create_time
1267551141.5019531
-&gt;&gt;&gt; p.get_cpu_percent()
-12.31243
+&gt;&gt;&gt; p.get_cpu_percent(interval=1.0)
+12.1
&gt;&gt;&gt; p.get_memory_percent()
0.63423
-&gt;&gt;&gt; rss, vms = p.get_memory_info()
-&gt;&gt;&gt; &quot;Resident memory: %s KB&quot; %(rss / 1024)
-&#x27;Resident memory: 3768 KB&#x27;
-&gt;&gt;&gt; &quot;Virtual memory: %s KB&quot; %(vms / 1024)
-&#x27;Virtual memory: 6176 KB&#x27;
+&gt;&gt;&gt; p.get_memory_info()
+meminfo(rss=7471104, vms=68513792)
+&gt;&gt;&gt; p.get_io_counters()
+io(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
+&gt;&gt;&gt;
+&gt;&gt;&gt; p.get_open_files()
+[openfile(path=&#x27;/home/giampaolo/svn/psutil/somefile&#x27;, fd=3)]
+&gt;&gt;&gt;
+&gt;&gt;&gt; p.get_connections()
+[connection(fd=115, family=2, type=1, local_address=(&#x27;10.0.0.1&#x27;, 48776), remote_address=(&#x27;93.186.135.91&#x27;, 80), status=&#x27;ESTABLISHED&#x27;),
+ connection(fd=117, family=2, type=1, local_address=(&#x27;10.0.0.1&#x27;, 43761), remote_address=(&#x27;72.14.234.100&#x27;, 80), status=&#x27;CLOSING&#x27;),
+ connection(fd=119, family=2, type=1, local_address=(&#x27;10.0.0.1&#x27;, 60759), remote_address=(&#x27;72.14.234.104&#x27;, 80), status=&#x27;ESTABLISHED&#x27;),
+ connection(fd=123, family=2, type=1, local_address=(&#x27;10.0.0.1&#x27;, 51314), remote_address=(&#x27;72.14.234.83&#x27;, 443), status=&#x27;SYN_SENT&#x27;)]
+&gt;&gt;&gt;
+&gt;&gt;&gt; p.get_threads()
+[thread(id=5234, user_time=22.5, system_time=9.2891),
+ thread(id=5235, user_time=0.0, system_time=0.0),
+ thread(id=5236, user_time=0.0, system_time=0.0),
+ thread(id=5237, user_time=0.0707, system_time=1.1)]
+&gt;&gt;&gt;
+&gt;&gt;&gt; p.nice
+0
+&gt;&gt;&gt; p.nice = 10 # set/change process priority
+&gt;&gt;&gt; p.nice
+10
&gt;&gt;&gt;
&gt;&gt;&gt; p.suspend()
&gt;&gt;&gt; p.resume()
+&gt;&gt;&gt;
+&gt;&gt;&gt; p.terminate()
+&gt;&gt;&gt; p.wait(timeout=3)
+0
+&gt;&gt;&gt;
&gt;&gt;&gt; psutil.test()
UID PID %CPU %MEM VSZ RSS START TIME COMMAND
0 0 0.0 0.0 0 0 00:12 00:00 [sched]
0 1 0.0 0.3 1740 600 00:12 00:04 /sbin/init
0 2 0.0 0.0 0 0 00:12 00:00 [kthreadd]
-0 3 0.0 0.0 0 0 00:12 00:00 [migration/0]
+0 3 0.1 0.0 0 0 00:12 00:00 [migration/0]
...
0 13239 0.0 2.6 13604 1044 00:38 00:00 /usr/sbin/smbd -D
-1000 23648 0.0 2.4 12512 2008 14:43 00:06 sshd: user@pts/2
+1000 23648 1.1 2.4 12512 2008 14:43 00:06 sshd: user@pts/2
1000 23649 0.0 1.2 5944 3340 14:43 00:00 -bash
-0 25926 0.0 1.1 5432 3072 17:55 00:00 -su
+0 25926 0.3 1.1 5432 3072 17:55 00:00 -su
0 28655 0.0 1.0 4932 3204 21:58 00:00 python _psutil.py
-&gt;&gt;&gt;</pre><h3><a name="System_monitoring_(CPU_and_memory)"></a>System monitoring (CPU and memory)<a href="#System_monitoring_(CPU_and_memory)" class="section_anchor"></a></h3><pre class="prettyprint">&gt;&gt;&gt; import psutil, time
-&gt;&gt;&gt; print psutil.cpu_times()
-softirq=50.87; iowait=39.63; system=1130.67; idle=164171.41; user=965.15; irq=7.08; nice=0.0
-&gt;&gt;&gt;
-&gt;&gt;&gt; while 1:
-... print round(psutil.cpu_percent(), 1)
-... time.sleep(1)
-...
-5.4
-3.2
-7.3
-7.1
-2.5
-Traceback (most recent call last):
- File &quot;&lt;stdin&gt;&quot;, line 3, in &lt;module&gt;
-KeyboardInterrupt
-&gt;&gt;&gt;
-&gt;&gt;&gt; psutil.TOTAL_PHYMEM
-526458880
-&gt;&gt;&gt; psutil.avail_phymem()
-153530368
-&gt;&gt;&gt; psutil.total_virtmem()
-197365760
-&gt;&gt;&gt; psutil.avail_virtmem()
-194277376</pre><h1><a name="Mailing_lists"></a>Mailing lists<a href="#Mailing_lists" class="section_anchor"></a></h1><p><strong>Users</strong><br><a href="http://groups.google.com/group/psutil/topics" rel="nofollow">http://groups.google.com/group/psutil/topics</a> </p><p><strong>Developers</strong><br><a href="http://groups.google.com/group/psutil-dev/topics" rel="nofollow">http://groups.google.com/group/psutil-dev/topics</a> </p><p><strong>SVN commits and issue tracker changes</strong><br><a href="http://groups.google.com/group/psutil-commits/topics" rel="nofollow">http://groups.google.com/group/psutil-commits/topics</a> </p><h1><a name="Contribute"></a>Contribute<a href="#Contribute" class="section_anchor"></a></h1><p>If you want to help or just give us suggestions about the project and other related things, subscribe to the <a href="http://groups.google.com/group/psutil" rel="nofollow">discussion mailing list</a>. If you want to talk with project team members about psutil and other related things feel free to contact us at the following addresses: </p><p><table><tr><td style="border: 1px solid #aaa; padding: 5px;"> <strong>Name</strong> </td><td style="border: 1px solid #aaa; padding: 5px;"> <strong>Country</strong> </td><td style="border: 1px solid #aaa; padding: 5px;"> <strong>E-mail</strong> </td></tr> <tr><td style="border: 1px solid #aaa; padding: 5px;"> Jay Loden </td><td style="border: 1px solid #aaa; padding: 5px;"> New Jersey (USA) </td><td style="border: 1px solid #aaa; padding: 5px;"> jloden at gmail dot com </td></tr> <tr><td style="border: 1px solid #aaa; padding: 5px;"> Giampaolo Rodola&#x27; </td><td style="border: 1px solid #aaa; padding: 5px;"> Turin (Italy) </td><td style="border: 1px solid #aaa; padding: 5px;"> g.rodola at gmail dot com </td></tr> </table></p><p>Feedbacks and suggestions are greatly appreciated as well as new testers and coders willing to join the development.<br> For any bug report, patch proposal or feature request, add an entry into the <a href="http://code.google.com/p/psutil/issues/list" rel="nofollow">Issue Tracker</a>.<br> </p><p>Thank you. </p>
-
-
+&gt;&gt;&gt;</pre><h1><a name="Donate"></a>Donate<a href="#Donate" class="section_anchor"></a></h1><p>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 it&#x27;s future development please consider donating us (Giampaolo Rodolà and Jay Loden) some money. We only ask for a small donation, but of course we appreciate any amount. </p><p><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&amp;hosted_button_id=A9ZS7PKKRM3S8" rel="nofollow"></a> </p><h2><a name="People_who_donated_so_far"></a>People who donated so far<a href="#People_who_donated_so_far" class="section_anchor"></a></h2><ul><li>Kim Gräsman </li></ul><h1><a name="Mailing_lists"></a>Mailing lists<a href="#Mailing_lists" class="section_anchor"></a></h1><p><strong>Users</strong><br><a href="http://groups.google.com/group/psutil/" rel="nofollow">http://groups.google.com/group/psutil/</a> </p><p><strong>Developers</strong><br><a href="http://groups.google.com/group/psutil-dev/" rel="nofollow">http://groups.google.com/group/psutil-dev/</a> </p><p><strong>SVN commits and issue tracker changes</strong><br><a href="http://groups.google.com/group/psutil-commits/" rel="nofollow">http://groups.google.com/group/psutil-commits/</a> </p><h1><a name="Contribute"></a>Contribute<a href="#Contribute" class="section_anchor"></a></h1><p>If you want to help or just give us suggestions about the project and other related things, subscribe to the <a href="http://groups.google.com/group/psutil" rel="nofollow">discussion mailing list</a>. If you want to talk with project team members about psutil and other related things feel free to contact us at the following addresses: </p><p><table class="wikitable"><tr><td style="border: 1px solid #ccc; padding: 5px;"> <strong>Name</strong> </td><td style="border: 1px solid #ccc; padding: 5px;"> <strong>Country</strong> </td><td style="border: 1px solid #ccc; padding: 5px;"> <strong>E-mail</strong> </td></tr> <tr><td style="border: 1px solid #ccc; padding: 5px;"> Giampaolo Rodola&#x27; </td><td style="border: 1px solid #ccc; padding: 5px;"> Turin (Italy) </td><td style="border: 1px solid #ccc; padding: 5px;"> g.rodola at gmail dot com </td></tr> <tr><td style="border: 1px solid #ccc; padding: 5px;"> Jay Loden </td><td style="border: 1px solid #ccc; padding: 5px;"> New Jersey (USA) </td><td style="border: 1px solid #ccc; padding: 5px;"> jloden at gmail dot com </td></tr> </table></p><p>Feedbacks and suggestions are greatly appreciated as well as new testers and coders willing to join the development.<br> For any bug report, patch proposal or feature request, add an entry into the <a href="http://code.google.com/p/psutil/issues/list" rel="nofollow">Issue Tracker</a>.<br> </p><p>Thank you. </p>
</body>
</html>
-
diff --git a/third_party/psutil/examples/disk_usage.py b/third_party/psutil/examples/disk_usage.py
new file mode 100644
index 0000000..23f2d0c
--- /dev/null
+++ b/third_party/psutil/examples/disk_usage.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+#
+# $Id: disk_usage.py 1143 2011-10-05 19:11:59Z g.rodola $
+#
+# 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.
+
+"""
+List all mounted disk partitions a-la "df -h" command.
+"""
+
+import sys
+import psutil
+
+def convert_bytes(n):
+ if n == 0:
+ return "0B"
+ 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 '%.1f%s' % (value, s)
+
+
+def main():
+ templ = "%-17s %8s %8s %8s %5s%% %9s %s"
+ print templ % ("Device", "Total", "Used", "Free", "Use ", "Type", "Mount")
+ for part in psutil.disk_partitions(all=False):
+ usage = psutil.disk_usage(part.mountpoint)
+ print templ % (part.device,
+ convert_bytes(usage.total),
+ convert_bytes(usage.used),
+ convert_bytes(usage.free),
+ int(usage.percent),
+ part.fstype,
+ part.mountpoint)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/third_party/psutil/examples/iotop.py b/third_party/psutil/examples/iotop.py
new file mode 100644
index 0000000..2307c75
--- /dev/null
+++ b/third_party/psutil/examples/iotop.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+#
+# $Id: iotop.py 1143 2011-10-05 19:11:59Z g.rodola $
+#
+# 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.
+
+"""
+A clone of iotop (http://guichaz.free.fr/iotop/) showing real time
+disk I/O statistics.
+
+It works on UNIX only as curses module is not available on Windows.
+
+Author: Giampaolo Rodola' <g.rodola@gmail.com>
+"""
+
+import time
+import curses
+import atexit
+
+import psutil
+
+win = curses.initscr()
+
+def bytes2human(n):
+ """
+ >>> bytes2human(10000)
+ '9.8 K/s'
+ >>> bytes2human(100001221)
+ '95.4 M/s'
+ """
+ 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/s' % (value, s)
+ return "0.00 B/s"
+
+def poll(interval):
+ """Calculate IO usage by comparing IO statics before and
+ after the interval.
+ Return a tuple including all currently running processes
+ sorted by IO activity and total disks I/O activity.
+ """
+ # first get a list of all processes and disk io counters
+ procs = [p for p in psutil.process_iter()]
+ for p in procs[:]:
+ try:
+ p._before = p.get_io_counters()
+ except psutil.Error:
+ procs.remove(p)
+ continue
+ disks_before = psutil.disk_io_counters()
+
+ # sleep some time
+ time.sleep(interval)
+
+ # then retrieve the same info again
+ for p in procs[:]:
+ try:
+ p._after = p.get_io_counters()
+ p._cmdline = ' '.join(p.cmdline)
+ if not p._cmdline:
+ p._cmdline = p.name
+ p._username = p.username
+ except psutil.NoSuchProcess:
+ procs.remove(p)
+ disks_after = psutil.disk_io_counters()
+
+ # finally calculate results by comparing data before and
+ # after the interval
+ for p in procs:
+ p._read_per_sec = p._after.read_bytes - p._before.read_bytes
+ p._write_per_sec = p._after.write_bytes - p._before.write_bytes
+ p._total = p._read_per_sec + p._write_per_sec
+
+ disks_read_per_sec = disks_after.read_bytes - disks_before.read_bytes
+ disks_write_per_sec = disks_after.write_bytes - disks_before.write_bytes
+
+ # sort processes by total disk IO so that the more intensive
+ # ones get listed first
+ processes = sorted(procs, key=lambda p: p._total, reverse=True)
+
+ return (processes, disks_read_per_sec, disks_write_per_sec)
+
+def run(win):
+ """Print results on screen by using curses."""
+ curses.endwin()
+ templ = "%-5s %-7s %11s %11s %s"
+ interval = 0
+ while 1:
+ procs, disks_read, disks_write = poll(interval)
+ win.erase()
+
+ disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \
+ % (bytes2human(disks_read), bytes2human(disks_write))
+ win.addstr(0, 0, disks_tot)
+
+ header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND")
+ header += " " * (win.getmaxyx()[1] - len(header))
+ win.addstr(1, 0, header, curses.A_REVERSE)
+
+ lineno = 2
+ for p in procs:
+ line = templ % (p.pid,
+ p._username[:7],
+ bytes2human(p._read_per_sec),
+ bytes2human(p._write_per_sec),
+ p._cmdline)
+ try:
+ win.addstr(lineno, 0, line)
+ except curses.error:
+ break
+ win.refresh()
+ lineno += 1
+ interval = 1
+
+def main():
+ def tear_down():
+ win.keypad(0)
+ curses.nocbreak()
+ curses.echo()
+ curses.endwin()
+
+ atexit.register(tear_down)
+ try:
+ run(win)
+ except (KeyboardInterrupt, SystemExit):
+ pass
+
+if __name__ == '__main__':
+ main()
diff --git a/third_party/psutil/examples/killall.py b/third_party/psutil/examples/killall.py
new file mode 100644
index 0000000..5381b54
--- /dev/null
+++ b/third_party/psutil/examples/killall.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# $Id: killall.py 1143 2011-10-05 19:11:59Z g.rodola $
+#
+# 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.
+
+"""
+Kill a process by name.
+"""
+
+import os
+import sys
+import psutil
+
+def main():
+ if len(sys.argv) != 2:
+ sys.exit('usage: %s name' % __file__)
+ else:
+ NAME = sys.argv[1]
+
+ killed = []
+ for proc in psutil.process_iter():
+ if proc.name == NAME and proc.pid != os.getpid():
+ proc.kill()
+ killed.append(proc.pid)
+ if not killed:
+ sys.exit('%s: no process found' % NAME)
+ else:
+ sys.exit(0)
+
+sys.exit(main())
diff --git a/third_party/psutil/examples/process_detail.py b/third_party/psutil/examples/process_detail.py
new file mode 100644
index 0000000..4c791d1
--- /dev/null
+++ b/third_party/psutil/examples/process_detail.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+#
+# $Id: process_detail.py 1143 2011-10-05 19:11:59Z g.rodola $
+#
+# 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.
+
+"""
+Print detailed information about a process.
+"""
+
+import os
+import datetime
+import socket
+import sys
+
+import psutil
+from psutil._compat import namedtuple
+
+
+def convert_bytes(n):
+ if n == 0:
+ return '0B'
+ 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 '%.1f%s' % (value, s)
+
+def print_(a, b):
+ if sys.stdout.isatty():
+ fmt = '\x1b[1;32m%-17s\x1b[0m %s' %(a, b)
+ else:
+ fmt = '%-15s %s' %(a, b)
+ print fmt
+
+def run(pid):
+ p = psutil.Process(pid)
+ if p.parent:
+ parent = '(%s)' % p.parent.name
+ else:
+ parent = ''
+ started = datetime.datetime.fromtimestamp(p.create_time).strftime('%Y-%M-%d %H:%M')
+ io = p.get_io_counters()
+ mem = p.get_memory_info()
+ mem = '%s%% (resident=%s, virtual=%s) ' %(round(p.get_memory_percent(), 1),
+ convert_bytes(mem.rss),
+ convert_bytes(mem.vms))
+ cpu_times = p.get_cpu_times()
+ cpu_percent = p.get_cpu_percent(0)
+ children = p.get_children()
+ files = p.get_open_files()
+ threads = p.get_threads()
+ connections = p.get_connections()
+
+ print_('pid', p.pid)
+ print_('name', p.name)
+ print_('exe', p.exe)
+ print_('parent', '%s %s' % (p.ppid, parent))
+ print_('cmdline', ' '.join(p.cmdline))
+ print_('started', started)
+ print_('user', p.username)
+ if os.name == 'posix':
+ print_('uids', 'real=%s, effective=%s, saved=%s' % p.uids)
+ print_('gids', 'real=%s, effective=%s, saved=%s' % p.gids)
+ print_('terminal', p.terminal or '')
+ if hasattr(p, 'getcwd'):
+ print_('cwd', p.getcwd())
+ print_('memory', mem)
+ print_('cpu', '%s%% (user=%s, system=%s)' % (cpu_percent,
+ cpu_times.user,
+ cpu_times.system))
+ print_('status', p.status)
+ print_('niceness', p.nice)
+ print_('num threads', p.get_num_threads())
+ if hasattr(p, 'get_io_counters'):
+ print_('I/O', 'bytes-read=%s, bytes-written=%s' % \
+ (convert_bytes(io.read_bytes),
+ convert_bytes(io.write_bytes)))
+ if children:
+ print_('children', '')
+ for child in children:
+ print_('', 'pid=%s name=%s' % (child.pid, child.name))
+
+ if files:
+ print_('open files', '')
+ for file in files:
+ print_('', 'fd=%s %s ' % (file.fd, file.path))
+
+ if threads:
+ print_('running threads', '')
+ for thread in threads:
+ print_('', 'id=%s, user-time=%s, sys-time=%s' \
+ % (thread.id, thread.user_time, thread.system_time))
+ if connections:
+ print_('open connections', '')
+ for conn in connections:
+ type = 'TCP' if conn.type == socket.SOCK_STREAM else 'UDP'
+ lip, lport = conn.local_address
+ if not conn.remote_address:
+ rip, rport = '*', '*'
+ else:
+ rip, rport = conn.remote_address
+ print_('', '%s:%s -> %s:%s type=%s status=%s' \
+ % (lip, lport, rip, rport, type, conn.status))
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv
+ if len(argv) == 1:
+ sys.exit(run(os.getpid()))
+ elif len(argv) == 2:
+ sys.exit(run(int(argv[1])))
+ else:
+ sys.exit('usage: %s [pid]' % __file__)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/third_party/psutil/psutil/__init__.py b/third_party/psutil/psutil/__init__.py
index 09b7955..93724fc 100644
--- a/third_party/psutil/psutil/__init__.py
+++ b/third_party/psutil/psutil/__init__.py
@@ -1,26 +1,35 @@
#!/usr/bin/env python
#
-# $Id: __init__.py 806 2010-11-12 23:09:35Z g.rodola $
+# $Id: __init__.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
"""psutil is a module providing convenience functions for managing
-processes in a portable way by using Python.
+processes and gather system information in a portable way by using
+Python.
"""
-__version__ = "0.2.0"
+__version__ = "0.3.1"
version_info = tuple([int(num) for num in __version__.split('.')])
__all__ = [
# exceptions
- "Error", "NoSuchProcess", "AccessDenied",
+ "Error", "NoSuchProcess", "AccessDenied", "TimeoutExpired",
# constants
- "NUM_CPUS", "TOTAL_PHYMEM", "version_info", "__version__",
+ "NUM_CPUS", "TOTAL_PHYMEM", "BOOT_TIME",
+ "version_info", "__version__",
+ "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP",
+ "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD",
+ "STATUS_WAKING", "STATUS_LOCKED",
# classes
- "Process",
+ "Process", "Popen",
# functions
"test", "pid_exists", "get_pid_list", "process_iter", "get_process_list",
- "avail_phymem", "used_phymem", "total_virtmem", "avail_virtmem",
- "used_virtmem", "cpu_times", "cpu_percent",
+ "phymem_usage", "virtmem_usage"
+ "cpu_times", "per_cpu_times", "cpu_percent", "per_cpu_percent",
+ "network_io_counters", "disk_io_counters",
]
import sys
@@ -29,67 +38,58 @@ import time
import signal
import warnings
import errno
+import subprocess
try:
import pwd
except ImportError:
pwd = None
-from psutil.error import Error, NoSuchProcess, AccessDenied
+from psutil.error import Error, NoSuchProcess, AccessDenied, TimeoutExpired
+from psutil._compat import property
+from psutil._common import (STATUS_RUNNING, STATUS_IDLE, STATUS_SLEEPING,
+ STATUS_DISK_SLEEP, STATUS_STOPPED,
+ STATUS_TRACING_STOP, STATUS_ZOMBIE, STATUS_DEAD,
+ STATUS_WAKING, STATUS_LOCKED
+ )
# import the appropriate module for our platform only
if sys.platform.lower().startswith("linux"):
- from psutil._pslinux import *
- __all__.extend(["cached_phymem", "phymem_buffers"])
+ import psutil._pslinux as _psplatform
+ from psutil._pslinux import (phymem_buffers,
+ cached_phymem,
+ IOPRIO_CLASS_NONE,
+ IOPRIO_CLASS_RT,
+ IOPRIO_CLASS_BE,
+ IOPRIO_CLASS_IDLE)
+ phymem_buffers = _psplatform.phymem_buffers
+ cached_phymem = _psplatform.cached_phymem
elif sys.platform.lower().startswith("win32"):
- from psutil._psmswindows import *
+ import psutil._psmswindows as _psplatform
+ from psutil._psmswindows import (ABOVE_NORMAL_PRIORITY_CLASS,
+ BELOW_NORMAL_PRIORITY_CLASS,
+ HIGH_PRIORITY_CLASS,
+ IDLE_PRIORITY_CLASS,
+ NORMAL_PRIORITY_CLASS,
+ REALTIME_PRIORITY_CLASS)
elif sys.platform.lower().startswith("darwin"):
- from psutil._psosx import *
+ import psutil._psosx as _psplatform
elif sys.platform.lower().startswith("freebsd"):
- from psutil._psbsd import *
+ import psutil._psbsd as _psplatform
else:
raise NotImplementedError('platform %s is not supported' % sys.platform)
+__all__.extend(_psplatform.__extra__all__)
-class CPUTimes:
- """This class contains information about CPU times.
- It is not used directly but it's returned as an instance by
- psutil.cpu_times() function.
+NUM_CPUS = _psplatform.NUM_CPUS
+BOOT_TIME = _psplatform.BOOT_TIME
+TOTAL_PHYMEM = _psplatform.phymem_usage()[0]
- Every CPU time is accessible in form of an attribute and represents
- the time CPU has spent in the given mode.
-
- The attributes availability varies depending on the platform.
- Here follows a list of all available attributes:
-
- - user
- - system
- - idle
- - nice (UNIX)
- - iowait (Linux)
- - irq (Linux, FreeBSD)
- - softirq (Linux)
- """
-
- def __init__(self, **kwargs):
- self.__attrs = []
- for name in kwargs:
- setattr(self, name, kwargs[name])
- self.__attrs.append(name)
-
- def __str__(self):
- string = []
- for attr in self.__attrs:
- value = getattr(self, attr)
- string.append("%s=%s" %(attr, value))
- return '; '.join(string)
-
- def __iter__(self):
- for attr in self.__attrs:
- yield getattr(self, attr)
+get_pid_list = _psplatform.get_pid_list
+pid_exists = _psplatform.pid_exists
class Process(object):
@@ -98,15 +98,16 @@ class Process(object):
def __init__(self, pid):
"""Create a new Process object, raises NoSuchProcess if the PID
does not exist, and ValueError if the parameter is not an
- integer PID."""
+ integer PID.
+ """
if not isinstance(pid, int):
- raise ValueError("An integer is required")
+ raise ValueError("an integer is required")
if not pid_exists(pid):
- raise NoSuchProcess(pid, None, "no process found with PID %s" % pid)
+ raise NoSuchProcess(pid, None, "no process found with pid %s" % pid)
self._pid = pid
- # platform-specific modules define an PlatformProcess
+ # platform-specific modules define an _psplatform.Process
# implementation class
- self._platform_impl = PlatformProcess(pid)
+ self._platform_impl = _psplatform.Process(pid)
self._last_sys_cpu_times = None
self._last_proc_cpu_times = None
@@ -114,30 +115,18 @@ class Process(object):
try:
pid = self.pid
name = repr(self.name)
- cmdline = self.cmdline and repr(' '.join(self.cmdline))
except NoSuchProcess:
details = "(pid=%s (terminated))" % self.pid
except AccessDenied:
details = "(pid=%s)" % (self.pid)
else:
- if cmdline:
- details = "(pid=%s, name=%s, cmdline=%s)" % (pid, name, cmdline)
- else:
- details = "(pid=%s, name=%s)" % (pid, name)
- return "%s.%s %s" % (self.__class__.__module__,
- self.__class__.__name__, details)
+ details = "(pid=%s, name=%s)" % (pid, name)
+ return "%s.%s%s" % (self.__class__.__module__,
+ self.__class__.__name__, details)
def __repr__(self):
return "<%s at %s>" % (self.__str__(), id(self))
- def __eq__(self, other):
- """Test for equality with another Process object based on pid
- and creation time.
- """
- h1 = (self.pid, self.create_time)
- h2 = (other.pid, other.create_time)
- return h1 == h2
-
@property
def pid(self):
"""The process pid."""
@@ -150,11 +139,15 @@ class Process(object):
@property
def parent(self):
- """Return the parent process as a Process object. If no ppid is
- known then return None."""
- if self.ppid is not None:
- return Process(self.ppid)
- return None
+ """Return the parent process as a Process object. If no parent
+ pid is known return None.
+ """
+ ppid = self.ppid
+ if ppid is not None:
+ try:
+ return Process(ppid)
+ except NoSuchProcess:
+ pass
@property
def name(self):
@@ -185,37 +178,63 @@ class Process(object):
_exe = os.path.realpath(cmdline[0])
if os.path.isfile(_exe) and os.access(_exe, os.X_OK):
return _exe
+ if not exe:
+ raise AccessDenied(self.pid, self._platform_impl._process_name)
return exe
@property
- def path(self):
- msg = "'path' property is deprecated; use 'os.path.dirname(exe)' instead"
- warnings.warn(msg, DeprecationWarning)
- return os.path.dirname(self.exe)
-
- @property
def cmdline(self):
"""The command line process has been called with."""
return self._platform_impl.get_process_cmdline()
@property
- def uid(self):
- """The real user id of the current process."""
- return self._platform_impl.get_process_uid()
+ def status(self):
+ """The process current status as a STATUS_* constant."""
+ return self._platform_impl.get_process_status()
@property
- def gid(self):
- """The real group id of the current process."""
- return self._platform_impl.get_process_gid()
+ def nice(self):
+ """Get or set process niceness (priority)."""
+ return self._platform_impl.get_process_nice()
+
+ @nice.setter
+ def nice(self, value):
+ # invoked on "p.nice = num"; change process niceness
+ return self._platform_impl.set_process_nice(value)
+
+ if os.name == 'posix':
+
+ @property
+ def uids(self):
+ """Return a named tuple denoting the process real,
+ effective, and saved user ids.
+ """
+ return self._platform_impl.get_process_uids()
+
+ @property
+ def gids(self):
+ """Return a named tuple denoting the process real,
+ effective, and saved group ids.
+ """
+ return self._platform_impl.get_process_gids()
+
+ @property
+ def terminal(self):
+ """The terminal associated with this process, if any,
+ else None.
+ """
+ return self._platform_impl.get_process_terminal()
@property
def username(self):
- """The name of the user that owns the process."""
+ """The name of the user that owns the process.
+ On UNIX this is calculated by using *real* process uid.
+ """
if os.name == 'posix':
if pwd is None:
- # might happen on compiled-from-sources python
+ # might happen if python was installed from sources
raise ImportError("requires pwd module shipped with standard python")
- return pwd.getpwuid(self.uid).pw_name
+ return pwd.getpwuid(self.uids.real).pw_name
else:
return self._platform_impl.get_process_username()
@@ -227,17 +246,49 @@ class Process(object):
return self._platform_impl.get_process_create_time()
# available for Windows and Linux only
- if hasattr(PlatformProcess, "get_process_cwd"):
+ if hasattr(_psplatform.Process, "get_process_cwd"):
+
def getcwd(self):
"""Return a string representing the process current working
directory.
"""
return self._platform_impl.get_process_cwd()
+ # Linux, BSD and Windows only
+ if hasattr(_psplatform.Process, "get_process_io_counters"):
+
+ def get_io_counters(self):
+ """Return process I/O statistics as a namedtuple including
+ the number of read/write calls performed and the amount of
+ bytes read and written by the process.
+ """
+ return self._platform_impl.get_process_io_counters()
+
+ # available only on Linux
+ if hasattr(_psplatform.Process, "get_process_ionice"):
+
+ def get_ionice(self):
+ """Return process I/O niceness (priority) as a namedtuple."""
+ return self._platform_impl.get_process_ionice()
+
+ def set_ionice(self, ioclass, value=None):
+ """Set process I/O niceness (priority).
+ ioclass is one of the IOPRIO_CLASS_* constants.
+ iodata is a number which goes from 0 to 7. The higher the
+ value, the lower the I/O priority of the process.
+ """
+ return self._platform_impl.set_process_ionice(ioclass, value)
+
def get_num_threads(self):
"""Return the number of threads used by this process."""
return self._platform_impl.get_process_num_threads()
+ def get_threads(self):
+ """Return threads opened by process as a list of namedtuples
+ including thread id and thread CPU times (user/system).
+ """
+ return self._platform_impl.get_process_threads()
+
def get_children(self):
"""Return the children of this process as a list of Process
objects.
@@ -304,8 +355,7 @@ class Process(object):
def get_cpu_times(self):
"""Return a tuple whose values are process CPU user and system
- time. These are the same first two values that os.times()
- returns for the current process.
+ times. The same as os.times() but per-process.
"""
return self._platform_impl.get_cpu_times()
@@ -332,27 +382,34 @@ class Process(object):
def get_open_files(self):
"""Return files opened by process as a list of namedtuples
- including absolute file name and file descriptor.
+ including absolute file name and file descriptor number.
"""
return self._platform_impl.get_open_files()
def get_connections(self):
"""Return TCP and UPD connections opened by process as a list
- of namedtuple/s.
- For third party processes (!= os.getpid()) results can differ
- depending on user privileges.
+ of namedtuples.
+ On BSD and OSX results for third party processes (!= os.getpid())
+ can differ depending on user privileges.
"""
return self._platform_impl.get_connections()
def is_running(self):
- """Return whether the current process is running in the current
- process list.
- """
+ """Return whether this process is running."""
try:
- newproc = Process(self.pid)
- return self == newproc
+ # Test for equality with another Process object based
+ # on pid and creation time.
+ # This pair is supposed to indentify a Process instance
+ # univocally over the time (the PID alone is not enough as
+ # it might refer to a process which is gone in meantime
+ # and its PID reused by another process).
+ new_self = Process(self.pid)
+ p1 = (self.pid, self.create_time)
+ p2 = (new_self.pid, new_self.create_time)
except NoSuchProcess:
return False
+ else:
+ return p1 == p2
def send_signal(self, sig):
"""Send a signal to process (see signal module constants).
@@ -426,14 +483,66 @@ class Process(object):
else:
self._platform_impl.kill_process()
+ def wait(self, timeout=None):
+ """Wait for process to terminate and, if process is a children
+ of the current one also return its exit code, else None.
+ """
+ if timeout is not None and not timeout >= 0:
+ raise ValueError("timeout must be a positive integer")
+ return self._platform_impl.process_wait(timeout)
+
+
+class Popen(Process):
+ """A more convenient interface to stdlib subprocess module.
+ It starts a sub process and deals with it exactly as when using
+ subprocess.Popen class but in addition also provides all the
+ property and methods of psutil.Process class in a unique interface:
+
+ >>> import psutil
+ >>> from subprocess import PIPE
+ >>> p = psutil.Popen(["/usr/bin/python", "-c", "print 'hi'"], stdout=PIPE)
+ >>> p.name
+ 'python'
+ >>> p.uids
+ user(real=1000, effective=1000, saved=1000)
+ >>> p.username
+ 'giampaolo'
+ >>> p.communicate()
+ ('hi\n', None)
+ >>> p.terminate()
+ >>> p.wait(timeout=2)
+ 0
+ >>>
+
+ For method names common to both classes such as kill(), terminate()
+ and wait(), psutil.Process implementation takes precedence.
+
+ For a complete documentation refers to:
+ http://docs.python.org/library/subprocess.html
+ """
+
+ def __init__(self, *args, **kwargs):
+ self.__subproc = subprocess.Popen(*args, **kwargs)
+ Process.__init__(self, self.__subproc.pid)
+
+ def __dir__(self):
+ return list(set(dir(Popen) + dir(subprocess.Popen)))
+
+ def __getattribute__(self, name):
+ try:
+ return object.__getattribute__(self, name)
+ except AttributeError:
+ try:
+ return object.__getattribute__(self.__subproc, name)
+ except AttributeError:
+ raise AttributeError("%s instance has no attribute '%s'"
+ %(self.__class__.__name__, name))
def process_iter():
"""Return an iterator yielding a Process class instances for all
running processes on the local machine.
"""
pids = get_pid_list()
- # for each PID, create a proxyied Process object
- # it will lazy init it's name and path later if required
for pid in pids:
try:
yield Process(pid)
@@ -446,15 +555,34 @@ def get_process_list():
"""
return list(process_iter())
-def cpu_times():
- """Return system CPU times as a CPUTimes object."""
- values = get_system_cpu_times()
- return CPUTimes(**values)
+def cpu_times(percpu=False):
+ """Return system-wide CPU times as a namedtuple object.
+ Every CPU time represents the time CPU has spent in the given mode.
+ The attributes availability varies depending on the platform.
+ Here follows a list of all available attributes:
+ - user
+ - system
+ - idle
+ - nice (UNIX)
+ - iowait (Linux)
+ - irq (Linux, FreeBSD)
+ - softirq (Linux)
+
+ When percpu is True return a list of nameduples for each CPU.
+ First element of the list refers to first CPU, second element
+ to second CPU and so on.
+ The order of the list is consistent across calls.
+ """
+ if not percpu:
+ return _psplatform.get_system_cpu_times()
+ else:
+ return _psplatform.get_system_per_cpu_times()
_last_cpu_times = cpu_times()
+_last_per_cpu_times = cpu_times(percpu=True)
-def cpu_percent(interval=0.1):
+def cpu_percent(interval=0.1, percpu=False):
"""Return a float representing the current system-wide CPU
utilization as a percentage.
@@ -465,33 +593,184 @@ def cpu_percent(interval=0.1):
since last call or module import, returning immediately.
In this case is recommended for accuracy that this function be
called with at least 0.1 seconds between calls.
+
+ When percpu is True returns a list of floats representing the
+ utilization as a percentage for each CPU.
+ First element of the list refers to first CPU, second element
+ to second CPU and so on.
+ The order of the list is consistent across calls.
"""
global _last_cpu_times
-
+ global _last_per_cpu_times
blocking = interval is not None and interval > 0.0
- if blocking:
- t1 = cpu_times()
- time.sleep(interval)
+
+ def calculate(t1, t2):
+ t1_all = sum(t1)
+ t1_busy = t1_all - t1.idle
+
+ t2_all = sum(t2)
+ t2_busy = t2_all - t2.idle
+
+ # 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
+ busy_perc = (busy_delta / all_delta) * 100
+ return round(busy_perc, 1)
+
+ # system-wide usage
+ if not percpu:
+ if blocking:
+ t1 = cpu_times()
+ time.sleep(interval)
+ else:
+ t1 = _last_cpu_times
+ _last_cpu_times = cpu_times()
+ return calculate(t1, _last_cpu_times)
+ # per-cpu usage
else:
- t1 = _last_cpu_times
+ ret = []
+ if blocking:
+ tot1 = cpu_times(percpu=True)
+ time.sleep(interval)
+ else:
+ tot1 = _last_per_cpu_times
+ _last_per_cpu_times = cpu_times(percpu=True)
+ for t1, t2 in zip(tot1, _last_per_cpu_times):
+ ret.append(calculate(t1, t2))
+ return ret
+
+def phymem_usage():
+ """Return the amount of total, used and free physical memory
+ on the system in bytes plus the percentage usage.
+ """
+ return _psplatform.phymem_usage()
+
+def virtmem_usage():
+ """Return the amount of total, used and free virtual memory
+ on the system in bytes plus the percentage usage.
+
+ On Linux they match the values returned by free command line utility.
+ On OS X and FreeBSD they represent the same values as returned by
+ sysctl vm.vmtotal. On Windows they are determined by reading the
+ PageFile values of MEMORYSTATUSEX structure.
+ """
+ return _psplatform.virtmem_usage()
- t1_all = sum(t1)
- t1_busy = t1_all - t1.idle
+def disk_usage(path):
+ """Return disk usage statistics about the given path as a namedtuple
+ including total, used and free space expressed in bytes plus the
+ percentage usage.
+ """
+ return _psplatform.get_disk_usage(path)
- t2 = cpu_times()
- t2_all = sum(t2)
- t2_busy = t2_all - t2.idle
+def disk_partitions(all=False):
+ """Return mounted partitions as a list of namedtuples including
+ device, mount point and filesystem type.
- _last_cpu_times = t1
- # this usually indicates a float precision issue
- if t2_busy <= t1_busy:
- return 0.0
+ If "all" parameter is False return physical devices only and ignore
+ all others.
+ """
+ return _psplatform.disk_partitions(all)
- busy_delta = t2_busy - t1_busy
- all_delta = t2_all - t1_all
- busy_perc = (busy_delta / all_delta) * 100
- return round(busy_perc, 1)
+if hasattr(_psplatform, "network_io_counters"):
+ def network_io_counters(pernic=False):
+ """Return network I/O statistics as a namedtuple including:
+ - number of bytes sent
+ - number of bytes received
+ - number of packets sent
+ - number of packets received
+
+ If pernic is True return the same information for every
+ network interface installed on the system as a dictionary
+ with network interface names as the keys and the namedtuple
+ described above as the values.
+ """
+ from psutil._common import ntuple_net_iostat
+ rawdict = _psplatform.network_io_counters()
+ if pernic:
+ for nic, fields in rawdict.iteritems():
+ rawdict[nic] = ntuple_net_iostat(*fields)
+ return rawdict
+ else:
+ bytes_sent, bytes_recv, packets_sent, packets_recv = 0, 0, 0, 0
+ for _, fields in rawdict.iteritems():
+ bytes_sent += fields[0]
+ bytes_recv += fields[1]
+ packets_sent += fields[2]
+ packets_recv += fields[3]
+ return ntuple_net_iostat(bytes_sent, bytes_recv,
+ packets_sent, packets_recv)
+
+if hasattr(_psplatform, "disk_io_counters"):
+
+ def disk_io_counters(perdisk=False):
+ """Return system disk I/O statistics as a namedtuple including:
+ - number of bytes read
+ - number of bytes written
+ - number of reads
+ - number of writes
+ - time spent reading from disk (in nanoseconds)
+ - time spent writing to disk (in nanoseconds)
+
+ If perdisk is True return the same information for every
+ physical disk installed on the system as a dictionary
+ with partition names as the keys and the namedutuple
+ described above as the values.
+ """
+ from psutil._common import ntuple_disk_iostat
+ rawdict = _psplatform.disk_io_counters()
+ if perdisk:
+ for disk, fields in rawdict.iteritems():
+ rawdict[disk] = ntuple_disk_iostat(*fields)
+ return rawdict
+ else:
+ reads, writes, rbytes, wbytes, rtime, wtime = 0, 0, 0, 0, 0, 0
+ for _, fields in rawdict.iteritems():
+ reads += fields[0]
+ writes += fields[1]
+ rbytes += fields[2]
+ wbytes += fields[3]
+ rtime += fields[4]
+ wtime += fields[5]
+ return ntuple_disk_iostat(reads, writes, rbytes, wbytes, rtime, wtime)
+
+
+def _deprecated(replacement):
+ # a decorator which can be used to mark functions as deprecated
+ def outer(fun):
+ def inner(*args, **kwargs):
+ msg = "psutil.%s is deprecated; use %s instead" \
+ % (fun.__name__, replacement)
+ warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
+ return fun(*args, **kwargs)
+ return inner
+ return outer
+
+# --- deprecated functions
+
+@_deprecated("psutil.phymem_usage")
+def avail_phymem():
+ return phymem_usage().free
+
+@_deprecated("psutil.phymem_usage")
+def used_phymem():
+ return phymem_usage().used
+
+@_deprecated("psutil.virtmem_usage")
+def total_virtmem():
+ return virtmem_usage().total
+
+@_deprecated("psutil.virtmem_usage")
+def used_virtmem():
+ return virtmem_usage().used
+
+@_deprecated("psutil.virtmem_usage")
+def avail_virtmem():
+ return virtmem_usage().free
def test():
"""List info of all currently running processes emulating a
diff --git a/third_party/psutil/psutil/_common.py b/third_party/psutil/psutil/_common.py
new file mode 100644
index 0000000..e08011d
--- /dev/null
+++ b/third_party/psutil/psutil/_common.py
@@ -0,0 +1,69 @@
+#/usr/bin/env python
+#
+#$Id: _common.py 1142 2011-10-05 18:45:49Z g.rodola $
+#
+# 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.
+
+"""Common objects shared by all _ps* modules."""
+
+from psutil._compat import namedtuple
+
+def usage_percent(used, total, _round=None):
+ """Calculate percentage usage of 'used' against 'total'."""
+ try:
+ ret = (float(used) / total) * 100
+ except ZeroDivisionError:
+ ret = 0
+ if _round is not None:
+ return round(ret, _round)
+ else:
+ return ret
+
+
+class constant(int):
+ """A constant type; overrides base int to provide a useful name on str()."""
+
+ def __new__(cls, value, name, doc=None):
+ inst = super(constant, cls).__new__(cls, value)
+ inst._name = name
+ if doc is not None:
+ inst.__doc__ = doc
+ return inst
+
+ def __str__(self):
+ return self._name
+
+STATUS_RUNNING = constant(0, "running")
+STATUS_SLEEPING = constant(1, "sleeping")
+STATUS_DISK_SLEEP = constant(2, "disk sleep")
+STATUS_STOPPED = constant(3, "stopped")
+STATUS_TRACING_STOP = constant(4, "tracing stop")
+STATUS_ZOMBIE = constant(5, "zombie")
+STATUS_DEAD = constant(6, "dead")
+STATUS_WAKE_KILL = constant(7, "wake kill")
+STATUS_WAKING = constant(8, "waking")
+STATUS_IDLE = constant(9, "idle") # BSD
+STATUS_LOCKED = constant(10, "locked") # BSD
+STATUS_WAITING = constant(11, "waiting") # BSD
+
+
+# system
+ntuple_sys_cputimes = namedtuple('cputimes', 'user nice system idle iowait irq softirq')
+ntuple_sysmeminfo = namedtuple('usage', 'total used free percent')
+ntuple_diskinfo = namedtuple('usage', 'total used free percent')
+ntuple_partition = namedtuple('partition', 'device mountpoint fstype')
+ntuple_net_iostat = namedtuple('iostat', 'bytes_sent bytes_recv packets_sent packets_recv')
+ntuple_disk_iostat = namedtuple('iostat', 'read_count write_count read_bytes write_bytes read_time write_time')
+
+# processes
+ntuple_meminfo = namedtuple('meminfo', 'rss vms')
+ntuple_cputimes = namedtuple('cputimes', 'user system')
+ntuple_openfile = namedtuple('openfile', 'path fd')
+ntuple_connection = namedtuple('connection', 'fd family type local_address remote_address status')
+ntuple_thread = namedtuple('thread', 'id user_time system_time')
+ntuple_uids = namedtuple('user', 'real effective saved')
+ntuple_gids = namedtuple('group', 'real effective saved')
+ntuple_io = namedtuple('io', 'read_count write_count read_bytes write_bytes')
+ntuple_ionice = namedtuple('ionice', 'ioclass value')
diff --git a/third_party/psutil/psutil/_compat.py b/third_party/psutil/psutil/_compat.py
new file mode 100644
index 0000000..1cac8b7
--- /dev/null
+++ b/third_party/psutil/psutil/_compat.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+#
+# $Id: _compat.py 1142 2011-10-05 18:45:49Z g.rodola $
+#
+# 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.
+
+"""Module which provides compatibility with older Python versions."""
+
+__all__ = ["namedtuple", "property"]
+
+from operator import itemgetter as _itemgetter
+from keyword import iskeyword as _iskeyword
+import sys as _sys
+import __builtin__
+
+try:
+ from collections import namedtuple
+except ImportError:
+ def namedtuple(typename, field_names, verbose=False, rename=False):
+ """A collections.namedtuple implementation written in Python
+ to support Python versions < 2.6.
+
+ Taken from: http://code.activestate.com/recipes/500261/
+ """
+ # Parse and validate the field names. Validation serves two
+ # purposes, generating informative error messages and preventing
+ # template injection attacks.
+ if isinstance(field_names, basestring):
+ # names separated by whitespace and/or commas
+ field_names = field_names.replace(',', ' ').split()
+ field_names = tuple(map(str, field_names))
+ if rename:
+ names = list(field_names)
+ seen = set()
+ for i, name in enumerate(names):
+ if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
+ or not name or name[0].isdigit() or name.startswith('_')
+ or name in seen):
+ names[i] = '_%d' % i
+ seen.add(name)
+ field_names = tuple(names)
+ for name in (typename,) + field_names:
+ if not min(c.isalnum() or c=='_' for c in name):
+ raise ValueError('Type names and field names can only contain ' \
+ 'alphanumeric characters and underscores: %r'
+ % name)
+ if _iskeyword(name):
+ raise ValueError('Type names and field names cannot be a keyword: %r' \
+ % name)
+ if name[0].isdigit():
+ raise ValueError('Type names and field names cannot start with a ' \
+ 'number: %r' % name)
+ seen_names = set()
+ for name in field_names:
+ if name.startswith('_') and not rename:
+ raise ValueError('Field names cannot start with an underscore: %r'
+ % name)
+ if name in seen_names:
+ raise ValueError('Encountered duplicate field name: %r' % name)
+ seen_names.add(name)
+
+ # Create and fill-in the class template
+ numfields = len(field_names)
+ # tuple repr without parens or quotes
+ argtxt = repr(field_names).replace("'", "")[1:-1]
+ reprtxt = ', '.join('%s=%%r' % name for name in field_names)
+ template = '''class %(typename)s(tuple):
+ '%(typename)s(%(argtxt)s)' \n
+ __slots__ = () \n
+ _fields = %(field_names)r \n
+ def __new__(_cls, %(argtxt)s):
+ return _tuple.__new__(_cls, (%(argtxt)s)) \n
+ @classmethod
+ def _make(cls, iterable, new=tuple.__new__, len=len):
+ 'Make a new %(typename)s object from a sequence or iterable'
+ result = new(cls, iterable)
+ if len(result) != %(numfields)d:
+ raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
+ return result \n
+ def __repr__(self):
+ return '%(typename)s(%(reprtxt)s)' %% self \n
+ def _asdict(self):
+ 'Return a new dict which maps field names to their values'
+ return dict(zip(self._fields, self)) \n
+ def _replace(_self, **kwds):
+ 'Return a new %(typename)s object replacing specified fields with new values'
+ result = _self._make(map(kwds.pop, %(field_names)r, _self))
+ if kwds:
+ raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
+ return result \n
+ def __getnewargs__(self):
+ return tuple(self) \n\n''' % locals()
+ for i, name in enumerate(field_names):
+ template += ' %s = _property(_itemgetter(%d))\n' % (name, i)
+ if verbose:
+ print template
+
+ # Execute the template string in a temporary namespace
+ namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
+ _property=property, _tuple=tuple)
+ try:
+ exec template in namespace
+ except SyntaxError, e:
+ raise SyntaxError(e.message + ':\n' + template)
+ result = namespace[typename]
+
+ # For pickling to work, the __module__ variable needs to be set
+ # to the frame where the named tuple is created. Bypass this
+ # step in enviroments where sys._getframe is not defined (Jython
+ # for example) or sys._getframe is not defined for arguments
+ # greater than 0 (IronPython).
+ try:
+ result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
+ except (AttributeError, ValueError):
+ pass
+
+ return result
+
+
+# dirty hack to support property.setter on python < 2.6
+property = property
+
+if not hasattr(property, "setter"):
+
+ class property(property):
+
+ def __init__(self, fget, *args, **kwargs):
+ self.__doc__ = fget.__doc__
+ super(property, self).__init__(fget, *args, **kwargs)
+
+ def setter(self, fset):
+ cls_ns = _sys._getframe(1).f_locals
+ for k, v in cls_ns.iteritems():
+ if v == self:
+ propname = k
+ break
+ cls_ns[propname] = property(self.fget, fset,
+ self.fdel, self.__doc__)
+ return cls_ns[propname]
+
+ def deleter(self, fdel):
+ cls_ns = _sys._getframe(1).f_locals
+ for k, v in cls_ns.iteritems():
+ if v == self:
+ propname = k
+ break
+ cls_ns[propname] = property(self.fget, self.fset,
+ fdel, self.__doc__)
+ return cls_ns[propname]
+
+ __builtin__.property = property
+
diff --git a/third_party/psutil/psutil/_psbsd.py b/third_party/psutil/psutil/_psbsd.py
index 6c4624e..b437a6a 100644
--- a/third_party/psutil/psutil/_psbsd.py
+++ b/third_party/psutil/psutil/_psbsd.py
@@ -1,62 +1,84 @@
#!/usr/bin/env python
#
-# $Id: _psbsd.py 806 2010-11-12 23:09:35Z g.rodola $
+# $Id: _psbsd.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
+
+"""FreeBSD platform implementation."""
import errno
import os
-try:
- from collections import namedtuple
-except ImportError:
- from psutil.compat import namedtuple # python < 2.6
-
import _psutil_bsd
+import _psutil_posix
import _psposix
-from psutil.error import AccessDenied, NoSuchProcess
+from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
+from psutil._compat import namedtuple
+from psutil._common import *
+__extra__all__ = []
# --- constants
NUM_CPUS = _psutil_bsd.get_num_cpus()
-TOTAL_PHYMEM = _psutil_bsd.get_total_phymem()
+BOOT_TIME = _psutil_bsd.get_system_boot_time()
+_TERMINAL_MAP = _psposix._get_terminal_map()
+_cputimes_ntuple = namedtuple('cputimes', 'user nice system idle irq')
# --- public functions
-def avail_phymem():
- "Return the amount of physical memory available on the system, in bytes."
- return _psutil_bsd.get_avail_phymem()
-
-def used_phymem():
- "Return the amount of physical memory currently in use on the system, in bytes."
- return TOTAL_PHYMEM - _psutil_bsd.get_avail_phymem()
-
-def total_virtmem():
- "Return the amount of total virtual memory available on the system, in bytes."
- return _psutil_bsd.get_total_virtmem()
-
-def avail_virtmem():
- "Return the amount of virtual memory currently in use on the system, in bytes."
- return _psutil_bsd.get_avail_virtmem()
-
-def used_virtmem():
- """Return the amount of used memory currently in use on the system, in bytes."""
- return _psutil_bsd.get_total_virtmem() - _psutil_bsd.get_avail_virtmem()
+def phymem_usage():
+ """Physical system memory as a (total, used, free) tuple."""
+ total = _psutil_bsd.get_total_phymem()
+ free = _psutil_bsd.get_avail_phymem()
+ used = total - free
+ # XXX check out whether we have to do the same math we do on Linux
+ percent = usage_percent(used, total, _round=1)
+ return ntuple_sysmeminfo(total, used, free, percent)
+
+def virtmem_usage():
+ """Virtual system memory as a (total, used, free) tuple."""
+ total = _psutil_bsd.get_total_virtmem()
+ free = _psutil_bsd.get_avail_virtmem()
+ used = total - free
+ percent = usage_percent(used, total, _round=1)
+ return ntuple_sysmeminfo(total, used, free, percent)
def get_system_cpu_times():
- """Return a dict representing the following CPU times:
- user, nice, system, idle, interrupt."""
- values = _psutil_bsd.get_system_cpu_times()
- return dict(user=values[0], nice=values[1], system=values[2],
- idle=values[3], irq=values[4])
-
-def get_pid_list():
- """Returns a list of PIDs currently running on the system."""
- return _psutil_bsd.get_pid_list()
-
-def pid_exists(pid):
- """Check For the existence of a unix pid."""
- return _psposix.pid_exists(pid)
+ """Return system per-CPU times as a named tuple"""
+ user, nice, system, idle, irq = _psutil_bsd.get_system_cpu_times()
+ return _cputimes_ntuple(user, nice, system, idle, irq)
+
+def get_system_per_cpu_times():
+ """Return system CPU times as a named tuple"""
+ ret = []
+ for cpu_t in _psutil_bsd.get_system_per_cpu_times():
+ user, nice, system, idle, irq = cpu_t
+ item = _cputimes_ntuple(user, nice, system, idle, irq)
+ ret.append(item)
+ return ret
+
+def disk_partitions(all=False):
+ retlist = []
+ partitions = _psutil_bsd.get_disk_partitions()
+ for partition in partitions:
+ device, mountpoint, fstype = partition
+ if device == 'none':
+ device = ''
+ if not all:
+ if not os.path.isabs(device) \
+ or not os.path.exists(device):
+ continue
+ ntuple = ntuple_partition(device, mountpoint, fstype)
+ retlist.append(ntuple)
+ return retlist
+
+get_pid_list = _psutil_bsd.get_pid_list
+pid_exists = _psposix.pid_exists
+get_disk_usage = _psposix.get_disk_usage
+network_io_counters = _psutil_osx.get_network_io_counters
def wrap_exceptions(method):
@@ -75,12 +97,20 @@ def wrap_exceptions(method):
raise
return wrapper
+_status_map = {
+ _psutil_bsd.SSTOP : STATUS_STOPPED,
+ _psutil_bsd.SSLEEP : STATUS_SLEEPING,
+ _psutil_bsd.SRUN : STATUS_RUNNING,
+ _psutil_bsd.SIDL : STATUS_IDLE,
+ _psutil_bsd.SWAIT : STATUS_WAITING,
+ _psutil_bsd.SLOCK : STATUS_LOCKED,
+ _psutil_bsd.SZOMB : STATUS_ZOMBIE,
+}
+
-class BSDProcess(object):
+class Process(object):
"""Wrapper class around underlying C implementation."""
- _meminfo_ntuple = namedtuple('meminfo', 'rss vms')
- _cputimes_ntuple = namedtuple('cputimes', 'user system')
__slots__ = ["pid", "_process_name"]
def __init__(self, pid):
@@ -92,10 +122,10 @@ class BSDProcess(object):
"""Return process name as a string of limited len (15)."""
return _psutil_bsd.get_process_name(self.pid)
+ @wrap_exceptions
def get_process_exe(self):
- # no such thing as "exe" on BSD; it will maybe be determined
- # later from cmdline[0]
- return ""
+ """Return process executable pathname."""
+ return _psutil_bsd.get_process_exe(self.pid)
@wrap_exceptions
def get_process_cmdline(self):
@@ -103,31 +133,41 @@ class BSDProcess(object):
return _psutil_bsd.get_process_cmdline(self.pid)
@wrap_exceptions
+ def get_process_terminal(self):
+ tty_nr = _psutil_bsd.get_process_tty_nr(self.pid)
+ try:
+ return _TERMINAL_MAP[tty_nr]
+ except KeyError:
+ return None
+
+ @wrap_exceptions
def get_process_ppid(self):
"""Return process parent pid."""
return _psutil_bsd.get_process_ppid(self.pid)
@wrap_exceptions
- def get_process_uid(self):
- """Return process real user id."""
- return _psutil_bsd.get_process_uid(self.pid)
+ def get_process_uids(self):
+ """Return real, effective and saved user ids."""
+ real, effective, saved = _psutil_bsd.get_process_uids(self.pid)
+ return ntuple_uids(real, effective, saved)
@wrap_exceptions
- def get_process_gid(self):
- """Return process real group id."""
- return _psutil_bsd.get_process_gid(self.pid)
+ def get_process_gids(self):
+ """Return real, effective and saved group ids."""
+ real, effective, saved = _psutil_bsd.get_process_gids(self.pid)
+ return ntuple_gids(real, effective, saved)
@wrap_exceptions
def get_cpu_times(self):
"""return a tuple containing process user/kernel time."""
user, system = _psutil_bsd.get_cpu_times(self.pid)
- return self._cputimes_ntuple(user, system)
+ return ntuple_cputimes(user, system)
@wrap_exceptions
def get_memory_info(self):
"""Return a tuple with the process' RSS and VMS size."""
rss, vms = _psutil_bsd.get_memory_info(self.pid)
- return self._meminfo_ntuple(rss, vms)
+ return ntuple_meminfo(rss, vms)
@wrap_exceptions
def get_process_create_time(self):
@@ -140,6 +180,16 @@ class BSDProcess(object):
"""Return the number of threads belonging to the process."""
return _psutil_bsd.get_process_num_threads(self.pid)
+ @wrap_exceptions
+ def get_process_threads(self):
+ """Return the number of threads belonging to the process."""
+ rawlist = _psutil_bsd.get_process_threads(self.pid)
+ retlist = []
+ for thread_id, utime, stime in rawlist:
+ ntuple = ntuple_thread(thread_id, utime, stime)
+ retlist.append(ntuple)
+ return retlist
+
def get_open_files(self):
"""Return files opened by process by parsing lsof output."""
lsof = _psposix.LsofParser(self.pid, self._process_name)
@@ -152,6 +202,29 @@ class BSDProcess(object):
lsof = _psposix.LsofParser(self.pid, self._process_name)
return lsof.get_process_connections()
+ @wrap_exceptions
+ def process_wait(self, timeout=None):
+ try:
+ return _psposix.wait_pid(self.pid, timeout)
+ except TimeoutExpired:
+ raise TimeoutExpired(self.pid, self._process_name)
+
+ @wrap_exceptions
+ def get_process_nice(self):
+ return _psutil_posix.getpriority(self.pid)
+
+ @wrap_exceptions
+ def set_process_nice(self, value):
+ return _psutil_posix.setpriority(self.pid, value)
-PlatformProcess = BSDProcess
+ @wrap_exceptions
+ def get_process_status(self):
+ code = _psutil_bsd.get_process_status(self.pid)
+ if code in _status_map:
+ return _status_map[code]
+ return constant(-1, "?")
+ @wrap_exceptions
+ def get_process_io_counters(self):
+ rc, wc, rb, wb = _psutil_bsd.get_process_io_counters(self.pid)
+ return ntuple_io(rc, wc, rb, wb)
diff --git a/third_party/psutil/psutil/_pslinux.py b/third_party/psutil/psutil/_pslinux.py
index 26a8abf..443b6ad 100644..100755
--- a/third_party/psutil/psutil/_pslinux.py
+++ b/third_party/psutil/psutil/_pslinux.py
@@ -1,15 +1,12 @@
#!/usr/bin/env python
#
-# $Id: _pslinux.py 800 2010-11-12 21:51:25Z g.rodola $
+# $Id: _pslinux.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
-__all__ = ["NUM_CPUS", "TOTAL_PHYMEM",
- "PlatformProcess",
- "avail_phymem", "used_phymem", "total_virtmem", "avail_virtmem",
- "used_virtmem", "get_system_cpu_times", "pid_exists", "get_pid_list",
- "phymem_buffers", "cached_phymem"
- ]
-
+"""Linux platform implementation."""
import os
import errno
@@ -17,50 +14,72 @@ import socket
import struct
import sys
import base64
+import re
-try:
- from collections import namedtuple
-except ImportError:
- from psutil.compat import namedtuple # python < 2.6
-
+import _psutil_posix
+import _psutil_linux
from psutil import _psposix
-from psutil.error import AccessDenied, NoSuchProcess
+from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
+from psutil._common import *
+
+__extra__all__ = [
+ "IOPRIO_CLASS_NONE", "IOPRIO_CLASS_RT", "IOPRIO_CLASS_BE",
+ "IOPRIO_CLASS_IDLE",
+ "phymem_buffers", "cached_phymem"]
-def _get_uptime():
+def _get_boot_time():
"""Return system boot time (epoch in seconds)"""
f = open('/proc/stat', 'r')
- for line in f:
- if line.startswith('btime'):
- f.close()
- return float(line.strip().split()[1])
+ try:
+ for line in f:
+ if line.startswith('btime'):
+ return float(line.strip().split()[1])
+ raise RuntimeError("line not found")
+ finally:
+ f.close()
def _get_num_cpus():
"""Return the number of CPUs on the system"""
num = 0
f = open('/proc/cpuinfo', 'r')
- for line in f:
- if line.startswith('processor'):
+ try:
+ lines = f.readlines()
+ finally:
+ f.close()
+ for line in lines:
+ if line.lower().startswith('processor'):
num += 1
- f.close()
- return num
-def _get_total_phymem():
- """Return the total amount of physical memory, in bytes"""
- f = open('/proc/meminfo', 'r')
- for line in f:
- if line.startswith('MemTotal:'):
+ # unknown format (e.g. amrel/sparc architectures), see:
+ # http://code.google.com/p/psutil/issues/detail?id=200
+ if num == 0:
+ f = open('/proc/stat', 'r')
+ try:
+ lines = f.readlines()
+ finally:
f.close()
- return int(line.split()[1]) * 1024
+ search = re.compile('cpu\d')
+ for line in lines:
+ line = line.split(' ')[0]
+ if search.match(line):
+ num += 1
+
+ if num == 0:
+ raise RuntimeError("can't determine number of CPUs")
+ return num
# Number of clock ticks per second
_CLOCK_TICKS = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
-_UPTIME = _get_uptime()
+_TERMINAL_MAP = _psposix._get_terminal_map()
+BOOT_TIME = _get_boot_time()
NUM_CPUS = _get_num_cpus()
-TOTAL_PHYMEM = _get_total_phymem()
-
-del _get_uptime, _get_num_cpus, _get_total_phymem
+# ioprio_* constants http://linux.die.net/man/2/ioprio_get
+IOPRIO_CLASS_NONE = 0
+IOPRIO_CLASS_RT = 1
+IOPRIO_CLASS_BE = 2
+IOPRIO_CLASS_IDLE = 3
# http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
_TCP_STATES_TABLE = {"01" : "ESTABLISHED",
@@ -76,55 +95,20 @@ _TCP_STATES_TABLE = {"01" : "ESTABLISHED",
"0B" : "CLOSING"
}
-def avail_phymem():
- """Return the amount of physical memory available, in bytes."""
- f = open('/proc/meminfo', 'r')
- free = None
- _flag = False
- for line in f:
- if line.startswith('MemFree:'):
- free = int(line.split()[1]) * 1024
- break
- f.close()
- return free
-
-def used_phymem():
- """"Return the amount of physical memory used, in bytes."""
- return (TOTAL_PHYMEM - avail_phymem())
-
-def total_virtmem():
- """"Return the total amount of virtual memory, in bytes."""
- f = open('/proc/meminfo', 'r')
- for line in f:
- if line.startswith('SwapTotal:'):
- f.close()
- return int(line.split()[1]) * 1024
-
-def avail_virtmem():
- """Return the amount of virtual memory currently in use on the
- system, in bytes.
- """
- f = open('/proc/meminfo', 'r')
- for line in f:
- if line.startswith('SwapFree:'):
- f.close()
- return int(line.split()[1]) * 1024
-
-def used_virtmem():
- """Return the amount of used memory currently in use on the system,
- in bytes.
- """
- return total_virtmem() - avail_virtmem()
+# --- system memory functions
def cached_phymem():
"""Return the amount of cached memory on the system, in bytes.
This reflects the "cached" column of free command line utility.
"""
f = open('/proc/meminfo', 'r')
- for line in f:
- if line.startswith('Cached:'):
- f.close()
- return int(line.split()[1]) * 1024
+ try:
+ for line in f:
+ if line.startswith('Cached:'):
+ return int(line.split()[1]) * 1024
+ raise RuntimeError("line not found")
+ finally:
+ f.close()
def phymem_buffers():
"""Return the amount of physical memory buffers used by the
@@ -132,36 +116,207 @@ def phymem_buffers():
This reflects the "buffers" column of free command line utility.
"""
f = open('/proc/meminfo', 'r')
- for line in f:
- if line.startswith('Buffers:'):
- f.close()
- return int(line.split()[1]) * 1024
+ try:
+ for line in f:
+ if line.startswith('Buffers:'):
+ return int(line.split()[1]) * 1024
+ raise RuntimeError("line not found")
+ finally:
+ f.close()
+
+def phymem_usage():
+ # total, used and free values are matched against free cmdline utility
+ # the percentage matches top/htop and gnome-system-monitor
+ f = open('/proc/meminfo', 'r')
+ try:
+ total = free = buffers = cached = None
+ for line in f:
+ if line.startswith('MemTotal:'):
+ total = int(line.split()[1]) * 1024
+ elif line.startswith('MemFree:'):
+ free = int(line.split()[1]) * 1024
+ elif line.startswith('Buffers:'):
+ buffers = int(line.split()[1]) * 1024
+ elif line.startswith('Cached:'):
+ cached = int(line.split()[1]) * 1024
+ break
+ used = total - free
+ percent = usage_percent(total - (free + buffers + cached), total,
+ _round=1)
+ return ntuple_sysmeminfo(total, used, free, percent)
+ finally:
+ f.close()
+
+
+def virtmem_usage():
+ f = open('/proc/meminfo', 'r')
+ try:
+ total = free = None
+ for line in f:
+ if line.startswith('SwapTotal:'):
+ total = int(line.split()[1]) * 1024
+ elif line.startswith('SwapFree:'):
+ free = int(line.split()[1]) * 1024
+ if total is not None and free is not None:
+ break
+ assert total is not None and free is not None
+ used = total - free
+ percent = usage_percent(used, total, _round=1)
+ return ntuple_sysmeminfo(total, used, free, percent)
+ finally:
+ f.close()
+
+
+# --- system CPU functions
def get_system_cpu_times():
- """Return a dict representing the following CPU times:
+ """Return a named tuple representing the following CPU times:
user, nice, system, idle, iowait, irq, softirq.
"""
f = open('/proc/stat', 'r')
- values = f.readline().split()
- f.close()
+ try:
+ values = f.readline().split()
+ finally:
+ f.close()
values = values[1:8]
values = tuple([float(x) / _CLOCK_TICKS for x in values])
+ return ntuple_sys_cputimes(*values[:7])
+
+def get_system_per_cpu_times():
+ """Return a list of namedtuple representing the CPU times
+ for every CPU available on the system.
+ """
+ cpus = []
+ f = open('/proc/stat', 'r')
+ # get rid of the first line who refers to system wide CPU stats
+ try:
+ f.readline()
+ for line in f.readlines():
+ if line.startswith('cpu'):
+ values = line.split()[1:8]
+ values = tuple([float(x) / _CLOCK_TICKS for x in values])
+ entry = ntuple_sys_cputimes(*values[:7])
+ cpus.append(entry)
+ return cpus
+ finally:
+ f.close()
- return dict(user=values[0], nice=values[1], system=values[2], idle=values[3],
- iowait=values[4], irq=values[5], softirq=values[6])
+
+# --- system disk functions
+
+def disk_partitions(all=False):
+ """Return mounted disk partitions as a list of nameduples"""
+ phydevs = []
+ f = open("/proc/filesystems", "r")
+ try:
+ for line in f:
+ if not line.startswith("nodev"):
+ phydevs.append(line.strip())
+ finally:
+ f.close()
+
+ retlist = []
+ partitions = _psutil_linux.get_disk_partitions()
+ for partition in partitions:
+ device, mountpoint, fstype = partition
+ if device == 'none':
+ device = ''
+ if not all:
+ if device == '' or fstype not in phydevs:
+ continue
+ ntuple = ntuple_partition(device, mountpoint, fstype)
+ retlist.append(ntuple)
+ return retlist
+
+get_disk_usage = _psposix.get_disk_usage
+
+# --- process functions
def get_pid_list():
"""Returns a list of PIDs currently running on the system."""
pids = [int(x) for x in os.listdir('/proc') if x.isdigit()]
- # special case for 0 (kernel process) PID
- pids.insert(0, 0)
return pids
def pid_exists(pid):
"""Check For the existence of a unix pid."""
return _psposix.pid_exists(pid)
+def network_io_counters():
+ """Return network I/O statistics for every network interface
+ installed on the system as a dict of raw tuples.
+ """
+ f = open("/proc/net/dev", "r")
+ try:
+ lines = f.readlines()
+ finally:
+ f.close()
+
+ retdict = {}
+ for line in lines[2:]:
+ fields = line.split()
+ name = fields[0][:-1]
+ bytes_recv = int(fields[1])
+ packets_recv = int(fields[2])
+ bytes_sent = int(fields[9])
+ packets_sent = int(fields[10])
+ retdict[name] = (bytes_sent, bytes_recv, packets_sent, packets_recv)
+ return retdict
+
+def disk_io_counters():
+ """Return disk I/O statistics for every disk installed on the
+ system as a dict of raw tuples.
+ """
+ # man iostat states that sectors are equivalent with blocks and
+ # have a size of 512 bytes since 2.4 kernels. This value is
+ # needed to calculate the amount of disk I/O in bytes.
+ SECTOR_SIZE = 512
+
+ # determine partitions we want to look for
+ partitions = []
+ f = open("/proc/partitions", "r")
+ try:
+ lines = f.readlines()[2:]
+ finally:
+ f.close()
+ for line in lines:
+ _, _, _, name = line.split()
+ if name[-1].isdigit():
+ partitions.append(name)
+ #
+ retdict = {}
+ f = open("/proc/diskstats", "r")
+ try:
+ lines = f.readlines()
+ finally:
+ f.close()
+ for line in lines:
+ _, _, name, reads, _, rbytes, rtime, writes, _, wbytes, wtime = \
+ line.split()[:11]
+ if name in partitions:
+ rbytes = int(rbytes) * SECTOR_SIZE
+ wbytes = int(wbytes) * SECTOR_SIZE
+ reads = int(reads)
+ writes = int(writes)
+ # TODO: times are expressed in milliseconds while OSX/BSD has
+ # these expressed in nanoseconds; figure this out.
+ rtime = int(rtime)
+ wtime = int(wtime)
+ retdict[name] = (reads, writes, rbytes, wbytes, rtime, wtime)
+ return retdict
+
+
+# taken from /fs/proc/array.c
+_status_map = {"R" : STATUS_RUNNING,
+ "S" : STATUS_SLEEPING,
+ "D" : STATUS_DISK_SLEEP,
+ "T" : STATUS_STOPPED,
+ "t" : STATUS_TRACING_STOP,
+ "Z" : STATUS_ZOMBIE,
+ "X" : STATUS_DEAD,
+ "x" : STATUS_DEAD,
+ "K" : STATUS_WAKE_KILL,
+ "W" : STATUS_WAKING}
# --- decorators
@@ -173,7 +328,10 @@ def wrap_exceptions(callable):
try:
return callable(self, *args, **kwargs)
except (OSError, IOError), err:
- if err.errno == errno.ENOENT: # no such file or directory
+ # ENOENT (no such file or directory) gets raised on open().
+ # ESRCH (no such process) can get raised on read() if
+ # process is gone in meantime.
+ if err.errno in (errno.ENOENT, errno.ESRCH):
raise NoSuchProcess(self.pid, self._process_name)
if err.errno in (errno.EPERM, errno.EACCES):
raise AccessDenied(self.pid, self._process_name)
@@ -181,14 +339,9 @@ def wrap_exceptions(callable):
return wrapper
-class LinuxProcess(object):
+class Process(object):
"""Linux process implementation."""
- _meminfo_ntuple = namedtuple('meminfo', 'rss vms')
- _cputimes_ntuple = namedtuple('cputimes', 'user system')
- _openfile_ntuple = namedtuple('openfile', 'path fd')
- _connection_ntuple = namedtuple('connection', 'fd family type local_address '
- 'remote_address status')
__slots__ = ["pid", "_process_name"]
def __init__(self, pid):
@@ -197,8 +350,6 @@ class LinuxProcess(object):
@wrap_exceptions
def get_process_name(self):
- if self.pid == 0:
- return 'sched' # special case for kernel process
f = open("/proc/%s/stat" % self.pid)
try:
name = f.read().split(' ')[1].replace('(', '').replace(')', '')
@@ -209,7 +360,7 @@ class LinuxProcess(object):
def get_process_exe(self):
if self.pid in (0, 2):
- return "" # special case for kernel processes
+ raise AccessDenied(self.pid, self._process_name)
try:
exe = os.readlink("/proc/%s/exe" % self.pid)
except (OSError, IOError), err:
@@ -226,6 +377,10 @@ class LinuxProcess(object):
raise AccessDenied(self.pid, self._process_name)
raise
+ # readlink() might return paths containing null bytes causing
+ # problems when used with other fs-related functions (os.*,
+ # open(), ...)
+ exe = exe.replace('\x00', '')
# It seems symlinks can point to a deleted/invalid location
# (this usually happens with "pulseaudio" process).
# However, if we had permissions to execute readlink() it's
@@ -237,8 +392,6 @@ class LinuxProcess(object):
@wrap_exceptions
def get_process_cmdline(self):
- if self.pid == 0:
- return [] # special case for kernel process
f = open("/proc/%s/cmdline" % self.pid)
try:
# return the args as a list
@@ -247,28 +400,62 @@ class LinuxProcess(object):
f.close()
@wrap_exceptions
+ def get_process_terminal(self):
+ f = open("/proc/%s/stat" % self.pid)
+ try:
+ tty_nr = int(f.read().split(' ')[6])
+ finally:
+ f.close()
+ try:
+ return _TERMINAL_MAP[tty_nr]
+ except KeyError:
+ return None
+
+ @wrap_exceptions
+ def get_process_io_counters(self):
+ f = open("/proc/%s/io" % self.pid)
+ try:
+ for line in f:
+ if line.startswith("rchar"):
+ read_count = int(line.split()[1])
+ elif line.startswith("wchar"):
+ write_count = int(line.split()[1])
+ elif line.startswith("read_bytes"):
+ read_bytes = int(line.split()[1])
+ elif line.startswith("write_bytes"):
+ write_bytes = int(line.split()[1])
+ return ntuple_io(read_count, write_count, read_bytes, write_bytes)
+ finally:
+ f.close()
+
+ @wrap_exceptions
def get_cpu_times(self):
- # special case for 0 (kernel process) PID
- if self.pid == 0:
- return self._cputimes_ntuple(0.0, 0.0)
f = open("/proc/%s/stat" % self.pid)
- st = f.read().strip()
- f.close()
+ try:
+ st = f.read().strip()
+ finally:
+ f.close()
# ignore the first two values ("pid (exe)")
st = st[st.find(')') + 2:]
values = st.split(' ')
utime = float(values[11]) / _CLOCK_TICKS
stime = float(values[12]) / _CLOCK_TICKS
- return self._cputimes_ntuple(utime, stime)
+ return ntuple_cputimes(utime, stime)
+
+ @wrap_exceptions
+ def process_wait(self, timeout=None):
+ try:
+ return _psposix.wait_pid(self.pid, timeout)
+ except TimeoutExpired:
+ raise TimeoutExpired(self.pid, self._process_name)
@wrap_exceptions
def get_process_create_time(self):
- # special case for 0 (kernel processes) PID; return system uptime
- if self.pid == 0:
- return _UPTIME
f = open("/proc/%s/stat" % self.pid)
- st = f.read().strip()
- f.close()
+ try:
+ st = f.read().strip()
+ finally:
+ f.close()
# ignore the first two values ("pid (exe)")
st = st[st.find(')') + 2:]
values = st.split(' ')
@@ -276,43 +463,129 @@ class LinuxProcess(object):
# unit is jiffies (clock ticks).
# We first divide it for clock ticks and then add uptime returning
# seconds since the epoch, in UTC.
- starttime = (float(values[19]) / _CLOCK_TICKS) + _UPTIME
+ starttime = (float(values[19]) / _CLOCK_TICKS) + BOOT_TIME
return starttime
@wrap_exceptions
def get_memory_info(self):
- # special case for 0 (kernel processes) PID
- if self.pid == 0:
- return self._meminfo_ntuple(0, 0)
f = open("/proc/%s/status" % self.pid)
- virtual_size = 0
- resident_size = 0
- _flag = False
- for line in f:
- if (not _flag) and line.startswith("VmSize:"):
- virtual_size = int(line.split()[1]) * 1024
- _flag = True
- elif line.startswith("VmRSS"):
- resident_size = int(line.split()[1]) * 1024
- break
- f.close()
- return self._meminfo_ntuple(resident_size, virtual_size)
+ try:
+ virtual_size = 0
+ resident_size = 0
+ _flag = False
+ for line in f:
+ if (not _flag) and line.startswith("VmSize:"):
+ virtual_size = int(line.split()[1]) * 1024
+ _flag = True
+ elif line.startswith("VmRSS"):
+ resident_size = int(line.split()[1]) * 1024
+ break
+ return ntuple_meminfo(resident_size, virtual_size)
+ finally:
+ f.close()
@wrap_exceptions
def get_process_cwd(self):
- if self.pid == 0:
- return ''
- return os.readlink("/proc/%s/cwd" % self.pid)
+ # readlink() might return paths containing null bytes causing
+ # problems when used with other fs-related functions (os.*,
+ # open(), ...)
+ path = os.readlink("/proc/%s/cwd" % self.pid)
+ return path.replace('\x00', '')
@wrap_exceptions
def get_process_num_threads(self):
- if self.pid == 0:
- return 0
f = open("/proc/%s/status" % self.pid)
- for line in f:
- if line.startswith("Threads:"):
+ try:
+ for line in f:
+ if line.startswith("Threads:"):
+ return int(line.split()[1])
+ raise RuntimeError("line not found")
+ finally:
+ f.close()
+
+ @wrap_exceptions
+ def get_process_threads(self):
+ thread_ids = os.listdir("/proc/%s/task" % self.pid)
+ thread_ids.sort()
+ retlist = []
+ for thread_id in thread_ids:
+ try:
+ f = open("/proc/%s/task/%s/stat" % (self.pid, thread_id))
+ except (OSError, IOError), err:
+ if err.errno == errno.ENOENT:
+ # no such file or directory; it means thread
+ # disappeared on us
+ continue
+ raise
+ try:
+ st = f.read().strip()
+ finally:
f.close()
- return int(line.split()[1])
+ # ignore the first two values ("pid (exe)")
+ st = st[st.find(')') + 2:]
+ values = st.split(' ')
+ utime = float(values[11]) / _CLOCK_TICKS
+ stime = float(values[12]) / _CLOCK_TICKS
+ ntuple = ntuple_thread(int(thread_id), utime, stime)
+ retlist.append(ntuple)
+ return retlist
+
+ @wrap_exceptions
+ def get_process_nice(self):
+ #f = open('/proc/%s/stat' % self.pid, 'r')
+ #try:
+ # data = f.read()
+ # return int(data.split()[18])
+ #finally:
+ # f.close()
+
+ # Use C implementation
+ return _psutil_posix.getpriority(self.pid)
+
+ @wrap_exceptions
+ def set_process_nice(self, value):
+ return _psutil_posix.setpriority(self.pid, value)
+
+ # only starting from kernel 2.6.13
+ if hasattr(_psutil_linux, "ioprio_get"):
+
+ @wrap_exceptions
+ def get_process_ionice(self):
+ ioclass, value = _psutil_linux.ioprio_get(self.pid)
+ return ntuple_ionice(ioclass, value)
+
+ @wrap_exceptions
+ def set_process_ionice(self, ioclass, value):
+ if ioclass in (IOPRIO_CLASS_NONE, None):
+ if value:
+ raise ValueError("can't specify value with IOPRIO_CLASS_NONE")
+ ioclass = IOPRIO_CLASS_NONE
+ value = 0
+ if ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE):
+ if value is None:
+ value = 4
+ elif ioclass == IOPRIO_CLASS_IDLE:
+ if value:
+ raise ValueError("can't specify value with IOPRIO_CLASS_IDLE")
+ value = 0
+ else:
+ value = 0
+ if not 0 <= value <= 8:
+ raise ValueError("value argument range expected is between 0 and 8")
+ return _psutil_linux.ioprio_set(self.pid, ioclass, value)
+
+ @wrap_exceptions
+ def get_process_status(self):
+ f = open("/proc/%s/status" % self.pid)
+ try:
+ for line in f:
+ if line.startswith("State:"):
+ letter = line.split()[1]
+ if letter in _status_map:
+ return _status_map[letter]
+ return constant(-1, '?')
+ finally:
+ f.close()
@wrap_exceptions
def get_open_files(self):
@@ -329,20 +602,12 @@ class LinuxProcess(object):
if file == "[]":
continue
if os.path.isfile(file) and not file in retlist:
- ntuple = self._openfile_ntuple(file, int(fd))
+ ntuple = ntuple_openfile(file, int(fd))
retlist.append(ntuple)
return retlist
-# --- lsof implementation
-#
-# def get_open_files(self):
-# lsof = _psposix.LsofParser(self.pid, self._process_name)
-# return lsof.get_process_open_files()
-
@wrap_exceptions
def get_connections(self):
- if self.pid == 0:
- return []
inodes = {}
# os.listdir() is gonna raise a lot of access denied
# exceptions in case of unprivileged user; that's fine:
@@ -364,27 +629,37 @@ class LinuxProcess(object):
def process(file, family, _type):
retlist = []
f = open(file)
- f.readline() # skip the first line
- for line in f:
- _, laddr, raddr, status, _, _, _, _, _, inode = line.split()[:10]
- if inode in inodes:
- laddr = self._decode_address(laddr, family)
- raddr = self._decode_address(raddr, family)
- if _type == socket.SOCK_STREAM:
- status = _TCP_STATES_TABLE[status]
- else:
- status = ""
- fd = int(inodes[inode])
- conn = self._connection_ntuple(fd, family, _type, laddr,
- raddr, status)
- retlist.append(conn)
- f.close()
- return retlist
+ try:
+ f.readline() # skip the first line
+ for line in f:
+ _, laddr, raddr, status, _, _, _, _, _, inode = \
+ line.split()[:10]
+ if inode in inodes:
+ laddr = self._decode_address(laddr, family)
+ raddr = self._decode_address(raddr, family)
+ if _type == socket.SOCK_STREAM:
+ status = _TCP_STATES_TABLE[status]
+ else:
+ status = ""
+ fd = int(inodes[inode])
+ conn = ntuple_connection(fd, family, _type, laddr,
+ raddr, status)
+ retlist.append(conn)
+ return retlist
+ finally:
+ f.close()
tcp4 = process("/proc/net/tcp", socket.AF_INET, socket.SOCK_STREAM)
- tcp6 = process("/proc/net/tcp6", socket.AF_INET6, socket.SOCK_STREAM)
udp4 = process("/proc/net/udp", socket.AF_INET, socket.SOCK_DGRAM)
- udp6 = process("/proc/net/udp6", socket.AF_INET6, socket.SOCK_DGRAM)
+ try:
+ tcp6 = process("/proc/net/tcp6", socket.AF_INET6, socket.SOCK_STREAM)
+ udp6 = process("/proc/net/udp6", socket.AF_INET6, socket.SOCK_DGRAM)
+ except IOError, err:
+ if err.errno == errno.ENOENT:
+ # IPv6 is not supported on this platform
+ tcp6 = udp6 = []
+ else:
+ raise
return tcp4 + tcp6 + udp4 + udp6
# --- lsof implementation
@@ -395,40 +670,39 @@ class LinuxProcess(object):
@wrap_exceptions
def get_process_ppid(self):
- if self.pid == 0:
- return 0
f = open("/proc/%s/status" % self.pid)
- for line in f:
- if line.startswith("PPid:"):
- # PPid: nnnn
- f.close()
- return int(line.split()[1])
+ try:
+ for line in f:
+ if line.startswith("PPid:"):
+ # PPid: nnnn
+ return int(line.split()[1])
+ raise RuntimeError("line not found")
+ finally:
+ f.close()
@wrap_exceptions
- def get_process_uid(self):
- if self.pid == 0:
- return 0
+ def get_process_uids(self):
f = open("/proc/%s/status" % self.pid)
- for line in f:
- if line.startswith('Uid:'):
- # Uid line provides 4 values which stand for real,
- # effective, saved set, and file system UIDs.
- # We want to provide real UID only.
- f.close()
- return int(line.split()[1])
+ try:
+ for line in f:
+ if line.startswith('Uid:'):
+ _, real, effective, saved, fs = line.split()
+ return ntuple_uids(int(real), int(effective), int(saved))
+ raise RuntimeError("line not found")
+ finally:
+ f.close()
@wrap_exceptions
- def get_process_gid(self):
- if self.pid == 0:
- return 0
+ def get_process_gids(self):
f = open("/proc/%s/status" % self.pid)
- for line in f:
- if line.startswith('Gid:'):
- # Uid line provides 4 values which stand for real,
- # effective, saved set, and file system GIDs.
- # We want to provide real GID only.
- f.close()
- return int(line.split()[1])
+ try:
+ for line in f:
+ if line.startswith('Gid:'):
+ _, real, effective, saved, fs = line.split()
+ return ntuple_gids(int(real), int(effective), int(saved))
+ raise RuntimeError("line not found")
+ finally:
+ f.close()
@staticmethod
def _decode_address(addr, family):
@@ -438,9 +712,9 @@ class LinuxProcess(object):
"0500000A:0016" -> ("10.0.0.5", 22)
"0000000000000000FFFF00000100007F:9E49" -> ("::ffff:127.0.0.1", 40521)
- The IPv4 address portion is a little-endian four-byte hexadecimal
- number; that is, the least significant byte is listed first,
- so we need to reverse the order of the bytes to convert it
+ The IP address portion is a little or big endian four-byte
+ hexadecimal number; that is, the least significant byte is listed
+ first, so we need to reverse the order of the bytes to convert it
to an IP address.
The port is represented as a two-byte hexadecimal number.
@@ -456,16 +730,22 @@ class LinuxProcess(object):
if not port:
return ()
if family == socket.AF_INET:
- ip = socket.inet_ntop(family, base64.b16decode(ip)[::-1])
+ # see: http://code.google.com/p/psutil/issues/detail?id=201
+ if sys.byteorder == 'little':
+ ip = socket.inet_ntop(family, base64.b16decode(ip)[::-1])
+ else:
+ ip = socket.inet_ntop(family, base64.b16decode(ip))
else: # IPv6
# old version - let's keep it, just in case...
#ip = ip.decode('hex')
#return socket.inet_ntop(socket.AF_INET6,
# ''.join(ip[i:i+4][::-1] for i in xrange(0, 16, 4)))
ip = base64.b16decode(ip)
- ip = socket.inet_ntop(socket.AF_INET6,
+ # see: http://code.google.com/p/psutil/issues/detail?id=201
+ if sys.byteorder == 'little':
+ ip = socket.inet_ntop(socket.AF_INET6,
struct.pack('>4I', *struct.unpack('<4I', ip)))
+ else:
+ ip = socket.inet_ntop(socket.AF_INET6,
+ struct.pack('<4I', *struct.unpack('<4I', ip)))
return (ip, port)
-
-PlatformProcess = LinuxProcess
-
diff --git a/third_party/psutil/psutil/_psmswindows.py b/third_party/psutil/psutil/_psmswindows.py
index ec75649..81ffad7 100644
--- a/third_party/psutil/psutil/_psmswindows.py
+++ b/third_party/psutil/psutil/_psmswindows.py
@@ -1,69 +1,120 @@
#!/usr/bin/env python
#
-# $Id: _psmswindows.py 802 2010-11-12 22:15:29Z g.rodola $
+# $Id: _psmswindows.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
+
+"""Windows platform implementation."""
import errno
import os
-import subprocess
-import socket
-import re
import sys
import platform
-try:
- from collections import namedtuple
-except ImportError:
- from psutil.compat import namedtuple # python < 2.6
-
import _psutil_mswindows
-from psutil.error import AccessDenied, NoSuchProcess
+from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
+from psutil._compat import namedtuple
+from psutil._common import *
+# Windows specific extended namespace
+__extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
+ "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
+ "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS"]
# --- module level constants (gets pushed up to psutil module)
NUM_CPUS = _psutil_mswindows.get_num_cpus()
-TOTAL_PHYMEM = _psutil_mswindows.get_total_phymem()
-_UPTIME = _psutil_mswindows.get_system_uptime()
+BOOT_TIME = _psutil_mswindows.get_system_uptime()
_WIN2000 = platform.win32_ver()[0] == '2000'
-
ERROR_ACCESS_DENIED = 5
+WAIT_TIMEOUT = 0x00000102 # 258 in decimal
+
+# process priority constants:
+# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
+from _psutil_mswindows import (ABOVE_NORMAL_PRIORITY_CLASS,
+ BELOW_NORMAL_PRIORITY_CLASS,
+ HIGH_PRIORITY_CLASS,
+ IDLE_PRIORITY_CLASS,
+ NORMAL_PRIORITY_CLASS,
+ REALTIME_PRIORITY_CLASS,
+ INFINITE)
# --- public functions
-def avail_phymem():
- "Return the amount of physical memory available on the system, in bytes."
- return _psutil_mswindows.get_avail_phymem()
-
-def used_phymem():
- "Return the amount of physical memory currently in use on the system, in bytes."
- return TOTAL_PHYMEM - _psutil_mswindows.get_avail_phymem()
-
-def total_virtmem():
- "Return the amount of total virtual memory available on the system, in bytes."
- return _psutil_mswindows.get_total_virtmem()
-
-def avail_virtmem():
- "Return the amount of virtual memory currently in use on the system, in bytes."
- return _psutil_mswindows.get_avail_virtmem()
-
-def used_virtmem():
- """Return the amount of used memory currently in use on the system, in bytes."""
- return _psutil_mswindows.get_total_virtmem() - _psutil_mswindows.get_avail_virtmem()
+def phymem_usage():
+ """Physical system memory as a (total, used, free) tuple."""
+ all = _psutil_mswindows.get_system_phymem()
+ total, free, total_pagef, avail_pagef, total_virt, free_virt, percent = all
+ used = total - free
+ return ntuple_sysmeminfo(total, used, free, round(percent, 1))
+
+def virtmem_usage():
+ """Virtual system memory as a (total, used, free) tuple."""
+ all = _psutil_mswindows.get_system_phymem()
+ total_virt = all[4]
+ free_virt = all[5]
+ used = total_virt - free_virt
+ percent = usage_percent(used, total_virt, _round=1)
+ return ntuple_sysmeminfo(total_virt, used, free_virt, percent)
+
+def get_disk_usage(path):
+ """Return disk usage associated with path."""
+ try:
+ total, free = _psutil_mswindows.get_disk_usage(path)
+ except WindowsError, err:
+ if not os.path.exists(path):
+ raise OSError(errno.ENOENT, "No such file or directory: '%s'" % path)
+ raise
+ used = total - free
+ percent = usage_percent(used, total, _round=1)
+ return ntuple_diskinfo(total, used, free, percent)
+
+def disk_partitions(all):
+ """Return disk partitions."""
+ retlist = []
+ drive_letters = _psutil_mswindows.win32_GetLogicalDriveStrings()
+ for letter in drive_letters:
+ mountpoint = letter
+ type = _psutil_mswindows.win32_GetDriveType(letter)
+ if not os.path.exists(mountpoint):
+ # usually a CD-ROM device with no disk inserted
+ mountpoint = ""
+ if not all:
+ if type not in ('cdrom', 'fixed', 'removable'):
+ continue
+ if not mountpoint:
+ continue
+ ntuple = ntuple_partition(letter, mountpoint, type)
+ retlist.append(ntuple)
+ return retlist
+
+
+_cputimes_ntuple = namedtuple('cputimes', 'user system idle')
def get_system_cpu_times():
- """Return a dict representing the following CPU times: user, system, idle."""
- times = _psutil_mswindows.get_system_cpu_times()
- return dict(user=times[0], system=times[1], idle=times[2])
-
-def get_pid_list():
- """Returns a list of PIDs currently running on the system."""
- return _psutil_mswindows.get_pid_list()
-
-def pid_exists(pid):
- return _psutil_mswindows.pid_exists(pid)
-
+ """Return system CPU times as a named tuple."""
+ user, system, idle = 0, 0, 0
+ # computes system global times summing each processor value
+ for cpu_time in _psutil_mswindows.get_system_cpu_times():
+ user += cpu_time[0]
+ system += cpu_time[1]
+ idle += cpu_time[2]
+ return _cputimes_ntuple(user, system, idle)
+
+def get_system_per_cpu_times():
+ """Return system per-CPU times as a list of named tuples."""
+ ret = []
+ for cpu_t in _psutil_mswindows.get_system_cpu_times():
+ user, system, idle = cpu_t
+ item = _cputimes_ntuple(user, system, idle)
+ ret.append(item)
+ return ret
+
+get_pid_list = _psutil_mswindows.get_pid_list
+pid_exists = _psutil_mswindows.pid_exists
# --- decorator
@@ -84,14 +135,9 @@ def wrap_exceptions(callable):
return wrapper
-class WindowsProcess(object):
+class Process(object):
"""Wrapper class around underlying C implementation."""
- _meminfo_ntuple = namedtuple('meminfo', 'rss vms')
- _cputimes_ntuple = namedtuple('cputimes', 'user system')
- _openfile_ntuple = namedtuple('openfile', 'path fd')
- _connection_ntuple = namedtuple('connection', 'fd family type local_address '
- 'remote_address status')
__slots__ = ["pid", "_process_name"]
def __init__(self, pid):
@@ -105,10 +151,12 @@ class WindowsProcess(object):
return _psutil_mswindows.get_process_name(self.pid)
def get_process_exe(self):
- # no such thing as "exe" on BSD; it will maybe be determined
+ # no such thing as "exe" on Windows; it will maybe be determined
# later from cmdline[0]
if not pid_exists(self.pid):
raise NoSuchProcess(self.pid, self._process_name)
+ if self.pid in (0, 4):
+ raise AccessDenied(self.pid, self._process_name)
return ""
@wrap_exceptions
@@ -121,26 +169,14 @@ class WindowsProcess(object):
"""Return process parent pid."""
return _psutil_mswindows.get_process_ppid(self.pid)
- def get_process_uid(self):
- # no such thing as uid on Windows
- if not pid_exists(self.pid):
- raise NoSuchProcess(self.pid, self._process_name)
- return -1
-
- def get_process_gid(self):
- # no such thing as gid on Windows
- if not pid_exists(self.pid):
- raise NoSuchProcess(self.pid, self._process_name)
- return -1
-
@wrap_exceptions
def get_memory_info(self):
"""Returns a tuple or RSS/VMS memory usage in bytes."""
# special case for 0 (kernel processes) PID
if self.pid == 0:
- return self._meminfo_ntuple(0, 0)
+ return ntuple_meminfo(0, 0)
rss, vms = _psutil_mswindows.get_memory_info(self.pid)
- return self._meminfo_ntuple(rss, vms)
+ return ntuple_meminfo(rss, vms)
@wrap_exceptions
def kill_process(self):
@@ -148,6 +184,18 @@ class WindowsProcess(object):
return _psutil_mswindows.kill_process(self.pid)
@wrap_exceptions
+ def process_wait(self, timeout=None):
+ if timeout is None:
+ timeout = INFINITE
+ else:
+ # WaitForSingleObject() expects time in milliseconds
+ timeout = int(timeout * 1000)
+ ret = _psutil_mswindows.process_wait(self.pid, timeout)
+ if ret == WAIT_TIMEOUT:
+ raise TimeoutExpired(self.pid, self._process_name)
+ return ret
+
+ @wrap_exceptions
def get_process_username(self):
"""Return the name of the user that owns the process"""
if self.pid in (0, 4) or self.pid == 8 and _WIN2000:
@@ -156,9 +204,9 @@ class WindowsProcess(object):
@wrap_exceptions
def get_process_create_time(self):
- # special case for kernel process PIDs; return system uptime
+ # special case for kernel process PIDs; return system boot time
if self.pid in (0, 4) or self.pid == 8 and _WIN2000:
- return _UPTIME
+ return BOOT_TIME
return _psutil_mswindows.get_process_create_time(self.pid)
@wrap_exceptions
@@ -166,20 +214,31 @@ class WindowsProcess(object):
return _psutil_mswindows.get_process_num_threads(self.pid)
@wrap_exceptions
+ def get_process_threads(self):
+ rawlist = _psutil_mswindows.get_process_threads(self.pid)
+ retlist = []
+ for thread_id, utime, stime in rawlist:
+ ntuple = ntuple_thread(thread_id, utime, stime)
+ retlist.append(ntuple)
+ return retlist
+
+ @wrap_exceptions
def get_cpu_times(self):
user, system = _psutil_mswindows.get_process_cpu_times(self.pid)
- return self._cputimes_ntuple(user, system)
+ return ntuple_cputimes(user, system)
+ @wrap_exceptions
def suspend_process(self):
return _psutil_mswindows.suspend_process(self.pid)
+ @wrap_exceptions
def resume_process(self):
return _psutil_mswindows.resume_process(self.pid)
@wrap_exceptions
def get_process_cwd(self):
if self.pid in (0, 4) or self.pid == 8 and _WIN2000:
- return ''
+ raise AccessDenied(self.pid, self._process_name)
# return a normalized pathname since the native C function appends
# "\\" at the and of the path
path = _psutil_mswindows.get_process_cwd(self.pid)
@@ -200,16 +259,35 @@ class WindowsProcess(object):
file = file.decode('utf8')
if file.startswith('\\Device\\'):
rawdrive = '\\'.join(file.split('\\')[:3])
- driveletter = _psutil_mswindows._QueryDosDevice(rawdrive)
+ driveletter = _psutil_mswindows.win32_QueryDosDevice(rawdrive)
file = file.replace(rawdrive, driveletter)
if os.path.isfile(file) and file not in retlist:
- ntuple = self._openfile_ntuple(file, -1)
+ ntuple = ntuple_openfile(file, -1)
retlist.append(ntuple)
return retlist
@wrap_exceptions
def get_connections(self):
retlist = _psutil_mswindows.get_process_connections(self.pid)
- return [self._connection_ntuple(*conn) for conn in retlist]
+ return [ntuple_connection(*conn) for conn in retlist]
-PlatformProcess = WindowsProcess
+ @wrap_exceptions
+ def get_process_nice(self):
+ return _psutil_mswindows.get_process_priority(self.pid)
+
+ @wrap_exceptions
+ def set_process_nice(self, value):
+ return _psutil_mswindows.set_process_priority(self.pid, value)
+
+ @wrap_exceptions
+ def get_process_io_counters(self):
+ rc, wc, rb, wb =_psutil_mswindows.get_process_io_counters(self.pid)
+ return ntuple_io(rc, wc, rb, wb)
+
+ @wrap_exceptions
+ def get_process_status(self):
+ suspended = _psutil_mswindows.is_process_suspended(self.pid)
+ if suspended:
+ return STATUS_STOPPED
+ else:
+ return STATUS_RUNNING
diff --git a/third_party/psutil/psutil/_psosx.py b/third_party/psutil/psutil/_psosx.py
index f8c867e..543124c 100644
--- a/third_party/psutil/psutil/_psosx.py
+++ b/third_party/psutil/psutil/_psosx.py
@@ -1,60 +1,84 @@
#!/usr/bin/env python
#
-# $Id: _psosx.py 794 2010-11-12 13:29:52Z g.rodola $
+# $Id: _psosx.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
+
+"""OSX platform implementation."""
import errno
import os
-try:
- from collections import namedtuple
-except ImportError:
- from psutil.compat import namedtuple # python < 2.6
-
import _psutil_osx
+import _psutil_posix
import _psposix
-from psutil.error import AccessDenied, NoSuchProcess
+from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
+from psutil._compat import namedtuple
+from psutil._common import *
+
+__extra__all__ = []
# --- constants
NUM_CPUS = _psutil_osx.get_num_cpus()
-TOTAL_PHYMEM = _psutil_osx.get_total_phymem()
+BOOT_TIME = _psutil_osx.get_system_boot_time()
+_TERMINAL_MAP = _psposix._get_terminal_map()
+_cputimes_ntuple = namedtuple('cputimes', 'user nice system idle')
# --- functions
-def avail_phymem():
- "Return the amount of physical memory available on the system, in bytes."
- return _psutil_osx.get_avail_phymem()
-
-def used_phymem():
- "Return the amount of physical memory currently in use on the system, in bytes."
- return TOTAL_PHYMEM - _psutil_osx.get_avail_phymem()
-
-def total_virtmem():
- "Return the amount of total virtual memory available on the system, in bytes."
- return _psutil_osx.get_total_virtmem()
-
-def avail_virtmem():
- "Return the amount of virtual memory currently in use on the system, in bytes."
- return _psutil_osx.get_avail_virtmem()
-
-def used_virtmem():
- """Return the amount of used memory currently in use on the system, in bytes."""
- return _psutil_osx.get_total_virtmem() - _psutil_osx.get_avail_virtmem()
+def phymem_usage():
+ """Physical system memory as a (total, used, free) tuple."""
+ total = _psutil_osx.get_total_phymem()
+ free = _psutil_osx.get_avail_phymem()
+ used = total - free
+ percent = usage_percent(used, total, _round=1)
+ return ntuple_sysmeminfo(total, used, free, percent)
+
+def virtmem_usage():
+ """Virtual system memory as a (total, used, free) tuple."""
+ total = _psutil_osx.get_total_virtmem()
+ free = _psutil_osx.get_avail_virtmem()
+ used = total - free
+ percent = usage_percent(used, total, _round=1)
+ return ntuple_sysmeminfo(total, used, free, percent)
def get_system_cpu_times():
- """Return a dict representing the following CPU times:
- user, nice, system, idle."""
- values = _psutil_osx.get_system_cpu_times()
- return dict(user=values[0], nice=values[1], system=values[2], idle=values[3])
-
-def get_pid_list():
- """Returns a list of PIDs currently running on the system."""
- return _psutil_osx.get_pid_list()
-
-def pid_exists(pid):
- """Check For the existence of a unix pid."""
- return _psposix.pid_exists(pid)
+ """Return system CPU times as a namedtuple."""
+ user, nice, system, idle = _psutil_osx.get_system_cpu_times()
+ return _cputimes_ntuple(user, nice, system, idle)
+
+def get_system_per_cpu_times():
+ """Return system CPU times as a named tuple"""
+ ret = []
+ for cpu_t in _psutil_osx.get_system_per_cpu_times():
+ user, nice, system, idle = cpu_t
+ item = _cputimes_ntuple(user, nice, system, idle)
+ ret.append(item)
+ return ret
+
+def disk_partitions(all=False):
+ retlist = []
+ partitions = _psutil_osx.get_disk_partitions()
+ for partition in partitions:
+ device, mountpoint, fstype = partition
+ if device == 'none':
+ device = ''
+ if not all:
+ if not os.path.isabs(device) \
+ or not os.path.exists(device):
+ continue
+ ntuple = ntuple_partition(device, mountpoint, fstype)
+ retlist.append(ntuple)
+ return retlist
+
+get_pid_list = _psutil_osx.get_pid_list
+pid_exists = _psposix.pid_exists
+get_disk_usage = _psposix.get_disk_usage
+network_io_counters = _psutil_osx.get_network_io_counters
+disk_io_counters = _psutil_osx.get_disk_io_counters
# --- decorator
@@ -75,11 +99,17 @@ def wrap_exceptions(callable):
return wrapper
-class OSXProcess(object):
+_status_map = {
+ _psutil_osx.SIDL : STATUS_IDLE,
+ _psutil_osx.SRUN : STATUS_RUNNING,
+ _psutil_osx.SSLEEP : STATUS_SLEEPING,
+ _psutil_osx.SSTOP : STATUS_STOPPED,
+ _psutil_osx.SZOMB : STATUS_ZOMBIE,
+}
+
+class Process(object):
"""Wrapper class around underlying C implementation."""
- _meminfo_ntuple = namedtuple('meminfo', 'rss vms')
- _cputimes_ntuple = namedtuple('cputimes', 'user system')
__slots__ = ["pid", "_process_name"]
def __init__(self, pid):
@@ -111,25 +141,33 @@ class OSXProcess(object):
return _psutil_osx.get_process_ppid(self.pid)
@wrap_exceptions
- def get_process_uid(self):
- """Return process real user id."""
- return _psutil_osx.get_process_uid(self.pid)
+ def get_process_uids(self):
+ real, effective, saved = _psutil_osx.get_process_uids(self.pid)
+ return ntuple_uids(real, effective, saved)
@wrap_exceptions
- def get_process_gid(self):
- """Return process real group id."""
- return _psutil_osx.get_process_gid(self.pid)
+ def get_process_gids(self):
+ real, effective, saved = _psutil_osx.get_process_gids(self.pid)
+ return ntuple_gids(real, effective, saved)
+
+ @wrap_exceptions
+ def get_process_terminal(self):
+ tty_nr = _psutil_osx.get_process_tty_nr(self.pid)
+ try:
+ return _TERMINAL_MAP[tty_nr]
+ except KeyError:
+ return None
@wrap_exceptions
def get_memory_info(self):
"""Return a tuple with the process' RSS and VMS size."""
rss, vms = _psutil_osx.get_memory_info(self.pid)
- return self._meminfo_ntuple(rss, vms)
+ return ntuple_meminfo(rss, vms)
@wrap_exceptions
def get_cpu_times(self):
user, system = _psutil_osx.get_cpu_times(self.pid)
- return self._cputimes_ntuple(user, system)
+ return ntuple_cputimes(user, system)
@wrap_exceptions
def get_process_create_time(self):
@@ -142,16 +180,54 @@ class OSXProcess(object):
"""Return the number of threads belonging to the process."""
return _psutil_osx.get_process_num_threads(self.pid)
+ @wrap_exceptions
def get_open_files(self):
- """Return files opened by process by parsing lsof output."""
- lsof = _psposix.LsofParser(self.pid, self._process_name)
- return lsof.get_process_open_files()
+ """Return files opened by process."""
+ if self.pid == 0:
+ raise AccessDenied(self.pid, self._process_name)
+ files = []
+ rawlist = _psutil_osx.get_process_open_files(self.pid)
+ for path, fd in rawlist:
+ if os.path.isfile(path):
+ ntuple = ntuple_openfile(path, fd)
+ files.append(ntuple)
+ return files
+ @wrap_exceptions
def get_connections(self):
"""Return etwork connections opened by a process as a list of
namedtuples."""
- lsof = _psposix.LsofParser(self.pid, self._process_name)
- return lsof.get_process_connections()
+ retlist = _psutil_osx.get_process_connections(self.pid)
+ return [ntuple_connection(*conn) for conn in retlist]
+
+ @wrap_exceptions
+ def process_wait(self, timeout=None):
+ try:
+ return _psposix.wait_pid(self.pid, timeout)
+ except TimeoutExpired:
+ raise TimeoutExpired(self.pid, self._process_name)
+
+ @wrap_exceptions
+ def get_process_nice(self):
+ return _psutil_posix.getpriority(self.pid)
+
+ @wrap_exceptions
+ def set_process_nice(self, value):
+ return _psutil_posix.setpriority(self.pid, value)
-PlatformProcess = OSXProcess
+ @wrap_exceptions
+ def get_process_status(self):
+ code = _psutil_osx.get_process_status(self.pid)
+ if code in _status_map:
+ return _status_map[code]
+ return constant(-1, "?")
+ @wrap_exceptions
+ def get_process_threads(self):
+ """Return the number of threads belonging to the process."""
+ rawlist = _psutil_osx.get_process_threads(self.pid)
+ retlist = []
+ for thread_id, utime, stime in rawlist:
+ ntuple = ntuple_thread(thread_id, utime, stime)
+ retlist.append(ntuple)
+ return retlist
diff --git a/third_party/psutil/psutil/_psposix.py b/third_party/psutil/psutil/_psposix.py
index cd860a5..08cc268 100644
--- a/third_party/psutil/psutil/_psposix.py
+++ b/third_party/psutil/psutil/_psposix.py
@@ -1,7 +1,10 @@
#!/usr/bin/env python
#
-# $Id: _psposix.py 800 2010-11-12 21:51:25Z g.rodola $
+# $Id: _psposix.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
"""Routines common to all posix systems."""
@@ -13,13 +16,12 @@ import socket
import re
import sys
import warnings
+import time
+import glob
-try:
- from collections import namedtuple
-except ImportError:
- from psutil.compat import namedtuple # python < 2.6
-
-from psutil.error import AccessDenied, NoSuchProcess
+from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired
+from psutil._compat import namedtuple
+from psutil._common import ntuple_diskinfo, usage_percent
def pid_exists(pid):
@@ -33,6 +35,82 @@ def pid_exists(pid):
else:
return True
+def wait_pid(pid, timeout=None):
+ """Wait for process with pid 'pid' to terminate and return its
+ exit status code as an integer.
+
+ If pid is not a children of os.getpid() (current process) just
+ waits until the process disappears and return None.
+
+ If pid does not exist at all return None immediately.
+
+ Raise TimeoutExpired on timeout expired.
+ """
+ def check_timeout():
+ if timeout is not None:
+ if time.time() >= stop_at:
+ raise TimeoutExpired
+ time.sleep(0.001)
+
+ if timeout is not None:
+ waitcall = lambda: os.waitpid(pid, os.WNOHANG)
+ stop_at = time.time() + timeout
+ else:
+ waitcall = lambda: os.waitpid(pid, 0)
+
+ while 1:
+ try:
+ retpid, status = waitcall()
+ except OSError, err:
+ if err.errno == errno.EINTR:
+ check_timeout()
+ continue
+ elif err.errno == errno.ECHILD:
+ # not a child of os.getpid(): poll until pid has
+ # disappeared and return None instead
+ while 1:
+ if pid_exists(pid):
+ check_timeout()
+ else:
+ return
+ else:
+ raise
+ else:
+ if retpid == 0:
+ check_timeout()
+ continue
+ # process exited due to a signal; return the integer of
+ # that signal
+ if os.WIFSIGNALED(status):
+ return os.WTERMSIG(status)
+ # process exited using exit(2) system call; return the
+ # integer exit(2) system call has been called with
+ elif os.WIFEXITED(status):
+ return os.WEXITSTATUS(status)
+ else:
+ # should never happen
+ raise RuntimeError("unknown process exit status")
+
+def get_disk_usage(path):
+ """Return disk usage associated with path."""
+ st = os.statvfs(path)
+ free = (st.f_bavail * st.f_frsize)
+ total = (st.f_blocks * st.f_frsize)
+ used = (st.f_blocks - st.f_bfree) * st.f_frsize
+ percent = usage_percent(used, total, _round=1)
+ # NB: the percentage is -5% than what shown by df due to
+ # reserved blocks that we are currently not considering:
+ # http://goo.gl/sWGbH
+ return ntuple_diskinfo(total, used, free, percent)
+
+def _get_terminal_map():
+ ret = {}
+ ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*')
+ for name in ls:
+ assert name not in ret
+ ret[os.stat(name).st_rdev] = name
+ return ret
+
class LsofParser:
"""A wrapper for lsof command line utility.
diff --git a/third_party/psutil/psutil/_psutil_bsd.c b/third_party/psutil/psutil/_psutil_bsd.c
index 7586d9f..d937cbf 100644
--- a/third_party/psutil/psutil/_psutil_bsd.c
+++ b/third_party/psutil/psutil/_psutil_bsd.c
@@ -1,5 +1,9 @@
/*
- * $Id: _psutil_bsd.c 780 2010-11-10 18:42:47Z jloden $
+ * $Id: _psutil_bsd.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
*
* FreeBSD platform-specific module methods for _psutil_bsd
*/
@@ -16,127 +20,19 @@
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/vmmeter.h> /* needed for vmtotal struct */
+#include <sys/mount.h>
+// network-related stuff
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
#include "_psutil_bsd.h"
+#include "_psutil_common.h"
#include "arch/bsd/process_info.h"
-/*
- * define the psutil C module methods and initialize the module.
- */
-static PyMethodDef
-PsutilMethods[] =
-{
- // --- per-process functions
-
- {"get_process_name", get_process_name, METH_VARARGS,
- "Return process name"},
- {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
- "Return process cmdline as a list of cmdline arguments"},
- {"get_process_ppid", get_process_ppid, METH_VARARGS,
- "Return process ppid as an integer"},
- {"get_process_uid", get_process_uid, METH_VARARGS,
- "Return process real user id as an integer"},
- {"get_process_gid", get_process_gid, METH_VARARGS,
- "Return process real group id as an integer"},
- {"get_cpu_times", get_cpu_times, METH_VARARGS,
- "Return tuple of user/kern time for the given PID"},
- {"get_process_create_time", get_process_create_time, METH_VARARGS,
- "Return a float indicating the process create time expressed in "
- "seconds since the epoch"},
- {"get_memory_info", get_memory_info, METH_VARARGS,
- "Return a tuple of RSS/VMS memory information"},
- {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
- "Return number of threads used by process"},
-
-
- // --- system-related functions
-
- {"get_pid_list", get_pid_list, METH_VARARGS,
- "Returns a list of PIDs currently running on the system"},
- {"get_num_cpus", get_num_cpus, METH_VARARGS,
- "Return number of CPUs on the system"},
- {"get_total_phymem", get_total_phymem, METH_VARARGS,
- "Return the total amount of physical memory, in bytes"},
- {"get_avail_phymem", get_avail_phymem, METH_VARARGS,
- "Return the amount of available physical memory, in bytes"},
- {"get_total_virtmem", get_total_virtmem, METH_VARARGS,
- "Return the total amount of virtual memory, in bytes"},
- {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS,
- "Return the amount of available virtual memory, in bytes"},
- {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
- "Return system cpu times as a tuple (user, system, nice, idle, irc)"},
-
- {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)
-static struct module_state _state;
-#endif
-
-#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 = {
- PyModuleDef_HEAD_INIT,
- "psutil_bsd",
- NULL,
- sizeof(struct module_state),
- PsutilMethods,
- NULL,
- psutil_bsd_traverse,
- psutil_bsd_clear,
- NULL
-};
-
-#define INITERROR return NULL
-
-PyObject *
-PyInit__psutil_bsd(void)
-
-#else
-#define INITERROR return
-
-void init_psutil_bsd(void)
-#endif
-{
-#if PY_MAJOR_VERSION >= 3
- PyObject *module = PyModule_Create(&moduledef);
-#else
- PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods);
-#endif
- if (module == NULL) {
- INITERROR;
- }
- struct module_state *st = GETSTATE(module);
-
- st->error = PyErr_NewException("_psutil_bsd.Error", NULL, NULL);
- if (st->error == NULL) {
- Py_DECREF(module);
- INITERROR;
- }
-#if PY_MAJOR_VERSION >= 3
- return module;
-#endif
-}
+// convert a timeval struct to a double
+#define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
/*
@@ -161,11 +57,9 @@ get_kinfo_proc(const pid_t pid, struct kinfo_proc *proc)
/*
* sysctl stores 0 in the size if we can't find the process information.
- * Set errno to ESRCH which will be translated in NoSuchProcess later on.
*/
if (size == 0) {
- errno = ESRCH;
- PyErr_SetFromErrno(PyExc_OSError);
+ NoSuchProcess();
return -1;
}
return 0;
@@ -207,6 +101,28 @@ get_pid_list(PyObject* self, PyObject* args)
/*
+ * Return a Python float indicating the system boot time expressed in
+ * seconds since the epoch.
+ */
+static PyObject*
+get_system_boot_time(PyObject* self, PyObject* args)
+{
+ /* fetch sysctl "kern.boottime" */
+ static int request[2] = { CTL_KERN, KERN_BOOTTIME };
+ struct timeval result;
+ size_t result_len = sizeof result;
+ time_t boot_time = 0;
+
+ if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) {
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+ boot_time = result.tv_sec;
+ return Py_BuildValue("f", (float)boot_time);
+}
+
+
+/*
* Return process name from kinfo_proc as a Python string.
*/
static PyObject*
@@ -225,6 +141,47 @@ get_process_name(PyObject* self, PyObject* args)
/*
+ * Return process pathname executable.
+ * Thanks to Robert N. M. Watson:
+ * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_bin.c?v=8-CURRENT
+ */
+static PyObject*
+get_process_exe(PyObject* self, PyObject* args)
+{
+ long pid;
+ char pathname[PATH_MAX];
+ int error;
+ int mib[4];
+ size_t size;
+
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = pid;
+
+ size = sizeof(pathname);
+ error = sysctl(mib, 4, pathname, &size, NULL, 0);
+ if (error == -1) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+ if (size == 0 || strlen(pathname) == 0) {
+ if (pid_exists(pid) == 0) {
+ return NoSuchProcess();
+ }
+ else {
+ strcpy(pathname, "");
+ }
+ }
+ return Py_BuildValue("s", pathname);
+}
+
+
+/*
* Return process cmdline as a Python list of cmdline arguments.
*/
static PyObject*
@@ -268,10 +225,29 @@ get_process_ppid(PyObject* self, PyObject* args)
/*
- * Return process real uid from kinfo_proc as a Python integer.
+ * Return process status as a Python integer.
+ */
+static PyObject*
+get_process_status(PyObject* self, PyObject* args)
+{
+ long pid;
+ struct kinfo_proc kp;
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ if (get_kinfo_proc(pid, &kp) == -1) {
+ return NULL;
+ }
+ return Py_BuildValue("i", (int)kp.ki_stat);
+}
+
+
+/*
+ * Return process real, effective and saved user ids from kinfo_proc
+ * as a Python tuple.
*/
static PyObject*
-get_process_uid(PyObject* self, PyObject* args)
+get_process_uids(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
@@ -281,15 +257,18 @@ get_process_uid(PyObject* self, PyObject* args)
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
- return Py_BuildValue("l", (long)kp.ki_ruid);
+ return Py_BuildValue("lll", (long)kp.ki_ruid,
+ (long)kp.ki_uid,
+ (long)kp.ki_svuid);
}
/*
- * Return process real group id from ki_comm as a Python integer.
+ * Return process real, effective and saved group ids from kinfo_proc
+ * as a Python tuple.
*/
static PyObject*
-get_process_gid(PyObject* self, PyObject* args)
+get_process_gids(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
@@ -299,7 +278,28 @@ get_process_gid(PyObject* self, PyObject* args)
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
- return Py_BuildValue("l", (long)kp.ki_rgid);
+ return Py_BuildValue("lll", (long)kp.ki_rgid,
+ (long)kp.ki_groups[0],
+ (long)kp.ki_svuid);
+}
+
+
+/*
+ * Return process real, effective and saved group ids from kinfo_proc
+ * as a Python tuple.
+ */
+static PyObject*
+get_process_tty_nr(PyObject* self, PyObject* args)
+{
+ long pid;
+ struct kinfo_proc kp;
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ if (get_kinfo_proc(pid, &kp) == -1) {
+ return NULL;
+ }
+ return Py_BuildValue("i", kp.ki_tdev);
}
@@ -321,9 +321,74 @@ get_process_num_threads(PyObject* self, PyObject* args)
}
+/*
+ * Retrieves all threads used by process returning a list of tuples
+ * including thread id, user time and system time.
+ * Thanks to Robert N. M. Watson:
+ * http://fxr.googlebit.com/source/usr.bin/procstat/procstat_threads.c?v=8-CURRENT
+ */
+static PyObject*
+get_process_threads(PyObject* self, PyObject* args)
+{
+ long pid;
+ int mib[4];
+ struct kinfo_proc *kip;
+ struct kinfo_proc *kipp;
+ int error;
+ unsigned int i;
+ size_t size;
+ PyObject* retList = PyList_New(0);
+ PyObject* pyTuple = NULL;
-// convert a timeval struct to a double
-#define TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+
+ /*
+ * We need to re-query for thread information, so don't use *kipp.
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID | KERN_PROC_INC_THREAD;
+ mib[3] = pid;
+
+ size = 0;
+ error = sysctl(mib, 4, NULL, &size, NULL, 0);
+ if (error == -1) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+ if (size == 0) {
+ return NoSuchProcess();
+ }
+
+ kip = malloc(size);
+ if (kip == NULL) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+
+ error = sysctl(mib, 4, kip, &size, NULL, 0);
+ if (error == -1) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+ if (size == 0) {
+ return NoSuchProcess();
+ }
+
+ for (i = 0; i < size / sizeof(*kipp); i++) {
+ kipp = &kip[i];
+ pyTuple = Py_BuildValue("Idd", kipp->ki_tid,
+ TV2DOUBLE(kipp->ki_rusage.ru_utime),
+ TV2DOUBLE(kipp->ki_rusage.ru_stime)
+ );
+ PyList_Append(retList, pyTuple);
+ Py_XDECREF(pyTuple);
+ }
+ free(kip);
+ return retList;
+}
/*
@@ -391,6 +456,29 @@ get_process_create_time(PyObject* self, PyObject* args)
/*
+ * Return a Python float indicating the process create time expressed in
+ * seconds since the epoch.
+ */
+static PyObject*
+get_process_io_counters(PyObject* self, PyObject* args)
+{
+ long pid;
+ struct kinfo_proc kp;
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ if (get_kinfo_proc(pid, &kp) == -1) {
+ return NULL;
+ }
+ // there's apparently no way to determine bytes count, hence return -1.
+ return Py_BuildValue("(llll)", kp.ki_rusage.ru_inblock,
+ kp.ki_rusage.ru_oublock,
+ -1, -1);
+}
+
+
+
+/*
* Return the RSS and VMS as a Python tuple.
*/
static PyObject*
@@ -546,15 +634,6 @@ get_system_cpu_times(PyObject* self, PyObject* args)
return NULL;
}
- /*
- #define CP_USER 0
- #define CP_NICE 1
- #define CP_SYS 2
- #define CP_INTR 3
- #define CP_IDLE 4
- #define CPUSTATES 5
- */
- //user, nice, system, idle, iowait, irqm, softirq
return Py_BuildValue("(ddddd)",
(double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
(double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
@@ -564,3 +643,317 @@ get_system_cpu_times(PyObject* self, PyObject* args)
);
}
+
+/*
+ * Return a Python list of tuple representing per-cpu times
+ */
+static PyObject*
+get_system_per_cpu_times(PyObject* self, PyObject* args)
+{
+ static int maxcpus;
+ int mib[2];
+ int ncpu;
+ size_t len;
+ size_t size;
+ int i;
+ PyObject* py_retlist = PyList_New(0);
+ PyObject* py_cputime;
+
+ // retrieve maxcpus value
+ size = sizeof(maxcpus);
+ if (sysctlbyname("kern.smp.maxcpus", &maxcpus, &size, NULL, 0) < 0) {
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+ long cpu_time[maxcpus][CPUSTATES];
+
+ // retrieve the number of cpus
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ len = sizeof(ncpu);
+ if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ // per-cpu info
+ size = sizeof(cpu_time);
+ if (sysctlbyname("kern.cp_times", &cpu_time, &size, NULL, 0) == -1) {
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ for (i = 0; i < ncpu; i++) {
+ py_cputime = Py_BuildValue("(ddddd)",
+ (double)cpu_time[i][CP_USER] / CLOCKS_PER_SEC,
+ (double)cpu_time[i][CP_NICE] / CLOCKS_PER_SEC,
+ (double)cpu_time[i][CP_SYS] / CLOCKS_PER_SEC,
+ (double)cpu_time[i][CP_IDLE] / CLOCKS_PER_SEC,
+ (double)cpu_time[i][CP_INTR] / CLOCKS_PER_SEC
+ );
+ PyList_Append(py_retlist, py_cputime);
+ Py_XDECREF(py_cputime);
+ }
+
+ return py_retlist;
+}
+
+
+/*
+ * Return a list of tuples including device, mount point and fs type
+ * for all partitions mounted on the system.
+ */
+static PyObject*
+get_disk_partitions(PyObject* self, PyObject* args)
+{
+ int num;
+ int i;
+ long len;
+ struct statfs *fs;
+ PyObject* py_retlist = PyList_New(0);
+ PyObject* py_tuple;
+
+ // get the number of mount points
+ Py_BEGIN_ALLOW_THREADS
+ num = getfsstat(NULL, 0, MNT_NOWAIT);
+ Py_END_ALLOW_THREADS
+ if (num == -1) {
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ len = sizeof(*fs) * num;
+ fs = malloc(len);
+
+ Py_BEGIN_ALLOW_THREADS
+ num = getfsstat(fs, len, MNT_NOWAIT);
+ Py_END_ALLOW_THREADS
+ if (num == -1) {
+ free(fs);
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ for (i = 0; i < num; i++) {
+ py_tuple = Py_BuildValue("(sss)", fs[i].f_mntfromname, // device
+ fs[i].f_mntonname, // mount point
+ fs[i].f_fstypename); // fs type
+ PyList_Append(py_retlist, py_tuple);
+ Py_XDECREF(py_tuple);
+ }
+
+ free(fs);
+ return py_retlist;
+}
+
+
+/*
+ * Return a Python list of named tuples with overall network I/O information
+ */
+static PyObject*
+get_network_io_counters(PyObject* self, PyObject* args)
+{
+ PyObject* py_retdict = PyDict_New();
+ PyObject* py_ifc_info;
+
+ char *buf = NULL, *lim, *next;
+ struct if_msghdr *ifm;
+ int mib[6];
+ size_t len;
+
+ mib[0] = CTL_NET; // networking subsystem
+ mib[1] = PF_ROUTE; // type of information
+ mib[2] = 0; // protocol (IPPROTO_xxx)
+ mib[3] = 0; // address family
+ mib[4] = NET_RT_IFLIST; // operation
+ mib[5] = 0;
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
+ Py_DECREF(py_retdict);
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+
+ buf = malloc(len);
+
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ if (buf) {
+ free(buf);
+ }
+ Py_DECREF(py_retdict);
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ lim = buf + len;
+
+ for (next = buf; next < lim; ) {
+ ifm = (struct if_msghdr *)next;
+ next += ifm->ifm_msglen;
+
+ if (ifm->ifm_type == RTM_IFINFO) {
+ struct if_msghdr *if2m = (struct if_msghdr *)ifm;
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
+ char ifc_name[32];
+
+ strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen);
+ ifc_name[sdl->sdl_nlen] = 0;
+
+ py_ifc_info = Py_BuildValue("(KKKK)",
+ if2m->ifm_data.ifi_obytes,
+ if2m->ifm_data.ifi_ibytes,
+ if2m->ifm_data.ifi_opackets,
+ if2m->ifm_data.ifi_ipackets);
+ PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info);
+ Py_XDECREF(py_ifc_info);
+ }
+ else {
+ continue;
+ }
+ }
+
+ return py_retdict;
+}
+
+
+
+
+/*
+ * define the psutil C module methods and initialize the module.
+ */
+static PyMethodDef
+PsutilMethods[] =
+{
+ // --- per-process functions
+
+ {"get_process_name", get_process_name, METH_VARARGS,
+ "Return process name"},
+ {"get_process_exe", get_process_exe, METH_VARARGS,
+ "Return process pathname executable"},
+ {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
+ "Return process cmdline as a list of cmdline arguments"},
+ {"get_process_ppid", get_process_ppid, METH_VARARGS,
+ "Return process ppid as an integer"},
+ {"get_process_uids", get_process_uids, METH_VARARGS,
+ "Return process real effective and saved user ids as a Python tuple"},
+ {"get_process_gids", get_process_gids, METH_VARARGS,
+ "Return process real effective and saved group ids as a Python tuple"},
+ {"get_cpu_times", get_cpu_times, METH_VARARGS,
+ "Return tuple of user/kern time for the given PID"},
+ {"get_process_create_time", get_process_create_time, METH_VARARGS,
+ "Return a float indicating the process create time expressed in "
+ "seconds since the epoch"},
+ {"get_memory_info", get_memory_info, METH_VARARGS,
+ "Return a tuple of RSS/VMS memory information"},
+ {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
+ "Return number of threads used by process"},
+ {"get_process_threads", get_process_threads, METH_VARARGS,
+ "Return process threads"},
+ {"get_process_status", get_process_status, METH_VARARGS,
+ "Return process status as an integer"},
+ {"get_process_io_counters", get_process_io_counters, METH_VARARGS,
+ "Return process IO counters"},
+ {"get_process_tty_nr", get_process_tty_nr, METH_VARARGS,
+ "Return process tty (terminal) number"},
+
+
+ // --- system-related functions
+
+ {"get_pid_list", get_pid_list, METH_VARARGS,
+ "Returns a list of PIDs currently running on the system"},
+ {"get_num_cpus", get_num_cpus, METH_VARARGS,
+ "Return number of CPUs on the system"},
+ {"get_total_phymem", get_total_phymem, METH_VARARGS,
+ "Return the total amount of physical memory, in bytes"},
+ {"get_avail_phymem", get_avail_phymem, METH_VARARGS,
+ "Return the amount of available physical memory, in bytes"},
+ {"get_total_virtmem", get_total_virtmem, METH_VARARGS,
+ "Return the total amount of virtual memory, in bytes"},
+ {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS,
+ "Return the amount of available virtual memory, in bytes"},
+ {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
+ "Return system cpu times as a tuple (user, system, nice, idle, irc)"},
+ {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS,
+ "Return system per-cpu times as a list of tuples"},
+ {"get_system_boot_time", get_system_boot_time, METH_VARARGS,
+ "Return a float indicating the system boot time expressed in "
+ "seconds since the epoch"},
+ {"get_disk_partitions", get_disk_partitions, METH_VARARGS,
+ "Return a list of tuples including device, mount point and "
+ "fs type for all partitions mounted on the system."},
+ {"get_network_io_counters", get_network_io_counters, METH_VARARGS,
+ "Return dict of tuples of networks I/O information."},
+
+ {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
+
+#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 = {
+ PyModuleDef_HEAD_INIT,
+ "psutil_bsd",
+ NULL,
+ sizeof(struct module_state),
+ PsutilMethods,
+ NULL,
+ psutil_bsd_traverse,
+ psutil_bsd_clear,
+ NULL
+};
+
+#define INITERROR return NULL
+
+PyObject *
+PyInit__psutil_bsd(void)
+
+#else
+#define INITERROR return
+
+void init_psutil_bsd(void)
+#endif
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *module = PyModule_Create(&moduledef);
+#else
+ PyObject *module = Py_InitModule("_psutil_bsd", PsutilMethods);
+#endif
+ PyModule_AddIntConstant(module, "SSTOP", SSTOP);
+ PyModule_AddIntConstant(module, "SSLEEP", SSLEEP);
+ PyModule_AddIntConstant(module, "SRUN", SRUN);
+ PyModule_AddIntConstant(module, "SIDL", SIDL);
+ PyModule_AddIntConstant(module, "SWAIT", SWAIT);
+ PyModule_AddIntConstant(module, "SLOCK", SLOCK);
+ PyModule_AddIntConstant(module, "SZOMB", SZOMB);
+
+ if (module == NULL) {
+ INITERROR;
+ }
+#if PY_MAJOR_VERSION >= 3
+ return module;
+#endif
+}
+
diff --git a/third_party/psutil/psutil/_psutil_bsd.h b/third_party/psutil/psutil/_psutil_bsd.h
index 80ccc1e..2cc76ae 100644
--- a/third_party/psutil/psutil/_psutil_bsd.h
+++ b/third_party/psutil/psutil/_psutil_bsd.h
@@ -1,5 +1,9 @@
/*
- * $Id: _psutil_bsd.h 777 2010-11-08 18:29:13Z g.rodola $
+ * $Id: _psutil_bsd.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
*
* BSD platform-specific module methods for _psutil_bsd
*/
@@ -10,13 +14,18 @@
static PyObject* get_cpu_times(PyObject* self, PyObject* args);
static PyObject* get_process_name(PyObject* self, PyObject* args);
+static PyObject* get_process_exe(PyObject* self, PyObject* args);
static PyObject* get_process_cmdline(PyObject* self, PyObject* args);
static PyObject* get_process_ppid(PyObject* self, PyObject* args);
-static PyObject* get_process_uid(PyObject* self, PyObject* args);
-static PyObject* get_process_gid(PyObject* self, PyObject* args);
+static PyObject* get_process_uids(PyObject* self, PyObject* args);
+static PyObject* get_process_gids(PyObject* self, PyObject* args);
static PyObject* get_process_create_time(PyObject* self, PyObject* args);
static PyObject* get_memory_info(PyObject* self, PyObject* args);
static PyObject* get_process_num_threads(PyObject* self, PyObject* args);
+static PyObject* get_process_threads(PyObject* self, PyObject* args);
+static PyObject* get_process_status(PyObject* self, PyObject* args);
+static PyObject* get_process_io_counters(PyObject* self, PyObject* args);
+static PyObject* get_process_tty_nr(PyObject* self, PyObject* args);
// --- system-related functions
@@ -27,4 +36,7 @@ static PyObject* get_avail_phymem(PyObject* self, PyObject* args);
static PyObject* get_total_virtmem(PyObject* self, PyObject* args);
static PyObject* get_avail_virtmem(PyObject* self, PyObject* args);
static PyObject* get_system_cpu_times(PyObject* self, PyObject* args);
-
+static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args);
+static PyObject* get_system_boot_time(PyObject* self, PyObject* args);
+static PyObject* get_disk_partitions(PyObject* self, PyObject* args);
+static PyObject* get_network_io_counters(PyObject* self, PyObject* args);
diff --git a/third_party/psutil/psutil/_psutil_common.c b/third_party/psutil/psutil/_psutil_common.c
new file mode 100644
index 0000000..79aef97
--- /dev/null
+++ b/third_party/psutil/psutil/_psutil_common.c
@@ -0,0 +1,39 @@
+/*
+ * $Id: _psutil_common.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
+ *
+ * Routines common to all platforms.
+ */
+
+#include <Python.h>
+
+
+/*
+ * Set OSError(errno=ESRCH, strerror="No such process") Python exception.
+ */
+PyObject *
+NoSuchProcess(void) {
+ PyObject *exc;
+ char *msg = strerror(ESRCH);
+ 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") Python exception.
+ */
+PyObject *
+AccessDenied(void) {
+ PyObject *exc;
+ char *msg = strerror(EACCES);
+ exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg);
+ PyErr_SetObject(PyExc_OSError, exc);
+ Py_XDECREF(exc);
+ return NULL;
+}
+
diff --git a/third_party/psutil/psutil/_psutil_common.h b/third_party/psutil/psutil/_psutil_common.h
new file mode 100644
index 0000000..cfe9493
--- /dev/null
+++ b/third_party/psutil/psutil/_psutil_common.h
@@ -0,0 +1,13 @@
+/*
+ * $Id: _psutil_common.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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* NoSuchProcess(void);
+PyObject* AccessDenied(void);
+
diff --git a/third_party/psutil/psutil/_psutil_linux.c b/third_party/psutil/psutil/_psutil_linux.c
new file mode 100644
index 0000000..6915c0c
--- /dev/null
+++ b/third_party/psutil/psutil/_psutil_linux.c
@@ -0,0 +1,211 @@
+/*
+ * $Id: _psutil_linux.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
+ *
+ * Linux-specific functions.
+ */
+
+#include <Python.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <mntent.h>
+#include <sys/syscall.h>
+#include <linux/unistd.h>
+
+#include "_psutil_linux.h"
+
+
+#define HAS_IOPRIO defined(__NR_ioprio_get) && defined(__NR_ioprio_set)
+
+#if HAS_IOPRIO
+enum {
+ IOPRIO_WHO_PROCESS = 1,
+};
+
+static inline int
+ioprio_get(int which, int who)
+{
+ return syscall(__NR_ioprio_get, which, who);
+}
+
+static inline int
+ioprio_set(int which, int who, int ioprio)
+{
+ return syscall(__NR_ioprio_set, which, who, ioprio);
+}
+
+#define IOPRIO_CLASS_SHIFT 13
+#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
+
+#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
+#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
+#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
+
+
+/*
+ * Return a (ioclass, iodata) Python tuple representing process I/O priority.
+ */
+static PyObject*
+linux_ioprio_get(PyObject* self, PyObject* args)
+{
+ long pid;
+ int ioprio, ioclass, iodata;
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
+ if (ioprio == -1) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ ioclass = IOPRIO_PRIO_CLASS(ioprio);
+ iodata = IOPRIO_PRIO_DATA(ioprio);
+ return Py_BuildValue("ii", ioclass, iodata);
+}
+
+
+/*
+ * A wrapper around ioprio_set(); sets process I/O priority.
+ * ioclass can be either IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE
+ * or 0. iodata goes from 0 to 7 depending on ioclass specified.
+ */
+static PyObject*
+linux_ioprio_set(PyObject* self, PyObject* args)
+{
+ long pid;
+ int ioprio, ioclass, iodata;
+ int retval;
+
+ if (! PyArg_ParseTuple(args, "lii", &pid, &ioclass, &iodata)) {
+ return NULL;
+ }
+ ioprio = IOPRIO_PRIO_VALUE(ioclass, iodata);
+ retval = ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio);
+ if (retval == -1) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif
+
+
+/*
+ * Return disk mounted partitions as a list of tuples including device,
+ * mount point and filesystem type
+ */
+static PyObject*
+get_disk_partitions(PyObject* self, PyObject* args)
+{
+ FILE *file;
+ struct mntent *entry;
+ PyObject* py_retlist = PyList_New(0);
+ PyObject* py_tuple;
+
+ // MOUNTED constant comes from mntent.h and it's == '/etc/mtab'
+ Py_BEGIN_ALLOW_THREADS
+ file = setmntent(MOUNTED, "r");
+ Py_END_ALLOW_THREADS
+ if ((file == 0) || (file == NULL)) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+
+ while ((entry = getmntent(file))) {
+ if (entry == NULL) {
+ endmntent(file);
+ return PyErr_Format(PyExc_RuntimeError, "getmntent() failed");
+ }
+ py_tuple = Py_BuildValue("(sss)", entry->mnt_fsname, // device
+ entry->mnt_dir, // mount point
+ entry->mnt_type); // fs type
+ PyList_Append(py_retlist, py_tuple);
+ Py_XDECREF(py_tuple);
+ }
+
+ endmntent(file);
+ return py_retlist;
+}
+
+
+/*
+ * Define the psutil C module methods and initialize the module.
+ */
+static PyMethodDef
+PsutilMethods[] =
+{
+#if HAS_IOPRIO
+ {"ioprio_get", linux_ioprio_get, METH_VARARGS,
+ "Get process I/O priority"},
+ {"ioprio_set", linux_ioprio_set, METH_VARARGS,
+ "Set process I/O priority"},
+#endif
+ {"get_disk_partitions", get_disk_partitions, METH_VARARGS,
+ "Return disk mounted partitions as a list of tuples including "
+ "device, mount point and filesystem type"},
+
+ {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
+
+#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 = {
+ PyModuleDef_HEAD_INIT,
+ "psutil_linux",
+ NULL,
+ sizeof(struct module_state),
+ PsutilMethods,
+ NULL,
+ psutil_linux_traverse,
+ psutil_linux_clear,
+ NULL
+};
+
+#define INITERROR return NULL
+
+PyObject *
+PyInit__psutil_linux(void)
+
+#else
+#define INITERROR return
+
+void init_psutil_linux(void)
+#endif
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *module = PyModule_Create(&moduledef);
+#else
+ PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
+#endif
+ if (module == NULL) {
+ INITERROR;
+ }
+#if PY_MAJOR_VERSION >= 3
+ return module;
+#endif
+}
+
diff --git a/third_party/psutil/psutil/_psutil_linux.h b/third_party/psutil/psutil/_psutil_linux.h
new file mode 100644
index 0000000..1dc36c8
--- /dev/null
+++ b/third_party/psutil/psutil/_psutil_linux.h
@@ -0,0 +1,16 @@
+/*
+ * $Id: _psutil_linux.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
+ *
+ * LINUX specific module methods for _psutil_linux
+ */
+
+#include <Python.h>
+
+static PyObject* linux_ioprio_get(PyObject* self, PyObject* args);
+static PyObject* linux_ioprio_set(PyObject* self, PyObject* args);
+static PyObject* get_disk_partitions(PyObject* self, PyObject* args);
+
diff --git a/third_party/psutil/psutil/_psutil_mswindows.c b/third_party/psutil/psutil/_psutil_mswindows.c
index 94f9057..3964179 100644
--- a/third_party/psutil/psutil/_psutil_mswindows.c
+++ b/third_party/psutil/psutil/_psutil_mswindows.c
@@ -1,5 +1,9 @@
/*
- * $Id: _psutil_mswindows.c 796 2010-11-12 20:31:28Z g.rodola $
+ * $Id: _psutil_mswindows.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
*
* Windows platform-specific module methods for _psutil_mswindows
*/
@@ -14,147 +18,13 @@
#include <iphlpapi.h>
#include "_psutil_mswindows.h"
+#include "_psutil_common.h"
#include "arch/mswindows/security.h"
#include "arch/mswindows/process_info.h"
#include "arch/mswindows/process_handles.h"
+#include "arch/mswindows/ntextapi.h"
-// ------------------------ Python init ---------------------------
-
-static PyMethodDef
-PsutilMethods[] =
-{
- // --- per-process functions
-
- {"get_process_name", get_process_name, METH_VARARGS,
- "Return process name"},
- {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
- "Return process cmdline as a list of cmdline arguments"},
- {"get_process_ppid", get_process_ppid, METH_VARARGS,
- "Return process ppid as an integer"},
- {"kill_process", kill_process, METH_VARARGS,
- "Kill the process identified by the given PID"},
- {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS,
- "Return tuple of user/kern time for the given PID"},
- {"get_process_create_time", get_process_create_time, METH_VARARGS,
- "Return a float indicating the process create time expressed in "
- "seconds since the epoch"},
- {"get_memory_info", get_memory_info, METH_VARARGS,
- "Return a tuple of RSS/VMS memory information"},
- {"get_process_cwd", get_process_cwd, METH_VARARGS,
- "Return process current working directory"},
- {"suspend_process", suspend_process, METH_VARARGS,
- "Suspend a process"},
- {"resume_process", resume_process, METH_VARARGS,
- "Resume a process"},
- {"get_process_open_files", get_process_open_files, METH_VARARGS,
- "Return files opened by process"},
- {"_QueryDosDevice", _QueryDosDevice, METH_VARARGS,
- "QueryDosDevice binding"},
- {"get_process_username", get_process_username, METH_VARARGS,
- "Return the username of a process"},
- {"get_process_connections", get_process_connections, METH_VARARGS,
- "Return the network connections of a process"},
- {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
- "Return the network connections of a process"},
-
- // --- system-related functions
-
- {"get_pid_list", get_pid_list, METH_VARARGS,
- "Returns a list of PIDs currently running on the system"},
- {"pid_exists", pid_exists, METH_VARARGS,
- "Determine if the process exists in the current process list."},
- {"get_num_cpus", get_num_cpus, METH_VARARGS,
- "Returns the number of CPUs on the system"},
- {"get_system_uptime", get_system_uptime, METH_VARARGS,
- "Return system uptime"},
- {"get_total_phymem", get_total_phymem, METH_VARARGS,
- "Return the total amount of physical memory, in bytes"},
- {"get_total_virtmem", get_total_virtmem, METH_VARARGS,
- "Return the total amount of virtual memory, in bytes"},
- {"get_avail_phymem", get_avail_phymem, METH_VARARGS,
- "Return the amount of available physical memory, in bytes"},
- {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS,
- "Return the amount of available virtual memory, in bytes"},
- {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
- "Return system cpu times as a tuple (user, system, idle)"},
-
- {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)
- static struct module_state _state;
-#endif
-
-#if PY_MAJOR_VERSION >= 3
-
- static int psutil_mswindows_traverse(PyObject *m, visitproc visit, void *arg) {
- Py_VISIT(GETSTATE(m)->error);
- return 0;
- }
-
- static int psutil_mswindows_clear(PyObject *m) {
- Py_CLEAR(GETSTATE(m)->error);
- return 0;
- }
-
- static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- "psutil_mswindows",
- NULL,
- sizeof(struct module_state),
- PsutilMethods,
- NULL,
- psutil_mswindows_traverse,
- psutil_mswindows_clear,
- NULL
- };
-
-#define INITERROR return NULL
-
- PyObject* PyInit__psutil_mswindows(void)
-
-#else
- #define INITERROR return
- void init_psutil_mswindows(void)
-#endif
-{
- struct module_state *st = NULL;
-#if PY_MAJOR_VERSION >= 3
- PyObject *module = PyModule_Create(&moduledef);
-#else
- PyObject *module = Py_InitModule("_psutil_mswindows", PsutilMethods);
-#endif
-
- if (module == NULL) {
- INITERROR;
- }
-
- st = GETSTATE(module);
- st->error = PyErr_NewException("_psutil_mswindow.Error", NULL, NULL);
- if (st->error == NULL) {
- Py_DECREF(module);
- INITERROR;
- }
-
- SetSeDebug();
-
-#if PY_MAJOR_VERSION >= 3
- return module;
-#endif
-}
-
-
-// ------------------------ Public functions ---------------------------
-
/*
* Return a Python float representing the system uptime expressed in seconds
* since the epoch.
@@ -253,10 +123,12 @@ kill_process(PyObject* self, PyObject* args)
HANDLE hProcess;
long pid;
- if (! PyArg_ParseTuple(args, "l", &pid))
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
- if (pid == 0)
+ }
+ if (pid == 0) {
return AccessDenied();
+ }
hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (hProcess == NULL) {
@@ -283,6 +155,67 @@ kill_process(PyObject* self, PyObject* args)
}
+/*
+ * Wait for process to terminate and return its exit code.
+ */
+static PyObject*
+process_wait(PyObject* self, PyObject* args)
+{
+ HANDLE hProcess;
+ DWORD ExitCode;
+ DWORD retVal;
+ long pid;
+ long timeout;
+
+ if (! PyArg_ParseTuple(args, "ll", &pid, &timeout)) {
+ return NULL;
+ }
+ if (pid == 0) {
+ return AccessDenied();
+ }
+
+ hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid);
+ if (hProcess == NULL) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ // no such process; we do not want to raise NSP but
+ // return None instead.
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ else {
+ PyErr_SetFromWindowsErr(0);
+ return NULL;
+ }
+ }
+
+ // wait until the process has terminated
+ Py_BEGIN_ALLOW_THREADS
+ retVal = WaitForSingleObject(hProcess, timeout);
+ Py_END_ALLOW_THREADS
+
+ if (retVal == WAIT_FAILED) {
+ CloseHandle(hProcess);
+ return PyErr_SetFromWindowsErr(GetLastError());
+ }
+ if (retVal == WAIT_TIMEOUT) {
+ CloseHandle(hProcess);
+ return Py_BuildValue("l", WAIT_TIMEOUT);
+ }
+
+ // get the exit code; note: subprocess module (erroneously?) uses
+ // what returned by WaitForSingleObject
+ if (GetExitCodeProcess(hProcess, &ExitCode) == 0) {
+ CloseHandle(hProcess);
+ return PyErr_SetFromWindowsErr(GetLastError());
+ }
+ CloseHandle(hProcess);
+#if PY_MAJOR_VERSION >= 3
+ return PyLong_FromLong((long) ExitCode);
+#else
+ return PyInt_FromLong((long) ExitCode);
+#endif
+}
+
/*
* Return a Python tuple (user_time, kernel_time)
@@ -309,15 +242,16 @@ get_process_cpu_times(PyObject* self, PyObject* args)
}
if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
+ CloseHandle(hProcess);
if (GetLastError() == ERROR_ACCESS_DENIED) {
// usually means the process has died so we throw a NoSuchProcess
// here
- CloseHandle(hProcess);
return NoSuchProcess();
}
- PyErr_SetFromWindowsErr(0);
- CloseHandle(hProcess);
- return NULL;
+ else {
+ PyErr_SetFromWindowsErr(0);
+ return NULL;
+ }
}
CloseHandle(hProcess);
@@ -370,15 +304,15 @@ get_process_create_time(PyObject* self, PyObject* args)
}
if (! GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
+ CloseHandle(hProcess);
if (GetLastError() == ERROR_ACCESS_DENIED) {
// usually means the process has died so we throw a NoSuchProcess here
return NoSuchProcess();
}
else {
PyErr_SetFromWindowsErr(0);
+ return NULL;
}
- CloseHandle(hProcess);
- return NULL;
}
CloseHandle(hProcess);
@@ -421,8 +355,9 @@ get_process_name(PyObject* self, PyObject* args) {
int pid_return;
PyObject* name;
- if (! PyArg_ParseTuple(args, "l", &pid))
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
+ }
if (pid == 0) {
return Py_BuildValue("s", "System Idle Process");
@@ -440,8 +375,9 @@ get_process_name(PyObject* self, PyObject* args) {
}
name = get_name(pid);
- if (name == NULL)
+ if (name == NULL) {
return NULL; // exception set in get_name()
+ }
return name;
}
@@ -455,10 +391,12 @@ get_process_ppid(PyObject* self, PyObject* args) {
int pid_return;
PyObject* ppid;
- if (! PyArg_ParseTuple(args, "l", &pid))
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
- if ((pid == 0) || (pid == 4))
+ }
+ if ((pid == 0) || (pid == 4)) {
return Py_BuildValue("l", 0);
+ }
pid_return = pid_is_running(pid);
if (pid_return == 0) {
@@ -469,8 +407,9 @@ get_process_ppid(PyObject* self, PyObject* args) {
}
ppid = get_ppid(pid);
- if (ppid == NULL)
+ if (ppid == NULL) {
return NULL; // exception set in get_ppid()
+ }
return ppid;
}
@@ -483,10 +422,12 @@ get_process_cmdline(PyObject* self, PyObject* args) {
int pid_return;
PyObject* arglist;
- if (! PyArg_ParseTuple(args, "l", &pid))
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
- if ((pid == 0) || (pid == 4))
+ }
+ if ((pid == 0) || (pid == 4)) {
return Py_BuildValue("[]");
+ }
pid_return = pid_is_running(pid);
if (pid_return == 0) {
@@ -529,9 +470,11 @@ get_memory_info(PyObject* self, PyObject* args)
}
if (! GetProcessMemoryInfo(hProcess, &counters, sizeof(counters)) ) {
+ CloseHandle(hProcess);
return PyErr_SetFromWindowsErr(0);
}
+ CloseHandle(hProcess);
return Py_BuildValue("(nn)", counters.WorkingSetSize, counters.PagefileUsage);
}
@@ -541,7 +484,7 @@ get_memory_info(PyObject* self, PyObject* args)
* in bytes.
*/
static PyObject*
-get_total_phymem(PyObject* self, PyObject* args)
+get_system_phymem(PyObject* self, PyObject* args)
{
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
@@ -550,255 +493,106 @@ get_total_phymem(PyObject* self, PyObject* args)
return PyErr_SetFromWindowsErr(0);
}
- return Py_BuildValue("L", memInfo.ullTotalPhys);
-}
-
-
-/*
- * Return a Python integer indicating the total amount of virtual memory
- * in bytes.
- */
-static PyObject*
-get_total_virtmem(PyObject* self, PyObject* args)
-{
- MEMORYSTATUSEX memInfo;
- memInfo.dwLength = sizeof(MEMORYSTATUSEX);
-
- if (! GlobalMemoryStatusEx(&memInfo) ) {
- return PyErr_SetFromWindowsErr(0);
- }
-
- return Py_BuildValue("L", memInfo.ullTotalPageFile);
-}
-
-
-/*
- * Return a Python integer indicating the amount of available physical memory
- * in bytes.
- */
-static PyObject*
-get_avail_phymem(PyObject* self, PyObject* args)
-{
- MEMORYSTATUSEX memInfo;
- memInfo.dwLength = sizeof(MEMORYSTATUSEX);
- if (! GlobalMemoryStatusEx(&memInfo) ) {
- return PyErr_SetFromWindowsErr(0);
- }
- return Py_BuildValue("L", memInfo.ullAvailPhys);
-}
-
-
-/*
- * Return a Python integer indicating the amount of available virtual memory
- * in bytes.
- */
-static PyObject*
-get_avail_virtmem(PyObject* self, PyObject* args)
-{
- MEMORYSTATUSEX memInfo;
- memInfo.dwLength = sizeof(MEMORYSTATUSEX);
-
- if (! GlobalMemoryStatusEx(&memInfo) ) {
- return PyErr_SetFromWindowsErr(0);
- }
- return Py_BuildValue("L", memInfo.ullAvailPageFile);
+ return Py_BuildValue("(LLLLLLk)",
+ memInfo.ullTotalPhys, // total
+ memInfo.ullAvailPhys, // avail
+ memInfo.ullTotalPageFile, // total page file
+ memInfo.ullAvailPageFile, // avail page file
+ memInfo.ullTotalVirtual, // total virtual
+ memInfo.ullAvailVirtual, // avail virtual
+ memInfo.dwMemoryLoad // percent
+ );
}
#define LO_T ((float)1e-7)
#define HI_T (LO_T*4294967296.0)
-// structures and enums from winternl.h (not available under mingw)
-typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
- LARGE_INTEGER IdleTime;
- LARGE_INTEGER KernelTime;
- LARGE_INTEGER UserTime;
- LARGE_INTEGER Reserved1[2];
- ULONG Reserved2;
-} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
-
-
-typedef enum _SYSTEM_INFORMATION_CLASS {
- SystemBasicInformation = 0,
- SystemPerformanceInformation = 2,
- SystemTimeOfDayInformation = 3,
- SystemProcessInformation = 5,
- SystemProcessorPerformanceInformation = 8,
- SystemInterruptInformation = 23,
- SystemExceptionInformation = 33,
- SystemRegistryQuotaInformation = 37,
- SystemLookasideInformation = 45
-} SYSTEM_INFORMATION_CLASS;
-
/*
- * Return a Python tuple representing user, kernel and idle CPU times
+ * Return a Python list of tuples representing user, kernel and idle
+ * CPU times for every CPU on the system.
*/
static PyObject*
get_system_cpu_times(PyObject* self, PyObject* args)
{
- typedef BOOL (_stdcall *GST_PROC) (LPFILETIME, LPFILETIME, LPFILETIME);
- static GST_PROC GetSystemTimes;
- static BOOL bFirstCall = TRUE;
float idle, kernel, user;
-
- // Improves performance calling GetProcAddress only the first time
- if (bFirstCall) {
- // retrieves GetSystemTimes address in Kernel32
- GetSystemTimes=(GST_PROC)GetProcAddress(GetModuleHandle
- (TEXT("Kernel32.dll")),
- "GetSystemTimes");
- bFirstCall = FALSE;
- }
-
-
- // Uses GetSystemTimes if supported (winXP sp1+)
- if (NULL!=GetSystemTimes) {
- // GetSystemTimes supported
-
- FILETIME idle_time;
- FILETIME kernel_time;
- FILETIME user_time;
-
- if (!GetSystemTimes(&idle_time, &kernel_time, &user_time)) {
- return PyErr_SetFromWindowsErr(0);
- }
-
- idle = (float)((HI_T * idle_time.dwHighDateTime) + \
- (LO_T * idle_time.dwLowDateTime));
- user = (float)((HI_T * user_time.dwHighDateTime) + \
- (LO_T * user_time.dwLowDateTime));
- kernel = (float)((HI_T * kernel_time.dwHighDateTime) + \
- (LO_T * kernel_time.dwLowDateTime));
-
- // kernel time includes idle time on windows
- // we return only busy kernel time subtracting idle time from kernel time
- return Py_BuildValue("(fff)", user,
- kernel - idle,
- idle);
-
- }
-
- else {
- // GetSystemTimes NOT supported, use NtQuerySystemInformation instead
-
- typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG);
- NTQSI_PROC NtQuerySystemInformation;
- HINSTANCE hNtDll;
- SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
- SYSTEM_INFO si;
- UINT i;
-
- // dynamic linking is mandatory to use NtQuerySystemInformation
- hNtDll = LoadLibrary(TEXT("ntdll.dll"));
- if (hNtDll != NULL) {
- // gets NtQuerySystemInformation address
- NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
- hNtDll, "NtQuerySystemInformation");
-
- if (NtQuerySystemInformation != NULL)
+ typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG);
+ NTQSI_PROC NtQuerySystemInformation;
+ HINSTANCE hNtDll;
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
+ SYSTEM_INFO si;
+ UINT i;
+ PyObject *arg = NULL;
+ PyObject *retlist = PyList_New(0);
+
+ // dynamic linking is mandatory to use NtQuerySystemInformation
+ hNtDll = LoadLibrary(TEXT("ntdll.dll"));
+ if (hNtDll != NULL) {
+ // gets NtQuerySystemInformation address
+ NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
+ hNtDll, "NtQuerySystemInformation");
+
+ if (NtQuerySystemInformation != NULL)
+ {
+ // retrives number of processors
+ GetSystemInfo(&si);
+
+ // allocates an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
+ // structures, one per processor
+ sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \
+ malloc(si.dwNumberOfProcessors * \
+ sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
+ if (sppi != NULL)
{
- // retrives number of processors
- GetSystemInfo(&si);
-
- // allocates an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
- // structures, one per processor
- sppi=(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \
- malloc(si.dwNumberOfProcessors * \
- sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
- if (sppi != NULL)
+ // gets cpu time informations
+ if (0 == NtQuerySystemInformation(
+ SystemProcessorPerformanceInformation,
+ sppi,
+ si.dwNumberOfProcessors * sizeof
+ (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
+ NULL)
+ )
{
- // gets cpu time informations
- if (0 == NtQuerySystemInformation(
- SystemProcessorPerformanceInformation,
- sppi,
- si.dwNumberOfProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
- NULL))
- {
- // computes system global times summing each processor value
- idle = user = kernel = 0;
- for (i=0; i<si.dwNumberOfProcessors; i++) {
- idle += (float)((HI_T * sppi[i].IdleTime.HighPart) + \
- (LO_T * sppi[i].IdleTime.LowPart));
- user += (float)((HI_T * sppi[i].UserTime.HighPart) + \
- (LO_T * sppi[i].UserTime.LowPart));
- kernel += (float)((HI_T * sppi[i].KernelTime.HighPart) + \
- (LO_T * sppi[i].KernelTime.LowPart));
- }
-
+ // computes system global times summing each processor value
+ idle = user = kernel = 0;
+ for (i=0; i<si.dwNumberOfProcessors; i++) {
+ user = (float)((HI_T * sppi[i].UserTime.HighPart) + \
+ (LO_T * sppi[i].UserTime.LowPart));
+ idle = (float)((HI_T * sppi[i].IdleTime.HighPart) + \
+ (LO_T * sppi[i].IdleTime.LowPart));
+ kernel = (float)((HI_T * sppi[i].KernelTime.HighPart) + \
+ (LO_T * sppi[i].KernelTime.LowPart));
// kernel time includes idle time on windows
- // we return only busy kernel time subtracting idle
- // time from kernel time
- return Py_BuildValue("(ddd)", user,
- kernel - idle,
- idle
- );
-
- } // END NtQuerySystemInformation
-
- } // END malloc SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
-
- } // END GetProcAddress
-
- } // END LoadLibrary
-
- PyErr_SetFromWindowsErr(0);
- if (sppi) {
- free(sppi);
- }
- if (hNtDll) {
- FreeLibrary(hNtDll);
- }
- return 0;
-
- } // END GetSystemTimes NOT supported
+ // we return only busy kernel time subtracting
+ // idle time from kernel time
+ arg = Py_BuildValue("(ddd)", user,
+ kernel - idle,
+ idle);
+ PyList_Append(retlist, arg);
+ Py_XDECREF(arg);
+ }
+ free(sppi);
+ FreeLibrary(hNtDll);
+ return retlist;
+
+ } // END NtQuerySystemInformation
+ } // END malloc SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
+ } // END GetProcAddress
+ } // END LoadLibrary
+
+ if (sppi) {
+ free(sppi);
+ }
+ if (hNtDll) {
+ FreeLibrary(hNtDll);
+ }
+ PyErr_SetFromWindowsErr(0);
+ return NULL;
}
/*
- * Sid to User convertion
- */
-BOOL SidToUser(PSID pSid, LPTSTR szUser, DWORD dwUserLen, LPTSTR szDomain, DWORD
-dwDomainLen, DWORD pid)
-{
- SID_NAME_USE snuSIDNameUse;
- DWORD dwULen;
- DWORD dwDLen;
-
- dwULen = dwUserLen;
- dwDLen = dwDomainLen;
-
- if ( IsValidSid( pSid ) ) {
- // Get user and domain name based on SID
- if ( LookupAccountSid( NULL, pSid, szUser, &dwULen, szDomain, &dwDLen, &snuSIDNameUse) ) {
- // LocalSystem processes are incorrectly reported as owned
- // by BUILTIN\Administrators We modify that behavior to
- // conform to standard taskmanager only if the process is
- // actually a System process
- if (is_system_proc(pid) == 1) {
- // default to *not* changing the data if we fail to
- // check for local system privileges, so only look for
- // definite confirmed system processes and ignore errors
- if ( lstrcmpi(szDomain, TEXT("builtin")) == 0 && lstrcmpi(szUser, TEXT("administrators")) == 0) {
- strncpy (szUser, "SYSTEM", dwUserLen);
- strncpy (szDomain, "NT AUTHORITY", dwDomainLen);
- }
- }
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-typedef struct _UNICODE_STRING {
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer;
-} UNICODE_STRING, *PUNICODE_STRING;
-
-/*
* Return process current working directory as a Python string.
*/
@@ -922,6 +716,11 @@ suspend_resume_process(DWORD pid, int suspend)
HANDLE hThreadSnap = NULL;
THREADENTRY32 te32 = {0};
+ if (pid == 0) {
+ AccessDenied();
+ return FALSE;
+ }
+
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE) {
PyErr_SetFromWindowsErr(0);
@@ -1015,14 +814,44 @@ resume_process(PyObject* self, PyObject* args)
static PyObject*
get_process_num_threads(PyObject* self, PyObject* args)
{
- long pid;
- int pid_return;
- long nthreads = 0;
+ DWORD pid;
+ PSYSTEM_PROCESS_INFORMATION process;
+ PVOID buffer;
+ int num;
+
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ if (get_process_info(pid, &process, &buffer) != 1) {
+ free(buffer);
+ return NULL;
+ }
+ if (pid_is_running(pid) == 0) {
+ free(buffer);
+ return NoSuchProcess();
+ }
+
+ num = (int)process->NumberOfThreads;
+ free(buffer);
+ return Py_BuildValue("i", num);
+}
+
+
+static PyObject*
+get_process_threads(PyObject* self, PyObject* args)
+{
+ PyObject* retList = PyList_New(0);
+ PyObject* pyTuple = NULL;
HANDLE hThreadSnap = NULL;
THREADENTRY32 te32 = {0};
+ long pid;
+ int pid_return;
+ int rc;
+ FILETIME ftDummy, ftKernel, ftUser;
- if (! PyArg_ParseTuple(args, "l", &pid))
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
+ }
if (pid == 0) {
// raise AD instead of returning 0 as procexp is able to
// retrieve useful information somehow
@@ -1061,30 +890,48 @@ get_process_num_threads(PyObject* self, PyObject* args)
HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION,
FALSE, te32.th32ThreadID);
if (hThread == NULL) {
- if (GetLastError() == ERROR_INVALID_PARAMETER) {
- NoSuchProcess();
- }
- else {
- PyErr_SetFromWindowsErr(0);
- }
+ // thread has disappeared on us
+ continue;
+ }
+
+ rc = GetThreadTimes(hThread, &ftDummy, &ftDummy, &ftKernel, &ftUser);
+ if (rc == 0) {
+ PyErr_SetFromWindowsErr(0);
CloseHandle(hThread);
CloseHandle(hThreadSnap);
return NULL;
}
- nthreads += 1;
+
+ /*
+ user and kernel times are represented as a FILETIME structure
+ wich contains a 64-bit value representing the number of
+ 100-nanosecond intervals since January 1, 1601 (UTC).
+ http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx
+
+ To convert it into a float representing the seconds that the
+ process has executed in user/kernel mode I borrowed the code
+ below from Python's Modules/posixmodule.c
+ */
+ pyTuple = Py_BuildValue("kdd",
+ te32.th32ThreadID,
+ (double)(ftUser.dwHighDateTime*429.4967296 + \
+ ftUser.dwLowDateTime*1e-7),
+ (double)(ftKernel.dwHighDateTime*429.4967296 + \
+ ftKernel.dwLowDateTime*1e-7)
+ );
+ PyList_Append(retList, pyTuple);
+ Py_XDECREF(pyTuple);
+
CloseHandle(hThread);
}
} while (Thread32Next(hThreadSnap, &te32));
- // every process should be supposed to have at least one thread
- if (nthreads == 0) {
- return NoSuchProcess();
- }
-
- return Py_BuildValue("l", nthreads);
+ CloseHandle(hThreadSnap);
+ return retList;
}
+
static PyObject*
get_process_open_files(PyObject* self, PyObject* args)
{
@@ -1103,6 +950,7 @@ get_process_open_files(PyObject* self, PyObject* args)
}
filesList = get_open_files(pid, processHandle);
+ CloseHandle(processHandle);
if (filesList == NULL) {
return PyErr_SetFromWindowsErr(0);
}
@@ -1116,7 +964,7 @@ get_process_open_files(PyObject* self, PyObject* args)
If no match is found return an empty string.
*/
static PyObject*
-_QueryDosDevice(PyObject* self, PyObject* args)
+win32_QueryDosDevice(PyObject* self, PyObject* args)
{
LPCTSTR lpDevicePath;
TCHAR d = TEXT('A');
@@ -1441,8 +1289,9 @@ get_process_connections(PyObject* self, PyObject* args)
for (i = 0; i < tcp4Table->dwNumEntries; i++)
{
- if (tcp4Table->table[i].dwOwningPid != pid)
+ if (tcp4Table->table[i].dwOwningPid != pid) {
continue;
+ }
if (tcp4Table->table[i].dwLocalAddr != 0 ||
tcp4Table->table[i].dwLocalPort != 0)
@@ -1572,8 +1421,9 @@ get_process_connections(PyObject* self, PyObject* args)
for (i = 0; i < udp4Table->dwNumEntries; i++)
{
- if (udp4Table->table[i].dwOwningPid != pid)
+ if (udp4Table->table[i].dwOwningPid != pid) {
continue;
+ }
if (udp4Table->table[i].dwLocalAddr != 0 ||
udp4Table->table[i].dwLocalPort != 0)
@@ -1653,3 +1503,395 @@ get_process_connections(PyObject* self, PyObject* args)
return connectionsList;
}
+
+/*
+ * Get process priority as a Python integer.
+ */
+static PyObject*
+get_process_priority(PyObject* self, PyObject* args)
+{
+ long pid;
+ DWORD priority;
+ HANDLE hProcess;
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+
+ hProcess = handle_from_pid(pid);
+ if (hProcess == NULL) {
+ return NULL;
+ }
+
+ priority = GetPriorityClass(hProcess);
+ CloseHandle(hProcess);
+ if (priority == 0) {
+ PyErr_SetFromWindowsErr(0);
+ return NULL;
+ }
+ return Py_BuildValue("i", priority);
+}
+
+
+/*
+ * Set process priority.
+ */
+static PyObject*
+set_process_priority(PyObject* self, PyObject* args)
+{
+ long pid;
+ int priority;
+ int retval;
+ HANDLE hProcess;
+ DWORD dwDesiredAccess = PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION;
+ if (! PyArg_ParseTuple(args, "li", &pid, &priority)) {
+ return NULL;
+ }
+
+ hProcess = handle_from_pid_waccess(pid, dwDesiredAccess);
+ if (hProcess == NULL) {
+ return NULL;
+ }
+
+ retval = SetPriorityClass(hProcess, priority);
+ CloseHandle(hProcess);
+ if (retval == 0) {
+ PyErr_SetFromWindowsErr(0);
+ return NULL;
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/*
+ * Return a Python tuple referencing process I/O counters.
+ */
+static PyObject*
+get_process_io_counters(PyObject* self, PyObject* args)
+{
+ DWORD pid;
+ HANDLE hProcess;
+ IO_COUNTERS IoCounters;
+
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ if (pid == 0) {
+ return AccessDenied();
+ }
+ hProcess = handle_from_pid(pid);
+ if (NULL == hProcess) {
+ return NULL;
+ }
+ if (! GetProcessIoCounters(hProcess, &IoCounters)) {
+ CloseHandle(hProcess);
+ return PyErr_SetFromWindowsErr(0);
+ }
+ CloseHandle(hProcess);
+ return Py_BuildValue("(KKKK)", IoCounters.ReadOperationCount,
+ IoCounters.WriteOperationCount,
+ IoCounters.ReadTransferCount,
+ IoCounters.WriteTransferCount);
+}
+
+
+/*
+ * Return True if one of the process threads is in a waiting or
+ * suspended status.
+ */
+static PyObject*
+is_process_suspended(PyObject* self, PyObject* args)
+{
+ DWORD pid;
+ ULONG i;
+ PSYSTEM_PROCESS_INFORMATION process;
+ PVOID buffer;
+
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ if (get_process_info(pid, &process, &buffer) != 1) {
+ free(buffer);
+ return NULL;
+ }
+ if (pid_is_running(pid) == 0) {
+ free(buffer);
+ return NoSuchProcess();
+ }
+
+ for (i = 0; i < process->NumberOfThreads; i++) {
+ if (process->Threads[i].ThreadState != Waiting ||
+ process->Threads[i].WaitReason != Suspended)
+ {
+ free(buffer);
+ Py_RETURN_FALSE;
+ }
+ }
+ free(buffer);
+ Py_RETURN_TRUE;
+}
+
+
+/*
+ * Return path's disk total and free as a Python tuple.
+ */
+static PyObject*
+get_disk_usage(PyObject* self, PyObject* args)
+{
+ BOOL retval;
+ ULARGE_INTEGER _, total, free;
+ LPCTSTR path;
+
+ if (! PyArg_ParseTuple(args, "s", &path)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ retval = GetDiskFreeSpaceEx(path, &_, &total, &free);
+ Py_END_ALLOW_THREADS
+ if (retval == 0) {
+ return PyErr_SetFromWindowsErr(0);
+ }
+
+ return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart);
+}
+
+
+/*
+ * Return disk partitions as a list of namedtuples.
+ */
+static PyObject*
+win32_GetLogicalDriveStrings(PyObject* self, PyObject* args)
+{
+ DWORD num_bytes;
+ char drive_strings[255];
+ char* drive_letter = drive_strings;
+ PyObject* py_retlist = PyList_New(0);
+
+ Py_BEGIN_ALLOW_THREADS
+ num_bytes = GetLogicalDriveStrings(254, drive_letter);
+ Py_END_ALLOW_THREADS
+
+ if (num_bytes == 0) {
+ return PyErr_SetFromWindowsErr(0);
+ }
+
+ while (*drive_letter != 0) {
+ PyList_Append(py_retlist, Py_BuildValue("s", drive_letter));
+ drive_letter = strchr(drive_letter, 0) +1;
+ }
+
+ return py_retlist;
+}
+
+
+static PyObject*
+win32_GetDriveType(PyObject* self, PyObject* args)
+{
+ LPCTSTR drive_letter;
+ int type;
+ char* type_str;
+
+ if (! PyArg_ParseTuple(args, "s", &drive_letter)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ type = GetDriveType(drive_letter);
+ Py_END_ALLOW_THREADS
+
+ switch (type) {
+ case DRIVE_UNKNOWN:
+ type_str = "unknown";
+ break;
+ case DRIVE_NO_ROOT_DIR:
+ type_str = "unmounted";
+ case DRIVE_REMOVABLE:
+ type_str = "removable";
+ break;
+ case DRIVE_FIXED:
+ type_str = "fixed";
+ break;
+ case DRIVE_REMOTE:
+ type_str = "remote";
+ break;
+ case DRIVE_CDROM:
+ type_str = "cdrom";
+ break;
+ case DRIVE_RAMDISK:
+ type_str = "ramdisk";
+ break;
+ default:
+ type_str = "?";
+ break;
+ }
+
+ return Py_BuildValue("s", type_str);
+}
+
+
+// ------------------------ Python init ---------------------------
+
+static PyMethodDef
+PsutilMethods[] =
+{
+ // --- per-process functions
+
+ {"get_process_name", get_process_name, METH_VARARGS,
+ "Return process name"},
+ {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
+ "Return process cmdline as a list of cmdline arguments"},
+ {"get_process_ppid", get_process_ppid, METH_VARARGS,
+ "Return process ppid as an integer"},
+ {"kill_process", kill_process, METH_VARARGS,
+ "Kill the process identified by the given PID"},
+ {"get_process_cpu_times", get_process_cpu_times, METH_VARARGS,
+ "Return tuple of user/kern time for the given PID"},
+ {"get_process_create_time", get_process_create_time, METH_VARARGS,
+ "Return a float indicating the process create time expressed in "
+ "seconds since the epoch"},
+ {"get_memory_info", get_memory_info, METH_VARARGS,
+ "Return a tuple of RSS/VMS memory information"},
+ {"get_process_cwd", get_process_cwd, METH_VARARGS,
+ "Return process current working directory"},
+ {"suspend_process", suspend_process, METH_VARARGS,
+ "Suspend a process"},
+ {"resume_process", resume_process, METH_VARARGS,
+ "Resume a process"},
+ {"get_process_open_files", get_process_open_files, METH_VARARGS,
+ "Return files opened by process"},
+ {"get_process_username", get_process_username, METH_VARARGS,
+ "Return the username of a process"},
+ {"get_process_connections", get_process_connections, METH_VARARGS,
+ "Return the network connections of a process"},
+ {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
+ "Return the network connections of a process"},
+ {"get_process_threads", get_process_threads, METH_VARARGS,
+ "Return process threads information as a list of tuple"},
+ {"process_wait", process_wait, METH_VARARGS,
+ "Wait for process to terminate and return its exit code."},
+ {"get_process_priority", get_process_priority, METH_VARARGS,
+ "Return process priority."},
+ {"set_process_priority", set_process_priority, METH_VARARGS,
+ "Set process priority."},
+ {"get_process_io_counters", get_process_io_counters, METH_VARARGS,
+ "Get process I/O counters."},
+ {"is_process_suspended", is_process_suspended, METH_VARARGS,
+ "Return True if one of the process threads is in a suspended state"},
+
+ // --- system-related functions
+
+ {"get_pid_list", get_pid_list, METH_VARARGS,
+ "Returns a list of PIDs currently running on the system"},
+ {"pid_exists", pid_exists, METH_VARARGS,
+ "Determine if the process exists in the current process list."},
+ {"get_num_cpus", get_num_cpus, METH_VARARGS,
+ "Returns the number of CPUs on the system"},
+ {"get_system_uptime", get_system_uptime, METH_VARARGS,
+ "Return system uptime"},
+ {"get_system_phymem", get_system_phymem, METH_VARARGS,
+ "Return the total amount of physical memory, in bytes"},
+ {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
+ "Return system per-cpu times as a list of tuples"},
+ {"get_disk_usage", get_disk_usage, METH_VARARGS,
+ "Return path's disk total and free as a Python tuple."},
+
+ // --- windows API bindings
+ {"win32_GetLogicalDriveStrings", win32_GetLogicalDriveStrings, METH_VARARGS,
+ "GetLogicalDriveStrings binding"},
+ {"win32_GetDriveType", win32_GetDriveType, METH_VARARGS,
+ "GetDriveType binding"},
+ {"win32_QueryDosDevice", win32_QueryDosDevice, METH_VARARGS,
+ "QueryDosDevice binding"},
+
+ {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)
+ static struct module_state _state;
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+
+ static int psutil_mswindows_traverse(PyObject *m, visitproc visit, void *arg) {
+ Py_VISIT(GETSTATE(m)->error);
+ return 0;
+ }
+
+ static int psutil_mswindows_clear(PyObject *m) {
+ Py_CLEAR(GETSTATE(m)->error);
+ return 0;
+ }
+
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "psutil_mswindows",
+ NULL,
+ sizeof(struct module_state),
+ PsutilMethods,
+ NULL,
+ psutil_mswindows_traverse,
+ psutil_mswindows_clear,
+ NULL
+ };
+
+#define INITERROR return NULL
+
+ PyObject* PyInit__psutil_mswindows(void)
+
+#else
+ #define INITERROR return
+ void init_psutil_mswindows(void)
+#endif
+{
+ struct module_state *st = NULL;
+#if PY_MAJOR_VERSION >= 3
+ PyObject *module = PyModule_Create(&moduledef);
+#else
+ PyObject *module = Py_InitModule("_psutil_mswindows", PsutilMethods);
+#endif
+
+ if (module == NULL) {
+ INITERROR;
+ }
+
+ st = GETSTATE(module);
+ st->error = PyErr_NewException("_psutil_mswindow.Error", NULL, NULL);
+ if (st->error == NULL) {
+ Py_DECREF(module);
+ INITERROR;
+ }
+
+ // Public constants
+ // http://msdn.microsoft.com/en-us/library/ms683211(v=vs.85).aspx
+ PyModule_AddIntConstant(module, "ABOVE_NORMAL_PRIORITY_CLASS",
+ ABOVE_NORMAL_PRIORITY_CLASS);
+ PyModule_AddIntConstant(module, "BELOW_NORMAL_PRIORITY_CLASS",
+ BELOW_NORMAL_PRIORITY_CLASS);
+ PyModule_AddIntConstant(module, "HIGH_PRIORITY_CLASS",
+ HIGH_PRIORITY_CLASS);
+ PyModule_AddIntConstant(module, "IDLE_PRIORITY_CLASS",
+ IDLE_PRIORITY_CLASS);
+ PyModule_AddIntConstant(module, "NORMAL_PRIORITY_CLASS",
+ NORMAL_PRIORITY_CLASS);
+ PyModule_AddIntConstant(module, "REALTIME_PRIORITY_CLASS",
+ REALTIME_PRIORITY_CLASS);
+ // private constants
+ PyModule_AddIntConstant(module, "INFINITE", INFINITE);
+ SetSeDebug();
+
+#if PY_MAJOR_VERSION >= 3
+ return module;
+#endif
+}
+
+
+
diff --git a/third_party/psutil/psutil/_psutil_mswindows.h b/third_party/psutil/psutil/_psutil_mswindows.h
index f844a14..c4ff4bc 100644
--- a/third_party/psutil/psutil/_psutil_mswindows.h
+++ b/third_party/psutil/psutil/_psutil_mswindows.h
@@ -1,8 +1,11 @@
/*
- * $Id: _psutil_mswindows.h 778 2010-11-08 19:59:08Z g.rodola $
+ * $Id: _psutil_mswindows.h 1142 2011-10-05 18:45:49Z g.rodola $
*
- * Windows platform-specific module methods for _psutil_mswindows
+ * 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.
*
+ * Windows platform-specific module methods for _psutil_mswindows
*/
#include <Python.h>
@@ -24,20 +27,29 @@ static PyObject* get_process_open_files(PyObject* self, PyObject* args);
static PyObject* get_process_username(PyObject* self, PyObject* args);
static PyObject* get_process_connections(PyObject* self, PyObject* args);
static PyObject* get_process_num_threads(PyObject* self, PyObject* args);
+static PyObject* get_process_threads(PyObject* self, PyObject* args);
+static PyObject* process_wait(PyObject* self, PyObject* args);
+static PyObject* get_process_priority(PyObject* self, PyObject* args);
+static PyObject* set_process_priority(PyObject* self, PyObject* args);
+static PyObject* get_process_io_counters(PyObject* self, PyObject* args);
+static PyObject* is_process_suspended(PyObject* self, PyObject* args);
// --- system-related functions
static PyObject* get_pid_list(PyObject* self, PyObject* args);
static PyObject* get_num_cpus(PyObject* self, PyObject* args);
static PyObject* get_system_uptime(PyObject* self, PyObject* args);
-static PyObject* get_total_phymem(PyObject* self, PyObject* args);
-static PyObject* get_total_virtmem(PyObject* self, PyObject* args);
-static PyObject* get_avail_phymem(PyObject* self, PyObject* args);
-static PyObject* get_avail_virtmem(PyObject* self, PyObject* args);
+static PyObject* get_system_phymem(PyObject* self, PyObject* args);
static PyObject* get_system_cpu_times(PyObject* self, PyObject* args);
-static PyObject* _QueryDosDevice(PyObject* self, PyObject* args);
static PyObject* pid_exists(PyObject* self, PyObject* args);
+static PyObject* get_disk_usage(PyObject* self, PyObject* args);
+static PyObject* get_disk_partitions(PyObject* self, PyObject* args);
+
+// --- windows API bindings
-// --- others
+static PyObject* win32_QueryDosDevice(PyObject* self, PyObject* args);
+static PyObject* win32_GetLogicalDriveStrings(PyObject* self, PyObject* args);
+static PyObject* win32_GetDriveType(PyObject* self, PyObject* args);
+// --- internal
int suspend_resume_process(DWORD pid, int suspend);
diff --git a/third_party/psutil/psutil/_psutil_osx.c b/third_party/psutil/psutil/_psutil_osx.c
index 64947a7..29162f2 100644
--- a/third_party/psutil/psutil/_psutil_osx.c
+++ b/third_party/psutil/psutil/_psutil_osx.c
@@ -1,5 +1,9 @@
/*
- * $Id: _psutil_osx.c 780 2010-11-10 18:42:47Z jloden $
+ * $Id: _psutil_osx.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
*
* OS X platform-specific module methods for _psutil_osx
*/
@@ -10,9 +14,13 @@
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
-#include <signal.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
+#include <libproc.h>
+#include <sys/proc_info.h>
+#include <netinet/tcp_fsm.h>
+#include <arpa/inet.h>
+#include <net/if_dl.h>
#include <mach/mach.h>
#include <mach/task.h>
@@ -22,152 +30,18 @@
#include <mach/mach_traps.h>
#include <mach/shared_memory_server.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/IOBSD.h>
+
#include "_psutil_osx.h"
+#include "_psutil_common.h"
#include "arch/osx/process_info.h"
/*
- * define the psutil C module methods and initialize the module.
- */
-static PyMethodDef
-PsutilMethods[] =
-{
- // --- per-process functions
-
- {"get_process_name", get_process_name, METH_VARARGS,
- "Return process name"},
- {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
- "Return process cmdline as a list of cmdline arguments"},
- {"get_process_ppid", get_process_ppid, METH_VARARGS,
- "Return process ppid as an integer"},
- {"get_process_uid", get_process_uid, METH_VARARGS,
- "Return process real user id as an integer"},
- {"get_process_gid", get_process_gid, METH_VARARGS,
- "Return process real group id as an integer"},
- {"get_cpu_times", get_cpu_times, METH_VARARGS,
- "Return tuple of user/kern time for the given PID"},
- {"get_process_create_time", get_process_create_time, METH_VARARGS,
- "Return a float indicating the process create time expressed in "
- "seconds since the epoch"},
- {"get_memory_info", get_memory_info, METH_VARARGS,
- "Return a tuple of RSS/VMS memory information"},
- {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
- "Return number of threads used by process"},
-
- // --- system-related functions
-
- {"get_pid_list", get_pid_list, METH_VARARGS,
- "Returns a list of PIDs currently running on the system"},
- {"get_num_cpus", get_num_cpus, METH_VARARGS,
- "Return number of CPUs on the system"},
- {"get_total_phymem", get_total_phymem, METH_VARARGS,
- "Return the total amount of physical memory, in bytes"},
- {"get_avail_phymem", get_avail_phymem, METH_VARARGS,
- "Return the amount of available physical memory, in bytes"},
- {"get_total_virtmem", get_total_virtmem, METH_VARARGS,
- "Return the total amount of virtual memory, in bytes"},
- {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS,
- "Return the amount of available virtual memory, in bytes"},
- {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
- "Return system cpu times as a tuple (user, system, nice, idle, irc)"},
-
- {NULL, NULL, 0, NULL}
-};
-
-
-/*
- * Raises an OSError(errno=ESRCH, strerror="No such process") exception
- * in Python.
- */
-static PyObject*
-NoSuchProcess(void) {
- errno = ESRCH;
- return PyErr_SetFromErrno(PyExc_OSError);
-}
-
-/*
- * Raises an OSError(errno=EPERM, strerror="Operation not permitted") exception
- * in Python.
- */
-static PyObject*
-AccessDenied(void) {
- errno = EPERM;
- return PyErr_SetFromErrno(PyExc_OSError);
-}
-
-struct module_state {
- PyObject *error;
-};
-
-#if PY_MAJOR_VERSION >= 3
-#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
-#else
-#define GETSTATE(m) (&_state)
-static struct module_state _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;
-}
-
-
-static struct PyModuleDef
-moduledef = {
- PyModuleDef_HEAD_INIT,
- "psutil_osx",
- NULL,
- sizeof(struct module_state),
- PsutilMethods,
- NULL,
- psutil_osx_traverse,
- psutil_osx_clear,
- NULL
-};
-
-#define INITERROR return NULL
-
-PyObject *
-PyInit__psutil_osx(void)
-
-#else
-#define INITERROR return
-
-void
-init_psutil_osx(void)
-#endif
-{
-#if PY_MAJOR_VERSION >= 3
- PyObject *module = PyModule_Create(&moduledef);
-#else
- PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods);
-#endif
- if (module == NULL) {
- INITERROR;
- }
- struct module_state *st = GETSTATE(module);
-
- st->error = PyErr_NewException("_psutil_osx.Error", NULL, NULL);
- if (st->error == NULL) {
- Py_DECREF(module);
- INITERROR;
- }
-#if PY_MAJOR_VERSION >= 3
- return module;
-#endif
-}
-
-
-/*
* Return a Python list of all the PIDs running on the system.
*/
static PyObject*
@@ -234,13 +108,7 @@ get_process_cmdline(PyObject* self, PyObject* args)
// get the commandline, defined in arch/osx/process_info.c
arglist = get_arg_list(pid);
-
- // get_arg_list() returns NULL only if getcmdargs failed with ESRCH
- // (no process with that PID)
- if (NULL == arglist) {
- return PyErr_SetFromErrno(PyExc_OSError);
- }
- return Py_BuildValue("N", arglist);
+ return arglist;
}
@@ -266,7 +134,7 @@ get_process_ppid(PyObject* self, PyObject* args)
* Return process real uid from kinfo_proc as a Python integer.
*/
static PyObject*
-get_process_uid(PyObject* self, PyObject* args)
+get_process_uids(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
@@ -276,7 +144,9 @@ get_process_uid(PyObject* self, PyObject* args)
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
- return Py_BuildValue("l", (long)kp.kp_eproc.e_pcred.p_ruid);
+ return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_ruid,
+ (long)kp.kp_eproc.e_ucred.cr_uid,
+ (long)kp.kp_eproc.e_pcred.p_svuid);
}
@@ -284,7 +154,7 @@ get_process_uid(PyObject* self, PyObject* args)
* Return process real group id from ki_comm as a Python integer.
*/
static PyObject*
-get_process_gid(PyObject* self, PyObject* args)
+get_process_gids(PyObject* self, PyObject* args)
{
long pid;
struct kinfo_proc kp;
@@ -294,30 +164,27 @@ get_process_gid(PyObject* self, PyObject* args)
if (get_kinfo_proc(pid, &kp) == -1) {
return NULL;
}
- return Py_BuildValue("l", (long)kp.kp_eproc.e_pcred.p_rgid);
+ return Py_BuildValue("lll", (long)kp.kp_eproc.e_pcred.p_rgid,
+ (long)kp.kp_eproc.e_ucred.cr_groups[0],
+ (long)kp.kp_eproc.e_pcred.p_svgid);
}
/*
- * Return 1 if PID exists in the current process list, else 0.
+ * Return process controlling terminal number as an integer.
*/
-static int
-pid_exists(long pid) {
- int kill_ret;
-
- // save some time if it's an invalid PID
- if (pid < 0) {
- return 0;
+static PyObject*
+get_process_tty_nr(PyObject* self, PyObject* args)
+{
+ long pid;
+ struct kinfo_proc kp;
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
}
-
- // if kill returns success of permission denied we know it's a valid PID
- kill_ret = kill(pid , 0);
- if ( (0 == kill_ret) || (EPERM == errno) ) {
- return 1;
+ if (get_kinfo_proc(pid, &kp) == -1) {
+ return NULL;
}
-
- // otherwise return 0 for PID not found
- return 0;
+ return Py_BuildValue("i", kp.kp_eproc.e_tdev);
}
@@ -356,45 +223,44 @@ get_cpu_times(PyObject* self, PyObject* args)
long pid;
int err;
unsigned int info_count = TASK_BASIC_INFO_COUNT;
- task_port_t task;// = (task_port_t)NULL;
+ task_port_t task; // = (task_port_t)NULL;
time_value_t user_time, system_time;
struct task_basic_info tasks_info;
struct task_thread_times_info task_times;
- // the argument passed should be a process id
if (! PyArg_ParseTuple(args, "l", &pid)) {
return NULL;
}
- /* task_for_pid() requires special privileges
+ /* task_for_pid() requires special privileges
* "This function can be called only if the process is owned by the
* procmod group or if the caller is root."
- * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/chapter_5_section_19.html
- */
+ * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/chapter_5_section_19.html */
err = task_for_pid(mach_task_self(), pid, &task);
if ( err == KERN_SUCCESS) {
info_count = TASK_BASIC_INFO_COUNT;
err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count);
if (err != KERN_SUCCESS) {
- if (err == 4) { // errcode 4 is "invalid argument" (access denied)
+ // errcode 4 is "invalid argument" (access denied)
+ if (err == 4) {
return AccessDenied();
}
- //otherwise throw a runtime error with appropriate error code
- return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed for pid %lu - %s (%i)",
- pid, mach_error_string(err), err);
-
+ // otherwise throw a runtime error with appropriate error code
+ return PyErr_Format(PyExc_RuntimeError,
+ "task_info(TASK_BASIC_INFO) failed");
}
info_count = TASK_THREAD_TIMES_INFO_COUNT;
- err = task_info(task, TASK_THREAD_TIMES_INFO, (task_info_t)&task_times, &info_count);
+ err = task_info(task, TASK_THREAD_TIMES_INFO,
+ (task_info_t)&task_times, &info_count);
if (err != KERN_SUCCESS) {
- if (err == 4) { // errcode 4 is "invalid argument" (access denied)
+ // errcode 4 is "invalid argument" (access denied)
+ if (err == 4) {
return AccessDenied();
}
-
- return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_THREAD_TIMES_INFO) failed for pid %lu - %s (%i)",
- pid, mach_error_string(err), err);
+ return PyErr_Format(PyExc_RuntimeError,
+ "task_info(TASK_BASIC_INFO) failed");
}
}
@@ -402,7 +268,6 @@ get_cpu_times(PyObject* self, PyObject* args)
if (! pid_exists(pid) ) {
return NoSuchProcess();
}
-
// pid exists, so return AccessDenied error since task_for_pid() failed
return AccessDenied();
}
@@ -464,20 +329,19 @@ get_memory_info(PyObject* self, PyObject* args)
/* task_for_pid() requires special privileges
* "This function can be called only if the process is owned by the
* procmod group or if the caller is root."
- * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/chapter_5_section_19.html
- */
+ * - http://developer.apple.com/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/chapter_5_section_19.html */
err = task_for_pid(mach_task_self(), pid, &task);
if ( err == KERN_SUCCESS) {
info_count = TASK_BASIC_INFO_COUNT;
err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count);
if (err != KERN_SUCCESS) {
- if (err == 4) { // errcode 4 is "invalid argument" (access denied)
+ if (err == 4) {
+ // errcode 4 is "invalid argument" (access denied)
return AccessDenied();
}
-
- //otherwise throw a runtime error with appropriate error code
- return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed for pid %lu - %s (%i)",
- pid, mach_error_string(err), err);
+ // otherwise throw a runtime error with appropriate error code
+ return PyErr_Format(PyExc_RuntimeError,
+ "task_info(TASK_BASIC_INFO) failed");
}
/* Issue #73 http://code.google.com/p/psutil/issues/detail?id=73
@@ -489,8 +353,9 @@ get_memory_info(PyObject* self, PyObject* args)
(vm_region_info_t)&b_info, &info_count, &object_name);
if (err == KERN_SUCCESS) {
if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) &&
- tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE)) {
- tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
+ tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE))
+ {
+ tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
}
}
}
@@ -515,7 +380,7 @@ static PyObject*
get_process_num_threads(PyObject* self, PyObject* args)
{
long pid;
- int err;
+ int err, ret;
unsigned int info_count = TASK_BASIC_INFO_COUNT;
mach_port_t task;
struct task_basic_info tasks_info;
@@ -537,22 +402,28 @@ get_process_num_threads(PyObject* self, PyObject* args)
info_count = TASK_BASIC_INFO_COUNT;
err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count);
if (err != KERN_SUCCESS) {
- if (err == 4) { // errcode 4 is "invalid argument" (access denied)
+ // errcode 4 is "invalid argument" (access denied)
+ if (err == 4) {
return AccessDenied();
}
- //otherwise throw a runtime error with appropriate error code
- return PyErr_Format(PyExc_RuntimeError, "task_info(TASK_BASIC_INFO) failed for pid %lu - %s (%i)",
- pid, mach_error_string(err), err);
+ // otherwise throw a runtime error with appropriate error code
+ return PyErr_Format(PyExc_RuntimeError,
+ "task_info(TASK_BASIC_INFO) failed");
}
-
err = task_threads(task, &thread_list, &thread_count);
if (err == KERN_SUCCESS) {
+ ret = vm_deallocate(task, (vm_address_t)thread_list,
+ thread_count * sizeof(int));
+ if (ret != KERN_SUCCESS) {
+ printf("vm_deallocate() failed\n");
+ }
return Py_BuildValue("l", (long)thread_count);
}
+ else {
+ return PyErr_Format(PyExc_RuntimeError, "task_thread() failed");
+ }
}
-
-
else {
if (! pid_exists(pid) ) {
return NoSuchProcess();
@@ -584,7 +455,6 @@ get_total_phymem(PyObject* self, PyObject* args)
PyErr_SetFromErrno(0);
return NULL;
}
-
return Py_BuildValue("L", total_phymem);
}
@@ -678,12 +548,883 @@ get_system_cpu_times(PyObject* self, PyObject* args)
"Error in host_statistics(): %s", mach_error_string(error));
}
- //user, nice, system, idle, iowait, irqm, softirq
return Py_BuildValue("(dddd)",
- (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK,
- (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK,
- (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK,
- (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK
- );
+ (double)r_load.cpu_ticks[CPU_STATE_USER] / CLK_TCK,
+ (double)r_load.cpu_ticks[CPU_STATE_NICE] / CLK_TCK,
+ (double)r_load.cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK,
+ (double)r_load.cpu_ticks[CPU_STATE_IDLE] / CLK_TCK
+ );
+}
+
+
+/*
+ * Return a Python list of tuple representing per-cpu times
+ */
+static PyObject*
+get_system_per_cpu_times(PyObject* self, PyObject* args)
+{
+ natural_t cpu_count;
+ processor_info_array_t info_array;
+ mach_msg_type_number_t info_count;
+ kern_return_t error;
+ processor_cpu_load_info_data_t* cpu_load_info;
+ PyObject* py_retlist = PyList_New(0);
+ PyObject* py_cputime;
+ int i, ret;
+
+ error = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO,
+ &cpu_count, &info_array, &info_count);
+ if (error != KERN_SUCCESS) {
+ return PyErr_Format(PyExc_RuntimeError,
+ "Error in host_processor_info(): %s", mach_error_string(error));
+ }
+
+ cpu_load_info = (processor_cpu_load_info_data_t*) info_array;
+
+ for (i = 0; i < cpu_count; i++) {
+ py_cputime = Py_BuildValue("(dddd)",
+ (double)cpu_load_info[i].cpu_ticks[CPU_STATE_USER] / CLK_TCK,
+ (double)cpu_load_info[i].cpu_ticks[CPU_STATE_NICE] / CLK_TCK,
+ (double)cpu_load_info[i].cpu_ticks[CPU_STATE_SYSTEM] / CLK_TCK,
+ (double)cpu_load_info[i].cpu_ticks[CPU_STATE_IDLE] / CLK_TCK
+ );
+ PyList_Append(py_retlist, py_cputime);
+ Py_XDECREF(py_cputime);
+ }
+
+ ret = vm_deallocate(mach_task_self(), (vm_address_t)info_array,
+ info_count * sizeof(int));
+ if (ret != KERN_SUCCESS) {
+ printf("vm_deallocate() failed\n");
+ }
+ return py_retlist;
+}
+
+
+/*
+ * Return a Python float indicating the system boot time expressed in
+ * seconds since the epoch.
+ */
+static PyObject*
+get_system_boot_time(PyObject* self, PyObject* args)
+{
+ /* fetch sysctl "kern.boottime" */
+ static int request[2] = { CTL_KERN, KERN_BOOTTIME };
+ struct timeval result;
+ size_t result_len = sizeof result;
+ time_t boot_time = 0;
+
+ if (sysctl(request, 2, &result, &result_len, NULL, 0) == -1) {
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+ boot_time = result.tv_sec;
+ return Py_BuildValue("f", (float)boot_time);
+}
+
+
+/*
+ * Return a list of tuples including device, mount point and fs type
+ * for all partitions mounted on the system.
+ */
+static PyObject*
+get_disk_partitions(PyObject* self, PyObject* args)
+{
+ int num;
+ int i;
+ long len;
+ struct statfs *fs;
+ PyObject* py_retlist = PyList_New(0);
+ PyObject* py_tuple;
+
+ // get the number of mount points
+ Py_BEGIN_ALLOW_THREADS
+ num = getfsstat(NULL, 0, MNT_NOWAIT);
+ Py_END_ALLOW_THREADS
+ if (num == -1) {
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ len = sizeof(*fs) * num;
+ fs = malloc(len);
+
+ Py_BEGIN_ALLOW_THREADS
+ num = getfsstat(fs, len, MNT_NOWAIT);
+ Py_END_ALLOW_THREADS
+ if (num == -1) {
+ free(fs);
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ for (i = 0; i < num; i++) {
+ py_tuple = Py_BuildValue("(sss)", fs[i].f_mntfromname, // device
+ fs[i].f_mntonname, // mount point
+ fs[i].f_fstypename); // fs type
+ PyList_Append(py_retlist, py_tuple);
+ Py_XDECREF(py_tuple);
+ }
+
+ free(fs);
+ return py_retlist;
+}
+
+
+/*
+ * Return process status as a Python integer.
+ */
+static PyObject*
+get_process_status(PyObject* self, PyObject* args)
+{
+ long pid;
+ struct kinfo_proc kp;
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ if (get_kinfo_proc(pid, &kp) == -1) {
+ return NULL;
+ }
+ return Py_BuildValue("i", (int)kp.kp_proc.p_stat);
+}
+
+
+/*
+ * Return process threads
+ */
+static PyObject*
+get_process_threads(PyObject* self, PyObject* args)
+{
+ long pid;
+ int err, j, ret;
+ kern_return_t kr;
+ unsigned int info_count = TASK_BASIC_INFO_COUNT;
+ mach_port_t task;
+ struct task_basic_info tasks_info;
+ thread_act_port_array_t thread_list;
+ thread_info_data_t thinfo;
+ thread_basic_info_t basic_info_th;
+ mach_msg_type_number_t thread_count, thread_info_count;
+
+ PyObject* retList = PyList_New(0);
+ PyObject* pyTuple = NULL;
+
+ // the argument passed should be a process id
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+
+ // task_for_pid() requires special privileges
+ err = task_for_pid(mach_task_self(), pid, &task);
+ if (err != KERN_SUCCESS) {
+ if (! pid_exists(pid) ) {
+ return NoSuchProcess();
+ }
+ return AccessDenied();
+ }
+
+ info_count = TASK_BASIC_INFO_COUNT;
+ err = task_info(task, TASK_BASIC_INFO, (task_info_t)&tasks_info, &info_count);
+ if (err != KERN_SUCCESS) {
+ // errcode 4 is "invalid argument" (access denied)
+ if (err == 4) {
+ return AccessDenied();
+ }
+ // otherwise throw a runtime error with appropriate error code
+ return PyErr_Format(PyExc_RuntimeError,
+ "task_info(TASK_BASIC_INFO) failed");
+ }
+
+ err = task_threads(task, &thread_list, &thread_count);
+ if (err != KERN_SUCCESS) {
+ return PyErr_Format(PyExc_RuntimeError, "task_threads() failed");
+ }
+
+ for (j = 0; j < thread_count; j++) {
+ thread_info_count = THREAD_INFO_MAX;
+ kr = thread_info(thread_list[j], THREAD_BASIC_INFO,
+ (thread_info_t)thinfo, &thread_info_count);
+ if (kr != KERN_SUCCESS) {
+ return PyErr_Format(PyExc_RuntimeError, "thread_info() failed");
+ }
+ basic_info_th = (thread_basic_info_t)thinfo;
+ // XXX - thread_info structure does not provide any process id;
+ // the best we can do is assigning an incremental bogus value
+ pyTuple = Py_BuildValue("Iff", j + 1,
+ (float)basic_info_th->user_time.microseconds / 1000000.0,
+ (float)basic_info_th->system_time.microseconds / 1000000.0
+ );
+ PyList_Append(retList, pyTuple);
+ Py_XDECREF(pyTuple);
+ }
+
+ ret = vm_deallocate(task, (vm_address_t)thread_list,
+ thread_count * sizeof(int));
+ if (ret != KERN_SUCCESS) {
+ printf("vm_deallocate() failed\n");
+ }
+
+ return retList;
+}
+
+
+/*
+ * Return process open files as a Python tuple.
+ * References:
+ * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/m78fd
+ * - /usr/include/sys/proc_info.h
+ */
+static PyObject*
+get_process_open_files(PyObject* self, PyObject* args)
+{
+ long pid;
+ int pidinfo_result;
+ int iterations;
+ int i;
+ int nb;
+
+ struct proc_fdinfo *fds_pointer;
+ struct proc_fdinfo *fdp_pointer;
+ struct vnode_fdinfowithpath vi;
+
+ PyObject *retList = PyList_New(0);
+ PyObject *tuple = NULL;
+
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+
+ pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
+ if (pidinfo_result <= 0) {
+ goto error;
+ }
+
+ fds_pointer = malloc(pidinfo_result);
+ pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
+ pidinfo_result);
+ free(fds_pointer);
+
+ if (pidinfo_result <= 0) {
+ goto error;
+ }
+
+ iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
+
+ for (i = 0; i < iterations; i++) {
+ fdp_pointer = &fds_pointer[i];
+
+ //
+ if (fdp_pointer->proc_fdtype == PROX_FDTYPE_VNODE)
+ {
+ nb = proc_pidfdinfo(pid,
+ fdp_pointer->proc_fd,
+ PROC_PIDFDVNODEPATHINFO,
+ &vi,
+ sizeof(vi));
+
+ // --- errors checking
+ if (nb <= 0) {
+ if ((errno == ENOENT) || (errno == EBADF)) {
+ // no such file or directory or bad file descriptor;
+ // let's assume the file has been closed or removed
+ continue;
+ }
+ if (errno != 0) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ else
+ return PyErr_Format(PyExc_RuntimeError,
+ "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
+ }
+ if (nb < sizeof(vi)) {
+ return PyErr_Format(PyExc_RuntimeError,
+ "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)");
+ }
+ // --- /errors checking
+
+ // --- construct python list
+ tuple = Py_BuildValue("(si)", vi.pvip.vip_path,
+ (int)fdp_pointer->proc_fd);
+ PyList_Append(retList, tuple);
+ Py_DECREF(tuple);
+ // --- /construct python list
+ }
+ }
+
+ return retList;
+
+error:
+ if (errno != 0)
+ return PyErr_SetFromErrno(PyExc_OSError);
+ else if (! pid_exists(pid) )
+ return NoSuchProcess();
+ else
+ return PyErr_Format(PyExc_RuntimeError,
+ "proc_pidinfo(PROC_PIDLISTFDS) failed");
+}
+
+
+/*
+ * mathes Linux net/tcp_states.h:
+ * http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
+ */
+static char *
+get_connection_status(int st) {
+ switch (st) {
+ case TCPS_CLOSED:
+ return "CLOSE";
+ case TCPS_CLOSING:
+ return "CLOSING";
+ case TCPS_CLOSE_WAIT:
+ return "CLOSE_WAIT";
+ case TCPS_LISTEN:
+ return "LISTEN";
+ case TCPS_ESTABLISHED:
+ return "ESTABLISHED";
+ case TCPS_SYN_SENT:
+ return "SYN_SENT";
+ case TCPS_SYN_RECEIVED:
+ return "SYN_RECV";
+ case TCPS_FIN_WAIT_1:
+ return "FIN_WAIT_1";
+ case TCPS_FIN_WAIT_2:
+ return "FIN_WAIT_2";
+ case TCPS_LAST_ACK:
+ return "LAST_ACK";
+ case TCPS_TIME_WAIT:
+ return "TIME_WAIT";
+ default:
+ return "";
+ }
+}
+
+
+/*
+ * Return process TCP and UDP connections as a list of tuples.
+ * References:
+ * - lsof source code: http://goo.gl/SYW79 and http://goo.gl/wNrC0
+ * - /usr/include/sys/proc_info.h
+ */
+static PyObject*
+get_process_connections(PyObject* self, PyObject* args)
+{
+ long pid;
+ int pidinfo_result;
+ int iterations;
+ int i;
+ int nb;
+
+ struct proc_fdinfo *fds_pointer;
+ struct proc_fdinfo *fdp_pointer;
+ struct socket_fdinfo si;
+
+
+ PyObject *retList = PyList_New(0);
+ PyObject *tuple = NULL;
+ PyObject *laddr = NULL;
+ PyObject *raddr = NULL;
+
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+
+ if (pid == 0) {
+ return retList;
+ }
+
+ pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
+ if (pidinfo_result <= 0) {
+ goto error;
+ }
+
+ fds_pointer = malloc(pidinfo_result);
+ pidinfo_result = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds_pointer,
+ pidinfo_result);
+ free(fds_pointer);
+
+ if (pidinfo_result <= 0) {
+ goto error;
+ }
+
+ iterations = (pidinfo_result / PROC_PIDLISTFD_SIZE);
+
+ for (i = 0; i < iterations; i++) {
+ errno = 0;
+ fdp_pointer = &fds_pointer[i];
+
+ //
+ if (fdp_pointer->proc_fdtype == PROX_FDTYPE_SOCKET)
+ {
+ nb = proc_pidfdinfo(pid, fdp_pointer->proc_fd, PROC_PIDFDSOCKETINFO,
+ &si, sizeof(si));
+
+ // --- errors checking
+ if (nb <= 0) {
+ if (errno == EBADF) {
+ // let's assume socket has been closed
+ continue;
+ }
+ if (errno != 0) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ else {
+ return PyErr_Format(PyExc_RuntimeError,
+ "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed");
+ }
+ }
+ if (nb < sizeof(si)) {
+ return PyErr_Format(PyExc_RuntimeError,
+ "proc_pidinfo(PROC_PIDFDVNODEPATHINFO) failed (buffer mismatch)");
+ }
+ // --- /errors checking
+
+ //
+ int fd, family, type, lport, rport;
+ char lip[200], rip[200];
+ char *state;
+
+ fd = (int)fdp_pointer->proc_fd;
+ family = si.psi.soi_family;
+ type = si.psi.soi_kind;
+
+ if ((family != AF_INET) && (family != AF_INET6)) {
+ continue;
+ }
+
+ if (type == 2)
+ type = SOCK_STREAM;
+ else if (type == 1)
+ type = SOCK_DGRAM;
+ else
+ continue;
+
+ if (errno != 0) {
+ printf("errno 1 = %i\n", errno);
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+
+
+ if (family == AF_INET) {
+ inet_ntop(AF_INET,
+ &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4,
+ lip,
+ sizeof(lip));
+ inet_ntop(AF_INET,
+ &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4,
+ rip,
+ sizeof(lip));
+ }
+ else {
+ inet_ntop(AF_INET6,
+ &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6,
+ lip, sizeof(lip));
+ inet_ntop(AF_INET6,
+ &si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6,
+ lip, sizeof(rip));
+ }
+
+ // check for inet_ntop failures
+ if (errno != 0) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+
+ lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
+ rport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
+ if (type == SOCK_STREAM)
+ state = get_connection_status((int)si.psi.soi_proto.pri_tcp.tcpsi_state);
+ else
+ state = "";
+
+ laddr = Py_BuildValue("(si)", lip, lport);
+ if (rport != 0)
+ raddr = Py_BuildValue("(si)", rip, rport);
+ else
+ raddr = PyTuple_New(0);
+
+ // --- construct python list
+ tuple = Py_BuildValue("(iiiNNs)", fd, family, type, laddr, raddr,
+ state);
+ PyList_Append(retList, tuple);
+ Py_DECREF(tuple);
+ // --- /construct python list
+ }
+ }
+
+ return retList;
+
+error:
+ if (errno != 0)
+ return PyErr_SetFromErrno(PyExc_OSError);
+ else if (! pid_exists(pid) )
+ return NoSuchProcess();
+ else
+ return PyErr_Format(PyExc_RuntimeError,
+ "proc_pidinfo(PROC_PIDLISTFDS) failed");
}
+
+/*
+ * Return a Python list of named tuples with overall network I/O information
+ */
+static PyObject*
+get_network_io_counters(PyObject* self, PyObject* args)
+{
+ PyObject* py_retdict = PyDict_New();
+ PyObject* py_ifc_info;
+
+ char *buf = NULL, *lim, *next;
+ struct if_msghdr *ifm;
+ int mib[6];
+ size_t len;
+
+ mib[0] = CTL_NET; // networking subsystem
+ mib[1] = PF_ROUTE; // type of information
+ mib[2] = 0; // protocol (IPPROTO_xxx)
+ mib[3] = 0; // address family
+ mib[4] = NET_RT_IFLIST2; // operation
+ mib[5] = 0;
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
+ Py_DECREF(py_retdict);
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ buf = malloc(len);
+
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ if (buf) {
+ free(buf);
+ }
+ Py_DECREF(py_retdict);
+ PyErr_SetFromErrno(0);
+ return NULL;
+ }
+
+ lim = buf + len;
+
+ for (next = buf; next < lim; ) {
+ ifm = (struct if_msghdr *)next;
+ next += ifm->ifm_msglen;
+
+ if (ifm->ifm_type == RTM_IFINFO2) {
+ struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1);
+ char ifc_name[32];
+
+ strncpy(ifc_name, sdl->sdl_data, sdl->sdl_nlen);
+ ifc_name[sdl->sdl_nlen] = 0;
+
+ py_ifc_info = Py_BuildValue("(KKKK)",
+ if2m->ifm_data.ifi_obytes,
+ if2m->ifm_data.ifi_ibytes,
+ if2m->ifm_data.ifi_opackets,
+ if2m->ifm_data.ifi_ipackets);
+ PyDict_SetItemString(py_retdict, ifc_name, py_ifc_info);
+ Py_XDECREF(py_ifc_info);
+ }
+ else {
+ continue;
+ }
+ }
+
+ free(buf);
+
+ return py_retdict;
+}
+
+
+/*
+ * Return a Python dict of tuples for disk I/O information
+ */
+static PyObject*
+get_disk_io_counters(PyObject* self, PyObject* args)
+{
+ PyObject* py_retdict = PyDict_New();
+ PyObject* py_disk_info;
+
+ CFDictionaryRef parent_dict;
+ CFDictionaryRef props_dict;
+ CFDictionaryRef stats_dict;
+ io_registry_entry_t parent;
+ io_registry_entry_t disk;
+ io_iterator_t disk_list;
+
+ /* Get list of disks */
+ if (IOServiceGetMatchingServices(kIOMasterPortDefault,
+ IOServiceMatching(kIOMediaClass),
+ &disk_list) != kIOReturnSuccess) {
+ Py_DECREF(py_retdict);
+ PyErr_SetString(PyExc_RuntimeError, "Unable to get the list of disks.");
+ return NULL;
+ }
+
+ /* Iterate over disks */
+ while ((disk = IOIteratorNext(disk_list)) != 0) {
+ parent_dict = NULL;
+ props_dict = NULL;
+ stats_dict = NULL;
+
+ if (IORegistryEntryGetParentEntry(disk, kIOServicePlane, &parent) != kIOReturnSuccess) {
+ PyErr_SetString(PyExc_RuntimeError, "Unable to get the disk's parent.");
+ Py_DECREF(py_retdict);
+ IOObjectRelease(disk);
+ return NULL;
+ }
+
+ if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) {
+ if(IORegistryEntryCreateCFProperties(
+ disk,
+ (CFMutableDictionaryRef *) &parent_dict,
+ kCFAllocatorDefault,
+ kNilOptions) != kIOReturnSuccess)
+ {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Unable to get the parent's properties.");
+ Py_DECREF(py_retdict);
+ IOObjectRelease(disk);
+ IOObjectRelease(parent);
+ return NULL;
+ }
+
+ if (IORegistryEntryCreateCFProperties(parent,
+ (CFMutableDictionaryRef *) &props_dict,
+ kCFAllocatorDefault,
+ kNilOptions) != kIOReturnSuccess)
+ {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Unable to get the disk properties.");
+ Py_DECREF(py_retdict);
+ IOObjectRelease(disk);
+ return NULL;
+ }
+
+ const int kMaxDiskNameSize = 64;
+ CFStringRef disk_name_ref = (CFStringRef)CFDictionaryGetValue(
+ parent_dict,
+ CFSTR(kIOBSDNameKey));
+ char disk_name[kMaxDiskNameSize];
+
+ CFStringGetCString(disk_name_ref,
+ disk_name,
+ kMaxDiskNameSize,
+ CFStringGetSystemEncoding());
+
+ stats_dict = (CFDictionaryRef)CFDictionaryGetValue(
+ props_dict,
+ CFSTR(kIOBlockStorageDriverStatisticsKey));
+
+ if (stats_dict == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "Unable to get disk stats.");
+ Py_DECREF(py_retdict);
+ CFRelease(props_dict);
+ IOObjectRelease(disk);
+ IOObjectRelease(parent);
+ return NULL;
+ }
+
+ CFNumberRef number;
+ int64_t reads, writes, read_bytes, write_bytes, read_time, write_time = 0;
+
+ /* Get disk reads/writes */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(
+ stats_dict,
+ CFSTR(kIOBlockStorageDriverStatisticsReadsKey))))
+ {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &reads);
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(
+ stats_dict,
+ CFSTR(kIOBlockStorageDriverStatisticsWritesKey))))
+ {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &writes);
+ }
+
+ /* Get disk bytes read/written */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(
+ stats_dict,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey))))
+ {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &read_bytes);
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(
+ stats_dict,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey))))
+ {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &write_bytes);
+ }
+
+ /* Get disk time spent reading/writing (nanoseconds) */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(
+ stats_dict,
+ CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey))))
+ {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &read_time);
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(
+ stats_dict,
+ CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &write_time);
+ }
+
+ py_disk_info = Py_BuildValue("(KKKKKK)",
+ reads, writes,
+ read_bytes, write_bytes,
+ read_time, write_time);
+ PyDict_SetItemString(py_retdict, disk_name, py_disk_info);
+ Py_XDECREF(py_disk_info);
+
+ CFRelease(parent_dict);
+ IOObjectRelease(parent);
+ CFRelease(props_dict);
+ IOObjectRelease(disk);
+ }
+ }
+
+ IOObjectRelease (disk_list);
+
+ return py_retdict;
+}
+
+
+/*
+ * define the psutil C module methods and initialize the module.
+ */
+static PyMethodDef
+PsutilMethods[] =
+{
+ // --- per-process functions
+
+ {"get_process_name", get_process_name, METH_VARARGS,
+ "Return process name"},
+ {"get_process_cmdline", get_process_cmdline, METH_VARARGS,
+ "Return process cmdline as a list of cmdline arguments"},
+ {"get_process_ppid", get_process_ppid, METH_VARARGS,
+ "Return process ppid as an integer"},
+ {"get_process_uids", get_process_uids, METH_VARARGS,
+ "Return process real user id as an integer"},
+ {"get_process_gids", get_process_gids, METH_VARARGS,
+ "Return process real group id as an integer"},
+ {"get_cpu_times", get_cpu_times, METH_VARARGS,
+ "Return tuple of user/kern time for the given PID"},
+ {"get_process_create_time", get_process_create_time, METH_VARARGS,
+ "Return a float indicating the process create time expressed in "
+ "seconds since the epoch"},
+ {"get_memory_info", get_memory_info, METH_VARARGS,
+ "Return a tuple of RSS/VMS memory information"},
+ {"get_process_num_threads", get_process_num_threads, METH_VARARGS,
+ "Return number of threads used by process"},
+ {"get_process_status", get_process_status, METH_VARARGS,
+ "Return process status as an integer"},
+ {"get_process_threads", get_process_threads, METH_VARARGS,
+ "Return process threads as a list of tuples"},
+ {"get_process_open_files", get_process_open_files, METH_VARARGS,
+ "Return files opened by process as a list of tuples"},
+ {"get_process_connections", get_process_connections, METH_VARARGS,
+ "Get process TCP and UDP connections as a list of tuples"},
+ {"get_process_tty_nr", get_process_tty_nr, METH_VARARGS,
+ "Return process tty number as an integer"},
+
+ // --- system-related functions
+
+ {"get_pid_list", get_pid_list, METH_VARARGS,
+ "Returns a list of PIDs currently running on the system"},
+ {"get_num_cpus", get_num_cpus, METH_VARARGS,
+ "Return number of CPUs on the system"},
+ {"get_total_phymem", get_total_phymem, METH_VARARGS,
+ "Return the total amount of physical memory, in bytes"},
+ {"get_avail_phymem", get_avail_phymem, METH_VARARGS,
+ "Return the amount of available physical memory, in bytes"},
+ {"get_total_virtmem", get_total_virtmem, METH_VARARGS,
+ "Return the total amount of virtual memory, in bytes"},
+ {"get_avail_virtmem", get_avail_virtmem, METH_VARARGS,
+ "Return the amount of available virtual memory, in bytes"},
+ {"get_system_cpu_times", get_system_cpu_times, METH_VARARGS,
+ "Return system cpu times as a tuple (user, system, nice, idle, irc)"},
+ {"get_system_per_cpu_times", get_system_per_cpu_times, METH_VARARGS,
+ "Return system per-cpu times as a list of tuples"},
+ {"get_system_boot_time", get_system_boot_time, METH_VARARGS,
+ "Return a float indicating the system boot time expressed in "
+ "seconds since the epoch"},
+ {"get_disk_partitions", get_disk_partitions, METH_VARARGS,
+ "Return a list of tuples including device, mount point and "
+ "fs type for all partitions mounted on the system."},
+ {"get_network_io_counters", get_network_io_counters, METH_VARARGS,
+ "Return dict of tuples of networks I/O information."},
+ {"get_disk_io_counters", get_disk_io_counters, METH_VARARGS,
+ "Return dict of tuples of disks I/O information."},
+
+ {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
+
+#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;
+}
+
+
+static struct PyModuleDef
+moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "psutil_osx",
+ NULL,
+ sizeof(struct module_state),
+ PsutilMethods,
+ NULL,
+ psutil_osx_traverse,
+ psutil_osx_clear,
+ NULL
+};
+
+#define INITERROR return NULL
+
+PyObject *
+PyInit__psutil_osx(void)
+
+#else
+#define INITERROR return
+
+void
+init_psutil_osx(void)
+#endif
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *module = PyModule_Create(&moduledef);
+#else
+ PyObject *module = Py_InitModule("_psutil_osx", PsutilMethods);
+#endif
+ // 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 (module == NULL) {
+ INITERROR;
+ }
+#if PY_MAJOR_VERSION >= 3
+ return module;
+#endif
+}
diff --git a/third_party/psutil/psutil/_psutil_osx.h b/third_party/psutil/psutil/_psutil_osx.h
index ebef764..a0378a7 100644
--- a/third_party/psutil/psutil/_psutil_osx.h
+++ b/third_party/psutil/psutil/_psutil_osx.h
@@ -1,5 +1,9 @@
/*
- * $Id: _psutil_osx.h 780 2010-11-10 18:42:47Z jloden $
+ * $Id: _psutil_osx.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
*
* OS X platform-specific module methods for _psutil_osx
*/
@@ -10,15 +14,19 @@
static PyObject* get_process_name(PyObject* self, PyObject* args);
static PyObject* get_process_cmdline(PyObject* self, PyObject* args);
static PyObject* get_process_ppid(PyObject* self, PyObject* args);
-static PyObject* get_process_uid(PyObject* self, PyObject* args);
-static PyObject* get_process_gid(PyObject* self, PyObject* args);
+static PyObject* get_process_uids(PyObject* self, PyObject* args);
+static PyObject* get_process_gids(PyObject* self, PyObject* args);
static PyObject* get_cpu_times(PyObject* self, PyObject* args);
static PyObject* get_process_create_time(PyObject* self, PyObject* args);
static PyObject* get_memory_info(PyObject* self, PyObject* args);
static PyObject* get_process_num_threads(PyObject* self, PyObject* args);
+static PyObject* get_process_status(PyObject* self, PyObject* args);
+static PyObject* get_process_threads(PyObject* self, PyObject* args);
+static PyObject* get_process_open_files(PyObject* self, PyObject* args);
+static PyObject* get_process_connections(PyObject* self, PyObject* args);
+static PyObject* get_process_tty_nr(PyObject* self, PyObject* args);
// --- system-related functions
-static int pid_exists(long pid);
static PyObject* get_pid_list(PyObject* self, PyObject* args);
static PyObject* get_num_cpus(PyObject* self, PyObject* args);
static PyObject* get_total_phymem(PyObject* self, PyObject* args);
@@ -26,4 +34,8 @@ static PyObject* get_avail_phymem(PyObject* self, PyObject* args);
static PyObject* get_total_virtmem(PyObject* self, PyObject* args);
static PyObject* get_avail_virtmem(PyObject* self, PyObject* args);
static PyObject* get_system_cpu_times(PyObject* self, PyObject* args);
-
+static PyObject* get_system_per_cpu_times(PyObject* self, PyObject* args);
+static PyObject* get_system_boot_time(PyObject* self, PyObject* args);
+static PyObject* get_disk_partitions(PyObject* self, PyObject* args);
+static PyObject* get_network_io_counters(PyObject* self, PyObject* args);
+static PyObject* get_disk_io_counters(PyObject* self, PyObject* args);
diff --git a/third_party/psutil/psutil/_psutil_posix.c b/third_party/psutil/psutil/_psutil_posix.c
new file mode 100644
index 0000000..6a530f0
--- /dev/null
+++ b/third_party/psutil/psutil/_psutil_posix.c
@@ -0,0 +1,134 @@
+/*
+ * $Id: _psutil_posix.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
+ *
+ * Functions specific to all POSIX compliant platforms.
+ */
+
+#include <Python.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+
+#include "_psutil_posix.h"
+
+
+/*
+ * Given a PID return process priority as a Python integer.
+ */
+static PyObject*
+posix_getpriority(PyObject* self, PyObject* args)
+{
+ long pid;
+ int priority;
+ errno = 0;
+ if (! PyArg_ParseTuple(args, "l", &pid)) {
+ return NULL;
+ }
+ priority = getpriority(PRIO_PROCESS, pid);
+ if (errno != 0) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ return Py_BuildValue("i", priority);
+}
+
+/*
+ * Given a PID and a value change process priority.
+ */
+static PyObject*
+posix_setpriority(PyObject* self, PyObject* args)
+{
+ long pid;
+ int priority;
+ int retval;
+ if (! PyArg_ParseTuple(args, "li", &pid, &priority)) {
+ return NULL;
+ }
+ retval = setpriority(PRIO_PROCESS, pid, priority);
+ if (retval == -1) {
+ return PyErr_SetFromErrno(PyExc_OSError);
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/*
+ * define the psutil C module methods and initialize the module.
+ */
+static PyMethodDef
+PsutilMethods[] =
+{
+ {"getpriority", posix_getpriority, METH_VARARGS,
+ "Return process priority"},
+ {"setpriority", posix_setpriority, METH_VARARGS,
+ "Set process priority"},
+ {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
+
+#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;
+}
+
+static struct PyModuleDef
+moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "psutil_posix",
+ NULL,
+ sizeof(struct module_state),
+ PsutilMethods,
+ NULL,
+ psutil_posix_traverse,
+ psutil_posix_clear,
+ NULL
+};
+
+#define INITERROR return NULL
+
+PyObject *
+PyInit__psutil_posix(void)
+
+#else
+#define INITERROR return
+
+void init_psutil_posix(void)
+#endif
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *module = PyModule_Create(&moduledef);
+#else
+ PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
+#endif
+ if (module == NULL) {
+ INITERROR;
+ }
+#if PY_MAJOR_VERSION >= 3
+ return module;
+#endif
+}
+
+
+
diff --git a/third_party/psutil/psutil/_psutil_posix.h b/third_party/psutil/psutil/_psutil_posix.h
new file mode 100644
index 0000000..8a1f522
--- /dev/null
+++ b/third_party/psutil/psutil/_psutil_posix.h
@@ -0,0 +1,15 @@
+/*
+ * $Id: _psutil_posix.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
+ *
+ * POSIX specific module methods for _psutil_posix
+ */
+
+#include <Python.h>
+
+static PyObject* posix_getpriority(PyObject* self, PyObject* args);
+static PyObject* posix_setpriority(PyObject* self, PyObject* args);
+
diff --git a/third_party/psutil/psutil/arch/bsd/process_info.c b/third_party/psutil/psutil/arch/bsd/process_info.c
index 64004c9..d300646 100644
--- a/third_party/psutil/psutil/arch/bsd/process_info.c
+++ b/third_party/psutil/psutil/arch/bsd/process_info.c
@@ -1,5 +1,9 @@
/*
- * $Id: process_info.c 772 2010-11-03 13:51:11Z g.rodola $
+ * $Id: process_info.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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 functions related to fetching process information. Used by _psutil_bsd
* module methods.
@@ -242,3 +246,25 @@ get_arg_list(long pid)
return retlist;
}
+
+/*
+ * Return 1 if PID exists in the current process list, else 0.
+ */
+int
+pid_exists(long pid)
+{
+ int kill_ret;
+ if (pid < 0) {
+ return 0;
+ }
+
+ // if kill returns success of permission denied we know it's a valid PID
+ kill_ret = kill(pid , 0);
+ if ((0 == kill_ret) || (EPERM == errno)) {
+ return 1;
+ }
+
+ // otherwise return 0 for PID not found
+ return 0;
+}
+
diff --git a/third_party/psutil/psutil/arch/bsd/process_info.h b/third_party/psutil/psutil/arch/bsd/process_info.h
index d72e69c..9129153 100644
--- a/third_party/psutil/psutil/arch/bsd/process_info.h
+++ b/third_party/psutil/psutil/arch/bsd/process_info.h
@@ -1,5 +1,9 @@
/*
- * $Id: process_info.h 213 2009-03-05 15:48:22Z jloden $
+ * $Id: process_info.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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 functions related to fetching process information. Used by _psutil_bsd
* module methods.
@@ -13,4 +17,5 @@ int get_proc_list(struct kinfo_proc **procList, size_t *procCount);
char *getcmdargs(long pid, size_t *argsize);
char *getcmdpath(long pid, size_t *pathsize);
PyObject* get_arg_list(long pid);
+int pid_exists(long pid);
diff --git a/third_party/psutil/psutil/arch/mswindows/ntextapi.h b/third_party/psutil/psutil/arch/mswindows/ntextapi.h
new file mode 100644
index 0000000..bb89923
--- /dev/null
+++ b/third_party/psutil/psutil/arch/mswindows/ntextapi.h
@@ -0,0 +1,183 @@
+/*
+ * $Id: ntextapi.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
+ *
+ */
+
+typedef enum _KTHREAD_STATE
+{
+ Initialized,
+ Ready,
+ Running,
+ Standby,
+ Terminated,
+ Waiting,
+ Transition,
+ DeferredReady,
+ GateWait,
+ MaximumThreadState
+} KTHREAD_STATE, *PKTHREAD_STATE;
+
+typedef enum _KWAIT_REASON
+{
+ Executive = 0,
+ FreePage = 1,
+ PageIn = 2,
+ PoolAllocation = 3,
+ DelayExecution = 4,
+ Suspended = 5,
+ UserRequest = 6,
+ WrExecutive = 7,
+ WrFreePage = 8,
+ WrPageIn = 9,
+ WrPoolAllocation = 10,
+ WrDelayExecution = 11,
+ WrSuspended = 12,
+ WrUserRequest = 13,
+ WrEventPair = 14,
+ WrQueue = 15,
+ WrLpcReceive = 16,
+ WrLpcReply = 17,
+ WrVirtualMemory = 18,
+ WrPageOut = 19,
+ WrRendezvous = 20,
+ Spare2 = 21,
+ Spare3 = 22,
+ Spare4 = 23,
+ Spare5 = 24,
+ WrCalloutStack = 25,
+ WrKernel = 26,
+ WrResource = 27,
+ WrPushLock = 28,
+ WrMutex = 29,
+ WrQuantumEnd = 30,
+ WrDispatchInt = 31,
+ WrPreempted = 32,
+ WrYieldExecution = 33,
+ WrFastMutex = 34,
+ WrGuardedMutex = 35,
+ WrRundown = 36,
+ MaximumWaitReason = 37
+} KWAIT_REASON, *PKWAIT_REASON;
+
+
+typedef struct _CLIENT_ID
+{
+ HANDLE UniqueProcess;
+ HANDLE UniqueThread;
+} CLIENT_ID, *PCLIENT_ID;
+
+
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+
+typedef struct _SYSTEM_TIMEOFDAY_INFORMATION
+{
+ LARGE_INTEGER BootTime;
+ LARGE_INTEGER CurrentTime;
+ LARGE_INTEGER TimeZoneBias;
+ ULONG TimeZoneId;
+ ULONG Reserved;
+ ULONGLONG BootTimeBias;
+ ULONGLONG SleepTimeBias;
+} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION;
+
+typedef struct _SYSTEM_THREAD_INFORMATION
+{
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER CreateTime;
+ ULONG WaitTime;
+ PVOID StartAddress;
+ CLIENT_ID ClientId;
+ LONG Priority;
+ LONG BasePriority;
+ ULONG ContextSwitches;
+ ULONG ThreadState;
+ KWAIT_REASON WaitReason;
+} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
+
+typedef struct _TEB *PTEB;
+
+// private
+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_INFORMATION
+{
+ ULONG NextEntryOffset;
+ ULONG NumberOfThreads;
+ LARGE_INTEGER SpareLi1;
+ LARGE_INTEGER SpareLi2;
+ LARGE_INTEGER SpareLi3;
+ LARGE_INTEGER CreateTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER KernelTime;
+ UNICODE_STRING ImageName;
+ LONG BasePriority;
+ HANDLE UniqueProcessId;
+ HANDLE InheritedFromUniqueProcessId;
+ ULONG HandleCount;
+ ULONG SessionId;
+ ULONG_PTR PageDirectoryBase;
+ SIZE_T PeakVirtualSize;
+ SIZE_T VirtualSize;
+ ULONG PageFaultCount;
+ SIZE_T PeakWorkingSetSize;
+ SIZE_T WorkingSetSize;
+ SIZE_T QuotaPeakPagedPoolUsage;
+ SIZE_T QuotaPagedPoolUsage;
+ SIZE_T QuotaPeakNonPagedPoolUsage;
+ SIZE_T QuotaNonPagedPoolUsage;
+ SIZE_T PagefileUsage;
+ SIZE_T PeakPagefileUsage;
+ SIZE_T PrivatePageCount;
+ LARGE_INTEGER ReadOperationCount;
+ LARGE_INTEGER WriteOperationCount;
+ LARGE_INTEGER OtherOperationCount;
+ LARGE_INTEGER ReadTransferCount;
+ LARGE_INTEGER WriteTransferCount;
+ LARGE_INTEGER OtherTransferCount;
+ SYSTEM_THREAD_INFORMATION Threads[1];
+} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
+
+
+// structures and enums from winternl.h (not available under mingw)
+typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
+ LARGE_INTEGER IdleTime;
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER Reserved1[2];
+ ULONG Reserved2;
+} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
+
+
+typedef enum _SYSTEM_INFORMATION_CLASS {
+ SystemBasicInformation = 0,
+ SystemPerformanceInformation = 2,
+ SystemTimeOfDayInformation = 3,
+ SystemProcessInformation = 5,
+ SystemProcessorPerformanceInformation = 8,
+ SystemInterruptInformation = 23,
+ SystemExceptionInformation = 33,
+ SystemRegistryQuotaInformation = 37,
+ SystemLookasideInformation = 45
+} SYSTEM_INFORMATION_CLASS;
+
+
diff --git a/third_party/psutil/psutil/arch/mswindows/process_handles.c b/third_party/psutil/psutil/arch/mswindows/process_handles.c
index fd272f2..0fc4a3f 100644
--- a/third_party/psutil/psutil/arch/mswindows/process_handles.c
+++ b/third_party/psutil/psutil/arch/mswindows/process_handles.c
@@ -1,3 +1,12 @@
+/*
+ * $Id: process_handles.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
+ *
+ */
+
#ifndef UNICODE
#define UNICODE
#endif
diff --git a/third_party/psutil/psutil/arch/mswindows/process_handles.h b/third_party/psutil/psutil/arch/mswindows/process_handles.h
index bd9d39b..3d007b8 100644
--- a/third_party/psutil/psutil/arch/mswindows/process_handles.h
+++ b/third_party/psutil/psutil/arch/mswindows/process_handles.h
@@ -1,3 +1,11 @@
+/*
+ * $Id: process_info.h 1060 2011-07-02 18:05:26Z g.rodola $
+ *
+ * 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>
#include <windows.h>
diff --git a/third_party/psutil/psutil/arch/mswindows/process_info.c b/third_party/psutil/psutil/arch/mswindows/process_info.c
index 3713eae..53b1480 100644
--- a/third_party/psutil/psutil/arch/mswindows/process_info.c
+++ b/third_party/psutil/psutil/arch/mswindows/process_info.c
@@ -1,5 +1,9 @@
/*
- * $Id: process_info.c 778 2010-11-08 19:59:08Z g.rodola $
+ * $Id: process_info.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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 functions related to fetching process information. Used by
* _psutil_mswindows module methods.
@@ -12,7 +16,7 @@
#include "security.h"
#include "process_info.h"
-
+#include "ntextapi.h"
/*
* NtQueryInformationProcess code taken from
@@ -29,13 +33,6 @@ typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
PDWORD ReturnLength
);
-typedef struct _UNICODE_STRING
-{
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer;
-} UNICODE_STRING, *PUNICODE_STRING;
-
typedef struct _PROCESS_BASIC_INFORMATION
{
PVOID Reserved1;
@@ -47,33 +44,6 @@ typedef struct _PROCESS_BASIC_INFORMATION
/*
- * Set OSError(errno=ESRCH, strerror="No such process") Python exception.
- */
-PyObject *
-NoSuchProcess(void) {
- PyObject *exc;
- char *msg = strerror(ESRCH);
- exc = PyObject_CallFunction(PyExc_OSError, "(is)", ESRCH, msg);
- PyErr_SetObject(PyExc_OSError, exc);
- Py_XDECREF(exc);
- return NULL;
-}
-
-/*
- * Set OSError(errno=EACCES, strerror="No such process") Python exception.
- */
-PyObject *
-AccessDenied(void) {
- PyObject *exc;
- char *msg = strerror(EACCES);
- exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg);
- PyErr_SetObject(PyExc_OSError, exc);
- Py_XDECREF(exc);
- return NULL;
-}
-
-
-/*
* A wrapper around OpenProcess setting NSP exception if process
* no longer exists.
* "pid" is the process pid, "dwDesiredAccess" is the first argument
@@ -177,39 +147,6 @@ get_pids(DWORD *numberOfReturnedPIDs) {
int
-is_system_proc(DWORD pid) {
- HANDLE hProcess;
-
- // Special case for PID 0 System Idle Process
- // and PID 4 (SYSTEM)
- if ((pid == 0) || (pid == 4)) {
- return 1;
- }
- if (pid < 0) {
- return 0;
- }
-
- hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
- if (NULL == hProcess) {
- // invalid parameter is no such process
- if (GetLastError() == ERROR_INVALID_PARAMETER) {
- return 0;
- }
-
- // access denied obviously means there's a process to deny access to...
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- return 1;
- }
-
- PyErr_SetFromWindowsErr(0);
- return -1;
- }
-
- return HasSystemPrivilege(hProcess);
-}
-
-
-int
pid_is_running(DWORD pid)
{
HANDLE hProcess;
@@ -270,7 +207,7 @@ pid_in_proclist(DWORD pid)
proclist = get_pids(&numberOfReturnedPIDs);
if (NULL == proclist) {
- return NULL;
+ return -1;
}
for (i = 0; i < numberOfReturnedPIDs; i++) {
@@ -340,7 +277,7 @@ get_ppid(long pid)
if( Process32First(h, &pe)) {
do {
if (pe.th32ProcessID == pid) {
- //printf("PID: %i; PPID: %i\n", pid, pe.th32ParentProcessID);
+ ////printf("PID: %i; PPID: %i\n", pid, pe.th32ParentProcessID);
CloseHandle(h);
return Py_BuildValue("I", pe.th32ParentProcessID);
}
@@ -376,7 +313,6 @@ get_arg_list(long pid)
PyObject *arg_from_wchar = NULL;
PyObject *argList = NULL;
-
hProcess = handle_from_pid(pid);
if(hProcess == NULL) {
return NULL;
@@ -393,7 +329,7 @@ get_arg_list(long pid)
&rtlUserProcParamsAddress, sizeof(PVOID), NULL))
#endif
{
- //printf("Could not read the address of ProcessParameters!\n");
+ ////printf("Could not read the address of ProcessParameters!\n");
PyErr_SetFromWindowsErr(0);
CloseHandle(hProcess);
return NULL;
@@ -408,9 +344,9 @@ get_arg_list(long pid)
&commandLine, sizeof(commandLine), NULL))
#endif
{
- //printf("Could not read CommandLine!\n");
- PyErr_SetFromWindowsErr(0);
+ ////printf("Could not read CommandLine!\n");
CloseHandle(hProcess);
+ PyErr_SetFromWindowsErr(0);
return NULL;
}
@@ -422,15 +358,15 @@ get_arg_list(long pid)
if (!ReadProcessMemory(hProcess, commandLine.Buffer,
commandLineContents, commandLine.Length, NULL))
{
- //printf("Could not read the command line string!\n");
- PyErr_SetFromWindowsErr(0);
+ ////printf("Could not read the command line string!\n");
CloseHandle(hProcess);
+ PyErr_SetFromWindowsErr(0);
free(commandLineContents);
return NULL;
}
/* print the commandline */
- //printf("%.*S\n", commandLine.Length / 2, commandLineContents);
+ ////printf("%.*S\n", commandLine.Length / 2, commandLineContents);
// null-terminate the string to prevent wcslen from returning incorrect length
// the length specifier is in characters, but commandLine.Length is in bytes
@@ -455,7 +391,7 @@ get_arg_list(long pid)
// string object and add to arg list
argList = Py_BuildValue("[]");
for(i=0; i<nArgs; i++) {
- //printf("%d: %.*S (%d characters)\n", i, wcslen(szArglist[i]),
+ ////printf("%d: %.*S (%d characters)\n", i, wcslen(szArglist[i]),
// szArglist[i], wcslen(szArglist[i]));
arg_from_wchar = PyUnicode_FromWideChar(szArglist[i],
wcslen(szArglist[i])
@@ -477,3 +413,78 @@ get_arg_list(long pid)
return argList;
}
+
+#define PH_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes))
+
+#define PH_NEXT_PROCESS(Process) ( \
+ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \
+ (PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \
+ ((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \
+ NULL \
+ )
+
+const STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
+const STATUS_BUFFER_TOO_SMALL = 0xC0000023L;
+
+/*
+ * Given a process PID and a PSYSTEM_PROCESS_INFORMATION structure
+ * fills the structure with process information.
+ * On success return 1, else 0 with Python exception already set.
+ */
+int
+get_process_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess, PVOID *retBuffer)
+{
+ static ULONG initialBufferSize = 0x4000;
+ NTSTATUS status;
+ PVOID buffer;
+ ULONG bufferSize;
+ PSYSTEM_PROCESS_INFORMATION process;
+
+ // get NtQuerySystemInformation
+ typedef DWORD (_stdcall *NTQSI_PROC) (int, PVOID, ULONG, PULONG);
+ NTQSI_PROC NtQuerySystemInformation;
+ HINSTANCE hNtDll;
+ hNtDll = LoadLibrary(TEXT("ntdll.dll"));
+ NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
+ hNtDll, "NtQuerySystemInformation");
+
+ bufferSize = initialBufferSize;
+ buffer = malloc(bufferSize);
+
+ while (TRUE) {
+ status = NtQuerySystemInformation(SystemProcessInformation, buffer,
+ bufferSize, &bufferSize);
+
+ if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ free(buffer);
+ buffer = malloc(bufferSize);
+ }
+ else {
+ break;
+ }
+ }
+
+ if (status != 0) {
+ PyErr_Format(PyExc_RuntimeError, "NtQuerySystemInformation() failed");
+ return 0;
+ }
+
+ if (bufferSize <= 0x20000) {
+ initialBufferSize = bufferSize;
+ }
+
+ process = PH_FIRST_PROCESS(buffer);
+ do {
+ if (process->UniqueProcessId == (HANDLE)pid) {
+ *retProcess = process;
+ *retBuffer = buffer;
+ return 1;
+ }
+ } while ( (process = PH_NEXT_PROCESS(process)) );
+
+ NoSuchProcess();
+ return 0;
+}
+
+
diff --git a/third_party/psutil/psutil/arch/mswindows/process_info.h b/third_party/psutil/psutil/arch/mswindows/process_info.h
index 9bce0f2..e7a855c 100644
--- a/third_party/psutil/psutil/arch/mswindows/process_info.h
+++ b/third_party/psutil/psutil/arch/mswindows/process_info.h
@@ -1,5 +1,9 @@
/*
- * $Id: process_info.h 779 2010-11-08 20:34:16Z g.rodola $
+ * $Id: process_info.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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 functions related to fetching process information. Used by _psutil_mswindows
* module methods.
@@ -8,8 +12,6 @@
#include <Python.h>
#include <windows.h>
-PyObject * NoSuchProcess(void);
-PyObject * AccessDenied(void);
HANDLE handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess);
HANDLE handle_from_pid(DWORD pid);
PVOID GetPebAddress(HANDLE ProcessHandle);
@@ -17,7 +19,6 @@ HANDLE handle_from_pid(DWORD pid);
BOOL is_running(HANDLE hProcess);
int pid_in_proclist(DWORD pid);
int pid_is_running(DWORD pid);
-int is_system_proc(DWORD pid);
PyObject* get_arg_list(long pid);
PyObject* get_ppid(long pid);
PyObject* get_name(long pid);
diff --git a/third_party/psutil/psutil/arch/mswindows/security.c b/third_party/psutil/psutil/arch/mswindows/security.c
index ee6ff9d..5a07df2f 100644
--- a/third_party/psutil/psutil/arch/mswindows/security.c
+++ b/third_party/psutil/psutil/arch/mswindows/security.c
@@ -1,5 +1,9 @@
/*
- * $Id: security.c 772 2010-11-03 13:51:11Z g.rodola $
+ * $Id: security.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
*
* Security related functions for Windows platform (Set privileges such as
* SeDebug), as well as security helper functions.
@@ -26,7 +30,7 @@ token_from_handle(HANDLE hProcess) {
/*
* http://www.ddj.com/windows/184405986
*
- * there’s a way to determine whether we’re running under the Local System
+ * There's a way to determine whether we're running under the Local System
* account. However (you guessed it), we have to call more Win32 functions to
* determine this. Backing up through the code listing, we need to make another
* call to GetTokenInformation, but instead of passing through the TOKEN_USER
@@ -171,7 +175,7 @@ int SetSeDebug()
){
if (GetLastError() == ERROR_NO_TOKEN){
if (!ImpersonateSelf(SecurityImpersonation)){
- //Log2File("Error setting impersonation [SetSeDebug()]", L_DEBUG);
+ CloseHandle(hToken);
return 0;
}
if (!OpenThreadToken(GetCurrentThread(),
@@ -179,7 +183,8 @@ int SetSeDebug()
FALSE,
&hToken)
){
- //Log2File("Error Opening Thread Token", L_DEBUG);
+ RevertToSelf();
+ CloseHandle(hToken);
return 0;
}
}
@@ -187,10 +192,12 @@ int SetSeDebug()
// enable SeDebugPrivilege (open any process)
if (! SetPrivilege(hToken, SE_DEBUG_NAME, TRUE)){
- //Log2File("Error setting SeDebug Privilege [SetPrivilege()]", L_WARN);
+ RevertToSelf();
+ CloseHandle(hToken);
return 0;
}
+ RevertToSelf();
CloseHandle(hToken);
return 1;
}
diff --git a/third_party/psutil/psutil/arch/mswindows/security.h b/third_party/psutil/psutil/arch/mswindows/security.h
index 5c55643..2cfce29 100644
--- a/third_party/psutil/psutil/arch/mswindows/security.h
+++ b/third_party/psutil/psutil/arch/mswindows/security.h
@@ -1,5 +1,9 @@
/*
- * $Id: security.h 435 2009-09-19 09:32:29Z jloden $
+ * $Id: security.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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.
*
* Security related functions for Windows platform (Set privileges such as
* SeDebug), as well as security helper functions.
diff --git a/third_party/psutil/psutil/arch/osx/process_info.c b/third_party/psutil/psutil/arch/osx/process_info.c
index 53b0409..ae7d407 100644
--- a/third_party/psutil/psutil/arch/osx/process_info.c
+++ b/third_party/psutil/psutil/arch/osx/process_info.c
@@ -1,5 +1,9 @@
/*
- * $Id: process_info.c 772 2010-11-03 13:51:11Z g.rodola $
+ * $Id: process_info.c 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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 functions related to fetching process information. Used by _psutil_osx
* module methods.
@@ -12,11 +16,35 @@
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
+#include <signal.h>
#include <sys/sysctl.h>
#include "process_info.h"
+#include "../../_psutil_common.h"
+
-#define ARGS_ACCESS_DENIED -2
+/*
+ * Return 1 if PID exists in the current process list, else 0.
+ */
+int
+pid_exists(long pid)
+{
+ int kill_ret;
+
+ // save some time if it's an invalid PID
+ if (pid < 0) {
+ return 0;
+ }
+
+ // if kill returns success of permission denied we know it's a valid PID
+ kill_ret = kill(pid , 0);
+ if ( (0 == kill_ret) || (EPERM == errno) ) {
+ return 1;
+ }
+
+ // otherwise return 0 for PID not found
+ return 0;
+}
@@ -94,179 +122,105 @@ get_proc_list(kinfo_proc **procList, size_t *procCount)
}
-/*
- * Modified from psi Python System Information project
- *
- * Get command path, arguments and environment variables.
- *
- * Based on code from ps.
- *
- * Returns:
- * 0 for success
- * 1 for sysctl error, errno exception raised
- * -1 for failure, system or memory exception raised
- * -2 rather ARGS_ACCESS_DENIED, for insufficient privileges
- */
+/* Read the maximum argument size for processes */
int
-getcmdargs(long pid, PyObject **exec_path, PyObject **envlist, PyObject **arglist)
+get_argmax()
{
- int nargs, mib[3];
- size_t size, argmax;
- char *curr_arg, *start_args, *iter_args, *end_args;
- char *procargs = NULL;
- char *err = NULL;
- PyObject *arg;
-
- *arglist = Py_BuildValue("[]"); /* empty list */
- if (*arglist == NULL) {
- err = "getcmdargs(): arglist exception";
- goto ERROR_RETURN;
+ int argmax;
+ int mib[] = { CTL_KERN, KERN_ARGMAX };
+ size_t size = sizeof(argmax);
+
+ if (sysctl(mib, 2, &argmax, &size, NULL, 0) == 0) {
+ return argmax;
}
+ return 0;
+}
- /* Get the maximum process arguments size. */
- mib[0] = CTL_KERN;
- mib[1] = KERN_ARGMAX;
- size = sizeof(argmax);
- if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
- PyErr_SetFromErrno(NULL);
- return errno;
+/* return process args as a python list */
+PyObject*
+get_arg_list(long pid)
+{
+ int mib[3];
+ int nargs;
+ int len;
+ char *procargs;
+ char *arg_ptr;
+ char *arg_end;
+ char *curr_arg;
+ size_t argmax;
+ PyObject *arg = NULL;
+ PyObject *arglist = NULL;
+
+ //special case for PID 0 (kernel_task) where cmdline cannot be fetched
+ if (pid == 0) {
+ return Py_BuildValue("[]");
}
- /* Allocate space for the arguments. */
+ /* read argmax and allocate memory for argument space. */
+ argmax = get_argmax();
+ if (! argmax) { return PyErr_SetFromErrno(PyExc_OSError); }
+
procargs = (char *)malloc(argmax);
- if (procargs == NULL) {
- PyErr_SetString(PyExc_MemoryError,
- "getcmdargs(): insufficient memory for procargs");
- return ENOMEM;
+ if (NULL == procargs) {
+ return PyErr_SetFromErrno(PyExc_OSError);
}
- /*
- * Make a sysctl() call to get the raw argument space of the process.
- */
+ /* read argument space */
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
- mib[2] = (int)pid;
-
- size = argmax;
- if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
- if (EINVAL == errno) { // invalid == access denied for some reason
- free(procargs);
- return ARGS_ACCESS_DENIED; /* Insufficient privileges */
+ mib[2] = pid;
+ if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
+ if (EINVAL == errno) { // invalid == access denied OR nonexistent PID
+ if ( pid_exists(pid) ) {
+ AccessDenied();
+ } else {
+ NoSuchProcess();
+ }
}
-
- PyErr_SetFromErrno(PyExc_OSError);
free(procargs);
- return errno;
+ return NULL;
}
- // copy the number of argument to nargs
+ arg_end = &procargs[argmax];
+ /* copy the number of arguments to nargs */
memcpy(&nargs, procargs, sizeof(nargs));
- iter_args = procargs + sizeof(nargs);
- end_args = &procargs[size]; // end of the argument space
- if (iter_args >= end_args) {
- err = "getcmdargs(): argument length mismatch";
- goto ERROR_RETURN;
+
+ arg_ptr = procargs + sizeof(nargs);
+ len = strlen(arg_ptr);
+ arg_ptr += len + 1;
+
+ if (arg_ptr == arg_end) {
+ free(procargs);
+ return Py_BuildValue("[]");
}
- // Save the path
- if (NULL != exec_path) {
- *exec_path = Py_BuildValue("s", iter_args);
- if (*exec_path == NULL) {
- err = "getcmdargs(): exec_path exception";
- goto ERROR_RETURN;
+ // skip ahead to the first argument
+ for (; arg_ptr < arg_end; arg_ptr++) {
+ if (*arg_ptr != '\0') {
+ break;
}
}
- //TODO: save the environment variables to envlist as well
- // Skip over the exec_path and '\0' characters.
- while (iter_args < end_args && *iter_args != '\0') { iter_args++; }
- while (iter_args < end_args && *iter_args == '\0') { iter_args++; }
-
- /* Iterate through the '\0'-terminated strings and add each string
- * to the Python List arglist as a Python string.
- * Stop when nargs strings have been extracted. That should be all
- * the arguments. The rest of the strings will be environment
- * strings for the command.
- */
- curr_arg = iter_args;
- start_args = iter_args; //reset start position to beginning of cmdline
- while (iter_args < end_args && nargs > 0) {
- if (*iter_args++ == '\0') {
- /* Fetch next argument */
+ /* iterate through arguments */
+ curr_arg = arg_ptr;
+ arglist = Py_BuildValue("[]");
+ while (arg_ptr < arg_end && nargs > 0) {
+ if (*arg_ptr++ == '\0') {
arg = Py_BuildValue("s", curr_arg);
- if (arg == NULL) {
- err = "getcmdargs(): exception building argument string";
- goto ERROR_RETURN;
+ if (NULL == arg) {
+ return NULL;
}
- PyList_Append(*arglist, arg);
+ PyList_Append(arglist, arg);
Py_DECREF(arg);
-
- curr_arg = iter_args;
+ // iterate to next arg and decrement # of args
+ curr_arg = arg_ptr;
nargs--;
}
}
- /*
- * curr_arg position should be further than the start of the argspace
- * and number of arguments should be 0 after iterating above. Otherwise
- * we had an empty argument space or a missing terminating \0 etc.
- */
- if (curr_arg == start_args || nargs > 0) {
- err = "getcmdargs(): argument parsing failed";
- goto ERROR_RETURN;
- }
-
-ERROR_RETURN:
- // Clean up.
- if (NULL != procargs) {
- free(procargs);
- }
- if (NULL != err) {
- PyErr_SetString(PyExc_SystemError, err);
- return -1;
- }
- return 0;
-}
-
-
-/* return process args as a python list */
-PyObject*
-get_arg_list(long pid)
-{
- int r;
- PyObject *argList;
- PyObject *env = NULL;
- PyObject *args = NULL;
- PyObject *exec_path = NULL;
-
- //special case for PID 0 (kernel_task) where cmdline cannot be fetched
- if (pid == 0) {
- return Py_BuildValue("[]");
- }
-
- /* Fetch the command-line arguments and environment variables */
- //printf("pid: %ld\n", pid);
- if (pid < 0 || pid > (long)INT_MAX) {
- return Py_BuildValue("");
- }
-
- r = getcmdargs(pid, &exec_path, &env, &args);
- if (r == 0) {
- //PySequence_Tuple(args);
- argList = PySequence_List(args);
- }
- else if (r == ARGS_ACCESS_DENIED) { //-2
- argList = Py_BuildValue("[]");
- }
- else {
- argList = Py_BuildValue("");
- }
-
- Py_XDECREF(args);
- Py_XDECREF(exec_path);
- Py_XDECREF(env);
- return argList;
+ free(procargs);
+ return arglist;
}
@@ -293,8 +247,7 @@ get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
* sysctl succeeds but len is zero, happens when process has gone away
*/
if (len == 0) {
- errno = ESRCH;
- PyErr_SetFromErrno(PyExc_OSError);
+ NoSuchProcess();
return -1;
}
return 0;
diff --git a/third_party/psutil/psutil/arch/osx/process_info.h b/third_party/psutil/psutil/arch/osx/process_info.h
index db93f06..5939284 100644
--- a/third_party/psutil/psutil/arch/osx/process_info.h
+++ b/third_party/psutil/psutil/arch/osx/process_info.h
@@ -1,5 +1,9 @@
/*
- * $Id: process_info.h 760 2010-10-30 17:41:07Z g.rodola $
+ * $Id: process_info.h 1142 2011-10-05 18:45:49Z g.rodola $
+ *
+ * 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 functions related to fetching process information. Used by _psutil_osx
* module methods.
@@ -11,6 +15,7 @@
typedef struct kinfo_proc kinfo_proc;
int get_proc_list(kinfo_proc **procList, size_t *procCount);
-int getcmdargs(long pid, PyObject **exec_path, PyObject **envlist, PyObject **arglist);
-PyObject* get_arg_list(long pid);
int get_kinfo_proc(pid_t pid, struct kinfo_proc *kp);
+int get_argmax(void);
+int pid_exists(long pid);
+PyObject* get_arg_list(long pid);
diff --git a/third_party/psutil/psutil/compat.py b/third_party/psutil/psutil/compat.py
deleted file mode 100644
index 9e05dfc..0000000
--- a/third_party/psutil/psutil/compat.py
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env python
-#
-# $Id: compat.py 712 2010-10-20 15:25:57Z g.rodola $
-#
-
-"""Module which provides compatibility with older Python versions."""
-
-from operator import itemgetter as _itemgetter
-from keyword import iskeyword as _iskeyword
-import sys as _sys
-
-
-def namedtuple(typename, field_names, verbose=False, rename=False):
- """A collections.namedtuple implementation written in Python
- to support Python versions < 2.6.
-
- Taken from: http://code.activestate.com/recipes/500261/
- """
- # Parse and validate the field names. Validation serves two
- # purposes, generating informative error messages and preventing
- # template injection attacks.
- if isinstance(field_names, basestring):
- # names separated by whitespace and/or commas
- field_names = field_names.replace(',', ' ').split()
- field_names = tuple(map(str, field_names))
- if rename:
- names = list(field_names)
- seen = set()
- for i, name in enumerate(names):
- if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
- or not name or name[0].isdigit() or name.startswith('_')
- or name in seen):
- names[i] = '_%d' % i
- seen.add(name)
- field_names = tuple(names)
- for name in (typename,) + field_names:
- if not min(c.isalnum() or c=='_' for c in name):
- raise ValueError('Type names and field names can only contain ' \
- 'alphanumeric characters and underscores: %r'
- % name)
- if _iskeyword(name):
- raise ValueError('Type names and field names cannot be a keyword: %r' \
- % name)
- if name[0].isdigit():
- raise ValueError('Type names and field names cannot start with a ' \
- 'number: %r' % name)
- seen_names = set()
- for name in field_names:
- if name.startswith('_') and not rename:
- raise ValueError('Field names cannot start with an underscore: %r'
- % name)
- if name in seen_names:
- raise ValueError('Encountered duplicate field name: %r' % name)
- seen_names.add(name)
-
- # Create and fill-in the class template
- numfields = len(field_names)
- # tuple repr without parens or quotes
- argtxt = repr(field_names).replace("'", "")[1:-1]
- reprtxt = ', '.join('%s=%%r' % name for name in field_names)
- template = '''class %(typename)s(tuple):
- '%(typename)s(%(argtxt)s)' \n
- __slots__ = () \n
- _fields = %(field_names)r \n
- def __new__(_cls, %(argtxt)s):
- return _tuple.__new__(_cls, (%(argtxt)s)) \n
- @classmethod
- def _make(cls, iterable, new=tuple.__new__, len=len):
- 'Make a new %(typename)s object from a sequence or iterable'
- result = new(cls, iterable)
- if len(result) != %(numfields)d:
- raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
- return result \n
- def __repr__(self):
- return '%(typename)s(%(reprtxt)s)' %% self \n
- def _asdict(self):
- 'Return a new dict which maps field names to their values'
- return dict(zip(self._fields, self)) \n
- def _replace(_self, **kwds):
- 'Return a new %(typename)s object replacing specified fields with new values'
- result = _self._make(map(kwds.pop, %(field_names)r, _self))
- if kwds:
- raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
- return result \n
- def __getnewargs__(self):
- return tuple(self) \n\n''' % locals()
- for i, name in enumerate(field_names):
- template += ' %s = _property(_itemgetter(%d))\n' % (name, i)
- if verbose:
- print template
-
- # Execute the template string in a temporary namespace
- namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
- _property=property, _tuple=tuple)
- try:
- exec template in namespace
- except SyntaxError, e:
- raise SyntaxError(e.message + ':\n' + template)
- result = namespace[typename]
-
- # For pickling to work, the __module__ variable needs to be set
- # to the frame where the named tuple is created. Bypass this
- # step in enviroments where sys._getframe is not defined (Jython
- # for example) or sys._getframe is not defined for arguments
- # greater than 0 (IronPython).
- try:
- result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
- except (AttributeError, ValueError):
- pass
-
- return result
diff --git a/third_party/psutil/psutil/error.py b/third_party/psutil/psutil/error.py
index 214a241..0298cb9 100644
--- a/third_party/psutil/psutil/error.py
+++ b/third_party/psutil/psutil/error.py
@@ -1,9 +1,12 @@
#!/usr/bin/env python
#
-# $Id: error.py 744 2010-10-27 22:42:42Z jloden $
+# $Id: error.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
-"""psutil exception classes"""
+"""psutil exception classes; do not import this directly"""
class Error(Exception):
@@ -49,3 +52,22 @@ class AccessDenied(Error):
def __str__(self):
return self.msg
+
+class TimeoutExpired(Error):
+ """Raised on Process.wait(timeout) if timeout expires and process
+ is still alive.
+ """
+
+ def __init__(self, pid=None, name=None):
+ 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
+ else:
+ self.msg = ""
+
+ def __str__(self):
+ return self.msg
+
diff --git a/third_party/psutil/setup.py b/third_party/psutil/setup.py
index fb944bf..d7383cb 100644
--- a/third_party/psutil/setup.py
+++ b/third_party/psutil/setup.py
@@ -1,22 +1,34 @@
#!/usr/bin/env python
#
-# $Id: setup.py 748 2010-10-29 12:51:58Z g.rodola $
+# $Id: setup.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
import sys
import os
-import shutil
-from distutils.core import setup, Extension
+try:
+ from setuptools import setup, Extension
+except ImportError:
+ from distutils.core import setup, Extension
+
+__ver__ = "0.3.1"
# Hack for Python 3 to tell distutils to run 2to3 against the files
# copied in the build directory before installing.
-# Reference: http://osdir.com/ml/python.python-3000.cvs/2008-03/msg00127.html
+# Reference: http://docs.python.org/dev/howto/pyporting.html#during-installation
try:
from distutils.command.build_py import build_py_2to3 as build_py
except ImportError:
from distutils.command.build_py import build_py
+if os.name == 'posix':
+ posix_extension = Extension('_psutil_posix',
+ sources = ['psutil/_psutil_posix.c'])
+
+
# Windows
if sys.platform.lower().startswith("win"):
@@ -24,31 +36,41 @@ if sys.platform.lower().startswith("win"):
maj,min = sys.getwindowsversion()[0:2]
return '0x0%s' % ((maj * 100) + min)
- extensions = Extension('_psutil_mswindows',
- sources=['psutil/_psutil_mswindows.c',
- 'psutil/arch/mswindows/process_info.c',
- 'psutil/arch/mswindows/process_handles.c',
- 'psutil/arch/mswindows/security.c'],
- define_macros=[('_WIN32_WINNT', get_winver()),
- ('_AVAIL_WINVER_', get_winver())],
- libraries=["psapi", "kernel32", "advapi32", "shell32",
- "netapi32"]
- )
+ extensions = [Extension('_psutil_mswindows',
+ sources=['psutil/_psutil_mswindows.c',
+ 'psutil/_psutil_common.c',
+ 'psutil/arch/mswindows/process_info.c',
+ 'psutil/arch/mswindows/process_handles.c',
+ 'psutil/arch/mswindows/security.c'],
+ define_macros=[('_WIN32_WINNT', get_winver()),
+ ('_AVAIL_WINVER_', get_winver())],
+ libraries=["psapi", "kernel32", "advapi32", "shell32",
+ "netapi32"]
+ )]
# OS X
elif sys.platform.lower().startswith("darwin"):
- extensions = Extension('_psutil_osx',
- sources = ['psutil/_psutil_osx.c',
- 'psutil/arch/osx/process_info.c']
- )
+ extensions = [Extension('_psutil_osx',
+ sources = ['psutil/_psutil_osx.c',
+ 'psutil/_psutil_common.c',
+ 'psutil/arch/osx/process_info.c'],
+ extra_link_args=['-framework', 'CoreFoundation', '-framework', 'IOKit']
+ ),
+ posix_extension]
# FreeBSD
elif sys.platform.lower().startswith("freebsd"):
- extensions = Extension('_psutil_bsd',
- sources = ['psutil/_psutil_bsd.c',
- 'psutil/arch/bsd/process_info.c']
- )
-# Others
+ extensions = [Extension('_psutil_bsd',
+ sources = ['psutil/_psutil_bsd.c',
+ 'psutil/_psutil_common.c',
+ 'psutil/arch/bsd/process_info.c']
+ ),
+ posix_extension]
+# Linux
elif sys.platform.lower().startswith("linux"):
- extensions = None
+ extensions = [Extension('_psutil_linux',
+ sources=['psutil/_psutil_linux.c'],
+ ),
+ posix_extension]
+
else:
raise NotImplementedError('platform %s is not supported' % sys.platform)
@@ -56,14 +78,17 @@ else:
def main():
setup_args = dict(
name='psutil',
- version="0.2.0",
+ version=__ver__,
+ download_url="http://psutil.googlecode.com/files/psutil-%s.tar.gz" % __ver__,
description='A process utilities module for Python',
- long_description="""
-psutil is a module providing convenience functions for managing processes in a
-portable way by using Python.""",
- keywords=['psutil', 'ps', 'top', 'process', 'utility'],
- author='Giampaolo Rodola, Dave Daeschler, Jay Loden',
- author_email='psutil-dev@googlegroups.com',
+ long_description="""\
+psutil is a module providing convenience functions for monitoring
+system and processes in a portable way by using Python.""",
+ keywords=['ps', 'top', 'kill', 'free', 'lsof', 'netstat', 'nice',
+ 'tty', 'ionice', 'uptime', 'taskmgr', 'process', 'df',
+ 'monitoring'],
+ author='Giampaolo Rodola, Jay Loden',
+ author_email='psutil@googlegroups.com',
url='http://code.google.com/p/psutil/',
platforms='Platform Independent',
license='License :: OSI Approved :: BSD License',
@@ -100,7 +125,7 @@ portable way by using Python.""",
],
)
if extensions is not None:
- setup_args["ext_modules"] = [extensions]
+ setup_args["ext_modules"] = extensions
setup(**setup_args)
diff --git a/third_party/psutil/test/_bsd.py b/third_party/psutil/test/_bsd.py
index f2df15d..0296b05 100644
--- a/third_party/psutil/test/_bsd.py
+++ b/third_party/psutil/test/_bsd.py
@@ -1,7 +1,12 @@
#!/usr/bin/env python
#
-# $Id: _bsd.py 664 2010-10-09 16:14:34Z g.rodola $
+# $Id: _bsd.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
+
+"""BSD specific tests. These are implicitly run by test_psutil.py."""
import unittest
import subprocess
@@ -11,18 +16,14 @@ import sys
import psutil
-from test_psutil import reap_children, get_test_subprocess
-from _posix import ps
-
+from test_psutil import reap_children, get_test_subprocess, sh
def sysctl(cmdline):
"""Expects a sysctl command with an argument and parse the result
returning only the value of interest.
"""
- p = subprocess.Popen(cmdline, shell=1, stdout=subprocess.PIPE)
- result = p.communicate()[0].strip().split()[1]
- if sys.version_info >= (3,):
- result = str(result, sys.stdout.encoding)
+ result = sh("sysctl " + cmdline)
+ result = result[result.find(": ") + 2:]
try:
return int(result)
except ValueError:
@@ -54,6 +55,13 @@ class BSDSpecificTestCase(unittest.TestCase):
sysctl_hwphymem = sysctl('sysctl hw.physmem')
self.assertEqual(sysctl_hwphymem, psutil.TOTAL_PHYMEM)
+ def test_BOOT_TIME(self):
+ s = sysctl('sysctl kern.boottime')
+ s = s[s.find(" sec = ") + 7:]
+ s = s[:s.find(',')]
+ btime = int(s)
+ self.assertEqual(btime, psutil.BOOT_TIME)
+
def test_avail_phymem(self):
# This test is not particularly accurate and may fail if the OS is
# consuming memory for other applications.
@@ -65,7 +73,7 @@ class BSDSpecificTestCase(unittest.TestCase):
))
_pagesize = sysctl("sysctl hw.pagesize")
sysctl_avail_phymem = _sum * _pagesize
- psutil_avail_phymem = psutil.avail_phymem()
+ psutil_avail_phymem = psutil.phymem_usage().free
difference = abs(psutil_avail_phymem - sysctl_avail_phymem)
# On my system both sysctl and psutil report the same values.
# Let's use a tollerance of 0.5 MB and consider the test as failed
@@ -84,7 +92,7 @@ class BSDSpecificTestCase(unittest.TestCase):
if sys.version_info >= (3,):
result = str(result, sys.stdout.encoding)
sysctl_total_virtmem, _ = parse_sysctl_vmtotal(result)
- psutil_total_virtmem = psutil.total_virtmem()
+ psutil_total_virtmem = psutil.virtmem_usage().total
difference = abs(sysctl_total_virtmem - psutil_total_virtmem)
# On my system I get a difference of 4657152 bytes, probably because
@@ -93,8 +101,7 @@ class BSDSpecificTestCase(unittest.TestCase):
# the test as failed if we go over it.
if difference > (10 * 2**20):
self.fail("sysctl=%s; psutil=%s; difference=%s;" %(
- sysctl_total_virtmem, psutil_total_virtmem, difference)
- )
+ sysctl_total_virtmem, psutil_total_virtmem, difference))
def test_avail_virtmem(self):
# This test is not particularly accurate and may fail if the OS is
@@ -106,12 +113,11 @@ class BSDSpecificTestCase(unittest.TestCase):
if sys.version_info >= (3,):
result = str(result, sys.stdout.encoding)
_, sysctl_avail_virtmem = parse_sysctl_vmtotal(result)
- psutil_avail_virtmem = psutil.avail_virtmem()
+ psutil_avail_virtmem = psutil.virtmem_usage().free
difference = abs(sysctl_avail_virtmem - psutil_avail_virtmem)
# let's assume the test is failed if difference is > 0.5 MB
if difference > (0.5 * 2**20):
- self.fail("sysctl=%s; psutil=%s; difference=%s;" %(
- sysctl_avail_virtmem, psutil_avail_virtmem, difference))
+ self.fail(difference)
def test_process_create_time(self):
cmdline = "ps -o lstart -p %s" %self.pid
@@ -125,12 +131,35 @@ class BSDSpecificTestCase(unittest.TestCase):
time.localtime(start_psutil))
self.assertEqual(start_ps, start_psutil)
+ def test_disks(self):
+ # test psutil.disk_usage() and psutil.disk_partitions()
+ # against "df -a"
+ def df(path):
+ out = sh('df -k "%s"' % path).strip()
+ lines = out.split('\n')
+ lines.pop(0)
+ line = lines.pop(0)
+ dev, total, used, free = line.split()[:4]
+ if dev == 'none':
+ dev = ''
+ total = int(total) * 1024
+ used = int(used) * 1024
+ free = int(free) * 1024
+ return dev, total, used, free
+
+ for part in psutil.disk_partitions(all=False):
+ usage = psutil.disk_usage(part.mountpoint)
+ dev, total, used, free = df(part.mountpoint)
+ self.assertEqual(part.device, dev)
+ self.assertEqual(usage.total, total)
+ # 10 MB tollerance
+ if abs(usage.free - free) > 10 * 1024 * 1024:
+ self.fail("psutil=%s, df=%s" % usage.free, free)
+ if abs(usage.used - used) > 10 * 1024 * 1024:
+ self.fail("psutil=%s, df=%s" % usage.used, used)
+
if __name__ == '__main__':
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase))
unittest.TextTestRunner(verbosity=2).run(test_suite)
-
-
-
-
diff --git a/third_party/psutil/test/_linux.py b/third_party/psutil/test/_linux.py
index 187c058..a20d8dc 100644
--- a/third_party/psutil/test/_linux.py
+++ b/third_party/psutil/test/_linux.py
@@ -1,12 +1,18 @@
#!/usr/bin/env python
#
-# $Id: _linux.py 707 2010-10-19 18:16:08Z g.rodola $
+# $Id: _linux.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
+
+"""Linux specific tests. These are implicitly run by test_psutil.py."""
import unittest
import subprocess
import sys
+from test_psutil import sh
import psutil
@@ -34,12 +40,33 @@ class LinuxSpecificTestCase(unittest.TestCase):
psutil_cmem = psutil.phymem_buffers() / 1024
self.assertEqual(free_cmem, psutil_cmem)
+ def test_disks(self):
+ # test psutil.disk_usage() and psutil.disk_partitions()
+ # against "df -a"
+ def df(path):
+ out = sh('df -P -B 1 "%s"' % path).strip()
+ lines = out.split('\n')
+ lines.pop(0)
+ line = lines.pop(0)
+ dev, total, used, free = line.split()[:4]
+ if dev == 'none':
+ dev = ''
+ total, used, free = int(total), int(used), int(free)
+ return dev, total, used, free
+
+ for part in psutil.disk_partitions(all=False):
+ usage = psutil.disk_usage(part.mountpoint)
+ dev, total, used, free = df(part.mountpoint)
+ self.assertEqual(part.device, dev)
+ self.assertEqual(usage.total, total)
+ # 10 MB tollerance
+ if abs(usage.free - free) > 10 * 1024 * 1024:
+ self.fail("psutil=%s, df=%s" % usage.free, free)
+ if abs(usage.used - used) > 10 * 1024 * 1024:
+ self.fail("psutil=%s, df=%s" % usage.used, used)
+
if __name__ == '__main__':
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(LinuxSpecificTestCase))
unittest.TextTestRunner(verbosity=2).run(test_suite)
-
-
-
-
diff --git a/third_party/psutil/test/_osx.py b/third_party/psutil/test/_osx.py
index aaf9215..fdee67b 100644
--- a/third_party/psutil/test/_osx.py
+++ b/third_party/psutil/test/_osx.py
@@ -1,17 +1,21 @@
#!/usr/bin/env python
#
-# $Id: _osx.py 664 2010-10-09 16:14:34Z g.rodola $
+# $Id: _osx.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
+
+"""OSX specific tests. These are implicitly run by test_psutil.py."""
import unittest
import subprocess
import time
-import re
import sys
import psutil
-from test_psutil import reap_children, get_test_subprocess
+from test_psutil import reap_children, get_test_subprocess, sh
#from _posix import ps
@@ -38,7 +42,7 @@ class OSXSpecificTestCase(unittest.TestCase):
reap_children()
def test_TOTAL_PHYMEM(self):
- sysctl_hwphymem = sysctl('sysctl hw.physmem')
+ sysctl_hwphymem = sysctl('sysctl hw.memsize')
self.assertEqual(sysctl_hwphymem, psutil.TOTAL_PHYMEM)
def test_process_create_time(self):
@@ -53,12 +57,35 @@ class OSXSpecificTestCase(unittest.TestCase):
time.localtime(start_psutil))
self.assertEqual(start_ps, start_psutil)
+ def test_disks(self):
+ # test psutil.disk_usage() and psutil.disk_partitions()
+ # against "df -a"
+ def df(path):
+ out = sh('df -k "%s"' % path).strip()
+ lines = out.split('\n')
+ lines.pop(0)
+ line = lines.pop(0)
+ dev, total, used, free = line.split()[:4]
+ if dev == 'none':
+ dev = ''
+ total = int(total) * 1024
+ used = int(used) * 1024
+ free = int(free) * 1024
+ return dev, total, used, free
+
+ for part in psutil.disk_partitions(all=False):
+ usage = psutil.disk_usage(part.mountpoint)
+ dev, total, used, free = df(part.mountpoint)
+ self.assertEqual(part.device, dev)
+ self.assertEqual(usage.total, total)
+ # 10 MB tollerance
+ if abs(usage.free - free) > 10 * 1024 * 1024:
+ self.fail("psutil=%s, df=%s" % usage.free, free)
+ if abs(usage.used - used) > 10 * 1024 * 1024:
+ self.fail("psutil=%s, df=%s" % usage.used, used)
+
if __name__ == '__main__':
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(OSXSpecificTestCase))
unittest.TextTestRunner(verbosity=2).run(test_suite)
-
-
-
-
diff --git a/third_party/psutil/test/_posix.py b/third_party/psutil/test/_posix.py
index 1879dc7..ad0db64 100644..100755
--- a/third_party/psutil/test/_posix.py
+++ b/third_party/psutil/test/_posix.py
@@ -1,7 +1,12 @@
#!/usr/bin/env python
#
-# $Id: _posix.py 744 2010-10-27 22:42:42Z jloden $
+# $Id: _posix.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
+
+"""POSIX specific tests. These are implicitly run by test_psutil.py."""
import unittest
import subprocess
@@ -11,7 +16,8 @@ import os
import psutil
-from test_psutil import kill, get_test_subprocess, PYTHON, LINUX, OSX
+from test_psutil import (get_test_subprocess, reap_children, PYTHON, LINUX, OSX,
+ ignore_access_denied, sh)
def ps(cmd):
@@ -41,7 +47,7 @@ class PosixSpecificTestCase(unittest.TestCase):
self.pid = get_test_subprocess([PYTHON, "-E", "-O"]).pid
def tearDown(self):
- kill(self.pid)
+ reap_children()
def test_process_parent_pid(self):
ppid_ps = ps("ps --no-headers -o ppid -p %s" %self.pid)
@@ -50,12 +56,12 @@ class PosixSpecificTestCase(unittest.TestCase):
def test_process_uid(self):
uid_ps = ps("ps --no-headers -o uid -p %s" %self.pid)
- uid_psutil = psutil.Process(self.pid).uid
+ uid_psutil = psutil.Process(self.pid).uids.real
self.assertEqual(uid_ps, uid_psutil)
def test_process_gid(self):
gid_ps = ps("ps --no-headers -o rgid -p %s" %self.pid)
- gid_psutil = psutil.Process(self.pid).gid
+ gid_psutil = psutil.Process(self.pid).gids.real
self.assertEqual(gid_ps, gid_psutil)
def test_process_username(self):
@@ -63,6 +69,7 @@ class PosixSpecificTestCase(unittest.TestCase):
username_psutil = psutil.Process(self.pid).username
self.assertEqual(username_ps, username_psutil)
+ @ignore_access_denied
def test_process_rss_memory(self):
# give python interpreter some time to properly initialize
# so that the results are the same
@@ -71,6 +78,7 @@ class PosixSpecificTestCase(unittest.TestCase):
rss_psutil = psutil.Process(self.pid).get_memory_info()[0] / 1024
self.assertEqual(rss_ps, rss_psutil)
+ @ignore_access_denied
def test_process_vsz_memory(self):
# give python interpreter some time to properly initialize
# so that the results are the same
@@ -83,18 +91,24 @@ class PosixSpecificTestCase(unittest.TestCase):
# use command + arg since "comm" keyword not supported on all platforms
name_ps = ps("ps --no-headers -o command -p %s" %self.pid).split(' ')[0]
# remove path if there is any, from the command
- name_ps = os.path.basename(name_ps)
- name_psutil = psutil.Process(self.pid).name
- if OSX:
- self.assertEqual(name_psutil, "Python")
- else:
- self.assertEqual(name_ps, name_psutil)
-
+ name_ps = os.path.basename(name_ps).lower()
+ name_psutil = psutil.Process(self.pid).name.lower()
+ self.assertEqual(name_ps, name_psutil)
def test_process_exe(self):
ps_pathname = ps("ps --no-headers -o command -p %s" %self.pid).split(' ')[0]
psutil_pathname = psutil.Process(self.pid).exe
- self.assertEqual(ps_pathname, psutil_pathname)
+ try:
+ self.assertEqual(ps_pathname, psutil_pathname)
+ except AssertionError:
+ # certain platforms such as BSD are more accurate returning:
+ # "/usr/local/bin/python2.7"
+ # ...instead of:
+ # "/usr/local/bin/python"
+ # We do not want to consider this difference in accuracy
+ # an error.
+ adjusted_ps_pathname = ps_pathname[:len(ps_pathname)]
+ self.assertEqual(ps_pathname, adjusted_ps_pathname)
def test_process_cmdline(self):
ps_cmdline = ps("ps --no-headers -o command -p %s" %self.pid)
@@ -116,18 +130,13 @@ class PosixSpecificTestCase(unittest.TestCase):
pids_ps.append(int(pid.strip()))
# remove ps subprocess pid which is supposed to be dead in meantime
pids_ps.remove(p.pid)
- # not all systems include pid 0 in their list but psutil does so
- # we force it
- if 0 not in pids_ps:
- pids_ps.append(0)
-
pids_psutil = psutil.get_pid_list()
pids_ps.sort()
pids_psutil.sort()
if pids_ps != pids_psutil:
- difference = filter(lambda x:x not in pids_ps, pids_psutil) + \
- filter(lambda x:x not in pids_psutil, pids_ps)
+ 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))
diff --git a/third_party/psutil/test/_windows.py b/third_party/psutil/test/_windows.py
index 95a45b6..ef5ff24 100644
--- a/third_party/psutil/test/_windows.py
+++ b/third_party/psutil/test/_windows.py
@@ -1,23 +1,29 @@
#!/usr/bin/env python
#
-# $Id: _windows.py 798 2010-11-12 20:52:57Z g.rodola $
+# $Id: _windows.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
+"""Windows specific tests. These are implicitly run by test_psutil.py."""
import os
import unittest
import platform
-import subprocess
import signal
import time
import warnings
import atexit
+import sys
import psutil
+import _psutil_mswindows
from test_psutil import reap_children, get_test_subprocess, wait_for_pid
try:
import wmi
-except ImportError, err:
+except ImportError:
+ err = sys.exc_info()[1]
atexit.register(warnings.warn, "Couldn't run wmi tests: %s" % str(err),
RuntimeWarning)
wmi = None
@@ -74,7 +80,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
p = psutil.Process(self.pid)
self.assertEqual(p.name, w.Caption)
- def test_process_path(self):
+ def test_process_exe(self):
w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
p = psutil.Process(self.pid)
self.assertEqual(p.exe, w.ExecutablePath)
@@ -140,6 +146,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
wmic_create = str(w.CreationDate.split('.')[0])
psutil_create = time.strftime("%Y%m%d%H%M%S",
time.localtime(p.create_time))
+ # XXX - ? no actual test here
def test_get_pids(self):
# Note: this test might fail if the OS is starting/killing
@@ -154,6 +161,26 @@ class WindowsSpecificTestCase(unittest.TestCase):
filter(lambda x:x not in psutil_pids, wmi_pids)
self.fail("difference: " + str(difference))
+ def test_disks(self):
+ ps_parts = psutil.disk_partitions(all=True)
+ wmi_parts = wmi.WMI().Win32_LogicalDisk()
+ for ps_part in ps_parts:
+ for wmi_part in wmi_parts:
+ if ps_part.device.replace('\\', '') == wmi_part.DeviceID:
+ if not ps_part.mountpoint:
+ # this is usually a CD-ROM with no disk inserted
+ break
+ usage = psutil.disk_usage(ps_part.mountpoint)
+ self.assertEqual(usage.total, int(wmi_part.Size))
+ wmi_free = int(wmi_part.FreeSpace)
+ self.assertEqual(usage.free, wmi_free)
+ # 10 MB tollerance
+ if abs(usage.free - wmi_free) > 10 * 1024 * 1024:
+ self.fail("psutil=%s, wmi=%s" % usage.free, wmi_free)
+ break
+ else:
+ self.fail("can't find partition %r", ps_part)
+
if __name__ == '__main__':
test_suite = unittest.TestSuite()
diff --git a/third_party/psutil/test/test_memory_leaks.py b/third_party/psutil/test/test_memory_leaks.py
index d5591a3..b6a3a4e 100644
--- a/third_party/psutil/test/test_memory_leaks.py
+++ b/third_party/psutil/test/test_memory_leaks.py
@@ -1,67 +1,95 @@
#!/usr/bin/env python
#
-# $Id: test_memory_leaks.py 777 2010-11-08 18:29:13Z g.rodola $
+# $Id: test_memory_leaks.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
"""
-Note: this is targeted for python 2.x.
-To run it under python 3.x you need to use 2to3 tool first:
-
-$ 2to3 -w test/test_memory_leaks.py
+A test script which attempts to detect memory leaks by calling C
+functions many times and compare process memory usage before and
+after the calls. It might produce false positives.
"""
-
import os
import gc
-import sys
import unittest
+import time
import psutil
from test_psutil import reap_children, skipUnless, skipIf, \
- POSIX, LINUX, WINDOWS, OSX, BSD
+ POSIX, LINUX, WINDOWS, OSX, BSD, PY3
LOOPS = 1000
TOLERANCE = 4096
+if PY3:
+ xrange = range
-class TestProcessObjectLeaks(unittest.TestCase):
- """Test leaks of Process class methods and properties"""
- def setUp(self):
- gc.collect()
+class Base(unittest.TestCase):
- def tearDown(self):
- reap_children()
-
- def execute(self, method, *args, **kwarks):
+ def execute(self, function, *args, **kwargs):
# step 1
- p = psutil.Process(os.getpid())
for x in xrange(LOOPS):
- obj = getattr(p, method)
- if callable(obj):
- retvalue = obj(*args, **kwarks)
- else:
- retvalue = obj # property
- del x, p, obj, retvalue
+ self.call(function, *args, **kwargs)
+ del x
gc.collect()
- rss1 = psutil.Process(os.getpid()).get_memory_info()[0]
+ rss1 = self.get_mem()
# step 2
- p = psutil.Process(os.getpid())
for x in xrange(LOOPS):
- obj = getattr(p, method)
- if callable(obj):
- retvalue = obj(*args, **kwarks)
- else:
- retvalue = obj # property
- del x, p, obj, retvalue
+ self.call(function, *args, **kwargs)
+ del x
gc.collect()
- rss2 = psutil.Process(os.getpid()).get_memory_info()[0]
+ rss2 = self.get_mem()
# comparison
difference = rss2 - rss1
if difference > TOLERANCE:
- self.fail("rss1=%s, rss2=%s, difference=%s" %(rss1, rss2, difference))
+ # This doesn't necessarily mean we have a leak yet.
+ # At this point we assume that after having called the
+ # function so many times the memory usage is stabilized
+ # and if there are no leaks it should not increase any
+ # more.
+ # Let's keep calling fun for 3 more seconds and fail if
+ # we notice any difference.
+ stop_at = time.time() + 3
+ while 1:
+ self.call(function, *args, **kwargs)
+ if time.time() >= stop_at:
+ break
+ del stop_at
+ gc.collect()
+ rss3 = self.get_mem()
+ difference = rss3 - rss2
+ if rss3 > rss2:
+ self.fail("rss2=%s, rss3=%s, difference=%s" \
+ % (rss2, rss3, difference))
+
+ @staticmethod
+ def get_mem():
+ return psutil.Process(os.getpid()).get_memory_info()[0]
+
+ def call(self):
+ raise NotImplementedError("must be implemented in subclass")
+
+
+class TestProcessObjectLeaks(Base):
+ """Test leaks of Process class methods and properties"""
+
+ def setUp(self):
+ gc.collect()
+
+ def tearDown(self):
+ reap_children()
+
+ def call(self, function, *args, **kwargs):
+ p = psutil.Process(os.getpid())
+ obj = getattr(p, function)
+ if callable(obj):
+ obj(*args, **kwargs)
def test_name(self):
self.execute('name')
@@ -72,11 +100,16 @@ class TestProcessObjectLeaks(unittest.TestCase):
def test_ppid(self):
self.execute('ppid')
- def test_uid(self):
- self.execute('uid')
+ @skipIf(WINDOWS)
+ def test_uids(self):
+ self.execute('uids')
- def test_uid(self):
- self.execute('gid')
+ @skipIf(WINDOWS)
+ def test_gids(self):
+ self.execute('gids')
+
+ def test_status(self):
+ self.execute('status')
@skipIf(POSIX)
def test_username(self):
@@ -88,6 +121,9 @@ class TestProcessObjectLeaks(unittest.TestCase):
def test_get_num_threads(self):
self.execute('get_num_threads')
+ def test_get_threads(self):
+ self.execute('get_threads')
+
def test_get_cpu_times(self):
self.execute('get_cpu_times')
@@ -97,6 +133,10 @@ class TestProcessObjectLeaks(unittest.TestCase):
def test_is_running(self):
self.execute('is_running')
+ @skipIf(WINDOWS)
+ def test_terminal(self):
+ self.execute('terminal')
+
@skipUnless(WINDOWS)
def test_resume(self):
self.execute('resume')
@@ -105,48 +145,25 @@ class TestProcessObjectLeaks(unittest.TestCase):
def test_getcwd(self):
self.execute('getcwd')
- @skipUnless(WINDOWS)
+ @skipUnless(WINDOWS or OSX)
def test_get_open_files(self):
self.execute('get_open_files')
- @skipUnless(WINDOWS)
+ @skipUnless(WINDOWS or OSX)
def test_get_connections(self):
self.execute('get_connections')
-class TestModuleFunctionsLeaks(unittest.TestCase):
+class TestModuleFunctionsLeaks(Base):
"""Test leaks of psutil module functions."""
def setUp(self):
gc.collect()
- def execute(self, function, *args, **kwarks):
- # step 1
- for x in xrange(LOOPS):
- obj = getattr(psutil, function)
- if callable(obj):
- retvalue = obj(*args, **kwarks)
- else:
- retvalue = obj # property
- del x, obj, retvalue
- gc.collect()
- rss1 = psutil.Process(os.getpid()).get_memory_info()[0]
-
- # step 2
- for x in xrange(LOOPS):
- obj = getattr(psutil, function)
- if callable(obj):
- retvalue = obj(*args, **kwarks)
- else:
- retvalue = obj # property
- del x, obj, retvalue
- gc.collect()
- rss2 = psutil.Process(os.getpid()).get_memory_info()[0]
-
- # comparison
- difference = rss2 - rss1
- if difference > TOLERANCE:
- self.fail("rss1=%s, rss2=%s, difference=%s" %(rss1, rss2, difference))
+ def call(self, function, *args, **kwargs):
+ obj = getattr(psutil, function)
+ if callable(obj):
+ retvalue = obj(*args, **kwargs)
def test_get_pid_list(self):
self.execute('get_pid_list')
@@ -158,24 +175,30 @@ class TestModuleFunctionsLeaks(unittest.TestCase):
def test_process_iter(self):
self.execute('process_iter')
- def test_used_phymem(self):
- self.execute('used_phymem')
+ def test_phymem_usage(self):
+ self.execute('phymem_usage')
+
+ def test_virtmem_usage(self):
+ self.execute('virtmem_usage')
- def test_avail_phymem(self):
- self.execute('avail_phymem')
+ def test_cpu_times(self):
+ self.execute('cpu_times')
- def test_total_virtmem(self):
- self.execute('total_virtmem')
+ def test_per_cpu_times(self):
+ self.execute('cpu_times', percpu=True)
- def test_used_virtmem(self):
- self.execute('used_virtmem')
+ @skipUnless(WINDOWS)
+ def test_disk_usage(self):
+ self.execute('disk_usage', '.')
- def test_avail_virtmem(self):
- self.execute('avail_virtmem')
+ def test_disk_partitions(self):
+ self.execute('disk_partitions')
- def test_cpu_times(self):
- self.execute('cpu_times')
+ def test_network_io_counters(self):
+ self.execute('network_io_counters')
+ def test_disk_io_counters(self):
+ self.execute('disk_io_counters')
def test_main():
test_suite = unittest.TestSuite()
diff --git a/third_party/psutil/test/test_psutil.py b/third_party/psutil/test/test_psutil.py
index c067dee..35ed744 100644
--- a/third_party/psutil/test/test_psutil.py
+++ b/third_party/psutil/test/test_psutil.py
@@ -1,13 +1,16 @@
#!/usr/bin/env python
#
-# $Id: test_psutil.py 806 2010-11-12 23:09:35Z g.rodola $
+# $Id: test_psutil.py 1142 2011-10-05 18:45:49Z g.rodola $
#
+# 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.
-"""psutil test suite.
-Note: this is targeted for python 2.x.
-To run it under python 3.x you need to use 2to3 tool first:
+"""
+psutil test suite.
-$ 2to3 -w test/*.py
+Note: this is targeted for both python 2.x and 3.x so there's no need
+to use 2to3 tool first.
"""
import unittest
@@ -23,13 +26,16 @@ import warnings
import atexit
import errno
import threading
+import tempfile
+import collections
import psutil
PYTHON = os.path.realpath(sys.executable)
DEVNULL = open(os.devnull, 'r+')
-
+TESTFN = os.path.join(os.getcwd(), "$testfile")
+PY3 = sys.version_info >= (3,)
POSIX = os.name == 'posix'
LINUX = sys.platform.lower().startswith("linux")
WINDOWS = sys.platform.lower().startswith("win32")
@@ -38,13 +44,20 @@ BSD = sys.platform.lower().startswith("freebsd")
try:
psutil.Process(os.getpid()).get_connections()
-except NotImplementedError, err:
+except NotImplementedError:
+ err = sys.exc_info()[1]
SUPPORT_CONNECTIONS = False
atexit.register(warnings.warn, "get_connections() not supported on this platform",
RuntimeWarning)
else:
SUPPORT_CONNECTIONS = True
+if PY3:
+ long = int
+
+ def callable(attr):
+ return isinstance(attr, collections.Callable)
+
_subprocesses_started = set()
@@ -59,6 +72,21 @@ def get_test_subprocess(cmd=None, stdout=DEVNULL, stderr=DEVNULL, stdin=None):
_subprocesses_started.add(sproc.pid)
return sproc
+def sh(cmdline):
+ """run cmd in a subprocess and return its output.
+ raises RuntimeError on error.
+ """
+ p = subprocess.Popen(cmdline, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ if p.returncode != 0:
+ raise RuntimeError(stderr)
+ if stderr:
+ warnings.warn(stderr, RuntimeWarning)
+ if sys.version_info >= (3,):
+ stdout = str(stdout, sys.stdout.encoding)
+ return stdout.strip()
+
def wait_for_pid(pid, timeout=1):
"""Wait for pid to show up in the process list then return.
Used in the test suite to give time the sub process to initialize.
@@ -73,38 +101,11 @@ def wait_for_pid(pid, timeout=1):
if time.time() >= raise_at:
raise RuntimeError("Timed out")
-def kill(pid):
- """Kill a process given its PID."""
- if hasattr(os, 'kill'):
- os.kill(pid, signal.SIGKILL)
- else:
- psutil.Process(pid).kill()
-
def reap_children(search_all=False):
"""Kill any subprocess started by this test suite and ensure that
no zombies stick around to hog resources and create problems when
looking for refleaks.
"""
- if POSIX:
- def waitpid(process):
- # on posix we are free to wait for any pending process by
- # passing -1 to os.waitpid()
- while True:
- try:
- any_process = -1
- pid, status = os.waitpid(any_process, os.WNOHANG)
- if pid == 0 and not process.is_running():
- break
- except OSError:
- if not process.is_running():
- break
- else:
- def waitpid(process):
- # on non-posix systems we just wait for the given process
- # to go away
- while process.is_running():
- time.sleep(0.01)
-
if search_all:
this_process = psutil.Process(os.getpid())
pids = [x.pid for x in this_process.get_children()]
@@ -118,7 +119,8 @@ def reap_children(search_all=False):
except psutil.NoSuchProcess:
pass
else:
- waitpid(child)
+ child.wait()
+
# we want to search through all processes before exiting
atexit.register(reap_children, search_all=True)
@@ -155,90 +157,123 @@ def skipUnless(condition, reason="", warn=False):
return skipIf(True, reason, warn)
return skipIf(False)
+def ignore_access_denied(fun):
+ """Decorator to Ignore AccessDenied exceptions."""
+ def outer(fun, *args, **kwargs):
+ def inner(self):
+ try:
+ return fun(self, *args, **kwargs)
+ except psutil.AccessDenied:
+ pass
+ return inner
+ return outer
+
+def supports_ipv6():
+ """Return True if IPv6 is supported on this platform."""
+ if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"):
+ return False
+ sock = None
+ try:
+ try:
+ sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+ sock.bind(("::1", 0))
+ except (socket.error, socket.gaierror):
+ return False
+ else:
+ return True
+ finally:
+ if sock is not None:
+ sock.close()
+
+
+class ThreadTask(threading.Thread):
+ """A thread object used for running process thread tests."""
+
+ def __init__(self):
+ threading.Thread.__init__(self)
+ self._running = False
+ self._interval = None
+ self._flag = threading.Event()
+
+ def __repr__(self):
+ name = self.__class__.__name__
+ return '<%s running=%s at %#x>' % (name, self._running, id(self))
+
+ def start(self, interval=0.001):
+ """Start thread and keep it running until an explicit
+ stop() request. Polls for shutdown every 'timeout' seconds.
+ """
+ if self._running:
+ raise ValueError("already started")
+ self._interval = interval
+ threading.Thread.start(self)
+ self._flag.wait()
+
+ def run(self):
+ self._running = True
+ self._flag.set()
+ while self._running:
+ time.sleep(self._interval)
+
+ def stop(self):
+ """Stop thread execution and and waits until it is stopped."""
+ if not self._running:
+ raise ValueError("already stopped")
+ self._running = False
+ self.join()
+
class TestCase(unittest.TestCase):
def tearDown(self):
reap_children()
+ # ============================
+ # tests for system-related API
+ # ============================
+
def test_get_process_list(self):
pids = [x.pid for x in psutil.get_process_list()]
self.assertTrue(os.getpid() in pids)
- self.assertTrue(0 in pids)
def test_process_iter(self):
pids = [x.pid for x in psutil.process_iter()]
self.assertTrue(os.getpid() in pids)
- self.assertTrue(0 in pids)
-
- def test_kill(self):
- sproc = get_test_subprocess()
- test_pid = sproc.pid
- wait_for_pid(test_pid)
- p = psutil.Process(test_pid)
- name = p.name
- p.kill()
- sproc.wait()
- self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
-
- def test_terminate(self):
- sproc = get_test_subprocess()
- test_pid = sproc.pid
- wait_for_pid(test_pid)
- p = psutil.Process(test_pid)
- name = p.name
- p.terminate()
- sproc.wait()
- self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
-
- def test_send_signal(self):
- if POSIX:
- sig = signal.SIGKILL
- else:
- sig = signal.SIGTERM
- sproc = get_test_subprocess()
- test_pid = sproc.pid
- p = psutil.Process(test_pid)
- name = p.name
- p.send_signal(sig)
- sproc.wait()
- self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
def test_TOTAL_PHYMEM(self):
x = psutil.TOTAL_PHYMEM
self.assertTrue(isinstance(x, (int, long)))
self.assertTrue(x > 0)
- def test_used_phymem(self):
- x = psutil.used_phymem()
- self.assertTrue(isinstance(x, (int, long)))
- self.assertTrue(x > 0)
-
- def test_avail_phymem(self):
- x = psutil.avail_phymem()
- self.assertTrue(isinstance(x, (int, long)))
+ def test_BOOT_TIME(self):
+ x = psutil.BOOT_TIME
+ self.assertTrue(isinstance(x, float))
self.assertTrue(x > 0)
- def test_total_virtmem(self):
- x = psutil.total_virtmem()
- self.assertTrue(isinstance(x, (int, long)))
- self.assertTrue(x >= 0)
-
- def test_used_virtmem(self):
- x = psutil.used_virtmem()
- self.assertTrue(isinstance(x, (int, long)))
- self.assertTrue(x >= 0)
+ def test_deprecated_memory_functions(self):
+ warnings.filterwarnings("error")
+ try:
+ self.assertRaises(DeprecationWarning, psutil.used_phymem)
+ self.assertRaises(DeprecationWarning, psutil.avail_phymem)
+ self.assertRaises(DeprecationWarning, psutil.total_virtmem)
+ self.assertRaises(DeprecationWarning, psutil.used_virtmem)
+ self.assertRaises(DeprecationWarning, psutil.avail_virtmem)
+ finally:
+ warnings.resetwarnings()
- def test_avail_virtmem(self):
- x = psutil.avail_virtmem()
- self.assertTrue(isinstance(x, (int, long)))
- self.assertTrue(x >= 0)
+ def test_phymem_usage(self):
+ mem = psutil.phymem_usage()
+ self.assertTrue(mem.total > 0)
+ self.assertTrue(mem.used > 0)
+ self.assertTrue(mem.free > 0)
+ self.assertTrue(0 <= mem.percent <= 100)
- @skipUnless(LINUX)
- def test_cached_phymem(self):
- x = psutil.cached_phymem()
- self.assertTrue(isinstance(x, (int, long)))
- self.assertTrue(x >= 0)
+ def test_virtmem_usage(self):
+ mem = psutil.virtmem_usage()
+ self.assertTrue(mem.total > 0)
+ self.assertTrue(mem.used >= 0)
+ self.assertTrue(mem.free > 0)
+ self.assertTrue(0 <= mem.percent <= 100)
@skipUnless(LINUX)
def test_phymem_buffers(self):
@@ -246,20 +281,60 @@ class TestCase(unittest.TestCase):
self.assertTrue(isinstance(x, (int, long)))
self.assertTrue(x >= 0)
- def test_system_cpu_times(self):
+ def test_pid_exists(self):
+ sproc = get_test_subprocess()
+ wait_for_pid(sproc.pid)
+ 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))
+
+ def test_pid_exists_2(self):
+ reap_children()
+ pids = psutil.get_pid_list()
+ for pid in pids:
+ try:
+ self.assertTrue(psutil.pid_exists(pid))
+ except AssertionError:
+ # in case the process disappeared in meantime fail only
+ # if it is no longer in get_pid_list()
+ time.sleep(.1)
+ if pid in psutil.get_pid_list():
+ self.fail(pid)
+ pids = range(max(pids) + 5000, max(pids) + 6000)
+ for pid in pids:
+ self.assertFalse(psutil.pid_exists(pid))
+
+ def test_get_pid_list(self):
+ plist = [x.pid for x in psutil.get_process_list()]
+ pidlist = psutil.get_pid_list()
+ 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_sys_cpu_times(self):
total = 0
times = psutil.cpu_times()
- self.assertTrue(isinstance(times, psutil.CPUTimes))
sum(times)
for cp_time in times:
self.assertTrue(isinstance(cp_time, float))
self.assertTrue(cp_time >= 0.0)
total += cp_time
- # test CPUTimes's __iter__ and __str__ implementation
self.assertEqual(total, sum(times))
str(times)
- def test_system_cpu_times2(self):
+ def test_sys_cpu_times2(self):
t1 = sum(psutil.cpu_times())
time.sleep(0.1)
t2 = sum(psutil.cpu_times())
@@ -267,26 +342,283 @@ class TestCase(unittest.TestCase):
if not difference >= 0.05:
self.fail("difference %s" % difference)
- def test_system_cpu_percent(self):
+ def test_sys_per_cpu_times(self):
+ for times in psutil.cpu_times(percpu=True):
+ total = 0
+ sum(times)
+ for cp_time in times:
+ self.assertTrue(isinstance(cp_time, float))
+ self.assertTrue(cp_time >= 0.0)
+ total += cp_time
+ self.assertEqual(total, sum(times))
+ str(times)
+
+ def test_sys_per_cpu_times2(self):
+ tot1 = psutil.cpu_times(percpu=True)
+ stop_at = time.time() + 0.1
+ while 1:
+ if time.time() >= stop_at:
+ break
+ tot2 = psutil.cpu_times(percpu=True)
+ for t1, t2 in zip(tot1, tot2):
+ t1, t2 = sum(t1), sum(t2)
+ difference = t2 - t1
+ if difference >= 0.05:
+ return
+ self.fail()
+
+ def test_sys_cpu_percent(self):
psutil.cpu_percent(interval=0.001)
psutil.cpu_percent(interval=0.001)
- for x in xrange(1000):
+ for x in range(1000):
percent = psutil.cpu_percent(interval=None)
self.assertTrue(isinstance(percent, float))
self.assertTrue(percent >= 0.0)
self.assertTrue(percent <= 100.0)
- def test_process_cpu_percent(self):
+ def test_sys_per_cpu_percent(self):
+ psutil.cpu_percent(interval=0.001, percpu=True)
+ psutil.cpu_percent(interval=0.001, percpu=True)
+ for x in range(1000):
+ percents = psutil.cpu_percent(interval=None, percpu=True)
+ for percent in percents:
+ self.assertTrue(isinstance(percent, float))
+ self.assertTrue(percent >= 0.0)
+ self.assertTrue(percent <= 100.0)
+
+ def test_sys_cpu_percent_compare(self):
+ psutil.cpu_percent(interval=0)
+ psutil.cpu_percent(interval=0, percpu=True)
+ time.sleep(.1)
+ t1 = psutil.cpu_percent(interval=0)
+ t2 = psutil.cpu_percent(interval=0, percpu=True)
+ # calculate total average
+ t2 = sum(t2) / len(t2)
+ if abs(t1 - t2) > 5:
+ self.assertEqual(t1, t2)
+
+ def test_disk_usage(self):
+ usage = psutil.disk_usage(os.getcwd())
+ self.assertTrue(usage.total > 0)
+ self.assertTrue(usage.used > 0)
+ self.assertTrue(usage.free > 0)
+ self.assertTrue(usage.total > usage.used)
+ self.assertTrue(usage.total > usage.free)
+ self.assertTrue(0 <= usage.percent <= 100)
+
+ # if path does not exist OSError ENOENT is expected across
+ # all platforms
+ fname = tempfile.mktemp()
+ try:
+ psutil.disk_usage(fname)
+ except OSError:
+ err = sys.exc_info()[1]
+ if err.args[0] != errno.ENOENT:
+ raise
+ else:
+ self.fail("OSError not raised")
+
+ def test_disk_partitions(self):
+ for disk in psutil.disk_partitions(all=False):
+ self.assertTrue(os.path.exists(disk.device))
+ self.assertTrue(os.path.isdir(disk.mountpoint))
+ self.assertTrue(disk.fstype)
+ for disk in psutil.disk_partitions(all=True):
+ if not WINDOWS:
+ self.assertTrue(os.path.isdir(disk.mountpoint))
+ self.assertTrue(disk.fstype)
+
+ def find_mount_point(path):
+ path = os.path.abspath(path)
+ while not os.path.ismount(path):
+ path = os.path.dirname(path)
+ return path
+
+ mount = find_mount_point(__file__)
+ mounts = [x.mountpoint for x in psutil.disk_partitions(all=True)]
+ self.assertTrue(mount in mounts)
+ psutil.disk_usage(mount)
+
+ # XXX
+ @skipUnless(hasattr(psutil, "network_io_counters"))
+ def test_anetwork_io_counters(self):
+ def check_ntuple(nt):
+ self.assertEqual(nt[0], nt.bytes_sent)
+ self.assertEqual(nt[1], nt.bytes_recv)
+ self.assertEqual(nt[2], nt.packets_sent)
+ self.assertEqual(nt[3], nt.packets_recv)
+ self.assertTrue(nt.bytes_sent >= 0)
+ self.assertTrue(nt.bytes_recv >= 0)
+ self.assertTrue(nt.packets_sent >= 0)
+ self.assertTrue(nt.packets_recv >= 0)
+
+ ret = psutil.network_io_counters(pernic=False)
+ check_ntuple(ret)
+ ret = psutil.network_io_counters(pernic=True)
+ for name, ntuple in ret.iteritems():
+ self.assertTrue(name)
+ check_ntuple(ntuple)
+ # XXX
+ @skipUnless(hasattr(psutil, "disk_io_counters"))
+ 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)
+ self.assertEqual(nt[4], nt.read_time)
+ self.assertEqual(nt[5], nt.write_time)
+ self.assertTrue(nt.read_count >= 0)
+ self.assertTrue(nt.write_count >= 0)
+ self.assertTrue(nt.read_bytes >= 0)
+ self.assertTrue(nt.write_bytes >= 0)
+ self.assertTrue(nt.read_time >= 0)
+ self.assertTrue(nt.write_time >= 0)
+
+ ret = psutil.disk_io_counters(perdisk=False)
+ check_ntuple(ret)
+ ret = psutil.disk_io_counters(perdisk=True)
+ for name, ntuple in ret.iteritems():
+ self.assertTrue(name)
+ check_ntuple(ntuple)
+
+ # ====================
+ # Process object tests
+ # ====================
+
+ def test_kill(self):
+ sproc = get_test_subprocess()
+ test_pid = sproc.pid
+ wait_for_pid(test_pid)
+ p = psutil.Process(test_pid)
+ name = p.name
+ p.kill()
+ p.wait()
+ self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
+
+ def test_terminate(self):
+ sproc = get_test_subprocess()
+ test_pid = sproc.pid
+ wait_for_pid(test_pid)
+ p = psutil.Process(test_pid)
+ name = p.name
+ p.terminate()
+ p.wait()
+ self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
+
+ def test_send_signal(self):
+ if POSIX:
+ sig = signal.SIGKILL
+ else:
+ sig = signal.SIGTERM
+ sproc = get_test_subprocess()
+ test_pid = sproc.pid
+ p = psutil.Process(test_pid)
+ name = p.name
+ p.send_signal(sig)
+ p.wait()
+ self.assertFalse(psutil.pid_exists(test_pid) and name == PYTHON)
+
+ def test_wait(self):
+ # check exit code signal
+ sproc = get_test_subprocess()
+ p = psutil.Process(sproc.pid)
+ p.kill()
+ code = p.wait()
+ if os.name == 'posix':
+ self.assertEqual(code, signal.SIGKILL)
+ else:
+ self.assertEqual(code, 0)
+ self.assertFalse(p.is_running())
+
+ sproc = get_test_subprocess()
+ p = psutil.Process(sproc.pid)
+ p.terminate()
+ code = p.wait()
+ if os.name == 'posix':
+ self.assertEqual(code, signal.SIGTERM)
+ else:
+ self.assertEqual(code, 0)
+ self.assertFalse(p.is_running())
+
+ # check sys.exit() code
+ code = "import time, sys; time.sleep(0.01); sys.exit(5);"
+ sproc = get_test_subprocess([PYTHON, "-c", code])
+ p = psutil.Process(sproc.pid)
+ self.assertEqual(p.wait(), 5)
+ self.assertFalse(p.is_running())
+
+ # Test wait() issued twice.
+ # It is not supposed to raise NSP when the process is gone.
+ # On UNIX this should return None, on Windows it should keep
+ # returning the exit code.
+ sproc = get_test_subprocess([PYTHON, "-c", code])
+ p = psutil.Process(sproc.pid)
+ self.assertEqual(p.wait(), 5)
+ self.assertTrue(p.wait() in (5, None))
+
+ # test timeout
+ sproc = get_test_subprocess()
+ p = psutil.Process(sproc.pid)
+ p.name
+ self.assertRaises(psutil.TimeoutExpired, p.wait, 0.01)
+
+ # timeout < 0 not allowed
+ self.assertRaises(ValueError, p.wait, -1)
+
+ @skipUnless(POSIX)
+ def test_wait_non_children(self):
+ # test wait() against processes which are not our children
+ code = "import sys;"
+ code += "from subprocess import Popen, PIPE;"
+ code += "cmd = ['%s', '-c', 'import time; time.sleep(10)'];" %PYTHON
+ code += "sp = Popen(cmd, stdout=PIPE);"
+ code += "sys.stdout.write(str(sp.pid));"
+ sproc = get_test_subprocess([PYTHON, "-c", code], stdout=subprocess.PIPE)
+
+ grandson_pid = int(sproc.stdout.read())
+ grandson_proc = psutil.Process(grandson_pid)
+ try:
+ self.assertRaises(psutil.TimeoutExpired, grandson_proc.wait, 0.01)
+ grandson_proc.kill()
+ ret = grandson_proc.wait()
+ self.assertEqual(ret, None)
+ finally:
+ if grandson_proc.is_running():
+ grandson_proc.kill()
+ grandson_proc.wait()
+
+ def test_wait_timeout_0(self):
+ sproc = get_test_subprocess()
+ p = psutil.Process(sproc.pid)
+ self.assertRaises(psutil.TimeoutExpired, p.wait, 0)
+ p.kill()
+ stop_at = time.time() + 2
+ while 1:
+ try:
+ code = p.wait(0)
+ except psutil.TimeoutExpired:
+ if time.time() >= stop_at:
+ raise
+ else:
+ break
+ if os.name == 'posix':
+ self.assertEqual(code, signal.SIGKILL)
+ else:
+ self.assertEqual(code, 0)
+ self.assertFalse(p.is_running())
+
+ def test_cpu_percent(self):
p = psutil.Process(os.getpid())
p.get_cpu_percent(interval=0.001)
p.get_cpu_percent(interval=0.001)
- for x in xrange(100):
+ for x in range(100):
percent = p.get_cpu_percent(interval=None)
self.assertTrue(isinstance(percent, float))
self.assertTrue(percent >= 0.0)
self.assertTrue(percent <= 100.0)
- def test_get_process_cpu_times(self):
+ def test_cpu_times(self):
times = psutil.Process(os.getpid()).get_cpu_times()
self.assertTrue((times.user > 0.0) or (times.system > 0.0))
# make sure returned values can be pretty printed with strftime
@@ -300,7 +632,7 @@ class TestCase(unittest.TestCase):
# try this with Python 2.7 and re-enable the test.
@skipUnless(sys.version_info > (2, 6, 1) and not OSX)
- def test_get_process_cpu_times2(self):
+ def test_cpu_times2(self):
user_time, kernel_time = psutil.Process(os.getpid()).get_cpu_times()
utime, ktime = os.times()[:2]
@@ -331,20 +663,113 @@ class TestCase(unittest.TestCase):
# make sure returned value can be pretty printed with strftime
time.strftime("%Y %m %d %H:%M:%S", time.localtime(p.create_time))
- def test_get_num_threads(self):
+ @skipIf(WINDOWS)
+ def test_terminal(self):
+ tty = sh('tty')
p = psutil.Process(os.getpid())
- numt1 = p.get_num_threads()
- if not WINDOWS and not OSX:
- # test is unreliable on Windows and OS X
- # NOTE: sleep(1) is too long for OS X, works with sleep(.5)
- self.assertEqual(numt1, 1)
- t = threading.Thread(target=lambda:time.sleep(1))
- t.start()
- numt2 = p.get_num_threads()
- if WINDOWS:
- self.assertTrue(numt2 > numt1)
+ self.assertEqual(p.terminal, tty)
+
+ @skipIf(OSX, warn=False)
+ def test_get_io_counters(self):
+ p = psutil.Process(os.getpid())
+ # test reads
+ io1 = p.get_io_counters()
+ f = open(PYTHON, 'rb')
+ f.read()
+ f.close()
+ io2 = p.get_io_counters()
+ if not BSD:
+ self.assertTrue(io2.read_count > io1.read_count)
+ self.assertTrue(io2.write_count == io1.write_count)
+ self.assertTrue(io2.read_bytes >= io1.read_bytes)
+ self.assertTrue(io2.write_bytes >= io1.write_bytes)
+ # test writes
+ io1 = p.get_io_counters()
+ f = tempfile.TemporaryFile()
+ if sys.version_info >= (3,):
+ f.write(bytes("x" * 1000000, 'ascii'))
else:
- self.assertEqual(numt2, 2)
+ f.write("x" * 1000000)
+ f.close()
+ io2 = p.get_io_counters()
+ if not BSD:
+ self.assertTrue(io2.write_count > io1.write_count)
+ self.assertTrue(io2.write_bytes > io1.write_bytes)
+ self.assertTrue(io2.read_count >= io1.read_count)
+ self.assertTrue(io2.read_bytes >= io1.read_bytes)
+
+ @skipUnless(LINUX)
+ def test_get_set_ionice(self):
+ 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)
+ p = psutil.Process(os.getpid())
+ try:
+ p.set_ionice(2)
+ ioclass, value = p.get_ionice()
+ self.assertEqual(ioclass, 2)
+ self.assertEqual(value, 4)
+ #
+ p.set_ionice(3)
+ ioclass, value = p.get_ionice()
+ self.assertEqual(ioclass, 3)
+ self.assertEqual(value, 0)
+ #
+ p.set_ionice(2, 0)
+ ioclass, value = p.get_ionice()
+ self.assertEqual(ioclass, 2)
+ self.assertEqual(value, 0)
+ p.set_ionice(2, 7)
+ ioclass, value = p.get_ionice()
+ self.assertEqual(ioclass, 2)
+ self.assertEqual(value, 7)
+ self.assertRaises(ValueError, p.set_ionice, 2, 10)
+ finally:
+ p.set_ionice(IOPRIO_CLASS_NONE)
+
+ def test_get_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)
+ p = psutil.Process(os.getpid())
+ step1 = p.get_num_threads()
+
+ thread = ThreadTask()
+ thread.start()
+ try:
+ step2 = p.get_num_threads()
+ self.assertEqual(step2, step1 + 1)
+ thread.stop()
+ finally:
+ if thread._running:
+ thread.stop()
+
+ def test_get_threads(self):
+ p = psutil.Process(os.getpid())
+ step1 = p.get_threads()
+
+ thread = ThreadTask()
+ thread.start()
+
+ try:
+ step2 = p.get_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])
+ # test num threads
+ thread.stop()
+ finally:
+ if thread._running:
+ thread.stop()
def test_get_memory_info(self):
p = psutil.Process(os.getpid())
@@ -374,33 +799,30 @@ class TestCase(unittest.TestCase):
sproc = get_test_subprocess()
self.assertEqual(psutil.Process(sproc.pid).pid, sproc.pid)
- def test_eq(self):
- sproc = get_test_subprocess()
- wait_for_pid(sproc.pid)
- self.assertTrue(psutil.Process(sproc.pid) == psutil.Process(sproc.pid))
-
def test_is_running(self):
sproc = get_test_subprocess()
wait_for_pid(sproc.pid)
p = psutil.Process(sproc.pid)
self.assertTrue(p.is_running())
- psutil.Process(sproc.pid).kill()
- sproc.wait()
+ p.kill()
+ p.wait()
self.assertFalse(p.is_running())
- def test_pid_exists(self):
- sproc = get_test_subprocess()
- wait_for_pid(sproc.pid)
- self.assertTrue(psutil.pid_exists(sproc.pid))
- psutil.Process(sproc.pid).kill()
- sproc.wait()
- self.assertFalse(psutil.pid_exists(sproc.pid))
- self.assertFalse(psutil.pid_exists(-1))
-
def test_exe(self):
sproc = get_test_subprocess()
wait_for_pid(sproc.pid)
- self.assertEqual(psutil.Process(sproc.pid).exe, PYTHON)
+ try:
+ self.assertEqual(psutil.Process(sproc.pid).exe, PYTHON)
+ except AssertionError:
+ # certain platforms such as BSD are more accurate returning:
+ # "/usr/local/bin/python2.7"
+ # ...instead of:
+ # "/usr/local/bin/python"
+ # We do not want to consider this difference in accuracy
+ # an error.
+ name = psutil.Process(sproc.pid).exe
+ adjusted_name = PYTHON[:len(name)]
+ self.assertEqual(name, adjusted_name)
for p in psutil.process_iter():
try:
exe = p.exe
@@ -416,14 +838,6 @@ class TestCase(unittest.TestCase):
self.fail("%s is not executable (pid=%s, name=%s, cmdline=%s)" \
% (repr(p.exe), p.pid, p.name, p.cmdline))
- def test_path(self):
- proc = psutil.Process(os.getpid())
- warnings.filterwarnings("error")
- try:
- self.assertRaises(DeprecationWarning, getattr, proc, 'path')
- finally:
- warnings.resetwarnings()
-
def test_cmdline(self):
sproc = get_test_subprocess([PYTHON, "-E"])
wait_for_pid(sproc.pid)
@@ -432,40 +846,82 @@ class TestCase(unittest.TestCase):
def test_name(self):
sproc = get_test_subprocess(PYTHON)
wait_for_pid(sproc.pid)
- if OSX:
- self.assertEqual(psutil.Process(sproc.pid).name, "Python")
- else:
- self.assertEqual(psutil.Process(sproc.pid).name, os.path.basename(PYTHON))
-
- def test_uid(self):
- sproc = get_test_subprocess()
- wait_for_pid(sproc.pid)
- uid = psutil.Process(sproc.pid).uid
- if hasattr(os, 'getuid'):
- self.assertEqual(uid, os.getuid())
- else:
- # On those platforms where UID doesn't make sense (Windows)
- # we expect it to be -1
- self.assertEqual(uid, -1)
-
- def test_gid(self):
- sproc = get_test_subprocess()
- wait_for_pid(sproc.pid)
- gid = psutil.Process(sproc.pid).gid
- if hasattr(os, 'getgid'):
- self.assertEqual(gid, os.getgid())
- else:
- # On those platforms where GID doesn't make sense (Windows)
- # we expect it to be -1
- self.assertEqual(gid, -1)
+ self.assertEqual(psutil.Process(sproc.pid).name.lower(),
+ os.path.basename(sys.executable).lower())
+
+ if os.name == 'posix':
+
+ def test_uids(self):
+ p = psutil.Process(os.getpid())
+ real, effective, saved = p.uids
+ # os.getuid() refers to "real" uid
+ self.assertEqual(real, os.getuid())
+ # os.geteuid() refers to "effective" uid
+ self.assertEqual(effective, os.geteuid())
+ # no such thing as os.getsuid() ("saved" uid), but starting
+ # from python 2.7 we have os.getresuid()[2]
+ if hasattr(os, "getresuid"):
+ self.assertEqual(saved, os.getresuid()[2])
+
+ def test_gids(self):
+ p = psutil.Process(os.getpid())
+ real, effective, saved = p.gids
+ # os.getuid() refers to "real" uid
+ self.assertEqual(real, os.getgid())
+ # os.geteuid() refers to "effective" uid
+ self.assertEqual(effective, os.getegid())
+ # no such thing as os.getsuid() ("saved" uid), but starting
+ # from python 2.7 we have os.getresgid()[2]
+ if hasattr(os, "getresuid"):
+ self.assertEqual(saved, os.getresgid()[2])
+
+ def test_nice(self):
+ p = psutil.Process(os.getpid())
+ self.assertRaises(TypeError, setattr, p, "nice", "str")
+ try:
+ try:
+ first_nice = p.nice
+ p.nice = 1
+ self.assertEqual(p.nice, 1)
+ # going back to previous nice value raises AccessDenied on OSX
+ if not OSX:
+ p.nice = 0
+ self.assertEqual(p.nice, 0)
+ except psutil.AccessDenied:
+ pass
+ finally:
+ # going back to previous nice value raises AccessDenied on OSX
+ if not OSX:
+ p.nice = first_nice
+
+ if os.name == 'nt':
+
+ def test_nice(self):
+ p = psutil.Process(os.getpid())
+ self.assertRaises(TypeError, setattr, p, "nice", "str")
+ try:
+ self.assertEqual(p.nice, psutil.NORMAL_PRIORITY_CLASS)
+ p.nice = psutil.HIGH_PRIORITY_CLASS
+ self.assertEqual(p.nice, psutil.HIGH_PRIORITY_CLASS)
+ p.nice = psutil.NORMAL_PRIORITY_CLASS
+ self.assertEqual(p.nice, psutil.NORMAL_PRIORITY_CLASS)
+ finally:
+ p.nice = psutil.NORMAL_PRIORITY_CLASS
+
+ def test_status(self):
+ p = psutil.Process(os.getpid())
+ self.assertEqual(p.status, psutil.STATUS_RUNNING)
+ self.assertEqual(str(p.status), "running")
+ for p in psutil.process_iter():
+ if str(p.status) == '?':
+ self.fail("invalid status for pid %d" % p.pid)
def test_username(self):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
if POSIX:
import pwd
- user = pwd.getpwuid(p.uid).pw_name
- self.assertEqual(p.username, user)
+ self.assertEqual(p.username, pwd.getpwuid(os.getuid()).pw_name)
elif WINDOWS:
expected_username = os.environ['USERNAME']
expected_domain = os.environ['USERDOMAIN']
@@ -493,27 +949,31 @@ class TestCase(unittest.TestCase):
self.assertEqual(p.getcwd(), expected_dir)
def test_get_open_files(self):
- thisfile = os.path.join(os.getcwd(), __file__)
-
# current process
p = psutil.Process(os.getpid())
files = p.get_open_files()
- self.assertFalse(thisfile in files)
- f = open(thisfile, 'r')
+ self.assertFalse(TESTFN in files)
+ f = open(TESTFN, 'r')
+ time.sleep(.1)
filenames = [x.path for x in p.get_open_files()]
- self.assertTrue(thisfile in filenames)
+ self.assertTrue(TESTFN in filenames)
f.close()
for file in filenames:
self.assertTrue(os.path.isfile(file))
# another process
- cmdline = "import time; f = open(r'%s', 'r'); time.sleep(100);" % thisfile
+ cmdline = "import time; f = open(r'%s', 'r'); time.sleep(100);" % TESTFN
sproc = get_test_subprocess([PYTHON, "-c", cmdline])
wait_for_pid(sproc.pid)
time.sleep(0.1)
p = psutil.Process(sproc.pid)
- filenames = [x.path for x in p.get_open_files()]
- self.assertTrue(thisfile in filenames)
+ for x in range(100):
+ filenames = [x.path for x in p.get_open_files()]
+ if TESTFN in filenames:
+ break
+ time.sleep(.01)
+ else:
+ self.assertTrue(TESTFN in filenames)
for file in filenames:
self.assertTrue(os.path.isfile(file))
# all processes
@@ -528,7 +988,7 @@ class TestCase(unittest.TestCase):
def test_get_open_files2(self):
# test fd and path fields
- fileobj = open(os.path.join(os.getcwd(), __file__), 'r')
+ fileobj = open(TESTFN, 'r')
p = psutil.Process(os.getpid())
for path, fd in p.get_open_files():
if path == fileobj.name or fd == fileobj.fileno():
@@ -557,10 +1017,13 @@ class TestCase(unittest.TestCase):
"conn, addr = s.accept();" \
"time.sleep(100);"
sproc = get_test_subprocess([PYTHON, "-c", arg])
- time.sleep(0.1)
p = psutil.Process(sproc.pid)
- cons = p.get_connections()
- self.assertTrue(len(cons) == 1)
+ for x in range(100):
+ cons = p.get_connections()
+ if cons:
+ break
+ time.sleep(.01)
+ self.assertEqual(len(cons), 1)
con = cons[0]
self.assertEqual(con.family, socket.AF_INET)
self.assertEqual(con.type, socket.SOCK_STREAM)
@@ -580,10 +1043,20 @@ class TestCase(unittest.TestCase):
self.assertEqual(con[4], con.remote_address)
self.assertEqual(con[5], con.status)
+ @skipUnless(supports_ipv6())
+ def test_get_connections_ipv6(self):
+ s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+ s.bind(('::1', 0))
+ s.listen(1)
+ cons = psutil.Process(os.getpid()).get_connections()
+ s.close()
+ self.assertEqual(len(cons), 1)
+ self.assertEqual(cons[0].local_address[0], '::1')
+
@skipUnless(hasattr(socket, "fromfd") and not WINDOWS)
def test_connection_fromfd(self):
sock = socket.socket()
- sock.bind(('127.0.0.1', 0))
+ sock.bind(('localhost', 0))
sock.listen(1)
p = psutil.Process(os.getpid())
for conn in p.get_connections():
@@ -609,24 +1082,12 @@ class TestCase(unittest.TestCase):
ip, port = addr
self.assertTrue(isinstance(port, int))
if family == socket.AF_INET:
- ip = map(int, ip.split('.'))
+ ip = list(map(int, ip.split('.')))
self.assertTrue(len(ip) == 4)
for num in ip:
self.assertTrue(0 <= num <= 255)
self.assertTrue(0 <= port <= 65535)
- def supports_ipv6():
- if not socket.has_ipv6 or not hasattr(socket, "AF_INET6"):
- return False
- try:
- sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- sock.bind(("::1", 0))
- except (socket.error, socket.gaierror):
- return False
- else:
- sock.close()
- return True
-
# all values are supposed to match Linux's tcp_states.h states
# table across all platforms.
valid_states = ["ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT1",
@@ -665,9 +1126,9 @@ class TestCase(unittest.TestCase):
tcp6_proc = None
udp6_proc = None
+ # --- check connections of all processes
+
time.sleep(0.1)
- this_proc = psutil.Process(os.getpid())
- children_pids = [p.pid for p in this_proc.get_children()]
for p in psutil.process_iter():
try:
cons = p.get_connections()
@@ -693,49 +1154,58 @@ class TestCase(unittest.TestCase):
s.close()
if not WINDOWS and hasattr(socket, 'fromfd'):
+ dupsock = None
try:
- dupsock = socket.fromfd(conn.fd, conn.family,
- conn.type)
- except (socket.error, OSError), err:
- if err.args[0] == errno.EBADF:
- continue
- else:
- raise
- self.assertEqual(dupsock.family, conn.family)
- self.assertEqual(dupsock.type, conn.type)
-
- # check matches against subprocesses
- if p.pid in children_pids:
- self.assertTrue(len(cons) == 1)
- conn = cons[0]
- # TCP v4
- if p.pid == tcp4_proc.pid:
- self.assertEqual(conn.family, socket.AF_INET)
- self.assertEqual(conn.type, socket.SOCK_STREAM)
- self.assertEqual(conn.local_address[0], "127.0.0.1")
- self.assertEqual(conn.remote_address, ())
- self.assertEqual(conn.status, "LISTEN")
- # UDP v4
- elif p.pid == udp4_proc.pid:
- self.assertEqual(conn.family, socket.AF_INET)
- self.assertEqual(conn.type, socket.SOCK_DGRAM)
- self.assertEqual(conn.local_address[0], "127.0.0.1")
- self.assertEqual(conn.remote_address, ())
- self.assertEqual(conn.status, "")
- # TCP v6
- elif p.pid == getattr(tcp6_proc, "pid", None):
- self.assertEqual(conn.family, socket.AF_INET6)
- self.assertEqual(conn.type, socket.SOCK_STREAM)
- self.assertEqual(conn.local_address[0], "::1")
- self.assertEqual(conn.remote_address, ())
- self.assertEqual(conn.status, "LISTEN")
- # UDP v6
- elif p.pid == getattr(udp6_proc, "pid", None):
- self.assertEqual(conn.family, socket.AF_INET6)
- self.assertEqual(conn.type, socket.SOCK_DGRAM)
- self.assertEqual(conn.local_address[0], "::1")
- self.assertEqual(conn.remote_address, ())
- self.assertEqual(conn.status, "")
+ try:
+ dupsock = socket.fromfd(conn.fd, conn.family,
+ conn.type)
+ except (socket.error, OSError):
+ err = sys.exc_info()[1]
+ if err.args[0] == errno.EBADF:
+ continue
+ else:
+ raise
+ # python >= 2.5
+ if hasattr(dupsock, "family"):
+ self.assertEqual(dupsock.family, conn.family)
+ self.assertEqual(dupsock.type, conn.type)
+ finally:
+ if dupsock is not None:
+ dupsock.close()
+
+
+ # --- check matches against subprocesses
+
+ for p in psutil.Process(os.getpid()).get_children():
+ for conn in p.get_connections():
+ # TCP v4
+ if p.pid == tcp4_proc.pid:
+ self.assertEqual(conn.family, socket.AF_INET)
+ self.assertEqual(conn.type, socket.SOCK_STREAM)
+ self.assertEqual(conn.local_address[0], "127.0.0.1")
+ self.assertEqual(conn.remote_address, ())
+ self.assertEqual(conn.status, "LISTEN")
+ # UDP v4
+ elif p.pid == udp4_proc.pid:
+ self.assertEqual(conn.family, socket.AF_INET)
+ self.assertEqual(conn.type, socket.SOCK_DGRAM)
+ self.assertEqual(conn.local_address[0], "127.0.0.1")
+ self.assertEqual(conn.remote_address, ())
+ self.assertEqual(conn.status, "")
+ # TCP v6
+ elif p.pid == getattr(tcp6_proc, "pid", None):
+ self.assertEqual(conn.family, socket.AF_INET6)
+ self.assertEqual(conn.type, socket.SOCK_STREAM)
+ self.assertTrue(conn.local_address[0] in ("::", "::1"))
+ self.assertEqual(conn.remote_address, ())
+ self.assertEqual(conn.status, "LISTEN")
+ # UDP v6
+ elif p.pid == getattr(udp6_proc, "pid", None):
+ self.assertEqual(conn.family, socket.AF_INET6)
+ self.assertEqual(conn.type, socket.SOCK_DGRAM)
+ self.assertTrue(conn.local_address[0] in ("::", "::1"))
+ self.assertEqual(conn.remote_address, ())
+ self.assertEqual(conn.status, "")
def test_parent_ppid(self):
this_parent = os.getpid()
@@ -762,68 +1232,11 @@ class TestCase(unittest.TestCase):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
p.suspend()
+ time.sleep(0.1)
+ self.assertEqual(p.status, psutil.STATUS_STOPPED)
+ self.assertEqual(str(p.status), "stopped")
p.resume()
-
- def test_get_pid_list(self):
- plist = [x.pid for x in psutil.get_process_list()]
- pidlist = psutil.get_pid_list()
- 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_types(self):
- sproc = get_test_subprocess()
- wait_for_pid(sproc.pid)
- p = psutil.Process(sproc.pid)
- self.assert_(isinstance(p.pid, int))
- self.assert_(isinstance(p.ppid, int))
- self.assert_(isinstance(p.parent, psutil.Process))
- self.assert_(isinstance(p.name, str))
- if self.__class__.__name__ != "LimitedUserTestCase":
- self.assert_(isinstance(p.exe, str))
- self.assert_(isinstance(p.cmdline, list))
- self.assert_(isinstance(p.uid, int))
- self.assert_(isinstance(p.gid, int))
- self.assert_(isinstance(p.create_time, float))
- self.assert_(isinstance(p.username, (unicode, str)))
- if hasattr(p, 'getcwd'):
- if not POSIX and self.__class__.__name__ != "LimitedUserTestCase":
- self.assert_(isinstance(p.getcwd(), str))
- if not POSIX and self.__class__.__name__ != "LimitedUserTestCase":
- self.assert_(isinstance(p.get_open_files(), list))
- for path, fd in p.get_open_files():
- self.assert_(isinstance(path, (unicode, str)))
- self.assert_(isinstance(fd, int))
- if not POSIX and self.__class__.__name__ != "LimitedUserTestCase" \
- and SUPPORT_CONNECTIONS:
- self.assert_(isinstance(p.get_connections(), list))
- self.assert_(isinstance(p.is_running(), bool))
- if not OSX or self.__class__.__name__ != "LimitedUserTestCase":
- self.assert_(isinstance(p.get_cpu_times(), tuple))
- self.assert_(isinstance(p.get_cpu_times()[0], float))
- self.assert_(isinstance(p.get_cpu_times()[1], float))
- self.assert_(isinstance(p.get_cpu_percent(0), float))
- self.assert_(isinstance(p.get_memory_info(), tuple))
- self.assert_(isinstance(p.get_memory_info()[0], int))
- self.assert_(isinstance(p.get_memory_info()[1], int))
- self.assert_(isinstance(p.get_memory_percent(), float))
- self.assert_(isinstance(p.get_num_threads(), int))
- self.assert_(isinstance(psutil.get_process_list(), list))
- self.assert_(isinstance(psutil.get_process_list()[0], psutil.Process))
- self.assert_(isinstance(psutil.process_iter(), types.GeneratorType))
- self.assert_(isinstance(psutil.process_iter().next(), psutil.Process))
- self.assert_(isinstance(psutil.get_pid_list(), list))
- self.assert_(isinstance(psutil.get_pid_list()[0], int))
- self.assert_(isinstance(psutil.pid_exists(1), bool))
+ self.assertTrue(p.status != psutil.STATUS_STOPPED)
def test_invalid_pid(self):
self.assertRaises(ValueError, psutil.Process, "1")
@@ -832,7 +1245,7 @@ class TestCase(unittest.TestCase):
self.assertRaises(psutil.NoSuchProcess, psutil.Process, -1)
def test_zombie_process(self):
- # Test that NoSuchProcess exception gets raised in the event the
+ # Test that NoSuchProcess exception gets raised in case the
# process dies after we create the Process object.
# Example:
# >>> proc = Process(1234)
@@ -842,103 +1255,126 @@ class TestCase(unittest.TestCase):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
p.kill()
- sproc.wait()
-
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "ppid")
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "parent")
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "name")
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "exe")
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "cmdline")
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "uid")
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "gid")
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "create_time")
- self.assertRaises(psutil.NoSuchProcess, getattr, p, "username")
- if hasattr(p, 'getcwd'):
- self.assertRaises(psutil.NoSuchProcess, p.getcwd)
- self.assertRaises(psutil.NoSuchProcess, p.get_open_files)
- self.assertRaises(psutil.NoSuchProcess, p.get_connections)
- self.assertRaises(psutil.NoSuchProcess, p.suspend)
- self.assertRaises(psutil.NoSuchProcess, p.resume)
- self.assertRaises(psutil.NoSuchProcess, p.kill)
- self.assertRaises(psutil.NoSuchProcess, p.terminate)
+ p.wait()
+
+ for name in dir(p):
+ if name.startswith('_')\
+ or name in ('pid', 'send_signal', 'is_running', 'set_ionice',
+ 'wait'):
+ continue
+ try:
+ meth = getattr(p, name)
+ if callable(meth):
+ meth()
+ except psutil.NoSuchProcess:
+ pass
+ else:
+ self.fail("NoSuchProcess exception not raised for %r" % name)
+
+ # other methods
+ try:
+ if os.name == 'posix':
+ p.nice = 1
+ else:
+ p.nice = psutil.NORMAL_PRIORITY_CLASS
+ except psutil.NoSuchProcess:
+ pass
+ else:
+ self.fail("exception not raised")
+ if hasattr(p, 'set_ionice'):
+ self.assertRaises(psutil.NoSuchProcess, p.set_ionice, 2)
self.assertRaises(psutil.NoSuchProcess, p.send_signal, signal.SIGTERM)
- self.assertRaises(psutil.NoSuchProcess, p.get_cpu_times)
- self.assertRaises(psutil.NoSuchProcess, p.get_cpu_percent, 0)
- self.assertRaises(psutil.NoSuchProcess, p.get_memory_info)
- self.assertRaises(psutil.NoSuchProcess, p.get_memory_percent)
- self.assertRaises(psutil.NoSuchProcess, p.get_children)
- self.assertRaises(psutil.NoSuchProcess, p.get_num_threads)
self.assertFalse(p.is_running())
def test__str__(self):
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
self.assertTrue(str(sproc.pid) in str(p))
- self.assertTrue(os.path.basename(PYTHON) in str(p))
+ # python shows up as 'Python' in cmdline on OS X so test fails on OS X
+ if not OSX:
+ self.assertTrue(os.path.basename(PYTHON) in str(p))
sproc = get_test_subprocess()
p = psutil.Process(sproc.pid)
p.kill()
- sproc.wait()
+ p.wait()
self.assertTrue(str(sproc.pid) in str(p))
self.assertTrue("terminated" in str(p))
def test_fetch_all(self):
valid_procs = 0
- attrs = ['__str__', 'create_time', 'username', 'getcwd', 'get_cpu_times',
- 'get_memory_info', 'get_memory_percent', 'get_open_files',
- 'get_num_threads']
+ excluded_names = ['send_signal', 'suspend', 'resume', 'terminate',
+ 'kill', 'wait']
+ excluded_names += ['get_cpu_percent', 'get_children']
+ # XXX - skip slow lsof implementation;
+ if BSD:
+ excluded_names += ['get_open_files', 'get_connections']
+ if OSX:
+ excluded_names += ['get_connections']
+ attrs = []
+ for name in dir(psutil.Process):
+ if name.startswith("_"):
+ continue
+ if name.startswith("set_"):
+ continue
+ if name in excluded_names:
+ continue
+ attrs.append(name)
+
for p in psutil.process_iter():
- for attr in attrs:
- # skip slow Python implementation; we're reasonably sure
- # it works anyway
- if POSIX and attr == 'get_open_files':
- continue
+ for name in attrs:
try:
- attr = getattr(p, attr, None)
- if attr is not None and callable(attr):
- attr()
- valid_procs += 1
- except (psutil.NoSuchProcess, psutil.AccessDenied), err:
- self.assertEqual(err.pid, p.pid)
- if err.name:
- self.assertEqual(err.name, p.name)
- self.assertTrue(str(err))
- self.assertTrue(err.msg)
- except:
+ try:
+ attr = getattr(p, name, None)
+ if attr is not None and callable(attr):
+ ret = attr()
+ else:
+ ret = attr
+ valid_procs += 1
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
+ err = sys.exc_info()[1]
+ self.assertEqual(err.pid, p.pid)
+ if err.name:
+ self.assertEqual(err.name, p.name)
+ self.assertTrue(str(err))
+ self.assertTrue(err.msg)
+ else:
+ if name == 'parent' or ret in (0, 0.0, [], None):
+ continue
+ self.assertTrue(ret)
+ if name == "exe":
+ self.assertTrue(os.path.isfile(ret))
+ elif name == "getcwd":
+ # XXX - temporary fix; on my Linux box
+ # chrome process cws is errnously reported
+ # as /proc/4144/fdinfo whichd doesn't exist
+ if 'chrome' in p.name:
+ continue
+ self.assertTrue(os.path.isdir(ret))
+ except Exception:
+ err = sys.exc_info()[1]
trace = traceback.format_exc()
- self.fail('Exception raised for method %s, pid %s:\n%s'
- %(attr, p.pid, trace))
+ self.fail('%s\nmethod=%s, pid=%s, retvalue=%s'
+ %(trace, name, p.pid, repr(ret)))
# we should always have a non-empty list, not including PID 0 etc.
# special cases.
self.assertTrue(valid_procs > 0)
+ @skipIf(LINUX)
def test_pid_0(self):
- # Process(0) is supposed to work on all platforms even if with
- # some differences
+ # Process(0) is supposed to work on all platforms except Linux
p = psutil.Process(0)
- if WINDOWS:
- self.assertEqual(p.name, 'System Idle Process')
- elif LINUX:
- self.assertEqual(p.name, 'sched')
- elif BSD:
- self.assertEqual(p.name, 'swapper')
- elif OSX:
- self.assertEqual(p.name, 'kernel_task')
+ self.assertTrue(p.name)
if os.name == 'posix':
- self.assertEqual(p.uid, 0)
- self.assertEqual(p.gid, 0)
- else:
- self.assertEqual(p.uid, -1)
- self.assertEqual(p.gid, -1)
+ self.assertEqual(p.uids.real, 0)
+ self.assertEqual(p.gids.real, 0)
self.assertTrue(p.ppid in (0, 1))
- self.assertEqual(p.exe, "")
+ #self.assertEqual(p.exe, "")
self.assertEqual(p.cmdline, [])
- # this can either raise AD (Win) or return 0 (UNIX)
try:
- self.assertTrue(p.get_num_threads() in (0, 1))
+ p.get_num_threads()
except psutil.AccessDenied:
pass
@@ -956,11 +1392,22 @@ class TestCase(unittest.TestCase):
else:
p.username
- # PID 0 is supposed to be available on all platforms
self.assertTrue(0 in psutil.get_pid_list())
self.assertTrue(psutil.pid_exists(0))
- # --- OS specific tests
+ def test_Popen(self):
+ # Popen class test
+ cmd = [PYTHON, "-c", "import time; time.sleep(3600);"]
+ proc = psutil.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ try:
+ proc.name
+ proc.stdin
+ self.assertTrue(hasattr(proc, 'name'))
+ self.assertTrue(hasattr(proc, 'stdin'))
+ self.assertRaises(AttributeError, getattr, proc, 'foo')
+ finally:
+ proc.kill()
+ proc.wait()
if hasattr(os, 'getuid'):
@@ -973,6 +1420,19 @@ if hasattr(os, 'getuid'):
PROCESS_UID = os.getuid()
PROCESS_GID = os.getgid()
+ def __init__(self, *args, **kwargs):
+ TestCase.__init__(self, *args, **kwargs)
+ # re-define all existent test methods in order to
+ # ignore AccessDenied exceptions
+ for attr in [x for x in dir(self) if x.startswith('test')]:
+ meth = getattr(self, attr)
+ def test_(self):
+ try:
+ meth()
+ except psutil.AccessDenied:
+ pass
+ setattr(self, attr, types.MethodType(test_, self))
+
def setUp(self):
os.setegid(1000)
os.seteuid(1000)
@@ -983,58 +1443,20 @@ if hasattr(os, 'getuid'):
os.seteuid(self.PROCESS_GID)
TestCase.tearDown(self)
- def test_path(self):
- # DeprecationWarning is only raised once
- pass
-
- # overridden tests known to raise AccessDenied when run
- # as limited user on different platforms
-
- if LINUX:
-
- def test_getcwd(self):
- self.assertRaises(psutil.AccessDenied, TestCase.test_getcwd, self)
-
- def test_getcwd_2(self):
- self.assertRaises(psutil.AccessDenied, TestCase.test_getcwd_2, self)
-
- def test_get_open_files(self):
- self.assertRaises(psutil.AccessDenied, TestCase.test_get_open_files, self)
-
- def test_get_connections(self):
+ def test_nice(self):
+ try:
+ psutil.Process(os.getpid()).nice = -1
+ except psutil.AccessDenied:
pass
-
- def test_exe(self):
- self.assertRaises(psutil.AccessDenied, TestCase.test_exe, self)
-
- if BSD:
-
- def test_get_open_files(self):
- self.assertRaises(psutil.AccessDenied, TestCase.test_get_open_files, self)
-
- def test_get_open_files2(self):
- self.assertRaises(psutil.AccessDenied, TestCase.test_get_open_files, self)
-
- def test_get_connections(self):
- self.assertRaises(psutil.AccessDenied, TestCase.test_get_connections, self)
-
- def test_connection_fromfd(self):
- self.assertRaises(psutil.AccessDenied, TestCase.test_connection_fromfd, self)
+ else:
+ self.fail("exception not raised")
def test_main():
tests = []
test_suite = unittest.TestSuite()
-
tests.append(TestCase)
- if hasattr(os, 'getuid'):
- if os.getuid() == 0:
- tests.append(LimitedUserTestCase)
- else:
- atexit.register(warnings.warn, "Couldn't run limited user tests ("
- "super-user privileges are required)", RuntimeWarning)
-
if POSIX:
from _posix import PosixSpecificTestCase
tests.append(PosixSpecificTestCase)
@@ -1050,13 +1472,22 @@ def test_main():
from _bsd import BSDSpecificTestCase as stc
tests.append(stc)
+ if hasattr(os, 'getuid'):
+ if os.getuid() == 0:
+ tests.append(LimitedUserTestCase)
+ else:
+ atexit.register(warnings.warn, "Couldn't run limited user tests ("
+ "super-user privileges are required)", RuntimeWarning)
+
for test_class in tests:
test_suite.addTest(unittest.makeSuite(test_class))
+ f = open(TESTFN, 'w')
+ f.close()
+ atexit.register(lambda: os.remove(TESTFN))
+
unittest.TextTestRunner(verbosity=2).run(test_suite)
DEVNULL.close()
if __name__ == '__main__':
test_main()
-
-