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 static int initialized;
67 static PyTypeObject StructRUsageType;
68
69 /*[clinic input]
70 resource.getrusage
71
72 who: int
73 /
74
75 [clinic start generated code]*/
76
77 static PyObject *
resource_getrusage_impl(PyObject * module,int who)78 resource_getrusage_impl(PyObject *module, int who)
79 /*[clinic end generated code: output=8fad2880ba6a9843 input=5c857bcc5b9ccb1b]*/
80 {
81 struct rusage ru;
82 PyObject *result;
83
84 if (getrusage(who, &ru) == -1) {
85 if (errno == EINVAL) {
86 PyErr_SetString(PyExc_ValueError,
87 "invalid who parameter");
88 return NULL;
89 }
90 PyErr_SetFromErrno(PyExc_OSError);
91 return NULL;
92 }
93
94 result = PyStructSequence_New(&StructRUsageType);
95 if (!result)
96 return NULL;
97
98 PyStructSequence_SET_ITEM(result, 0,
99 PyFloat_FromDouble(doubletime(ru.ru_utime)));
100 PyStructSequence_SET_ITEM(result, 1,
101 PyFloat_FromDouble(doubletime(ru.ru_stime)));
102 PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong(ru.ru_maxrss));
103 PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong(ru.ru_ixrss));
104 PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong(ru.ru_idrss));
105 PyStructSequence_SET_ITEM(result, 5, PyLong_FromLong(ru.ru_isrss));
106 PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(ru.ru_minflt));
107 PyStructSequence_SET_ITEM(result, 7, PyLong_FromLong(ru.ru_majflt));
108 PyStructSequence_SET_ITEM(result, 8, PyLong_FromLong(ru.ru_nswap));
109 PyStructSequence_SET_ITEM(result, 9, PyLong_FromLong(ru.ru_inblock));
110 PyStructSequence_SET_ITEM(result, 10, PyLong_FromLong(ru.ru_oublock));
111 PyStructSequence_SET_ITEM(result, 11, PyLong_FromLong(ru.ru_msgsnd));
112 PyStructSequence_SET_ITEM(result, 12, PyLong_FromLong(ru.ru_msgrcv));
113 PyStructSequence_SET_ITEM(result, 13, PyLong_FromLong(ru.ru_nsignals));
114 PyStructSequence_SET_ITEM(result, 14, PyLong_FromLong(ru.ru_nvcsw));
115 PyStructSequence_SET_ITEM(result, 15, PyLong_FromLong(ru.ru_nivcsw));
116
117 if (PyErr_Occurred()) {
118 Py_DECREF(result);
119 return NULL;
120 }
121
122 return result;
123 }
124
125 static int
py2rlimit(PyObject * limits,struct rlimit * rl_out)126 py2rlimit(PyObject *limits, struct rlimit *rl_out)
127 {
128 PyObject *curobj, *maxobj;
129 limits = PySequence_Tuple(limits);
130 if (!limits)
131 /* Here limits is a borrowed reference */
132 return -1;
133
134 if (PyTuple_GET_SIZE(limits) != 2) {
135 PyErr_SetString(PyExc_ValueError,
136 "expected a tuple of 2 integers");
137 goto error;
138 }
139 curobj = PyTuple_GET_ITEM(limits, 0);
140 maxobj = PyTuple_GET_ITEM(limits, 1);
141 #if !defined(HAVE_LARGEFILE_SUPPORT)
142 rl_out->rlim_cur = PyLong_AsLong(curobj);
143 if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
144 goto error;
145 rl_out->rlim_max = PyLong_AsLong(maxobj);
146 if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
147 goto error;
148 #else
149 /* The limits are probably bigger than a long */
150 rl_out->rlim_cur = PyLong_AsLongLong(curobj);
151 if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
152 goto error;
153 rl_out->rlim_max = PyLong_AsLongLong(maxobj);
154 if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
155 goto error;
156 #endif
157
158 Py_DECREF(limits);
159 rl_out->rlim_cur = rl_out->rlim_cur & RLIM_INFINITY;
160 rl_out->rlim_max = rl_out->rlim_max & RLIM_INFINITY;
161 return 0;
162
163 error:
164 Py_DECREF(limits);
165 return -1;
166 }
167
168 static PyObject*
rlimit2py(struct rlimit rl)169 rlimit2py(struct rlimit rl)
170 {
171 if (sizeof(rl.rlim_cur) > sizeof(long)) {
172 return Py_BuildValue("LL",
173 (long long) rl.rlim_cur,
174 (long long) rl.rlim_max);
175 }
176 return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max);
177 }
178
179 /*[clinic input]
180 resource.getrlimit
181
182 resource: int
183 /
184
185 [clinic start generated code]*/
186
187 static PyObject *
resource_getrlimit_impl(PyObject * module,int resource)188 resource_getrlimit_impl(PyObject *module, int resource)
189 /*[clinic end generated code: output=98327b25061ffe39 input=a697cb0004cb3c36]*/
190 {
191 struct rlimit rl;
192
193 if (resource < 0 || resource >= RLIM_NLIMITS) {
194 PyErr_SetString(PyExc_ValueError,
195 "invalid resource specified");
196 return NULL;
197 }
198
199 if (getrlimit(resource, &rl) == -1) {
200 PyErr_SetFromErrno(PyExc_OSError);
201 return NULL;
202 }
203 return rlimit2py(rl);
204 }
205
206 /*[clinic input]
207 resource.setrlimit
208
209 resource: int
210 limits: object
211 /
212
213 [clinic start generated code]*/
214
215 static PyObject *
resource_setrlimit_impl(PyObject * module,int resource,PyObject * limits)216 resource_setrlimit_impl(PyObject *module, int resource, PyObject *limits)
217 /*[clinic end generated code: output=4e82ec3f34d013d1 input=6235a6ce23b4ca75]*/
218 {
219 struct rlimit rl;
220
221 if (resource < 0 || resource >= RLIM_NLIMITS) {
222 PyErr_SetString(PyExc_ValueError,
223 "invalid resource specified");
224 return NULL;
225 }
226
227 if (py2rlimit(limits, &rl) < 0) {
228 return NULL;
229 }
230
231 if (setrlimit(resource, &rl) == -1) {
232 if (errno == EINVAL)
233 PyErr_SetString(PyExc_ValueError,
234 "current limit exceeds maximum limit");
235 else if (errno == EPERM)
236 PyErr_SetString(PyExc_ValueError,
237 "not allowed to raise maximum limit");
238 else
239 PyErr_SetFromErrno(PyExc_OSError);
240 return NULL;
241 }
242 Py_RETURN_NONE;
243 }
244
245 #ifdef HAVE_PRLIMIT
246 /*[clinic input]
247 resource.prlimit
248
249 pid: pid_t
250 resource: int
251 [
252 limits: object
253 ]
254 /
255
256 [clinic start generated code]*/
257
258 static PyObject *
resource_prlimit_impl(PyObject * module,pid_t pid,int resource,int group_right_1,PyObject * limits)259 resource_prlimit_impl(PyObject *module, pid_t pid, int resource,
260 int group_right_1, PyObject *limits)
261 /*[clinic end generated code: output=ee976b393187a7a3 input=b77743bdccc83564]*/
262 {
263 struct rlimit old_limit, new_limit;
264 int retval;
265
266 if (resource < 0 || resource >= RLIM_NLIMITS) {
267 PyErr_SetString(PyExc_ValueError,
268 "invalid resource specified");
269 return NULL;
270 }
271
272 if (group_right_1) {
273 if (py2rlimit(limits, &new_limit) < 0) {
274 return NULL;
275 }
276 retval = prlimit(pid, resource, &new_limit, &old_limit);
277 }
278 else {
279 retval = prlimit(pid, resource, NULL, &old_limit);
280 }
281
282 if (retval == -1) {
283 if (errno == EINVAL) {
284 PyErr_SetString(PyExc_ValueError,
285 "current limit exceeds maximum limit");
286 } else {
287 PyErr_SetFromErrno(PyExc_OSError);
288 }
289 return NULL;
290 }
291 return rlimit2py(old_limit);
292 }
293 #endif /* HAVE_PRLIMIT */
294
295 /*[clinic input]
296 resource.getpagesize -> int
297 [clinic start generated code]*/
298
299 static int
resource_getpagesize_impl(PyObject * module)300 resource_getpagesize_impl(PyObject *module)
301 /*[clinic end generated code: output=9ba93eb0f3d6c3a9 input=546545e8c1f42085]*/
302 {
303 long pagesize = 0;
304 #if defined(HAVE_GETPAGESIZE)
305 pagesize = getpagesize();
306 #elif defined(HAVE_SYSCONF)
307 #if defined(_SC_PAGE_SIZE)
308 pagesize = sysconf(_SC_PAGE_SIZE);
309 #else
310 /* Irix 5.3 has _SC_PAGESIZE, but not _SC_PAGE_SIZE */
311 pagesize = sysconf(_SC_PAGESIZE);
312 #endif
313 #endif
314 return pagesize;
315 }
316
317 /* List of functions */
318
319 static struct PyMethodDef
320 resource_methods[] = {
321 RESOURCE_GETRUSAGE_METHODDEF
322 RESOURCE_GETRLIMIT_METHODDEF
323 RESOURCE_PRLIMIT_METHODDEF
324 RESOURCE_SETRLIMIT_METHODDEF
325 RESOURCE_GETPAGESIZE_METHODDEF
326 {NULL, NULL} /* sentinel */
327 };
328
329
330 /* Module initialization */
331
332
333 static struct PyModuleDef resourcemodule = {
334 PyModuleDef_HEAD_INIT,
335 "resource",
336 NULL,
337 -1,
338 resource_methods,
339 NULL,
340 NULL,
341 NULL,
342 NULL
343 };
344
345 PyMODINIT_FUNC
PyInit_resource(void)346 PyInit_resource(void)
347 {
348 PyObject *m, *v;
349
350 /* Create the module and add the functions */
351 m = PyModule_Create(&resourcemodule);
352 if (m == NULL)
353 return NULL;
354
355 /* Add some symbolic constants to the module */
356 Py_INCREF(PyExc_OSError);
357 PyModule_AddObject(m, "error", PyExc_OSError);
358 if (!initialized) {
359 if (PyStructSequence_InitType2(&StructRUsageType,
360 &struct_rusage_desc) < 0)
361 return NULL;
362 }
363
364 Py_INCREF(&StructRUsageType);
365 PyModule_AddObject(m, "struct_rusage",
366 (PyObject*) &StructRUsageType);
367
368 /* insert constants */
369 #ifdef RLIMIT_CPU
370 PyModule_AddIntMacro(m, RLIMIT_CPU);
371 #endif
372
373 #ifdef RLIMIT_FSIZE
374 PyModule_AddIntMacro(m, RLIMIT_FSIZE);
375 #endif
376
377 #ifdef RLIMIT_DATA
378 PyModule_AddIntMacro(m, RLIMIT_DATA);
379 #endif
380
381 #ifdef RLIMIT_STACK
382 PyModule_AddIntMacro(m, RLIMIT_STACK);
383 #endif
384
385 #ifdef RLIMIT_CORE
386 PyModule_AddIntMacro(m, RLIMIT_CORE);
387 #endif
388
389 #ifdef RLIMIT_NOFILE
390 PyModule_AddIntMacro(m, RLIMIT_NOFILE);
391 #endif
392
393 #ifdef RLIMIT_OFILE
394 PyModule_AddIntMacro(m, RLIMIT_OFILE);
395 #endif
396
397 #ifdef RLIMIT_VMEM
398 PyModule_AddIntMacro(m, RLIMIT_VMEM);
399 #endif
400
401 #ifdef RLIMIT_AS
402 PyModule_AddIntMacro(m, RLIMIT_AS);
403 #endif
404
405 #ifdef RLIMIT_RSS
406 PyModule_AddIntMacro(m, RLIMIT_RSS);
407 #endif
408
409 #ifdef RLIMIT_NPROC
410 PyModule_AddIntMacro(m, RLIMIT_NPROC);
411 #endif
412
413 #ifdef RLIMIT_MEMLOCK
414 PyModule_AddIntMacro(m, RLIMIT_MEMLOCK);
415 #endif
416
417 #ifdef RLIMIT_SBSIZE
418 PyModule_AddIntMacro(m, RLIMIT_SBSIZE);
419 #endif
420
421 /* Linux specific */
422 #ifdef RLIMIT_MSGQUEUE
423 PyModule_AddIntMacro(m, RLIMIT_MSGQUEUE);
424 #endif
425
426 #ifdef RLIMIT_NICE
427 PyModule_AddIntMacro(m, RLIMIT_NICE);
428 #endif
429
430 #ifdef RLIMIT_RTPRIO
431 PyModule_AddIntMacro(m, RLIMIT_RTPRIO);
432 #endif
433
434 #ifdef RLIMIT_RTTIME
435 PyModule_AddIntMacro(m, RLIMIT_RTTIME);
436 #endif
437
438 #ifdef RLIMIT_SIGPENDING
439 PyModule_AddIntMacro(m, RLIMIT_SIGPENDING);
440 #endif
441
442 /* target */
443 #ifdef RUSAGE_SELF
444 PyModule_AddIntMacro(m, RUSAGE_SELF);
445 #endif
446
447 #ifdef RUSAGE_CHILDREN
448 PyModule_AddIntMacro(m, RUSAGE_CHILDREN);
449 #endif
450
451 #ifdef RUSAGE_BOTH
452 PyModule_AddIntMacro(m, RUSAGE_BOTH);
453 #endif
454
455 #ifdef RUSAGE_THREAD
456 PyModule_AddIntMacro(m, RUSAGE_THREAD);
457 #endif
458
459 /* FreeBSD specific */
460
461 #ifdef RLIMIT_SWAP
462 PyModule_AddIntMacro(m, RLIMIT_SWAP);
463 #endif
464
465 #ifdef RLIMIT_SBSIZE
466 PyModule_AddIntMacro(m, RLIMIT_SBSIZE);
467 #endif
468
469 #ifdef RLIMIT_NPTS
470 PyModule_AddIntMacro(m, RLIMIT_NPTS);
471 #endif
472
473 if (sizeof(RLIM_INFINITY) > sizeof(long)) {
474 v = PyLong_FromLongLong((long long) RLIM_INFINITY);
475 } else
476 {
477 v = PyLong_FromLong((long) RLIM_INFINITY);
478 }
479 if (v) {
480 PyModule_AddObject(m, "RLIM_INFINITY", v);
481 }
482 initialized = 1;
483 return m;
484 }
485