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

fijal at codespeak.net fijal at codespeak.net
Mon Oct 15 16:58:32 CEST 2007


Author: fijal
Date: Mon Oct 15 16:58:31 2007
New Revision: 47466

Modified:
   pypy/dist/pypy/module/_ffi/__init__.py
   pypy/dist/pypy/module/_ffi/app_ffi.py
   pypy/dist/pypy/module/_ffi/interp_ffi.py
   pypy/dist/pypy/module/_ffi/test/test__ffi.py
Log:
Very strange implementation of structure (only flat ones, no nested
structures). Needs rethinking, but at least I've got better idea now.


Modified: pypy/dist/pypy/module/_ffi/__init__.py
==============================================================================
--- pypy/dist/pypy/module/_ffi/__init__.py	(original)
+++ pypy/dist/pypy/module/_ffi/__init__.py	Mon Oct 15 16:58:31 2007
@@ -10,9 +10,11 @@
     applevelname = '_ffi'
 
     interpleveldefs = {
-        'CDLL'    : 'interp_ffi.W_CDLL',
-        'FuncPtr' : 'interp_ffi.W_FuncPtr',
+        'CDLL'      : 'interp_ffi.W_CDLL',
+        'FuncPtr'   : 'interp_ffi.W_FuncPtr',
     }
 
     appleveldefs = {
+        'Structure'         : 'app_ffi.Structure',
+        'StructureInstance' : 'app_ffi.StructureInstance',
     }

Modified: pypy/dist/pypy/module/_ffi/app_ffi.py
==============================================================================
--- pypy/dist/pypy/module/_ffi/app_ffi.py	(original)
+++ pypy/dist/pypy/module/_ffi/app_ffi.py	Mon Oct 15 16:58:31 2007
@@ -0,0 +1,26 @@
+# NOT_RPYTHON
+
+class Structure(object):
+    def __init__(self, fields):
+        self.fields = fields
+
+    def __call__(self, **kwds):
+        from _ffi import StructureInstance
+        return StructureInstance(self.fields, kwds)
+
+class StructureInstance(object):
+    def __init__(self, shape, **kwds):
+        self.shape = shape
+        self.format = "".join([i[1] for i in shape])
+        for kwd, value in kwds.items():
+            setattr(self, kwd, value)
+
+    def pack(self):
+        args = [getattr(self, i[0], 0) for i in self.shape]
+        return struct.pack(self.format, *args)
+
+    def unpack(self, s):
+        values = struct.unpack(self.format, s)
+        for (name, _), value in zip(self.shape, values):
+            setattr(self, name, value)
+    

Modified: pypy/dist/pypy/module/_ffi/interp_ffi.py
==============================================================================
--- pypy/dist/pypy/module/_ffi/interp_ffi.py	(original)
+++ pypy/dist/pypy/module/_ffi/interp_ffi.py	Mon Oct 15 16:58:31 2007
@@ -5,14 +5,48 @@
 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.rlib.libffi import *
 from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.unroll import unrolling_iterable
 
