Home | History | Annotate | Download | only in Modules
      1 
      2 #include "Python.h"
      3 #include "structseq.h"
      4 #include <sys/resource.h>
      5 #include <sys/time.h>
      6 #include <string.h>
      7 #include <errno.h>
      8 /* for sysconf */
      9 #if defined(HAVE_UNISTD_H)
     10 #include <unistd.h>
     11 #endif
     12 
     13 /* On some systems, these aren't in any header file.
     14    On others they are, with inconsistent prototypes.
     15    We declare the (default) return type, to shut up gcc -Wall;
     16    but we can't declare the prototype, to avoid errors
     17    when the header files declare it different.
     18    Worse, on some Linuxes, getpagesize() returns a size_t... */
     19 
     20 #define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
     21 
     22 static PyObject *ResourceError;
     23 
     24 PyDoc_STRVAR(struct_rusage__doc__,
     25 "struct_rusage: Result from getrusage.\n\n"
     26 "This object may be accessed either as a tuple of\n"
     27 "    (utime,stime,maxrss,ixrss,idrss,isrss,minflt,majflt,\n"
     28 "    nswap,inblock,oublock,msgsnd,msgrcv,nsignals,nvcsw,nivcsw)\n"
     29 "or via the attributes ru_utime, ru_stime, ru_maxrss, and so on.");
     30 
     31 static PyStructSequence_Field struct_rusage_fields[] = {
     32     {"ru_utime",        "user time used"},
     33     {"ru_stime",        "system time used"},
     34     {"ru_maxrss",       "max. resident set size"},
     35     {"ru_ixrss",        "shared memory size"},
     36     {"ru_idrss",        "unshared data size"},
     37     {"ru_isrss",        "unshared stack size"},
     38     {"ru_minflt",       "page faults not requiring I/O"},
     39     {"ru_majflt",       "page faults requiring I/O"},
     40     {"ru_nswap",        "number of swap outs"},
     41     {"ru_inblock",      "block input operations"},
     42     {"ru_oublock",      "block output operations"},
     43     {"ru_msgsnd",       "IPC messages sent"},
     44     {"ru_msgrcv",       "IPC messages received"},
     45     {"ru_nsignals",     "signals received"},
     46     {"ru_nvcsw",        "voluntary context switches"},
     47     {"ru_nivcsw",       "involuntary context switches"},
     48     {0}
     49 };
     50 
     51 static PyStructSequence_Desc struct_rusage_desc = {
     52     "resource.struct_rusage",           /* name */
     53     struct_rusage__doc__,       /* doc */
     54     struct_rusage_fields,       /* fields */
     55     16          /* n_in_sequence */
     56 };
     57 
     58 static int initialized;
     59 static PyTypeObject StructRUsageType;
     60 
     61 static PyObject *
     62 resource_getrusage(PyObject *self, PyObject *args)
     63 {
     64     int who;
     65     struct rusage ru;
     66     PyObject *result;
     67 
     68     if (!PyArg_ParseTuple(args, "i:getrusage", &who))
     69         return NULL;
     70 
     71     if (getrusage(who, &ru) == -1) {
     72         if (errno == EINVAL) {
     73             PyErr_SetString(PyExc_ValueError,
     74                             "invalid who parameter");
     75             return NULL;
     76         }
     77         PyErr_SetFromErrno(ResourceError);
     78         return NULL;
     79     }
     80 
     81     result = PyStructSequence_New(&StructRUsageType);
     82     if (!result)
     83         return NULL;
     84 
     85     PyStructSequence_SET_ITEM(result, 0,
     86                     PyFloat_FromDouble(doubletime(ru.ru_utime)));
     87     PyStructSequence_SET_ITEM(result, 1,
     88                     PyFloat_FromDouble(doubletime(ru.ru_stime)));
     89     PyStructSequence_SET_ITEM(result, 2, PyInt_FromLong(ru.ru_maxrss));
     90     PyStructSequence_SET_ITEM(result, 3, PyInt_FromLong(ru.ru_ixrss));
     91     PyStructSequence_SET_ITEM(result, 4, PyInt_FromLong(ru.ru_idrss));
     92     PyStructSequence_SET_ITEM(result, 5, PyInt_FromLong(ru.ru_isrss));
     93     PyStructSequence_SET_ITEM(result, 6, PyInt_FromLong(ru.ru_minflt));
     94     PyStructSequence_SET_ITEM(result, 7, PyInt_FromLong(ru.ru_majflt));
     95     PyStructSequence_SET_ITEM(result, 8, PyInt_FromLong(ru.ru_nswap));
     96     PyStructSequence_SET_ITEM(result, 9, PyInt_FromLong(ru.ru_inblock));
     97     PyStructSequence_SET_ITEM(result, 10, PyInt_FromLong(ru.ru_oublock));
     98     PyStructSequence_SET_ITEM(result, 11, PyInt_FromLong(ru.ru_msgsnd));
     99     PyStructSequence_SET_ITEM(result, 12, PyInt_FromLong(ru.ru_msgrcv));
    100     PyStructSequence_SET_ITEM(result, 13, PyInt_FromLong(ru.ru_nsignals));
    101     PyStructSequence_SET_ITEM(result, 14, PyInt_FromLong(ru.ru_nvcsw));
    102     PyStructSequence_SET_ITEM(result, 15, PyInt_FromLong(ru.ru_nivcsw));
    103 
    104     if (PyErr_Occurred()) {
    105         Py_DECREF(result);
    106         return NULL;
    107     }
    108 
    109     return result;
    110 }
    111 
    112 
    113 static PyObject *
    114 resource_getrlimit(PyObject *self, PyObject *args)
    115 {
    116     struct rlimit rl;
    117     int resource;
    118 
    119     if (!PyArg_ParseTuple(args, "i:getrlimit", &resource))
    120         return NULL;
    121 
    122     if (resource < 0 || resource >= RLIM_NLIMITS) {
    123         PyErr_SetString(PyExc_ValueError,
    124                         "invalid resource specified");
    125         return NULL;
    126     }
    127 
    128     if (getrlimit(resource, &rl) == -1) {
    129         PyErr_SetFromErrno(ResourceError);
    130         return NULL;
    131     }
    132 
    133 #if defined(HAVE_LONG_LONG)
    134     if (sizeof(rl.rlim_cur) > sizeof(long)) {
    135         return Py_BuildValue("LL",
    136                              (PY_LONG_LONG) rl.rlim_cur,
    137                              (PY_LONG_LONG) rl.rlim_max);
    138     }
    139 #endif
    140     return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max);
    141 }
    142 
    143 static PyObject *
    144 resource_setrlimit(PyObject *self, PyObject *args)
    145 {
    146     struct rlimit rl;
    147     int resource;
    148     PyObject *limits, *curobj, *maxobj;
    149 
    150     if (!PyArg_ParseTuple(args, "iO:setrlimit", &resource, &limits))
    151         return NULL;
    152 
    153     if (resource < 0 || resource >= RLIM_NLIMITS) {
    154         PyErr_SetString(PyExc_ValueError,
    155                         "invalid resource specified");
    156         return NULL;
    157     }
    158 
    159     limits = PySequence_Tuple(limits);
    160     if (!limits)
    161         /* Here limits is a borrowed reference */
    162         return NULL;
    163 
    164     if (PyTuple_GET_SIZE(limits) != 2) {
    165         PyErr_SetString(PyExc_ValueError,
    166                         "expected a tuple of 2 integers");
    167         goto error;
    168     }
    169     curobj = PyTuple_GET_ITEM(limits, 0);
    170     maxobj = PyTuple_GET_ITEM(limits, 1);
    171 
    172 #if !defined(HAVE_LARGEFILE_SUPPORT)
    173     rl.rlim_cur = PyInt_AsLong(curobj);
    174     if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
    175         goto error;
    176     rl.rlim_max = PyInt_AsLong(maxobj);
    177     if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
    178         goto error;
    179 #else
    180     /* The limits are probably bigger than a long */
    181     rl.rlim_cur = PyLong_Check(curobj) ?
    182         PyLong_AsLongLong(curobj) : PyInt_AsLong(curobj);
    183     if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
    184         goto error;
    185     rl.rlim_max = PyLong_Check(maxobj) ?
    186         PyLong_AsLongLong(maxobj) : PyInt_AsLong(maxobj);
    187     if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
    188         goto error;
    189 #endif
    190 
    191     rl.rlim_cur = rl.rlim_cur & RLIM_INFINITY;
    192     rl.rlim_max = rl.rlim_max & RLIM_INFINITY;
    193     if (setrlimit(resource, &rl) == -1) {
    194         if (errno == EINVAL)
    195             PyErr_SetString(PyExc_ValueError,
    196                             "current limit exceeds maximum limit");
    197         else if (errno == EPERM)
    198             PyErr_SetString(PyExc_ValueError,
    199                             "not allowed to raise maximum limit");
    200         else
    201             PyErr_SetFromErrno(ResourceError);
    202         goto error;
    203     }
    204     Py_DECREF(limits);
    205     Py_INCREF(Py_None);
    206     return Py_None;
    207 
    208   error:
    209     Py_DECREF(limits);
    210     return NULL;
    211 }
    212 
    213 static PyObject *
    214 resource_getpagesize(PyObject *self, PyObject *unused)
    215 {
    216     long pagesize = 0;
    217 #if defined(HAVE_GETPAGESIZE)
    218     pagesize = getpagesize();
    219 #elif defined(HAVE_SYSCONF)
    220 #if defined(_SC_PAGE_SIZE)
    221     pagesize = sysconf(_SC_PAGE_SIZE);
    222 #else
    223     /* Irix 5.3 has _SC_PAGESIZE, but not _SC_PAGE_SIZE */
    224     pagesize = sysconf(_SC_PAGESIZE);
    225 #endif
    226 #endif
    227     return Py_BuildValue("i", pagesize);
    228 
    229 }
    230 
    231 /* List of functions */
    232 
    233 static struct PyMethodDef
    234 resource_methods[] = {
    235     {"getrusage",    resource_getrusage,   METH_VARARGS},
    236     {"getrlimit",    resource_getrlimit,   METH_VARARGS},
    237     {"setrlimit",    resource_setrlimit,   METH_VARARGS},
    238     {"getpagesize",  resource_getpagesize, METH_NOARGS},
    239     {NULL, NULL}                             /* sentinel */
    240 };
    241 
    242 
    243 /* Module initialization */
    244 
    245 PyMODINIT_FUNC
    246 initresource(void)
    247 {
    248     PyObject *m, *v;
    249 
    250     /* Create the module and add the functions */
    251     m = Py_InitModule("resource", resource_methods);
    252     if (m == NULL)
    253         return;
    254 
    255     /* Add some symbolic constants to the module */
    256     if (ResourceError == NULL) {
    257         ResourceError = PyErr_NewException("resource.error",
    258                                            NULL, NULL);
    259     }
    260     Py_INCREF(ResourceError);
    261     PyModule_AddObject(m, "error", ResourceError);
    262     if (!initialized)
    263         PyStructSequence_InitType(&StructRUsageType,
    264                                   &struct_rusage_desc);
    265     Py_INCREF(&StructRUsageType);
    266     PyModule_AddObject(m, "struct_rusage",
    267                        (PyObject*) &StructRUsageType);
    268 
    269     /* insert constants */
    270 #ifdef RLIMIT_CPU
    271     PyModule_AddIntConstant(m, "RLIMIT_CPU", RLIMIT_CPU);
    272 #endif
    273 
    274 #ifdef RLIMIT_FSIZE
    275     PyModule_AddIntConstant(m, "RLIMIT_FSIZE", RLIMIT_FSIZE);
    276 #endif
    277 
    278 #ifdef RLIMIT_DATA
    279     PyModule_AddIntConstant(m, "RLIMIT_DATA", RLIMIT_DATA);
    280 #endif
    281 
    282 #ifdef RLIMIT_STACK
    283     PyModule_AddIntConstant(m, "RLIMIT_STACK", RLIMIT_STACK);
    284 #endif
    285 
    286 #ifdef RLIMIT_CORE
    287     PyModule_AddIntConstant(m, "RLIMIT_CORE", RLIMIT_CORE);
    288 #endif
    289 
    290 #ifdef RLIMIT_NOFILE
    291     PyModule_AddIntConstant(m, "RLIMIT_NOFILE", RLIMIT_NOFILE);
    292 #endif
    293 
    294 #ifdef RLIMIT_OFILE
    295     PyModule_AddIntConstant(m, "RLIMIT_OFILE", RLIMIT_OFILE);
    296 #endif
    297 
    298 #ifdef RLIMIT_VMEM
    299     PyModule_AddIntConstant(m, "RLIMIT_VMEM", RLIMIT_VMEM);
    300 #endif
    301 
    302 #ifdef RLIMIT_AS
    303     PyModule_AddIntConstant(m, "RLIMIT_AS", RLIMIT_AS);
    304 #endif
    305 
    306 #ifdef RLIMIT_RSS
    307     PyModule_AddIntConstant(m, "RLIMIT_RSS", RLIMIT_RSS);
    308 #endif
    309 
    310 #ifdef RLIMIT_NPROC
    311     PyModule_AddIntConstant(m, "RLIMIT_NPROC", RLIMIT_NPROC);
    312 #endif
    313 
    314 #ifdef RLIMIT_MEMLOCK
    315     PyModule_AddIntConstant(m, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK);
    316 #endif
    317 
    318 #ifdef RLIMIT_SBSIZE
    319     PyModule_AddIntConstant(m, "RLIMIT_SBSIZE", RLIMIT_SBSIZE);
    320 #endif
    321 
    322 #ifdef RUSAGE_SELF
    323     PyModule_AddIntConstant(m, "RUSAGE_SELF", RUSAGE_SELF);
    324 #endif
    325 
    326 #ifdef RUSAGE_CHILDREN
    327     PyModule_AddIntConstant(m, "RUSAGE_CHILDREN", RUSAGE_CHILDREN);
    328 #endif
    329 
    330 #ifdef RUSAGE_BOTH
    331     PyModule_AddIntConstant(m, "RUSAGE_BOTH", RUSAGE_BOTH);
    332 #endif
    333 
    334 #if defined(HAVE_LONG_LONG)
    335     if (sizeof(RLIM_INFINITY) > sizeof(long)) {
    336         v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY);
    337     } else
    338 #endif
    339     {
    340         v = PyInt_FromLong((long) RLIM_INFINITY);
    341     }
    342     if (v) {
    343         PyModule_AddObject(m, "RLIM_INFINITY", v);
    344     }
    345     initialized = 1;
    346 }
    347