@@ -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,24 +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_GetXIDataWithFallback (
645- tstate , resobj , fallback , call -> result ) < 0 )
646- {
647- _interp_call_clear_result (call );
648552 goto finally ;
649553 }
554+ * p_result = resobj ;
650555 res = 0 ;
651556
652557finally :
@@ -673,19 +578,32 @@ _run_script(_PyXIData_t *script, PyObject *ns)
673578 return 0 ;
674579}
675580
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+
676593static int
677594_run_in_interpreter (PyThreadState * tstate , PyInterpreterState * interp ,
678595 _PyXIData_t * script , struct interp_call * call ,
679- PyObject * shareables , _PyXI_session_result * result )
596+ PyObject * shareables , struct run_result * runres )
680597{
681598 assert (!_PyErr_Occurred (tstate ));
682599 _PyXI_session * session = _PyXI_NewSession ();
683600 if (session == NULL ) {
684601 return -1 ;
685602 }
603+ _PyXI_session_result result = {0 };
686604
687605 // Prep and switch interpreters.
688- if (_PyXI_Enter (session , interp , shareables , result ) < 0 ) {
606+ if (_PyXI_Enter (session , interp , shareables , & result ) < 0 ) {
689607 // If an error occured at this step, it means that interp
690608 // was not prepared and switched.
691609 _PyXI_FreeSession (session );
@@ -694,7 +612,6 @@ _run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
694612
695613 int res = -1 ;
696614 if (script != NULL ) {
697- // Run the script.
698615 assert (call == NULL );
699616 PyObject * mainns = _PyXI_GetMainNamespace (session );
700617 if (mainns == NULL ) {
@@ -704,13 +621,31 @@ _run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
704621 }
705622 else {
706623 assert (call != NULL );
707- 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+ }
708630 }
709631
710632finally :
711633 // Clean up and switch back.
712- (void )_PyXI_Exit (session , result );
634+ (void )_PyXI_Exit (session , & result );
713635 _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+ }
714649 return res ;
715650}
716651
@@ -1139,13 +1074,13 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
11391074 return NULL ;
11401075 }
11411076
1142- _PyXI_session_result result = {0 };
1077+ struct run_result runres = {0 };
11431078 int res = _run_in_interpreter (
1144- tstate , interp , & xidata , NULL , shared , & result );
1079+ tstate , interp , & xidata , NULL , shared , & runres );
11451080 _PyXIData_Release (& xidata );
11461081 if (res < 0 ) {
1147- assert ((result .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1148- return result .excinfo ;
1082+ assert ((runres .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1083+ return runres .excinfo ;
11491084 }
11501085 Py_RETURN_NONE ;
11511086#undef FUNCNAME
@@ -1203,13 +1138,13 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
12031138 return NULL ;
12041139 }
12051140
1206- _PyXI_session_result result = {0 };
1141+ struct run_result runres = {0 };
12071142 int res = _run_in_interpreter (
1208- tstate , interp , & xidata , NULL , shared , & result );
1143+ tstate , interp , & xidata , NULL , shared , & runres );
12091144 _PyXIData_Release (& xidata );
12101145 if (res < 0 ) {
1211- assert ((result .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1212- return result .excinfo ;
1146+ assert ((runres .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1147+ return runres .excinfo ;
12131148 }
12141149 Py_RETURN_NONE ;
12151150#undef FUNCNAME
@@ -1266,13 +1201,13 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
12661201 return NULL ;
12671202 }
12681203
1269- _PyXI_session_result result = {0 };
1204+ struct run_result runres = {0 };
12701205 int res = _run_in_interpreter (
1271- tstate , interp , & xidata , NULL , shared , & result );
1206+ tstate , interp , & xidata , NULL , shared , & runres );
12721207 _PyXIData_Release (& xidata );
12731208 if (res < 0 ) {
1274- assert ((result .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1275- return result .excinfo ;
1209+ assert ((runres .excinfo == NULL ) != (PyErr_Occurred () == NULL ));
1210+ return runres .excinfo ;
12761211 }
12771212 Py_RETURN_NONE ;
12781213#undef FUNCNAME
@@ -1293,17 +1228,18 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
12931228#define FUNCNAME MODULE_NAME_STR ".call"
12941229 PyThreadState * tstate = _PyThreadState_GET ();
12951230 static char * kwlist [] = {"id" , "callable" , "args" , "kwargs" ,
1296- "restrict" , NULL };
1231+ "preserve_exc" , " restrict" , NULL };
12971232 PyObject * id , * callable ;
12981233 PyObject * args_obj = NULL ;
12991234 PyObject * kwargs_obj = NULL ;
1235+ int preserve_exc = 0 ;
13001236 int restricted = 0 ;
13011237 if (!PyArg_ParseTupleAndKeywords (args , kwds ,
1302- "OO|O!O!$p :" FUNCNAME , kwlist ,
1238+ "OO|O!O!$pp :" FUNCNAME , kwlist ,
13031239 & id , & callable ,
13041240 & PyTuple_Type , & args_obj ,
13051241 & PyDict_Type , & kwargs_obj ,
1306- & restricted ))
1242+ & preserve_exc , & restricted ))
13071243 {
13081244 return NULL ;
13091245 }
@@ -1321,31 +1257,22 @@ interp_call(PyObject *self, PyObject *args, PyObject *kwds)
13211257 }
13221258
13231259 PyObject * res_and_exc = NULL ;
1324- _PyXI_session_result result = {0 };
1325- if (_run_in_interpreter (tstate , interp , NULL , & call , NULL , & result ) < 0 ) {
1326- assert (result .preserved == NULL );
1327- 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 ) {
13281263 assert (_PyErr_Occurred (tstate ));
13291264 goto finally ;
13301265 }
13311266 assert (!_PyErr_Occurred (tstate ));
1332- assert (call .result == NULL );
1333- res_and_exc = Py_BuildValue ("OO" , Py_None , result .excinfo );
1334- Py_CLEAR (result .excinfo );
1335- }
1336- else {
1337- assert (result .preserved == NULL );
1338- assert (result .excinfo == NULL );
1339- PyObject * res = _interp_call_pop_result (tstate , & call , interp );
1340- if (res == NULL ) {
1341- goto finally ;
1342- }
1343- res_and_exc = Py_BuildValue ("OO" , res , Py_None );
1344- Py_DECREF (res );
13451267 }
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 ));
13461272
13471273finally :
13481274 _interp_call_clear (& call );
1275+ _run_result_clear (& runres );
13491276 return res_and_exc ;
13501277#undef FUNCNAME
13511278}
0 commit comments