[pypy-svn] pypy fast-forward: _rawffi: Add support for callbacks taking structures by value.

amauryfa commits-noreply at bitbucket.org
Fri Jan 14 18:25:00 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: fast-forward
Changeset: r40691:3b9f55150110
Date: 2011-01-14 17:53 +0100
http://bitbucket.org/pypy/pypy/changeset/3b9f55150110/

Log:	_rawffi: Add support for callbacks taking structures by value.

diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py
--- a/pypy/module/_rawffi/callback.py
+++ b/pypy/module/_rawffi/callback.py
@@ -5,8 +5,9 @@
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.module._rawffi.array import get_elem, push_elem
+from pypy.module._rawffi.structure import W_Structure
 from pypy.module._rawffi.interp_rawffi import W_DataInstance, letter2tp, \
-     wrap_value, unwrap_value, unwrap_truncate_int
+     wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes
 from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL
 from pypy.rlib.clibffi import ffi_type_void
 from pypy.module._rawffi.tracker import tracker
@@ -26,14 +27,20 @@
     userdata = rffi.cast(USERDATA_P, ll_userdata)
     callback_ptr = global_counter.CallbackPtr_by_number[userdata.addarg]
     w_callable = callback_ptr.w_callable
-    nargs = callback_ptr.nargs
+    argtypes = callback_ptr.argtypes
     space = callback_ptr.space
     try:
         # XXX The app-level callback gets the arguments as a list of integers.
         #     Irregular interface here.  Shows something, I say.
-        w_args = space.newlist([space.wrap(rffi.cast(rffi.ULONG, ll_args[i]))
-                                for i in range(nargs)])
-        w_res = space.call(w_callable, w_args)
+        args_w = [None] * len(argtypes)
+        for i in range(len(argtypes)):
+            argtype = argtypes[i]
+            if isinstance(argtype, W_Structure):
+                args_w[i] = space.wrap(argtype.fromaddress(
+                    space, rffi.cast(rffi.SIZE_T, ll_args[i])))
+            else:
+                args_w[i] = space.wrap(rffi.cast(rffi.ULONG, ll_args[i]))
+        w_res = space.call_function(w_callable, *args_w)
         if callback_ptr.result is not None: # don't return void
             unwrap_value(space, push_elem, ll_res, 0,
                          callback_ptr.result, w_res)
@@ -62,10 +69,8 @@
                  flags=FUNCFLAG_CDECL):
         self.space = space
         self.w_callable = w_callable
-        args = [space.str_w(w_arg) for w_arg in space.unpackiterable(
-            w_args)]
-        self.nargs = len(args)
-        ffiargs = [letter2tp(space, x).get_basic_ffi_type() for x in args]
+        self.argtypes = unpack_argshapes(space, w_args)
+        ffiargs = [tp.get_basic_ffi_type() for tp in self.argtypes]
         if not space.is_w(w_result, space.w_None):
             self.result = space.str_w(w_result)
             ffiresult = letter2tp(space, self.result).get_basic_ffi_type()

diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py
--- a/pypy/module/_rawffi/test/test__rawffi.py
+++ b/pypy/module/_rawffi/test/test__rawffi.py
@@ -124,6 +124,11 @@
             return s.x + s.y;
         }
 
+        long op_x_y(struct x_y s, long(*callback)(struct x_y))
+        {
+            return callback(s);
+        }
+
         struct s2h {
             short x;
             short y;
@@ -183,7 +188,7 @@
                      runcallback
                      allocate_array
                      static_int static_double static_longdouble
-                     sum_x_y
+                     sum_x_y op_x_y
                      give perturb get_s2a check_s2a
                      AAA_first_ordinal_function
                      ret_un_func
@@ -209,6 +214,10 @@
         cls.w_sizes_and_alignments = space.wrap(dict(
             [(k, (v.c_size, v.c_alignment)) for k,v in TYPEMAP.iteritems()]))
 
+    def teardown_method(self, func):
+        from pypy.module._rawffi.callback import global_counter
+        global_counter.CallbackPtr_by_number.clear()
+
     def test_libload(self):
         import _rawffi
         _rawffi.CDLL(self.libc_name)
@@ -942,6 +951,27 @@
         assert res[0] == 420
         x_y.free()
 
+    def test_callback_struct_byvalue(self):
+        import _rawffi, sys
+        X_Y = _rawffi.Structure([('x', 'l'), ('y', 'l')])
+        lib = _rawffi.CDLL(self.lib_name)
+        op_x_y = lib.ptr('op_x_y', [(X_Y, 1), 'P'], 'l')
+
+        def callback(x_y):
+            return x_y.x + x_y.y
+        cb = _rawffi.CallbackPtr(callback, [(X_Y, 1)], 'l')
+
+        x_y = X_Y()
+        x_y.x = 200
+        x_y.y = 220
+
+        a1 = cb.byptr()
+        res = op_x_y(x_y, a1)
+        a1.free()
+        x_y.free()
+
+        assert res[0] == 420
+
     def test_ret_struct(self):
         import _rawffi
         S2H = _rawffi.Structure([('x', 'h'), ('y', 'h')])


More information about the Pypy-commit mailing list