LCOV - code coverage report
Current view: top level - Modules - resource.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 116 152 76.3 %
Date: 2022-07-07 18:19:46 Functions: 13 13 100.0 %

          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             : }

Generated by: LCOV version 1.14