cpython/Include/internal/pycore_crossinterp.h

#ifndef Py_INTERNAL_CROSSINTERP_H
#define Py_INTERNAL_CROSSINTERP_H
#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_BUILD_CORE
#  error "this header requires Py_BUILD_CORE define"
#endif

#include "pycore_lock.h"            // PyMutex
#include "pycore_pyerrors.h"


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

PyAPI_DATA(PyObject *) PyExc_InterpreterError;
PyAPI_DATA(PyObject *) PyExc_InterpreterNotFoundError;


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

_Py_simple_func;
extern int _Py_CallInInterpreter(
    PyInterpreterState *interp,
    _Py_simple_func func,
    void *arg);
extern int _Py_CallInInterpreterAndRawFree(
    PyInterpreterState *interp,
    _Py_simple_func func,
    void *arg);


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

_PyXIData_t;
xid_newobjfunc;
xid_freefunc;

// _PyXIData_t is similar to Py_buffer as an effectively
// opaque struct that holds data outside the object machinery.  This
// is necessary to pass safely between interpreters in the same process.
struct _xidata {};

PyAPI_FUNC(_PyXIData_t *) _PyXIData_New(void);
PyAPI_FUNC(void) _PyXIData_Free(_PyXIData_t *data);

#define _PyXIData_DATA(DATA)
#define _PyXIData_OBJ(DATA)
#define _PyXIData_INTERPID(DATA)
// Users should not need getters for "new_object" or "free".


/* getting cross-interpreter data */

xidatafunc;

_PyXIData_lookup_t;

_PyXIData_lookup_context_t;

PyAPI_FUNC(int) _PyXIData_GetLookupContext(
        PyInterpreterState *,
        _PyXIData_lookup_context_t *);

PyAPI_FUNC(xidatafunc) _PyXIData_Lookup(
        _PyXIData_lookup_context_t *,
        PyObject *);
PyAPI_FUNC(int) _PyObject_CheckXIData(
        _PyXIData_lookup_context_t *,
        PyObject *);
PyAPI_FUNC(int) _PyObject_GetXIData(
        _PyXIData_lookup_context_t *,
        PyObject *,
        _PyXIData_t *);


/* using cross-interpreter data */

PyAPI_FUNC(PyObject *) _PyXIData_NewObject(_PyXIData_t *);
PyAPI_FUNC(int) _PyXIData_Release(_PyXIData_t *);
PyAPI_FUNC(int) _PyXIData_ReleaseAndRawFree(_PyXIData_t *);


/* defining cross-interpreter data */

PyAPI_FUNC(void) _PyXIData_Init(
        _PyXIData_t *data,
        PyInterpreterState *interp, void *shared, PyObject *obj,
        xid_newobjfunc new_object);
PyAPI_FUNC(int) _PyXIData_InitWithSize(
        _PyXIData_t *,
        PyInterpreterState *interp, const size_t, PyObject *,
        xid_newobjfunc);
PyAPI_FUNC(void) _PyXIData_Clear( PyInterpreterState *, _PyXIData_t *);

// Normally the Init* functions are sufficient.  The only time
// additional initialization might be needed is to set the "free" func,
// though that should be infrequent.
#define _PyXIData_SET_FREE(DATA, FUNC)
// Additionally, some shareable types are essentially light wrappers
// around other shareable types.  The xidatafunc of the wrapper
// can often be implemented by calling the wrapped object's
// xidatafunc and then changing the "new_object" function.
// We have _PyXIData_SET_NEW_OBJECT() here for that,
// but might be better to have a function like
// _PyXIData_AdaptToWrapper() instead.
#define _PyXIData_SET_NEW_OBJECT(DATA, FUNC)


/* cross-interpreter data registry */

#define Py_CORE_CROSSINTERP_DATA_REGISTRY_H
#include "pycore_crossinterp_data_registry.h"
#undef Py_CORE_CROSSINTERP_DATA_REGISTRY_H


