resource.c 10 KB
Newer Older
1

2 3 4 5 6
#include "Python.h"
#include <sys/resource.h>
#include <sys/time.h>
#include <string.h>
#include <errno.h>
7 8 9 10
/* for sysconf */
#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
11

12 13 14 15 16 17
/* On some systems, these aren't in any header file.
   On others they are, with inconsistent prototypes.
   We declare the (default) return type, to shut up gcc -Wall;
   but we can't declare the prototype, to avoid errors
   when the header files declare it different.
   Worse, on some Linuxes, getpagesize() returns a size_t... */
18 19 20

#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)

21 22 23 24 25 26
PyDoc_STRVAR(struct_rusage__doc__,
"struct_rusage: Result from getrusage.\n\n"
"This object may be accessed either as a tuple of\n"
"    (utime,stime,maxrss,ixrss,idrss,isrss,minflt,majflt,\n"
"    nswap,inblock,oublock,msgsnd,msgrcv,nsignals,nvcsw,nivcsw)\n"
"or via the attributes ru_utime, ru_stime, ru_maxrss, and so on.");
27 28

static PyStructSequence_Field struct_rusage_fields[] = {
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
    {"ru_utime",        "user time used"},
    {"ru_stime",        "system time used"},
    {"ru_maxrss",       "max. resident set size"},
    {"ru_ixrss",        "shared memory size"},
    {"ru_idrss",        "unshared data size"},
    {"ru_isrss",        "unshared stack size"},
    {"ru_minflt",       "page faults not requiring I/O"},
    {"ru_majflt",       "page faults requiring I/O"},
    {"ru_nswap",        "number of swap outs"},
    {"ru_inblock",      "block input operations"},
    {"ru_oublock",      "block output operations"},
    {"ru_msgsnd",       "IPC messages sent"},
    {"ru_msgrcv",       "IPC messages received"},
    {"ru_nsignals",     "signals received"},
    {"ru_nvcsw",        "voluntary context switches"},
    {"ru_nivcsw",       "involuntary context switches"},
    {0}
46 47 48
};

static PyStructSequence_Desc struct_rusage_desc = {
49 50 51 52
    "resource.struct_rusage",           /* name */
    struct_rusage__doc__,       /* doc */
    struct_rusage_fields,       /* fields */
    16          /* n_in_sequence */
53 54
};

55
static int initialized;
56 57
static PyTypeObject StructRUsageType;

58
static PyObject *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
59
resource_getrusage(PyObject *self, PyObject *args)
60
{
61 62 63 64 65 66 67 68 69 70 71 72 73
    int who;
    struct rusage ru;
    PyObject *result;

    if (!PyArg_ParseTuple(args, "i:getrusage", &who))
        return NULL;

    if (getrusage(who, &ru) == -1) {
        if (errno == EINVAL) {
            PyErr_SetString(PyExc_ValueError,
                            "invalid who parameter");
            return NULL;
        }
74
        PyErr_SetFromErrno(PyExc_OSError);
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
        return NULL;
    }

    result = PyStructSequence_New(&StructRUsageType);
    if (!result)
        return NULL;

    PyStructSequence_SET_ITEM(result, 0,
                    PyFloat_FromDouble(doubletime(ru.ru_utime)));
    PyStructSequence_SET_ITEM(result, 1,
                    PyFloat_FromDouble(doubletime(ru.ru_stime)));
    PyStructSequence_SET_ITEM(result, 2, PyLong_FromLong(ru.ru_maxrss));
    PyStructSequence_SET_ITEM(result, 3, PyLong_FromLong(ru.ru_ixrss));
    PyStructSequence_SET_ITEM(result, 4, PyLong_FromLong(ru.ru_idrss));
    PyStructSequence_SET_ITEM(result, 5, PyLong_FromLong(ru.ru_isrss));
    PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(ru.ru_minflt));
    PyStructSequence_SET_ITEM(result, 7, PyLong_FromLong(ru.ru_majflt));
    PyStructSequence_SET_ITEM(result, 8, PyLong_FromLong(ru.ru_nswap));
    PyStructSequence_SET_ITEM(result, 9, PyLong_FromLong(ru.ru_inblock));
    PyStructSequence_SET_ITEM(result, 10, PyLong_FromLong(ru.ru_oublock));
    PyStructSequence_SET_ITEM(result, 11, PyLong_FromLong(ru.ru_msgsnd));
    PyStructSequence_SET_ITEM(result, 12, PyLong_FromLong(ru.ru_msgrcv));
    PyStructSequence_SET_ITEM(result, 13, PyLong_FromLong(ru.ru_nsignals));
    PyStructSequence_SET_ITEM(result, 14, PyLong_FromLong(ru.ru_nvcsw));
    PyStructSequence_SET_ITEM(result, 15, PyLong_FromLong(ru.ru_nivcsw));

    if (PyErr_Occurred()) {
        Py_DECREF(result);
        return NULL;
    }

    return result;
