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"   // _PyXIData_t
#include "pycore_initconfig.h"    // _PyStatus_OK()
#include "pycore_namespace.h"     //_PyNamespace_New()
#include "pycore_pyerrors.h"      // _PyErr_Clear()


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

exceptions_t;
static int init_static_exctypes(exceptions_t *, PyInterpreterState *);
static void fini_static_exctypes(exceptions_t *, PyInterpreterState *);
static int init_heap_exctypes(exceptions_t *);
static void fini_heap_exctypes(exceptions_t *);
#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 -> xidatafunc} */

/* For now we use a global registry of shareable classes.  An
   alternative would be to add a tp_* slot for a class's
   xidatafunc. It would be simpler and more efficient. */

static void xid_lookup_init(_PyXIData_lookup_t *);
static void xid_lookup_fini(_PyXIData_lookup_t *);
static xidatafunc lookup_getdata(_PyXIData_lookup_context_t *, PyObject *);
#include "crossinterp_data_lookup.h"


/* lifecycle */

_PyXIData_t *
_PyXIData_New(void)
{}

void
_PyXIData_Free(_PyXIData_t *xid)
{}


/* defining cross-interpreter data */

static inline void
_xidata_init(_PyXIData_t *data)
{}

static inline void
_xidata_clear(_PyXIData_t *data)
{}

void
_PyXIData_Init(_PyXIData_t *data,
               PyInterpreterState *interp,
               void *shared, PyObject *obj,
               xid_newobjfunc new_object)
{}

int
_PyXIData_InitWithSize(_PyXIData_t *data,
                       PyInterpreterState *interp,
                       const size_t size, PyObject *obj,
                       xid_newobjfunc new_object)
{}

void
_PyXIData_Clear(PyInterpreterState *interp, _PyXIData_t *data)
{}


/* using cross-interpreter data */

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

static inline void
_set_xid_lookup_failure(dlcontext_t *ctx, PyObject *obj, const char *msg)
{}

int
_PyObject_CheckXIData(_PyXIData_lookup_context_t *ctx, PyObject *obj)
{}

int
_PyObject_GetXIData(_PyXIData_lookup_context_t *ctx,
                    PyObject *obj, _PyXIData_t *data)
{}

PyObject *
_PyXIData_NewObject(_PyXIData_t *data)
{}

static int
_call_clear_xidata(void *data)
{}

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

int
_PyXIData_Release(_PyXIData_t *data)
{}

int
_PyXIData_ReleaseAndRawFree(_PyXIData_t *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(_PyXIData_t *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 */
/*********************/

int
_Py_xi_global_state_init(_PyXI_global_state_t *state)
{}

void
_Py_xi_global_state_fini(_PyXI_global_state_t *state)
{}

int
_Py_xi_state_init(_PyXI_state_t *state, PyInterpreterState *interp)
{}

void
_Py_xi_state_fini(_PyXI_state_t *state, PyInterpreterState *interp)
{}


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)
{}