[pypy-svn] r47394 - in pypy/dist/pypy/module/_ffi: . test

fijal at codespeak.net fijal at codespeak.net
Thu Oct 11 14:34:04 CEST 2007


Author: fijal
Date: Thu Oct 11 14:34:03 2007
New Revision: 47394

Added:
   pypy/dist/pypy/module/_ffi/   (props changed)
   pypy/dist/pypy/module/_ffi/__init__.py   (contents, props changed)
   pypy/dist/pypy/module/_ffi/app_ffi.py   (contents, props changed)
   pypy/dist/pypy/module/_ffi/interp_ffi.py   (contents, props changed)
   pypy/dist/pypy/module/_ffi/test/   (props changed)
   pypy/dist/pypy/module/_ffi/test/__init__.py   (contents, props changed)
   pypy/dist/pypy/module/_ffi/test/test__ffi.py   (contents, props changed)
Log:
Expose libffi to applevel with a very basic interface


Added: pypy/dist/pypy/module/_ffi/__init__.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_ffi/__init__.py	Thu Oct 11 14:34:03 2007
@@ -0,0 +1,18 @@
+
+""" Low-level interface to libffi
+"""
+
+from pypy.interpreter.mixedmodule import MixedModule
+from pypy.module._ffi.interp_ffi import W_CDLL
+from pypy.rpython.lltypesystem import lltype, rffi
+
+class Module(MixedModule):
+    applevelname = '_ffi'
+
+    interpleveldefs = {
+        'CDLL'    : 'interp_ffi.W_CDLL',
+        'FuncPtr' : 'interp_ffi.W_FuncPtr',
+    }
+
+    appleveldefs = {
+    }

Added: pypy/dist/pypy/module/_ffi/app_ffi.py
==============================================================================

Added: pypy/dist/pypy/module/_ffi/interp_ffi.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_ffi/interp_ffi.py	Thu Oct 11 14:34:03 2007
@@ -0,0 +1,107 @@
+
+from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable, \
+     Arguments
+from pypy.interpreter.error import OperationError, wrap_oserror
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef, GetSetProperty
+
+from pypy.rlib.libffi import CDLL, RTLD_LOCAL, RTLD_GLOBAL,\
+     ffi_type_sint, ffi_type_double, ffi_type_slong
+from pypy.rpython.lltypesystem import lltype, rffi
+
+typemap = {
+    'i' : ffi_type_sint,
+    'l' : ffi_type_slong,
+    'd' : ffi_type_double
+}
+
+class W_CDLL(Wrappable):
+    def __init__(self, space, name):
+        self.cdll = CDLL(name)
+        self.name = name
+        self.w_cache = space.newdict()
+        self.space = space
+
+    def get_type(self, key):
+        space = self.space
+        try:
+            return typemap[key]
+        except KeyError:
+            raise OperationError(space.w_ValueError, space.wrap(
+                "Uknown type letter %s" % key))
+
+    def ptr(self, space, name, w_argtypes, restype):
+        """ Get a pointer for function name with provided argtypes
+        and restype
+        """
+        w = space.wrap
+        w_argtypes = space.newtuple(space.unpackiterable(w_argtypes))
+        w_key = space.newtuple([w(name), w_argtypes, w(restype)])
+        try:
+            return space.getitem(self.w_cache, w_key)
+        except OperationError, e:
+            if e.match(space, space.w_KeyError):
+                pass
+            else:
+                raise
+        argtypes_w = space.unpackiterable(w_argtypes)
+        argtypes = [space.str_w(w_arg) for w_arg in argtypes_w]
+        ffi_argtypes = [self.get_type(arg) for arg in argtypes]
+        ffi_restype = self.get_type(restype)
+        try:
+            ptr = self.cdll.getpointer(name, ffi_argtypes, ffi_restype)
+            w_funcptr = W_FuncPtr(ptr, argtypes, restype)
+            space.setitem(self.w_cache, w_key, w_funcptr)
+            return w_funcptr
+        except KeyError:
+            raise OperationError(space.w_AttributeError, space.wrap(
+                "No symbol %s found in library %s" % (name, self.name)))
+    ptr.unwrap_spec = ['self', ObjSpace, str, W_Root, str]
+
+def descr_new_cdll(space, w_type, name):
+    try:
+        return space.wrap(W_CDLL(space, name))
+    except OSError, e:
+        raise wrap_oserror(space, e)
+descr_new_cdll.unwrap_spec = [ObjSpace, W_Root, str]
+
+W_CDLL.typedef = TypeDef(
+    'CDLL',
+    __new__     = interp2app(descr_new_cdll),
+    ptr         = interp2app(W_CDLL.ptr)
+)
+
+def push_arg(space, ptr, argtype, w_arg):
+    if argtype == "i":
+        ptr.push_arg(space.int_w(w_arg))
+    elif argtype == "d":
+        ptr.push_arg(space.float_w(w_arg))
+    else:
+        raise TypeError("Stuff changed in between?")
+
+class W_FuncPtr(Wrappable):
+    def __init__(self, ptr, argtypes, restype):
+        self.ptr = ptr
+        self.restype = restype
+        self.argtypes = argtypes
+
+    def call(self, space, arguments):
+        args_w, kwds_w = arguments.unpack()
+        # C has no keyword arguments
+        if kwds_w:
+            raise OperationError(space.w_TypeError, space.wrap(
+                "Provided keyword arguments for C function call"))
+        for argtype, w_arg in zip(self.argtypes, args_w):
+            push_arg(space, self.ptr, argtype, w_arg)
+        # a bit of specialcasing, rpython trick instead?
+        if self.restype == "i":
+            return space.wrap(self.ptr.call(rffi.INT))
+        elif self.restype == "d":
+            return space.wrap(self.ptr.call(rffi.DOUBLE))
+        raise TypeError("Stuff changed in between?")
+    call.unwrap_spec = ['self', ObjSpace, Arguments]
+
+W_FuncPtr.typedef = TypeDef(
+    'FuncPtr',
+    __call__ = interp2app(W_FuncPtr.call)
+)