107 108 109 110
}


static PyObject *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
111
resource_getrlimit(PyObject *self, PyObject *args)
112
{
113 114
    struct rlimit rl;
    int resource;
115

116 117
    if (!PyArg_ParseTuple(args, "i:getrlimit", &resource))
        return NULL;
118

119 120 121 122 123
    if (resource < 0 || resource >= RLIM_NLIMITS) {
        PyErr_SetString(PyExc_ValueError,
                        "invalid resource specified");
        return NULL;
    }
124

125
    if (getrlimit(resource, &rl) == -1) {
126
        PyErr_SetFromErrno(PyExc_OSError);
127 128
        return NULL;
    }
129 130

#if defined(HAVE_LONG_LONG)
131 132 133 134 135
    if (sizeof(rl.rlim_cur) > sizeof(long)) {
        return Py_BuildValue("LL",
                             (PY_LONG_LONG) rl.rlim_cur,
                             (PY_LONG_LONG) rl.rlim_max);
    }
136
#endif
137
    return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max);
138 139 140
}

static PyObject *
Peter Schneider-Kamp's avatar
Peter Schneider-Kamp committed
141
resource_setrlimit(PyObject *self, PyObject *args)
142
{
143 144
    struct rlimit rl;
    int resource;
145
    PyObject *limits, *curobj, *maxobj;
146

147
    if (!PyArg_ParseTuple(args, "iO:setrlimit", &resource, &limits))
148
        return NULL;
149

150 151 152 153 154
    if (resource < 0 || resource >= RLIM_NLIMITS) {
        PyErr_SetString(PyExc_ValueError,
                        "invalid resource specified");
        return NULL;
    }
155

156 157 158 159 160 161 162 163 164 165 166 167 168
    limits = PySequence_Tuple(limits);
    if (!limits)
        /* Here limits is a borrowed reference */
        return NULL;

    if (PyTuple_GET_SIZE(limits) != 2) {
        PyErr_SetString(PyExc_ValueError,
                        "expected a tuple of 2 integers");
        goto error;
    }
    curobj = PyTuple_GET_ITEM(limits, 0);
    maxobj = PyTuple_GET_ITEM(limits, 1);

169
#if !defined(HAVE_LARGEFILE_SUPPORT)
170 171
    rl.rlim_cur = PyLong_AsLong(curobj);
    if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
172
        goto error;
173 174
    rl.rlim_max = PyLong_AsLong(maxobj);
    if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
175
        goto error;
176
#else
177 178 179
    /* The limits are probably bigger than a long */
    rl.rlim_cur = PyLong_AsLongLong(curobj);
    if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
180
        goto error;
181 182
    rl.rlim_max = PyLong_AsLongLong(maxobj);
    if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
183
        goto error;
184 185
#endif

186 187 188 189 190 191 192 193 194 195
    rl.rlim_cur = rl.rlim_cur & RLIM_INFINITY;
    rl.rlim_max = rl.rlim_max & RLIM_INFINITY;
    if (setrlimit(resource, &rl) == -1) {
        if (errno == EINVAL)
            PyErr_SetString(PyExc_ValueError,
                            "current limit exceeds maximum limit");
        else if (errno == EPERM)
            PyErr_SetString(PyExc_ValueError,
                            "not allowed to raise maximum limit");
        else
196
            PyErr_SetFromErrno(PyExc_OSError);
197
        goto error;
198
    }
199
    Py_DECREF(limits);
200 201
    Py_INCREF(Py_None);
    return Py_None;
202 203 204 205

  error:
    Py_DECREF(limits);
    return NULL;
206 207 208
}

static PyObject *
209
resource_getpagesize(PyObject *self, PyObject *unused)
210
{
211
    long pagesize = 0;
212
#if defined(HAVE_GETPAGESIZE)
213
    pagesize = getpagesize();
214
#elif defined(HAVE_SYSCONF)
215
#if defined(_SC_PAGE_SIZE)
216
    pagesize = sysconf(_SC_PAGE_SIZE);
217
#else
218 219
    /* Irix 5.3 has _SC_PAGESIZE, but not _SC_PAGE_SIZE */
    pagesize = sysconf(_SC_PAGESIZE);
220
#endif
221
#endif
222
    return Py_BuildValue("i", pagesize);
223

224 225 226 227 228 229
}

/* List of functions */

