(root)/
Python-3.12.0/
Modules/
resource.c
       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  }