[pypy-commit] pypy cpyext-ext: add a failing test for PyGILState_Release, passes with -A. Also add thread to config.translation

mattip pypy.commits at gmail.com
Sun Mar 20 18:04:04 EDT 2016


Author: mattip <matti.picus at gmail.com>
Branch: cpyext-ext
Changeset: r83204:61665eeb889c
Date: 2016-03-21 00:03 +0200
http://bitbucket.org/pypy/pypy/changeset/61665eeb889c/

Log:	add a failing test for PyGILState_Release, passes with -A. Also add
	thread to config.translation

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
@@ -48,7 +48,7 @@
 
     def test_basic_threadstate_dance(self):
         if self.runappdirect:
-            py.test.xfail('segfault')
+            py.test.xfail('segfault: PyThreadState_Get: no current thread')
         module = self.import_extension('foo', [
                 ("dance", "METH_NOARGS",
                  """
@@ -113,6 +113,127 @@
                                   """),
                 ])
 
+class AppTestState(AppTestCpythonExtensionBase):
+
+    def test_frame_tstate_tracing(self):
+        import sys, threading
+        module = self.import_extension('foo', [
+            ("call_in_temporary_c_thread", "METH_O",
+             """
+                PyObject *res = NULL;
+                test_c_thread_t test_c_thread;
+                long thread;
+
+                PyEval_InitThreads();
+
+                test_c_thread.start_event = PyThread_allocate_lock();
+                test_c_thread.exit_event = PyThread_allocate_lock();
+                test_c_thread.callback = NULL;
+                if (!test_c_thread.start_event || !test_c_thread.exit_event) {
+                    PyErr_SetString(PyExc_RuntimeError, "could not allocate lock");
+                    goto exit;
+                }
+
+                Py_INCREF(args);
+                test_c_thread.callback = args;
+
+                PyThread_acquire_lock(test_c_thread.start_event, 1);
+                PyThread_acquire_lock(test_c_thread.exit_event, 1);
+
+                thread = PyThread_start_new_thread(temporary_c_thread, &test_c_thread);
+                if (thread == -1) {
+                    PyErr_SetString(PyExc_RuntimeError, "unable to start the thread");
+                    PyThread_release_lock(test_c_thread.start_event);
+                    PyThread_release_lock(test_c_thread.exit_event);
+                    goto exit;
+                }
+
+                PyThread_acquire_lock(test_c_thread.start_event, 1);
+                PyThread_release_lock(test_c_thread.start_event);
+
+                Py_BEGIN_ALLOW_THREADS
+                    PyThread_acquire_lock(test_c_thread.exit_event, 1);
+                    PyThread_release_lock(test_c_thread.exit_event);
+                Py_END_ALLOW_THREADS
+
+                Py_INCREF(Py_None);
+                res = Py_None;
+
+            exit:
+                Py_CLEAR(test_c_thread.callback);
+                if (test_c_thread.start_event)
+                    PyThread_free_lock(test_c_thread.start_event);
+                if (test_c_thread.exit_event)
+                    PyThread_free_lock(test_c_thread.exit_event);
+                return res;
+            """), ], prologue = """
+            #include "pythread.h"
+            typedef struct {
+                PyThread_type_lock start_event;
+                PyThread_type_lock exit_event;
+                PyObject *callback;
+            } test_c_thread_t;
+
+            static void
+            temporary_c_thread(void *data)
+            {
+                test_c_thread_t *test_c_thread = data;
+                PyGILState_STATE state;
+                PyObject *res;
+
+                PyThread_release_lock(test_c_thread->start_event);
+
+                /* Allocate a Python thread state for this thread */
+                state = PyGILState_Ensure();
+
+                res = PyObject_CallFunction(test_c_thread->callback, "", NULL);
+                Py_CLEAR(test_c_thread->callback);
+
+                if (res == NULL) {
+                    PyErr_Print();
+                }
+                else {
+                    Py_DECREF(res);
+                }
+
+                /* Destroy the Python thread state for this thread */
+                PyGILState_Release(state);
+
+                PyThread_release_lock(test_c_thread->exit_event);
+
+                /*PyThread_exit_thread(); NOP (on linux) and not implememnted */
+            };
+            """)
+        def noop_trace(frame, event, arg):
+            # no operation
+            return noop_trace
+
+        def generator():
+            while 1:
+                yield "genereator"
+
+        def callback():
+            if callback.gen is None:
+                callback.gen = generator()
+            return next(callback.gen)
+        callback.gen = None
+
+        old_trace = sys.gettrace()
+        sys.settrace(noop_trace)
+        try:
+            # Install a trace function
+            threading.settrace(noop_trace)
+
+            # Create a generator in a C thread which exits after the call
+            module.call_in_temporary_c_thread(callback)
+
+            # Call the generator in a different Python thread, check that the
+            # generator didn't keep a reference to the destroyed thread state
+            for test in range(3):
+                # The trace function is still called here
+                callback()
+        finally:
+            sys.settrace(old_trace)
 
 
 class TestInterpreterState(BaseApiTest):
diff --git a/pypy/tool/pytest/objspace.py b/pypy/tool/pytest/objspace.py
--- a/pypy/tool/pytest/objspace.py
+++ b/pypy/tool/pytest/objspace.py
@@ -28,6 +28,8 @@
 def maketestobjspace(config=None):
     if config is None:
         config = make_config(option)
+    if config.objspace.usemodules.thread:
+        config.translation.thread = True
     space = make_objspace(config)
     space.startup() # Initialize all builtin modules
     space.setitem(space.builtin.w_dict, space.wrap('AssertionError'),


More information about the pypy-commit mailing list