• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     PyObject *builtins;
149 
150     state = PyGILState_Ensure();
151 
152     /* Call the initxxx() function from the present module.  It will
153        create and initialize us as a CPython extension module, instead
154        of letting the startup Python code do it---it might reimport
155        the same .dll/.so and get maybe confused on some platforms.
156        It might also have troubles locating the .dll/.so again for all
157        I know.
158     */
159     (void)_CFFI_PYTHON_STARTUP_FUNC();
160     if (PyErr_Occurred())
161         goto error;
162 
163     /* Now run the Python code provided to ffi.embedding_init_code().
164      */
165     pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE,
166                               "<init code for '" _CFFI_MODULE_NAME "'>",
167                               Py_file_input);
168     if (pycode == NULL)
169         goto error;
170     global_dict = PyDict_New();
171     if (global_dict == NULL)
172         goto error;
173     builtins = PyEval_GetBuiltins();
174     if (builtins == NULL)
175         goto error;
176     if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0)
177         goto error;
178     x = PyEval_EvalCode(
179 #if PY_MAJOR_VERSION < 3
180                         (PyCodeObject *)
181 #endif
182                         pycode, global_dict, global_dict);
183     if (x == NULL)
184         goto error;
185     Py_DECREF(x);
186 
187     /* Done!  Now if we've been called from
188        _cffi_start_and_call_python() in an ``extern "Python"``, we can
189        only hope that the Python code did correctly set up the
190        corresponding @ffi.def_extern() function.  Otherwise, the
191        general logic of ``extern "Python"`` functions (inside the
192        _cffi_backend module) will find that the reference is still
193        missing and print an error.
194      */
195     result = 0;
196  done:
197     Py_XDECREF(pycode);
198     Py_XDECREF(global_dict);
199     PyGILState_Release(state);
200     return result;
201 
202  error:;
203     {
204         /* Print as much information as potentially useful.
205            Debugging load-time failures with embedding is not fun
206         */
207         PyObject *ecap;
208         PyObject *exception, *v, *tb, *f, *modules, *mod;
209         PyErr_Fetch(&exception, &v, &tb);
210         ecap = _cffi_start_error_capture();
211         f = PySys_GetObject((char *)"stderr");
212         if (f != NULL && f != Py_None) {
213             PyFile_WriteString(
214                 "Failed to initialize the Python-CFFI embedding logic:\n\n", f);
215         }
216 
217         if (exception != NULL) {
218             PyErr_NormalizeException(&exception, &v, &tb);
219             PyErr_Display(exception, v, tb);
220         }
221         Py_XDECREF(exception);
222         Py_XDECREF(v);
223         Py_XDECREF(tb);
224 
225         if (f != NULL && f != Py_None) {
226             PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
227                                "\ncompiled with cffi version: 1.15.0"
228                                "\n_cffi_backend module: ", f);
229             modules = PyImport_GetModuleDict();
230             mod = PyDict_GetItemString(modules, "_cffi_backend");
231             if (mod == NULL) {
232                 PyFile_WriteString("not loaded", f);
233             }
234             else {
235                 v = PyObject_GetAttrString(mod, "__file__");
236                 PyFile_WriteObject(v, f, 0);
237                 Py_XDECREF(v);
238             }
239             PyFile_WriteString("\nsys.path: ", f);
240             PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0);
241             PyFile_WriteString("\n\n", f);
242         }
243         _cffi_stop_error_capture(ecap);
244     }
245     result = -1;
246     goto done;
247 }
248 
249 #if PY_VERSION_HEX < 0x03080000
250 PyAPI_DATA(char *) _PyParser_TokenNames[];  /* from CPython */
251 #endif
252 
_cffi_carefully_make_gil(void)253 static int _cffi_carefully_make_gil(void)
254 {
255     /* This does the basic initialization of Python.  It can be called
256        completely concurrently from unrelated threads.  It assumes
257        that we don't hold the GIL before (if it exists), and we don't
258        hold it afterwards.
259 
260        (What it really does used to be completely different in Python 2
261        and Python 3, with the Python 2 solution avoiding the spin-lock
262        around the Py_InitializeEx() call.  However, after recent changes
263        to CPython 2.7 (issue #358) it no longer works.  So we use the
264        Python 3 solution everywhere.)
265 
266        This initializes Python by calling Py_InitializeEx().
267        Important: this must not be called concurrently at all.
268        So we use a global variable as a simple spin lock.  This global
269        variable must be from 'libpythonX.Y.so', not from this
270        cffi-based extension module, because it must be shared from
271        different cffi-based extension modules.
272 
273        In Python < 3.8, we choose
274        _PyParser_TokenNames[0] as a completely arbitrary pointer value
275        that is never written to.  The default is to point to the
276        string "ENDMARKER".  We change it temporarily to point to the
277        next character in that string.  (Yes, I know it's REALLY
278        obscure.)
279 
280        In Python >= 3.8, this string array is no longer writable, so
281        instead we pick PyCapsuleType.tp_version_tag.  We can't change
282        Python < 3.8 because someone might use a mixture of cffi
283        embedded modules, some of which were compiled before this file
284        changed.
285     */
286 
287 #ifdef WITH_THREAD
288 # if PY_VERSION_HEX < 0x03080000
289     char *volatile *lock = (char *volatile *)_PyParser_TokenNames;
290     char *old_value, *locked_value;
291 
292     while (1) {    /* spin loop */
293         old_value = *lock;
294         locked_value = old_value + 1;
295         if (old_value[0] == 'E') {
296             assert(old_value[1] == 'N');
297             if (cffi_compare_and_swap(lock, old_value, locked_value))
298                 break;
299         }
300         else {
301             assert(old_value[0] == 'N');
302             /* should ideally do a spin loop instruction here, but
303                hard to do it portably and doesn't really matter I
304                think: PyEval_InitThreads() should be very fast, and
305                this is only run at start-up anyway. */
306         }
307     }
308 # else
309     int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag;
310     int old_value, locked_value;
311     assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG));
312 
313     while (1) {    /* spin loop */
314         old_value = *lock;
315         locked_value = -42;
316         if (old_value == 0) {
317             if (cffi_compare_and_swap(lock, old_value, locked_value))
318                 break;
319         }
320         else {
321             assert(old_value == locked_value);
322             /* should ideally do a spin loop instruction here, but
323                hard to do it portably and doesn't really matter I
324                think: PyEval_InitThreads() should be very fast, and
325                this is only run at start-up anyway. */
326         }
327     }
328 # endif
329 #endif
330 
331     /* call Py_InitializeEx() */
332     if (!Py_IsInitialized()) {
333         _cffi_py_initialize();
334 #if PY_VERSION_HEX < 0x03070000
335         PyEval_InitThreads();
336 #endif
337         PyEval_SaveThread();  /* release the GIL */
338         /* the returned tstate must be the one that has been stored into the
339            autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */
340     }
341     else {
342 #if PY_VERSION_HEX < 0x03070000
343         /* PyEval_InitThreads() is always a no-op from CPython 3.7 */
344         PyGILState_STATE state = PyGILState_Ensure();
345         PyEval_InitThreads();
346         PyGILState_Release(state);
347 #endif
348     }
349 
350 #ifdef WITH_THREAD
351     /* release the lock */
352     while (!cffi_compare_and_swap(lock, locked_value, old_value))
353         ;
354 #endif
355 
356     return 0;
357 }
358 
359 /**********  end CPython-specific section  **********/
360 
361 
362 #else
363 
364 
365 /**********  PyPy-specific section  **********/
366 
367 PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]);   /* forward */
368 
369 static struct _cffi_pypy_init_s {
370     const char *name;
371     void *func;    /* function pointer */
372     const char *code;
373 } _cffi_pypy_init = {
374     _CFFI_MODULE_NAME,
375     _CFFI_PYTHON_STARTUP_FUNC,
376     _CFFI_PYTHON_STARTUP_CODE,
377 };
378 
379 extern int pypy_carefully_make_gil(const char *);
380 extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *);
381 
_cffi_carefully_make_gil(void)382 static int _cffi_carefully_make_gil(void)
383 {
384     return pypy_carefully_make_gil(_CFFI_MODULE_NAME);
385 }
386 
_cffi_initialize_python(void)387 static int _cffi_initialize_python(void)
388 {
389     return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init);
390 }
391 
392 /**********  end PyPy-specific section  **********/
393 
394 
395 #endif
396 
397 
398 #ifdef __GNUC__
399 __attribute__((noinline))
400 #endif
_cffi_start_python(void)401 static _cffi_call_python_fnptr _cffi_start_python(void)
402 {
403     /* Delicate logic to initialize Python.  This function can be
404        called multiple times concurrently, e.g. when the process calls
405        its first ``extern "Python"`` functions in multiple threads at
406        once.  It can also be called recursively, in which case we must
407        ignore it.  We also have to consider what occurs if several
408        different cffi-based extensions reach this code in parallel
409        threads---it is a different copy of the code, then, and we
410        can't have any shared global variable unless it comes from
411        'libpythonX.Y.so'.
412 
413        Idea:
414 
415        * _cffi_carefully_make_gil(): "carefully" call
416          PyEval_InitThreads() (possibly with Py_InitializeEx() first).
417 
418        * then we use a (local) custom lock to make sure that a call to this
419          cffi-based extension will wait if another call to the *same*
420          extension is running the initialization in another thread.
421          It is reentrant, so that a recursive call will not block, but
422          only one from a different thread.
423 
424        * then we grab the GIL and (Python 2) we call Py_InitializeEx().
425          At this point, concurrent calls to Py_InitializeEx() are not
426          possible: we have the GIL.
427 
428        * do the rest of the specific initialization, which may
429          temporarily release the GIL but not the custom lock.
430          Only release the custom lock when we are done.
431     */
432     static char called = 0;
433 
434     if (_cffi_carefully_make_gil() != 0)
435         return NULL;
436 
437     _cffi_acquire_reentrant_mutex();
438 
439     /* Here the GIL exists, but we don't have it.  We're only protected
440        from concurrency by the reentrant mutex. */
441 
442     /* This file only initializes the embedded module once, the first
443        time this is called, even if there are subinterpreters. */
444     if (!called) {
445         called = 1;  /* invoke _cffi_initialize_python() only once,
446                         but don't set '_cffi_call_python' right now,
447                         otherwise concurrent threads won't call
448                         this function at all (we need them to wait) */
449         if (_cffi_initialize_python() == 0) {
450             /* now initialization is finished.  Switch to the fast-path. */
451 
452             /* We would like nobody to see the new value of
453                '_cffi_call_python' without also seeing the rest of the
454                data initialized.  However, this is not possible.  But
455                the new value of '_cffi_call_python' is the function
456                'cffi_call_python()' from _cffi_backend.  So:  */
457             cffi_write_barrier();
458             /* ^^^ we put a write barrier here, and a corresponding
459                read barrier at the start of cffi_call_python().  This
460                ensures that after that read barrier, we see everything
461                done here before the write barrier.
462             */
463 
464             assert(_cffi_call_python_org != NULL);
465             _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org;
466         }
467         else {
468             /* initialization failed.  Reset this to NULL, even if it was
469                already set to some other value.  Future calls to
470                _cffi_start_python() are still forced to occur, and will
471                always return NULL from now on. */
472             _cffi_call_python_org = NULL;
473         }
474     }
475 
476     _cffi_release_reentrant_mutex();
477 
478     return (_cffi_call_python_fnptr)_cffi_call_python_org;
479 }
480 
481 static
_cffi_start_and_call_python(struct _cffi_externpy_s * externpy,char * args)482 void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args)
483 {
484     _cffi_call_python_fnptr fnptr;
485     int current_err = errno;
486 #ifdef _MSC_VER
487     int current_lasterr = GetLastError();
488 #endif
489     fnptr = _cffi_start_python();
490     if (fnptr == NULL) {
491         fprintf(stderr, "function %s() called, but initialization code "
492                         "failed.  Returning 0.\n", externpy->name);
493         memset(args, 0, externpy->size_of_result);
494     }
495 #ifdef _MSC_VER
496     SetLastError(current_lasterr);
497 #endif
498     errno = current_err;
499 
500     if (fnptr != NULL)
501         fnptr(externpy, args);
502 }
503 
504 
505 /* The cffi_start_python() function makes sure Python is initialized
506    and our cffi module is set up.  It can be called manually from the
507    user C code.  The same effect is obtained automatically from any
508    dll-exported ``extern "Python"`` function.  This function returns
509    -1 if initialization failed, 0 if all is OK.  */
510 _CFFI_UNUSED_FN
cffi_start_python(void)511 static int cffi_start_python(void)
512 {
513     if (_cffi_call_python == &_cffi_start_and_call_python) {
514         if (_cffi_start_python() == NULL)
515             return -1;
516     }
517     cffi_read_barrier();
518     return 0;
519 }
520 
521 #undef cffi_compare_and_swap
522 #undef cffi_write_barrier
523 #undef cffi_read_barrier
524 
525 #ifdef __cplusplus
526 }
527 #endif
528