-typemap = {
+TYPEMAP = {
+    # XXX A mess with unsigned/signed/normal chars :-/
+    'c' : ffi_type_uchar,
+    'b' : ffi_type_schar,
+    'B' : ffi_type_uchar,
+    'h' : ffi_type_sshort,
+    'H' : ffi_type_ushort,
     'i' : ffi_type_sint,
+    'I' : ffi_type_uint,
     'l' : ffi_type_slong,
-    'd' : ffi_type_double
+    'L' : ffi_type_ulong,
+    # XXX I'm not sure what is long long here, let's assume it's 64 bit :-/
+    'q' : ffi_type_sint64,
+    'Q' : ffi_type_uint64,
+    'f' : ffi_type_float,
+    'd' : ffi_type_double,
+    's' : ffi_type_pointer,
+    'p' : ffi_type_pointer,
+    'P' : ffi_type_pointer,
+}
+
+LL_TYPEMAP = {
+    'c' : rffi.CHAR,
+    'b' : rffi.UCHAR,
+    'B' : rffi.CHAR,
+    'h' : rffi.SHORT,
+    'H' : rffi.USHORT,
+    'i' : rffi.INT,
+    'I' : rffi.UINT,
+    'l' : rffi.LONG,
+    'L' : rffi.ULONG,
+    'q' : rffi.LONGLONG,
+    'Q' : rffi.ULONGLONG,
+    'f' : rffi.FLOAT,
+    'd' : rffi.DOUBLE,
+    's' : rffi.CCHARP,
+    'p' : rffi.CCHARP,
+    'P' : rffi.VOIDP,    
 }
 
 class W_CDLL(Wrappable):
@@ -25,7 +59,7 @@
     def get_type(self, key):
         space = self.space
         try:
-            return typemap[key]
+            return TYPEMAP[key]
         except KeyError:
             raise OperationError(space.w_ValueError, space.wrap(
                 "Uknown type letter %s" % key))
@@ -68,16 +102,67 @@
 W_CDLL.typedef = TypeDef(
     'CDLL',
     __new__     = interp2app(descr_new_cdll),
-    ptr         = interp2app(W_CDLL.ptr)
+    ptr         = interp2app(W_CDLL.ptr),
+    __doc__     = """ C Dynamically loaded library
+use CDLL(libname) to create handle to C library (argument is processed the
+same way as dlopen processes it). On such library call:
+lib.ptr(func_name, argtype_list, restype)
+
+where argtype_list is a list of single characters and restype is a single
+character. Character meanings are more or less the same as in struct module,
+except that s has trailing \x00 added, while p is considered a raw buffer.
+"""
 )
 
-def push_arg(space, ptr, argtype, w_arg):
-    if argtype == "i":
-        ptr.push_arg(space.int_w(w_arg))
-    elif argtype == "d":
+def pack_pointer(space, w_arg, ptr):
+    arg = space.str_w(w_arg)
+    ll_str = lltype.malloc(rffi.CCHARP.TO, len(arg), flavor='raw')
+    for i in range(len(arg)):
+        ll_str[i] = arg[i]
+    ptr.push_arg(ll_str)
+    return ll_str
+
+def push_arg(space, ptr, argnum, argtype, w_arg, to_free, to_reconsider):
+    w = space.wrap
+    # XXX how to handle LONGLONG here?
+    # they're probably long, so we'll not get them through int_w
+    if argtype == "d" or argtype == "f":
         ptr.push_arg(space.float_w(w_arg))
+    elif argtype == "s":
+        ll_str = rffi.str2charp(space.str_w(w_arg))
+        ptr.push_arg(ll_str)
+        to_free.append(ll_str)
+    elif argtype == "p":
+        # check for NULL ptr
+        if space.is_w(w_arg, space.w_None):
+            ptr.push_arg(lltype.nullptr(rffi.VOIDP.TO))
+        elif space.is_true(space.isinstance(w_arg, space.w_basestring)):
+            to_free.append(pack_pointer(space, w_arg, ptr))
+        else:
+            mod = space.getbuiltinmodule('_ffi')
+            w_StructureInstance = space.getattr(mod, w('StructureInstance'))
+            if space.is_true(space.isinstance(w_arg, w_StructureInstance)):
+                w_pack = space.getattr(w_arg, w('pack'))
+                w_res = space.call(w_pack, space.newtuple([]))
+                size = space.int_w(space.len(w_res))
+                ll_ptr = pack_pointer(space, w_res, ptr)
+                to_reconsider.append((argnum, ll_ptr, size))
+            else:
+                raise OperationError(space.w_TypeError, w(
+                    "Expected structure, array or simple type"))
+    elif argtype == "c" or argtype == "b" or argtype == "B":
+        ptr.push_arg(space.str_w(w_arg))
     else:
-        raise TypeError("Stuff changed in between?")
+        assert argtype in ["iIhHlLqQ"]
+        ptr.push_arg(space.int_w(w_arg))
+
+ll_typemap_iter = unrolling_iterable(LL_TYPEMAP.items())
+
+def repack_struct(space, w_struct, value, size):
+    w_unpack = space.getattr(w_struct, space.wrap('unpack'))
+    # ARGH! too much copying!
+    x = "".join([value[i] for i in range(size)])
+    space.call(w_unpack, space.newtuple([space.wrap(x)]))
 
 class W_FuncPtr(Wrappable):
     def __init__(self, ptr, argtypes, restype):
@@ -91,14 +176,30 @@
         if kwds_w:
             raise OperationError(space.w_TypeError, space.wrap(
                 "Provided keyword arguments for C function call"))
+        to_free = []
+        to_reconsider = []
+        i = 0
         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?")
+            push_arg(space, self.ptr, i, argtype, w_arg, to_free, to_reconsider)
+            i += 1
+        try:
+            for c, ll_type in ll_typemap_iter:
+                if self.restype == c:
+                    if c == 's' or c == 'p':
+                        return space.wrap(rffi.charp2str(self.ptr.call(rffi.CCHARP)))
+                    elif c == 'P':
+                        res = self.ptr.call(rffi.VOIDP)
+                        return space.wrap(lltype.cast_ptr_to_int(res))
+                    elif c == 'q' or c == 'Q' or c == 'L':
+                        return space.newlong(self.ptr.call(ll_type))
+                    else:
+                        return space.wrap(self.ptr.call(ll_type))
+        finally:
+            for elem in to_free:
+                lltype.free(elem, flavor='raw')
+            for num, value, size in to_reconsider:
+                repack_struct(space, args_w[num], value, size)
+                lltype.free(value, flavor='raw')
     call.unwrap_spec = ['self', ObjSpace, Arguments]
 
 W_FuncPtr.typedef = TypeDef(

Modified: pypy/dist/pypy/module/_ffi/test/test__ffi.py
==============================================================================
--- pypy/dist/pypy/module/_ffi/test/test__ffi.py	(original)
+++ pypy/dist/pypy/module/_ffi/test/test__ffi.py	Mon Oct 15 16:58:31 2007
@@ -10,7 +10,7 @@
 
 class AppTestCTypes:
     def setup_class(cls):
-        cls.space = gettestobjspace(usemodules=('_ffi',))
+        cls.space = gettestobjspace(usemodules=('_ffi','struct'))
 
     def test_libload(self):
         import _ffi
@@ -46,4 +46,31 @@
         assert pow(2, 2) == 4.0
         raises(TypeError, "pow('x', 2.0)")
 
-        
+    def test_strlen(self):
+        import _ffi
+        libc = _ffi.CDLL('libc.so.6')
+        strlen = libc.ptr('strlen', ['s'], 'i')
+        assert strlen("dupa") == 4
+        assert strlen("zupa") == 4
+        strlen = libc.ptr('strlen', ['p'], 'i')
+        assert strlen("ddd\x00") == 3
+        strdup = libc.ptr('strdup', ['s'], 's')
+        assert strdup("xxx") == "xxx"
+
+    def test_time(self):
+        import _ffi
+        libc = _ffi.CDLL('libc.so.6')
+        time = libc.ptr('time', ['p'], 'l')
+        assert time(None) != 0
+
+    def test_gettimeofday(self):
+        import _ffi
+        struct_type = _ffi.Structure([('tv_sec', 'l'), ('tv_usec', 'l')])
+        structure = struct_type()
+        libc = _ffi.CDLL('libc.so.6')
+        gettimeofday = libc.ptr('gettimeofday', ['p', 'p'], 'i')
+        assert gettimeofday(structure, None) == 0
+        struct2 = struct_type()
+        assert gettimeofday(struct2, None) == 0
+        assert structure.tv_usec != struct2.tv_usec
+        assert structure.tv_sec == struct2.tv_sec or structure.tv_sec == struct2.tv_sec - 1



More information about the Pypy-commit mailing list