@@ -8,6 +8,8 @@ extern "C" {
88# error "this header requires Py_BUILD_CORE define"
99#endif
1010
11+ #include "pycore_pyerrors.h"
12+
1113
1214/***************************/
1315/* cross-interpreter calls */
@@ -124,6 +126,8 @@ struct _xidregitem {
124126};
125127
126128struct _xidregistry {
129+ int global ; /* builtin types or heap types */
130+ int initialized ;
127131 PyThread_type_lock mutex ;
128132 struct _xidregitem * head ;
129133};
@@ -133,6 +137,130 @@ PyAPI_FUNC(int) _PyCrossInterpreterData_UnregisterClass(PyTypeObject *);
133137PyAPI_FUNC (crossinterpdatafunc ) _PyCrossInterpreterData_Lookup (PyObject * );
134138
135139
140+ /*****************************/
141+ /* runtime state & lifecycle */
142+ /*****************************/
143+
144+ struct _xi_runtime_state {
145+ // builtin types
146+ // XXX Remove this field once we have a tp_* slot.
147+ struct _xidregistry registry ;
148+ };
149+
150+ struct _xi_state {
151+ // heap types
152+ // XXX Remove this field once we have a tp_* slot.
153+ struct _xidregistry registry ;
154+
155+ // heap types
156+ PyObject * PyExc_NotShareableError ;
157+ };
158+
159+ extern PyStatus _PyXI_Init (PyInterpreterState * interp );
160+ extern void _PyXI_Fini (PyInterpreterState * interp );
161+
162+
163+ /***************************/
164+ /* short-term data sharing */
165+ /***************************/
166+
167+ typedef enum error_code {
168+ _PyXI_ERR_NO_ERROR = 0 ,
169+ _PyXI_ERR_UNCAUGHT_EXCEPTION = -1 ,
170+ _PyXI_ERR_OTHER = -2 ,
171+ _PyXI_ERR_NO_MEMORY = -3 ,
172+ _PyXI_ERR_ALREADY_RUNNING = -4 ,
173+ _PyXI_ERR_MAIN_NS_FAILURE = -5 ,
174+ _PyXI_ERR_APPLY_NS_FAILURE = -6 ,
175+ _PyXI_ERR_NOT_SHAREABLE = -7 ,
176+ } _PyXI_errcode ;
177+
178+
179+ typedef struct _sharedexception {
180+ // The originating interpreter.
181+ PyInterpreterState * interp ;
182+ // The kind of error to propagate.
183+ _PyXI_errcode code ;
184+ // The exception information to propagate, if applicable.
185+ // This is populated only for _PyXI_ERR_UNCAUGHT_EXCEPTION.
186+ _Py_excinfo uncaught ;
187+ } _PyXI_exception_info ;
188+
189+ PyAPI_FUNC (void ) _PyXI_ApplyExceptionInfo (
190+ _PyXI_exception_info * info ,
191+ PyObject * exctype );
192+
193+ typedef struct xi_session _PyXI_session ;
194+ typedef struct _sharedns _PyXI_namespace ;
195+
196+ PyAPI_FUNC (void ) _PyXI_FreeNamespace (_PyXI_namespace * ns );
197+ PyAPI_FUNC (_PyXI_namespace * ) _PyXI_NamespaceFromNames (PyObject * names );
198+ PyAPI_FUNC (int ) _PyXI_FillNamespaceFromDict (
199+ _PyXI_namespace * ns ,
200+ PyObject * nsobj ,
201+ _PyXI_session * session );
202+ PyAPI_FUNC (int ) _PyXI_ApplyNamespace (
203+ _PyXI_namespace * ns ,
204+ PyObject * nsobj ,
205+ PyObject * dflt );
206+
207+
208+ // A cross-interpreter session involves entering an interpreter
209+ // (_PyXI_Enter()), doing some work with it, and finally exiting
210+ // that interpreter (_PyXI_Exit()).
211+ //
212+ // At the boundaries of the session, both entering and exiting,
213+ // data may be exchanged between the previous interpreter and the
214+ // target one in a thread-safe way that does not violate the
215+ // isolation between interpreters. This includes setting objects
216+ // in the target's __main__ module on the way in, and capturing
217+ // uncaught exceptions on the way out.
218+ struct xi_session {
219+ // Once a session has been entered, this is the tstate that was
220+ // current before the session. If it is different from cur_tstate
221+ // then we must have switched interpreters. Either way, this will
222+ // be the current tstate once we exit the session.
223+ PyThreadState * prev_tstate ;
224+ // Once a session has been entered, this is the current tstate.
225+ // It must be current when the session exits.
226+ PyThreadState * init_tstate ;
227+ // This is true if init_tstate needs cleanup during exit.
228+ int own_init_tstate ;
229+
230+ // This is true if, while entering the session, init_thread took
231+ // "ownership" of the interpreter's __main__ module. This means
232+ // it is the only thread that is allowed to run code there.
233+ // (Caveat: for now, users may still run exec() against the
234+ // __main__ module's dict, though that isn't advisable.)
235+ int running ;
236+ // This is a cached reference to the __dict__ of the entered
237+ // interpreter's __main__ module. It is looked up when at the
238+ // beginning of the session as a convenience.
239+ PyObject * main_ns ;
240+
241+ // This is set if the interpreter is entered and raised an exception
242+ // that needs to be handled in some special way during exit.
243+ _PyXI_errcode * exc_override ;
244+ // This is set if exit captured an exception to propagate.
245+ _PyXI_exception_info * exc ;
246+
247+ // -- pre-allocated memory --
248+ _PyXI_exception_info _exc ;
249+ _PyXI_errcode _exc_override ;
250+ };
251+
252+ PyAPI_FUNC (int ) _PyXI_Enter (
253+ _PyXI_session * session ,
254+ PyInterpreterState * interp ,
255+ PyObject * nsupdates );
256+ PyAPI_FUNC (void ) _PyXI_Exit (_PyXI_session * session );
257+
258+ PyAPI_FUNC (void ) _PyXI_ApplyCapturedException (
259+ _PyXI_session * session ,
260+ PyObject * excwrapper );
261+ PyAPI_FUNC (int ) _PyXI_HasCapturedException (_PyXI_session * session );
262+
263+
136264#ifdef __cplusplus
137265}
138266#endif
0 commit comments