[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