static struct PyMethodDef
resource_methods[] = {
230 231 232 233 234
    {"getrusage",    resource_getrusage,   METH_VARARGS},
    {"getrlimit",    resource_getrlimit,   METH_VARARGS},
    {"setrlimit",    resource_setrlimit,   METH_VARARGS},
    {"getpagesize",  resource_getpagesize, METH_NOARGS},
    {NULL, NULL}                             /* sentinel */
235 236 237 238 239
};


/* Module initialization */

240 241

static struct PyModuleDef resourcemodule = {
242 243 244 245 246 247 248 249 250
    PyModuleDef_HEAD_INIT,
    "resource",
    NULL,
    -1,
    resource_methods,
    NULL,
    NULL,
    NULL,
    NULL
251 252
};

253
PyMODINIT_FUNC
254
PyInit_resource(void)
255
{
256 257 258 259 260 261 262 263
    PyObject *m, *v;

    /* Create the module and add the functions */
    m = PyModule_Create(&resourcemodule);
    if (m == NULL)
        return NULL;

    /* Add some symbolic constants to the module */
264 265
    Py_INCREF(PyExc_OSError);
    PyModule_AddObject(m, "error", PyExc_OSError);
266 267 268 269 270 271 272 273
    if (!initialized)
        PyStructSequence_InitType(&StructRUsageType,
                                  &struct_rusage_desc);
    Py_INCREF(&StructRUsageType);
    PyModule_AddObject(m, "struct_rusage",
                       (PyObject*) &StructRUsageType);

    /* insert constants */
274
#ifdef RLIMIT_CPU
275
    PyModule_AddIntConstant(m, "RLIMIT_CPU", RLIMIT_CPU);
276 277 278
#endif

#ifdef RLIMIT_FSIZE
279
    PyModule_AddIntConstant(m, "RLIMIT_FSIZE", RLIMIT_FSIZE);
280 281 282
#endif

#ifdef RLIMIT_DATA
283
    PyModule_AddIntConstant(m, "RLIMIT_DATA", RLIMIT_DATA);
284 285 286
#endif

#ifdef RLIMIT_STACK
287
    PyModule_AddIntConstant(m, "RLIMIT_STACK", RLIMIT_STACK);
288 289 290
#endif

#ifdef RLIMIT_CORE
291
    PyModule_AddIntConstant(m, "RLIMIT_CORE", RLIMIT_CORE);
292 293 294
#endif

#ifdef RLIMIT_NOFILE
295
    PyModule_AddIntConstant(m, "RLIMIT_NOFILE", RLIMIT_NOFILE);
296 297 298
#endif

#ifdef RLIMIT_OFILE
299
    PyModule_AddIntConstant(m, "RLIMIT_OFILE", RLIMIT_OFILE);
300 301 302
#endif

#ifdef RLIMIT_VMEM
303
    PyModule_AddIntConstant(m, "RLIMIT_VMEM", RLIMIT_VMEM);
304 305 306
#endif

#ifdef RLIMIT_AS
307
    PyModule_AddIntConstant(m, "RLIMIT_AS", RLIMIT_AS);
308 309 310
#endif

#ifdef RLIMIT_RSS
311
    PyModule_AddIntConstant(m, "RLIMIT_RSS", RLIMIT_RSS);
312 313 314
#endif

#ifdef RLIMIT_NPROC
315
    PyModule_AddIntConstant(m, "RLIMIT_NPROC", RLIMIT_NPROC);
316 317 318
#endif

#ifdef RLIMIT_MEMLOCK
319
    PyModule_AddIntConstant(m, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK);
320 321
#endif

322
#ifdef RLIMIT_SBSIZE
323
    PyModule_AddIntConstant(m, "RLIMIT_SBSIZE", RLIMIT_SBSIZE);
324 325
#endif

326
#ifdef RUSAGE_SELF
327
    PyModule_AddIntConstant(m, "RUSAGE_SELF", RUSAGE_SELF);
328 329
#endif

330
#ifdef RUSAGE_CHILDREN
331
    PyModule_AddIntConstant(m, "RUSAGE_CHILDREN", RUSAGE_CHILDREN);
332 333 334
#endif

#ifdef RUSAGE_BOTH
335
    PyModule_AddIntConstant(m, "RUSAGE_BOTH", RUSAGE_BOTH);
336
#endif
337

338 339 340 341
#ifdef RUSAGE_THREAD
    PyModule_AddIntConstant(m, "RUSAGE_THREAD", RUSAGE_THREAD);
#endif

342
#if defined(HAVE_LONG_LONG)
343 344 345
    if (sizeof(RLIM_INFINITY) > sizeof(long)) {
        v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY);
    } else
346
#endif
347 348 349 350 351 352 353 354
    {
        v = PyLong_FromLong((long) RLIM_INFINITY);
    }
    if (v) {
        PyModule_AddObject(m, "RLIM_INFINITY", v);
    }
    initialized = 1;
    return m;
355
}