mirror of https://github.com/kivy/pyjnius.git
jnius: fix push/pop jnienv in order to avoid GIL going on using the previous thread env while we are still on the current thread
This commit is contained in:
parent
eedf301d60
commit
8349037dd3
|
@ -11,17 +11,22 @@ cdef JNIEnv *get_jnienv():
|
|||
env_stack = 0
|
||||
return env_current
|
||||
|
||||
cdef void push_jnienv(JNIEnv *env):
|
||||
cdef void push_jnienv(JNIEnv *env) nogil:
|
||||
global env_stacks, env_stack, env_current
|
||||
if env_stack == 255:
|
||||
raise Exception('Jnius: cannot push JNI env, too many entries')
|
||||
with gil:
|
||||
print('ERROR: Jnius cannot push JNI env, too many entries')
|
||||
return
|
||||
env_stack += 1
|
||||
env_stacks[env_stack] = env_current = env
|
||||
|
||||
cdef void pop_jnienv():
|
||||
global env_stacks, env_stack
|
||||
cdef void pop_jnienv() nogil:
|
||||
global env_stacks, env_stack, env_current
|
||||
if env_stack == 0:
|
||||
raise Exception('Jnius: cannot pop JNI env, already at 0')
|
||||
with gil:
|
||||
print('ERROR: Jnius cannot pop JNI env, already at 0')
|
||||
return
|
||||
env_stacks[env_stack] = NULL
|
||||
env_stack -= 1
|
||||
env_current = env_stacks[env_stack]
|
||||
|
||||
|
|
|
@ -72,8 +72,9 @@ cdef class PythonJavaClass(object):
|
|||
|
||||
return py_method(*args)
|
||||
|
||||
cdef jobject invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject
|
||||
cdef jobject py_invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject
|
||||
j_method, jobjectArray args) with gil:
|
||||
|
||||
from .reflect import get_signature, Method
|
||||
cdef jfieldID ptrField
|
||||
cdef jlong jptr
|
||||
|
@ -82,72 +83,79 @@ cdef jobject invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject
|
|||
cdef LocalRef ref
|
||||
cdef jobject j_arg
|
||||
|
||||
# get the python object
|
||||
ptrField = j_env[0].GetFieldID(j_env,
|
||||
j_env[0].GetObjectClass(j_env, j_this), "ptr", "J")
|
||||
jptr = j_env[0].GetLongField(j_env, j_this, ptrField)
|
||||
py_obj = <object><void *>jptr
|
||||
|
||||
# extract the method information
|
||||
method = Method(noinstance=True)
|
||||
ref = create_local_ref(j_env, j_method)
|
||||
method.instanciate_from(create_local_ref(j_env, j_method))
|
||||
ret_signature = get_signature(method.getReturnType())
|
||||
args_signature = [get_signature(x) for x in method.getParameterTypes()]
|
||||
|
||||
# convert java argument to python object
|
||||
# native java type are given with java.lang.*, even if the signature say
|
||||
# it's a native type.
|
||||
py_args = []
|
||||
convert_signature = {
|
||||
'Z': 'Ljava/lang/Boolean;',
|
||||
'B': 'Ljava/lang/Byte;',
|
||||
'C': 'Ljava/lang/Character;',
|
||||
'S': 'Ljava/lang/Short;',
|
||||
'I': 'Ljava/lang/Integer;',
|
||||
'J': 'Ljava/lang/Long;',
|
||||
'F': 'Ljava/lang/Float;',
|
||||
'D': 'Ljava/lang/Double;'}
|
||||
|
||||
for index, arg_signature in enumerate(args_signature):
|
||||
arg_signature = convert_signature.get(arg_signature, arg_signature)
|
||||
j_arg = j_env[0].GetObjectArrayElement(j_env, args, index)
|
||||
py_arg = convert_jobject_to_python(j_env, arg_signature, j_arg)
|
||||
py_args.append(py_arg)
|
||||
|
||||
# really invoke the python method
|
||||
name = method.getName()
|
||||
ret = py_obj.invoke(method, *py_args)
|
||||
|
||||
# convert back to the return type
|
||||
# use the populate_args(), but in the reverse way :)
|
||||
t = ret_signature[:1]
|
||||
|
||||
# did python returned a "native" type ?
|
||||
jtype = None
|
||||
|
||||
if ret_signature == 'Ljava/lang/Object;':
|
||||
# generic object, try to manually convert it
|
||||
tp = type(ret)
|
||||
if tp == int:
|
||||
jtype = 'J'
|
||||
elif tp == float:
|
||||
jtype = 'D'
|
||||
elif tp == bool:
|
||||
jtype = 'Z'
|
||||
elif len(ret_signature) == 1:
|
||||
jtype = ret_signature
|
||||
|
||||
try:
|
||||
push_jnienv(j_env)
|
||||
return convert_python_to_jobject(j_env, jtype or ret_signature, ret)
|
||||
except Exception as e:
|
||||
traceback.print_exc(e)
|
||||
|
||||
# get the python object
|
||||
ptrField = j_env[0].GetFieldID(j_env,
|
||||
j_env[0].GetObjectClass(j_env, j_this), "ptr", "J")
|
||||
jptr = j_env[0].GetLongField(j_env, j_this, ptrField)
|
||||
py_obj = <object><void *>jptr
|
||||
|
||||
# extract the method information
|
||||
method = Method(noinstance=True)
|
||||
ref = create_local_ref(j_env, j_method)
|
||||
method.instanciate_from(create_local_ref(j_env, j_method))
|
||||
ret_signature = get_signature(method.getReturnType())
|
||||
args_signature = [get_signature(x) for x in method.getParameterTypes()]
|
||||
|
||||
# convert java argument to python object
|
||||
# native java type are given with java.lang.*, even if the signature say
|
||||
# it's a native type.
|
||||
py_args = []
|
||||
convert_signature = {
|
||||
'Z': 'Ljava/lang/Boolean;',
|
||||
'B': 'Ljava/lang/Byte;',
|
||||
'C': 'Ljava/lang/Character;',
|
||||
'S': 'Ljava/lang/Short;',
|
||||
'I': 'Ljava/lang/Integer;',
|
||||
'J': 'Ljava/lang/Long;',
|
||||
'F': 'Ljava/lang/Float;',
|
||||
'D': 'Ljava/lang/Double;'}
|
||||
|
||||
for index, arg_signature in enumerate(args_signature):
|
||||
arg_signature = convert_signature.get(arg_signature, arg_signature)
|
||||
j_arg = j_env[0].GetObjectArrayElement(j_env, args, index)
|
||||
py_arg = convert_jobject_to_python(j_env, arg_signature, j_arg)
|
||||
py_args.append(py_arg)
|
||||
|
||||
# really invoke the python method
|
||||
name = method.getName()
|
||||
ret = py_obj.invoke(method, *py_args)
|
||||
|
||||
# convert back to the return type
|
||||
# use the populate_args(), but in the reverse way :)
|
||||
t = ret_signature[:1]
|
||||
|
||||
# did python returned a "native" type ?
|
||||
jtype = None
|
||||
|
||||
if ret_signature == 'Ljava/lang/Object;':
|
||||
# generic object, try to manually convert it
|
||||
tp = type(ret)
|
||||
if tp == int:
|
||||
jtype = 'J'
|
||||
elif tp == float:
|
||||
jtype = 'D'
|
||||
elif tp == bool:
|
||||
jtype = 'Z'
|
||||
elif len(ret_signature) == 1:
|
||||
jtype = ret_signature
|
||||
|
||||
cdef jobject invoke0(JNIEnv *j_env, jobject j_this, jobject j_proxy, jobject
|
||||
j_method, jobjectArray args) nogil:
|
||||
cdef jobject ret = NULL
|
||||
push_jnienv(j_env)
|
||||
with gil:
|
||||
try:
|
||||
return convert_python_to_jobject(j_env, jtype or ret_signature, ret)
|
||||
ret = py_invoke0(j_env, j_this, j_proxy, j_method, args)
|
||||
except Exception as e:
|
||||
traceback.print_exc(e)
|
||||
|
||||
finally:
|
||||
pop_jnienv()
|
||||
pop_jnienv()
|
||||
return ret
|
||||
|
||||
|
||||
# now we need to create a proxy and pass it an invocation handler
|
||||
|
|
Loading…
Reference in New Issue