Author: Ronan Lamy <[email protected]>
Branch:
Changeset: r84383:51732368583f
Date: 2016-05-11 19:21 +0100
http://bitbucket.org/pypy/pypy/changeset/51732368583f/
Log: turn make_wrapper() into a method of ApiFunction
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -203,46 +203,46 @@
# id. Invariant: this variable always contain 0 when the PyPy GIL is
# released. It should also contain 0 when regular RPython code
# executes. In non-cpyext-related code, it will thus always be 0.
-#
+#
# **make_generic_cpy_call():** RPython to C, with the GIL held. Before
# the call, must assert that the global variable is 0 and set the
# current thread identifier into the global variable. After the call,
# assert that the global variable still contains the current thread id,
# and reset it to 0.
-#
+#
# **make_wrapper():** C to RPython; by default assume that the GIL is
# held, but accepts gil="acquire", "release", "around",
# "pygilstate_ensure", "pygilstate_release".
-#
+#
# When a wrapper() is called:
-#
+#
# * "acquire": assert that the GIL is not currently held, i.e. the
# global variable does not contain the current thread id (otherwise,
# deadlock!). Acquire the PyPy GIL. After we acquired it, assert
# that the global variable is 0 (it must be 0 according to the
# invariant that it was 0 immediately before we acquired the GIL,
# because the GIL was released at that point).
-#
+#
# * gil=None: we hold the GIL already. Assert that the current thread
# identifier is in the global variable, and replace it with 0.
-#
+#
# * "pygilstate_ensure": if the global variable contains the current
# thread id, replace it with 0 and set the extra arg to 0. Otherwise,
# do the "acquire" and set the extra arg to 1. Then we'll call
# pystate.py:PyGILState_Ensure() with this extra arg, which will do
# the rest of the logic.
-#
+#
# When a wrapper() returns, first assert that the global variable is
# still 0, and then:
-#
+#
# * "release": release the PyPy GIL. The global variable was 0 up to
# and including at the point where we released the GIL, but afterwards
# it is possible that the GIL is acquired by a different thread very
# quickly.
-#
+#
# * gil=None: we keep holding the GIL. Set the current thread
# identifier into the global variable.
-#
+#
# * "pygilstate_release": if the argument is PyGILState_UNLOCKED,
# release the PyPy GIL; otherwise, set the current thread identifier
# into the global variable. The rest of the logic of
@@ -254,7 +254,7 @@
cpyext_namespace = NameManager('cpyext_')
-class ApiFunction:
+class ApiFunction(object):
def __init__(self, argtypes, restype, callable, error=_NOT_SPECIFIED,
c_name=None, gil=None, result_borrowed=False,
result_is_ll=False):
self.argtypes = argtypes
@@ -292,13 +292,61 @@
def get_wrapper(self, space):
wrapper = getattr(self, '_wrapper', None)
if wrapper is None:
- wrapper = make_wrapper(space, self.callable, self.gil)
+ wrapper = self._make_wrapper(space)
self._wrapper = wrapper
wrapper.relax_sig_check = True
if self.c_name is not None:
wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
return wrapper
+ # Make the wrapper for the cases (1) and (2)
+ def _make_wrapper(self, space):
+ "NOT_RPYTHON"
+ # This logic is obscure, because we try to avoid creating one
+ # big wrapper() function for every callable. Instead we create
+ # only one per "signature".
+
+ callable = self.callable
+ gil = self.gil
+ argnames = self.argnames
+ argtypesw = zip(self.argtypes,
+ [_name.startswith("w_") for _name in argnames])
+ error_value = getattr(self, "error_value", CANNOT_FAIL)
+ if (isinstance(self.restype, lltype.Ptr)
+ and error_value is not CANNOT_FAIL):
+ assert lltype.typeOf(error_value) == self.restype
+ assert not error_value # only support error=NULL
+ error_value = 0 # because NULL is not hashable
+
+ if self.result_is_ll:
+ result_kind = "L"
+ elif self.result_borrowed:
+ result_kind = "B" # note: 'result_borrowed' is ignored if we
also
+ else: # say 'result_is_ll=True' (in this case it's
+ result_kind = "." # up to you to handle refcounting anyway)
+
+ signature = (tuple(argtypesw),
+ self.restype,
+ result_kind,
+ error_value,
+ gil)
+
+ cache = space.fromcache(WrapperCache)
+ cache.stats[1] += 1
+ try:
+ wrapper_gen = cache.wrapper_gens[signature]
+ except KeyError:
+ #print signature
+ wrapper_gen = cache.wrapper_gens[signature] = WrapperGen(space,
+ signature)
+ cache.stats[0] += 1
+ #print 'Wrapper cache [wrappers/total]:', cache.stats
+ wrapper = wrapper_gen.make_wrapper(callable)
+ wrapper.relax_sig_check = True
+ if self.c_name is not None:
+ wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
+ return wrapper
+
DEFAULT_HEADER = 'pypy_decl.h'
def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, header=DEFAULT_HEADER,
gil=None, result_borrowed=False, result_is_ll=False):
@@ -709,48 +757,6 @@
return wrapper
-# Make the wrapper for the cases (1) and (2)
-def make_wrapper(space, callable, gil=None):
- "NOT_RPYTHON"
- # This logic is obscure, because we try to avoid creating one
- # big wrapper() function for every callable. Instead we create
- # only one per "signature".
-
- argnames = callable.api_func.argnames
- argtypesw = zip(callable.api_func.argtypes,
- [_name.startswith("w_") for _name in argnames])
- error_value = getattr(callable.api_func, "error_value", CANNOT_FAIL)
- if (isinstance(callable.api_func.restype, lltype.Ptr)
- and error_value is not CANNOT_FAIL):
- assert lltype.typeOf(error_value) == callable.api_func.restype
- assert not error_value # only support error=NULL
- error_value = 0 # because NULL is not hashable
-
- if callable.api_func.result_is_ll:
- result_kind = "L"
- elif callable.api_func.result_borrowed:
- result_kind = "B" # note: 'result_borrowed' is ignored if we also
- else: # say 'result_is_ll=True' (in this case it's
- result_kind = "." # up to you to handle refcounting anyway)
-
- signature = (tuple(argtypesw),
- callable.api_func.restype,
- result_kind,
- error_value,
- gil)
-
- cache = space.fromcache(WrapperCache)
- cache.stats[1] += 1
- try:
- wrapper_gen = cache.wrapper_gens[signature]
- except KeyError:
- #print signature
- wrapper_gen = cache.wrapper_gens[signature] = WrapperGen(space,
- signature)
- cache.stats[0] += 1
- #print 'Wrapper cache [wrappers/total]:', cache.stats
- return wrapper_gen.make_wrapper(callable)
-
@dont_inline
def deadlock_error(funcname):
@@ -1019,7 +1025,7 @@
structindex = {}
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
- if not func:
+ if not func:
# added only for the macro, not the decl
continue
restype, args = c_function_signature(db, func)
@@ -1033,7 +1039,7 @@
RPY_EXTERN struct PyPyAPI* pypyAPI = &_pypyAPI;
""" % dict(members=structmembers)
- functions = generate_decls_and_callbacks(db, export_symbols,
+ functions = generate_decls_and_callbacks(db, export_symbols,
prefix='cpyexttest')
global_objects = []
@@ -1415,7 +1421,7 @@
generate_macros(export_symbols, prefix=prefix)
- functions = generate_decls_and_callbacks(db, [], api_struct=False,
+ functions = generate_decls_and_callbacks(db, [], api_struct=False,
prefix=prefix)
code = "#include <Python.h>\n"
if use_micronumpy:
@@ -1471,7 +1477,7 @@
if not func:
continue
newname = mangle_name('PyPy', name) or name
- deco = entrypoint_lowlevel("cpyext", func.argtypes, newname,
+ deco = entrypoint_lowlevel("cpyext", func.argtypes, newname,
relax=True)
deco(func.get_wrapper(space))
diff --git a/pypy/module/cpyext/test/test_translate.py
b/pypy/module/cpyext/test/test_translate.py
--- a/pypy/module/cpyext/test/test_translate.py
+++ b/pypy/module/cpyext/test/test_translate.py
@@ -11,11 +11,11 @@
FT = lltype.FuncType([], lltype.Signed)
FTPTR = lltype.Ptr(FT)
- def make_wrapper(space, func, gil=None):
+ def make_wrapper(self, space):
def wrapper():
- return func(space)
+ return self.callable(space)
return wrapper
- monkeypatch.setattr(pypy.module.cpyext.api, 'make_wrapper', make_wrapper)
+ monkeypatch.setattr(pypy.module.cpyext.api.ApiFunction, '_make_wrapper',
make_wrapper)
@specialize.memo()
def get_tp_function(space, typedef):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit