cpython/Python/crossinterp.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_initconfig.h"    // _PyStatus_OK()
#include "pycore_namespace.h"     //_PyNamespace_New()
#include "pycore_pyerrors.h"      // _PyErr_Clear()
#include "pycore_weakref.h"       // _PyWeakref_GET_REF()


/**************/
/* exceptions */
/**************/

static int init_exceptions(PyInterpreterState *);
static void fini_exceptions(PyInterpreterState *);
static int _init_not_shareable_error_type(PyInterpreterState *);
static void _fini_not_shareable_error_type(PyInterpreterState *);
static PyObject * _get_not_shareable_error_type(PyInterpreterState *);
#include "crossinterp_exceptions.h"


/***************************/
/* cross-interpreter calls */
/***************************/

int
_Py_CallInInterpreter(PyInterpreterState *interp,
                      _Py_simple_func func, void *arg)
{}

int
_Py_CallInInterpreterAndRawFree(PyInterpreterState *interp,
                                _Py_simple_func func, void *arg)
{}


/**************************/
/* cross-interpreter data */
/**************************/

/* 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 void xid_lookup_init(PyInterpreterState *);
static void xid_lookup_fini(PyInterpreterState *);
static crossinterpdatafunc lookup_getdata(PyInterpreterState *, PyObject *);
#include "crossinterp_data_lookup.h"


/* lifecycle */

_PyCrossInterpreterData *
_PyCrossInterpreterData_New(void)
{}

void
_PyCrossInterpreterData_Free(_PyCrossInterpreterData *xid)
{}


/* defining cross-interpreter data */

static inline void
_xidata_init(_PyCrossInterpreterData *data)
{}

static inline void
_xidata_clear(_PyCrossInterpreterData *data)
{}

void
_PyCrossInterpreterData_Init(_PyCrossInterpreterData *data,
                             PyInterpreterState *interp,
                             void *shared, PyObject *obj,
                             xid_newobjectfunc new_object)
{}

int
_PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data,
                                     PyInterpreterState *interp,
                                     const size_t size, PyObject *obj,
                                     xid_newobjectfunc new_object)
{}

void
_PyCrossInterpreterData_Clear(PyInterpreterState *interp,
                              _PyCrossInterpreterData *data)
{}


/* using cross-interpreter data */

static int
_check_xidata(PyThreadState *tstate, _PyCrossInterpreterData *data)
{}

static inline void
_set_xid_lookup_failure(PyInterpreterState *interp,
                        PyObject *obj, const char *msg)
{}

int
_PyObject_CheckCrossInterpreterData(PyObject *obj)
{}

int
_PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
{}

PyObject *
_PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *data)
{}

static int
_call_clear_xidata(void *data)
{}

static int
_xidata_release(_PyCrossInterpreterData *data, int rawfree)
{}

int
_PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
{}

int
_PyCrossInterpreterData_ReleaseAndRawFree(_PyCrossInterpreterData *data)
{}


/*************************/
/* convenience utilities */
/*************************/

static const char *
_copy_string_obj_raw(PyObject *strobj, Py_ssize_t *p_size)
{}


static int
_convert_exc_to_TracebackException(PyObject *exc, PyObject **p_tbexc)
{}

// We accommodate backports here.
#ifndef _Py_EMPTY_STR
#define _Py_EMPTY_STR
#endif

static const char *
_format_TracebackException(PyObject *tbexc)
{}


static int
_release_xid_data(_PyCrossInterpreterData *data, int rawfree)
{}


/***********************/
/* exception snapshots */
/***********************/

static int
_excinfo_init_type_from_exception(struct _excinfo_type *info, PyObject *exc)
{}

static int
_excinfo_init_type_from_object(struct _excinfo_type *info, PyObject *exctype)
{}

static void
_excinfo_clear_type(struct _excinfo_type *info)
{}

static void
_excinfo_normalize_type(struct _excinfo_type *info,
                        const char **p_module, const char **p_qualname)
{}

static void
_PyXI_excinfo_Clear(_PyXI_excinfo *info)
{}

PyObject *
_PyXI_excinfo_format(_PyXI_excinfo *info)
{}

static const char *
_PyXI_excinfo_InitFromException(_PyXI_excinfo *info, PyObject *exc)
{}

static const char *
_PyXI_excinfo_InitFromObject(_PyXI_excinfo *info, PyObject *obj)
{}

static void
_PyXI_excinfo_Apply(_PyXI_excinfo *info, PyObject *exctype)
{}

static PyObject *
_PyXI_excinfo_TypeAsObject(_PyXI_excinfo *info)
{}

static PyObject *
_PyXI_excinfo_AsObject(_PyXI_excinfo *info)
{}


int
_PyXI_InitExcInfo(_PyXI_excinfo *info, PyObject *exc)
{}

PyObject *
_PyXI_FormatExcInfo(_PyXI_excinfo *info)
{}

PyObject *
_PyXI_ExcInfoAsObject(_PyXI_excinfo *info)
{}

void
_PyXI_ClearExcInfo(_PyXI_excinfo *info)
{}


