Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FreeBSD] process resource limits #1859

Merged
merged 10 commits into from
Oct 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ XXXX-XX-XX

**Enhancements**

- 893_: implement `Process.environ()` on BSD family. (patch by Armin Gruner)
- 809_: [FreeBSD] add support for `Process.rlimit()`.
- 893_: [BSD] add support for `Process.environ()` (patch by Armin Gruner)
- 1830_: [UNIX] `net_if_stats()`'s `isup` also checks whether the NIC is
running (meaning Wi-Fi or ethernet cable is connected). (patch by Chris Burger)
- 1837_: [Linux] improved battery detection and charge "secsleft" calculation
Expand Down
2 changes: 1 addition & 1 deletion docs/_static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
}

.rst-content dl:not(.docutils) {
margin: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px !important;
}

.data dd {
Expand Down
85 changes: 48 additions & 37 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1348,16 +1348,17 @@ Process class

>>> import psutil
>>> p = psutil.Process()
>>> # process may open no more than 128 file descriptors
>>> p.rlimit(psutil.RLIMIT_NOFILE, (128, 128))
>>> # process may create files no bigger than 1024 bytes
>>> p.rlimit(psutil.RLIMIT_FSIZE, (1024, 1024))
>>> # get
>>> p.rlimit(psutil.RLIMIT_FSIZE)
>>> p.rlimit(psutil.RLIMIT_NOFILE, (128, 128)) # process can open max 128 file descriptors
>>> p.rlimit(psutil.RLIMIT_FSIZE, (1024, 1024)) # can create files no bigger than 1024 bytes
>>> p.rlimit(psutil.RLIMIT_FSIZE) # get
(1024, 1024)
>>>

Availability: Linux
Also see `procinfo.py`_ script.

Availability: Linux, FreeBSD

.. versionchanged:: 5.7.3 added FreeBSD support

.. method:: io_counters()

Expand Down Expand Up @@ -2247,29 +2248,43 @@ Process priority constants
Process resources constants
---------------------------

.. data:: RLIM_INFINITY
.. data:: RLIMIT_AS
.. data:: RLIMIT_CORE
.. data:: RLIMIT_CPU
.. data:: RLIMIT_DATA
.. data:: RLIMIT_FSIZE
.. data:: RLIMIT_LOCKS
.. data:: RLIMIT_MEMLOCK
.. data:: RLIMIT_MSGQUEUE
.. data:: RLIMIT_NICE
.. data:: RLIMIT_NOFILE
.. data:: RLIMIT_NPROC
.. data:: RLIMIT_RSS
.. data:: RLIMIT_RTPRIO
.. data:: RLIMIT_RTTIME
.. data:: RLIMIT_SIGPENDING
.. data:: RLIMIT_STACK

Constants used for getting and setting process resource limits to be used in
conjunction with :meth:`psutil.Process.rlimit()`. See `man prlimit`_ for
further information.
Linux / FreeBSD:

Availability: Linux
.. data:: RLIM_INFINITY
.. data:: RLIMIT_AS
.. data:: RLIMIT_CORE
.. data:: RLIMIT_CPU
.. data:: RLIMIT_DATA
.. data:: RLIMIT_FSIZE
.. data:: RLIMIT_MEMLOCK
.. data:: RLIMIT_NOFILE
.. data:: RLIMIT_NPROC
.. data:: RLIMIT_RSS
.. data:: RLIMIT_STACK

Linux specific:

.. data:: RLIMIT_LOCKS
.. data:: RLIMIT_MSGQUEUE
.. data:: RLIMIT_NICE
.. data:: RLIMIT_RTPRIO
.. data:: RLIMIT_RTTIME
.. data:: RLIMIT_SIGPENDING

FreeBSD specific:

.. data:: RLIMIT_SWAP
.. data:: RLIMIT_SBSIZE
.. data:: RLIMIT_NPTS

Constants used for getting and setting process resource limits to be used in
conjunction with :meth:`psutil.Process.rlimit()`. See `resource.getrlimit`_
for further information.

Availability: Linux, FreeBSD

.. versionchanged:: 5.7.3 added FreeBSD support, added ``RLIMIT_SWAP``,
``RLIMIT_SBSIZE``, ``RLIMIT_NPTS``.

Connections constants
---------------------
Expand Down Expand Up @@ -2513,11 +2528,6 @@ Security
To report a security vulnerability, please use the `Tidelift security
contact`_. Tidelift will coordinate the fix and disclosure.

.. _`Giampaolo Rodola`: https://gmpy.dev/about
.. _`donation`: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
.. _Tidelift security contact: https://tidelift.com/security
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme

Development guide
=================

Expand Down Expand Up @@ -2874,13 +2884,12 @@ Timeline
.. _`cpu_distribution.py`: https://github.com/giampaolo/psutil/blob/master/scripts/cpu_distribution.py
.. _`development guide`: https://github.com/giampaolo/psutil/blob/master/docs/DEVGUIDE.rst
.. _`disk_usage.py`: https://github.com/giampaolo/psutil/blob/master/scripts/disk_usage.py
.. _`donation`: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
.. _`enum`: https://docs.python.org/3/library/enum.html#module-enum
.. _`fans.py`: https://github.com/giampaolo/psutil/blob/master/scripts/fans.py
.. _`GetDriveType`: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getdrivetypea
.. _`GetExitCodeProcess`: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess
.. _`getfsstat`: http://www.manpagez.com/man/2/getfsstat/
.. _`GetPriorityClass`: https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getpriorityclass
.. _`GetExitCodeProcess`: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess
.. _`Giampaolo Rodola`: https://gmpy.dev/about
.. _`hash`: https://docs.python.org/3/library/functions.html#hash
.. _`ifconfig.py`: https://github.com/giampaolo/psutil/blob/master/scripts/ifconfig.py
Expand Down Expand Up @@ -2908,6 +2917,7 @@ Timeline
.. _`os.times`: https://docs.python.org//library/os.html#os.times
.. _`pmap.py`: https://github.com/giampaolo/psutil/blob/master/scripts/pmap.py
.. _`PROCESS_MEMORY_COUNTERS_EX`: https://docs.microsoft.com/en-us/windows/desktop/api/psapi/ns-psapi-_process_memory_counters_ex
.. _`procinfo.py`: https://github.com/giampaolo/psutil/blob/master/scripts/procinfo.py
.. _`procsmem.py`: https://github.com/giampaolo/psutil/blob/master/scripts/procsmem.py
.. _`resource.getrlimit`: https://docs.python.org/3/library/resource.html#resource.getrlimit
.. _`resource.setrlimit`: https://docs.python.org/3/library/resource.html#resource.setrlimit
Expand All @@ -2920,9 +2930,10 @@ Timeline
.. _`SOCK_SEQPACKET`: https://docs.python.org/3/library/socket.html#socket.SOCK_SEQPACKET
.. _`SOCK_STREAM`: https://docs.python.org/3/library/socket.html#socket.SOCK_STREAM
.. _`socket.fromfd`: https://docs.python.org/3/library/socket.html#socket.fromfd
.. _`subprocess.Popen`: https://docs.python.org/3/library/subprocess.html#subprocess.Popen
.. _`subprocess.Popen.wait`: https://docs.python.org/3/library/subprocess.html#subprocess.Popen.wait
.. _`subprocess.Popen`: https://docs.python.org/3/library/subprocess.html#subprocess.Popen
.. _`temperatures.py`: https://github.com/giampaolo/psutil/blob/master/scripts/temperatures.py
.. _`TerminateProcess`: https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-terminateprocess
.. _Tidelift security contact: https://tidelift.com/security
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
72 changes: 25 additions & 47 deletions psutil/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,44 +102,6 @@
from ._pslinux import IOPRIO_CLASS_IDLE # NOQA
from ._pslinux import IOPRIO_CLASS_NONE # NOQA
from ._pslinux import IOPRIO_CLASS_RT # NOQA
# Linux >= 2.6.36
if _psplatform.HAS_PRLIMIT:
from ._psutil_linux import RLIM_INFINITY # NOQA
from ._psutil_linux import RLIMIT_AS # NOQA
from ._psutil_linux import RLIMIT_CORE # NOQA
from ._psutil_linux import RLIMIT_CPU # NOQA
from ._psutil_linux import RLIMIT_DATA # NOQA
from ._psutil_linux import RLIMIT_FSIZE # NOQA
from ._psutil_linux import RLIMIT_LOCKS # NOQA
from ._psutil_linux import RLIMIT_MEMLOCK # NOQA
from ._psutil_linux import RLIMIT_NOFILE # NOQA
from ._psutil_linux import RLIMIT_NPROC # NOQA
from ._psutil_linux import RLIMIT_RSS # NOQA
from ._psutil_linux import RLIMIT_STACK # NOQA
# Kinda ugly but considerably faster than using hasattr() and
# setattr() against the module object (we are at import time:
# speed matters).
from . import _psutil_linux
try:
RLIMIT_MSGQUEUE = _psutil_linux.RLIMIT_MSGQUEUE
except AttributeError:
pass
try:
RLIMIT_NICE = _psutil_linux.RLIMIT_NICE
except AttributeError:
pass
try:
RLIMIT_RTPRIO = _psutil_linux.RLIMIT_RTPRIO
except AttributeError:
pass
try:
RLIMIT_RTTIME = _psutil_linux.RLIMIT_RTTIME
except AttributeError:
pass
try:
RLIMIT_SIGPENDING = _psutil_linux.RLIMIT_SIGPENDING
except AttributeError:
pass

elif WINDOWS:
from . import _pswindows as _psplatform
Expand Down Expand Up @@ -197,6 +159,7 @@
"CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1",
"CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT",
"CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE",
# "CONN_IDLE", "CONN_BOUND",

"AF_LINK",

Expand All @@ -207,6 +170,11 @@
"BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "MACOS", "OSX", "POSIX",
"SUNOS", "WINDOWS", "AIX",

# "RLIM_INFINITY", "RLIMIT_AS", "RLIMIT_CORE", "RLIMIT_CPU", "RLIMIT_DATA",
# "RLIMIT_FSIZE", "RLIMIT_LOCKS", "RLIMIT_MEMLOCK", "RLIMIT_NOFILE",
# "RLIMIT_NPROC", "RLIMIT_RSS", "RLIMIT_STACK", "RLIMIT_MSGQUEUE",
# "RLIMIT_NICE", "RLIMIT_RTPRIO", "RLIMIT_RTTIME", "RLIMIT_SIGPENDING",

# classes
"Process", "Popen",

Expand All @@ -222,9 +190,22 @@
"users", "boot_time", # others
]

