Skip to content

Commit b8171d9

Browse files
Use _PyXI_Preserve().
1 parent 1d15480 commit b8171d9

File tree

1 file changed

+61
-134
lines changed

1 file changed

+61
-134
lines changed

Modules/_interpretersmodule.c

Lines changed: 61 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -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

517458
static 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-
596514
static 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

652557
finally:
@@ -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+
676593
static 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

710632
finally:
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

13471273
finally:
13481274
_interp_call_clear(&call);
1275+
_run_result_clear(&runres);
13491276
return res_and_exc;
13501277
#undef FUNCNAME
13511278
}

0 commit comments

Comments
 (0)