@@ -250,6 +250,11 @@ _sharedns_apply(_sharedns *shared, PyObject *ns)
250250// of the exception in the calling interpreter.
251251
252252typedef struct _sharedexception {
253+ PyInterpreterState * interp ;
254+ #define ERR_NOT_SET 0
255+ #define ERR_NO_MEMORY 1
256+ #define ERR_ALREADY_RUNNING 2
257+ int code ;
253258 const char * name ;
254259 const char * msg ;
255260} _sharedexception ;
@@ -271,14 +276,26 @@ _sharedexception_clear(_sharedexception *exc)
271276}
272277
273278static const char *
274- _sharedexception_bind (PyObject * exc , _sharedexception * sharedexc )
279+ _sharedexception_bind (PyObject * exc , int code , _sharedexception * sharedexc )
275280{
281+ if (sharedexc -> interp == NULL ) {
282+ sharedexc -> interp = PyInterpreterState_Get ();
283+ }
284+
285+ if (code != ERR_NOT_SET ) {
286+ assert (exc == NULL );
287+ assert (code > 0 );
288+ sharedexc -> code = code ;
289+ return NULL ;
290+ }
291+
276292 assert (exc != NULL );
277293 const char * failure = NULL ;
278294
279295 PyObject * nameobj = PyUnicode_FromFormat ("%S" , Py_TYPE (exc ));
280296 if (nameobj == NULL ) {
281297 failure = "unable to format exception type name" ;
298+ code = ERR_NO_MEMORY ;
282299 goto error ;
283300 }
284301 sharedexc -> name = _copy_raw_string (nameobj );
@@ -289,13 +306,15 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
289306 } else {
290307 failure = "unable to encode and copy exception type name" ;
291308 }
309+ code = ERR_NO_MEMORY ;
292310 goto error ;
293311 }
294312
295313 if (exc != NULL ) {
296314 PyObject * msgobj = PyUnicode_FromFormat ("%S" , exc );
297315 if (msgobj == NULL ) {
298316 failure = "unable to format exception message" ;
317+ code = ERR_NO_MEMORY ;
299318 goto error ;
300319 }
301320 sharedexc -> msg = _copy_raw_string (msgobj );
@@ -306,6 +325,7 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
306325 } else {
307326 failure = "unable to encode and copy exception message" ;
308327 }
328+ code = ERR_NO_MEMORY ;
309329 goto error ;
310330 }
311331 }
@@ -316,14 +336,18 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
316336 assert (failure != NULL );
317337 PyErr_Clear ();
318338 _sharedexception_clear (sharedexc );
319- * sharedexc = no_exception ;
339+ * sharedexc = (_sharedexception ){
340+ .interp = sharedexc -> interp ,
341+ .code = code ,
342+ };
320343 return failure ;
321344}
322345
323346static void
324347_sharedexception_apply (_sharedexception * exc , PyObject * wrapperclass )
325348{
326349 if (exc -> name != NULL ) {
350+ assert (exc -> code == ERR_NOT_SET );
327351 if (exc -> msg != NULL ) {
328352 PyErr_Format (wrapperclass , "%s: %s" , exc -> name , exc -> msg );
329353 }
@@ -332,9 +356,19 @@ _sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
332356 }
333357 }
334358 else if (exc -> msg != NULL ) {
359+ assert (exc -> code == ERR_NOT_SET );
335360 PyErr_SetString (wrapperclass , exc -> msg );
336361 }
362+ else if (exc -> code == ERR_NO_MEMORY ) {
363+ PyErr_NoMemory ();
364+ }
365+ else if (exc -> code == ERR_ALREADY_RUNNING ) {
366+ assert (exc -> interp != NULL );
367+ assert (_PyInterpreterState_IsRunningMain (exc -> interp ));
368+ _PyInterpreterState_FailIfRunningMain (exc -> interp );
369+ }
337370 else {
371+ assert (exc -> code == ERR_NOT_SET );
338372 PyErr_SetNone (wrapperclass );
339373 }
340374}
@@ -370,9 +404,16 @@ static int
370404_run_script (PyInterpreterState * interp , const char * codestr ,
371405 _sharedns * shared , _sharedexception * sharedexc )
372406{
407+ int errcode = ERR_NOT_SET ;
408+
373409 if (_PyInterpreterState_SetRunningMain (interp ) < 0 ) {
374- // We skip going through the shared exception.
375- return -1 ;
410+ assert (PyErr_Occurred ());
411+ // In the case where we didn't switch interpreters, it would
412+ // be more efficient to leave the exception in place and return
413+ // immediately. However, life is simpler if we don't.
414+ PyErr_Clear ();
415+ errcode = ERR_ALREADY_RUNNING ;
416+ goto error ;
376417 }
377418
378419 PyObject * excval = NULL ;
@@ -411,16 +452,17 @@ _run_script(PyInterpreterState *interp, const char *codestr,
411452
412453error :
413454 excval = PyErr_GetRaisedException ();
414- const char * failure = _sharedexception_bind (excval , sharedexc );
455+ const char * failure = _sharedexception_bind (excval , errcode , sharedexc );
415456 if (failure != NULL ) {
416457 fprintf (stderr ,
417458 "RunFailedError: script raised an uncaught exception (%s)" ,
418459 failure );
419- PyErr_Clear ();
420460 }
421461 Py_XDECREF (excval );
462+ if (errcode != ERR_ALREADY_RUNNING ) {
463+ _PyInterpreterState_SetNotRunningMain (interp );
464+ }
422465 assert (!PyErr_Occurred ());
423- _PyInterpreterState_SetNotRunningMain (interp );
424466 return -1 ;
425467}
426468
@@ -429,6 +471,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
429471 const char * codestr , PyObject * shareables )
430472{
431473 module_state * state = get_module_state (mod );
474+ assert (state != NULL );
432475
433476 _sharedns * shared = _get_shared_ns (shareables );
434477 if (shared == NULL && PyErr_Occurred ()) {
@@ -437,50 +480,30 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
437480
438481 // Switch to interpreter.
439482 PyThreadState * save_tstate = NULL ;
483+ PyThreadState * tstate = NULL ;
440484 if (interp != PyInterpreterState_Get ()) {
441- // XXX gh-109860: Using the "head" thread isn't strictly correct.
442- PyThreadState * tstate = PyInterpreterState_ThreadHead (interp );
443- assert (tstate != NULL );
444- // Hack (until gh-109860): The interpreter's initial thread state
445- // is least likely to break.
446- while (tstate -> next != NULL ) {
447- tstate = tstate -> next ;
448- }
449- // We must do this check before switching interpreters, so any
450- // exception gets raised in the right one.
451- // XXX gh-109860: Drop this redundant check once we stop
452- // re-using tstates that might already be in use.
453- if (_PyInterpreterState_IsRunningMain (interp )) {
454- PyErr_SetString (PyExc_RuntimeError ,
455- "interpreter already running" );
456- if (shared != NULL ) {
457- _sharedns_free (shared );
458- }
459- return -1 ;
460- }
485+ tstate = PyThreadState_New (interp );
486+ tstate -> _whence = _PyThreadState_WHENCE_EXEC ;
461487 // XXX Possible GILState issues?
462488 save_tstate = PyThreadState_Swap (tstate );
463489 }
464490
465491 // Run the script.
466- _sharedexception exc = { NULL , NULL };
492+ _sharedexception exc = ( _sharedexception ){ . interp = interp };
467493 int result = _run_script (interp , codestr , shared , & exc );
468494
469495 // Switch back.
470496 if (save_tstate != NULL ) {
497+ PyThreadState_Clear (tstate );
471498 PyThreadState_Swap (save_tstate );
499+ PyThreadState_Delete (tstate );
472500 }
473501
474502 // Propagate any exception out to the caller.
475- if (exc . name != NULL ) {
476- assert (state != NULL );
503+ if (result < 0 ) {
504+ assert (! PyErr_Occurred () );
477505 _sharedexception_apply (& exc , state -> RunFailedError );
478- }
479- else if (result != 0 ) {
480- if (!PyErr_Occurred ()) {
481- // We were unable to allocate a shared exception.
482- PyErr_NoMemory ();
483- }
506+ assert (PyErr_Occurred ());
484507 }
485508
486509 if (shared != NULL ) {
@@ -510,6 +533,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
510533 const PyInterpreterConfig config = isolated
511534 ? (PyInterpreterConfig )_PyInterpreterConfig_INIT
512535 : (PyInterpreterConfig )_PyInterpreterConfig_LEGACY_INIT ;
536+
513537 // XXX Possible GILState issues?
514538 PyThreadState * tstate = NULL ;
515539 PyStatus status = Py_NewInterpreterFromConfig (& tstate , & config );
@@ -525,6 +549,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
525549 return NULL ;
526550 }
527551 assert (tstate != NULL );
552+
528553 PyInterpreterState * interp = PyThreadState_GetInterpreter (tstate );
529554 PyObject * idobj = _PyInterpreterState_GetIDObject (interp );
530555 if (idobj == NULL ) {
@@ -534,6 +559,10 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
534559 PyThreadState_Swap (save_tstate );
535560 return NULL ;
536561 }
562+
563+ PyThreadState_Clear (tstate );
564+ PyThreadState_Delete (tstate );
565+
537566 _PyInterpreterState_RequireIDRef (interp , 1 );
538567 return idobj ;
539568}
@@ -581,14 +610,8 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
581610 }
582611
583612 // Destroy the interpreter.
584- // XXX gh-109860: Using the "head" thread isn't strictly correct.
585- PyThreadState * tstate = PyInterpreterState_ThreadHead (interp );
586- assert (tstate != NULL );
587- // Hack (until gh-109860): The interpreter's initial thread state
588- // is least likely to break.
589- while (tstate -> next != NULL ) {
590- tstate = tstate -> next ;
591- }
613+ PyThreadState * tstate = PyThreadState_New (interp );
614+ tstate -> _whence = _PyThreadState_WHENCE_INTERP ;
592615 // XXX Possible GILState issues?
593616 PyThreadState * save_tstate = PyThreadState_Swap (tstate );
594617 Py_EndInterpreter (tstate );
0 commit comments