/***************************/
/* short-term data sharing */
/***************************/

/* error codes */

static int
_PyXI_ApplyErrorCode(_PyXI_errcode code, PyInterpreterState *interp)
{}

/* shared exceptions */

static const char *
_PyXI_InitError(_PyXI_error *error, PyObject *excobj, _PyXI_errcode code)
{}

PyObject *
_PyXI_ApplyError(_PyXI_error *error)
{}

/* shared namespaces */

/* Shared namespaces are expected to have relatively short lifetimes.
   This means dealloc of a shared namespace will normally happen "soon".
   Namespace items hold cross-interpreter data, which must get released.
   If the namespace/items are cleared in a different interpreter than
   where the items' cross-interpreter data was set then that will cause
   pending calls to be used to release the cross-interpreter data.
   The tricky bit is that the pending calls can happen sufficiently
   later that the namespace/items might already be deallocated.  This is
   a problem if the cross-interpreter data is allocated as part of a
   namespace item.  If that's the case then we must ensure the shared
   namespace is only cleared/freed *after* that data has been released. */

_PyXI_namespace_item;

static int
_sharednsitem_is_initialized(_PyXI_namespace_item *item)
{}

static int
_sharednsitem_init(_PyXI_namespace_item *item, PyObject *key)
{}

static int
_sharednsitem_has_value(_PyXI_namespace_item *item, int64_t *p_interpid)
{}

static int
_sharednsitem_set_value(_PyXI_namespace_item *item, PyObject *value)
{}

static void
_sharednsitem_clear_value(_PyXI_namespace_item *item)
{}

static void
_sharednsitem_clear(_PyXI_namespace_item *item)
{}

static int
_sharednsitem_copy_from_ns(struct _sharednsitem *item, PyObject *ns)
{}

static int
_sharednsitem_apply(_PyXI_namespace_item *item, PyObject *ns, PyObject *dflt)
{}

struct _sharedns {};

static _PyXI_namespace *
_sharedns_new(void)
{}

static int
_sharedns_is_initialized(_PyXI_namespace *ns)
{}

#define HAS_COMPLETE_DATA
#define HAS_PARTIAL_DATA

static int
_sharedns_has_xidata(_PyXI_namespace *ns, int64_t *p_interpid)
{}

static void
_sharedns_clear(_PyXI_namespace *ns)
{}

static void
_sharedns_free(_PyXI_namespace *ns)
{}

static int
_sharedns_init(_PyXI_namespace *ns, PyObject *names)
{}

void
_PyXI_FreeNamespace(_PyXI_namespace *ns)
{}

_PyXI_namespace *
_PyXI_NamespaceFromNames(PyObject *names)
{}

#ifndef NDEBUG
static int _session_is_active(_PyXI_session *);
#endif
static void _propagate_not_shareable_error(_PyXI_session *);

int
_PyXI_FillNamespaceFromDict(_PyXI_namespace *ns, PyObject *nsobj,
                            _PyXI_session *session)
{}

// All items are expected to be shareable.
static _PyXI_namespace *
_PyXI_NamespaceFromDict(PyObject *nsobj, _PyXI_session *session)
{}

int
_PyXI_ApplyNamespace(_PyXI_namespace *ns, PyObject *nsobj, PyObject *dflt)
{}


/**********************/
/* high-level helpers */
/**********************/

/* enter/exit a cross-interpreter session */

static void
_enter_session(_PyXI_session *session, PyInterpreterState *interp)
{}

static void
_exit_session(_PyXI_session *session)
{}

#ifndef NDEBUG
static int
_session_is_active(_PyXI_session *session)
{
    return (session->init_tstate != NULL);
}
#endif

static void
_propagate_not_shareable_error(_PyXI_session *session)
{}

static void
_capture_current_exception(_PyXI_session *session)
{}

PyObject *
_PyXI_ApplyCapturedException(_PyXI_session *session)
{}

int
_PyXI_HasCapturedException(_PyXI_session *session)
{}

int
_PyXI_Enter(_PyXI_session *session,
            PyInterpreterState *interp, PyObject *nsupdates)
{}

void
_PyXI_Exit(_PyXI_session *session)
{}


/*********************/
/* runtime lifecycle */
/*********************/

PyStatus
_PyXI_Init(PyInterpreterState *interp)
{}

// _PyXI_Fini() must be called before the interpreter is cleared,
// since we must clear some heap objects.

void
_PyXI_Fini(PyInterpreterState *interp)
{}

PyStatus
_PyXI_InitTypes(PyInterpreterState *interp)
{}

void
_PyXI_FiniTypes(PyInterpreterState *interp)
{}


/*************/
/* other API */
/*************/

PyInterpreterState *
_PyXI_NewInterpreter(PyInterpreterConfig *config, long *maybe_whence,
                     PyThreadState **p_tstate, PyThreadState **p_save_tstate)
{}

void
_PyXI_EndInterpreter(PyInterpreterState *interp,
                     PyThreadState *tstate, PyThreadState **p_save_tstate)
{}