Added: pypy/dist/pypy/module/_ffi/test/__init__.py
==============================================================================

Added: pypy/dist/pypy/module/_ffi/test/test__ffi.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_ffi/test/test__ffi.py	Thu Oct 11 14:34:03 2007
@@ -0,0 +1,49 @@
+
+
+from pypy.conftest import gettestobjspace
+
+import os, sys, py
+
+def setup_module(mod):
+    if sys.platform != 'linux2':
+        py.test.skip("Linux only tests by now")
+
+class AppTestCTypes:
+    def setup_class(cls):
+        cls.space = gettestobjspace(usemodules=('_ffi',))
+
+    def test_libload(self):
+        import _ffi
+        _ffi.CDLL('libc.so.6')
+
+    def test_getattr(self):
+        import _ffi
+        libc = _ffi.CDLL('libc.so.6')
+        func = libc.ptr('rand', [], 'i')
+        assert libc.ptr('rand', [], 'i') is func # caching
+        assert libc.ptr('rand', [], 'l') is not func
+        assert isinstance(func, _ffi.FuncPtr)
+        raises(AttributeError, "libc.xxxxxxxxxxxxxx")
+
+    def test_rand(self):
+        import _ffi
+        libc = _ffi.CDLL('libc.so.6')
+        func = libc.ptr('rand', [], 'i')
+        first = func()
+        count = 0
+        for i in range(100):
+            res = func()
+            if res == first:
+                count += 1
+        assert count != 100
+
+    def test_pow(self):
+        import _ffi
+        libm = _ffi.CDLL('libm.so')
+        pow = libm.ptr('pow', ['d', 'd'], 'd')
+        assert pow(2.0, 2.0) == 4.0
+        assert pow(3.0, 3.0) == 27.0
+        assert pow(2, 2) == 4.0
+        raises(TypeError, "pow('x', 2.0)")
+
+        



More information about the Pypy-commit mailing list