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