_embedding.h 17.2 KB
Newer Older
Armin Rigo's avatar
Armin Rigo committed
1
2
3

/***** Support code for embedding *****/

4
5
6
7
8
#ifdef __cplusplus
extern "C" {
#endif


Armin Rigo's avatar
Armin Rigo committed
9
#if defined(_WIN32)
Armin Rigo's avatar
Armin Rigo committed
10
11
#  define CFFI_DLLEXPORT  __declspec(dllexport)
#elif defined(__GNUC__)
Armin Rigo's avatar
tweaks    
Armin Rigo committed
12
#  define CFFI_DLLEXPORT  __attribute__((visibility("default")))
Armin Rigo's avatar
Armin Rigo committed
13
14
15
16
#else
#  define CFFI_DLLEXPORT  /* nothing */
#endif

Armin Rigo's avatar
Armin Rigo committed
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

/* There are two global variables of type _cffi_call_python_fnptr:

   * _cffi_call_python, which we declare just below, is the one called
     by ``extern "Python"`` implementations.

   * _cffi_call_python_org, which on CPython is actually part of the
     _cffi_exports[] array, is the function pointer copied from
     _cffi_backend.

   After initialization is complete, both are equal.  However, the
   first one remains equal to &_cffi_start_and_call_python until the
   very end of initialization, when we are (or should be) sure that
   concurrent threads also see a completely initialized world, and
   only then is it changed.
*/
#undef _cffi_call_python
typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *);
static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *);
static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python;


#ifndef _MSC_VER
   /* --- Assuming a GCC not infinitely old --- */
Armin Rigo's avatar
tweaks    
Armin Rigo committed
41
42
43
44
45
46
47
48
# define cffi_compare_and_swap(l,o,n)  __sync_bool_compare_and_swap(l,o,n)
# define cffi_write_barrier()          __sync_synchronize()
# if !defined(__amd64__) && !defined(__x86_64__) &&   \
     !defined(__i386__) && !defined(__i386)
#   define cffi_read_barrier()         __sync_synchronize()
# else
#   define cffi_read_barrier()         (void)0
# endif
Armin Rigo's avatar
Armin Rigo committed
49
50
#else
   /* --- Windows threads version --- */
Armin Rigo's avatar
Armin Rigo committed
51
# include <Windows.h>
Armin Rigo's avatar
Armin Rigo committed
52
53
# define cffi_compare_and_swap(l,o,n) \
                               (InterlockedCompareExchangePointer(l,n,o) == (o))
Armin Rigo's avatar
tweaks    
Armin Rigo committed
54
55
# define cffi_write_barrier()       InterlockedCompareExchange(&_cffi_dummy,0,0)
# define cffi_read_barrier()           (void)0
Armin Rigo's avatar
typo    
Armin Rigo committed
56
static volatile LONG _cffi_dummy;
Armin Rigo's avatar
Armin Rigo committed
57
58
#endif

59
60
61
62
63
64
65
66
#ifdef WITH_THREAD
# ifndef _MSC_VER
#  include <pthread.h>
   static pthread_mutex_t _cffi_embed_startup_lock;
# else
   static CRITICAL_SECTION _cffi_embed_startup_lock;
# endif
  static char _cffi_embed_startup_lock_ready = 0;
Armin Rigo's avatar
Armin Rigo committed
67
68
#endif

Armin Rigo's avatar
Armin Rigo committed
69
static void _cffi_acquire_reentrant_mutex(void)
Armin Rigo's avatar
Armin Rigo committed
70
{
Armin Rigo's avatar
Armin Rigo committed
71
    static void *volatile lock = NULL;
Armin Rigo's avatar
Armin Rigo committed
72

Armin Rigo's avatar
tweaks    
Armin Rigo committed
73
    while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) {
Armin Rigo's avatar
Armin Rigo committed
74
75
        /* should ideally do a spin loop instruction here, but
           hard to do it portably and doesn't really matter I
Armin Rigo's avatar
Armin Rigo committed
76
           think: pthread_mutex_init() should be very fast, and
Armin Rigo's avatar
Armin Rigo committed
77
78
79
           this is only run at start-up anyway. */
    }

