PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rlib/clibffi.py

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