@@ -432,7 +432,6 @@ struct interp_call {
432432 _PyXIData_t * func ;
433433 _PyXIData_t * args ;
434434 _PyXIData_t * kwargs ;
435- _PyXIData_t * result ; // dynamically allocated
436435 struct {
437436 _PyXIData_t func ;
438437 _PyXIData_t args ;
@@ -454,64 +453,6 @@ _interp_call_clear(struct interp_call *call)
454453 if (temp .kwargs != NULL ) {
455454 _PyXIData_Clear (NULL , temp .kwargs );
456455 }
457- if (temp .result != NULL ) {
458- (void )_PyXIData_ReleaseAndRawFree (temp .result );
459- }
460- }
461-
462- static int
463- _interp_call_init_result (struct interp_call * call )
464- {
465- call -> result = _PyXIData_New ();
466- return (call -> result == NULL ) ? -1 : 0 ;
467- }
468-
469- static void
470- _interp_call_clear_result (struct interp_call * call )
471- {
472- _PyXIData_t * xidata = call -> result ;
473- if (xidata == NULL ) {
474- return ;
475- }
476- call -> result = NULL ;
477- _PyXIData_Clear (NULL , xidata );
478- _PyXIData_Release (xidata );
479- PyMem_RawFree (xidata );
480- }
481-
482- static int
483- _interp_call_clear_result_immediately (PyThreadState * tstate ,
484- struct interp_call * call ,
485- PyInterpreterState * interp )
486- {
487- _PyXIData_t * xidata = call -> result ;
488- if (xidata == NULL ) {
489- return 0 ;
490- }
491- assert (tstate == _PyThreadState_GET ());
492- assert (interp != NULL );
493- assert (interp == _PyInterpreterState_LookUpID (_PyXIData_INTERPID (xidata )));
494- if (tstate -> interp == interp ) {
495- // There's no need to switch interpreters.
496- _interp_call_clear_result (call );
497- return 0 ;
498- }
499-
500- // It's from a different interpreter.
501- PyThreadState * temp_tstate =
502- _PyThreadState_NewBound (interp , _PyThreadState_WHENCE_EXEC );
503- if (temp_tstate == NULL ) {
504- return -1 ;
505- }
506- PyThreadState * save_tstate = PyThreadState_Swap (temp_tstate );
507- assert (save_tstate == tstate );
508-
509- _interp_call_clear_result (call );
510-
511- PyThreadState_Clear (temp_tstate );
512- (void )PyThreadState_Swap (save_tstate );
513- PyThreadState_Delete (temp_tstate );
514- return 0 ;
515456}
516457
517458static int
@@ -522,7 +463,6 @@ _interp_call_pack(PyThreadState *tstate, struct interp_call *call,
522463 assert (call -> func == NULL );
523464 assert (call -> args == NULL );
524465 assert (call -> kwargs == NULL );
525- assert (call -> result == NULL );
526466 // Handle the func.
527467 if (!PyCallable_Check (func )) {
528468 _PyErr_Format (tstate , PyExc_TypeError ,
@@ -571,34 +511,11 @@ _interp_call_pack(PyThreadState *tstate, struct interp_call *call,
571511 return 0 ;
572512}
573513
574- static PyObject *
575- _interp_call_pop_result (PyThreadState * tstate , struct interp_call * call ,
576- PyInterpreterState * interp )
577- {
578- assert (tstate == _PyThreadState_GET ());
579- assert (!_PyErr_Occurred (tstate ));
580- assert (call -> result != NULL );
581- PyObject * res = _PyXIData_NewObject (call -> result );
582- PyObject * exc = _PyErr_GetRaisedException (tstate );
583-
584- if (_interp_call_clear_result_immediately (tstate , call , interp ) < 0 ) {
585- // We couldn't do it immediately, so we fall back to adding
586- // a pending call. If this fails then there are other,
587- // bigger problems.
588- (int )_PyXIData_ReleaseAndRawFree (call -> result );
589- call -> result = NULL ;
590- }
591-
592- _PyErr_SetRaisedException (tstate , exc );
593- return res ;
594- }
595-
596514static int
597- _make_call (struct interp_call * call )
515+ _make_call (struct interp_call * call , PyObject * * p_result )
598516{
599517 assert (call != NULL && call -> func != NULL );
600518 int res = -1 ;
601- PyThreadState * tstate = _PyThreadState_GET ();
602519 PyObject * args = NULL ;
603520 PyObject * kwargs = NULL ;
604521 PyObject * resobj = NULL ;
@@ -629,22 +546,12 @@ _make_call(struct interp_call *call)
629546 }
630547 assert (PyDict_Check (kwargs ));
631548 }
632- // Prepare call->result.
633- if (_interp_call_init_result (call ) < 0 ) {
634- goto finally ;
635- }
636549 // Make the call.
637550 resobj = PyObject_Call (func , args , kwargs );
638551 if (resobj == NULL ) {
639- _interp_call_clear_result (call );
640- goto finally ;
641- }
642- // Pack the result.
643- xidata_fallback_t fallback = _PyXIDATA_FULL_FALLBACK ;
644- if (_PyObject_GetXIData (tstate , resobj , fallback , call -> result ) < 0 ) {
645- _interp_call_clear_result (call );
646552 goto finally ;
647553 }
554+ * p_result = resobj ;
648555 res = 0 ;
649556
650557finally :
@@ -671,19 +578,32 @@ _run_script(_PyXIData_t *script, PyObject *ns)
671578 return 0 ;
672579}
673580
581+ struct run_result {
582+ PyObject * result ;
583+ PyObject * excinfo ;
584+ };
585+
586+ static void
587+ _run_result_clear (struct run_result * runres )
588+ {
589+ Py_CLEAR (runres -> result );
590+ Py_CLEAR (runres -> excinfo );
591+ }
592+
674593static int
675594_run_in_interpreter (PyThreadState * tstate , PyInterpreterState * interp ,
676595 _PyXIData_t * script , struct interp_call * call ,
677- PyObject * shareables , _PyXI_session_result * result )
596+ PyObject * shareables , struct run_result * runres )
678597{
679598 assert (!_PyErr_Occurred (tstate ));
680599 _PyXI_session * session = _PyXI_NewSession ();
681600 if (session == NULL ) {
682601 return -1 ;
683602 }
603+ _PyXI_session_result result = {0 };
684604
685605 // Prep and switch interpreters.
686- if (_PyXI_Enter (session , interp , shareables , result ) < 0 ) {
606+ if (_PyXI_Enter (session , interp , shareables , & result ) < 0 ) {
687607 // If an error occured at this step, it means that interp
688608 // was not prepared and switched.
689609 _PyXI_FreeSession (session );
@@ -692,7 +612,6 @@ _run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
692612
693613 int res = -1 ;
694614 if (script != NULL ) {
695- // Run the script.
696615 assert (call == NULL );
697616 PyObject * mainns = _PyXI_GetMainNamespace (session );
698617 if (mainns == NULL ) {
@@ -702,13 +621,31 @@ _run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
702621 }
703622 else {
704623 assert (call != NULL );
705- res = _make_call (call );
624+ PyObject * resobj ;
625+ res = _make_call (call , & resobj );
626+ if (res == 0 ) {
627+ (void )_PyXI_Preserve (session , "resobj" , resobj );
628+ Py_DECREF (resobj );
629+ }
706630 }
707631
708632finally :
709633 // Clean up and switch back.
710- (void )_PyXI_Exit (session , result );
634+ (void )_PyXI_Exit (session , & result );
711635 _PyXI_FreeSession (session );
636+ if (res < 0 ) {
637+ runres -> excinfo = result .excinfo ;
638+ }
639+ else if (result .excinfo != NULL ) {
640+ runres -> excinfo = result .excinfo ;
641+ res = -1 ;
642+ }
643+ else {
644+ runres -> result = _PyXI_GetPreserved (& result , "resobj" );
645+ if (_PyErr_Occurred (tstate )) {
646+ res = -1 ;
647+ }
648+ }
712649 return res ;
713650}
714651
@@ -1137,13 +1074,13 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
11371074 return NULL ;
11381075 }
11391076
1140- _PyXI_session_result result = {0 };
1077+ struct run_result runres = {0 };
11411078 int res = _run_in_interpreter (
1142- tstate , interp , & xidata , NULL , shared , & result );
1079+ tstate , interp , & xidata , NULL , shared , & runres );
11431080 _PyXIData_Release (& xidata );
11441081 if (res < 0 ) {
1145- assert ((result .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1146- return result .excinfo ;
1082+ assert ((runres .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1083+ return runres .excinfo ;
11471084 }
11481085 Py_RETURN_NONE ;
11491086#undef FUNCNAME
@@ -1201,13 +1138,13 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
12011138 return NULL ;
12021139 }
12031140
1204- _PyXI_session_result result = {0 };
1141+ struct run_result runres = {0 };
12051142 int res = _run_in_interpreter (
1206- tstate , interp , & xidata , NULL , shared , & result );
1143+ tstate , interp , & xidata , NULL , shared , & runres );
12071144 _PyXIData_Release (& xidata );
12081145 if (res < 0 ) {
1209- assert ((result .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1210- return result .excinfo ;
1146+ assert ((runres .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1147+ return runres .excinfo ;
12111148 }
12121149 Py_RETURN_NONE ;
12131150#undef FUNCNAME
@@ -1264,13 +1201,13 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
12641201 return NULL ;
12651202 }
12661203
1267- _PyXI_session_result result = {0 };
1204+ struct run_result runres = {0 };
12681205 int res = _run_in_interpreter (
1269- tstate , interp , & xidata , NULL , shared , & result );
1206+ tstate , interp , & xidata , NULL , shared , & runres );
12701207 _PyXIData_Release (& xidata );
12711208 if (res < 0 ) {
1272- assert ((result .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1273- return result .excinfo ;
1209+ assert ((runres .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1210+ return runres .excinfo ;
12741211 }
12751212 Py_RETURN_NONE ;
12761213#undef FUNCNAME
@@ -1291,17 +1228,18 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
12911228#define FUNCNAME MODULE_NAME_STR ".call"
12921229 PyThreadState * tstate = _PyThreadState_GET ();
12931230 static char * kwlist [] = {"id" , "callable" , "args" , "kwargs" ,
1294- "restrict" , NULL };
1231+ "preserve_exc" , " restrict" , NULL };
12951232 PyObject * id , * callable ;
12961233 PyObject * args_obj = NULL ;
12971234 PyObject * kwargs_obj = NULL ;
1235+ int preserve_exc = 0 ;
12981236 int restricted = 0 ;
12991237 if (!PyArg_ParseTupleAndKeywords (args , kwds ,
1300- "OO|O!O!$p :" FUNCNAME , kwlist ,
1238+ "OO|O!O!$pp :" FUNCNAME , kwlist ,
13011239 & id , & callable ,
13021240 & PyTuple_Type , & args_obj ,
13031241 & PyDict_Type , & kwargs_obj ,
1304- & restricted ))
1242+ & preserve_exc , & restricted ))
13051243 {
13061244 return NULL ;
13071245 }
@@ -1319,31 +1257,22 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
13191257 }
13201258
13211259 PyObject * res_and_exc = NULL ;
1322- _PyXI_session_result result = {0 };
1323- if (_run_in_interpreter (tstate , interp , NULL , & call , NULL , & result ) < 0 ) {
1324- assert (result .preserved == NULL );
1325- if (result .excinfo == NULL ) {
1260+ struct run_result runres = {0 };
1261+ if (_run_in_interpreter (tstate , interp , NULL , & call , NULL , & runres ) < 0 ) {
1262+ if (runres .excinfo == NULL ) {
13261263 assert (_PyErr_Occurred (tstate ));
13271264 goto finally ;
13281265 }
13291266 assert (!_PyErr_Occurred (tstate ));
1330- assert (call .result == NULL );
1331- res_and_exc = Py_BuildValue ("OO" , Py_None , result .excinfo );
1332- Py_CLEAR (result .excinfo );
1333- }
1334- else {
1335- assert (result .preserved == NULL );
1336- assert (result .excinfo == NULL );
1337- PyObject * res = _interp_call_pop_result (tstate , & call , interp );
1338- if (res == NULL ) {
1339- goto finally ;
1340- }
1341- res_and_exc = Py_BuildValue ("OO" , res , Py_None );
1342- Py_DECREF (res );
13431267 }
1268+ assert (runres .result == NULL || runres .excinfo == NULL );
1269+ res_and_exc = Py_BuildValue ("OO" ,
1270+ (runres .result ? runres .result : Py_None ),
1271+ (runres .excinfo ? runres .excinfo : Py_None ));
13441272
13451273finally :
13461274 _interp_call_clear (& call );
1275+ _run_result_clear (& runres );
13471276 return res_and_exc ;
13481277#undef FUNCNAME
13491278}
0 commit comments