Armin Rigo's avatar
Armin Rigo committed
80
81
82
83
84
85
86
87
88
89
90
91
92
#ifdef WITH_THREAD
    if (!_cffi_embed_startup_lock_ready) {
# ifndef _MSC_VER
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
        pthread_mutex_init(&_cffi_embed_startup_lock, &attr);
# else
        InitializeCriticalSection(&_cffi_embed_startup_lock);
# endif
        _cffi_embed_startup_lock_ready = 1;
    }
#endif
Armin Rigo's avatar
Armin Rigo committed
93

Armin Rigo's avatar
tweaks    
Armin Rigo committed
94
    while (!cffi_compare_and_swap(&lock, (void *)1, NULL))
Armin Rigo's avatar
Armin Rigo committed
95
        ;
Armin Rigo's avatar
Armin Rigo committed
96
97

#ifndef _MSC_VER
Armin Rigo's avatar
Armin Rigo committed
98
    pthread_mutex_lock(&_cffi_embed_startup_lock);
Armin Rigo's avatar
Armin Rigo committed
99
#else
Armin Rigo's avatar
Armin Rigo committed
100
    EnterCriticalSection(&_cffi_embed_startup_lock);
Armin Rigo's avatar
Armin Rigo committed
101
#endif
Armin Rigo's avatar
Armin Rigo committed
102
}
Armin Rigo's avatar
Armin Rigo committed
103

Armin Rigo's avatar
Armin Rigo committed
104
105
106
107
108
109
110
111
static void _cffi_release_reentrant_mutex(void)
{
#ifndef _MSC_VER
    pthread_mutex_unlock(&_cffi_embed_startup_lock);
#else
    LeaveCriticalSection(&_cffi_embed_startup_lock);
#endif
}
112

Armin Rigo's avatar
Armin Rigo committed
113

Armin Rigo's avatar
Armin Rigo committed
114
115
116
/**********  CPython-specific section  **********/
#ifndef PYPY_VERSION

Armin Rigo's avatar
Armin Rigo committed
117
#include "_cffi_errors.h"
118
119


120
#define _cffi_call_python_org  _cffi_exports[_CFFI_CPIDX]
Armin Rigo's avatar
Armin Rigo committed
121
122

PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void);   /* forward */
Armin Rigo's avatar
Armin Rigo committed
123

124
125
126
127
128
129
130
131
132
static void _cffi_py_initialize(void)
{
    /* XXX use initsigs=0, which "skips initialization registration of
       signal handlers, which might be useful when Python is
       embedded" according to the Python docs.  But review and think
       if it should be a user-controllable setting.

       XXX we should also give a way to write errors to a buffer
       instead of to stderr.
Armin Rigo's avatar
Bah    
Armin Rigo committed
133
134
135

       XXX if importing 'site' fails, CPython (any version) calls
       exit().  Should we try to work around this behavior here?
136
137
138
139
    */
    Py_InitializeEx(0);
}

140
static int _cffi_initialize_python(void)
Armin Rigo's avatar
Armin Rigo committed
141
{
142
143
    /* This initializes Python, imports _cffi_backend, and then the
       present .dll/.so is set up as a CPython C extension module.
144
    */
Armin Rigo's avatar
Armin Rigo committed
145
    int result;
146
    PyGILState_STATE state;
147
    PyObject *pycode=NULL, *global_dict=NULL, *x;
Armin Rigo's avatar
Armin Rigo committed
148
    PyObject *builtins;
149

150
151
    state = PyGILState_Ensure();

152
    /* Call the initxxx() function from the present module.  It will
153
154
155
156
157
158
       create and initialize us as a CPython extension module, instead
       of letting the startup Python code do it---it might reimport
       the same .dll/.so and get maybe confused on some platforms.
       It might also have troubles locating the .dll/.so again for all
       I know.
    */
Armin Rigo's avatar
Armin Rigo committed
159
160
161
162
    (void)_CFFI_PYTHON_STARTUP_FUNC();
    if (PyErr_Occurred())
        goto error;

163
164
    /* Now run the Python code provided to ffi.embedding_init_code().
     */
Armin Rigo's avatar
Armin Rigo committed
165
166
167
168
169
    pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE,
                              "<init code for '" _CFFI_MODULE_NAME "'>",
                              Py_file_input);
    if (pycode == NULL)
        goto error;
