Author: Armin Rigo <[email protected]>
Branch:
Changeset: r83736:09ae247ce9d7
Date: 2016-04-18 11:48 +0200
http://bitbucket.org/pypy/pypy/changeset/09ae247ce9d7/
Log: Rewrite resource.py to use cffi instead of ctypes_config_cache
diff --git a/lib_pypy/_resource_build.py b/lib_pypy/_resource_build.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_resource_build.py
@@ -0,0 +1,109 @@
+from cffi import FFI
+
+ffi = FFI()
+
+# Note: we don't directly expose 'struct timeval' or 'struct rlimit'
+
+
+rlimit_consts = '''
+RLIMIT_CPU
+RLIMIT_FSIZE
+RLIMIT_DATA
+RLIMIT_STACK
+RLIMIT_CORE
+RLIMIT_NOFILE
+RLIMIT_OFILE
+RLIMIT_VMEM
+RLIMIT_AS
+RLIMIT_RSS
+RLIMIT_NPROC
+RLIMIT_MEMLOCK
+RLIMIT_SBSIZE
+RLIM_INFINITY
+RUSAGE_SELF
+RUSAGE_CHILDREN
+RUSAGE_BOTH
+'''.split()
+
+rlimit_consts = ['#ifdef %s\n\t{"%s", %s},\n#endif\n' % (s, s, s)
+ for s in rlimit_consts]
+
+
+ffi.set_source("_resource_cffi", """
+#include <sys/resource.h>
+
+static const struct my_rlimit_def {
+ const char *name;
+ long long value;
+} my_rlimit_consts[] = {
+$RLIMIT_CONSTS
+ { NULL, 0 }
+};
+
+#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001)
+
+static int my_getrusage(int who, struct rusage *result, double times[2])
+{
+ if (getrusage(who, result) == -1)
+ return -1;
+ times[0] = doubletime(result->ru_utime);
+ times[1] = doubletime(result->ru_stime);
+ return 0;
+}
+
+static int my_getrlimit(int resource, long long result[2])
+{
+ struct rlimit rl;
+ if (getrlimit(resource, &rl) == -1)
+ return -1;
+ result[0] = rl.rlim_cur;
+ result[1] = rl.rlim_max;
+ return 0;
+}
+
+static int my_setrlimit(int resource, long long cur, long long max)
+{
+ struct rlimit rl;
+ rl.rlim_cur = cur & RLIM_INFINITY;
+ rl.rlim_max = max & RLIM_INFINITY;
+ return setrlimit(resource, &rl);
+}
+
+""".replace('$RLIMIT_CONSTS', ''.join(rlimit_consts)))
+
+
+ffi.cdef("""
+
+#define RLIM_NLIMITS ...
+
+const struct my_rlimit_def {
+ const char *name;
+ long long value;
+} my_rlimit_consts[];
+
+struct rusage {
+ long ru_maxrss;
+ long ru_ixrss;
+ long ru_idrss;
+ long ru_isrss;
+ long ru_minflt;
+ long ru_majflt;
+ long ru_nswap;
+ long ru_inblock;
+ long ru_oublock;
+ long ru_msgsnd;
+ long ru_msgrcv;
+ long ru_nsignals;
+ long ru_nvcsw;
+ long ru_nivcsw;
+ ...;
+};
+
+void my_getrusage(int who, struct rusage *result, double times[2]);
+int my_getrlimit(int resource, long long result[2]);
+int my_setrlimit(int resource, long long cur, long long max);
+""")
+
+
+if __name__ == "__main__":
+ ffi.compile()
diff --git a/lib_pypy/pwd.py b/lib_pypy/pwd.py
--- a/lib_pypy/pwd.py
+++ b/lib_pypy/pwd.py
@@ -1,4 +1,4 @@
-# ctypes implementation: Victor Stinner, 2008-05-08
+# indirectly based on ctypes implementation: Victor Stinner, 2008-05-08
"""
This module provides access to the Unix password database.
It is available on all Unix versions.
diff --git a/lib_pypy/resource.py b/lib_pypy/resource.py
--- a/lib_pypy/resource.py
+++ b/lib_pypy/resource.py
@@ -1,15 +1,8 @@
-import sys
-if sys.platform == 'win32':
- raise ImportError('resource module not available for win32')
+"""http://docs.python.org/library/resource"""
-# load the platform-specific cache made by running resource.ctc.py
-from ctypes_config_cache._resource_cache import *
-
-from ctypes_support import standard_c_lib as libc
-from ctypes_support import get_errno
-from ctypes import Structure, c_int, c_long, byref, POINTER
+from _resource_cffi import ffi, lib
from errno import EINVAL, EPERM
-import _structseq
+import _structseq, os
try: from __pypy__ import builtinify
except ImportError: builtinify = lambda f: f
@@ -18,106 +11,47 @@
class error(Exception):
pass
+class struct_rusage:
+ """struct_rusage: Result from getrusage.
-# Read required libc functions
-_getrusage = libc.getrusage
-_getrlimit = libc.getrlimit
-_setrlimit = libc.setrlimit
-try:
- _getpagesize = libc.getpagesize
- _getpagesize.argtypes = ()
- _getpagesize.restype = c_int
-except AttributeError:
- from os import sysconf
- _getpagesize = None
+This object may be accessed either as a tuple of
+ (utime,stime,maxrss,ixrss,idrss,isrss,minflt,majflt,
+ nswap,inblock,oublock,msgsnd,msgrcv,nsignals,nvcsw,nivcsw)
+or via the attributes ru_utime, ru_stime, ru_maxrss, and so on."""
-
-class timeval(Structure):
- _fields_ = (
- ("tv_sec", c_long),
- ("tv_usec", c_long),
- )
- def __str__(self):
- return "(%s, %s)" % (self.tv_sec, self.tv_usec)
-
- def __float__(self):
- return self.tv_sec + self.tv_usec/1000000.0
-
-class _struct_rusage(Structure):
- _fields_ = (
- ("ru_utime", timeval),
- ("ru_stime", timeval),
- ("ru_maxrss", c_long),
- ("ru_ixrss", c_long),
- ("ru_idrss", c_long),
- ("ru_isrss", c_long),
- ("ru_minflt", c_long),
- ("ru_majflt", c_long),
- ("ru_nswap", c_long),
- ("ru_inblock", c_long),
- ("ru_oublock", c_long),
- ("ru_msgsnd", c_long),
- ("ru_msgrcv", c_long),
- ("ru_nsignals", c_long),
- ("ru_nvcsw", c_long),
- ("ru_nivcsw", c_long),
- )
-
-_getrusage.argtypes = (c_int, POINTER(_struct_rusage))
-_getrusage.restype = c_int
-
-
-class struct_rusage:
__metaclass__ = _structseq.structseqtype
- ru_utime = _structseq.structseqfield(0)
- ru_stime = _structseq.structseqfield(1)
- ru_maxrss = _structseq.structseqfield(2)
- ru_ixrss = _structseq.structseqfield(3)
- ru_idrss = _structseq.structseqfield(4)
- ru_isrss = _structseq.structseqfield(5)
- ru_minflt = _structseq.structseqfield(6)
- ru_majflt = _structseq.structseqfield(7)
- ru_nswap = _structseq.structseqfield(8)
- ru_inblock = _structseq.structseqfield(9)
- ru_oublock = _structseq.structseqfield(10)
- ru_msgsnd = _structseq.structseqfield(11)
- ru_msgrcv = _structseq.structseqfield(12)
- ru_nsignals = _structseq.structseqfield(13)
- ru_nvcsw = _structseq.structseqfield(14)
- ru_nivcsw = _structseq.structseqfield(15)
-
-@builtinify
-def rlimit_check_bounds(rlim_cur, rlim_max):
- if rlim_cur > rlim_t_max:
- raise ValueError("%d does not fit into rlim_t" % rlim_cur)
- if rlim_max > rlim_t_max:
- raise ValueError("%d does not fit into rlim_t" % rlim_max)
-
-class rlimit(Structure):
- _fields_ = (
- ("rlim_cur", rlim_t),
- ("rlim_max", rlim_t),
- )
-
-_getrlimit.argtypes = (c_int, POINTER(rlimit))
-_getrlimit.restype = c_int
-_setrlimit.argtypes = (c_int, POINTER(rlimit))
-_setrlimit.restype = c_int
+ ru_utime = _structseq.structseqfield(0, "user time used")
+ ru_stime = _structseq.structseqfield(1, "system time used")
+ ru_maxrss = _structseq.structseqfield(2, "max. resident set size")
+ ru_ixrss = _structseq.structseqfield(3, "shared memory size")
+ ru_idrss = _structseq.structseqfield(4, "unshared data size")
+ ru_isrss = _structseq.structseqfield(5, "unshared stack size")
+ ru_minflt = _structseq.structseqfield(6, "page faults not requiring I/O")
+ ru_majflt = _structseq.structseqfield(7, "page faults requiring I/O")
+ ru_nswap = _structseq.structseqfield(8, "number of swap outs")
+ ru_inblock = _structseq.structseqfield(9, "block input operations")
+ ru_oublock = _structseq.structseqfield(10, "block output operations")
+ ru_msgsnd = _structseq.structseqfield(11, "IPC messages sent")
+ ru_msgrcv = _structseq.structseqfield(12, "IPC messages received")
+ ru_nsignals = _structseq.structseqfield(13,"signals received")
+ ru_nvcsw = _structseq.structseqfield(14, "voluntary context switches")
+ ru_nivcsw = _structseq.structseqfield(15, "involuntary context switches")
@builtinify
def getrusage(who):
- ru = _struct_rusage()
- ret = _getrusage(who, byref(ru))
+ ru = ffi.new("struct rusage *")
+ times = ffi.new("double[2]")
+ ret = lib.my_getrusage(who, ru, times)
if ret == -1:
- errno = get_errno()
+ errno = ffi.errno
if errno == EINVAL:
raise ValueError("invalid who parameter")
raise error(errno)
return struct_rusage((
- float(ru.ru_utime),
- float(ru.ru_stime),
+ times[0],
+ times[1],
ru.ru_maxrss,
ru.ru_ixrss,
ru.ru_idrss,
@@ -136,47 +70,49 @@
@builtinify
def getrlimit(resource):
- if not(0 <= resource < RLIM_NLIMITS):
+ if not (0 <= resource < lib.RLIM_NLIMITS):
return ValueError("invalid resource specified")
- rlim = rlimit()
- ret = _getrlimit(resource, byref(rlim))
- if ret == -1:
- errno = get_errno()
- raise error(errno)
- return (rlim.rlim_cur, rlim.rlim_max)
+ result = ffi.new("long long[2]")
+ if lib.my_getrlimit(resource, result) == -1:
+ raise error(ffi.errno)
+ return (result[0], result[1])
@builtinify
-def setrlimit(resource, rlim):
- if not(0 <= resource < RLIM_NLIMITS):
+def setrlimit(resource, limits):
+ if not (0 <= resource < lib.RLIM_NLIMITS):
return ValueError("invalid resource specified")
- rlimit_check_bounds(*rlim)
- rlim = rlimit(rlim[0], rlim[1])
- ret = _setrlimit(resource, byref(rlim))
- if ret == -1:
- errno = get_errno()
- if errno == EINVAL:
- return ValueError("current limit exceeds maximum limit")
- elif errno == EPERM:
- return ValueError("not allowed to raise maximum limit")
+ limits = tuple(limits)
+ if len(limits) != 2:
+ raise ValueError("expected a tuple of 2 integers")
+
+ if lib.my_setrlimit(resource, limits[0], limits[1]) == -1:
+ if ffi.errno == EINVAL:
+ raise ValueError("current limit exceeds maximum limit")
+ elif ffi.errno == EPERM:
+ raise ValueError("not allowed to raise maximum limit")
else:
- raise error(errno)
+ raise error(ffi.errno)
+
@builtinify
def getpagesize():
- if _getpagesize:
- return _getpagesize()
- else:
- try:
- return sysconf("SC_PAGE_SIZE")
- except ValueError:
- # Irix 5.3 has _SC_PAGESIZE, but not _SC_PAGE_SIZE
- return sysconf("SC_PAGESIZE")
+ return os.sysconf("SC_PAGESIZE")
-__all__ = ALL_CONSTANTS + (
- 'error', 'timeval', 'struct_rusage', 'rlimit',
- 'getrusage', 'getrlimit', 'setrlimit', 'getpagesize',
+
+def _setup():
+ all_constants = []
+ p = lib.my_rlimit_consts
+ while p.name:
+ name = ffi.string(p.name)
+ globals()[name] = int(p.value)
+ all_constants.append(name)
+ p += 1
+ return all_constants
+
+__all__ = tuple(_setup()) + (
+ 'error', 'getpagesize', 'struct_rusage',
+ 'getrusage', 'getrlimit', 'setrlimit',
)
-
-del ALL_CONSTANTS
+del _setup
diff --git a/pypy/module/test_lib_pypy/test_resource.py
b/pypy/module/test_lib_pypy/test_resource.py
--- a/pypy/module/test_lib_pypy/test_resource.py
+++ b/pypy/module/test_lib_pypy/test_resource.py
@@ -1,44 +1,46 @@
from __future__ import absolute_import
-from lib_pypy.ctypes_config_cache import rebuild
-from pypy.module.test_lib_pypy.support import import_lib_pypy
-
import os
if os.name != 'posix':
skip('resource.h only available on unix')
-class AppTestResource:
+from lib_pypy import resource
- spaceconfig = dict(usemodules=('_rawffi', 'itertools'))
- def setup_class(cls):
- rebuild.rebuild_one('resource.ctc.py')
- cls.w_resource = import_lib_pypy(cls.space, 'resource',
- 'No resource module available')
+def test_getrusage():
+ x = resource.getrusage(resource.RUSAGE_SELF)
+ assert len(x) == 16
+ assert x[0] == x[-16] == x.ru_utime
+ assert x[1] == x[-15] == x.ru_stime
+ assert x[2] == x[-14] == x.ru_maxrss
+ assert x[3] == x[-13] == x.ru_ixrss
+ assert x[4] == x[-12] == x.ru_idrss
+ assert x[5] == x[-11] == x.ru_isrss
+ assert x[6] == x[-10] == x.ru_minflt
+ assert x[7] == x[-9] == x.ru_majflt
+ assert x[8] == x[-8] == x.ru_nswap
+ assert x[9] == x[-7] == x.ru_inblock
+ assert x[10] == x[-6] == x.ru_oublock
+ assert x[11] == x[-5] == x.ru_msgsnd
+ assert x[12] == x[-4] == x.ru_msgrcv
+ assert x[13] == x[-3] == x.ru_nsignals
+ assert x[14] == x[-2] == x.ru_nvcsw
+ assert x[15] == x[-1] == x.ru_nivcsw
+ for i in range(16):
+ if i < 2:
+ expected_type = float
+ else:
+ expected_type = (int, long)
+ assert isinstance(x[i], expected_type)
- def test_resource(self):
- resource = self.resource
- x = resource.getrusage(resource.RUSAGE_SELF)
- assert len(x) == 16
- assert x[0] == x[-16] == x.ru_utime
- assert x[1] == x[-15] == x.ru_stime
- assert x[2] == x[-14] == x.ru_maxrss
- assert x[3] == x[-13] == x.ru_ixrss
- assert x[4] == x[-12] == x.ru_idrss
- assert x[5] == x[-11] == x.ru_isrss
- assert x[6] == x[-10] == x.ru_minflt
- assert x[7] == x[-9] == x.ru_majflt
- assert x[8] == x[-8] == x.ru_nswap
- assert x[9] == x[-7] == x.ru_inblock
- assert x[10] == x[-6] == x.ru_oublock
- assert x[11] == x[-5] == x.ru_msgsnd
- assert x[12] == x[-4] == x.ru_msgrcv
- assert x[13] == x[-3] == x.ru_nsignals
- assert x[14] == x[-2] == x.ru_nvcsw
- assert x[15] == x[-1] == x.ru_nivcsw
- for i in range(16):
- if i < 2:
- expected_type = float
- else:
- expected_type = (int, long)
- assert isinstance(x[i], expected_type)
+def test_getrlimit():
+ x = resource.getrlimit(resource.RLIMIT_CPU)
+ assert isinstance(x, tuple)
+ assert len(x) == 2
+ assert isinstance(x[0], (int, long))
+ assert isinstance(x[1], (int, long))
+
+def test_setrlimit():
+ # minimal "does not crash" test
+ x = resource.getrlimit(resource.RLIMIT_CPU)
+ resource.setrlimit(resource.RLIMIT_CPU, x)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit