[pypy-commit] pypy cpyext-tls-operror: cpyext: add a test for error state race condition
pv
pypy.commits at gmail.com
Sun May 6 15:27:25 EDT 2018
Author: Pauli Virtanen <pav at iki.fi>
Branch: cpyext-tls-operror
Changeset: r94472:db2b75a607e4
Date: 2018-03-20 21:17 +0100
http://bitbucket.org/pypy/pypy/changeset/db2b75a607e4/
Log: cpyext: add a test for error state race condition
diff --git a/pypy/module/cpyext/test/test_pyerrors.py b/pypy/module/cpyext/test/test_pyerrors.py
--- a/pypy/module/cpyext/test/test_pyerrors.py
+++ b/pypy/module/cpyext/test/test_pyerrors.py
@@ -478,3 +478,59 @@
'''),
])
raises(SystemError, module.oops)
+
+ def test_error_thread_race(self):
+ # Check race condition: thread 0 returns from cpyext with error set,
+ # after thread 1 has set an error but before it returns.
+ module = self.import_extension('foo', [
+ ("emit_error", "METH_VARARGS",
+ '''
+ PyThreadState *save = NULL;
+ PyGILState_STATE gilsave;
+
+ /* NB. synchronization due to GIL */
+ static volatile int flag = 0;
+ int id;
+
+ if (!PyArg_ParseTuple(args, "i", &id))
+ return NULL;
+
+ /* Proceed in thread 1 first */
+ save = PyEval_SaveThread();
+ while (id == 0 && flag == 0);
+ gilsave = PyGILState_Ensure();
+
+ PyErr_SetString(PyExc_ValueError, "failure");
+
+ /* Proceed in thread 0 first */
+ if (id == 1) flag = 1;
+ PyGILState_Release(gilsave);
+ while (id == 1 && flag == 1);
+ PyEval_RestoreThread(save);
+
+ if (id == 0) flag = 0;
+ return NULL;
+ '''
+ ),
+ ])
+
+ import threading
+
+ failures = []
+
+ def worker(arg):
+ try:
+ module.emit_error(arg)
+ failures.append(True)
+ except ValueError as exc:
+ if str(exc) != "failure":
+ failures.append(exc)
+
+ threads = [threading.Thread(target=worker, args=(j,))
+ for j in (0, 1)]
+ for t in threads:
+ t.start()
+ for t in threads:
+ t.join()
+
+ assert not failures
More information about the pypy-commit
mailing list