Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b7bd5df

Browse files
committed
Issue #16595: Add prlimit() to resource module
prlimit() is a Linux specific command that combines setrlimit, getrlimit and can set the limit of other processes.
1 parent 6fc79bf commit b7bd5df

8 files changed

Lines changed: 169 additions & 26 deletions

File tree

Doc/library/resource.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,27 @@ this module for those platforms.
7474
``setrlimit`` may also raise :exc:`error` if the underlying system call
7575
fails.
7676

77+
.. function:: prlimit(pid, resource[, limits])
78+
79+
Combines :func:`setrlimit` and :func:`getrlimit` in one function and
80+
supports to get and set the resources limits of an arbitrary process. If
81+
*pid* is 0, then the call applies to the current process. *resource* and
82+
*limits* have the same meaning as in :func:`setrlimit`, except that
83+
*limits* is optional.
84+
85+
When *limits* is not given the function returns the *resource* limit of the
86+
process *pid*. When *limits* is given the *resource* limit of the process is
87+
set and the former resource limit is returned.
88+
89+
Raises :exc:`ProcessLookupError` when *pid* can't be found and
90+
:exc:`PermissionError` when the user doesn't have ``CAP_SYS_RESOURCE`` for
91+
the process.
92+
93+
Availability: Linux (glibc 2.13+)
94+
95+
.. versionadded:: 3.4
96+
97+
7798
These symbols define resources whose consumption can be controlled using the
7899
:func:`setrlimit` and :func:`getrlimit` functions described below. The values of
79100
these symbols are exactly the constants used by C programs.

Doc/whatsnew/3.4.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,12 @@ The :mod:`pprint` module now supports *compact* mode for formatting long
438438
sequences (:issue:`19132`).
439439

440440

441+
resource
442+
--------
443+
444+
New :func:`resource.prlimit` function and Linux specific constants.
445+
(Contributed by Christian Heimes in :issue:`16595` and :issue:`19324`.)
446+
441447
smtplib
442448
-------
443449

Lib/test/test_resource.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,18 @@ def test_linux_constants(self):
139139
self.assertIsInstance(resource.RLIMIT_SIGPENDING, int)
140140

141141

142+
@unittest.skipUnless(hasattr(resource, 'prlimit'), 'no prlimit')
143+
def test_prlimit(self):
144+
self.assertRaises(TypeError, resource.prlimit)
145+
self.assertRaises(PermissionError, resource.prlimit,
146+
1, resource.RLIMIT_AS)
147+
self.assertRaises(ProcessLookupError, resource.prlimit,
148+
-1, resource.RLIMIT_AS)
149+
self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS), (-1, -1))
150+
self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, (-1, -1)),
151+
(-1, -1))
152+
153+
142154
def test_main(verbose=None):
143155
support.run_unittest(ResourceTest)
144156

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Core and Builtins
1919
Library
2020
-------
2121

22+
- Issue #16595: Add prlimit() to resource module.
23+
2224
- Issue #19324: Expose Linux-specific constants in resource module.
2325

2426
- Issue #17400: ipaddress should make it easy to identify rfc6598 addresses.

Modules/resource.c

Lines changed: 86 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,44 @@ resource_getrusage(PyObject *self, PyObject *args)
106106
return result;
107107
}
108108

109+
static int
110+
py2rlimit(PyObject *curobj, PyObject *maxobj, struct rlimit *rl_out)
111+
{
112+
#if !defined(HAVE_LARGEFILE_SUPPORT)
113+
rl_out->rlim_cur = PyLong_AsLong(curobj);
114+
if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
115+
return -1;
116+
rl_out->rlim_max = PyLong_AsLong(maxobj);
117+
if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
118+
return -1;
119+
#else
120+
/* The limits are probably bigger than a long */
121+
rl_out->rlim_cur = PyLong_AsLongLong(curobj);
122+
if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
123+
return -1;
124+
rl_out->rlim_max = PyLong_AsLongLong(maxobj);
125+
if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
126+
return -1;
127+
#endif
128+
129+
rl_out->rlim_cur = rl_out->rlim_cur & RLIM_INFINITY;
130+
rl_out->rlim_max = rl_out->rlim_max & RLIM_INFINITY;
131+
return 0;
132+
133+
}
134+
135+
static PyObject*
136+
rlimit2py(struct rlimit rl)
137+
{
138+
#if defined(HAVE_LONG_LONG)
139+
if (sizeof(rl.rlim_cur) > sizeof(long)) {
140+
return Py_BuildValue("LL",
141+
(PY_LONG_LONG) rl.rlim_cur,
142+
(PY_LONG_LONG) rl.rlim_max);
143+
}
144+
#endif
145+
return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max);
146+
}
109147

110148
static PyObject *
111149
resource_getrlimit(PyObject *self, PyObject *args)
@@ -126,15 +164,7 @@ resource_getrlimit(PyObject *self, PyObject *args)
126164
PyErr_SetFromErrno(PyExc_OSError);
127165
return NULL;
128166
}
129-
130-
#if defined(HAVE_LONG_LONG)
131-
if (sizeof(rl.rlim_cur) > sizeof(long)) {
132-
return Py_BuildValue("LL",
133-
(PY_LONG_LONG) rl.rlim_cur,
134-
(PY_LONG_LONG) rl.rlim_max);
135-
}
136-
#endif
137-
return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max);
167+
return rlimit2py(rl);
138168
}
139169

140170
static PyObject *
@@ -166,25 +196,10 @@ resource_setrlimit(PyObject *self, PyObject *args)
166196
curobj = PyTuple_GET_ITEM(limits, 0);
167197
maxobj = PyTuple_GET_ITEM(limits, 1);
168198

