mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	This only affects users of the APIs in pycore_crossinterp.h (AKA _xxsubinterpretersmodule.c and _xxinterpchannels.c).
		
			
				
	
	
		
			655 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			655 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
 | 
						|
/* API for managing interactions between isolated interpreters */
 | 
						|
 | 
						|
#include "Python.h"
 | 
						|
#include "pycore_ceval.h"         // _Py_simple_func
 | 
						|
#include "pycore_crossinterp.h"   // struct _xid
 | 
						|
#include "pycore_pyerrors.h"      // _PyErr_Clear()
 | 
						|
#include "pycore_pystate.h"       // _PyInterpreterState_GET()
 | 
						|
#include "pycore_weakref.h"       // _PyWeakref_GET_REF()
 | 
						|
 | 
						|
 | 
						|
/***************************/
 | 
						|
/* cross-interpreter calls */
 | 
						|
/***************************/
 | 
						|
 | 
						|
int
 | 
						|
_Py_CallInInterpreter(PyInterpreterState *interp,
 | 
						|
                      _Py_simple_func func, void *arg)
 | 
						|
{
 | 
						|
    if (interp == _PyThreadState_GetCurrent()->interp) {
 | 
						|
        return func(arg);
 | 
						|
    }
 | 
						|
    // XXX Emit a warning if this fails?
 | 
						|
    _PyEval_AddPendingCall(interp, (_Py_pending_call_func)func, arg, 0);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_Py_CallInInterpreterAndRawFree(PyInterpreterState *interp,
 | 
						|
                                _Py_simple_func func, void *arg)
 | 
						|
{
 | 
						|
    if (interp == _PyThreadState_GetCurrent()->interp) {
 | 
						|
        int res = func(arg);
 | 
						|
        PyMem_RawFree(arg);
 | 
						|
        return res;
 | 
						|
    }
 | 
						|
    // XXX Emit a warning if this fails?
 | 
						|
    _PyEval_AddPendingCall(interp, func, arg, _Py_PENDING_RAWFREE);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**************************/
 | 
						|
/* cross-interpreter data */
 | 
						|
/**************************/
 | 
						|
 | 
						|
_PyCrossInterpreterData *
 | 
						|
_PyCrossInterpreterData_New(void)
 | 
						|
{
 | 
						|
    _PyCrossInterpreterData *xid = PyMem_RawMalloc(
 | 
						|
                                            sizeof(_PyCrossInterpreterData));
 | 
						|
    if (xid == NULL) {
 | 
						|
        PyErr_NoMemory();
 | 
						|
    }
 | 
						|
    return xid;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
_PyCrossInterpreterData_Free(_PyCrossInterpreterData *xid)
 | 
						|
{
 | 
						|
    PyInterpreterState *interp = PyInterpreterState_Get();
 | 
						|
    _PyCrossInterpreterData_Clear(interp, xid);
 | 
						|
    PyMem_RawFree(xid);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* defining cross-interpreter data */
 | 
						|
 | 
						|
static inline void
 | 
						|
_xidata_init(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    // If the value is being reused
 | 
						|
    // then _xidata_clear() should have been called already.
 | 
						|
    assert(data->data == NULL);
 | 
						|
    assert(data->obj == NULL);
 | 
						|
    *data = (_PyCrossInterpreterData){0};
 | 
						|
    data->interpid = -1;
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
_xidata_clear(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    // _PyCrossInterpreterData only has two members that need to be
 | 
						|
    // cleaned up, if set: "data" must be freed and "obj" must be decref'ed.
 | 
						|
    // In both cases the original (owning) interpreter must be used,
 | 
						|
    // which is the caller's responsibility to ensure.
 | 
						|
    if (data->data != NULL) {
 | 
						|
        if (data->free != NULL) {
 | 
						|
            data->free(data->data);
 | 
						|
        }
 | 
						|
        data->data = NULL;
 | 
						|
    }
 | 
						|
    Py_CLEAR(data->obj);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
_PyCrossInterpreterData_Init(_PyCrossInterpreterData *data,
 | 
						|
                             PyInterpreterState *interp,
 | 
						|
                             void *shared, PyObject *obj,
 | 
						|
                             xid_newobjectfunc new_object)
 | 
						|
{
 | 
						|
    assert(data != NULL);
 | 
						|
    assert(new_object != NULL);
 | 
						|
    _xidata_init(data);
 | 
						|
    data->data = shared;
 | 
						|
    if (obj != NULL) {
 | 
						|
        assert(interp != NULL);
 | 
						|
        // released in _PyCrossInterpreterData_Clear()
 | 
						|
        data->obj = Py_NewRef(obj);
 | 
						|
    }
 | 
						|
    // Ideally every object would know its owning interpreter.
 | 
						|
    // Until then, we have to rely on the caller to identify it
 | 
						|
    // (but we don't need it in all cases).
 | 
						|
    data->interpid = (interp != NULL) ? interp->id : -1;
 | 
						|
    data->new_object = new_object;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data,
 | 
						|
                                     PyInterpreterState *interp,
 | 
						|
                                     const size_t size, PyObject *obj,
 | 
						|
                                     xid_newobjectfunc new_object)
 | 
						|
{
 | 
						|
    assert(size > 0);
 | 
						|
    // For now we always free the shared data in the same interpreter
 | 
						|
    // where it was allocated, so the interpreter is required.
 | 
						|
    assert(interp != NULL);
 | 
						|
    _PyCrossInterpreterData_Init(data, interp, NULL, obj, new_object);
 | 
						|
    data->data = PyMem_RawMalloc(size);
 | 
						|
    if (data->data == NULL) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    data->free = PyMem_RawFree;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
_PyCrossInterpreterData_Clear(PyInterpreterState *interp,
 | 
						|
                              _PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    assert(data != NULL);
 | 
						|
    // This must be called in the owning interpreter.
 | 
						|
    assert(interp == NULL
 | 
						|
           || data->interpid == -1
 | 
						|
           || data->interpid == interp->id);
 | 
						|
    _xidata_clear(data);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* using cross-interpreter data */
 | 
						|
 | 
						|
static int
 | 
						|
_check_xidata(PyThreadState *tstate, _PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    // data->data can be anything, including NULL, so we don't check it.
 | 
						|
 | 
						|
    // data->obj may be NULL, so we don't check it.
 | 
						|
 | 
						|
    if (data->interpid < 0) {
 | 
						|
        _PyErr_SetString(tstate, PyExc_SystemError, "missing interp");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (data->new_object == NULL) {
 | 
						|
        _PyErr_SetString(tstate, PyExc_SystemError, "missing new_object func");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    // data->free may be NULL, so we don't check it.
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
crossinterpdatafunc _PyCrossInterpreterData_Lookup(PyObject *);
 | 
						|
 | 
						|
/* This is a separate func from _PyCrossInterpreterData_Lookup in order
 | 
						|
   to keep the registry code separate. */
 | 
						|
static crossinterpdatafunc
 | 
						|
_lookup_getdata(PyObject *obj)
 | 
						|
{
 | 
						|
    crossinterpdatafunc getdata = _PyCrossInterpreterData_Lookup(obj);
 | 
						|
    if (getdata == NULL && PyErr_Occurred() == 0)
 | 
						|
        PyErr_Format(PyExc_ValueError,
 | 
						|
                     "%S does not support cross-interpreter data", obj);
 | 
						|
    return getdata;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_PyObject_CheckCrossInterpreterData(PyObject *obj)
 | 
						|
{
 | 
						|
    crossinterpdatafunc getdata = _lookup_getdata(obj);
 | 
						|
    if (getdata == NULL) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    PyThreadState *tstate = _PyThreadState_GetCurrent();
 | 
						|
#ifdef Py_DEBUG
 | 
						|
    // The caller must hold the GIL
 | 
						|
    _Py_EnsureTstateNotNULL(tstate);
 | 
						|
#endif
 | 
						|
    PyInterpreterState *interp = tstate->interp;
 | 
						|
 | 
						|
    // Reset data before re-populating.
 | 
						|
    *data = (_PyCrossInterpreterData){0};
 | 
						|
    data->interpid = -1;
 | 
						|
 | 
						|
    // Call the "getdata" func for the object.
 | 
						|
    Py_INCREF(obj);
 | 
						|
    crossinterpdatafunc getdata = _lookup_getdata(obj);
 | 
						|
    if (getdata == NULL) {
 | 
						|
        Py_DECREF(obj);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    int res = getdata(tstate, obj, data);
 | 
						|
    Py_DECREF(obj);
 | 
						|
    if (res != 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    // Fill in the blanks and validate the result.
 | 
						|
    data->interpid = interp->id;
 | 
						|
    if (_check_xidata(tstate, data) != 0) {
 | 
						|
        (void)_PyCrossInterpreterData_Release(data);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
PyObject *
 | 
						|
_PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    return data->new_object(data);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
_call_clear_xidata(void *data)
 | 
						|
{
 | 
						|
    _xidata_clear((_PyCrossInterpreterData *)data);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
_xidata_release(_PyCrossInterpreterData *data, int rawfree)
 | 
						|
{
 | 
						|
    if ((data->data == NULL || data->free == NULL) && data->obj == NULL) {
 | 
						|
        // Nothing to release!
 | 
						|
        if (rawfree) {
 | 
						|
            PyMem_RawFree(data);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            data->data = NULL;
 | 
						|
        }
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    // Switch to the original interpreter.
 | 
						|
    PyInterpreterState *interp = _PyInterpreterState_LookUpID(data->interpid);
 | 
						|
    if (interp == NULL) {
 | 
						|
        // The interpreter was already destroyed.
 | 
						|
        // This function shouldn't have been called.
 | 
						|
        // XXX Someone leaked some memory...
 | 
						|
        assert(PyErr_Occurred());
 | 
						|
        if (rawfree) {
 | 
						|
            PyMem_RawFree(data);
 | 
						|
        }
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    // "Release" the data and/or the object.
 | 
						|
    if (rawfree) {
 | 
						|
        return _Py_CallInInterpreterAndRawFree(interp, _call_clear_xidata, data);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        return _Py_CallInInterpreter(interp, _call_clear_xidata, data);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    return _xidata_release(data, 0);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_PyCrossInterpreterData_ReleaseAndRawFree(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    return _xidata_release(data, 1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* registry of {type -> crossinterpdatafunc} */
 | 
						|
 | 
						|
/* For now we use a global registry of shareable classes.  An
 | 
						|
   alternative would be to add a tp_* slot for a class's
 | 
						|
   crossinterpdatafunc. It would be simpler and more efficient. */
 | 
						|
 | 
						|
static int
 | 
						|
_xidregistry_add_type(struct _xidregistry *xidregistry,
 | 
						|
                      PyTypeObject *cls, crossinterpdatafunc getdata)
 | 
						|
{
 | 
						|
    struct _xidregitem *newhead = PyMem_RawMalloc(sizeof(struct _xidregitem));
 | 
						|
    if (newhead == NULL) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    *newhead = (struct _xidregitem){
 | 
						|
        // We do not keep a reference, to avoid keeping the class alive.
 | 
						|
        .cls = cls,
 | 
						|
        .refcount = 1,
 | 
						|
        .getdata = getdata,
 | 
						|
    };
 | 
						|
    if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
 | 
						|
        // XXX Assign a callback to clear the entry from the registry?
 | 
						|
        newhead->weakref = PyWeakref_NewRef((PyObject *)cls, NULL);
 | 
						|
        if (newhead->weakref == NULL) {
 | 
						|
            PyMem_RawFree(newhead);
 | 
						|
            return -1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    newhead->next = xidregistry->head;
 | 
						|
    if (newhead->next != NULL) {
 | 
						|
        newhead->next->prev = newhead;
 | 
						|
    }
 | 
						|
    xidregistry->head = newhead;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static struct _xidregitem *
 | 
						|
_xidregistry_remove_entry(struct _xidregistry *xidregistry,
 | 
						|
                          struct _xidregitem *entry)
 | 
						|
{
 | 
						|
    struct _xidregitem *next = entry->next;
 | 
						|
    if (entry->prev != NULL) {
 | 
						|
        assert(entry->prev->next == entry);
 | 
						|
        entry->prev->next = next;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        assert(xidregistry->head == entry);
 | 
						|
        xidregistry->head = next;
 | 
						|
    }
 | 
						|
    if (next != NULL) {
 | 
						|
        next->prev = entry->prev;
 | 
						|
    }
 | 
						|
    Py_XDECREF(entry->weakref);
 | 
						|
    PyMem_RawFree(entry);
 | 
						|
    return next;
 | 
						|
}
 | 
						|
 | 
						|
// This is used in pystate.c (for now).
 | 
						|
void
 | 
						|
_Py_xidregistry_clear(struct _xidregistry *xidregistry)
 | 
						|
{
 | 
						|
    struct _xidregitem *cur = xidregistry->head;
 | 
						|
    xidregistry->head = NULL;
 | 
						|
    while (cur != NULL) {
 | 
						|
        struct _xidregitem *next = cur->next;
 | 
						|
        Py_XDECREF(cur->weakref);
 | 
						|
        PyMem_RawFree(cur);
 | 
						|
        cur = next;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static struct _xidregitem *
 | 
						|
_xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls)
 | 
						|
{
 | 
						|
    struct _xidregitem *cur = xidregistry->head;
 | 
						|
    while (cur != NULL) {
 | 
						|
        if (cur->weakref != NULL) {
 | 
						|
            // cur is/was a heap type.
 | 
						|
            PyObject *registered = _PyWeakref_GET_REF(cur->weakref);
 | 
						|
            if (registered == NULL) {
 | 
						|
                // The weakly ref'ed object was freed.
 | 
						|
                cur = _xidregistry_remove_entry(xidregistry, cur);
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            assert(PyType_Check(registered));
 | 
						|
            assert(cur->cls == (PyTypeObject *)registered);
 | 
						|
            assert(cur->cls->tp_flags & Py_TPFLAGS_HEAPTYPE);
 | 
						|
            Py_DECREF(registered);
 | 
						|
        }
 | 
						|
        if (cur->cls == cls) {
 | 
						|
            return cur;
 | 
						|
        }
 | 
						|
        cur = cur->next;
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static inline struct _xidregistry *
 | 
						|
_get_xidregistry(PyInterpreterState *interp, PyTypeObject *cls)
 | 
						|
{
 | 
						|
    struct _xidregistry *xidregistry = &interp->runtime->xidregistry;
 | 
						|
    if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
 | 
						|
        assert(interp->xidregistry.mutex == xidregistry->mutex);
 | 
						|
        xidregistry = &interp->xidregistry;
 | 
						|
    }
 | 
						|
    return xidregistry;
 | 
						|
}
 | 
						|
 | 
						|
static void _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry);
 | 
						|
 | 
						|
static inline void
 | 
						|
_ensure_builtins_xid(PyInterpreterState *interp, struct _xidregistry *xidregistry)
 | 
						|
{
 | 
						|
    if (xidregistry != &interp->xidregistry) {
 | 
						|
        assert(xidregistry == &interp->runtime->xidregistry);
 | 
						|
        if (xidregistry->head == NULL) {
 | 
						|
            _register_builtins_for_crossinterpreter_data(xidregistry);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,
 | 
						|
                                      crossinterpdatafunc getdata)
 | 
						|
{
 | 
						|
    if (!PyType_Check(cls)) {
 | 
						|
        PyErr_Format(PyExc_ValueError, "only classes may be registered");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (getdata == NULL) {
 | 
						|
        PyErr_Format(PyExc_ValueError, "missing 'getdata' func");
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    int res = 0;
 | 
						|
    PyInterpreterState *interp = _PyInterpreterState_GET();
 | 
						|
    struct _xidregistry *xidregistry = _get_xidregistry(interp, cls);
 | 
						|
    PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK);
 | 
						|
 | 
						|
    _ensure_builtins_xid(interp, xidregistry);
 | 
						|
 | 
						|
    struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
 | 
						|
    if (matched != NULL) {
 | 
						|
        assert(matched->getdata == getdata);
 | 
						|
        matched->refcount += 1;
 | 
						|
        goto finally;
 | 
						|
    }
 | 
						|
 | 
						|
    res = _xidregistry_add_type(xidregistry, cls, getdata);
 | 
						|
 | 
						|
finally:
 | 
						|
    PyThread_release_lock(xidregistry->mutex);
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
_PyCrossInterpreterData_UnregisterClass(PyTypeObject *cls)
 | 
						|
{
 | 
						|
    int res = 0;
 | 
						|
    PyInterpreterState *interp = _PyInterpreterState_GET();
 | 
						|
    struct _xidregistry *xidregistry = _get_xidregistry(interp, cls);
 | 
						|
    PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK);
 | 
						|
 | 
						|
    struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
 | 
						|
    if (matched != NULL) {
 | 
						|
        assert(matched->refcount > 0);
 | 
						|
        matched->refcount -= 1;
 | 
						|
        if (matched->refcount == 0) {
 | 
						|
            (void)_xidregistry_remove_entry(xidregistry, matched);
 | 
						|
        }
 | 
						|
        res = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    PyThread_release_lock(xidregistry->mutex);
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Cross-interpreter objects are looked up by exact match on the class.
 | 
						|
   We can reassess this policy when we move from a global registry to a
 | 
						|
   tp_* slot. */
 | 
						|
 | 
						|
crossinterpdatafunc
 | 
						|
_PyCrossInterpreterData_Lookup(PyObject *obj)
 | 
						|
{
 | 
						|
    PyTypeObject *cls = Py_TYPE(obj);
 | 
						|
 | 
						|
    PyInterpreterState *interp = _PyInterpreterState_GET();
 | 
						|
    struct _xidregistry *xidregistry = _get_xidregistry(interp, cls);
 | 
						|
    PyThread_acquire_lock(xidregistry->mutex, WAIT_LOCK);
 | 
						|
 | 
						|
    _ensure_builtins_xid(interp, xidregistry);
 | 
						|
 | 
						|
    struct _xidregitem *matched = _xidregistry_find_type(xidregistry, cls);
 | 
						|
    crossinterpdatafunc func = matched != NULL ? matched->getdata : NULL;
 | 
						|
 | 
						|
    PyThread_release_lock(xidregistry->mutex);
 | 
						|
    return func;
 | 
						|
}
 | 
						|
 | 
						|
/* cross-interpreter data for builtin types */
 | 
						|
 | 
						|
struct _shared_bytes_data {
 | 
						|
    char *bytes;
 | 
						|
    Py_ssize_t len;
 | 
						|
};
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_new_bytes_object(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    struct _shared_bytes_data *shared = (struct _shared_bytes_data *)(data->data);
 | 
						|
    return PyBytes_FromStringAndSize(shared->bytes, shared->len);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
_bytes_shared(PyThreadState *tstate, PyObject *obj,
 | 
						|
              _PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    if (_PyCrossInterpreterData_InitWithSize(
 | 
						|
            data, tstate->interp, sizeof(struct _shared_bytes_data), obj,
 | 
						|
            _new_bytes_object
 | 
						|
            ) < 0)
 | 
						|
    {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    struct _shared_bytes_data *shared = (struct _shared_bytes_data *)data->data;
 | 
						|
    if (PyBytes_AsStringAndSize(obj, &shared->bytes, &shared->len) < 0) {
 | 
						|
        _PyCrossInterpreterData_Clear(tstate->interp, data);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
struct _shared_str_data {
 | 
						|
    int kind;
 | 
						|
    const void *buffer;
 | 
						|
    Py_ssize_t len;
 | 
						|
};
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_new_str_object(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    struct _shared_str_data *shared = (struct _shared_str_data *)(data->data);
 | 
						|
    return PyUnicode_FromKindAndData(shared->kind, shared->buffer, shared->len);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
_str_shared(PyThreadState *tstate, PyObject *obj,
 | 
						|
            _PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    if (_PyCrossInterpreterData_InitWithSize(
 | 
						|
            data, tstate->interp, sizeof(struct _shared_str_data), obj,
 | 
						|
            _new_str_object
 | 
						|
            ) < 0)
 | 
						|
    {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    struct _shared_str_data *shared = (struct _shared_str_data *)data->data;
 | 
						|
    shared->kind = PyUnicode_KIND(obj);
 | 
						|
    shared->buffer = PyUnicode_DATA(obj);
 | 
						|
    shared->len = PyUnicode_GET_LENGTH(obj);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_new_long_object(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    return PyLong_FromSsize_t((Py_ssize_t)(data->data));
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
_long_shared(PyThreadState *tstate, PyObject *obj,
 | 
						|
             _PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    /* Note that this means the size of shareable ints is bounded by
 | 
						|
     * sys.maxsize.  Hence on 32-bit architectures that is half the
 | 
						|
     * size of maximum shareable ints on 64-bit.
 | 
						|
     */
 | 
						|
    Py_ssize_t value = PyLong_AsSsize_t(obj);
 | 
						|
    if (value == -1 && PyErr_Occurred()) {
 | 
						|
        if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
 | 
						|
            PyErr_SetString(PyExc_OverflowError, "try sending as bytes");
 | 
						|
        }
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    _PyCrossInterpreterData_Init(data, tstate->interp, (void *)value, NULL,
 | 
						|
            _new_long_object);
 | 
						|
    // data->obj and data->free remain NULL
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_new_float_object(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    double * value_ptr = data->data;
 | 
						|
    return PyFloat_FromDouble(*value_ptr);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
_float_shared(PyThreadState *tstate, PyObject *obj,
 | 
						|
             _PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    if (_PyCrossInterpreterData_InitWithSize(
 | 
						|
            data, tstate->interp, sizeof(double), NULL,
 | 
						|
            _new_float_object
 | 
						|
            ) < 0)
 | 
						|
    {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    double *shared = (double *)data->data;
 | 
						|
    *shared = PyFloat_AsDouble(obj);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
_new_none_object(_PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    // XXX Singleton refcounts are problematic across interpreters...
 | 
						|
    return Py_NewRef(Py_None);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
_none_shared(PyThreadState *tstate, PyObject *obj,
 | 
						|
             _PyCrossInterpreterData *data)
 | 
						|
{
 | 
						|
    _PyCrossInterpreterData_Init(data, tstate->interp, NULL, NULL,
 | 
						|
            _new_none_object);
 | 
						|
    // data->data, data->obj and data->free remain NULL
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
_register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry)
 | 
						|
{
 | 
						|
    // None
 | 
						|
    if (_xidregistry_add_type(xidregistry, (PyTypeObject *)PyObject_Type(Py_None), _none_shared) != 0) {
 | 
						|
        Py_FatalError("could not register None for cross-interpreter sharing");
 | 
						|
    }
 | 
						|
 | 
						|
    // int
 | 
						|
    if (_xidregistry_add_type(xidregistry, &PyLong_Type, _long_shared) != 0) {
 | 
						|
        Py_FatalError("could not register int for cross-interpreter sharing");
 | 
						|
    }
 | 
						|
 | 
						|
    // bytes
 | 
						|
    if (_xidregistry_add_type(xidregistry, &PyBytes_Type, _bytes_shared) != 0) {
 | 
						|
        Py_FatalError("could not register bytes for cross-interpreter sharing");
 | 
						|
    }
 | 
						|
 | 
						|
    // str
 | 
						|
    if (_xidregistry_add_type(xidregistry, &PyUnicode_Type, _str_shared) != 0) {
 | 
						|
        Py_FatalError("could not register str for cross-interpreter sharing");
 | 
						|
    }
 | 
						|
 | 
						|
    // float
 | 
						|
    if (_xidregistry_add_type(xidregistry, &PyFloat_Type, _float_shared) != 0) {
 | 
						|
        Py_FatalError("could not register float for cross-interpreter sharing");
 | 
						|
    }
 | 
						|
}
 |