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