_embedding.h 18 KB

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