Branch data Line data Source code
1 : :
2 : : #include "Python.h"
3 : : #include <sys/resource.h>
4 : : #include <sys/time.h>
5 : : #include <string.h>
6 : : #include <errno.h>
7 : : #include <unistd.h>
8 : :
9 : : /* On some systems, these aren't in any header file.
10 : : On others they are, with inconsistent prototypes.
11 : : We declare the (default) return type, to shut up gcc -Wall;
12 : : but we can't declare the prototype, to avoid errors
13 : : when the header files declare it different.
14 : : Worse, on some Linuxes, getpagesize() returns a size_t... */
15 : :
16 : : #define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
17 : :
18 : : /*[clinic input]
19 : : module resource
20 : : [clinic start generated code]*/
21 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e89d38ed52609d7c]*/
22 : :
23 : : /*[python input]
24 : : class pid_t_converter(CConverter):
25 : : type = 'pid_t'
26 : : format_unit = '" _Py_PARSE_PID "'
27 : :
28 : : def parse_arg(self, argname, displayname):
29 : : return """
30 : : {paramname} = PyLong_AsPid({argname});
31 : : if ({paramname} == -1 && PyErr_Occurred()) {{{{
32 : : goto exit;
33 : : }}}}
34 : : """.format(argname=argname, paramname=self.parser_name)
35 : : [python start generated code]*/
36 : : /*[python end generated code: output=da39a3ee5e6b4b0d input=5af1c116d56cbb5a]*/
37 : :
38 : : #include "clinic/resource.c.h"
39 : :
40 : : PyDoc_STRVAR(struct_rusage__doc__,
41 : : "struct_rusage: Result from getrusage.\n\n"
42 : : "This object may be accessed either as a tuple of\n"
43 : : " (utime,stime,maxrss,ixrss,idrss,isrss,minflt,majflt,\n"
44 : : " nswap,inblock,oublock,msgsnd,msgrcv,nsignals,nvcsw,nivcsw)\n"
45 : : "or via the attributes ru_utime, ru_stime, ru_maxrss, and so on.");
46 : :
47 : : static PyStructSequence_Field struct_rusage_fields[] = {
48 : : {"ru_utime", "user time used"},
49 : : {"ru_stime", "system time used"},
50 : : {"ru_maxrss", "max. resident set size"},
51 : : {"ru_ixrss", "shared memory size"},
52 : : {"ru_idrss", "unshared data size"},
53 : : {"ru_isrss", "unshared stack size"},
54 : : {"ru_minflt", "page faults not requiring I/O"},
55 : : {"ru_majflt", "page faults requiring I/O"},
56 : : {"ru_nswap", "number of swap outs"},
57 : : {"ru_inblock", "block input operations"},
58 : : {"ru_oublock", "block output operations"},
59 : : {"ru_msgsnd", "IPC messages sent"},
60 : : {"ru_msgrcv", "IPC messages received"},
61 : : {"ru_nsignals", "signals received"},
62 : : {"ru_nvcsw", "voluntary context switches"},
63 : : {"ru_nivcsw", "involuntary context switches"},
64 : : {0}
65 : : };
66 : :
67 : : static PyStructSequence_Desc struct_rusage_desc = {
68 : : "resource.struct_rusage", /* name */
69 : : struct_rusage__doc__, /* doc */
70 : : struct_rusage_fields, /* fields */
71 : : 16 /* n_in_sequence */
72 : : };
73 : :
74 : : typedef struct {
75 : : PyTypeObject *StructRUsageType;
76 : : } resourcemodulestate;
77 : :
78 : :
79 : : static inline resourcemodulestate*
80 : 74 : get_resource_state(PyObject *module)
81 : : {
82 : 74 : void *state = PyModule_GetState(module);
83 : : assert(state != NULL);
84 : 74 : return (resourcemodulestate *)state;
85 : : }
86 : :
87 : : static struct PyModuleDef resourcemodule;
88 : :
89 : : #ifdef HAVE_GETRUSAGE
90 : : /*[clinic input]
91 : : resource.getrusage
92 : :
93 : : who: int
94 : : /
95 : :
96 : : [clinic start generated code]*/
97 : :
98 : : static PyObject *
99 : 0 : resource_getrusage_impl(PyObject *module, int who)
100 : : /*[clinic end generated code: output=8fad2880ba6a9843 input=5c857bcc5b9ccb1b]*/
101 : : {
102 : : struct rusage ru;
103 : : PyObject *result;
104 : :
105 [ # # ]: 0 : if (getrusage(who, &ru) == -1) {
106 [ # # ]: 0 : if (errno == EINVAL) {
107 : 0 : PyErr_SetString(PyExc_ValueError,
108 : : "invalid who parameter");
109 : 0 : return NULL;
110 : : }
111 : 0 : PyErr_SetFromErrno(PyExc_OSError);
112 : 0 : return NULL;
113 : : }
114 : :
115 : 0 : result = PyStructSequence_New(
116 : 0 : get_resource_state(module)->StructRUsageType);
117 [ # # ]: 0 : if (!result)
118 : 0 : return NULL;
119 : :
120 : 0 : PyStructSequence_SET_ITEM(result, 0,
121 : : PyFloat_FromDouble(doubletime(ru.ru_utime)));
122 : 0 : PyStructSequence_SET_ITEM(result, 1,
123 : : PyFloat_FromDouble(doubletime(ru.ru_stime)));
124 : 0 : PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong(ru.ru_maxrss));
125 : 0 : PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong(ru.ru_ixrss));
126 : 0 : PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong(ru.ru_idrss));
127 : 0 : PyStructSequence_SET_ITEM(result, 5, PyLong_FromLong(ru.ru_isrss));
128 : 0 : PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(ru.ru_minflt));
129 : 0 : PyStructSequence_SET_ITEM(result, 7, PyLong_FromLong(ru.ru_majflt));
130 : 0 : PyStructSequence_SET_ITEM(result, 8, PyLong_FromLong(ru.ru_nswap));
131 : 0 : PyStructSequence_SET_ITEM(result, 9, PyLong_FromLong(ru.ru_inblock));
132 : 0 : PyStructSequence_SET_ITEM(result, 10, PyLong_FromLong(ru.ru_oublock));
133 : 0 : PyStructSequence_SET_ITEM(result, 11, PyLong_FromLong(ru.ru_msgsnd));
134 : 0 : PyStructSequence_SET_ITEM(result, 12, PyLong_FromLong(ru.ru_msgrcv));
135 : 0 : PyStructSequence_SET_ITEM(result, 13, PyLong_FromLong(ru.ru_nsignals));
136 : 0 : PyStructSequence_SET_ITEM(result, 14, PyLong_FromLong(ru.ru_nvcsw));
137 : 0 : PyStructSequence_SET_ITEM(result, 15, PyLong_FromLong(ru.ru_nivcsw));
138 : :
139 [ # # ]: 0 : if (PyErr_Occurred()) {
140 : 0 : Py_DECREF(result);
141 : 0 : return NULL;
142 : : }
143 : :
144 : 0 : return result;
145 : : }
146 : : #endif
147 : :
148 : : static int
149 : 0 : py2rlimit(PyObject *limits, struct rlimit *rl_out)
150 : : {
151 : : PyObject *curobj, *maxobj;
152 : 0 : limits = PySequence_Tuple(limits);
153 [ # # ]: 0 : if (!limits)
154 : : /* Here limits is a borrowed reference */
155 : 0 : return -1;
156 : :
157 [ # # ]: 0 : if (PyTuple_GET_SIZE(limits) != 2) {
158 : 0 : PyErr_SetString(PyExc_ValueError,
159 : : "expected a tuple of 2 integers");
160 : 0 : goto error;
161 : : }
162 : 0 : curobj = PyTuple_GET_ITEM(limits, 0);
163 : 0 : maxobj = PyTuple_GET_ITEM(limits, 1);
164 : : #if !defined(HAVE_LARGEFILE_SUPPORT)
165 : 0 : rl_out->rlim_cur = PyLong_AsLong(curobj);
166 [ # # # # ]: 0 : if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
167 : 0 : goto error;
168 : 0 : rl_out->rlim_max = PyLong_AsLong(maxobj);
169 [ # # # # ]: 0 : if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
170 : 0 : goto error;
171 : : #else
172 : : /* The limits are probably bigger than a long */
173 : : rl_out->rlim_cur = PyLong_AsLongLong(curobj);
174 : : if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
175 : : goto error;
176 : : rl_out->rlim_max = PyLong_AsLongLong(maxobj);
177 : : if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
178 : : goto error;
179 : : #endif
180 : :
181 : 0 : Py_DECREF(limits);
182 : 0 : rl_out->rlim_cur = rl_out->rlim_cur & RLIM_INFINITY;
183 : 0 : rl_out->rlim_max = rl_out->rlim_max & RLIM_INFINITY;
184 : 0 : return 0;
185 : :
186 : 0 : error:
187 : 0 : Py_DECREF(limits);
188 : 0 : return -1;
189 : : }
190 : :
191 : : static PyObject*
192 : 1 : rlimit2py(struct rlimit rl)
193 : : {
194 : : if (sizeof(rl.rlim_cur) > sizeof(long)) {
195 : : return Py_BuildValue("LL",
196 : : (long long) rl.rlim_cur,
197 : : (long long) rl.rlim_max);
198 : : }
199 : 1 : return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max);
200 : : }
201 : :
202 : : /*[clinic input]
203 : : resource.getrlimit
204 : :
205 : : resource: int
206 : : /
207 : :
208 : : [clinic start generated code]*/
209 : :
210 : : static PyObject *
211 : 1 : resource_getrlimit_impl(PyObject *module, int resource)
212 : : /*[clinic end generated code: output=98327b25061ffe39 input=a697cb0004cb3c36]*/
213 : : {
214 : : struct rlimit rl;
215 : :
216 [ + - - + ]: 1 : if (resource < 0 || resource >= RLIM_NLIMITS) {
217 : 0 : PyErr_SetString(PyExc_ValueError,
218 : : "invalid resource specified");
219 : 0 : return NULL;
220 : : }
221 : :
222 [ - + ]: 1 : if (getrlimit(resource, &rl) == -1) {
223 : 0 : PyErr_SetFromErrno(PyExc_OSError);
224 : 0 : return NULL;
225 : : }
226 : 1 : return rlimit2py(rl);
227 : : }
228 : :
229 : : /*[clinic input]
230 : : resource.setrlimit
231 : :
232 : : resource: int
233 : : limits: object
234 : : /
235 : :
236 : : [clinic start generated code]*/
237 : :
238 : : static PyObject *
239 : 0 : resource_setrlimit_impl(PyObject *module, int resource, PyObject *limits)
240 : : /*[clinic end generated code: output=4e82ec3f34d013d1 input=6235a6ce23b4ca75]*/
241 : : {
242 : : struct rlimit rl;
243 : :
244 [ # # # # ]: 0 : if (resource < 0 || resource >= RLIM_NLIMITS) {
245 : 0 : PyErr_SetString(PyExc_ValueError,
246 : : "invalid resource specified");
247 : 0 : return NULL;
248 : : }
249 : :
250 [ # # # # ]: 0 : if (PySys_Audit("resource.setrlimit", "iO", resource,
251 : : limits ? limits : Py_None) < 0) {
252 : 0 : return NULL;
253 : : }
254 : :
255 [ # # ]: 0 : if (py2rlimit(limits, &rl) < 0) {
256 : 0 : return NULL;
257 : : }
258 : :
259 [ # # ]: 0 : if (setrlimit(resource, &rl) == -1) {
260 [ # # ]: 0 : if (errno == EINVAL)
261 : 0 : PyErr_SetString(PyExc_ValueError,
262 : : "current limit exceeds maximum limit");
263 [ # # ]: 0 : else if (errno == EPERM)
264 : 0 : PyErr_SetString(PyExc_ValueError,
265 : : "not allowed to raise maximum limit");
266 : : else
267 : 0 : PyErr_SetFromErrno(PyExc_OSError);
268 : 0 : return NULL;
269 : : }
270 : 0 : Py_RETURN_NONE;
271 : : }
272 : :
273 : : #ifdef HAVE_PRLIMIT
274 : : /*[clinic input]
275 : : resource.prlimit
276 : :
277 : : pid: pid_t
278 : : resource: int
279 : : limits: object = None
280 : : /
281 : :
282 : : [clinic start generated code]*/
283 : :
284 : : static PyObject *
285 : 0 : resource_prlimit_impl(PyObject *module, pid_t pid, int resource,
286 : : PyObject *limits)
287 : : /*[clinic end generated code: output=6ebc49ff8c3a816e input=54bb69c9585e33bf]*/
288 : : {
289 : : struct rlimit old_limit, new_limit;
290 : : int retval;
291 : :
292 [ # # # # ]: 0 : if (resource < 0 || resource >= RLIM_NLIMITS) {
293 : 0 : PyErr_SetString(PyExc_ValueError,
294 : : "invalid resource specified");
295 : 0 : return NULL;
296 : : }
297 : :
298 [ # # # # ]: 0 : if (PySys_Audit("resource.prlimit", "iiO", pid, resource,
299 : : limits ? limits : Py_None) < 0) {
300 : 0 : return NULL;
301 : : }
302 : :
303 [ # # ]: 0 : if (limits != Py_None) {
304 [ # # ]: 0 : if (py2rlimit(limits, &new_limit) < 0) {
305 : 0 : return NULL;
306 : : }
307 : 0 : retval = prlimit(pid, resource, &new_limit, &old_limit);
308 : : }
309 : : else {
310 : 0 : retval = prlimit(pid, resource, NULL, &old_limit);
311 : : }
312 : :
313 [ # # ]: 0 : if (retval == -1) {
314 [ # # ]: 0 : if (errno == EINVAL) {
315 : 0 : PyErr_SetString(PyExc_ValueError,
316 : : "current limit exceeds maximum limit");
317 : : } else {
318 : 0 : PyErr_SetFromErrno(PyExc_OSError);
319 : : }
320 : 0 : return NULL;
321 : : }
322 : 0 : return rlimit2py(old_limit);
323 : : }
324 : : #endif /* HAVE_PRLIMIT */
325 : :
326 : : /*[clinic input]
327 : : resource.getpagesize -> int
328 : : [clinic start generated code]*/
329 : :
330 : : static int
331 : 0 : resource_getpagesize_impl(PyObject *module)
332 : : /*[clinic end generated code: output=9ba93eb0f3d6c3a9 input=546545e8c1f42085]*/
333 : : {
334 : 0 : long pagesize = 0;
335 : : #if defined(HAVE_GETPAGESIZE)
336 : 0 : pagesize = getpagesize();
337 : : #elif defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
338 : : pagesize = sysconf(_SC_PAGE_SIZE);
339 : : #else
340 : : # error "unsupported platform: resource.getpagesize()"
341 : : #endif
342 : 0 : return pagesize;
343 : : }
344 : :
345 : : /* List of functions */
346 : :
347 : : static struct PyMethodDef
348 : : resource_methods[] = {
349 : : RESOURCE_GETRUSAGE_METHODDEF
350 : : RESOURCE_GETRLIMIT_METHODDEF
351 : : RESOURCE_PRLIMIT_METHODDEF
352 : : RESOURCE_SETRLIMIT_METHODDEF
353 : : RESOURCE_GETPAGESIZE_METHODDEF
354 : : {NULL, NULL} /* sentinel */
355 : : };
356 : :
357 : :
358 : : /* Module initialization */
359 : :
360 : : static int
361 : 2 : resource_exec(PyObject *module)
362 : : {
363 : 2 : resourcemodulestate *state = get_resource_state(module);
364 : : #define ADD_INT(module, value) \
365 : : do { \
366 : : if (PyModule_AddIntConstant(module, #value, value) < 0) { \
367 : : return -1; \
368 : : } \
369 : : } while (0)
370 : :
371 : : /* Add some symbolic constants to the module */
372 : 2 : Py_INCREF(PyExc_OSError);
373 [ - + ]: 2 : if (PyModule_AddObject(module, "error", PyExc_OSError) < 0) {
374 : 0 : Py_DECREF(PyExc_OSError);
375 : 0 : return -1;
376 : : }
377 : :
378 : 2 : state->StructRUsageType = PyStructSequence_NewType(&struct_rusage_desc);
379 [ - + ]: 2 : if (state->StructRUsageType == NULL) {
380 : 0 : return -1;
381 : : }
382 [ - + ]: 2 : if (PyModule_AddType(module, state->StructRUsageType) < 0) {
383 : 0 : return -1;
384 : : }
385 : :
386 : : /* insert constants */
387 : : #ifdef RLIMIT_CPU
388 [ - + ]: 2 : ADD_INT(module, RLIMIT_CPU);
389 : : #endif
390 : :
391 : : #ifdef RLIMIT_FSIZE
392 [ - + ]: 2 : ADD_INT(module, RLIMIT_FSIZE);
393 : : #endif
394 : :
395 : : #ifdef RLIMIT_DATA
396 [ - + ]: 2 : ADD_INT(module, RLIMIT_DATA);
397 : : #endif
398 : :
399 : : #ifdef RLIMIT_STACK
400 [ - + ]: 2 : ADD_INT(module, RLIMIT_STACK);
401 : : #endif
402 : :
403 : : #ifdef RLIMIT_CORE
404 [ - + ]: 2 : ADD_INT(module, RLIMIT_CORE);
405 : : #endif
406 : :
407 : : #ifdef RLIMIT_NOFILE
408 [ - + ]: 2 : ADD_INT(module, RLIMIT_NOFILE);
409 : : #endif
410 : :
411 : : #ifdef RLIMIT_OFILE
412 [ - + ]: 2 : ADD_INT(module, RLIMIT_OFILE);
413 : : #endif
414 : :
415 : : #ifdef RLIMIT_VMEM
416 : : ADD_INT(module, RLIMIT_VMEM);
417 : : #endif
418 : :
419 : : #ifdef RLIMIT_AS
420 [ - + ]: 2 : ADD_INT(module, RLIMIT_AS);
421 : : #endif
422 : :
423 : : #ifdef RLIMIT_RSS
424 [ - + ]: 2 : ADD_INT(module, RLIMIT_RSS);
425 : : #endif
426 : :
427 : : #ifdef RLIMIT_NPROC
428 [ - + ]: 2 : ADD_INT(module, RLIMIT_NPROC);
429 : : #endif
430 : :
431 : : #ifdef RLIMIT_MEMLOCK
432 [ - + ]: 2 : ADD_INT(module, RLIMIT_MEMLOCK);
433 : : #endif
434 : :
435 : : #ifdef RLIMIT_SBSIZE
436 : : ADD_INT(module, RLIMIT_SBSIZE);
437 : : #endif
438 : :
439 : : /* Linux specific */
440 : : #ifdef RLIMIT_MSGQUEUE
441 [ - + ]: 2 : ADD_INT(module, RLIMIT_MSGQUEUE);
442 : : #endif
443 : :
444 : : #ifdef RLIMIT_NICE
445 [ - + ]: 2 : ADD_INT(module, RLIMIT_NICE);
446 : : #endif
447 : :
448 : : #ifdef RLIMIT_RTPRIO
449 [ - + ]: 2 : ADD_INT(module, RLIMIT_RTPRIO);
450 : : #endif
451 : :
452 : : #ifdef RLIMIT_RTTIME
453 [ - + ]: 2 : ADD_INT(module, RLIMIT_RTTIME);
454 : : #endif
455 : :
456 : : #ifdef RLIMIT_SIGPENDING
457 [ - + ]: 2 : ADD_INT(module, RLIMIT_SIGPENDING);
458 : : #endif
459 : :
460 : : /* target */
461 : : #ifdef RUSAGE_SELF
462 [ - + ]: 2 : ADD_INT(module, RUSAGE_SELF);
463 : : #endif
464 : :
465 : : #ifdef RUSAGE_CHILDREN
466 [ - + ]: 2 : ADD_INT(module, RUSAGE_CHILDREN);
467 : : #endif
468 : :
469 : : #ifdef RUSAGE_BOTH
470 : : ADD_INT(module, RUSAGE_BOTH);
471 : : #endif
472 : :
473 : : #ifdef RUSAGE_THREAD
474 [ - + ]: 2 : ADD_INT(module, RUSAGE_THREAD);
475 : : #endif
476 : :
477 : : /* FreeBSD specific */
478 : :
479 : : #ifdef RLIMIT_SWAP
480 : : ADD_INT(module, RLIMIT_SWAP);
481 : : #endif
482 : :
483 : : #ifdef RLIMIT_SBSIZE
484 : : ADD_INT(module, RLIMIT_SBSIZE);
485 : : #endif
486 : :
487 : : #ifdef RLIMIT_NPTS
488 : : ADD_INT(module, RLIMIT_NPTS);
489 : : #endif
490 : :
491 : : #ifdef RLIMIT_KQUEUES
492 : : ADD_INT(module, RLIMIT_KQUEUES);
493 : : #endif
494 : :
495 : : PyObject *v;
496 : : if (sizeof(RLIM_INFINITY) > sizeof(long)) {
497 : : v = PyLong_FromLongLong((long long) RLIM_INFINITY);
498 : : } else
499 : : {
500 : 2 : v = PyLong_FromLong((long) RLIM_INFINITY);
501 : : }
502 [ - + ]: 2 : if (!v) {
503 : 0 : return -1;
504 : : }
505 : :
506 [ - + ]: 2 : if (PyModule_AddObject(module, "RLIM_INFINITY", v) < 0) {
507 : 0 : Py_DECREF(v);
508 : 0 : return -1;
509 : : }
510 : 2 : return 0;
511 : :
512 : : #undef ADD_INT
513 : : }
514 : :
515 : : static struct PyModuleDef_Slot resource_slots[] = {
516 : : {Py_mod_exec, resource_exec},
517 : : {0, NULL}
518 : : };
519 : :
520 : : static int
521 : 34 : resourcemodule_traverse(PyObject *m, visitproc visit, void *arg) {
522 [ + - - + ]: 34 : Py_VISIT(get_resource_state(m)->StructRUsageType);
523 : 34 : return 0;
524 : : }
525 : :
526 : : static int
527 : 4 : resourcemodule_clear(PyObject *m) {
528 [ + + ]: 4 : Py_CLEAR(get_resource_state(m)->StructRUsageType);
529 : 4 : return 0;
530 : : }
531 : :
532 : : static void
533 : 2 : resourcemodule_free(void *m) {
534 : 2 : resourcemodule_clear((PyObject *)m);
535 : 2 : }
536 : :
537 : : static struct PyModuleDef resourcemodule = {
538 : : PyModuleDef_HEAD_INIT,
539 : : .m_name = "resource",
540 : : .m_size = sizeof(resourcemodulestate),
541 : : .m_methods = resource_methods,
542 : : .m_slots = resource_slots,
543 : : .m_traverse = resourcemodule_traverse,
544 : : .m_clear = resourcemodule_clear,
545 : : .m_free = resourcemodule_free,
546 : : };
547 : :
548 : : PyMODINIT_FUNC
549 : 2 : PyInit_resource(void)
550 : : {
551 : 2 : return PyModuleDef_Init(&resourcemodule);
552 : : }
|