@@ -242,6 +242,11 @@ _sharedns_apply(_sharedns *shared, PyObject *ns)
242242// of the exception in the calling interpreter.
243243
244244typedef struct _sharedexception {
245+ PyInterpreterState * interp ;
246+ #define ERR_NOT_SET 0
247+ #define ERR_NO_MEMORY 1
248+ #define ERR_ALREADY_RUNNING 2
249+ int code ;
245250 const char * name ;
246251 const char * msg ;
247252} _sharedexception ;
@@ -263,14 +268,26 @@ _sharedexception_clear(_sharedexception *exc)
263268}
264269
265270static const char *
266- _sharedexception_bind (PyObject * exc , _sharedexception * sharedexc )
271+ _sharedexception_bind (PyObject * exc , int code , _sharedexception * sharedexc )
267272{
273+ if (sharedexc -> interp == NULL ) {
274+ sharedexc -> interp = PyInterpreterState_Get ();
275+ }
276+
277+ if (code != ERR_NOT_SET ) {
278+ assert (exc == NULL );
279+ assert (code > 0 );
280+ sharedexc -> code = code ;
281+ return NULL ;
282+ }
283+
268284 assert (exc != NULL );
269285 const char * failure = NULL ;
270286
271287 PyObject * nameobj = PyUnicode_FromString (Py_TYPE (exc )-> tp_name );
272288 if (nameobj == NULL ) {
273289 failure = "unable to format exception type name" ;
290+ code = ERR_NO_MEMORY ;
274291 goto error ;
275292 }
276293 sharedexc -> name = _copy_raw_string (nameobj );
@@ -281,13 +298,15 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
281298 } else {
282299 failure = "unable to encode and copy exception type name" ;
283300 }
301+ code = ERR_NO_MEMORY ;
284302 goto error ;
285303 }
286304
287305 if (exc != NULL ) {
288306 PyObject * msgobj = PyUnicode_FromFormat ("%S" , exc );
289307 if (msgobj == NULL ) {
290308 failure = "unable to format exception message" ;
309+ code = ERR_NO_MEMORY ;
291310 goto error ;
292311 }
293312 sharedexc -> msg = _copy_raw_string (msgobj );
@@ -298,6 +317,7 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
298317 } else {
299318 failure = "unable to encode and copy exception message" ;
300319 }
320+ code = ERR_NO_MEMORY ;
301321 goto error ;
302322 }
303323 }
@@ -308,14 +328,18 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
308328 assert (failure != NULL );
309329 PyErr_Clear ();
310330 _sharedexception_clear (sharedexc );
311- * sharedexc = no_exception ;
331+ * sharedexc = (_sharedexception ){
332+ .interp = sharedexc -> interp ,
333+ .code = code ,
334+ };
312335 return failure ;
313336}
314337
315338static void
316339_sharedexception_apply (_sharedexception * exc , PyObject * wrapperclass )
317340{
318341 if (exc -> name != NULL ) {
342+ assert (exc -> code == ERR_NOT_SET );
319343 if (exc -> msg != NULL ) {
320344 PyErr_Format (wrapperclass , "%s: %s" , exc -> name , exc -> msg );
321345 }
@@ -324,9 +348,19 @@ _sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
324348 }
325349 }
326350 else if (exc -> msg != NULL ) {
351+ assert (exc -> code == ERR_NOT_SET );
327352 PyErr_SetString (wrapperclass , exc -> msg );
328353 }
354+ else if (exc -> code == ERR_NO_MEMORY ) {
355+ PyErr_NoMemory ();
356+ }
357+ else if (exc -> code == ERR_ALREADY_RUNNING ) {
358+ assert (exc -> interp != NULL );
359+ assert (_PyInterpreterState_IsRunningMain (exc -> interp ));
360+ _PyInterpreterState_FailIfRunningMain (exc -> interp );
361+ }
329362 else {
363+ assert (exc -> code == ERR_NOT_SET );
330364 PyErr_SetNone (wrapperclass );
331365 }
332366}
@@ -362,9 +396,16 @@ static int
362396_run_script (PyInterpreterState * interp , const char * codestr ,
363397 _sharedns * shared , _sharedexception * sharedexc )
364398{
399+ int errcode = ERR_NOT_SET ;
400+
365401 if (_PyInterpreterState_SetRunningMain (interp ) < 0 ) {
366- // We skip going through the shared exception.
367- return -1 ;
402+ assert (PyErr_Occurred ());
403+ // In the case where we didn't switch interpreters, it would
404+ // be more efficient to leave the exception in place and return
405+ // immediately. However, life is simpler if we don't.
406+ PyErr_Clear ();
407+ errcode = ERR_ALREADY_RUNNING ;
408+ goto error ;
368409 }
369410
370411 PyObject * excval = NULL ;
@@ -403,16 +444,17 @@ _run_script(PyInterpreterState *interp, const char *codestr,
403444
404445error :
405446 excval = PyErr_GetRaisedException ();
406- const char * failure = _sharedexception_bind (excval , sharedexc );
447+ const char * failure = _sharedexception_bind (excval , errcode , sharedexc );
407448 if (failure != NULL ) {
408449 fprintf (stderr ,
409450 "RunFailedError: script raised an uncaught exception (%s)" ,
410451 failure );
411- PyErr_Clear ();
412452 }
413453 Py_XDECREF (excval );
454+ if (errcode != ERR_ALREADY_RUNNING ) {
455+ _PyInterpreterState_SetNotRunningMain (interp );
456+ }
414457 assert (!PyErr_Occurred ());
415- _PyInterpreterState_SetNotRunningMain (interp );
416458 return -1 ;
417459}
418460
@@ -421,6 +463,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
421463 const char * codestr , PyObject * shareables )
422464{
423465 module_state * state = get_module_state (mod );
466+ assert (state != NULL );
424467
425468 _sharedns * shared = _get_shared_ns (shareables );
426469 if (shared == NULL && PyErr_Occurred ()) {
@@ -429,50 +472,30 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
429472
430473 // Switch to interpreter.
431474 PyThreadState * save_tstate = NULL ;
475+ PyThreadState * tstate = NULL ;
432476 if (interp != PyInterpreterState_Get ()) {
433- // XXX gh-109860: Using the "head" thread isn't strictly correct.
434- PyThreadState * tstate = PyInterpreterState_ThreadHead (interp );
435- assert (tstate != NULL );
436- // Hack (until gh-109860): The interpreter's initial thread state
437- // is least likely to break.
438- while (tstate -> next != NULL ) {
439- tstate = tstate -> next ;
440- }
441- // We must do this check before switching interpreters, so any
442- // exception gets raised in the right one.
443- // XXX gh-109860: Drop this redundant check once we stop
444- // re-using tstates that might already be in use.
445- if (_PyInterpreterState_IsRunningMain (interp )) {
446- PyErr_SetString (PyExc_RuntimeError ,
447- "interpreter already running" );
448- if (shared != NULL ) {
449- _sharedns_free (shared );
450- }
451- return -1 ;
452- }
477+ tstate = PyThreadState_New (interp );
478+ tstate -> _whence = _PyThreadState_WHENCE_EXEC ;
453479 // XXX Possible GILState issues?
454480 save_tstate = PyThreadState_Swap (tstate );
455481 }
456482
457483 // Run the script.
458- _sharedexception exc = { NULL , NULL };
484+ _sharedexception exc = ( _sharedexception ){ . interp = interp };
459485 int result = _run_script (interp , codestr , shared , & exc );
460486
461487 // Switch back.
462488 if (save_tstate != NULL ) {
489+ PyThreadState_Clear (tstate );
463490 PyThreadState_Swap (save_tstate );
491+ PyThreadState_Delete (tstate );
464492 }
465493
466494 // Propagate any exception out to the caller.
467- if (exc . name != NULL ) {
468- assert (state != NULL );
495+ if (result < 0 ) {
496+ assert (! PyErr_Occurred () );
469497 _sharedexception_apply (& exc , state -> RunFailedError );
470- }
471- else if (result != 0 ) {
472- if (!PyErr_Occurred ()) {
473- // We were unable to allocate a shared exception.
474- PyErr_NoMemory ();
475- }
498+ assert (PyErr_Occurred ());
476499 }
477500
478501 if (shared != NULL ) {
@@ -502,6 +525,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
502525 const PyInterpreterConfig config = isolated
503526 ? (PyInterpreterConfig )_PyInterpreterConfig_INIT
504527 : (PyInterpreterConfig )_PyInterpreterConfig_LEGACY_INIT ;
528+
505529 // XXX Possible GILState issues?
506530 PyThreadState * tstate = NULL ;
507531 PyStatus status = Py_NewInterpreterFromConfig (& tstate , & config );
@@ -517,6 +541,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
517541 return NULL ;
518542 }
519543 assert (tstate != NULL );
544+
520545 PyInterpreterState * interp = PyThreadState_GetInterpreter (tstate );
521546 PyObject * idobj = PyInterpreterState_GetIDObject (interp );
522547 if (idobj == NULL ) {
@@ -526,6 +551,10 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
526551 PyThreadState_Swap (save_tstate );
527552 return NULL ;
528553 }
554+
555+ PyThreadState_Clear (tstate );
556+ PyThreadState_Delete (tstate );
557+
529558 _PyInterpreterState_RequireIDRef (interp , 1 );
530559 return idobj ;
531560}
@@ -573,14 +602,8 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
573602 }
574603
575604 // Destroy the interpreter.
576- // XXX gh-109860: Using the "head" thread isn't strictly correct.
577- PyThreadState * tstate = PyInterpreterState_ThreadHead (interp );
578- assert (tstate != NULL );
579- // Hack (until gh-109860): The interpreter's initial thread state
580- // is least likely to break.
581- while (tstate -> next != NULL ) {
582- tstate = tstate -> next ;
583- }
605+ PyThreadState * tstate = PyThreadState_New (interp );
606+ tstate -> _whence = _PyThreadState_WHENCE_INTERP ;
584607 // XXX Possible GILState issues?
585608 PyThreadState * save_tstate = PyThreadState_Swap (tstate );
586609 Py_EndInterpreter (tstate );
0 commit comments