Added Jeremy's resource module.
diff --git a/Modules/resource.c b/Modules/resource.c
new file mode 100644
index 0000000..48d148d
--- /dev/null
+++ b/Modules/resource.c
@@ -0,0 +1,240 @@
+#include "Python.h"
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+/* don't know why this isn't defined in a header file */
+#ifndef getrusage
+int getrusage(int who, struct rusage *rusage);
+#endif
+
+#ifndef getpagesize
+int getpagesize(void);
+#endif
+
+#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
+
+static PyObject *ResourceError;
+
+static PyObject *
+resource_getrusage(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	int who;
+	struct rusage ru;
+
+	if (!PyArg_ParseTuple(args, "i", &who))
+		return NULL;
+
+	if (getrusage(who, &ru) == -1) {
+		if (errno == EINVAL) {
+			PyErr_SetString(PyExc_ValueError,
+					"invalid who parameter");
+			return NULL;
+		} 
+		PyErr_SetFromErrno(ResourceError);
+		return NULL;
+	}
+
+	/* Yeah, this 16-tuple is way ugly. It's probably a lot less
+	   ugly than a dictionary with keys (or object attributes)
+	   named things like 'ixrss'. 
+	   */
+	return Py_BuildValue(
+		"ddiiiiiiiiiiiiii",
+		doubletime(ru.ru_utime),     /* user time used */
+		doubletime(ru.ru_stime),     /* system time used */
+		ru.ru_maxrss,		     /* max. resident set size */
+		ru.ru_ixrss,		     /* shared memory size */
+		ru.ru_idrss,		     /* unshared memory size */
+		ru.ru_isrss,		     /* unshared stack size */
+		ru.ru_minflt,		     /* page faults not requiring I/O*/
+		ru.ru_majflt,		     /* page faults requiring I/O */
+		ru.ru_nswap,		     /* number of swap outs */
+		ru.ru_inblock,		     /* block input operations */
+		ru.ru_oublock,		     /* block output operations */
+		ru.ru_msgsnd,		     /* messages sent */
+		ru.ru_msgrcv,		     /* messages received */
+		ru.ru_nsignals,		     /* signals received */
+		ru.ru_nvcsw,		     /* voluntary context switchs */
+		ru.ru_nivcsw		     /* involuntary context switchs */
+		);
+}
+
+
+static PyObject *
+resource_getrlimit(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	struct rlimit rl;
+	int resource;
+	char *errstr;
+
+	if (!PyArg_ParseTuple(args, "i", &resource)) 
+		return NULL;
+
+	if (resource < 0 || resource >= RLIM_NLIMITS) {
+		PyErr_SetString(PyExc_ValueError,
+				"invalid resource specified");
+		return NULL;
+	}
+
+	if (getrlimit(resource, &rl) == -1) {
+		PyErr_SetFromErrno(ResourceError);
+		return NULL;
+	}
+	return Py_BuildValue("ii", rl.rlim_cur, rl.rlim_max);
+}
+
+static PyObject *
+resource_setrlimit(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	struct rlimit rl;
+	int resource;
+	char *errstr;
+
+	if (!PyArg_ParseTuple(args, "i(ii)", &resource, &rl.rlim_cur, 
+			      &rl.rlim_max)) 
+		return NULL;
+
+	if (resource < 0 || resource >= RLIM_NLIMITS) {
+		PyErr_SetString(PyExc_ValueError,
+				"invalid resource specified");
+		return NULL;
+	}
+
+	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
+			PyErr_SetFromErrno(ResourceError);
+		return NULL;
+	}
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+resource_getpagesize(self, args)
+	PyObject *self;
+	PyObject *args;
+{
+	if (!PyArg_ParseTuple(args, ""))
+		return NULL;
+	return Py_BuildValue("i", getpagesize());
+}
+
+/* List of functions */
+
+static struct PyMethodDef
+resource_methods[] = {
+	{"getrusage",    resource_getrusage,   1},
+	{"getrlimit",    resource_getrlimit,   1},
+	{"setrlimit",    resource_setrlimit,   1},
+	{"getpagesize",  resource_getpagesize, 1},
+	{NULL, NULL}			     /* sentinel */
+};
+
+
+/* Module initialization */
+
+static void
+ins(PyObject *dict, char *name, int value)
+{
+	PyObject *v = PyInt_FromLong((long) value);
+	if (v) {
+		PyDict_SetItemString(dict, name, v);
+		Py_DECREF(v);
+	}
+	/* errors will be checked by initresource() */
+}
+
+void initresource()
+{
+	PyObject *m, *d;
+
+	/* Create the module and add the functions */
+	m = Py_InitModule("resource", resource_methods);
+
+	/* Add some symbolic constants to the module */
+	d = PyModule_GetDict(m);
+	ResourceError = PyString_FromString("resource.error");
+	PyDict_SetItemString(d, "error", ResourceError);
+
+	/* insert constants */
+#ifdef RLIMIT_CPU
+	ins(d, "RLIMIT_CPU", RLIMIT_CPU);
+#endif
+
+#ifdef RLIMIT_FSIZE
+	ins(d, "RLIMIT_FSIZE", RLIMIT_FSIZE);
+#endif
+
+#ifdef RLIMIT_DATA
+	ins(d, "RLIMIT_DATA", RLIMIT_DATA);
+#endif
+
+#ifdef RLIMIT_STACK
+	ins(d, "RLIMIT_STACK", RLIMIT_STACK);
+#endif
+
+#ifdef RLIMIT_CORE
+	ins(d, "RLIMIT_CORE", RLIMIT_CORE);
+#endif
+
+#ifdef RLIMIT_NOFILE
+	ins(d, "RLIMIT_NOFILE", RLIMIT_NOFILE);
+#endif
+
+#ifdef RLIMIT_OFILE
+	ins(d, "RLIMIT_OFILE", RLIMIT_OFILE);
+#endif
+
+#ifdef RLIMIT_VMEM
+	ins(d, "RLIMIT_VMEM", RLIMIT_VMEM);
+#endif
+
+#ifdef RLIMIT_AS
+	ins(d, "RLIMIT_AS", RLIMIT_AS);
+#endif
+
+#ifdef RLIMIT_RSS
+	ins(d, "RLIMIT_RSS", RLIMIT_RSS);
+#endif
+
+#ifdef RLIMIT_NPROC
+	ins(d, "RLIMIT_NPROC", RLIMIT_NPROC);
+#endif
+
+#ifdef RLIMIT_MEMLOCK
+	ins(d, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK);
+#endif
+
+#ifdef RUSAGE_SELF
+	ins(d, "RUSAGE_SELF", RUSAGE_SELF);
+#endif
+
+#ifdef RUSAGE_CHILDERN
+	ins(d, "RUSAGE_CHILDREN", RUSAGE_CHILDREN);
+#endif
+
+#ifdef RUSAGE_BOTH
+	ins(d, "RUSAGE_BOTH", RUSAGE_BOTH);
+#endif
+
+	/* Check for errors */
+	if (PyErr_Occurred())
+		Py_FatalError("can't initialize module resource");
+}