Skip to content

Commit 530cc9d

Browse files
gh-99741: Implement Multi-Phase Init for the _xxsubinterpreters Module (gh-99742)
_xxsubinterpreters is an internal module used for testing. #99741
1 parent 51ee0a2 commit 530cc9d

File tree

6 files changed

+384
-190
lines changed

6 files changed

+384
-190
lines changed

Include/cpython/pystate.h

+18-3
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,9 @@ PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
353353
// is necessary to pass safely between interpreters in the same process.
354354
typedef struct _xid _PyCrossInterpreterData;
355355

356+
typedef PyObject *(*xid_newobjectfunc)(_PyCrossInterpreterData *);
357+
typedef void (*xid_freefunc)(void *);
358+
356359
struct _xid {
357360
// data is the cross-interpreter-safe derivation of a Python object
358361
// (see _PyObject_GetCrossInterpreterData). It will be NULL if the
@@ -379,7 +382,7 @@ struct _xid {
379382
// interpreter given the data. The resulting object (a new
380383
// reference) will be equivalent to the original object. This field
381384
// is required.
382-
PyObject *(*new_object)(_PyCrossInterpreterData *);
385+
xid_newobjectfunc new_object;
383386
// free is called when the data is released. If it is NULL then
384387
// nothing will be done to free the data. For some types this is
385388
// okay (e.g. bytes) and for those types this field should be set
@@ -389,9 +392,20 @@ struct _xid {
389392
// leak. In that case, at the very least this field should be set
390393
// to PyMem_RawFree (the default if not explicitly set to NULL).
391394
// The call will happen with the original interpreter activated.
392-
void (*free)(void *);
395+
xid_freefunc free;
393396
};
394397

398+
PyAPI_FUNC(void) _PyCrossInterpreterData_Init(
399+
_PyCrossInterpreterData *data,
400+
PyInterpreterState *interp, void *shared, PyObject *obj,
401+
xid_newobjectfunc new_object);
402+
PyAPI_FUNC(int) _PyCrossInterpreterData_InitWithSize(
403+
_PyCrossInterpreterData *,
404+
PyInterpreterState *interp, const size_t, PyObject *,
405+
xid_newobjectfunc);
406+
PyAPI_FUNC(void) _PyCrossInterpreterData_Clear(
407+
PyInterpreterState *, _PyCrossInterpreterData *);
408+
395409
PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *);
396410
PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *);
397411
PyAPI_FUNC(int) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *);
@@ -400,7 +414,8 @@ PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *);
400414

401415
/* cross-interpreter data registry */
402416

403-
typedef int (*crossinterpdatafunc)(PyObject *, _PyCrossInterpreterData *);
417+
typedef int (*crossinterpdatafunc)(PyThreadState *tstate, PyObject *,
418+
_PyCrossInterpreterData *);
404419

405420
PyAPI_FUNC(int) _PyCrossInterpreterData_RegisterClass(PyTypeObject *, crossinterpdatafunc);
406421
PyAPI_FUNC(int) _PyCrossInterpreterData_UnregisterClass(PyTypeObject *);

Lib/test/test__xxsubinterpreters.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,8 @@ def clean_up_channels():
295295
class TestBase(unittest.TestCase):
296296

297297
def tearDown(self):
298-
clean_up_interpreters()
299298
clean_up_channels()
299+
clean_up_interpreters()
300300

301301

302302
##################################
@@ -411,6 +411,15 @@ def test_non_shareable_int(self):
411411
interpreters.channel_send(self.cid, i)
412412

413413

414+
class ModuleTests(TestBase):
415+
416+
def test_import_in_interpreter(self):
417+
_run_output(
418+
interpreters.create(),
419+
'import _xxsubinterpreters as _interpreters',
420+
)
421+
422+
414423
##################################
415424
# interpreter tests
416425

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
We've implemented multi-phase init (PEP 489/630/687)
2+
for the internal (for testing) _xxsubinterpreters module.

0 commit comments

Comments
 (0)