170
171
172
    global_dict = PyDict_New();
    if (global_dict == NULL)
        goto error;
Armin Rigo's avatar
Armin Rigo committed
173
    builtins = PyEval_GetBuiltins();
Armin Rigo's avatar
Armin Rigo committed
174
175
176
    if (builtins == NULL)
        goto error;
    if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0)
Armin Rigo's avatar
Armin Rigo committed
177
        goto error;
178
179
180
181
182
    x = PyEval_EvalCode(
#if PY_MAJOR_VERSION < 3
                        (PyCodeObject *)
#endif
                        pycode, global_dict, global_dict);
Armin Rigo's avatar
Armin Rigo committed
183
184
185
    if (x == NULL)
        goto error;
    Py_DECREF(x);
Armin Rigo's avatar
Armin Rigo committed
186

187
188
    /* Done!  Now if we've been called from
       _cffi_start_and_call_python() in an ``extern "Python"``, we can
Armin Rigo's avatar
Armin Rigo committed
189
190
191
192
193
       only hope that the Python code did correctly set up the
       corresponding @ffi.def_extern() function.  Otherwise, the
       general logic of ``extern "Python"`` functions (inside the
       _cffi_backend module) will find that the reference is still
       missing and print an error.
194
     */
Armin Rigo's avatar
Armin Rigo committed
195
196
197
    result = 0;
 done:
    Py_XDECREF(pycode);
198
    Py_XDECREF(global_dict);
199
    PyGILState_Release(state);
Armin Rigo's avatar
Armin Rigo committed
200
    return result;
Armin Rigo's avatar
Armin Rigo committed
201
202
203
204
205
206

 error:;
    {
        /* Print as much information as potentially useful.
           Debugging load-time failures with embedding is not fun
        */
207
        PyObject *ecap;
Armin Rigo's avatar
Armin Rigo committed
208
209
        PyObject *exception, *v, *tb, *f, *modules, *mod;
        PyErr_Fetch(&exception, &v, &tb);
210
211
212
213
214
215
216
        ecap = _cffi_start_error_capture();
        f = PySys_GetObject((char *)"stderr");
        if (f != NULL && f != Py_None) {
            PyFile_WriteString(
                "Failed to initialize the Python-CFFI embedding logic:\n\n", f);
        }

Armin Rigo's avatar
Armin Rigo committed
217
218
219
220
221
222
223
224
225
        if (exception != NULL) {
            PyErr_NormalizeException(&exception, &v, &tb);
            PyErr_Display(exception, v, tb);
        }
        Py_XDECREF(exception);
        Py_XDECREF(v);
        Py_XDECREF(tb);

        if (f != NULL && f != Py_None) {
Armin Rigo's avatar
Armin Rigo committed
226
            PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
Matt Davis's avatar
Matt Davis committed
227
                               "\ncompiled with cffi version: 1.15.0rc2"
Armin Rigo's avatar
Armin Rigo committed
228
                               "\n_cffi_backend module: ", f);
Armin Rigo's avatar
Armin Rigo committed
229
230
231
232
233
234
235
236
237
238
239
            modules = PyImport_GetModuleDict();
            mod = PyDict_GetItemString(modules, "_cffi_backend");
            if (mod == NULL) {
                PyFile_WriteString("not loaded", f);
            }
            else {
                v = PyObject_GetAttrString(mod, "__file__");
                PyFile_WriteObject(v, f, 0);
                Py_XDECREF(v);
            }
            PyFile_WriteString("\nsys.path: ", f);
Armin Rigo's avatar
Armin Rigo committed
240
            PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0);
Armin Rigo's avatar
Armin Rigo committed
241
242
            PyFile_WriteString("\n\n", f);
        }
243
        _cffi_stop_error_capture(ecap);
Armin Rigo's avatar
Armin Rigo committed
244
    }
Armin Rigo's avatar
Armin Rigo committed
245
246
    result = -1;
    goto done;
Armin Rigo's avatar
Armin Rigo committed
247
248
}

