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] 19module resource 20[clinic start generated code]*/ 21/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e89d38ed52609d7c]*/ 22 23/*[python input] 24class 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 32PyDoc_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 39static 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 59static 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 66typedef struct { 67 PyTypeObject *StructRUsageType; 68} resourcemodulestate; 69 70 71static inline resourcemodulestate* 72get_resource_state(PyObject *module) 73{ 74 void *state = PyModule_GetState(module); 75 assert(state != NULL); 76 return (resourcemodulestate *)state; 77} 78 79static struct PyModuleDef resourcemodule; 80 81#ifdef HAVE_GETRUSAGE 82/*[clinic input] 83resource.getrusage 84 85 who: int 86 / 87 88[clinic start generated code]*/ 89 90static PyObject * 91resource_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 if (getrusage(who, &ru) == -1) { 98 if (errno == EINVAL) { 99 PyErr_SetString(PyExc_ValueError, 100 "invalid who parameter"); 101 return NULL; 102 } 103 PyErr_SetFromErrno(PyExc_OSError); 104 return NULL; 105 } 106 107 result = PyStructSequence_New( 108 get_resource_state(module)->StructRUsageType); 109 if (!result) 110 return NULL; 111 112 PyStructSequence_SET_ITEM(result, 0, 113 PyFloat_FromDouble(doubletime(ru.ru_utime))); 114 PyStructSequence_SET_ITEM(result, 1, 115 PyFloat_FromDouble(doubletime(ru.ru_stime))); 116 PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong(ru.ru_maxrss)); 117 PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong(ru.ru_ixrss)); 118 PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong(ru.ru_idrss)); 119 PyStructSequence_SET_ITEM(result, 5, PyLong_FromLong(ru.ru_isrss)); 120 PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(ru.ru_minflt)); 121 PyStructSequence_SET_ITEM(result, 7, PyLong_FromLong(ru.ru_majflt)); 122 PyStructSequence_SET_ITEM(result, 8, PyLong_FromLong(ru.ru_nswap)); 123 PyStructSequence_SET_ITEM(result, 9, PyLong_FromLong(ru.ru_inblock)); 124 PyStructSequence_SET_ITEM(result, 10, PyLong_FromLong(ru.ru_oublock)); 125 PyStructSequence_SET_ITEM(result, 11, PyLong_FromLong(ru.ru_msgsnd)); 126 PyStructSequence_SET_ITEM(result, 12, PyLong_FromLong(ru.ru_msgrcv)); 127 PyStructSequence_SET_ITEM(result, 13, PyLong_FromLong(ru.ru_nsignals)); 128 PyStructSequence_SET_ITEM(result, 14, PyLong_FromLong(ru.ru_nvcsw)); 129 PyStructSequence_SET_ITEM(result, 15, PyLong_FromLong(ru.ru_nivcsw)); 130 131 if (PyErr_Occurred()) { 132 Py_DECREF(result); 133 return NULL; 134 } 135 136 return result; 137} 138#endif 139 140static int 141py2rlimit(PyObject *limits, struct rlimit *rl_out) 142{ 143 PyObject *curobj, *maxobj; 144 limits = PySequence_Tuple(limits); 145 if (!limits) 146 /* Here limits is a borrowed reference */ 147 return -1; 148 149 if (PyTuple_GET_SIZE(limits) != 2) { 150 PyErr_SetString(PyExc_ValueError, 151 "expected a tuple of 2 integers"); 152 goto error; 153 } 154 curobj = PyTuple_GET_ITEM(limits, 0); 155 maxobj = PyTuple_GET_ITEM(limits, 1); 156#if !defined(HAVE_LARGEFILE_SUPPORT) 157 rl_out->rlim_cur = PyLong_AsLong(curobj); 158 if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred()) 159 goto error; 160 rl_out->rlim_max = PyLong_AsLong(maxobj); 161 if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred()) 162 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 Py_DECREF(limits); 174 rl_out->rlim_cur = rl_out->rlim_cur & RLIM_INFINITY; 175 rl_out->rlim_max = rl_out->rlim_max & RLIM_INFINITY; 176 return 0; 177 178error: 179 Py_DECREF(limits); 180 return -1; 181} 182 183static PyObject* 184rlimit2py(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 return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max); 192} 193 194/*[clinic input] 195resource.getrlimit 196 197 resource: int 198 / 199 200[clinic start generated code]*/ 201 202static PyObject * 203resource_getrlimit_impl(PyObject *module, int resource) 204/*[clinic end generated code: output=98327b25061ffe39 input=a697cb0004cb3c36]*/ 205{ 206 struct rlimit rl; 207 208 if (resource < 0 || resource >= RLIM_NLIMITS) { 209 PyErr_SetString(PyExc_ValueError, 210 "invalid resource specified"); 211 return NULL; 212 } 213 214 if (getrlimit(resource, &rl) == -1) { 215 PyErr_SetFromErrno(PyExc_OSError); 216 return NULL; 217 } 218 return rlimit2py(rl); 219} 220 221/*[clinic input] 222resource.setrlimit 223 224 resource: int 225 limits: object 226 / 227 228[clinic start generated code]*/ 229 230static PyObject * 231resource_setrlimit_impl(PyObject *module, int resource, PyObject *limits) 232/*[clinic end generated code: output=4e82ec3f34d013d1 input=6235a6ce23b4ca75]*/ 233{ 234 struct rlimit rl; 235 236 if (resource < 0 || resource >= RLIM_NLIMITS) { 237 PyErr_SetString(PyExc_ValueError, 238 "invalid resource specified"); 239 return NULL; 240 } 241 242 if (PySys_Audit("resource.setrlimit", "iO", resource, 243 limits ? limits : Py_None) < 0) { 244 return NULL; 245 } 246 247 if (py2rlimit(limits, &rl) < 0) { 248 return NULL; 249 } 250 251 if (setrlimit(resource, &rl) == -1) { 252 if (errno == EINVAL) 253 PyErr_SetString(PyExc_ValueError, 254 "current limit exceeds maximum limit"); 255 else if (errno == EPERM) 256 PyErr_SetString(PyExc_ValueError, 257 "not allowed to raise maximum limit"); 258 else 259 PyErr_SetFromErrno(PyExc_OSError); 260 return NULL; 261 } 262 Py_RETURN_NONE; 263} 264 265#ifdef HAVE_PRLIMIT 266/*[clinic input] 267resource.prlimit 268 269 pid: pid_t 270 resource: int 271 [ 272 limits: object 273 ] 274 / 275 276[clinic start generated code]*/ 277 278static PyObject * 279resource_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 if (resource < 0 || resource >= RLIM_NLIMITS) { 287 PyErr_SetString(PyExc_ValueError, 288 "invalid resource specified"); 289 return NULL; 290 } 291 292 if (PySys_Audit("resource.prlimit", "iiO", pid, resource, 293 limits ? limits : Py_None) < 0) { 294 return NULL; 295 } 296 297 if (group_right_1) { 298 if (py2rlimit(limits, &new_limit) < 0) { 299 return NULL; 300 } 301 retval = prlimit(pid, resource, &new_limit, &old_limit); 302 } 303 else { 304 retval = prlimit(pid, resource, NULL, &old_limit); 305 } 306 307 if (retval == -1) { 308 if (errno == EINVAL) { 309 PyErr_SetString(PyExc_ValueError, 310 "current limit exceeds maximum limit"); 311 } else { 312 PyErr_SetFromErrno(PyExc_OSError); 313 } 314 return NULL; 315 } 316 return rlimit2py(old_limit); 317} 318#endif /* HAVE_PRLIMIT */ 319 320/*[clinic input] 321resource.getpagesize -> int 322[clinic start generated code]*/ 323 324static int 325resource_getpagesize_impl(PyObject *module) 326/*[clinic end generated code: output=9ba93eb0f3d6c3a9 input=546545e8c1f42085]*/ 327{ 328 long pagesize = 0; 329#if defined(HAVE_GETPAGESIZE) 330 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 return pagesize; 337} 338 339/* List of functions */ 340 341static struct PyMethodDef 342resource_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 354static int 355resource_exec(PyObject *module) 356{ 357 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 Py_INCREF(PyExc_OSError); 367 if (PyModule_AddObject(module, "error", PyExc_OSError) < 0) { 368 Py_DECREF(PyExc_OSError); 369 return -1; 370 } 371 372 state->StructRUsageType = PyStructSequence_NewType(&struct_rusage_desc); 373 if (state->StructRUsageType == NULL) { 374 return -1; 375 } 376 if (PyModule_AddType(module, state->StructRUsageType) < 0) { 377 return -1; 378 } 379 380 /* insert constants */ 381#ifdef RLIMIT_CPU 382 ADD_INT(module, RLIMIT_CPU); 383#endif 384 385#ifdef RLIMIT_FSIZE 386 ADD_INT(module, RLIMIT_FSIZE); 387#endif 388 389#ifdef RLIMIT_DATA 390 ADD_INT(module, RLIMIT_DATA); 391#endif 392 393#ifdef RLIMIT_STACK 394 ADD_INT(module, RLIMIT_STACK); 395#endif 396 397#ifdef RLIMIT_CORE 398 ADD_INT(module, RLIMIT_CORE); 399#endif 400 401#ifdef RLIMIT_NOFILE 402 ADD_INT(module, RLIMIT_NOFILE); 403#endif 404 405#ifdef RLIMIT_OFILE 406 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 ADD_INT(module, RLIMIT_AS); 415#endif 416 417#ifdef RLIMIT_RSS 418 ADD_INT(module, RLIMIT_RSS); 419#endif 420 421#ifdef RLIMIT_NPROC 422 ADD_INT(module, RLIMIT_NPROC); 423#endif 424 425#ifdef RLIMIT_MEMLOCK 426 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 ADD_INT(module, RLIMIT_MSGQUEUE); 436#endif 437 438#ifdef RLIMIT_NICE 439 ADD_INT(module, RLIMIT_NICE); 440#endif 441 442#ifdef RLIMIT_RTPRIO 443 ADD_INT(module, RLIMIT_RTPRIO); 444#endif 445 446#ifdef RLIMIT_RTTIME 447 ADD_INT(module, RLIMIT_RTTIME); 448#endif 449 450#ifdef RLIMIT_SIGPENDING 451 ADD_INT(module, RLIMIT_SIGPENDING); 452#endif 453 454/* target */ 455#ifdef RUSAGE_SELF 456 ADD_INT(module, RUSAGE_SELF); 457#endif 458 459#ifdef RUSAGE_CHILDREN 460 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 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 v = PyLong_FromLong((long) RLIM_INFINITY); 495 } 496 if (!v) { 497 return -1; 498 } 499 500 if (PyModule_AddObject(module, "RLIM_INFINITY", v) < 0) { 501 Py_DECREF(v); 502 return -1; 503 } 504 return 0; 505 506#undef ADD_INT 507} 508 509static struct PyModuleDef_Slot resource_slots[] = { 510 {Py_mod_exec, resource_exec}, 511 {0, NULL} 512}; 513 514static int 515resourcemodule_traverse(PyObject *m, visitproc visit, void *arg) { 516 Py_VISIT(get_resource_state(m)->StructRUsageType); 517 return 0; 518} 519 520static int 521resourcemodule_clear(PyObject *m) { 522 Py_CLEAR(get_resource_state(m)->StructRUsageType); 523 return 0; 524} 525 526static void 527resourcemodule_free(void *m) { 528 resourcemodule_clear((PyObject *)m); 529} 530 531static 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 542PyMODINIT_FUNC 543PyInit_resource(void) 544{ 545 return PyModuleDef_Init(&resourcemodule); 546} 547