|
| 1 | +#ifndef Py_INTERNAL_CROSSINTERP_H |
| 2 | +#define Py_INTERNAL_CROSSINTERP_H |
| 3 | +#ifdef __cplusplus |
| 4 | +extern "C" { |
| 5 | +#endif |
| 6 | + |
| 7 | +#ifndef Py_BUILD_CORE |
| 8 | +# error "this header requires Py_BUILD_CORE define" |
| 9 | +#endif |
| 10 | + |
| 11 | + |
| 12 | +/***************************/ |
| 13 | +/* cross-interpreter calls */ |
| 14 | +/***************************/ |
| 15 | + |
| 16 | +typedef int (*_Py_simple_func)(void *); |
| 17 | +extern int _Py_CallInInterpreter( |
| 18 | + PyInterpreterState *interp, |
| 19 | + _Py_simple_func func, |
| 20 | + void *arg); |
| 21 | +extern int _Py_CallInInterpreterAndRawFree( |
| 22 | + PyInterpreterState *interp, |
| 23 | + _Py_simple_func func, |
| 24 | + void *arg); |
| 25 | + |
| 26 | + |
| 27 | +/**************************/ |
| 28 | +/* cross-interpreter data */ |
| 29 | +/**************************/ |
| 30 | + |
| 31 | +typedef struct _xid _PyCrossInterpreterData; |
| 32 | +typedef PyObject *(*xid_newobjectfunc)(_PyCrossInterpreterData *); |
| 33 | +typedef void (*xid_freefunc)(void *); |
| 34 | + |
| 35 | +// _PyCrossInterpreterData is similar to Py_buffer as an effectively |
| 36 | +// opaque struct that holds data outside the object machinery. This |
| 37 | +// is necessary to pass safely between interpreters in the same process. |
| 38 | +struct _xid { |
| 39 | + // data is the cross-interpreter-safe derivation of a Python object |
| 40 | + // (see _PyObject_GetCrossInterpreterData). It will be NULL if the |
| 41 | + // new_object func (below) encodes the data. |
| 42 | + void *data; |
| 43 | + // obj is the Python object from which the data was derived. This |
| 44 | + // is non-NULL only if the data remains bound to the object in some |
| 45 | + // way, such that the object must be "released" (via a decref) when |
| 46 | + // the data is released. In that case the code that sets the field, |
| 47 | + // likely a registered "crossinterpdatafunc", is responsible for |
| 48 | + // ensuring it owns the reference (i.e. incref). |
| 49 | + PyObject *obj; |
| 50 | + // interp is the ID of the owning interpreter of the original |
| 51 | + // object. It corresponds to the active interpreter when |
| 52 | + // _PyObject_GetCrossInterpreterData() was called. This should only |
| 53 | + // be set by the cross-interpreter machinery. |
| 54 | + // |
| 55 | + // We use the ID rather than the PyInterpreterState to avoid issues |
| 56 | + // with deleted interpreters. Note that IDs are never re-used, so |
| 57 | + // each one will always correspond to a specific interpreter |
| 58 | + // (whether still alive or not). |
| 59 | + int64_t interpid; |
| 60 | + // new_object is a function that returns a new object in the current |
| 61 | + // interpreter given the data. The resulting object (a new |
| 62 | + // reference) will be equivalent to the original object. This field |
| 63 | + // is required. |
| 64 | + xid_newobjectfunc new_object; |
| 65 | + // free is called when the data is released. If it is NULL then |
| 66 | + // nothing will be done to free the data. For some types this is |
| 67 | + // okay (e.g. bytes) and for those types this field should be set |
| 68 | + // to NULL. However, for most the data was allocated just for |
| 69 | + // cross-interpreter use, so it must be freed when |
| 70 | + // _PyCrossInterpreterData_Release is called or the memory will |
| 71 | + // leak. In that case, at the very least this field should be set |
| 72 | + // to PyMem_RawFree (the default if not explicitly set to NULL). |
| 73 | + // The call will happen with the original interpreter activated. |
| 74 | + xid_freefunc free; |
| 75 | +}; |
| 76 | + |
| 77 | +PyAPI_FUNC(_PyCrossInterpreterData *) _PyCrossInterpreterData_New(void); |
| 78 | +PyAPI_FUNC(void) _PyCrossInterpreterData_Free(_PyCrossInterpreterData *data); |
| 79 | + |
| 80 | + |
| 81 | +/* defining cross-interpreter data */ |
| 82 | + |
| 83 | +PyAPI_FUNC(void) _PyCrossInterpreterData_Init( |
| 84 | + _PyCrossInterpreterData *data, |
| 85 | + PyInterpreterState *interp, void *shared, PyObject *obj, |
| 86 | + xid_newobjectfunc new_object); |
| 87 | +PyAPI_FUNC(int) _PyCrossInterpreterData_InitWithSize( |
| 88 | + _PyCrossInterpreterData *, |
| 89 | + PyInterpreterState *interp, const size_t, PyObject *, |
| 90 | + xid_newobjectfunc); |
| 91 | +PyAPI_FUNC(void) _PyCrossInterpreterData_Clear( |
| 92 | + PyInterpreterState *, _PyCrossInterpreterData *); |
| 93 | + |
| 94 | + |
| 95 | +/* using cross-interpreter data */ |
| 96 | + |
| 97 | +PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *); |
| 98 | +PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *); |
| 99 | +PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *); |
| 100 | +PyAPI_FUNC(int) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *); |
| 101 | +PyAPI_FUNC(int) _PyCrossInterpreterData_ReleaseAndRawFree(_PyCrossInterpreterData *); |
| 102 | + |
| 103 | + |
| 104 | +/* cross-interpreter data registry */ |
| 105 | + |
| 106 | +// For now we use a global registry of shareable classes. An |
| 107 | +// alternative would be to add a tp_* slot for a class's |
| 108 | +// crossinterpdatafunc. It would be simpler and more efficient. |
| 109 | + |
| 110 | +typedef int (*crossinterpdatafunc)(PyThreadState *tstate, PyObject *, |
| 111 | + _PyCrossInterpreterData *); |
| 112 | + |
| 113 | +struct _xidregitem; |
| 114 | + |
| 115 | +struct _xidregitem { |
| 116 | + struct _xidregitem *prev; |
| 117 | + struct _xidregitem *next; |
| 118 | + /* This can be a dangling pointer, but only if weakref is set. */ |
| 119 | + PyTypeObject *cls; |
| 120 | + /* This is NULL for builtin types. */ |
| 121 | + PyObject *weakref; |
| 122 | + size_t refcount; |
| 123 | + crossinterpdatafunc getdata; |
| 124 | +}; |
| 125 | + |
| 126 | +struct _xidregistry { |
| 127 | + PyThread_type_lock mutex; |
| 128 | + struct _xidregitem *head; |
| 129 | +}; |
| 130 | + |
| 131 | +PyAPI_FUNC(int) _PyCrossInterpreterData_RegisterClass(PyTypeObject *, crossinterpdatafunc); |
| 132 | +PyAPI_FUNC(int) _PyCrossInterpreterData_UnregisterClass(PyTypeObject *); |
| 133 | +PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *); |
| 134 | + |
| 135 | + |
| 136 | +#ifdef __cplusplus |
| 137 | +} |
| 138 | +#endif |
| 139 | +#endif /* !Py_INTERNAL_CROSSINTERP_H */ |
0 commit comments