Armin Rigo's avatar
Armin Rigo committed
249
#if PY_VERSION_HEX < 0x03080000
Armin Rigo's avatar
Armin Rigo committed
250
PyAPI_DATA(char *) _PyParser_TokenNames[];  /* from CPython */
Armin Rigo's avatar
Armin Rigo committed
251
#endif
Armin Rigo's avatar
Armin Rigo committed
252

Armin Rigo's avatar
Armin Rigo committed
253
static int _cffi_carefully_make_gil(void)
254
{
255
256
257
258
259
    /* This does the basic initialization of Python.  It can be called
       completely concurrently from unrelated threads.  It assumes
       that we don't hold the GIL before (if it exists), and we don't
       hold it afterwards.

Armin Rigo's avatar
Armin Rigo committed
260
261
262
263
264
       (What it really does used to be completely different in Python 2
       and Python 3, with the Python 2 solution avoiding the spin-lock
       around the Py_InitializeEx() call.  However, after recent changes
       to CPython 2.7 (issue #358) it no longer works.  So we use the
       Python 3 solution everywhere.)
265

Armin Rigo's avatar
Armin Rigo committed
266
267
       This initializes Python by calling Py_InitializeEx().
       Important: this must not be called concurrently at all.
268
269
270
       So we use a global variable as a simple spin lock.  This global
       variable must be from 'libpythonX.Y.so', not from this
       cffi-based extension module, because it must be shared from
Armin Rigo's avatar
Armin Rigo committed
271
272
273
       different cffi-based extension modules.

       In Python < 3.8, we choose
Armin Rigo's avatar
Armin Rigo committed
274
275
276
277
       _PyParser_TokenNames[0] as a completely arbitrary pointer value
       that is never written to.  The default is to point to the
       string "ENDMARKER".  We change it temporarily to point to the
       next character in that string.  (Yes, I know it's REALLY
278
       obscure.)
Armin Rigo's avatar
Armin Rigo committed
279
280
281
282
283
284

       In Python >= 3.8, this string array is no longer writable, so
       instead we pick PyCapsuleType.tp_version_tag.  We can't change
       Python < 3.8 because someone might use a mixture of cffi
       embedded modules, some of which were compiled before this file
       changed.
285
    */
286

Armin Rigo's avatar
Armin Rigo committed
287
#ifdef WITH_THREAD
Armin Rigo's avatar
Armin Rigo committed
288
# if PY_VERSION_HEX < 0x03080000
Armin Rigo's avatar
Armin Rigo committed
289
    char *volatile *lock = (char *volatile *)_PyParser_TokenNames;
Armin Rigo's avatar
Armin Rigo committed
290
    char *old_value, *locked_value;
291

292
    while (1) {    /* spin loop */
Armin Rigo's avatar
Armin Rigo committed
293
        old_value = *lock;
Armin Rigo's avatar
Armin Rigo committed
294
        locked_value = old_value + 1;
Armin Rigo's avatar
Armin Rigo committed
295
296
        if (old_value[0] == 'E') {
            assert(old_value[1] == 'N');
Armin Rigo's avatar
Armin Rigo committed
297
            if (cffi_compare_and_swap(lock, old_value, locked_value))
298
299
300
                break;
        }
        else {
Armin Rigo's avatar
Armin Rigo committed
301
            assert(old_value[0] == 'N');
302
303
304
305
306
307
            /* should ideally do a spin loop instruction here, but
               hard to do it portably and doesn't really matter I
               think: PyEval_InitThreads() should be very fast, and
               this is only run at start-up anyway. */
        }
    }
Armin Rigo's avatar
Armin Rigo committed
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# else
    int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag;
    int old_value, locked_value;
    assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG));

    while (1) {    /* spin loop */
        old_value = *lock;
        locked_value = -42;
        if (old_value == 0) {
            if (cffi_compare_and_swap(lock, old_value, locked_value))
                break;
        }
        else {
            assert(old_value == locked_value);
            /* should ideally do a spin loop instruction here, but
               hard to do it portably and doesn't really matter I
               think: PyEval_InitThreads() should be very fast, and
               this is only run at start-up anyway. */
        }
    }
# endif
329
#endif
330

Armin Rigo's avatar
Armin Rigo committed
331
    /* call Py_InitializeEx() */
