@@ -242,6 +242,11 @@ _sharedns_apply(_sharedns *shared, PyObject *ns)
242
242
// of the exception in the calling interpreter.
243
243
244
244
typedef 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 ;
245
250
const char * name ;
246
251
const char * msg ;
247
252
} _sharedexception ;
@@ -263,14 +268,26 @@ _sharedexception_clear(_sharedexception *exc)
263
268
}
264
269
265
270
static const char *
266
- _sharedexception_bind (PyObject * exc , _sharedexception * sharedexc )
271
+ _sharedexception_bind (PyObject * exc , int code , _sharedexception * sharedexc )
267
272
{
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
+
268
284
assert (exc != NULL );
269
285
const char * failure = NULL ;
270
286
271
287
PyObject * nameobj = PyUnicode_FromString (Py_TYPE (exc )-> tp_name );
272
288
if (nameobj == NULL ) {
273
289
failure = "unable to format exception type name" ;
290
+ code = ERR_NO_MEMORY ;
274
291
goto error ;
275
292
}
276
293
sharedexc -> name = _copy_raw_string (nameobj );
@@ -281,13 +298,15 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
281
298
} else {
282
299
failure = "unable to encode and copy exception type name" ;
283
300
}
301
+ code = ERR_NO_MEMORY ;
284
302
goto error ;
285
303
}
286
304
287
305
if (exc != NULL ) {
288
306
PyObject * msgobj = PyUnicode_FromFormat ("%S" , exc );
289
307
if (msgobj == NULL ) {
290
308
failure = "unable to format exception message" ;
309
+ code = ERR_NO_MEMORY ;
291
310
goto error ;
292
311
}
293
312
sharedexc -> msg = _copy_raw_string (msgobj );
@@ -298,6 +317,7 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
298
317
} else {
299
318
failure = "unable to encode and copy exception message" ;
300
319
}
320
+ code = ERR_NO_MEMORY ;
301
321
goto error ;
302
322
}
303
323
}
@@ -308,14 +328,18 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
308
328
assert (failure != NULL );
309
329
PyErr_Clear ();
310
330
_sharedexception_clear (sharedexc );
311
- * sharedexc = no_exception ;
331
+ * sharedexc = (_sharedexception ){
332
+ .interp = sharedexc -> interp ,
333
+ .code = code ,
334
+ };
312
335
return failure ;
313
336
}
314
337
315
338
static void
316
339
_sharedexception_apply (_sharedexception * exc , PyObject * wrapperclass )
317
340
{
318
341
if (exc -> name != NULL ) {
342
+ assert (exc -> code == ERR_NOT_SET );
319
343
if (exc -> msg != NULL ) {
320
344
PyErr_Format (wrapperclass , "%s: %s" , exc -> name , exc -> msg );
321
345
}
@@ -324,9 +348,19 @@ _sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
324
348
}
325
349
}
326
350
else if (exc -> msg != NULL ) {
351
+ assert (exc -> code == ERR_NOT_SET );
327
352
PyErr_SetString (wrapperclass , exc -> msg );
328
353
}
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
+ }
329
362
else {
363
+ assert (exc -> code == ERR_NOT_SET );
330
364
PyErr_SetNone (wrapperclass );
331
365
}
332
366
}
@@ -362,9 +396,16 @@ static int
362
396
_run_script (PyInterpreterState * interp , const char * codestr ,
363
397
_sharedns * shared , _sharedexception * sharedexc )
364
398
{
399
+ int errcode = ERR_NOT_SET ;
400
+
365
401
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 ;
368
409
}
369
410
370
411
PyObject * excval = NULL ;
@@ -403,16 +444,17 @@ _run_script(PyInterpreterState *interp, const char *codestr,
403
444
404
445
error :
405
446
excval = PyErr_GetRaisedException ();
406
- const char * failure = _sharedexception_bind (excval , sharedexc );
447
+ const char * failure = _sharedexception_bind (excval , errcode , sharedexc );
407
448
if (failure != NULL ) {
408
449
fprintf (stderr ,
409
450
"RunFailedError: script raised an uncaught exception (%s)" ,
410
451
failure );
411
- PyErr_Clear ();
412
452
}
413
453
Py_XDECREF (excval );
454
+ if (errcode != ERR_ALREADY_RUNNING ) {
455
+ _PyInterpreterState_SetNotRunningMain (interp );
456
+ }
414
457
assert (!PyErr_Occurred ());
415
- _PyInterpreterState_SetNotRunningMain (interp );
416
458
return -1 ;
417
459
}
418
460
@@ -421,6 +463,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
421
463
const char * codestr , PyObject * shareables )
422
464
{
423
465
module_state * state = get_module_state (mod );
466
+ assert (state != NULL );
424
467
425
468
_sharedns * shared = _get_shared_ns (shareables );
426
469
if (shared == NULL && PyErr_Occurred ()) {
@@ -429,50 +472,30 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
429
472
430
473
// Switch to interpreter.
431
474
PyThreadState * save_tstate = NULL ;
475
+ PyThreadState * tstate = NULL ;
432
476
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 ;
453
479
// XXX Possible GILState issues?
454
480
save_tstate = PyThreadState_Swap (tstate );
455
481
}
456
482
457
483
// Run the script.
458
- _sharedexception exc = { NULL , NULL };
484
+ _sharedexception exc = ( _sharedexception ){ . interp = interp };
459
485
int result = _run_script (interp , codestr , shared , & exc );
460
486
461
487
// Switch back.
462
488
if (save_tstate != NULL ) {
489
+ PyThreadState_Clear (tstate );
463
490
PyThreadState_Swap (save_tstate );
491
+ PyThreadState_Delete (tstate );
464
492
}
465
493
466
494
// Propagate any exception out to the caller.
467
- if (exc . name != NULL ) {
468
- assert (state != NULL );
495
+ if (result < 0 ) {
496
+ assert (! PyErr_Occurred () );
469
497
_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 ());
476
499
}
477
500
478
501
if (shared != NULL ) {
@@ -502,6 +525,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
502
525
const PyInterpreterConfig config = isolated
503
526
? (PyInterpreterConfig )_PyInterpreterConfig_INIT
504
527
: (PyInterpreterConfig )_PyInterpreterConfig_LEGACY_INIT ;
528
+
505
529
// XXX Possible GILState issues?
506
530
PyThreadState * tstate = NULL ;
507
531
PyStatus status = Py_NewInterpreterFromConfig (& tstate , & config );
@@ -517,6 +541,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
517
541
return NULL ;
518
542
}
519
543
assert (tstate != NULL );
544
+
520
545
PyInterpreterState * interp = PyThreadState_GetInterpreter (tstate );
521
546
PyObject * idobj = PyInterpreterState_GetIDObject (interp );
522
547
if (idobj == NULL ) {
@@ -526,6 +551,10 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
526
551
PyThreadState_Swap (save_tstate );
527
552
return NULL ;
528
553
}
554
+
555
+ PyThreadState_Clear (tstate );
556
+ PyThreadState_Delete (tstate );
557
+
529
558
_PyInterpreterState_RequireIDRef (interp , 1 );
530
559
return idobj ;
531
560
}
@@ -573,14 +602,8 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
573
602
}
574
603
575
604
// 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 ;
584
607
// XXX Possible GILState issues?
585
608
PyThreadState * save_tstate = PyThreadState_Swap (tstate );
586
609
Py_EndInterpreter (tstate );
0 commit comments