summaryrefslogtreecommitdiffstats
path: root/Python/pystate.c
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2019-04-12 15:18:16 (GMT)
committerGitHub <noreply@github.com>2019-04-12 15:18:16 (GMT)
commitf13c5c8b9401a9dc19e95d8b420ee100ac022208 (patch)
tree00e61cfbb38d11341b39c3d5abe6b04a2ccbbbb5 /Python/pystate.c
parent44235041f3b957abd36d3792450c3540aa09e120 (diff)
downloadcpython-f13c5c8b9401a9dc19e95d8b420ee100ac022208.zip
cpython-f13c5c8b9401a9dc19e95d8b420ee100ac022208.tar.gz
cpython-f13c5c8b9401a9dc19e95d8b420ee100ac022208.tar.bz2
bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). (gh-12360)
This is effectively an un-revert of #11617 and #12024 (reverted in #12159). Portions of those were merged in other PRs (with lower risk) and this represents the remainder. Note that I found 3 different bugs in the original PRs and have fixed them here.
Diffstat (limited to 'Python/pystate.c')
-rw-r--r--Python/pystate.c60
1 files changed, 32 insertions, 28 deletions
diff --git a/Python/pystate.c b/Python/pystate.c
index a2464b6..fee3501 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -173,6 +173,14 @@ PyInterpreterState_New(void)
memset(interp, 0, sizeof(*interp));
interp->id_refcount = -1;
interp->check_interval = 100;
+
+ interp->ceval.pending.lock = PyThread_allocate_lock();
+ if (interp->ceval.pending.lock == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "failed to create interpreter ceval pending mutex");
+ return NULL;
+ }
+
interp->core_config = _PyCoreConfig_INIT;
interp->eval_frame = _PyEval_EvalFrameDefault;
#ifdef HAVE_DLOPEN
@@ -279,6 +287,9 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
if (interp->id_mutex != NULL) {
PyThread_free_lock(interp->id_mutex);
}
+ if (interp->ceval.pending.lock != NULL) {
+ PyThread_free_lock(interp->ceval.pending.lock);
+ }
PyMem_RawFree(interp);
}
@@ -928,7 +939,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
p->async_exc = exc;
HEAD_UNLOCK();
Py_XDECREF(old_exc);
- _PyEval_SignalAsyncExc();
+ _PyEval_SignalAsyncExc(interp);
return 1;
}
}
@@ -1342,7 +1353,7 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
return 0;
}
-static void
+static int
_release_xidata(void *arg)
{
_PyCrossInterpreterData *data = (_PyCrossInterpreterData *)arg;
@@ -1350,30 +1361,8 @@ _release_xidata(void *arg)
data->free(data->data);
}
Py_XDECREF(data->obj);
-}
-
-static void
-_call_in_interpreter(PyInterpreterState *interp,
- void (*func)(void *), void *arg)
-{
- /* We would use Py_AddPendingCall() if it weren't specific to the
- * main interpreter (see bpo-33608). In the meantime we take a
- * naive approach.
- */
- PyThreadState *save_tstate = NULL;
- if (interp != _PyInterpreterState_Get()) {
- // XXX Using the "head" thread isn't strictly correct.
- PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
- // XXX Possible GILState issues?
- save_tstate = PyThreadState_Swap(tstate);
- }
-
- func(arg);
-
- // Switch back.
- if (save_tstate != NULL) {
- PyThreadState_Swap(save_tstate);
- }
+ PyMem_Free(data);
+ return 0;
}
void
@@ -1384,7 +1373,7 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
return;
}
- // Switch to the original interpreter.
+ // Get the original interpreter.
PyInterpreterState *interp = _PyInterpreterState_LookUpID(data->interp);
if (interp == NULL) {
// The intepreter was already destroyed.
@@ -1393,9 +1382,24 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
}
return;
}
+ // XXX There's an ever-so-slight race here...
+ if (interp->finalizing) {
+ // XXX Someone leaked some memory...
+ return;
+ }
// "Release" the data and/or the object.
- _call_in_interpreter(interp, _release_xidata, data);
+ _PyCrossInterpreterData *copied = PyMem_Malloc(sizeof(_PyCrossInterpreterData));
+ if (copied == NULL) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Not enough memory to preserve cross-interpreter data");
+ PyErr_Print();
+ return;
+ }
+ memcpy(copied, data, sizeof(_PyCrossInterpreterData));
+ if (_Py_AddPendingCall(interp, 0, _release_xidata, copied) != 0) {
+ // XXX Queue full or couldn't get lock. Try again somehow?
+ }
}
PyObject *