Author: Ronan Lamy <[email protected]>
Branch:
Changeset: r90235:03278118ee16
Date: 2017-02-21 05:38 +0000
http://bitbucket.org/pypy/pypy/changeset/03278118ee16/
Log: Fix interaction of PyGILState_* with thread states
Instead of nulling the ec.cpyext_threadstate when releasing the gil
via PyEval_SaveThread(), we now keep it around and use a flag to
emulate CPython's nulling of the thread state. This allows
PyGILState_Ensure() to restore the thread state.
diff --git a/pypy/module/cpyext/pystate.py b/pypy/module/cpyext/pystate.py
--- a/pypy/module/cpyext/pystate.py
+++ b/pypy/module/cpyext/pystate.py
@@ -1,6 +1,6 @@
from pypy.module.cpyext.api import (
- cpython_api, generic_cpy_call, CANNOT_FAIL, CConfig, cpython_struct)
-from pypy.module.cpyext.pyobject import PyObject, Py_DecRef, make_ref, from_ref
+ cpython_api, CANNOT_FAIL, cpython_struct)
+from pypy.module.cpyext.pyobject import PyObject, Py_DecRef, make_ref
from pypy.interpreter.error import OperationError
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rlib import rthread
@@ -29,8 +29,9 @@
the current thread must have acquired it. (This function is available even
when thread support is disabled at compile time.)"""
state = space.fromcache(InterpreterState)
- tstate = state.swap_thread_state(
- space, lltype.nullptr(PyThreadState.TO))
+ ec = space.getexecutioncontext()
+ tstate = state._get_thread_state(space, ec).memory
+ ec.cpyext_threadstate_is_current = False
return tstate
@cpython_api([PyThreadState], lltype.Void, gil="acquire")
@@ -40,8 +41,8 @@
NULL. If the lock has been created, the current thread must not have
acquired it, otherwise deadlock ensues. (This function is available even
when thread support is disabled at compile time.)"""
- state = space.fromcache(InterpreterState)
- state.swap_thread_state(space, tstate)
+ ec = space.getexecutioncontext()
+ ec.cpyext_threadstate_is_current = True
@cpython_api([], lltype.Void)
def PyEval_InitThreads(space):
@@ -91,9 +92,11 @@
# released, so a check against that can't be used to determine the need for
# initialization).
ExecutionContext.cpyext_initialized_threadstate = False
+ExecutionContext.cpyext_threadstate_is_current = True
def cleanup_cpyext_state(self):
self.cpyext_threadstate = None
+ self.cpyext_threadstate_is_current = True
self.cpyext_initialized_threadstate = False
ExecutionContext.cleanup_cpyext_state = cleanup_cpyext_state
@@ -162,6 +165,7 @@
if not ec.cpyext_initialized_threadstate:
ec.cpyext_threadstate = self.new_thread_state(space)
ec.cpyext_initialized_threadstate = True
+ ec.cpyext_threadstate_is_current = True
return ec.cpyext_threadstate
@cpython_api([], PyThreadState, error=CANNOT_FAIL)
@@ -181,7 +185,7 @@
meant that an exception was raised."""
state = space.fromcache(InterpreterState)
ts = state.get_thread_state(space)
- if not ts:
+ if not space.getexecutioncontext().cpyext_threadstate_is_current:
return lltype.nullptr(PyObject.TO)
return ts.c_dict
@@ -189,8 +193,17 @@
def PyThreadState_Swap(space, tstate):
"""Swap the current thread state with the thread state given by the
argument
tstate, which may be NULL. The global interpreter lock must be held."""
+ ec = space.getexecutioncontext()
state = space.fromcache(InterpreterState)
- return state.swap_thread_state(space, tstate)
+ old_tstate = state.get_thread_state(space)
+ if not ec.cpyext_threadstate_is_current:
+ old_tstate = lltype.nullptr(PyThreadState.TO)
+ if tstate:
+ assert tstate == state.get_thread_state(space)
+ ec.cpyext_threadstate_is_current = True
+ else:
+ ec.cpyext_threadstate_is_current = False
+ return old_tstate
@cpython_api([PyThreadState], lltype.Void, gil="acquire")
def PyEval_AcquireThread(space, tstate):
@@ -254,6 +267,7 @@
if not we_are_translated():
_workaround_cpython_untranslated(space)
#
+ ec.cpyext_threadstate_is_current = True
return rffi.cast(PyGILState_STATE, previous_state)
@cpython_api([PyGILState_STATE], lltype.Void, gil="pygilstate_release")
@@ -266,6 +280,7 @@
assert ec.cpyext_gilstate_counter_noleave == 0
assert oldstate == PyGILState_UNLOCKED
space.threadlocals.leave_thread(space)
+ ec.cpyext_threadstate_is_current = False
@cpython_api([], PyInterpreterState, error=CANNOT_FAIL)
def PyInterpreterState_Head(space):
diff --git a/pypy/module/cpyext/test/test_api.py
b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -66,7 +66,7 @@
raise
try:
- self.space.getexecutioncontext().cleanup_cpyext_threadstate()
+ self.space.getexecutioncontext().cleanup_cpyext_state()
except AttributeError:
pass
diff --git a/pypy/module/cpyext/test/test_cpyext.py
b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -106,7 +106,6 @@
del obj
import gc; gc.collect()
- space.getexecutioncontext().cleanup_cpyext_state()
for w_obj in state.non_heaptypes_w:
Py_DecRef(space, w_obj)
@@ -180,6 +179,7 @@
def teardown_method(self, meth):
if self.runappdirect:
return
+ self.space.getexecutioncontext().cleanup_cpyext_state()
self.cleanup_references(self.space)
# XXX: like AppTestCpythonExtensionBase.teardown_method:
# find out how to disable check_and_print_leaks() if the
@@ -370,6 +370,7 @@
return
for name in self.imported_module_names:
self.unimport_module(name)
+ self.space.getexecutioncontext().cleanup_cpyext_state()
self.cleanup_references(self.space)
# XXX: find out how to disable check_and_print_leaks() if the
# test failed...
diff --git a/pypy/module/cpyext/test/test_pystate.py
b/pypy/module/cpyext/test/test_pystate.py
--- a/pypy/module/cpyext/test/test_pystate.py
+++ b/pypy/module/cpyext/test/test_pystate.py
@@ -69,8 +69,6 @@
assert module.get() == 3
def test_basic_threadstate_dance(self):
- if self.runappdirect:
- py.test.xfail('segfault: on cpython cannot Get() a NULL tstate')
module = self.import_extension('foo', [
("dance", "METH_NOARGS",
"""
@@ -83,8 +81,8 @@
return PyLong_FromLong(0);
}
- new_tstate = PyThreadState_Get(); /* fails on cpython */
- if (new_tstate != NULL) {
+ PyObject* d = PyThreadState_GetDict(); /* fails on
cpython */
+ if (d != NULL) {
return PyLong_FromLong(1);
}
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit