@@ -8,6 +8,8 @@ extern "C" {
8
8
# error "this header requires Py_BUILD_CORE define"
9
9
#endif
10
10
11
+ #include "pycore_pyerrors.h"
12
+
11
13
12
14
/***************************/
13
15
/* cross-interpreter calls */
@@ -124,6 +126,8 @@ struct _xidregitem {
124
126
};
125
127
126
128
struct _xidregistry {
129
+ int global ; /* builtin types or heap types */
130
+ int initialized ;
127
131
PyThread_type_lock mutex ;
128
132
struct _xidregitem * head ;
129
133
};
@@ -133,6 +137,130 @@ PyAPI_FUNC(int) _PyCrossInterpreterData_UnregisterClass(PyTypeObject *);
133
137
PyAPI_FUNC (crossinterpdatafunc ) _PyCrossInterpreterData_Lookup (PyObject * );
134
138
135
139
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
+
136
264
#ifdef __cplusplus
137
265
}
138
266
#endif
0 commit comments