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

Reply via email to