1 #if PY_VERSION_HEX >= 0x03080000
2 # define Py_BUILD_CORE
3 /* for access to the fields of PyInterpreterState */
4 # include "internal/pycore_pystate.h"
5 # undef Py_BUILD_CORE
6 #endif
7
_get_interpstate_dict(void)8 static PyObject *_get_interpstate_dict(void)
9 {
10 /* Hack around to return a dict that is subinterpreter-local.
11 Does not return a new reference. Returns NULL in case of
12 error, but without setting any exception. (If called late
13 during shutdown, we *can't* set an exception!)
14 */
15 static PyObject *attr_name = NULL;
16 PyThreadState *tstate;
17 PyObject *d, *builtins;
18 int err;
19
20 tstate = PyThreadState_GET();
21 if (tstate == NULL) {
22 /* no thread state! */
23 return NULL;
24 }
25
26 builtins = tstate->interp->builtins;
27 if (builtins == NULL) {
28 /* subinterpreter was cleared already, or is being cleared right now,
29 to a point that is too much for us to continue */
30 return NULL;
31 }
32
33 /* from there on, we know the (sub-)interpreter is still valid */
34
35 if (attr_name == NULL) {
36 attr_name = PyText_InternFromString("__cffi_backend_extern_py");
37 if (attr_name == NULL)
38 goto error;
39 }
40
41 d = PyDict_GetItem(builtins, attr_name);
42 if (d == NULL) {
43 d = PyDict_New();
44 if (d == NULL)
45 goto error;
46 err = PyDict_SetItem(builtins, attr_name, d);
47 Py_DECREF(d); /* if successful, there is one ref left in builtins */
48 if (err < 0)
49 goto error;
50 }
51 return d;
52
53 error:
54 PyErr_Clear(); /* typically a MemoryError */
55 return NULL;
56 }
57
_ffi_def_extern_decorator(PyObject * outer_args,PyObject * fn)58 static PyObject *_ffi_def_extern_decorator(PyObject *outer_args, PyObject *fn)
59 {
60 const char *s;
61 PyObject *error, *onerror, *infotuple, *old1;
62 int index, err;
63 const struct _cffi_global_s *g;
64 struct _cffi_externpy_s *externpy;
65 CTypeDescrObject *ct;
66 FFIObject *ffi;
67 builder_c_t *types_builder;
68 PyObject *name = NULL;
69 PyObject *interpstate_dict;
70 PyObject *interpstate_key;
71
72 if (!PyArg_ParseTuple(outer_args, "OzOO", &ffi, &s, &error, &onerror))
73 return NULL;
74
75 if (s == NULL) {
76 name = PyObject_GetAttrString(fn, "__name__");
77 if (name == NULL)
78 return NULL;
79 s = PyText_AsUTF8(name);
80 if (s == NULL) {
81 Py_DECREF(name);
82 return NULL;
83 }
84 }
85
86 types_builder = &ffi->types_builder;
87 index = search_in_globals(&types_builder->ctx, s, strlen(s));
88 if (index < 0)
89 goto not_found;
90 g = &types_builder->ctx.globals[index];
91 if (_CFFI_GETOP(g->type_op) != _CFFI_OP_EXTERN_PYTHON)
92 goto not_found;
93 Py_XDECREF(name);
94
95 ct = realize_c_type(types_builder, types_builder->ctx.types,
96 _CFFI_GETARG(g->type_op));
97 if (ct == NULL)
98 return NULL;
99
100 infotuple = prepare_callback_info_tuple(ct, fn, error, onerror, 0);
101 Py_DECREF(ct);
102 if (infotuple == NULL)
103 return NULL;
104
105 /* don't directly attach infotuple to externpy: in the presence of
106 subinterpreters, each time we switch to a different
107 subinterpreter and call the C function, it will notice the
108 change and look up infotuple from the interpstate_dict.
109 */
110 interpstate_dict = _get_interpstate_dict();
111 if (interpstate_dict == NULL) {
112 Py_DECREF(infotuple);
113 return PyErr_NoMemory();
114 }
115
116 externpy = (struct _cffi_externpy_s *)g->address;
117 interpstate_key = PyLong_FromVoidPtr((void *)externpy);
118 if (interpstate_key == NULL) {
119 Py_DECREF(infotuple);
120 return NULL;
121 }
122
123 err = PyDict_SetItem(interpstate_dict, interpstate_key, infotuple);
124 Py_DECREF(interpstate_key);
125 Py_DECREF(infotuple); /* interpstate_dict owns the last ref */
126 if (err < 0)
127 return NULL;
128
129 /* force _update_cache_to_call_python() to be called the next time
130 the C function invokes cffi_call_python, to update the cache */
131 old1 = externpy->reserved1;
132 externpy->reserved1 = Py_None; /* a non-NULL value */
133 Py_INCREF(Py_None);
134 Py_XDECREF(old1);
135
136 /* return the function object unmodified */
137 Py_INCREF(fn);
138 return fn;
139
140 not_found:
141 PyErr_Format(FFIError, "ffi.def_extern('%s'): no 'extern \"Python\"' "
142 "function with this name", s);
143 Py_XDECREF(name);
144 return NULL;
145 }
146
147
_update_cache_to_call_python(struct _cffi_externpy_s * externpy)148 static int _update_cache_to_call_python(struct _cffi_externpy_s *externpy)
149 {
150 PyObject *interpstate_dict, *interpstate_key, *infotuple, *old1, *new1;
151 PyObject *old2;
152
153 interpstate_dict = _get_interpstate_dict();
154 if (interpstate_dict == NULL)
155 return 4; /* oops, shutdown issue? */
156
157 interpstate_key = PyLong_FromVoidPtr((void *)externpy);
158 if (interpstate_key == NULL)
159 goto error;
160
161 infotuple = PyDict_GetItem(interpstate_dict, interpstate_key);
162 Py_DECREF(interpstate_key);
163 if (infotuple == NULL)
164 return 3; /* no ffi.def_extern() from this subinterpreter */
165
166 new1 = PyThreadState_GET()->interp->modules;
167 Py_INCREF(new1);
168 Py_INCREF(infotuple);
169 old1 = (PyObject *)externpy->reserved1;
170 old2 = (PyObject *)externpy->reserved2;
171 externpy->reserved1 = new1; /* holds a reference */
172 externpy->reserved2 = infotuple; /* holds a reference (issue #246) */
173 Py_XDECREF(old1);
174 Py_XDECREF(old2);
175
176 return 0; /* no error */
177
178 error:
179 PyErr_Clear();
180 return 2; /* out of memory? */
181 }
182
183 #if (defined(WITH_THREAD) && !defined(_MSC_VER) && \
184 !defined(__amd64__) && !defined(__x86_64__) && \
185 !defined(__i386__) && !defined(__i386))
186 # if defined(HAVE_SYNC_SYNCHRONIZE)
187 # define read_barrier() __sync_synchronize()
188 # elif defined(_AIX)
189 # define read_barrier() __lwsync()
190 # elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
191 # include <mbarrier.h>
192 # define read_barrier() __compiler_barrier()
193 # elif defined(__hpux)
194 # define read_barrier() _Asm_mf()
195 # else
196 # define read_barrier() /* missing */
197 # warning "no definition for read_barrier(), missing synchronization for\
198 multi-thread initialization in embedded mode"
199 # endif
200 #else
201 # define read_barrier() (void)0
202 #endif
203
cffi_call_python(struct _cffi_externpy_s * externpy,char * args)204 static void cffi_call_python(struct _cffi_externpy_s *externpy, char *args)
205 {
206 /* Invoked by the helpers generated from extern "Python" in the cdef.
207
208 'externpy' is a static structure that describes which of the
209 extern "Python" functions is called. It has got fields 'name' and
210 'type_index' describing the function, and more reserved fields
211 that are initially zero. These reserved fields are set up by
212 ffi.def_extern(), which invokes _ffi_def_extern_decorator() above.
213
214 'args' is a pointer to an array of 8-byte entries. Each entry
215 contains an argument. If an argument is less than 8 bytes, only
216 the part at the beginning of the entry is initialized. If an
217 argument is 'long double' or a struct/union, then it is passed
218 by reference.
219
220 'args' is also used as the place to write the result to
221 (directly, even if more than 8 bytes). In all cases, 'args' is
222 at least 8 bytes in size.
223 */
224 int err = 0;
225
226 /* This read barrier is needed for _embedding.h. It is paired
227 with the write_barrier() there. Without this barrier, we can
228 in theory see the following situation: the Python
229 initialization code already ran (in another thread), and the
230 '_cffi_call_python' function pointer directed execution here;
231 but any number of other data could still be seen as
232 uninitialized below. For example, 'externpy' would still
233 contain NULLs even though it was correctly set up, or
234 'interpreter_lock' (the GIL inside CPython) would still be seen
235 as NULL, or 'autoInterpreterState' (used by
236 PyGILState_Ensure()) would be NULL or contain bogus fields.
237 */
238 read_barrier();
239
240 save_errno();
241
242 /* We need the infotuple here. We could always go through
243 _update_cache_to_call_python(), but to avoid the extra dict
244 lookups, we cache in (reserved1, reserved2) the last seen pair
245 (interp->modules, infotuple). The first item in this tuple is
246 a random PyObject that identifies the subinterpreter.
247 */
248 if (externpy->reserved1 == NULL) {
249 /* Not initialized! We didn't call @ffi.def_extern() on this
250 externpy object from any subinterpreter at all. */
251 err = 1;
252 }
253 else {
254 PyGILState_STATE state = gil_ensure();
255 if (externpy->reserved1 != PyThreadState_GET()->interp->modules) {
256 /* Update the (reserved1, reserved2) cache. This will fail
257 if we didn't call @ffi.def_extern() in this particular
258 subinterpreter. */
259 err = _update_cache_to_call_python(externpy);
260 }
261 if (!err) {
262 general_invoke_callback(0, args, args, externpy->reserved2);
263 }
264 gil_release(state);
265 }
266 if (err) {
267 static const char *msg[] = {
268 "no code was attached to it yet with @ffi.def_extern()",
269 "got internal exception (out of memory?)",
270 "@ffi.def_extern() was not called in the current subinterpreter",
271 "got internal exception (shutdown issue?)",
272 };
273 fprintf(stderr, "extern \"Python\": function %s() called, "
274 "but %s. Returning 0.\n", externpy->name, msg[err-1]);
275 memset(args, 0, externpy->size_of_result);
276 }
277 restore_errno();
278 }
279