@@ -713,6 +713,99 @@ _bool_shared(PyThreadState *tstate, PyObject *obj,
713713 return 0 ;
714714}
715715
716+ struct _shared_tuple_data {
717+ Py_ssize_t len ;
718+ _PyCrossInterpreterData * * data ;
719+ };
720+
721+ static PyObject *
722+ _new_tuple_object (_PyCrossInterpreterData * data )
723+ {
724+ struct _shared_tuple_data * shared = (struct _shared_tuple_data * )(data -> data );
725+ PyObject * tuple = PyTuple_New (shared -> len );
726+ if (tuple == NULL ) {
727+ return NULL ;
728+ }
729+
730+ for (Py_ssize_t i = 0 ; i < shared -> len ; i ++ ) {
731+ PyObject * item = _PyCrossInterpreterData_NewObject (shared -> data [i ]);
732+ if (item == NULL ){
733+ Py_DECREF (tuple );
734+ return NULL ;
735+ }
736+ PyTuple_SET_ITEM (tuple , i , item );
737+ }
738+ return tuple ;
739+ }
740+
741+ static void
742+ _tuple_shared_free (void * data )
743+ {
744+ struct _shared_tuple_data * shared = (struct _shared_tuple_data * )(data );
745+ #ifndef NDEBUG
746+ int64_t interpid = PyInterpreterState_GetID (_PyInterpreterState_GET ());
747+ #endif
748+ for (Py_ssize_t i = 0 ; i < shared -> len ; i ++ ) {
749+ if (shared -> data [i ] != NULL ) {
750+ assert (shared -> data [i ]-> interpid == interpid );
751+ _PyCrossInterpreterData_Release (shared -> data [i ]);
752+ PyMem_RawFree (shared -> data [i ]);
753+ shared -> data [i ] = NULL ;
754+ }
755+ }
756+ PyMem_Free (shared -> data );
757+ PyMem_RawFree (shared );
758+ }
759+
760+ static int
761+ _tuple_shared (PyThreadState * tstate , PyObject * obj ,
762+ _PyCrossInterpreterData * data )
763+ {
764+ Py_ssize_t len = PyTuple_GET_SIZE (obj );
765+ if (len < 0 ) {
766+ return -1 ;
767+ }
768+ struct _shared_tuple_data * shared = PyMem_RawMalloc (sizeof (struct _shared_tuple_data ));
769+ if (shared == NULL ){
770+ PyErr_NoMemory ();
771+ return -1 ;
772+ }
773+
774+ shared -> len = len ;
775+ shared -> data = (_PyCrossInterpreterData * * ) PyMem_Calloc (shared -> len , sizeof (_PyCrossInterpreterData * ));
776+ if (shared -> data == NULL ) {
777+ PyErr_NoMemory ();
778+ return -1 ;
779+ }
780+
781+ for (Py_ssize_t i = 0 ; i < shared -> len ; i ++ ) {
782+ _PyCrossInterpreterData * data = _PyCrossInterpreterData_New ();
783+ if (data == NULL ) {
784+ goto error ; // PyErr_NoMemory already set
785+ }
786+ PyObject * item = PyTuple_GET_ITEM (obj , i );
787+
788+ int res = -1 ;
789+ if (!_Py_EnterRecursiveCallTstate (tstate , " while sharing a tuple" )) {
790+ res = _PyObject_GetCrossInterpreterData (item , data );
791+ _Py_LeaveRecursiveCallTstate (tstate );
792+ }
793+ if (res < 0 ) {
794+ PyMem_RawFree (data );
795+ goto error ;
796+ }
797+ shared -> data [i ] = data ;
798+ }
799+ _PyCrossInterpreterData_Init (
800+ data , tstate -> interp , shared , obj , _new_tuple_object );
801+ data -> free = _tuple_shared_free ;
802+ return 0 ;
803+
804+ error :
805+ _tuple_shared_free (shared );
806+ return -1 ;
807+ }
808+
716809static void
717810_register_builtins_for_crossinterpreter_data (struct _xidregistry * xidregistry )
718811{
@@ -745,6 +838,11 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry)
745838 if (_xidregistry_add_type (xidregistry , & PyFloat_Type , _float_shared ) != 0 ) {
746839 Py_FatalError ("could not register float for cross-interpreter sharing" );
747840 }
841+
842+ // tuple
843+ if (_xidregistry_add_type (xidregistry , & PyTuple_Type , _tuple_shared ) != 0 ) {
844+ Py_FatalError ("could not register tuple for cross-interpreter sharing" );
845+ }
748846}
749847
750848/* registry lifecycle */
0 commit comments