| Kevin Cheng | 757c264 | 2019-04-18 11:31:16 -0700 | [diff] [blame] | 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | } |