• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&registry->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(&registry->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