summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2019-04-05 01:33:35 +0200
committerGitHub <noreply@github.com>2019-04-05 01:33:35 +0200
commite471e7cbad9e2d84f9fb114da86df78755836852 (patch)
treef6b1f59ef6499470cdbd58ab8b1b5ed00de4ab4e
parentdf45572111dbce4a576d23648ef8b5b88e1df899 (diff)
downloadpsutil-e471e7cbad9e2d84f9fb114da86df78755836852.tar.gz
[Win] Process IO priority constants + high priority (#1479 / #1476)
-rw-r--r--HISTORY.rst3
-rw-r--r--docs/index.rst26
-rw-r--r--psutil/__init__.py4
-rw-r--r--psutil/_psutil_windows.c3
-rw-r--r--psutil/_pswindows.py50
-rwxr-xr-xpsutil/tests/test_process.py57
6 files changed, 95 insertions, 48 deletions
diff --git a/HISTORY.rst b/HISTORY.rst
index b01d8fea..1c745b8b 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -10,6 +10,9 @@
the number of physical CPUs in case /proc/cpuinfo does not provide this info.
- 1458_: provide coloured test output. Also show failures on KeyboardInterrupt.
- 1464_: various docfixes (always point to python3 doc, fix links, etc.).
+- 1473_: [Windows] process IO priority (ionice()) values are now exposed as 4
+ new constants: IOPRIO_VERYLOW, IOPRIO_LOW, IOPRIO_NORMAL, IOPRIO_HIGH.
+ Also it was not possible to set high I/O priority (not it is).
- 1478_: add make command to re-run tests failed on last run.
**Bug fixes**
diff --git a/docs/index.rst b/docs/index.rst
index 6ff1e22c..94713f54 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1245,13 +1245,16 @@ Process class
pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
>>>
- On Windows only *ioclass* is used and it can be set to ``2`` (normal),
- ``1`` (low) or ``0`` (very low). Also it returns an integer instead of a
- named tuple.
+ On Windows only *ioclass* is used and it can be set to ``3`` (high),
+ ``2`` (normal), ``1`` (low) or ``0`` (very low).
+ Also it returns an integer instead of a named tuple.
Availability: Linux and Windows > Vista
.. versionchanged::
+ Windows accepts ``3`` (high) value.
+
+ .. versionchanged::
3.0.0 on Python >= 3.4 the returned ``ioclass`` constant is an
`enum <https://docs.python.org/3/library/enum.html#module-enum>`__
instead of a plain integer.
@@ -2157,10 +2160,19 @@ Constants
Availability: Linux
- .. versionchanged::
- 3.0.0 on Python >= 3.4 these constants are
- `enums <https://docs.python.org/3/library/enum.html#module-enum>`__
- instead of a plain integer.
+.. _const-ioprio:
+.. data:: IOPRIO_VERYLOW
+.. data:: IOPRIO_LOW
+.. data:: IOPRIO_NORMAL
+.. data:: IOPRIO_HIGH
+
+ A set of integers representing the I/O priority of a process on Linux.
+ They can be used in conjunction with :meth:`psutil.Process.ionice()` to get
+ or set process I/O priority.
+
+ Availability: Windows
+
+ .. versionadded:: 5.6.2
.. _const-rlimit:
.. data:: RLIM_INFINITY
diff --git a/psutil/__init__.py b/psutil/__init__.py
index ab2ed349..2f33436c 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -146,6 +146,10 @@ elif WINDOWS:
from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA
from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA
from ._pswindows import CONN_DELETE_TCB # NOQA
+ from ._pswindows import IOPRIO_VERYLOW # NOQA
+ from ._pswindows import IOPRIO_LOW # NOQA
+ from ._pswindows import IOPRIO_NORMAL # NOQA
+ from ._pswindows import IOPRIO_HIGH # NOQA
elif MACOS:
from . import _psosx as _psplatform
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index b1f8d650..a1a68857 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -3685,7 +3685,8 @@ void init_psutil_windows(void)
module, "ERROR_INVALID_NAME", ERROR_INVALID_NAME);
PyModule_AddIntConstant(
module, "ERROR_SERVICE_DOES_NOT_EXIST", ERROR_SERVICE_DOES_NOT_EXIST);
-
+ PyModule_AddIntConstant(
+ module, "ERROR_PRIVILEGE_NOT_HELD", ERROR_PRIVILEGE_NOT_HELD);
PyModule_AddIntConstant(
module, "WINVER", PSUTIL_WINVER);
PyModule_AddIntConstant(
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index 260651d1..929e27d7 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -63,11 +63,14 @@ else:
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
__extra__all__ = [
"win_service_iter", "win_service_get",
+ # Process priority
"ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
- "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
- "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
- "CONN_DELETE_TCB",
- "AF_LINK",
+ "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", "NORMAL_PRIORITY_CLASS",
+ "REALTIME_PRIORITY_CLASS",
+ # IO priority
+ "IOPRIO_VERYLOW", "IOPRIO_LOW", "IOPRIO_NORMAL", "IOPRIO_HIGH",
+ # others
+ "CONN_DELETE_TCB", "AF_LINK",
]
@@ -112,6 +115,19 @@ if enum is not None:
globals().update(Priority.__members__)
+if enum is None:
+ IOPRIO_VERYLOW = 0
+ IOPRIO_LOW = 1
+ IOPRIO_NORMAL = 2
+ IOPRIO_HIGH = 3
+else:
+ class IOPriority(enum.IntEnum):
+ IOPRIO_VERYLOW = 0
+ IOPRIO_LOW = 1
+ IOPRIO_NORMAL = 2
+ IOPRIO_HIGH = 3
+ globals().update(IOPriority.__members__)
+
pinfo_map = dict(
num_handles=0,
ctx_switches=1,
@@ -656,8 +672,12 @@ ppid_map = cext.ppid_map # used internally by Process.children()
def is_permission_err(exc):
"""Return True if this is a permission error."""
assert isinstance(exc, OSError), exc
+ # On Python 2 OSError doesn't always have 'winerror'. Sometimes
+ # it does, in which case the original exception was WindowsError
+ # (which is a subclass of OSError).
return exc.errno in (errno.EPERM, errno.EACCES) or \
- exc.winerror == cext.ERROR_ACCESS_DENIED
+ getattr(exc, "winerror", -1) in (cext.ERROR_ACCESS_DENIED,
+ cext.ERROR_PRIVILEGE_NOT_HELD)
def convert_oserror(exc, pid=None, name=None):
@@ -981,17 +1001,19 @@ class Process(object):
if HAS_PROC_IO_PRIORITY:
@wrap_exceptions
def ionice_get(self):
- return cext.proc_io_priority_get(self.pid)
+ ret = cext.proc_io_priority_get(self.pid)
+ if enum is not None:
+ ret = IOPriority(ret)
+ return ret
@wrap_exceptions
- def ionice_set(self, value, _):
- if _:
- raise TypeError("set_proc_ionice() on Windows takes only "
- "1 argument (2 given)")
- if value not in (2, 1, 0):
- raise ValueError("value must be 2 (normal), 1 (low) or 0 "
- "(very low); got %r" % value)
- return cext.proc_io_priority_set(self.pid, value)
+ def ionice_set(self, ioclass, value):
+ if value:
+ raise TypeError("value argument not accepted on Windows")
+ if ioclass not in (IOPRIO_VERYLOW, IOPRIO_LOW, IOPRIO_NORMAL,
+ IOPRIO_HIGH):
+ raise ValueError("%s is not a valid priority" % ioclass)
+ cext.proc_io_priority_set(self.pid, ioclass)
@wrap_exceptions
def io_counters(self):
diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py
index d264ce6d..753bf612 100755
--- a/psutil/tests/test_process.py
+++ b/psutil/tests/test_process.py
@@ -380,29 +380,7 @@ class TestProcess(unittest.TestCase):
(psutil.IOPRIO_CLASS_RT, 7))
with self.assertRaises(ValueError):
p.ionice(psutil.IOPRIO_CLASS_IDLE, value=8)
- finally:
- p.ionice(psutil.IOPRIO_CLASS_BE)
-
- @unittest.skipIf(not HAS_IONICE, "not supported")
- @unittest.skipIf(not WINDOWS, 'not supported on this win version')
- def test_ionice_win(self):
- p = psutil.Process()
- original = p.ionice()
- self.assertIsInstance(original, int)
- try:
- value = 0 # very low
- if original == value:
- value = 1 # low
- p.ionice(value)
- self.assertEqual(p.ionice(), value)
- finally:
- p.ionice(original)
-
- @unittest.skipIf(not HAS_IONICE, "not supported")
- def test_ionice_errs(self):
- sproc = get_test_subprocess()
- p = psutil.Process(sproc.pid)
- if LINUX:
+ # errs
self.assertRaises(ValueError, p.ionice, 2, 10)
self.assertRaises(ValueError, p.ionice, 2, -1)
self.assertRaises(ValueError, p.ionice, 4)
@@ -416,9 +394,36 @@ class TestProcess(unittest.TestCase):
self.assertRaisesRegex(
ValueError, "'ioclass' argument must be specified",
p.ionice, value=1)
- else:
- self.assertRaises(ValueError, p.ionice, 3)
- self.assertRaises(TypeError, p.ionice, 2, 1)
+ finally:
+ p.ionice(psutil.IOPRIO_CLASS_BE)
+
+ @unittest.skipIf(not HAS_IONICE, "not supported")
+ @unittest.skipIf(not WINDOWS, 'not supported on this win version')
+ def test_ionice_win(self):
+ p = psutil.Process()
+ self.assertEqual(p.ionice(), psutil.IOPRIO_NORMAL)
+ try:
+ # base
+ p.ionice(psutil.IOPRIO_VERYLOW)
+ self.assertEqual(p.ionice(), psutil.IOPRIO_VERYLOW)
+ p.ionice(psutil.IOPRIO_LOW)
+ self.assertEqual(p.ionice(), psutil.IOPRIO_LOW)
+ try:
+ p.ionice(psutil.IOPRIO_HIGH)
+ except psutil.AccessDenied:
+ pass
+ else:
+ self.assertEqual(p.ionice(), psutil.IOPRIO_HIGH)
+ # errs
+ self.assertRaisesRegex(
+ TypeError, "value argument not accepted on Windows",
+ p.ionice, psutil.IOPRIO_NORMAL, value=1)
+ self.assertRaisesRegex(
+ ValueError, "is not a valid priority",
+ p.ionice, psutil.IOPRIO_HIGH + 1)
+ finally:
+ p.ionice(psutil.IOPRIO_NORMAL)
+ self.assertEqual(p.ionice(), psutil.IOPRIO_NORMAL)
@unittest.skipIf(not HAS_RLIMIT, "not supported")
def test_rlimit_get(self):