diff options
| -rw-r--r-- | c/call_python.c | 4 | ||||
| -rw-r--r-- | cffi/_embedding.h | 54 | ||||
| -rw-r--r-- | cffi/recompiler.py | 1 | ||||
| -rw-r--r-- | demo/embedding.py | 2 |
4 files changed, 47 insertions, 14 deletions
diff --git a/c/call_python.c b/c/call_python.c index 8196000..1943e7d 100644 --- a/c/call_python.c +++ b/c/call_python.c @@ -146,9 +146,9 @@ static int _update_cache_to_call_python(struct _cffi_externpy_s *externpy) return 2; /* out of memory? */ } -#if (defined(WITH_THREAD) && !defined(!_MSC_VER) && \ +#if (defined(WITH_THREAD) && !defined(_MSC_VER) && \ !defined(__amd64__) && !defined(__x86_64__) && \ - !defined(__i386__) && !defined(__i386) + !defined(__i386__) && !defined(__i386)) # define read_barrier() __sync_synchronize() #else # define read_barrier() (void)0 diff --git a/cffi/_embedding.h b/cffi/_embedding.h index acb4024..c6acd70 100644 --- a/cffi/_embedding.h +++ b/cffi/_embedding.h @@ -110,6 +110,8 @@ static int _cffi_initialize_python(void) /* This initializes Python, imports _cffi_backend, and then the present .dll/.so is set up as a CPython C extension module. */ + int result; + PyObject *pycode=NULL, *m=NULL, *global_dict, *x; PyEval_AcquireLock(); /* acquire the GIL */ @@ -136,8 +138,19 @@ static int _cffi_initialize_python(void) /* Now run the Python code provided to ffi.embedding_init_code(). */ - if (PyRun_SimpleString(_CFFI_PYTHON_STARTUP_CODE) < 0) + m = PyImport_ImportModule(_CFFI_MODULE_NAME); + if (m == NULL) goto error; + pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE, + "<init code for '" _CFFI_MODULE_NAME "'>", + Py_file_input); + if (pycode == NULL) + goto error; + global_dict = PyModule_GetDict(m); + x = PyEval_EvalCode((PyCodeObject *)pycode, global_dict, global_dict); + if (x == NULL) + goto error; + Py_DECREF(x); /* Done! Now if we've been called from _cffi_start_and_call_python() in an ``extern "Python"``, we can @@ -147,9 +160,12 @@ static int _cffi_initialize_python(void) _cffi_backend module) will find that the reference is still missing and print an error. */ - + result = 0; + done: + Py_XDECREF(pycode); + Py_XDECREF(m); PyEval_ReleaseLock(); /* release the GIL */ - return 0; + return result; error:; { @@ -184,16 +200,17 @@ static int _cffi_initialize_python(void) PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); PyFile_WriteString("\n\n", f); } - PyEval_ReleaseLock(); /* release the GIL */ - return -1; } + result = -1; + goto done; } static void _cffi_carefully_make_gil(void) { -#ifdef WITH_THREAD /* This initializes the GIL. It can be called completely - concurrently from unrelated threads. + concurrently from unrelated threads. It assumes that we don't + hold the GIL before (if it exists), and we don't hold it + afterwards. PyEval_InitThreads() must not be called concurrently at all. So we use a global variable as a simple spin lock. This global @@ -204,6 +221,7 @@ static void _cffi_carefully_make_gil(void) never-used word for this lock. (Yes, I know it's really obscure.) */ +#ifdef WITH_THREAD void *volatile *lock = (void *volatile *)&PyEllipsis_Type.tp_dealloc; while (1) { /* spin loop */ @@ -244,12 +262,25 @@ static void _cffi_carefully_make_gil(void) PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */ -extern int pypy_init_embedded_cffi_module(void(const void *[])); +static struct _cffi_pypy_init_s { + const char *name; + void (*func)(const void *[]); + const char *code; +} _cffi_pypy_init = { + _CFFI_MODULE_NAME, + _CFFI_PYTHON_STARTUP_FUNC, + _CFFI_PYTHON_STARTUP_CODE, +}; + +extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); + +static void _cffi_carefully_make_gil(void) +{ +} static int _cffi_initialize_python(void) { - return pypy_init_embedded_cffi_module(0xB011, _CFFI_PYTHON_STARTUP_FUNC, - _CFFI_PYTHON_STARTUP_CODE); + return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); } /********** end PyPy-specific section **********/ @@ -302,6 +333,9 @@ static _cffi_call_python_fnptr _cffi_start_python(void) /* Here the GIL exists, but we don't have it. We're only protected from concurrency by the reentrant mutex. */ + + /* This file ignores subinterpreters and can only initialize the + embedded module once, in the main interpreter. */ if (!called) { called = 1; /* invoke _cffi_initialize_python() only once, but don't set '_cffi_call_python' right now, diff --git a/cffi/recompiler.py b/cffi/recompiler.py index fe98cb5..c717e74 100644 --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -285,6 +285,7 @@ class Recompiler: # and include an extra file base_module_name = self.module_name.split('.')[-1] if self.ffi._embedding_init_code is not None: + prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) prnt('#define _CFFI_PYTHON_STARTUP_CODE %s' % (self._string_literal(self.ffi._embedding_init_code),)) prnt('#ifdef PYPY_VERSION') diff --git a/demo/embedding.py b/demo/embedding.py index 0d776ef..365238d 100644 --- a/demo/embedding.py +++ b/demo/embedding.py @@ -7,8 +7,6 @@ ffi.cdef(""" """, dllexport=True) ffi.embedding_init_code(""" - from _embedding_cffi import ffi, lib - print "preparing" @ffi.def_extern() |