Armin Rigo's avatar
Armin Rigo committed
332
333
    if (!Py_IsInitialized()) {
        _cffi_py_initialize();
334
#if PY_VERSION_HEX < 0x03070000
Armin Rigo's avatar
Armin Rigo committed
335
        PyEval_InitThreads();
336
#endif
Armin Rigo's avatar
Armin Rigo committed
337
338
339
340
341
        PyEval_SaveThread();  /* release the GIL */
        /* the returned tstate must be the one that has been stored into the
           autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */
    }
    else {
342
343
#if PY_VERSION_HEX < 0x03070000
        /* PyEval_InitThreads() is always a no-op from CPython 3.7 */
Armin Rigo's avatar
Armin Rigo committed
344
        PyGILState_STATE state = PyGILState_Ensure();
345
346
        PyEval_InitThreads();
        PyGILState_Release(state);
347
#endif
348
    }
349

350
#ifdef WITH_THREAD
351
    /* release the lock */
Armin Rigo's avatar
Armin Rigo committed
352
    while (!cffi_compare_and_swap(lock, locked_value, old_value))
353
        ;
Armin Rigo's avatar
Armin Rigo committed
354
#endif
355

Armin Rigo's avatar
Armin Rigo committed
356
    return 0;
357
}
358

Armin Rigo's avatar
Armin Rigo committed
359
360
/**********  end CPython-specific section  **********/

Armin Rigo's avatar
Armin Rigo committed
361

Armin Rigo's avatar
Armin Rigo committed
362
363
#else

Armin Rigo's avatar
Armin Rigo committed
364

Armin Rigo's avatar
Armin Rigo committed
365
366
/**********  PyPy-specific section  **********/

Armin Rigo's avatar
Armin Rigo committed
367
PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]);   /* forward */
Armin Rigo's avatar
Armin Rigo committed
368

Armin Rigo's avatar
Armin Rigo committed
369
370
static struct _cffi_pypy_init_s {
    const char *name;
371
    void *func;    /* function pointer */
Armin Rigo's avatar
Armin Rigo committed
372
373
374
    const char *code;
} _cffi_pypy_init = {
    _CFFI_MODULE_NAME,
375
    _CFFI_PYTHON_STARTUP_FUNC,
Armin Rigo's avatar
Armin Rigo committed
376
377
378
    _CFFI_PYTHON_STARTUP_CODE,
};

Armin Rigo's avatar
Armin Rigo committed
379
extern int pypy_carefully_make_gil(const char *);
Armin Rigo's avatar
Armin Rigo committed
380
381
extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *);

Armin Rigo's avatar
Armin Rigo committed
382
static int _cffi_carefully_make_gil(void)
Armin Rigo's avatar
Armin Rigo committed
383
{
Armin Rigo's avatar
Armin Rigo committed
384
    return pypy_carefully_make_gil(_CFFI_MODULE_NAME);
Armin Rigo's avatar
Armin Rigo committed
385
}
Armin Rigo's avatar
Armin Rigo committed
386
387
388

static int _cffi_initialize_python(void)
{
Armin Rigo's avatar
Armin Rigo committed
389
    return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init);
Armin Rigo's avatar
Armin Rigo committed
390
391
392
393
}

/**********  end PyPy-specific section  **********/

Armin Rigo's avatar
Armin Rigo committed
394

395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
#endif