/*****************************/
/* runtime state & lifecycle */
/*****************************/

_PyXI_global_state_t;

_PyXI_state_t;

#define _PyXI_GET_GLOBAL_STATE(interp)
#define _PyXI_GET_STATE(interp)

#ifndef Py_BUILD_CORE_MODULE
extern PyStatus _PyXI_Init(PyInterpreterState *interp);
extern void _PyXI_Fini(PyInterpreterState *interp);
extern PyStatus _PyXI_InitTypes(PyInterpreterState *interp);
extern void _PyXI_FiniTypes(PyInterpreterState *interp);
#endif  // Py_BUILD_CORE_MODULE

int _Py_xi_global_state_init(_PyXI_global_state_t *);
void _Py_xi_global_state_fini(_PyXI_global_state_t *);
int _Py_xi_state_init(_PyXI_state_t *, PyInterpreterState *);
void _Py_xi_state_fini(_PyXI_state_t *, PyInterpreterState *);


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

// Ultimately we'd like to preserve enough information about the
// exception and traceback that we could re-constitute (or at least
// simulate, a la traceback.TracebackException), and even chain, a copy
// of the exception in the calling interpreter.

_PyXI_excinfo;

PyAPI_FUNC(int) _PyXI_InitExcInfo(_PyXI_excinfo *info, PyObject *exc);
PyAPI_FUNC(PyObject *) _PyXI_FormatExcInfo(_PyXI_excinfo *info);
PyAPI_FUNC(PyObject *) _PyXI_ExcInfoAsObject(_PyXI_excinfo *info);
PyAPI_FUNC(void) _PyXI_ClearExcInfo(_PyXI_excinfo *info);


_PyXI_errcode;


_PyXI_error;

PyAPI_FUNC(PyObject *) _PyXI_ApplyError(_PyXI_error *err);


_PyXI_session;
_PyXI_namespace;

PyAPI_FUNC(void) _PyXI_FreeNamespace(_PyXI_namespace *ns);
PyAPI_FUNC(_PyXI_namespace *) _PyXI_NamespaceFromNames(PyObject *names);
PyAPI_FUNC(int) _PyXI_FillNamespaceFromDict(
    _PyXI_namespace *ns,
    PyObject *nsobj,
    _PyXI_session *session);
PyAPI_FUNC(int) _PyXI_ApplyNamespace(
    _PyXI_namespace *ns,
    PyObject *nsobj,
    PyObject *dflt);


// A cross-interpreter session involves entering an interpreter
// (_PyXI_Enter()), doing some work with it, and finally exiting
// that interpreter (_PyXI_Exit()).
//
// At the boundaries of the session, both entering and exiting,
// data may be exchanged between the previous interpreter and the
// target one in a thread-safe way that does not violate the
// isolation between interpreters.  This includes setting objects
// in the target's __main__ module on the way in, and capturing
// uncaught exceptions on the way out.
struct xi_session {};

PyAPI_FUNC(int) _PyXI_Enter(
    _PyXI_session *session,
    PyInterpreterState *interp,
    PyObject *nsupdates);
PyAPI_FUNC(void) _PyXI_Exit(_PyXI_session *session);

PyAPI_FUNC(PyObject *) _PyXI_ApplyCapturedException(_PyXI_session *session);
PyAPI_FUNC(int) _PyXI_HasCapturedException(_PyXI_session *session);


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

// Export for _testinternalcapi shared extension
PyAPI_FUNC(PyInterpreterState *) _PyXI_NewInterpreter(
    PyInterpreterConfig *config,
    long *maybe_whence,
    PyThreadState **p_tstate,
    PyThreadState **p_save_tstate);
PyAPI_FUNC(void) _PyXI_EndInterpreter(
    PyInterpreterState *interp,
    PyThreadState *tstate,
    PyThreadState **p_save_tstate);


#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_CROSSINTERP_H */