1
2 /***** Support code for embedding *****/
3
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7
8
9 #if defined(_WIN32)
10 # define CFFI_DLLEXPORT __declspec(dllexport)
11 #elif defined(__GNUC__)
12 # define CFFI_DLLEXPORT __attribute__((visibility("default")))
13 #else
14 # define CFFI_DLLEXPORT /* nothing */
15 #endif
16
17
18 /* There are two global variables of type _cffi_call_python_fnptr:
19
20 * _cffi_call_python, which we declare just below, is the one called
21 by ``extern "Python"`` implementations.
22
23 * _cffi_call_python_org, which on CPython is actually part of the
24 _cffi_exports[] array, is the function pointer copied from
25 _cffi_backend.
26
27 After initialization is complete, both are equal. However, the
28 first one remains equal to &_cffi_start_and_call_python until the
29 very end of initialization, when we are (or should be) sure that
30 concurrent threads also see a completely initialized world, and
31 only then is it changed.
32 */
33 #undef _cffi_call_python
34 typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *);
35 static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *);
36 static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python;
37
38
39 #ifndef _MSC_VER
40 /* --- Assuming a GCC not infinitely old --- */
41 # define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n)
42 # define cffi_write_barrier() __sync_synchronize()
43 # if !defined(__amd64__) && !defined(__x86_64__) && \
44 !defined(__i386__) && !defined(__i386)
45 # define cffi_read_barrier() __sync_synchronize()
46 # else
47 # define cffi_read_barrier() (void)0
48 # endif
49 #else
50 /* --- Windows threads version --- */
51 # include <Windows.h>
52 # define cffi_compare_and_swap(l,o,n) \
53 (InterlockedCompareExchangePointer(l,n,o) == (o))
54 # define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0)
55 # define cffi_read_barrier() (void)0
56 static volatile LONG _cffi_dummy;
57 #endif
58
59 #ifdef WITH_THREAD
60 # ifndef _MSC_VER
61 # include <pthread.h>
62 static pthread_mutex_t _cffi_embed_startup_lock;
63 # else
64 static CRITICAL_SECTION _cffi_embed_startup_lock;
65 # endif
66 static char _cffi_embed_startup_lock_ready = 0;
67 #endif
68
_cffi_acquire_reentrant_mutex(void)69 static void _cffi_acquire_reentrant_mutex(void)
70 {
71 static void *volatile lock = NULL;
72
73 while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) {
74 /* should ideally do a spin loop instruction here, but
75 hard to do it portably and doesn't really matter I
76 think: pthread_mutex_init() should be very fast, and
77 this is only run at start-up anyway. */
78 }
79
80 #ifdef WITH_THREAD
81 if (!_cffi_embed_startup_lock_ready) {
82 # ifndef _MSC_VER
83 pthread_mutexattr_t attr;
84 pthread_mutexattr_init(&attr);
85 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
86 pthread_mutex_init(&_cffi_embed_startup_lock, &attr);
87 # else
88 InitializeCriticalSection(&_cffi_embed_startup_lock);
89 # endif
90 _cffi_embed_startup_lock_ready = 1;
91 }
92 #endif
93
94 while (!cffi_compare_and_swap(&lock, (void *)1, NULL))
95 ;
96
97 #ifndef _MSC_VER
98 pthread_mutex_lock(&_cffi_embed_startup_lock);
99 #else
100 EnterCriticalSection(&_cffi_embed_startup_lock);
101 #endif
102 }
103
_cffi_release_reentrant_mutex(void)104 static void _cffi_release_reentrant_mutex(void)
105 {
106 #ifndef _MSC_VER
107 pthread_mutex_unlock(&_cffi_embed_startup_lock);
108 #else
109 LeaveCriticalSection(&_cffi_embed_startup_lock);
110 #endif
111 }
112
113
114 /********** CPython-specific section **********/
115 #ifndef PYPY_VERSION
116
117 #include "_cffi_errors.h"
118
119
120 #define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX]
121
122 PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */
123
_cffi_py_initialize(void)124 static void _cffi_py_initialize(void)
125 {
126 /* XXX use initsigs=0, which "skips initialization registration of
127 signal handlers, which might be useful when Python is
128 embedded" according to the Python docs. But review and think
129 if it should be a user-controllable setting.
130
131 XXX we should also give a way to write errors to a buffer
132 instead of to stderr.
133
134 XXX if importing 'site' fails, CPython (any version) calls
135 exit(). Should we try to work around this behavior here?
136 */
137 Py_InitializeEx(0);
138 }
139
_cffi_initialize_python(void)140 static int _cffi_initialize_python(void)
141 {
142 /* This initializes Python, imports _cffi_backend, and then the
143 present .dll/.so is set up as a CPython C extension module.
144 */
145 int result;
146 PyGILState_STATE state;
147 PyObject *pycode=NULL, *global_dict=NULL, *x;
148
149 state = PyGILState_Ensure();
150
151 /* Call the initxxx() function from the present module. It will
152 create and initialize us as a CPython extension module, instead
153 of letting the startup Python code do it---it might reimport
154 the same .dll/.so and get maybe confused on some platforms.
155 It might also have troubles locating the .dll/.so again for all
156 I know.
157 */
158 (void)_CFFI_PYTHON_STARTUP_FUNC();
159 if (PyErr_Occurred())
160 goto error;
161
162 /* Now run the Python code provided to ffi.embedding_init_code().
163 */
164 pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE,
165 "<init code for '" _CFFI_MODULE_NAME "'>",
166 Py_file_input);
167 if (pycode == NULL)
168 goto error;
169 global_dict = PyDict_New();
170 if (global_dict == NULL)
171 goto error;
172 if (PyDict_SetItemString(global_dict, "__builtins__",
173 PyThreadState_GET()->interp->builtins) < 0)
174 goto error;
175 x = PyEval_EvalCode(
176 #if PY_MAJOR_VERSION < 3
177 (PyCodeObject *)
178 #endif
179 pycode, global_dict, global_dict);
180 if (x == NULL)
181 goto error;
182 Py_DECREF(x);
183
184 /* Done! Now if we've been called from
185 _cffi_start_and_call_python() in an ``extern "Python"``, we can
186 only hope that the Python code did correctly set up the
187 corresponding @ffi.def_extern() function. Otherwise, the
188 general logic of ``extern "Python"`` functions (inside the
189 _cffi_backend module) will find that the reference is still
190 missing and print an error.
191 */
192 result = 0;
193 done:
194 Py_XDECREF(pycode);
195 Py_XDECREF(global_dict);
196 PyGILState_Release(state);
197 return result;
198
199 error:;
200 {
201 /* Print as much information as potentially useful.
202 Debugging load-time failures with embedding is not fun
203 */
204 PyObject *ecap;
205 PyObject *exception, *v, *tb, *f, *modules, *mod;
206 PyErr_Fetch(&exception, &v, &tb);
207 ecap = _cffi_start_error_capture();
208 f = PySys_GetObject((char *)"stderr");
209 if (f != NULL && f != Py_None) {
210 PyFile_WriteString(
211 "Failed to initialize the Python-CFFI embedding logic:\n\n", f);
212 }
213
214 if (exception != NULL) {
215 PyErr_NormalizeException(&exception, &v, &tb);
216 PyErr_Display(exception, v, tb);
217 }
218 Py_XDECREF(exception);
219 Py_XDECREF(v);
220 Py_XDECREF(tb);
221
222 if (f != NULL && f != Py_None) {
223 PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
224 "\ncompiled with cffi version: 1.12.2"
225 "\n_cffi_backend module: ", f);
226 modules = PyImport_GetModuleDict();
227 mod = PyDict_GetItemString(modules, "_cffi_backend");
228 if (mod == NULL) {
229 PyFile_WriteString("not loaded", f);
230 }
231 else {
232 v = PyObject_GetAttrString(mod, "__file__");
233 PyFile_WriteObject(v, f, 0);
234 Py_XDECREF(v);
235 }
236 PyFile_WriteString("\nsys.path: ", f);
237 PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0);
238 PyFile_WriteString("\n\n", f);
239 }
240 _cffi_stop_error_capture(ecap);
241 }
242 result = -1;
243 goto done;
244 }
245
246 PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */
247
_cffi_carefully_make_gil(void)248 static int _cffi_carefully_make_gil(void)
249 {
250 /* This does the basic initialization of Python. It can be called
251 completely concurrently from unrelated threads. It assumes
252 that we don't hold the GIL before (if it exists), and we don't
253 hold it afterwards.
254
255 (What it really does used to be completely different in Python 2
256 and Python 3, with the Python 2 solution avoiding the spin-lock
257 around the Py_InitializeEx() call. However, after recent changes
258 to CPython 2.7 (issue #358) it no longer works. So we use the
259 Python 3 solution everywhere.)
260
261 This initializes Python by calling Py_InitializeEx().
262 Important: this must not be called concurrently at all.
263 So we use a global variable as a simple spin lock. This global
264 variable must be from 'libpythonX.Y.so', not from this
265 cffi-based extension module, because it must be shared from
266 different cffi-based extension modules. We choose
267 _PyParser_TokenNames[0] as a completely arbitrary pointer value
268 that is never written to. The default is to point to the
269 string "ENDMARKER". We change it temporarily to point to the
270 next character in that string. (Yes, I know it's REALLY
271 obscure.)
272 */
273
274 #ifdef WITH_THREAD
275 char *volatile *lock = (char *volatile *)_PyParser_TokenNames;
276 char *old_value;
277
278 while (1) { /* spin loop */
279 old_value = *lock;
280 if (old_value[0] == 'E') {
281 assert(old_value[1] == 'N');
282 if (cffi_compare_and_swap(lock, old_value, old_value + 1))
283 break;
284 }
285 else {
286 assert(old_value[0] == 'N');
287 /* should ideally do a spin loop instruction here, but
288 hard to do it portably and doesn't really matter I
289 think: PyEval_InitThreads() should be very fast, and
290 this is only run at start-up anyway. */
291 }
292 }
293 #endif
294
295 /* call Py_InitializeEx() */
296 {
297 PyGILState_STATE state = PyGILState_UNLOCKED;
298 if (!Py_IsInitialized())
299 _cffi_py_initialize();
300 else
301 state = PyGILState_Ensure();
302
303 PyEval_InitThreads();
304 PyGILState_Release(state);
305 }
306
307 #ifdef WITH_THREAD
308 /* release the lock */
309 while (!cffi_compare_and_swap(lock, old_value + 1, old_value))
310 ;
311 #endif
312
313 return 0;
314 }
315
316 /********** end CPython-specific section **********/
317
318
319 #else
320
321
322 /********** PyPy-specific section **********/
323
324 PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */
325
326 static struct _cffi_pypy_init_s {
327 const char *name;
328 void (*func)(const void *[]);
329 const char *code;
330 } _cffi_pypy_init = {
331 _CFFI_MODULE_NAME,
332 (void(*)(const void *[]))_CFFI_PYTHON_STARTUP_FUNC,
333 _CFFI_PYTHON_STARTUP_CODE,
334 };
335
336 extern int pypy_carefully_make_gil(const char *);
337 extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *);
338
_cffi_carefully_make_gil(void)339 static int _cffi_carefully_make_gil(void)
340 {
341 return pypy_carefully_make_gil(_CFFI_MODULE_NAME);
342 }
343
_cffi_initialize_python(void)344 static int _cffi_initialize_python(void)
345 {
346 return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init);
347 }
348
349 /********** end PyPy-specific section **********/
350
351
352 #endif
353
354
355 #ifdef __GNUC__
356 __attribute__((noinline))
357 #endif
_cffi_start_python(void)358 static _cffi_call_python_fnptr _cffi_start_python(void)
359 {
360 /* Delicate logic to initialize Python. This function can be
361 called multiple times concurrently, e.g. when the process calls
362 its first ``extern "Python"`` functions in multiple threads at
363 once. It can also be called recursively, in which case we must
364 ignore it. We also have to consider what occurs if several
365 different cffi-based extensions reach this code in parallel
366 threads---it is a different copy of the code, then, and we
367 can't have any shared global variable unless it comes from
368 'libpythonX.Y.so'.
369
370 Idea:
371
372 * _cffi_carefully_make_gil(): "carefully" call
373 PyEval_InitThreads() (possibly with Py_InitializeEx() first).
374
375 * then we use a (local) custom lock to make sure that a call to this
376 cffi-based extension will wait if another call to the *same*
377 extension is running the initialization in another thread.
378 It is reentrant, so that a recursive call will not block, but
379 only one from a different thread.
380
381 * then we grab the GIL and (Python 2) we call Py_InitializeEx().
382 At this point, concurrent calls to Py_InitializeEx() are not
383 possible: we have the GIL.
384
385 * do the rest of the specific initialization, which may
386 temporarily release the GIL but not the custom lock.
387 Only release the custom lock when we are done.
388 */
389 static char called = 0;
390
391 if (_cffi_carefully_make_gil() != 0)
392 return NULL;
393
394 _cffi_acquire_reentrant_mutex();
395
396 /* Here the GIL exists, but we don't have it. We're only protected
397 from concurrency by the reentrant mutex. */
398
399 /* This file only initializes the embedded module once, the first
400 time this is called, even if there are subinterpreters. */
401 if (!called) {
402 called = 1; /* invoke _cffi_initialize_python() only once,
403 but don't set '_cffi_call_python' right now,
404 otherwise concurrent threads won't call
405 this function at all (we need them to wait) */
406 if (_cffi_initialize_python() == 0) {
407 /* now initialization is finished. Switch to the fast-path. */
408
409 /* We would like nobody to see the new value of
410 '_cffi_call_python' without also seeing the rest of the
411 data initialized. However, this is not possible. But
412 the new value of '_cffi_call_python' is the function
413 'cffi_call_python()' from _cffi_backend. So: */
414 cffi_write_barrier();
415 /* ^^^ we put a write barrier here, and a corresponding
416 read barrier at the start of cffi_call_python(). This
417 ensures that after that read barrier, we see everything
418 done here before the write barrier.
419 */
420
421 assert(_cffi_call_python_org != NULL);
422 _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org;
423 }
424 else {
425 /* initialization failed. Reset this to NULL, even if it was
426 already set to some other value. Future calls to
427 _cffi_start_python() are still forced to occur, and will
428 always return NULL from now on. */
429 _cffi_call_python_org = NULL;
430 }
431 }
432
433 _cffi_release_reentrant_mutex();
434
435 return (_cffi_call_python_fnptr)_cffi_call_python_org;
436 }
437
438 static
_cffi_start_and_call_python(struct _cffi_externpy_s * externpy,char * args)439 void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args)
440 {
441 _cffi_call_python_fnptr fnptr;
442 int current_err = errno;
443 #ifdef _MSC_VER
444 int current_lasterr = GetLastError();
445 #endif
446 fnptr = _cffi_start_python();
447 if (fnptr == NULL) {
448 fprintf(stderr, "function %s() called, but initialization code "
449 "failed. Returning 0.\n", externpy->name);
450 memset(args, 0, externpy->size_of_result);
451 }
452 #ifdef _MSC_VER
453 SetLastError(current_lasterr);
454 #endif
455 errno = current_err;
456
457 if (fnptr != NULL)
458 fnptr(externpy, args);
459 }
460
461
462 /* The cffi_start_python() function makes sure Python is initialized
463 and our cffi module is set up. It can be called manually from the
464 user C code. The same effect is obtained automatically from any
465 dll-exported ``extern "Python"`` function. This function returns
466 -1 if initialization failed, 0 if all is OK. */
467 _CFFI_UNUSED_FN
cffi_start_python(void)468 static int cffi_start_python(void)
469 {
470 if (_cffi_call_python == &_cffi_start_and_call_python) {
471 if (_cffi_start_python() == NULL)
472 return -1;
473 }
474 cffi_read_barrier();
475 return 0;
476 }
477
478 #undef cffi_compare_and_swap
479 #undef cffi_write_barrier
480 #undef cffi_read_barrier
481
482 #ifdef __cplusplus
483 }
484 #endif
485