@@ -328,28 +328,39 @@ PyInterpreterState_GetID(PyInterpreterState *interp)
328328}
329329
330330
331- PyInterpreterState *
332- _PyInterpreterState_LookUpID (PY_INT64_T requested_id )
331+ static PyInterpreterState *
332+ interp_look_up_id (PY_INT64_T requested_id )
333333{
334- if (requested_id < 0 )
335- goto error ;
336-
337334 PyInterpreterState * interp = PyInterpreterState_Head ();
338335 while (interp != NULL ) {
339336 PY_INT64_T id = PyInterpreterState_GetID (interp );
340- if (id < 0 )
337+ if (id < 0 ) {
341338 return NULL ;
342- if (requested_id == id )
339+ }
340+ if (requested_id == id ) {
343341 return interp ;
342+ }
344343 interp = PyInterpreterState_Next (interp );
345344 }
346-
347- error :
348- PyErr_Format (PyExc_RuntimeError ,
349- "unrecognized interpreter ID %lld" , requested_id );
350345 return NULL ;
351346}
352347
348+ PyInterpreterState *
349+ _PyInterpreterState_LookUpID (PY_INT64_T requested_id )
350+ {
351+ PyInterpreterState * interp = NULL ;
352+ if (requested_id >= 0 ) {
353+ HEAD_UNLOCK ();
354+ interp = interp_look_up_id (requested_id );
355+ HEAD_UNLOCK ();
356+ }
357+ if (interp == NULL && !PyErr_Occurred ()) {
358+ PyErr_Format (PyExc_RuntimeError ,
359+ "unrecognized interpreter ID %lld" , requested_id );
360+ }
361+ return interp ;
362+ }
363+
353364
354365int
355366_PyInterpreterState_IDInitref (PyInterpreterState * interp )
@@ -1280,38 +1291,16 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
12801291 return 0 ;
12811292}
12821293
1283- static void
1294+ static int
12841295_release_xidata (void * arg )
12851296{
12861297 _PyCrossInterpreterData * data = (_PyCrossInterpreterData * )arg ;
12871298 if (data -> free != NULL ) {
12881299 data -> free (data -> data );
12891300 }
12901301 Py_XDECREF (data -> obj );
1291- }
1292-
1293- static void
1294- _call_in_interpreter (PyInterpreterState * interp ,
1295- void (* func )(void * ), void * arg )
1296- {
1297- /* We would use Py_AddPendingCall() if it weren't specific to the
1298- * main interpreter (see bpo-33608). In the meantime we take a
1299- * naive approach.
1300- */
1301- PyThreadState * save_tstate = NULL ;
1302- if (interp != _PyInterpreterState_Get ()) {
1303- // XXX Using the "head" thread isn't strictly correct.
1304- PyThreadState * tstate = PyInterpreterState_ThreadHead (interp );
1305- // XXX Possible GILState issues?
1306- save_tstate = PyThreadState_Swap (tstate );
1307- }
1308-
1309- func (arg );
1310-
1311- // Switch back.
1312- if (save_tstate != NULL ) {
1313- PyThreadState_Swap (save_tstate );
1314- }
1302+ PyMem_Free (data );
1303+ return 0 ;
13151304}
13161305
13171306void
@@ -1322,7 +1311,7 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
13221311 return ;
13231312 }
13241313
1325- // Switch to the original interpreter.
1314+ // Get the original interpreter.
13261315 PyInterpreterState * interp = _PyInterpreterState_LookUpID (data -> interp );
13271316 if (interp == NULL ) {
13281317 // The intepreter was already destroyed.
@@ -1331,10 +1320,24 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
13311320 }
13321321 return ;
13331322 }
1323+ // XXX There's an ever-so-slight race here...
1324+ if (interp -> finalizing ) {
1325+ // XXX Someone leaked some memory...
1326+ return ;
1327+ }
13341328
13351329 // "Release" the data and/or the object.
1336- // XXX Use _Py_AddPendingCall().
1337- _call_in_interpreter (interp , _release_xidata , data );
1330+ _PyCrossInterpreterData * copied = PyMem_Malloc (sizeof (_PyCrossInterpreterData ));
1331+ if (copied == NULL ) {
1332+ PyErr_SetString (PyExc_MemoryError ,
1333+ "Not enough memory to preserve cross-interpreter data" );
1334+ PyErr_Print ();
1335+ return ;
1336+ }
1337+ memcpy (copied , data , sizeof (_PyCrossInterpreterData ));
1338+ if (_Py_AddPendingCall (interp , 0 , _release_xidata , copied ) != 0 ) {
1339+ // XXX Queue full or couldn't get lock. Try again somehow?
1340+ }
13381341}
13391342
13401343PyObject *
0 commit comments