1
2 static crossinterpdatafunc _lookup_getdata_from_registry(
3 PyInterpreterState *, PyObject *);
4
5 static crossinterpdatafunc
lookup_getdata(PyInterpreterState * interp,PyObject * obj)6 lookup_getdata(PyInterpreterState *interp, PyObject *obj)
7 {
8 /* Cross-interpreter objects are looked up by exact match on the class.
9 We can reassess this policy when we move from a global registry to a
10 tp_* slot. */
11 return _lookup_getdata_from_registry(interp, obj);
12 }
13
14 crossinterpdatafunc
_PyCrossInterpreterData_Lookup(PyObject * obj)15 _PyCrossInterpreterData_Lookup(PyObject *obj)
16 {
17 PyInterpreterState *interp = PyInterpreterState_Get();
18 return lookup_getdata(interp, obj);
19 }
20
21
22 /***********************************************/
23 /* a registry of {type -> crossinterpdatafunc} */
24 /***********************************************/
25
26 /* For now we use a global registry of shareable classes. An
27 alternative would be to add a tp_* slot for a class's
28 crossinterpdatafunc. It would be simpler and more efficient. */
29
30
31 /* registry lifecycle */
32
33 static void _register_builtins_for_crossinterpreter_data(struct _xidregistry *);
34
35 static void
_xidregistry_init(struct _xidregistry * registry)36 _xidregistry_init(struct _xidregistry *registry)
37 {
38 if (registry->initialized) {
39 return;
40 }
41 registry->initialized = 1;
42
43 if (registry->global) {
44 // Registering the builtins is cheap so we don't bother doing it lazily.
45 assert(registry->head == NULL);
46 _register_builtins_for_crossinterpreter_data(registry);
47 }
48 }
49
50 static void _xidregistry_clear(struct _xidregistry *);
51
52 static void
_xidregistry_fini(struct _xidregistry * registry)53 _xidregistry_fini(struct _xidregistry *registry)
54 {
55 if (!registry->initialized) {
56 return;
57 }
58 registry->initialized = 0;
59
60 _xidregistry_clear(registry);
61 }
62
63 static inline struct _xidregistry * _get_global_xidregistry(_PyRuntimeState *);
64 static inline struct _xidregistry * _get_xidregistry(PyInterpreterState *);
65
66 static void
xid_lookup_init(PyInterpreterState * interp)67 xid_lookup_init(PyInterpreterState *interp)
68 {
69 if (_Py_IsMainInterpreter(interp)) {
70 _xidregistry_init(_get_global_xidregistry(interp->runtime));
71 }
72 _xidregistry_init(_get_xidregistry(interp));
73 }
74
75 static void
xid_lookup_fini(PyInterpreterState * interp)76 xid_lookup_fini(PyInterpreterState *interp)
77 {
78 _xidregistry_fini(_get_xidregistry(interp));
79 if (_Py_IsMainInterpreter(interp)) {
80 _xidregistry_fini(_get_global_xidregistry(interp->runtime));
81 }
82 }
83
84
85 /* registry thread safety */
86
87 static void
_xidregistry_lock(struct _xidregistry * registry)88 _xidregistry_lock(struct _xidregistry *registry)
89 {
90 if (registry->global) {
91 PyMutex_Lock(®istry->mutex);
92 }
93 // else: Within an interpreter we rely on the GIL instead of a separate lock.
94 }
95
96 static void
_xidregistry_unlock(struct _xidregistry * registry)97 _xidregistry_unlock(struct _xidregistry *registry)
98 {
99 if (registry->global) {
100 PyMutex_Unlock(®istry->mutex);
101 }
102 }
103
104
105 /* accessing the registry */
106
107 static inline struct _xidregistry *
_get_global_xidregistry(_PyRuntimeState * runtime)108 _get_global_xidregistry(_PyRuntimeState *runtime)
109 {
110 return &runtime->xi.registry;
111 }
112
113 static inline struct _xidregistry *
_get_xidregistry(PyInterpreterState * interp)114 _get_xidregistry(PyInterpreterState *interp)
115 {
116 return &interp->xi.registry;
117 }
118
119 static inline struct _xidregistry *
_get_xidregistry_for_type(PyInterpreterState * interp,PyTypeObject * cls)120 _get_xidregistry_for_type(PyInterpreterState *interp, PyTypeObject *cls)
121 {
122 struct _xidregistry *registry = _get_global_xidregistry(interp->runtime);
123 if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
124 registry = _get_xidregistry(interp);
125 }
126 return registry;
127 }
128
129 static struct _xidregitem * _xidregistry_remove_entry(
130 struct _xidregistry *, struct _xidregitem *);
131
132 static struct _xidregitem *
_xidregistry_find_type(struct _xidregistry * xidregistry,PyTypeObject * cls)133 _xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls)
134 {
135 struct _xidregitem *cur = xidregistry->head;
136 while (cur != NULL) {
137 if (cur->weakref != NULL) {
138 // cur is/was a heap type.
139 PyObject *registered = _PyWeakref_GET_REF(cur->weakref);
140 if (registered == NULL) {
141 // The weakly ref'ed object was freed.
142 cur = _xidregistry_remove_entry(xidregistry, cur);
143 continue;
144 }
145 assert(PyType_Check(registered));
146 assert(cur->cls == (PyTypeObject *)registered);
147 assert(cur->cls->tp_flags & Py_TPFLAGS_HEAPTYPE);
148 Py_DECREF(registered);
149 }
150 if (cur->cls == cls) {
151 return cur;
152 }
153 cur = cur->next;
154 }
155 return NULL;
156 }
157
158 static crossinterpdatafunc
_lookup_getdata_from_registry(PyInterpreterState * interp,PyObject * obj)159 _lookup_getdata_from_registry(PyInterpreterState *interp, PyObject *obj)
160 {
161 PyTypeObject *cls = Py_TYPE(obj);
162
163 struct _xidregistry *xidregistry = _get_xidregistry_for_type(interp, cls);
164 _xidregistry_lock(xidregistry);
165
166 struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
167 crossinterpdatafunc func = matched != NULL ? matched->getdata : NULL;
168
169 _xidregistry_unlock(xidregistry);
170 return func;
171 }
172
173
174 /* updating the registry */
175
176 static int
_xidregistry_add_type(struct _xidregistry * xidregistry,PyTypeObject * cls,crossinterpdatafunc getdata)177 _xidregistry_add_type(struct _xidregistry *xidregistry,
178 PyTypeObject *cls, crossinterpdatafunc getdata)
179 {
180 struct _xidregitem *newhead = PyMem_RawMalloc(sizeof(struct _xidregitem));
181 if (newhead == NULL) {
182 return -1;
183 }
184 *newhead = (struct _xidregitem){
185 // We do not keep a reference, to avoid keeping the class alive.
186 .cls = cls,
187 .refcount = 1,
188 .getdata = getdata,
189 };
190 if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
191 // XXX Assign a callback to clear the entry from the registry?
192 newhead->weakref = PyWeakref_NewRef((PyObject *)cls, NULL);
193 if (newhead->weakref == NULL) {
194 PyMem_RawFree(newhead);
195 return -1;
196 }
197 }
198 newhead->next = xidregistry->head;
199 if (newhead->next != NULL) {
200 newhead->next->prev = newhead;
201 }
202 xidregistry->head = newhead;
203 return 0;
204 }
205
206 static struct _xidregitem *
_xidregistry_remove_entry(struct _xidregistry * xidregistry,struct _xidregitem * entry)207 _xidregistry_remove_entry(struct _xidregistry *xidregistry,
208 struct _xidregitem *entry)
209 {
210 struct _xidregitem *next = entry->next;
211 if (entry->prev != NULL) {
212 assert(entry->prev->next == entry);
213 entry->prev->next = next;
214 }
215 else {
216 assert(xidregistry->head == entry);
217 xidregistry->head = next;
218 }
219 if (next != NULL) {
220 next->prev = entry->prev;
221 }
222 Py_XDECREF(entry->weakref);
223 PyMem_RawFree(entry);
224 return next;
225 }
226
227 static void
_xidregistry_clear(struct _xidregistry * xidregistry)228 _xidregistry_clear(struct _xidregistry *xidregistry)
229 {
230 struct _xidregitem *cur = xidregistry->head;
231 xidregistry->head = NULL;
232 while (cur != NULL) {
233 struct _xidregitem *next = cur->next;
234 Py_XDECREF(cur->weakref);
235 PyMem_RawFree(cur);
236 cur = next;
237 }
238 }
239
240 int
_PyCrossInterpreterData_RegisterClass(PyTypeObject * cls,crossinterpdatafunc getdata)241 _PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,
242 crossinterpdatafunc getdata)
243 {
244 if (!PyType_Check(cls)) {
245 PyErr_Format(PyExc_ValueError, "only classes may be registered");
246 return -1;
247 }
248 if (getdata == NULL) {
249 PyErr_Format(PyExc_ValueError, "missing 'getdata' func");
250 return -1;
251 }
252
253 int res = 0;
254 PyInterpreterState *interp = _PyInterpreterState_GET();
255 struct _xidregistry *xidregistry = _get_xidregistry_for_type(interp, cls);
256 _xidregistry_lock(xidregistry);
257
258 struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
259 if (matched != NULL) {
260 assert(matched->getdata == getdata);
261 matched->refcount += 1;
262 goto finally;
263 }
264
265 res = _xidregistry_add_type(xidregistry, cls, getdata);
266
267 finally:
268 _xidregistry_unlock(xidregistry);
269 return res;
270 }
271
272 int
_PyCrossInterpreterData_UnregisterClass(PyTypeObject * cls)273 _PyCrossInterpreterData_UnregisterClass(PyTypeObject *cls)
274 {
275 int res = 0;
276 PyInterpreterState *interp = _PyInterpreterState_GET();
277 struct _xidregistry *xidregistry = _get_xidregistry_for_type(interp, cls);
278 _xidregistry_lock(xidregistry);
279
280 struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
281 if (matched != NULL) {
282 assert(matched->refcount > 0);
283 matched->refcount -= 1;
284 if (matched->refcount == 0) {
285 (void)_xidregistry_remove_entry(xidregistry, matched);
286 }
287 res = 1;
288 }
289
290 _xidregistry_unlock(xidregistry);
291 return res;
292 }
293
294
295 /********************************************/
296 /* cross-interpreter data for builtin types */
297 /********************************************/
298
299 // bytes
300
301 struct _shared_bytes_data {
302 char *bytes;
303 Py_ssize_t len;
304 };
305
306 static PyObject *
_new_bytes_object(_PyCrossInterpreterData * data)307 _new_bytes_object(_PyCrossInterpreterData *data)
308 {
309 struct _shared_bytes_data *shared = (struct _shared_bytes_data *)(data->data);
310 return PyBytes_FromStringAndSize(shared->bytes, shared->len);
311 }
312
313 static int
_bytes_shared(PyThreadState * tstate,PyObject * obj,_PyCrossInterpreterData * data)314 _bytes_shared(PyThreadState *tstate, PyObject *obj,
315 _PyCrossInterpreterData *data)
316 {
317 if (_PyCrossInterpreterData_InitWithSize(
318 data, tstate->interp, sizeof(struct _shared_bytes_data), obj,
319 _new_bytes_object
320 ) < 0)
321 {
322 return -1;
323 }
324 struct _shared_bytes_data *shared = (struct _shared_bytes_data *)data->data;
325 if (PyBytes_AsStringAndSize(obj, &shared->bytes, &shared->len) < 0) {
326 _PyCrossInterpreterData_Clear(tstate->interp, data);
327 return -1;
328 }
329 return 0;
330 }
331
332 // str
333
334 struct _shared_str_data {
335 int kind;
336 const void *buffer;
337 Py_ssize_t len;
338 };
339
340 static PyObject *
_new_str_object(_PyCrossInterpreterData * data)341 _new_str_object(_PyCrossInterpreterData *data)
342 {
343 struct _shared_str_data *shared = (struct _shared_str_data *)(data->data);
344 return PyUnicode_FromKindAndData(shared->kind, shared->buffer, shared->len);
345 }
346
347 static int
_str_shared(PyThreadState * tstate,PyObject * obj,_PyCrossInterpreterData * data)348 _str_shared(PyThreadState *tstate, PyObject *obj,
349 _PyCrossInterpreterData *data)
350 {
351 if (_PyCrossInterpreterData_InitWithSize(
352 data, tstate->interp, sizeof(struct _shared_str_data), obj,
353 _new_str_object
354 ) < 0)
355 {
356 return -1;
357 }
358 struct _shared_str_data *shared = (struct _shared_str_data *)data->data;
359 shared->kind = PyUnicode_KIND(obj);
360 shared->buffer = PyUnicode_DATA(obj);
361 shared->len = PyUnicode_GET_LENGTH(obj);
362 return 0;
363 }
364
365 // int
366
367 static PyObject *
_new_long_object(_PyCrossInterpreterData * data)368 _new_long_object(_PyCrossInterpreterData *data)
369 {
370 return PyLong_FromSsize_t((Py_ssize_t)(data->data));
371 }
372
373 static int
_long_shared(PyThreadState * tstate,PyObject * obj,_PyCrossInterpreterData * data)374 _long_shared(PyThreadState *tstate, PyObject *obj,
375 _PyCrossInterpreterData *data)
376 {
377 /* Note that this means the size of shareable ints is bounded by
378 * sys.maxsize. Hence on 32-bit architectures that is half the
379 * size of maximum shareable ints on 64-bit.
380 */
381 Py_ssize_t value = PyLong_AsSsize_t(obj);
382 if (value == -1 && PyErr_Occurred()) {
383 if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
384 PyErr_SetString(PyExc_OverflowError, "try sending as bytes");
385 }
386 return -1;
387 }
388 _PyCrossInterpreterData_Init(data, tstate->interp, (void *)value, NULL,
389 _new_long_object);
390 // data->obj and data->free remain NULL
391 return 0;
392 }
393
394 // float
395
396 static PyObject *
_new_float_object(_PyCrossInterpreterData * data)397 _new_float_object(_PyCrossInterpreterData *data)
398 {
399 double * value_ptr = data->data;
400 return PyFloat_FromDouble(*value_ptr);
401 }
402
403 static int
_float_shared(PyThreadState * tstate,PyObject * obj,_PyCrossInterpreterData * data)404 _float_shared(PyThreadState *tstate, PyObject *obj,
405 _PyCrossInterpreterData *data)
406 {
407 if (_PyCrossInterpreterData_InitWithSize(
408 data, tstate->interp, sizeof(double), NULL,
409 _new_float_object
410 ) < 0)
411 {
412 return -1;
413 }
414 double *shared = (double *)data->data;
415 *shared = PyFloat_AsDouble(obj);
416 return 0;
417 }
418
419 // None
420
421 static PyObject *
_new_none_object(_PyCrossInterpreterData * data)422 _new_none_object(_PyCrossInterpreterData *data)
423 {
424 // XXX Singleton refcounts are problematic across interpreters...
425 return Py_NewRef(Py_None);
426 }
427
428 static int
_none_shared(PyThreadState * tstate,PyObject * obj,_PyCrossInterpreterData * data)429 _none_shared(PyThreadState *tstate, PyObject *obj,
430 _PyCrossInterpreterData *data)
431 {
432 _PyCrossInterpreterData_Init(data, tstate->interp, NULL, NULL,
433 _new_none_object);
434 // data->data, data->obj and data->free remain NULL
435 return 0;
436 }
437
438 // bool
439
440 static PyObject *
_new_bool_object(_PyCrossInterpreterData * data)441 _new_bool_object(_PyCrossInterpreterData *data)
442 {
443 if (data->data){
444 Py_RETURN_TRUE;
445 }
446 Py_RETURN_FALSE;
447 }
448
449 static int
_bool_shared(PyThreadState * tstate,PyObject * obj,_PyCrossInterpreterData * data)450 _bool_shared(PyThreadState *tstate, PyObject *obj,
451 _PyCrossInterpreterData *data)
452 {
453 _PyCrossInterpreterData_Init(data, tstate->interp,
454 (void *) (Py_IsTrue(obj) ? (uintptr_t) 1 : (uintptr_t) 0), NULL,
455 _new_bool_object);
456 // data->obj and data->free remain NULL
457 return 0;
458 }
459
460 // tuple
461
462 struct _shared_tuple_data {
463 Py_ssize_t len;
464 _PyCrossInterpreterData **data;
465 };
466
467 static PyObject *
_new_tuple_object(_PyCrossInterpreterData * data)468 _new_tuple_object(_PyCrossInterpreterData *data)
469 {
470 struct _shared_tuple_data *shared = (struct _shared_tuple_data *)(data->data);
471 PyObject *tuple = PyTuple_New(shared->len);
472 if (tuple == NULL) {
473 return NULL;
474 }
475
476 for (Py_ssize_t i = 0; i < shared->len; i++) {
477 PyObject *item = _PyCrossInterpreterData_NewObject(shared->data[i]);
478 if (item == NULL){
479 Py_DECREF(tuple);
480 return NULL;
481 }
482 PyTuple_SET_ITEM(tuple, i, item);
483 }
484 return tuple;
485 }
486
487 static void
_tuple_shared_free(void * data)488 _tuple_shared_free(void* data)
489 {
490 struct _shared_tuple_data *shared = (struct _shared_tuple_data *)(data);
491 #ifndef NDEBUG
492 int64_t interpid = PyInterpreterState_GetID(_PyInterpreterState_GET());
493 #endif
494 for (Py_ssize_t i = 0; i < shared->len; i++) {
495 if (shared->data[i] != NULL) {
496 assert(_PyCrossInterpreterData_INTERPID(shared->data[i]) == interpid);
497 _PyCrossInterpreterData_Release(shared->data[i]);
498 PyMem_RawFree(shared->data[i]);
499 shared->data[i] = NULL;
500 }
501 }
502 PyMem_Free(shared->data);
503 PyMem_RawFree(shared);
504 }
505
506 static int
_tuple_shared(PyThreadState * tstate,PyObject * obj,_PyCrossInterpreterData * data)507 _tuple_shared(PyThreadState *tstate, PyObject *obj,
508 _PyCrossInterpreterData *data)
509 {
510 Py_ssize_t len = PyTuple_GET_SIZE(obj);
511 if (len < 0) {
512 return -1;
513 }
514 struct _shared_tuple_data *shared = PyMem_RawMalloc(sizeof(struct _shared_tuple_data));
515 if (shared == NULL){
516 PyErr_NoMemory();
517 return -1;
518 }
519
520 shared->len = len;
521 shared->data = (_PyCrossInterpreterData **) PyMem_Calloc(shared->len, sizeof(_PyCrossInterpreterData *));
522 if (shared->data == NULL) {
523 PyErr_NoMemory();
524 return -1;
525 }
526
527 for (Py_ssize_t i = 0; i < shared->len; i++) {
528 _PyCrossInterpreterData *data = _PyCrossInterpreterData_New();
529 if (data == NULL) {
530 goto error; // PyErr_NoMemory already set
531 }
532 PyObject *item = PyTuple_GET_ITEM(obj, i);
533
534 int res = -1;
535 if (!_Py_EnterRecursiveCallTstate(tstate, " while sharing a tuple")) {
536 res = _PyObject_GetCrossInterpreterData(item, data);
537 _Py_LeaveRecursiveCallTstate(tstate);
538 }
539 if (res < 0) {
540 PyMem_RawFree(data);
541 goto error;
542 }
543 shared->data[i] = data;
544 }
545 _PyCrossInterpreterData_Init(
546 data, tstate->interp, shared, obj, _new_tuple_object);
547 data->free = _tuple_shared_free;
548 return 0;
549
550 error:
551 _tuple_shared_free(shared);
552 return -1;
553 }
554
555 // registration
556
557 static void
_register_builtins_for_crossinterpreter_data(struct _xidregistry * xidregistry)558 _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry)
559 {
560 // None
561 if (_xidregistry_add_type(xidregistry, (PyTypeObject *)PyObject_Type(Py_None), _none_shared) != 0) {
562 Py_FatalError("could not register None for cross-interpreter sharing");
563 }
564
565 // int
566 if (_xidregistry_add_type(xidregistry, &PyLong_Type, _long_shared) != 0) {
567 Py_FatalError("could not register int for cross-interpreter sharing");
568 }
569
570 // bytes
571 if (_xidregistry_add_type(xidregistry, &PyBytes_Type, _bytes_shared) != 0) {
572 Py_FatalError("could not register bytes for cross-interpreter sharing");
573 }
574
575 // str
576 if (_xidregistry_add_type(xidregistry, &PyUnicode_Type, _str_shared) != 0) {
577 Py_FatalError("could not register str for cross-interpreter sharing");
578 }
579
580 // bool
581 if (_xidregistry_add_type(xidregistry, &PyBool_Type, _bool_shared) != 0) {
582 Py_FatalError("could not register bool for cross-interpreter sharing");
583 }
584
585 // float
586 if (_xidregistry_add_type(xidregistry, &PyFloat_Type, _float_shared) != 0) {
587 Py_FatalError("could not register float for cross-interpreter sharing");
588 }
589
590 // tuple
591 if (_xidregistry_add_type(xidregistry, &PyTuple_Type, _tuple_shared) != 0) {
592 Py_FatalError("could not register tuple for cross-interpreter sharing");
593 }
594 }
595