Author: Armin Rigo <[email protected]>
Branch: static-callback-embedding
Changeset: r2511:99cb43d80de0
Date: 2016-01-01 14:49 +0100
http://bitbucket.org/cffi/cffi/changeset/99cb43d80de0/
Log: Fix the multithreaded initialization.
diff --git a/cffi/_embedding.h b/cffi/_embedding.h
--- a/cffi/_embedding.h
+++ b/cffi/_embedding.h
@@ -118,9 +118,14 @@
present .dll/.so is set up as a CPython C extension module.
*/
int result;
+ PyGILState_STATE state;
PyObject *pycode=NULL, *m=NULL, *global_dict, *x;
- PyEval_AcquireLock(); /* acquire the GIL */
+ /* Acquire the GIL. We have no threadstate here. If Python is
+ already initialized, it is possible that there is already one
+ existing for this thread, but it is not made current now.
+ */
+ PyEval_AcquireLock();
/* XXX use initsigs=0, which "skips initialization registration of
signal handlers, which might be useful when Python is
@@ -132,6 +137,20 @@
*/
Py_InitializeEx(0);
+ /* The Py_InitializeEx() sometimes made a threadstate for us, but
+ not always. Indeed Py_InitializeEx() could be called and do
+ nothing. So do we have a threadstate, or not? We don't know,
+ but we can replace it with NULL in all cases.
+ */
+ (void)PyThreadState_Swap(NULL);
+
+ /* Now we can release the GIL and re-acquire immediately using the
+ logic of PyGILState(), which handles making or installing the
+ correct threadstate.
+ */
+ PyEval_ReleaseLock();
+ state = PyGILState_Ensure();
+
/* Call the initxxx() function from the present module. It will
create and initialize us as a CPython extension module, instead
of letting the startup Python code do it---it might reimport
@@ -175,7 +194,7 @@
done:
Py_XDECREF(pycode);
Py_XDECREF(m);
- PyEval_ReleaseLock(); /* release the GIL */
+ PyGILState_Release(state);
return result;
error:;
diff --git a/testing/embedding/add2.py b/testing/embedding/add2.py
--- a/testing/embedding/add2.py
+++ b/testing/embedding/add2.py
@@ -6,12 +6,13 @@
extern "Python" int add2(int, int, int);
""", dllexport=True)
-ffi.embedding_init_code("""
- print("preparing ADD2")
+ffi.embedding_init_code(r"""
+ import sys
+ sys.stdout.write("prepADD2\n")
@ffi.def_extern()
def add2(x, y, z):
- print "adding", x, "and", y, "and", z
+ sys.stdout.write("adding %d and %d and %d\n" % (x, y, z))
return x + y + z
""")
diff --git a/testing/embedding/test_basic.py b/testing/embedding/test_basic.py
--- a/testing/embedding/test_basic.py
+++ b/testing/embedding/test_basic.py
@@ -67,6 +67,6 @@
output = self.execute('add2-test')
assert output == ("preparing...\n"
"adding 40 and 2\n"
- "preparing ADD2\n"
+ "prepADD2\n"
"adding 100 and -5 and -20\n"
"got: 42 75\n")
diff --git a/testing/embedding/test_thread.py b/testing/embedding/test_thread.py
--- a/testing/embedding/test_thread.py
+++ b/testing/embedding/test_thread.py
@@ -5,24 +5,44 @@
def test_first_calls_in_parallel(self):
self.prepare_module('add1')
self.compile('thread1-test', ['_add1_cffi'], ['-pthread'])
- for i in range(5):
+ for i in range(50):
output = self.execute('thread1-test')
assert output == ("starting\n"
"preparing...\n" +
"adding 40 and 2\n" * 10 +
"done\n")
+ def _take_out(self, text, content):
+ assert content in text
+ i = text.index(content)
+ return text[:i] + text[i+len(content):]
+
def test_init_different_modules_in_different_threads(self):
self.prepare_module('add1')
self.prepare_module('add2')
self.compile('thread2-test', ['_add1_cffi', '_add2_cffi'],
['-pthread'])
output = self.execute('thread2-test')
- assert output == XXX
+ output = self._take_out(output, "preparing")
+ output = self._take_out(output, ".")
+ output = self._take_out(output, ".")
+ # at least the 3rd dot should be after everything from ADD2
+ assert output == ("starting\n"
+ "prepADD2\n"
+ "adding 1000 and 200 and 30\n"
+ ".\n"
+ "adding 40 and 2\n"
+ "done\n")
- def test_next_issue(self):
+ def test_alt_issue(self):
self.prepare_module('add1')
self.prepare_module('add2')
self.compile('thread2-test', ['_add1_cffi', '_add2_cffi'],
['-pthread', '-DT2TEST_AGAIN_ADD1'])
output = self.execute('thread2-test')
- assert output == XXX
+ output = self._take_out(output, "adding 40 and 2\n")
+ assert output == ("starting\n"
+ "preparing...\n"
+ "adding -1 and -1\n"
+ "prepADD2\n"
+ "adding 1000 and 200 and 30\n"
+ "done\n")
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit