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

Reply via email to