|
|
|
|
|
|
|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
|
|
|
|
#if defined(_WIN32) |
|
# define CFFI_DLLEXPORT __declspec(dllexport) |
|
#elif defined(__GNUC__) |
|
# define CFFI_DLLEXPORT __attribute__((visibility("default"))) |
|
#else |
|
# define CFFI_DLLEXPORT |
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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 |
|
|
|
# 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 |
|
#else |
|
|
|
# include <Windows.h> |
|
# define cffi_compare_and_swap(l,o,n) \ |
|
(InterlockedCompareExchangePointer(l,n,o) == (o)) |
|
# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0) |
|
# define cffi_read_barrier() (void)0 |
|
static volatile LONG _cffi_dummy; |
|
#endif |
|
|
|
#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; |
|
#endif |
|
|
|
static void _cffi_acquire_reentrant_mutex(void) |
|
{ |
|
static void *volatile lock = NULL; |
|
|
|
while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
#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 |
|
|
|
while (!cffi_compare_and_swap(&lock, (void *)1, NULL)) |
|
; |
|
|
|
#ifndef _MSC_VER |
|
pthread_mutex_lock(&_cffi_embed_startup_lock); |
|
#else |
|
EnterCriticalSection(&_cffi_embed_startup_lock); |
|
#endif |
|
} |
|
|
|
static void _cffi_release_reentrant_mutex(void) |
|
{ |
|
#ifndef _MSC_VER |
|
pthread_mutex_unlock(&_cffi_embed_startup_lock); |
|
#else |
|
LeaveCriticalSection(&_cffi_embed_startup_lock); |
|
#endif |
|
} |
|
|
|
|
|
|
|
#ifndef PYPY_VERSION |
|
|
|
#include "_cffi_errors.h" |
|
|
|
|
|
#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] |
|
|
|
PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); |
|
|
|
static void _cffi_py_initialize(void) |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Py_InitializeEx(0); |
|
} |
|
|
|
static int _cffi_initialize_python(void) |
|
{ |
|
|
|
|
|
|
|
int result; |
|
PyGILState_STATE state; |
|
PyObject *pycode=NULL, *global_dict=NULL, *x; |
|
PyObject *builtins; |
|
|
|
state = PyGILState_Ensure(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(void)_CFFI_PYTHON_STARTUP_FUNC(); |
|
if (PyErr_Occurred()) |
|
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 = PyDict_New(); |
|
if (global_dict == NULL) |
|
goto error; |
|
builtins = PyEval_GetBuiltins(); |
|
if (builtins == NULL) |
|
goto error; |
|
if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0) |
|
goto error; |
|
x = PyEval_EvalCode( |
|
#if PY_MAJOR_VERSION < 3 |
|
(PyCodeObject *) |
|
#endif |
|
pycode, global_dict, global_dict); |
|
if (x == NULL) |
|
goto error; |
|
Py_DECREF(x); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = 0; |
|
done: |
|
Py_XDECREF(pycode); |
|
Py_XDECREF(global_dict); |
|
PyGILState_Release(state); |
|
return result; |
|
|
|
error:; |
|
{ |
|
|
|
|
|
|
|
PyObject *ecap; |
|
PyObject *exception, *v, *tb, *f, *modules, *mod; |
|
PyErr_Fetch(&exception, &v, &tb); |
|
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); |
|
} |
|
|
|
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) { |
|
PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME |
|
"\ncompiled with cffi version: 1.16.0" |
|
"\n_cffi_backend module: ", f); |
|
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); |
|
PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); |
|
PyFile_WriteString("\n\n", f); |
|
} |
|
_cffi_stop_error_capture(ecap); |
|
} |
|
result = -1; |
|
goto done; |
|
} |
|
|
|
#if PY_VERSION_HEX < 0x03080000 |
|
PyAPI_DATA(char *) _PyParser_TokenNames[]; |
|
#endif |
|
|
|
static int _cffi_carefully_make_gil(void) |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_THREAD |
|
# if PY_VERSION_HEX < 0x03080000 |
|
char *volatile *lock = (char *volatile *)_PyParser_TokenNames; |
|
char *old_value, *locked_value; |
|
|
|
while (1) { |
|
old_value = *lock; |
|
locked_value = old_value + 1; |
|
if (old_value[0] == 'E') { |
|
assert(old_value[1] == 'N'); |
|
if (cffi_compare_and_swap(lock, old_value, locked_value)) |
|
break; |
|
} |
|
else { |
|
assert(old_value[0] == 'N'); |
|
|
|
|
|
|
|
|
|
} |
|
} |
|
# else |
|
# if PY_VERSION_HEX < 0x030C0000 |
|
int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; |
|
int old_value, locked_value = -42; |
|
assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); |
|
# else |
|
static struct ebp_s { PyBufferProcs buf; int mark; } empty_buffer_procs; |
|
empty_buffer_procs.mark = -42; |
|
PyBufferProcs *volatile *lock = (PyBufferProcs *volatile *) |
|
&PyCapsule_Type.tp_as_buffer; |
|
PyBufferProcs *old_value, *locked_value = &empty_buffer_procs.buf; |
|
# endif |
|
|
|
while (1) { |
|
old_value = *lock; |
|
if (old_value == 0) { |
|
if (cffi_compare_and_swap(lock, old_value, locked_value)) |
|
break; |
|
} |
|
else { |
|
# if PY_VERSION_HEX < 0x030C0000 |
|
assert(old_value == locked_value); |
|
# else |
|
|
|
|
|
assert(((struct ebp_s *)old_value)->mark == -42); |
|
# endif |
|
|
|
|
|
|
|
|
|
} |
|
} |
|
# endif |
|
#endif |
|
|
|
|
|
if (!Py_IsInitialized()) { |
|
_cffi_py_initialize(); |
|
#if PY_VERSION_HEX < 0x03070000 |
|
PyEval_InitThreads(); |
|
#endif |
|
PyEval_SaveThread(); |
|
|
|
|
|
} |
|
else { |
|
#if PY_VERSION_HEX < 0x03070000 |
|
|
|
PyGILState_STATE state = PyGILState_Ensure(); |
|
PyEval_InitThreads(); |
|
PyGILState_Release(state); |
|
#endif |
|
} |
|
|
|
#ifdef WITH_THREAD |
|
|
|
while (!cffi_compare_and_swap(lock, locked_value, old_value)) |
|
; |
|
#endif |
|
|
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
|
|
PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); |
|
|
|
static struct _cffi_pypy_init_s { |
|
const char *name; |
|
void *func; |
|
const char *code; |
|
} _cffi_pypy_init = { |
|
_CFFI_MODULE_NAME, |
|
_CFFI_PYTHON_STARTUP_FUNC, |
|
_CFFI_PYTHON_STARTUP_CODE, |
|
}; |
|
|
|
extern int pypy_carefully_make_gil(const char *); |
|
extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); |
|
|
|
static int _cffi_carefully_make_gil(void) |
|
{ |
|
return pypy_carefully_make_gil(_CFFI_MODULE_NAME); |
|
} |
|
|
|
static int _cffi_initialize_python(void) |
|
{ |
|
return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); |
|
} |
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
#ifdef __GNUC__ |
|
__attribute__((noinline)) |
|
#endif |
|
static _cffi_call_python_fnptr _cffi_start_python(void) |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char called = 0; |
|
|
|
if (_cffi_carefully_make_gil() != 0) |
|
return NULL; |
|
|
|
_cffi_acquire_reentrant_mutex(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!called) { |
|
called = 1; |
|
|
|
|
|
|
|
if (_cffi_initialize_python() == 0) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cffi_write_barrier(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
assert(_cffi_call_python_org != NULL); |
|
_cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org; |
|
} |
|
else { |
|
|
|
|
|
|
|
|
|
_cffi_call_python_org = NULL; |
|
} |
|
} |
|
|
|
_cffi_release_reentrant_mutex(); |
|
|
|
return (_cffi_call_python_fnptr)_cffi_call_python_org; |
|
} |
|
|
|
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); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_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; |
|
} |
|
cffi_read_barrier(); |
|
return 0; |
|
} |
|
|
|
#undef cffi_compare_and_swap |
|
#undef cffi_write_barrier |
|
#undef cffi_read_barrier |
|
|
|
#ifdef __cplusplus |
|
} |
|
#endif |
|
|