__all__.extend(_psplatform.__extra__all__)

if LINUX or FREEBSD:
# Populate global namespace with RLIM* constants.
from . import _psutil_posix

_globals = globals()
_name = None
for _name in dir(_psutil_posix):
if _name.startswith('RLIM') and _name.isupper():
_globals[_name] = getattr(_psutil_posix, _name)
__all__.append(_name)
del _globals, _name

AF_LINK = _psplatform.AF_LINK

__all__.extend(_psplatform.__extra__all__)
__author__ = "Giampaolo Rodola'"
__version__ = "5.7.3"
version_info = tuple([int(num) for num in __version__.split('.')])
Expand Down Expand Up @@ -801,23 +782,20 @@ def ionice(self, ioclass=None, value=None):
else:
return self._proc.ionice_set(ioclass, value)

# Linux only
# Linux / FreeBSD only
if hasattr(_psplatform.Process, "rlimit"):

def rlimit(self, resource, limits=None):
"""Get or set process resource limits as a (soft, hard)
tuple.

*resource* is one of the RLIMIT_* constants.
*limits* is supposed to be a (soft, hard) tuple.
*limits* is supposed to be a (soft, hard) tuple.

See "man prlimit" for further info.
Available on Linux only.
Available on Linux and FreeBSD only.
"""
if limits is None:
return self._proc.rlimit(resource)
else:
return self._proc.rlimit(resource, limits)
return self._proc.rlimit(resource, limits)