#ifdef __GNUC__
__attribute__((noinline))
#endif
static _cffi_call_python_fnptr _cffi_start_python(void)
{
    /* Delicate logic to initialize Python.  This function can be
       called multiple times concurrently, e.g. when the process calls
       its first ``extern "Python"`` functions in multiple threads at
       once.  It can also be called recursively, in which case we must
       ignore it.  We also have to consider what occurs if several
       different cffi-based extensions reach this code in parallel
       threads---it is a different copy of the code, then, and we
       can't have any shared global variable unless it comes from
       'libpythonX.Y.so'.

       Idea:

       * _cffi_carefully_make_gil(): "carefully" call
416
         PyEval_InitThreads() (possibly with Py_InitializeEx() first).
417

418
419
       * then we use a (local) custom lock to make sure that a call to this
         cffi-based extension will wait if another call to the *same*
420
421
422
423
         extension is running the initialization in another thread.
         It is reentrant, so that a recursive call will not block, but
         only one from a different thread.

424
425
426
       * then we grab the GIL and (Python 2) we call Py_InitializeEx().
         At this point, concurrent calls to Py_InitializeEx() are not
         possible: we have the GIL.
427
428
429
430
431
432
433

       * do the rest of the specific initialization, which may
         temporarily release the GIL but not the custom lock.
         Only release the custom lock when we are done.
    */
    static char called = 0;

Armin Rigo's avatar
Armin Rigo committed
434
435
436
    if (_cffi_carefully_make_gil() != 0)
        return NULL;

Armin Rigo's avatar
Armin Rigo committed
437
    _cffi_acquire_reentrant_mutex();
438

Armin Rigo's avatar
Armin Rigo committed
439
440
    /* Here the GIL exists, but we don't have it.  We're only protected
       from concurrency by the reentrant mutex. */
Armin Rigo's avatar
Armin Rigo committed
441

Armin Rigo's avatar
Armin Rigo committed
442
443
    /* This file only initializes the embedded module once, the first
       time this is called, even if there are subinterpreters. */
444
445
    if (!called) {
        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. */
Armin Rigo's avatar
Armin Rigo committed
451
452
453
454
455

            /* We would like nobody to see the new value of
               '_cffi_call_python' without also seeing the rest of the
               data initialized.  However, this is not possible.  But
               the new value of '_cffi_call_python' is the function
Armin Rigo's avatar
Armin Rigo committed
456
               'cffi_call_python()' from _cffi_backend.  So:  */
Armin Rigo's avatar
tweaks    
Armin Rigo committed
457
            cffi_write_barrier();
Armin Rigo's avatar
Armin Rigo committed
458
459
460
461
462
            /* ^^^ we put a write barrier here, and a corresponding
               read barrier at the start of cffi_call_python().  This
               ensures that after that read barrier, we see everything
               done here before the write barrier.
            */
Armin Rigo's avatar
Armin Rigo committed
463

Armin Rigo's avatar
Armin Rigo committed
464
            assert(_cffi_call_python_org != NULL);
465
466
467
468
469
470
471
472
            _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org;
        }
        else {
            /* initialization failed.  Reset this to NULL, even if it was
               already set to some other value.  Future calls to
               _cffi_start_python() are still forced to occur, and will
               always return NULL from now on. */
            _cffi_call_python_org = NULL;
473
        }
474
475
    }

Armin Rigo's avatar
Armin Rigo committed
476
    _cffi_release_reentrant_mutex();
477

478
    return (_cffi_call_python_fnptr)_cffi_call_python_org;
479
480
}

481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
static
void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args)
{
    _cffi_call_python_fnptr fnptr;
    int current_err = errno;
#ifdef _MSC_VER
    int current_lasterr = GetLastError();
#endif
    fnptr = _cffi_start_python();
    if (fnptr == NULL) {
        fprintf(stderr, "function %s() called, but initialization code "
                        "failed.  Returning 0.\n", externpy->name);
        memset(args, 0, externpy->size_of_result);
    }
#ifdef _MSC_VER
    SetLastError(current_lasterr);
#endif
    errno = current_err;

    if (fnptr != NULL)
        fnptr(externpy, args);
}


/* The cffi_start_python() function makes sure Python is initialized
   and our cffi module is set up.  It can be called manually from the
   user C code.  The same effect is obtained automatically from any
   dll-exported ``extern "Python"`` function.  This function returns
   -1 if initialization failed, 0 if all is OK.  */
_CFFI_UNUSED_FN
static int cffi_start_python(void)
{
    if (_cffi_call_python == &_cffi_start_and_call_python) {
        if (_cffi_start_python() == NULL)
            return -1;
    }
Armin Rigo's avatar
tweaks    
Armin Rigo committed
517
    cffi_read_barrier();
518
519
    return 0;
}
Armin Rigo's avatar
tweaks    
Armin Rigo committed
520
521
522
523

#undef cffi_compare_and_swap
#undef cffi_write_barrier
#undef cffi_read_barrier
524
525
526
527

#ifdef __cplusplus
}
#endif