resource.c 14 KB

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