[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