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