169-
#if !defined(HAVE_LARGEFILE_SUPPORT)
170-
rl.rlim_cur = PyLong_AsLong(curobj);
171-
if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
172-
goto error;
173-
rl.rlim_max = PyLong_AsLong(maxobj);
174-
if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
175-
goto error;
176-
#else
177-
/* The limits are probably bigger than a long */
178-
rl.rlim_cur = PyLong_AsLongLong(curobj);
179-
if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
199+
if (py2rlimit(curobj, maxobj, &rl) < 0) {
180200
goto error;
181-
rl.rlim_max = PyLong_AsLongLong(maxobj);
182-
if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
183-
goto error;
184-
#endif
201+
}
185202

186-
rl.rlim_cur = rl.rlim_cur & RLIM_INFINITY;
187-
rl.rlim_max = rl.rlim_max & RLIM_INFINITY;
188203
if (setrlimit(resource, &rl) == -1) {
189204
if (errno == EINVAL)
190205
PyErr_SetString(PyExc_ValueError,
@@ -205,6 +220,48 @@ resource_setrlimit(PyObject *self, PyObject *args)
205220
return NULL;
206221
}
207222

223+
#ifdef HAVE_PRLIMIT
224+
static PyObject *
225+
resource_prlimit(PyObject *self, PyObject *args)
226+
{
227+
struct rlimit old_limit, new_limit;
228+
int resource, retval;
229+
pid_t pid;
230+
PyObject *curobj=NULL, *maxobj=NULL;
231+
232+
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|(OO):prlimit",
233+
&pid, &resource, &curobj, &maxobj))
234+
return NULL;
235+
236+
if (resource < 0 || resource >= RLIM_NLIMITS) {
237+
PyErr_SetString(PyExc_ValueError,
238+
"invalid resource specified");
239+
return NULL;
240+
}
241+
242+
if (curobj != NULL) {
243+
if (py2rlimit(curobj, maxobj, &new_limit) < 0) {
244+
return NULL;
245+
}
246+
retval = prlimit(pid, resource, &new_limit, &old_limit);
247+
}
248+
else {
249+
retval = prlimit(pid, resource, NULL, &old_limit);
250+
}
251+
252+
if (retval == -1) {
253+
if (errno == EINVAL) {
254+
PyErr_SetString(PyExc_ValueError,
255+
"current limit exceeds maximum limit");
256+
} else {
257+
PyErr_SetFromErrno(PyExc_OSError);
258+
}
259+
return NULL;
260+
}
261+
return rlimit2py(old_limit);
262+
}
263+
#endif /* HAVE_PRLIMIT */
264+
208265
static PyObject *
209266
resource_getpagesize(PyObject *self, PyObject *unused)
210267
{
@@ -229,6 +286,9 @@ static struct PyMethodDef
229286
resource_methods[] = {
230287
{"getrusage", resource_getrusage, METH_VARARGS},
231288
{"getrlimit", resource_getrlimit, METH_VARARGS},
289+
#ifdef HAVE_PRLIMIT
290+
{"prlimit", resource_prlimit, METH_VARARGS},
291+
#endif
232292
{"setrlimit", resource_setrlimit, METH_VARARGS},
233293
{"getpagesize", resource_getpagesize, METH_NOARGS},
234294
{NULL, NULL} /* sentinel */

configure

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10601,6 +10601,35 @@ $as_echo "no" >&6; }
1060110601

1060210602
fi
1060310603
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
10604+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for prlimit" >&5
10605+
$as_echo_n "checking for prlimit... " >&6; }
10606+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
10607+
/* end confdefs.h. */
10608+
10609+
#include <sys/time.h>
10610+
#include <sys/resource.h>
10611+
10612+
int
10613+
main ()
10614+
{
10615+
void *x=prlimit
10616+
;
10617+
return 0;
10618+
}
10619+
_ACEOF
10620+
if ac_fn_c_try_compile "$LINENO"; then :
10621+
10622+
$as_echo "#define HAVE_PRLIMIT 1" >>confdefs.h
10623+
10624+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
10625+
$as_echo "yes" >&6; }
10626+
else
10627+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
10628+
$as_echo "no" >&6; }
10629+
10630+
fi
10631+
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
10632+
1060410633
# On some systems (eg. FreeBSD 5), we would find a definition of the
1060510634
# functions ctermid_r, setgroups in the library, but no prototype
1060610635
# (e.g. because we use _XOPEN_SOURCE). See whether we can take their

configure.ac

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2927,6 +2927,16 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
29272927
AC_MSG_RESULT(yes)],
29282928
[AC_MSG_RESULT(no)
29292929
])
2930+
AC_MSG_CHECKING(for prlimit)
2931+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
2932+
#include <sys/time.h>
2933+
#include <sys/resource.h>
2934+
]], [[void *x=prlimit]])],
2935+
[AC_DEFINE(HAVE_PRLIMIT, 1, Define if you have the 'prlimit' functions.)
2936+
AC_MSG_RESULT(yes)],
2937+
[AC_MSG_RESULT(no)
2938+
])
2939+
29302940
# On some systems (eg. FreeBSD 5), we would find a definition of the
29312941
# functions ctermid_r, setgroups in the library, but no prototype
29322942
# (e.g. because we use _XOPEN_SOURCE). See whether we can take their

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,9 @@
627627
/* Define to 1 if you have the `pread' function. */
628628
#undef HAVE_PREAD
629629

630+
/* Define if you have the 'prlimit' functions. */
631+
#undef HAVE_PRLIMIT
632+
630633
/* Define to 1 if you have the <process.h> header file. */
631634
#undef HAVE_PROCESS_H
632635

0 commit comments

Comments
 (0)