# Windows, Linux and FreeBSD only
if hasattr(_psplatform.Process, "cpu_affinity_get"):
Expand All @@ -831,7 +809,7 @@ def cpu_affinity(self, cpus=None):
(Windows, Linux and BSD only).
"""
if cpus is None:
return list(set(self._proc.cpu_affinity_get()))
return sorted(set(self._proc.cpu_affinity_get()))
else:
if not cpus:
if hasattr(self._proc, "_get_eligible_cpus"):
Expand Down
12 changes: 12 additions & 0 deletions psutil/_psbsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -904,3 +904,15 @@ def cpu_affinity_set(self, cpus):
@wrap_exceptions
def memory_maps(self):
return cext.proc_memory_maps(self.pid)

@wrap_exceptions
def rlimit(self, resource, limits=None):
if limits is None:
return cext.proc_getrlimit(self.pid, resource)
else:
if len(limits) != 2:
raise ValueError(
"second argument must be a (soft, hard) tuple, "
"got %s" % repr(limits))
soft, hard = limits
return cext.proc_setrlimit(self.pid, resource, soft, hard)
6 changes: 0 additions & 6 deletions psutil/_pslinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,6 @@
HAS_CPU_AFFINITY = hasattr(cext, "proc_cpu_affinity_get")
_DEFAULT = object()

# RLIMIT_* constants, not guaranteed to be present on all kernels
if HAS_PRLIMIT:
for name in dir(cext):
if name.startswith('RLIM'):
__extra__all__.append(name)

# Number of clock ticks per second
CLOCK_TICKS = os.sysconf("SC_CLK_TCK")
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
Expand Down
4 changes: 4 additions & 0 deletions psutil/_psutil_bsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,10 @@ static PyMethodDef mod_methods[] = {
"Return process CPU affinity."},
{"proc_cpu_affinity_set", psutil_proc_cpu_affinity_set, METH_VARARGS,
"Set process CPU affinity."},
{"proc_getrlimit", psutil_proc_getrlimit, METH_VARARGS,
"Get process resource limits."},
{"proc_setrlimit", psutil_proc_setrlimit, METH_VARARGS,
"Set process resource limits."},
{"cpu_count_phys", psutil_cpu_count_phys, METH_VARARGS,
"Return an XML string to determine the number physical CPUs."},
#endif
Expand Down
43 changes: 0 additions & 43 deletions psutil/_psutil_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,6 @@ static PyMethodDef mod_methods[] = {
void init_psutil_linux(void)
#endif /* PY_MAJOR_VERSION */
{
PyObject *v;
#if PY_MAJOR_VERSION >= 3
PyObject *mod = PyModule_Create(&moduledef);
#else
Expand All @@ -616,48 +615,6 @@ static PyMethodDef mod_methods[] = {
INITERR;

if (PyModule_AddIntConstant(mod, "version", PSUTIL_VERSION)) INITERR;
#if PSUTIL_HAVE_PRLIMIT
if (PyModule_AddIntConstant(mod, "RLIMIT_AS", RLIMIT_AS)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_CORE", RLIMIT_CORE)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_CPU", RLIMIT_CPU)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_DATA", RLIMIT_DATA)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_FSIZE", RLIMIT_FSIZE)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_LOCKS", RLIMIT_LOCKS)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_NOFILE", RLIMIT_NOFILE)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_NPROC", RLIMIT_NPROC)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_RSS", RLIMIT_RSS)) INITERR;
if (PyModule_AddIntConstant(mod, "RLIMIT_STACK", RLIMIT_STACK)) INITERR;

#if defined(HAVE_LONG_LONG)
if (sizeof(RLIM_INFINITY) > sizeof(long)) {
v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY);
} else
#endif
{
v = PyLong_FromLong((long) RLIM_INFINITY);
}
if (v) {
PyModule_AddObject(mod, "RLIM_INFINITY", v);
}

#ifdef RLIMIT_MSGQUEUE
if (PyModule_AddIntConstant(mod, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE)) INITERR;
#endif
#ifdef RLIMIT_NICE
if (PyModule_AddIntConstant(mod, "RLIMIT_NICE", RLIMIT_NICE)) INITERR;
#endif
#ifdef RLIMIT_RTPRIO
if (PyModule_AddIntConstant(mod, "RLIMIT_RTPRIO", RLIMIT_RTPRIO)) INITERR;
#endif
#ifdef RLIMIT_RTTIME
if (PyModule_AddIntConstant(mod, "RLIMIT_RTTIME", RLIMIT_RTTIME)) INITERR;
#endif
#ifdef RLIMIT_SIGPENDING
if (PyModule_AddIntConstant(mod, "RLIMIT_SIGPENDING", RLIMIT_SIGPENDING))
INITERR;
#endif
#endif
if (PyModule_AddIntConstant(mod, "DUPLEX_HALF", DUPLEX_HALF)) INITERR;
if (PyModule_AddIntConstant(mod, "DUPLEX_FULL", DUPLEX_FULL)) INITERR;
if (PyModule_AddIntConstant(mod, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN)) INITERR;
Expand Down
Loading