• 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 
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