[pypy-commit] pypy non-null-threadstate: (fijal, glyph, exarkun) Encapsulate cpyext tstate cleanup for tests in a method; fix a bug in that cleanup that made it hard to have more than a single unit test, ever. Port all the tests to be written in C, the language of wonder and beauty.
exarkun
noreply at buildbot.pypy.org
Fri Mar 9 08:20:11 CET 2012
Author: Jean-Paul Calderone <exarkun at twistedmatrix.com>
Branch: non-null-threadstate
Changeset: r53280:554e5a0f831e
Date: 2012-03-08 23:19 -0800
http://bitbucket.org/pypy/pypy/changeset/554e5a0f831e/
Log: (fijal, glyph, exarkun) Encapsulate cpyext tstate cleanup for tests
in a method; fix a bug in that cleanup that made it hard to have
more than a single unit test, ever. Port all the tests to be
written in C, the language of wonder and beauty.
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
@@ -84,12 +84,19 @@
# initialization).
ExecutionContext.cpyext_initialized_threadstate = False
+def cleanup_cpyext_state(self):
+ try:
+ del self.cpyext_threadstate
+ except AttributeError:
+ pass
+ self.cpyext_initialized_threadstate = False
+ExecutionContext.cleanup_cpyext_state = cleanup_cpyext_state
+
class InterpreterState(object):
def __init__(self, space):
self.interpreter_state = lltype.malloc(
PyInterpreterState.TO, flavor='raw', zero=True, immortal=True)
-
def new_thread_state(self, space):
"""
Create a new ThreadStateCapsule to hold the PyThreadState for a
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,10 +106,7 @@
del obj
import gc; gc.collect()
- try:
- del space.getexecutioncontext().cpyext_threadstate
- except AttributeError:
- pass
+ space.getexecutioncontext().cleanup_cpyext_state()
for w_obj in state.non_heaptypes_w:
Py_DecRef(space, w_obj)
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
@@ -25,6 +25,93 @@
# Should compile at least
module.test()
+
+ def test_thread_state_get(self):
+ module = self.import_extension('foo', [
+ ("get", "METH_NOARGS",
+ """
+ PyThreadState *tstate = PyThreadState_Get();
+ if (tstate == NULL) {
+ return PyLong_FromLong(0);
+ }
+ if (tstate->interp != PyInterpreterState_Head()) {
+ return PyLong_FromLong(1);
+ }
+ if (tstate->interp->next != NULL) {
+ return PyLong_FromLong(2);
+ }
+ return PyLong_FromLong(3);
+ """),
+ ])
+ assert module.get() == 3
+
+ def test_basic_threadstate_dance(self):
+ module = self.import_extension('foo', [
+ ("dance", "METH_NOARGS",
+ """
+ PyThreadState *old_tstate, *new_tstate;
+
+ old_tstate = PyThreadState_Swap(NULL);
+ if (old_tstate == NULL) {
+ return PyLong_FromLong(0);
+ }
+
+ new_tstate = PyThreadState_Get();
+ if (new_tstate != NULL) {
+ return PyLong_FromLong(1);
+ }
+
+ new_tstate = PyThreadState_Swap(old_tstate);
+ if (new_tstate != NULL) {
+ return PyLong_FromLong(2);
+ }
+
+ new_tstate = PyThreadState_Get();
+ if (new_tstate != old_tstate) {
+ return PyLong_FromLong(3);
+ }
+
+ return PyLong_FromLong(4);
+ """),
+ ])
+ assert module.dance() == 4
+
+ def test_threadstate_dict(self):
+ module = self.import_extension('foo', [
+ ("getdict", "METH_NOARGS",
+ """
+ PyObject *dict = PyThreadState_GetDict();
+ Py_INCREF(dict);
+ return dict;
+ """),
+ ])
+ assert isinstance(module.getdict(), dict)
+
+ def test_savethread(self):
+ module = self.import_extension('foo', [
+ ("bounce", "METH_NOARGS",
+ """
+ PyThreadState *tstate = PyEval_SaveThread();
+ if (tstate == NULL) {
+ return PyLong_FromLong(0);
+ }
+
+ if (PyThreadState_Get() != NULL) {
+ return PyLong_FromLong(1);
+ }
+
+ PyEval_RestoreThread(tstate);
+
+ if (PyThreadState_Get() != tstate) {
+ return PyLong_FromLong(2);
+ }
+
+ return PyLong_FromLong(3);
+ """),
+ ])
+
+
+
class TestInterpreterState(BaseApiTest):
def test_interpreter_head(self, space, api):
state = api.PyInterpreterState_Head()
@@ -33,73 +120,3 @@
def test_interpreter_next(self, space, api):
state = api.PyInterpreterState_Head()
assert nullptr(PyInterpreterState.TO) == api.PyInterpreterState_Next(state)
-
-
-class DirectThreadStateBase(LeakCheckingTest):
- # XXX Subclasses of this are probably pretty slow, because creating new
- # spaces is pretty slow. They probably leak some memory too, because cpyext
- # initialization allocates some stuff and it's too hard to find it to clean
- # it up.
- # XXX This should be setup_method not setup_class, but mystery failures.
- def setup_class(cls):
- # XXX HACK HACK HACK Mystery bug, not going to debug it, just going to hack it
- leakfinder.TRACK_ALLOCATIONS = True
- leakfinder.stop_tracking_allocations(check=False)
-
- # Make a *new* space. blah blah explain more
- from pypy.conftest import maketestobjspace, make_config, option
- cls.space = maketestobjspace(make_config(option, usemodules=["cpyext"]))
-
-
- def teardown_class(cls):
- ec = cls.space.getexecutioncontext()
- del ec.cpyext_threadstate
- ec.cpyext_initialized_threadstate = False
-
- leakfinder.start_tracking_allocations()
-
-
-class TestThreadStateDirect(DirectThreadStateBase):
- def test_thread_state_interp(self):
- ts = PyThreadState_Get(self.space)
- assert ts.c_interp == PyInterpreterState_Head(self.space)
- assert ts.c_interp.c_next == nullptr(PyInterpreterState.TO)
-
- def test_thread_state_get(self):
- return
- ts = PyThreadState_Get(self.space)
- assert ts != nullptr(PyThreadState.TO)
-
-
- def test_basic_threadstate_dance(self, space, api):
- return
- # Let extension modules call these functions,
- # Not sure of the semantics in pypy though.
- # (cpyext always acquires and releases the GIL around calls)
- tstate = api.PyThreadState_Swap(None)
- assert tstate is not None
-
- assert api.PyThreadState_Get() is None
- assert api.PyThreadState_Swap(tstate) is None
- assert api.PyThreadState_Get() is tstate
-
- api.PyEval_AcquireThread(tstate)
- api.PyEval_ReleaseThread(tstate)
-
- def test_threadstate_dict(self, space, api):
- return
- ts = api.PyThreadState_Get()
- ref = ts.c_dict
- assert ref == api.PyThreadState_GetDict()
- w_obj = from_ref(space, ref)
- assert space.isinstance_w(w_obj, space.w_dict)
-
- def test_savethread(self, space, api):
- return
- ts = api.PyEval_SaveThread()
- assert ts
- assert api.PyThreadState_Get() == nullptr(PyThreadState.TO)
- api.PyEval_RestoreThread(ts)
- assert api.PyThreadState_Get() != nullptr(PyThreadState.TO)
-
-del LeakCheckingTest
More information about the pypy-commit
mailing list