PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rlib/clibffi.py

https://bitbucket.org/pypy/pypy/
Python | 710 lines | 583 code | 53 blank | 74 comment | 53 complexity | bb65c4de7213a80a946583b44d0b104b MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """ Libffi wrapping
  2. """
  3. from __future__ import with_statement
  4. from rpython.rtyper.tool import rffi_platform
  5. from rpython.rtyper.lltypesystem import lltype, rffi
  6. from rpython.rtyper.tool import rffi_platform
  7. from rpython.rlib.unroll import unrolling_iterable
  8. from rpython.rlib.rarithmetic import intmask, is_emulated_long
  9. from rpython.rlib.objectmodel import we_are_translated
  10. from rpython.rlib.rmmap import alloc
  11. from rpython.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal
  12. from rpython.rlib.rdynload import DLOpenError, DLLHANDLE
  13. from rpython.rlib import jit, rposix
  14. from rpython.rlib.objectmodel import specialize
  15. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  16. from rpython.translator.platform import platform
  17. from rpython.translator import cdir
  18. from platform import machine
  19. import py
  20. import os
  21. import sys
  22. import ctypes.util
  23. # maaaybe isinstance here would be better. Think
  24. _MSVC = platform.name == "msvc"
  25. _MINGW = platform.name == "mingw32"
  26. _WIN32 = _MSVC or _MINGW
  27. _WIN64 = _WIN32 and is_emulated_long
  28. _MAC_OS = platform.name == "darwin"
  29. _LITTLE_ENDIAN = sys.byteorder == 'little'
  30. _BIG_ENDIAN = sys.byteorder == 'big'
  31. _ARM = rffi_platform.getdefined('__arm__', '')
  32. if _WIN32:
  33. from rpython.rlib import rwin32
  34. if _WIN32:
  35. separate_module_sources = ['''
  36. #include "src/precommondefs.h"
  37. #include <stdio.h>
  38. #include <windows.h>
  39. /* Get the module where the "fopen" function resides in */
  40. RPY_EXTERN
  41. HANDLE pypy_get_libc_handle() {
  42. MEMORY_BASIC_INFORMATION mi;
  43. char buf[1000];
  44. memset(&mi, 0, sizeof(mi));
  45. if( !VirtualQueryEx(GetCurrentProcess(), &fopen, &mi, sizeof(mi)) )
  46. return 0;
  47. GetModuleFileName((HMODULE)mi.AllocationBase, buf, 500);
  48. return (HMODULE)mi.AllocationBase;
  49. }
  50. ''']
  51. else:
  52. separate_module_sources = []
  53. if not _WIN32:
  54. includes = ['ffi.h']
  55. if _MAC_OS:
  56. pre_include_bits = ['#define MACOSX']
  57. else:
  58. pre_include_bits = []
  59. libraries = ['ffi']
  60. link_files = []
  61. eci = ExternalCompilationInfo(
  62. pre_include_bits = pre_include_bits,
  63. includes = includes,
  64. libraries = libraries,
  65. separate_module_sources = separate_module_sources,
  66. include_dirs = platform.include_dirs_for_libffi(),
  67. library_dirs = platform.library_dirs_for_libffi(),
  68. link_files = link_files,
  69. testonly_libraries = ['ffi'],
  70. )
  71. elif _MINGW:
  72. includes = ['ffi.h']
  73. libraries = ['libffi-5']
  74. eci = ExternalCompilationInfo(
  75. libraries = libraries,
  76. includes = includes,
  77. separate_module_sources = separate_module_sources,
  78. )
  79. eci = rffi_platform.configure_external_library(
  80. 'ffi-5', eci,
  81. [dict(prefix='libffi-',
  82. include_dir='include', library_dir='.libs'),
  83. dict(prefix=r'c:\\mingw64', include_dir='include', library_dir='lib'),
  84. ])
  85. else:
  86. USE_C_LIBFFI_MSVC = True
  87. libffidir = py.path.local(cdir).join('src', 'libffi_msvc')
  88. if not _WIN64:
  89. asm_ifc = 'win32.c'
  90. else:
  91. asm_ifc = 'win64.asm'
  92. eci = ExternalCompilationInfo(
  93. includes = ['ffi.h', 'windows.h'],
  94. libraries = ['kernel32'],
  95. include_dirs = [libffidir, cdir],
  96. separate_module_sources = separate_module_sources,
  97. separate_module_files = [libffidir.join('ffi.c'),
  98. libffidir.join('prep_cif.c'),
  99. libffidir.join(asm_ifc),
  100. libffidir.join('pypy_ffi.c'),
  101. ],
  102. )
  103. FFI_TYPE_P = lltype.Ptr(lltype.ForwardReference())
  104. FFI_TYPE_PP = rffi.CArrayPtr(FFI_TYPE_P)
  105. FFI_TYPE_NULL = lltype.nullptr(FFI_TYPE_P.TO)
  106. class CConfig:
  107. _compilation_info_ = eci
  108. FFI_OK = rffi_platform.ConstantInteger('FFI_OK')
  109. FFI_BAD_TYPEDEF = rffi_platform.ConstantInteger('FFI_BAD_TYPEDEF')
  110. FFI_DEFAULT_ABI = rffi_platform.ConstantInteger('FFI_DEFAULT_ABI')
  111. if _WIN32 and not _WIN64:
  112. FFI_STDCALL = rffi_platform.ConstantInteger('FFI_STDCALL')
  113. if _ARM:
  114. FFI_SYSV = rffi_platform.ConstantInteger('FFI_SYSV')
  115. FFI_VFP = rffi_platform.ConstantInteger('FFI_VFP')
  116. FFI_TYPE_STRUCT = rffi_platform.ConstantInteger('FFI_TYPE_STRUCT')
  117. size_t = rffi_platform.SimpleType("size_t", rffi.ULONG)
  118. ffi_abi = rffi_platform.SimpleType("ffi_abi", rffi.USHORT)
  119. ffi_arg = rffi_platform.SimpleType("ffi_arg", lltype.Signed)
  120. ffi_type = rffi_platform.Struct('ffi_type', [('size', rffi.ULONG),
  121. ('alignment', rffi.USHORT),
  122. ('type', rffi.USHORT),
  123. ('elements', FFI_TYPE_PP)])
  124. ffi_cif = rffi_platform.Struct('ffi_cif', [])
  125. ffi_closure = rffi_platform.Struct('ffi_closure',
  126. [('user_data', rffi.VOIDP)])
  127. def add_simple_type(type_name):
  128. for name in ['size', 'alignment', 'type']:
  129. setattr(CConfig, type_name + '_' + name,
  130. rffi_platform.ConstantInteger(type_name + '.' + name))
  131. def configure_simple_type(type_name):
  132. l = lltype.malloc(FFI_TYPE_P.TO, flavor='raw', immortal=True)
  133. for tp, name in [(size_t, 'size'),
  134. (rffi.USHORT, 'alignment'),
  135. (rffi.USHORT, 'type')]:
  136. value = getattr(cConfig, '%s_%s' % (type_name, name))
  137. setattr(l, 'c_' + name, rffi.cast(tp, value))
  138. l.c_elements = lltype.nullptr(FFI_TYPE_PP.TO)
  139. return l
  140. base_names = ['double', 'uchar', 'schar', 'sshort', 'ushort', 'uint', 'sint',
  141. # ffi_type_slong and ffi_type_ulong are omitted because
  142. # their meaning changes too much from one libffi version to
  143. # another. DON'T USE THEM! use cast_type_to_ffitype().
  144. 'float', 'longdouble', 'pointer', 'void',
  145. # by size
  146. 'sint8', 'uint8', 'sint16', 'uint16', 'sint32', 'uint32',
  147. 'sint64', 'uint64']
  148. type_names = ['ffi_type_%s' % name for name in base_names]
  149. for i in type_names:
  150. add_simple_type(i)
  151. class cConfig:
  152. pass
  153. for k, v in rffi_platform.configure(CConfig).items():
  154. setattr(cConfig, k, v)
  155. FFI_TYPE_P.TO.become(cConfig.ffi_type)
  156. size_t = cConfig.size_t
  157. FFI_ABI = cConfig.ffi_abi
  158. ffi_arg = cConfig.ffi_arg
  159. for name in type_names:
  160. locals()[name] = configure_simple_type(name)
  161. def _signed_type_for(TYPE):
  162. sz = rffi.sizeof(TYPE)
  163. if sz == 1: return ffi_type_sint8
  164. elif sz == 2: return ffi_type_sint16
  165. elif sz == 4: return ffi_type_sint32
  166. elif sz == 8: return ffi_type_sint64
  167. else: raise ValueError("unsupported type size for %r" % (TYPE,))
  168. def _unsigned_type_for(TYPE):
  169. sz = rffi.sizeof(TYPE)
  170. if sz == 1: return ffi_type_uint8
  171. elif sz == 2: return ffi_type_uint16
  172. elif sz == 4: return ffi_type_uint32
  173. elif sz == 8: return ffi_type_uint64
  174. else: raise ValueError("unsupported type size for %r" % (TYPE,))
  175. __int_type_map = [
  176. (rffi.UCHAR, ffi_type_uchar),
  177. (rffi.SIGNEDCHAR, ffi_type_schar),
  178. (rffi.SHORT, ffi_type_sshort),
  179. (rffi.USHORT, ffi_type_ushort),
  180. (rffi.UINT, ffi_type_uint),
  181. (rffi.INT, ffi_type_sint),
  182. # xxx don't use ffi_type_slong and ffi_type_ulong - their meaning
  183. # changes from a libffi version to another :-((
  184. (rffi.ULONG, _unsigned_type_for(rffi.ULONG)),
  185. (rffi.LONG, _signed_type_for(rffi.LONG)),
  186. (rffi.ULONGLONG, _unsigned_type_for(rffi.ULONGLONG)),
  187. (rffi.LONGLONG, _signed_type_for(rffi.LONGLONG)),
  188. (lltype.UniChar, _unsigned_type_for(lltype.UniChar)),
  189. (lltype.Bool, _unsigned_type_for(lltype.Bool)),
  190. (lltype.Char, _signed_type_for(lltype.Char)),
  191. ]
  192. __float_type_map = [
  193. (rffi.DOUBLE, ffi_type_double),
  194. (rffi.FLOAT, ffi_type_float),
  195. (rffi.LONGDOUBLE, ffi_type_longdouble),
  196. ]
  197. __ptr_type_map = [
  198. (rffi.VOIDP, ffi_type_pointer),
  199. ]
  200. __type_map = __int_type_map + __float_type_map + [
  201. (lltype.Void, ffi_type_void)
  202. ]
  203. TYPE_MAP_INT = dict(__int_type_map)
  204. TYPE_MAP_FLOAT = dict(__float_type_map)
  205. TYPE_MAP = dict(__type_map)
  206. ffitype_map_int = unrolling_iterable(__int_type_map)
  207. ffitype_map_int_or_ptr = unrolling_iterable(__int_type_map + __ptr_type_map)
  208. ffitype_map_float = unrolling_iterable(__float_type_map)
  209. ffitype_map = unrolling_iterable(__type_map)
  210. del __int_type_map, __float_type_map, __ptr_type_map, __type_map
  211. def external(name, args, result, **kwds):
  212. return rffi.llexternal(name, args, result, compilation_info=eci, **kwds)
  213. def winexternal(name, args, result):
  214. return rffi.llexternal(name, args, result, compilation_info=eci, calling_conv='win')
  215. if not _MSVC:
  216. def check_fficall_result(result, flags):
  217. pass # No check
  218. else:
  219. def check_fficall_result(result, flags):
  220. if result == 0:
  221. return
  222. # if win64:
  223. # raises ValueError("ffi_call failed with code %d" % (result,))
  224. if result < 0:
  225. if flags & FUNCFLAG_CDECL:
  226. raise StackCheckError(
  227. "Procedure called with not enough arguments"
  228. " (%d bytes missing)"
  229. " or wrong calling convention" % (-result,))
  230. else:
  231. raise StackCheckError(
  232. "Procedure called with not enough arguments "
  233. " (%d bytes missing) " % (-result,))
  234. else:
  235. raise StackCheckError(
  236. "Procedure called with too many "
  237. "arguments (%d bytes in excess) " % (result,))
  238. if not _WIN32:
  239. libc_name = ctypes.util.find_library('c')
  240. assert libc_name is not None, "Cannot find C library, ctypes.util.find_library('c') returned None"
  241. def get_libc_name():
  242. return libc_name
  243. elif _MSVC:
  244. get_libc_handle = external('pypy_get_libc_handle', [], DLLHANDLE)
  245. @jit.dont_look_inside
  246. def get_libc_name():
  247. return rwin32.GetModuleFileName(get_libc_handle())
  248. assert "msvcr" in get_libc_name().lower(), \
  249. "Suspect msvcrt library: %s" % (get_libc_name(),)
  250. elif _MINGW:
  251. def get_libc_name():
  252. return 'msvcrt.dll'
  253. if _WIN32:
  254. LoadLibrary = rwin32.LoadLibrary
  255. FFI_OK = cConfig.FFI_OK
  256. FFI_BAD_TYPEDEF = cConfig.FFI_BAD_TYPEDEF
  257. FFI_DEFAULT_ABI = cConfig.FFI_DEFAULT_ABI
  258. if _WIN32 and not _WIN64:
  259. FFI_STDCALL = cConfig.FFI_STDCALL
  260. if _ARM:
  261. FFI_SYSV = cConfig.FFI_SYSV
  262. FFI_VFP = cConfig.FFI_VFP
  263. FFI_TYPE_STRUCT = cConfig.FFI_TYPE_STRUCT
  264. FFI_CIFP = lltype.Ptr(cConfig.ffi_cif)
  265. FFI_CLOSUREP = lltype.Ptr(cConfig.ffi_closure)
  266. VOIDPP = rffi.CArrayPtr(rffi.VOIDP)
  267. c_ffi_prep_cif = external('ffi_prep_cif', [FFI_CIFP, FFI_ABI, rffi.UINT,
  268. FFI_TYPE_P, FFI_TYPE_PP], rffi.INT)
  269. if _MSVC:
  270. c_ffi_call_return_type = rffi.INT
  271. else:
  272. c_ffi_call_return_type = lltype.Void
  273. c_ffi_call = external('ffi_call', [FFI_CIFP, rffi.VOIDP, rffi.VOIDP,
  274. VOIDPP], c_ffi_call_return_type,
  275. save_err=rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
  276. # Note: the RFFI_ALT_ERRNO flag matches the one in pyjitpl.direct_libffi_call
  277. CALLBACK_TP = rffi.CCallback([FFI_CIFP, rffi.VOIDP, rffi.VOIDPP, rffi.VOIDP],
  278. lltype.Void)
  279. c_ffi_prep_closure = external('ffi_prep_closure', [FFI_CLOSUREP, FFI_CIFP,
  280. CALLBACK_TP, rffi.VOIDP],
  281. rffi.INT)
  282. FFI_STRUCT_P = lltype.Ptr(lltype.Struct('FFI_STRUCT',
  283. ('ffistruct', FFI_TYPE_P.TO),
  284. ('members', lltype.Array(FFI_TYPE_P))))
  285. @specialize.arg(3)
  286. def make_struct_ffitype_e(size, aligment, field_types, track_allocation=True):
  287. """Compute the type of a structure. Returns a FFI_STRUCT_P out of
  288. which the 'ffistruct' member is a regular FFI_TYPE.
  289. """
  290. tpe = lltype.malloc(FFI_STRUCT_P.TO, len(field_types)+1, flavor='raw',
  291. track_allocation=track_allocation)
  292. tpe.ffistruct.c_type = rffi.cast(rffi.USHORT, FFI_TYPE_STRUCT)
  293. tpe.ffistruct.c_size = rffi.cast(rffi.SIZE_T, size)
  294. tpe.ffistruct.c_alignment = rffi.cast(rffi.USHORT, aligment)
  295. tpe.ffistruct.c_elements = rffi.cast(FFI_TYPE_PP,
  296. lltype.direct_arrayitems(tpe.members))
  297. n = 0
  298. while n < len(field_types):
  299. tpe.members[n] = field_types[n]
  300. n += 1
  301. tpe.members[n] = lltype.nullptr(FFI_TYPE_P.TO)
  302. return tpe
  303. def cast_type_to_ffitype(tp):
  304. """ This function returns ffi representation of rpython type tp
  305. """
  306. return TYPE_MAP[tp]
  307. cast_type_to_ffitype._annspecialcase_ = 'specialize:memo'
  308. def push_arg_as_ffiptr(ffitp, arg, ll_buf):
  309. # This is for primitive types. Note that the exact type of 'arg' may be
  310. # different from the expected 'c_size'. To cope with that, we fall back
  311. # to a byte-by-byte copy.
  312. TP = lltype.typeOf(arg)
  313. TP_P = lltype.Ptr(rffi.CArray(TP))
  314. TP_size = rffi.sizeof(TP)
  315. c_size = intmask(ffitp.c_size)
  316. # if both types have the same size, we can directly write the
  317. # value to the buffer
  318. if c_size == TP_size:
  319. buf = rffi.cast(TP_P, ll_buf)
  320. buf[0] = arg
  321. else:
  322. # needs byte-by-byte copying. Make sure 'arg' is an integer type.
  323. # Note that this won't work for rffi.FLOAT/rffi.DOUBLE.
  324. assert TP is not rffi.FLOAT and TP is not rffi.DOUBLE
  325. if TP_size <= rffi.sizeof(lltype.Signed):
  326. arg = rffi.cast(lltype.Unsigned, arg)
  327. else:
  328. arg = rffi.cast(lltype.UnsignedLongLong, arg)
  329. if _LITTLE_ENDIAN:
  330. for i in range(c_size):
  331. ll_buf[i] = chr(arg & 0xFF)
  332. arg >>= 8
  333. elif _BIG_ENDIAN:
  334. for i in range(c_size-1, -1, -1):
  335. ll_buf[i] = chr(arg & 0xFF)
  336. arg >>= 8
  337. else:
  338. raise AssertionError
  339. push_arg_as_ffiptr._annspecialcase_ = 'specialize:argtype(1)'
  340. # type defs for callback and closure userdata
  341. USERDATA_P = lltype.Ptr(lltype.ForwardReference())
  342. CALLBACK_TP = lltype.Ptr(lltype.FuncType([rffi.VOIDPP, rffi.VOIDP, USERDATA_P],
  343. lltype.Void))
  344. USERDATA_P.TO.become(lltype.Struct('userdata',
  345. ('callback', CALLBACK_TP),
  346. ('addarg', lltype.Signed),
  347. hints={'callback':True}))
  348. @jit.jit_callback("CLIBFFI")
  349. def _ll_callback(ffi_cif, ll_res, ll_args, ll_userdata):
  350. """ Callback specification.
  351. ffi_cif - something ffi specific, don't care
  352. ll_args - rffi.VOIDPP - pointer to array of pointers to args
  353. ll_restype - rffi.VOIDP - pointer to result
  354. ll_userdata - a special structure which holds necessary information
  355. (what the real callback is for example), casted to VOIDP
  356. """
  357. userdata = rffi.cast(USERDATA_P, ll_userdata)
  358. userdata.callback(ll_args, ll_res, userdata)
  359. def ll_callback(ffi_cif, ll_res, ll_args, ll_userdata):
  360. rposix._errno_after(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
  361. _ll_callback(ffi_cif, ll_res, ll_args, ll_userdata)
  362. rposix._errno_before(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
  363. class StackCheckError(ValueError):
  364. message = None
  365. def __init__(self, message):
  366. self.message = message
  367. class LibFFIError(Exception):
  368. pass
  369. CHUNK = 4096
  370. CLOSURES = rffi.CArrayPtr(FFI_CLOSUREP.TO)
  371. class ClosureHeap(object):
  372. def __init__(self):
  373. self.free_list = lltype.nullptr(rffi.VOIDP.TO)
  374. def _more(self):
  375. chunk = rffi.cast(CLOSURES, alloc(CHUNK))
  376. count = CHUNK//rffi.sizeof(FFI_CLOSUREP.TO)
  377. for i in range(count):
  378. rffi.cast(rffi.VOIDPP, chunk)[0] = self.free_list
  379. self.free_list = rffi.cast(rffi.VOIDP, chunk)
  380. chunk = rffi.ptradd(chunk, 1)
  381. def alloc(self):
  382. if not self.free_list:
  383. self._more()
  384. p = self.free_list
  385. self.free_list = rffi.cast(rffi.VOIDPP, p)[0]
  386. return rffi.cast(FFI_CLOSUREP, p)
  387. def free(self, p):
  388. rffi.cast(rffi.VOIDPP, p)[0] = self.free_list
  389. self.free_list = rffi.cast(rffi.VOIDP, p)
  390. closureHeap = ClosureHeap()
  391. FUNCFLAG_STDCALL = 0 # on Windows: for WINAPI calls
  392. FUNCFLAG_CDECL = 1 # on Windows: for __cdecl calls
  393. FUNCFLAG_PYTHONAPI = 4
  394. FUNCFLAG_USE_ERRNO = 8
  395. FUNCFLAG_USE_LASTERROR = 16
  396. def get_call_conv(flags, from_jit):
  397. if _WIN32 and not _WIN64 and (flags & FUNCFLAG_CDECL == 0):
  398. return FFI_STDCALL
  399. else:
  400. return FFI_DEFAULT_ABI
  401. get_call_conv._annspecialcase_ = 'specialize:arg(1)' # hack :-/
  402. class AbstractFuncPtr(object):
  403. ll_cif = lltype.nullptr(FFI_CIFP.TO)
  404. ll_argtypes = lltype.nullptr(FFI_TYPE_PP.TO)
  405. _immutable_fields_ = ['argtypes', 'restype']
  406. def __init__(self, name, argtypes, restype, flags=FUNCFLAG_CDECL):
  407. self.name = name
  408. self.argtypes = argtypes
  409. self.restype = restype
  410. self.flags = flags
  411. argnum = len(argtypes)
  412. self.ll_argtypes = lltype.malloc(FFI_TYPE_PP.TO, argnum, flavor='raw',
  413. track_allocation=False) # freed by the __del__
  414. for i in range(argnum):
  415. self.ll_argtypes[i] = argtypes[i]
  416. self.ll_cif = lltype.malloc(FFI_CIFP.TO, flavor='raw',
  417. track_allocation=False) # freed by the __del__
  418. if _MSVC:
  419. # This little trick works correctly with MSVC.
  420. # It returns small structures in registers
  421. if intmask(restype.c_type) == FFI_TYPE_STRUCT:
  422. if restype.c_size <= 4:
  423. restype = ffi_type_sint32
  424. elif restype.c_size <= 8:
  425. restype = ffi_type_sint64
  426. res = c_ffi_prep_cif(self.ll_cif,
  427. rffi.cast(rffi.USHORT, get_call_conv(flags,False)),
  428. rffi.cast(rffi.UINT, argnum), restype,
  429. self.ll_argtypes)
  430. if not res == FFI_OK:
  431. raise LibFFIError
  432. def __del__(self):
  433. if self.ll_cif:
  434. lltype.free(self.ll_cif, flavor='raw', track_allocation=False)
  435. self.ll_cif = lltype.nullptr(FFI_CIFP.TO)
  436. if self.ll_argtypes:
  437. lltype.free(self.ll_argtypes, flavor='raw', track_allocation=False)
  438. self.ll_argtypes = lltype.nullptr(FFI_TYPE_PP.TO)
  439. # as long as CallbackFuncPtr is kept alive, the underlaying userdata
  440. # is kept alive as well
  441. class CallbackFuncPtr(AbstractFuncPtr):
  442. ll_closure = lltype.nullptr(FFI_CLOSUREP.TO)
  443. ll_userdata = lltype.nullptr(USERDATA_P.TO)
  444. # additional_arg should really be a non-heap type like a integer,
  445. # it cannot be any kind of movable gc reference
  446. def __init__(self, argtypes, restype, func, additional_arg=0,
  447. flags=FUNCFLAG_CDECL):
  448. AbstractFuncPtr.__init__(self, "callback", argtypes, restype, flags)
  449. self.ll_closure = closureHeap.alloc()
  450. self.ll_userdata = lltype.malloc(USERDATA_P.TO, flavor='raw',
  451. track_allocation=False)
  452. self.ll_userdata.callback = rffi.llhelper(CALLBACK_TP, func)
  453. self.ll_userdata.addarg = additional_arg
  454. res = c_ffi_prep_closure(self.ll_closure, self.ll_cif,
  455. ll_callback, rffi.cast(rffi.VOIDP,
  456. self.ll_userdata))
  457. if not res == FFI_OK:
  458. raise LibFFIError
  459. def __del__(self):
  460. AbstractFuncPtr.__del__(self)
  461. if self.ll_closure:
  462. closureHeap.free(self.ll_closure)
  463. self.ll_closure = lltype.nullptr(FFI_CLOSUREP.TO)
  464. if self.ll_userdata:
  465. lltype.free(self.ll_userdata, flavor='raw', track_allocation=False)
  466. self.ll_userdata = lltype.nullptr(USERDATA_P.TO)
  467. class RawFuncPtr(AbstractFuncPtr):
  468. def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL,
  469. keepalive=None):
  470. AbstractFuncPtr.__init__(self, name, argtypes, restype, flags)
  471. self.keepalive = keepalive
  472. self.funcsym = funcsym
  473. def call(self, args_ll, ll_result):
  474. # adjust_return_size() should always be used here on ll_result
  475. assert len(args_ll) == len(self.argtypes), (
  476. "wrong number of arguments in call to %s(): "
  477. "%d instead of %d" % (self.name, len(args_ll), len(self.argtypes)))
  478. ll_args = lltype.malloc(rffi.VOIDPP.TO, len(args_ll), flavor='raw')
  479. for i in range(len(args_ll)):
  480. assert args_ll[i] # none should be NULL
  481. ll_args[i] = args_ll[i]
  482. ffires = c_ffi_call(self.ll_cif, self.funcsym, ll_result, ll_args)
  483. lltype.free(ll_args, flavor='raw')
  484. check_fficall_result(ffires, self.flags)
  485. class FuncPtr(AbstractFuncPtr):
  486. ll_args = lltype.nullptr(rffi.VOIDPP.TO)
  487. ll_result = lltype.nullptr(rffi.VOIDP.TO)
  488. def __init__(self, name, argtypes, restype, funcsym, flags=FUNCFLAG_CDECL,
  489. keepalive=None):
  490. # initialize each one of pointers with null
  491. AbstractFuncPtr.__init__(self, name, argtypes, restype, flags)
  492. self.keepalive = keepalive
  493. self.funcsym = funcsym
  494. self.argnum = len(self.argtypes)
  495. self.pushed_args = 0
  496. self.ll_args = lltype.malloc(rffi.VOIDPP.TO, self.argnum, flavor='raw')
  497. for i in range(self.argnum):
  498. # space for each argument
  499. self.ll_args[i] = lltype.malloc(rffi.VOIDP.TO,
  500. intmask(argtypes[i].c_size),
  501. flavor='raw')
  502. if restype != ffi_type_void:
  503. self.restype_size = intmask(restype.c_size)
  504. size = adjust_return_size(self.restype_size)
  505. self.ll_result = lltype.malloc(rffi.VOIDP.TO, size,
  506. flavor='raw')
  507. else:
  508. self.restype_size = -1
  509. def push_arg(self, value):
  510. #if self.pushed_args == self.argnum:
  511. # raise TypeError("Too many arguments, eats %d, pushed %d" %
  512. # (self.argnum, self.argnum + 1))
  513. if not we_are_translated():
  514. TP = lltype.typeOf(value)
  515. if isinstance(TP, lltype.Ptr):
  516. if TP.TO._gckind != 'raw':
  517. raise ValueError("Can only push raw values to C, not 'gc'")
  518. # XXX probably we should recursively check for struct fields
  519. # here, lets just ignore that for now
  520. if isinstance(TP.TO, lltype.Array):
  521. try:
  522. TP.TO._hints['nolength']
  523. except KeyError:
  524. raise ValueError("Can only push to C arrays without length info")
  525. push_arg_as_ffiptr(self.argtypes[self.pushed_args], value,
  526. self.ll_args[self.pushed_args])
  527. self.pushed_args += 1
  528. push_arg._annspecialcase_ = 'specialize:argtype(1)'
  529. def _check_args(self):
  530. if self.pushed_args < self.argnum:
  531. raise TypeError("Did not specify arg nr %d" % (self.pushed_args + 1))
  532. def _clean_args(self):
  533. self.pushed_args = 0
  534. def call(self, RES_TP):
  535. self._check_args()
  536. ffires = c_ffi_call(self.ll_cif, self.funcsym,
  537. rffi.cast(rffi.VOIDP, self.ll_result),
  538. rffi.cast(VOIDPP, self.ll_args))
  539. if RES_TP is not lltype.Void:
  540. TP = lltype.Ptr(rffi.CArray(RES_TP))
  541. ptr = self.ll_result
  542. if _BIG_ENDIAN and RES_TP in TYPE_MAP_INT:
  543. # we get a 8 byte value in big endian
  544. n = rffi.sizeof(lltype.Signed) - self.restype_size
  545. ptr = rffi.ptradd(ptr, n)
  546. res = rffi.cast(TP, ptr)[0]
  547. else:
  548. res = None
  549. self._clean_args()
  550. check_fficall_result(ffires, self.flags)
  551. return res
  552. call._annspecialcase_ = 'specialize:arg(1)'
  553. def __del__(self):
  554. if self.ll_args:
  555. argnum = len(self.argtypes)
  556. for i in range(argnum):
  557. if self.ll_args[i]:
  558. lltype.free(self.ll_args[i], flavor='raw')
  559. lltype.free(self.ll_args, flavor='raw')
  560. self.ll_args = lltype.nullptr(rffi.VOIDPP.TO)
  561. if self.ll_result:
  562. lltype.free(self.ll_result, flavor='raw')
  563. self.ll_result = lltype.nullptr(rffi.VOIDP.TO)
  564. AbstractFuncPtr.__del__(self)
  565. class RawCDLL(object):
  566. def __init__(self, handle):
  567. self.lib = handle
  568. def getpointer(self, name, argtypes, restype, flags=FUNCFLAG_CDECL):
  569. # these arguments are already casted to proper ffi
  570. # structures!
  571. return FuncPtr(name, argtypes, restype, dlsym(self.lib, name),
  572. flags=flags, keepalive=self)
  573. def getrawpointer(self, name, argtypes, restype, flags=FUNCFLAG_CDECL):
  574. # these arguments are already casted to proper ffi
  575. # structures!
  576. return RawFuncPtr(name, argtypes, restype, dlsym(self.lib, name),
  577. flags=flags, keepalive=self)
  578. def getrawpointer_byordinal(self, ordinal, argtypes, restype,
  579. flags=FUNCFLAG_CDECL):
  580. # these arguments are already casted to proper ffi
  581. # structures!
  582. return RawFuncPtr(name, argtypes, restype,
  583. dlsym_byordinal(self.lib, ordinal), flags=flags,
  584. keepalive=self)
  585. def getaddressindll(self, name):
  586. return dlsym(self.lib, name)
  587. class CDLL(RawCDLL):
  588. def __init__(self, libname, mode=-1):
  589. """Load the library, or raises DLOpenError."""
  590. RawCDLL.__init__(self, rffi.cast(DLLHANDLE, -1))
  591. with rffi.scoped_str2charp(libname) as ll_libname:
  592. self.lib = dlopen(ll_libname, mode)
  593. def __del__(self):
  594. if self.lib != rffi.cast(DLLHANDLE, -1):
  595. dlclose(self.lib)
  596. self.lib = rffi.cast(DLLHANDLE, -1)
  597. def adjust_return_size(memsize):
  598. # Workaround for a strange behavior of libffi: make sure that
  599. # we always have at least 8 bytes. ffi_call() writes 8 bytes
  600. # into the buffer even if the function's result type asks for
  601. # less. This strange behavior is documented.
  602. if memsize < 8:
  603. memsize = 8
  604. return memsize