(root)/
Python-3.11.7/
Modules/
resource.c
       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  get_resource_state(PyObject *module)
      73  {
      74      void *state = PyModule_GetState(module);
      75      assert(state != NULL);
      76      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  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      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  
     140  static int
     141  py2rlimit(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  
     178  error:
     179      Py_DECREF(limits);
     180      return -1;
     181  }
     182  
     183  static PyObject*
     184  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      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  resource_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]
     222  resource.setrlimit
     223  
     224      resource: int
     225      limits: object
     226      /
     227  
     228  [clinic start generated code]*/
     229  
     230  static PyObject *
     231  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      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]
     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  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      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]
     321  resource.getpagesize -> int
     322  [clinic start generated code]*/
     323  
     324  static int
     325  resource_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  
     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  resource_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  
     509  static struct PyModuleDef_Slot resource_slots[] = {
     510      {Py_mod_exec, resource_exec},
     511      {0, NULL}
     512  };
     513  
     514  static int
     515  resourcemodule_traverse(PyObject *m, visitproc visit, void *arg) {
     516      Py_VISIT(get_resource_state(m)->StructRUsageType);
     517      return 0;
     518  }
     519  
     520  static int
     521  resourcemodule_clear(PyObject *m) {
     522      Py_CLEAR(get_resource_state(m)->StructRUsageType);
     523      return 0;
     524  }
     525  
     526  static void
     527  resourcemodule_free(void *m) {
     528      resourcemodule_clear((PyObject *)m);
     529  }
     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  PyInit_resource(void)
     544  {
     545      return PyModuleDef_Init(&resourcemodule);
     546  }