Thanks to visit codestin.com
Credit goes to github.com

Skip to content

bpo-38644: Make tstate more explicit inside pystate.c #19182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,8 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
Return the interpreter's unique ID. If there was any error in doing
so then ``-1`` is returned and an error is set.

The caller must hold the GIL.

.. versionadded:: 3.7


Expand Down
4 changes: 4 additions & 0 deletions Doc/c-api/module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ since multiple such modules can be created from a single definition.
mechanisms (either by calling it directly, or by referring to its
implementation for details of the required state updates).

The caller must hold the GIL.

Return 0 on success or -1 on failure.

.. versionadded:: 3.3
Expand All @@ -536,4 +538,6 @@ since multiple such modules can be created from a single definition.
Removes the module object created from *def* from the interpreter state.
Return 0 on success or -1 on failure.

The caller must hold the GIL.

.. versionadded:: 3.3
108 changes: 61 additions & 47 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "pycore_pylifecycle.h"
#include "pycore_pymem.h"
#include "pycore_pystate.h"
#include "pycore_sysmodule.h"

/* --------------------------------------------------------------------------
CAUTION
Expand Down Expand Up @@ -203,7 +204,10 @@ _PyInterpreterState_Enable(_PyRuntimeState *runtime)
PyInterpreterState *
PyInterpreterState_New(void)
{
if (PySys_Audit("cpython.PyInterpreterState_New", NULL) < 0) {
PyThreadState *tstate = _PyThreadState_GET();
/* tstate is NULL when Py_InitializeFromConfig() calls
PyInterpreterState_New() to create the main interpreter. */
if (_PySys_Audit(tstate, "cpython.PyInterpreterState_New", NULL) < 0) {
return NULL;
}

Expand All @@ -214,6 +218,7 @@ PyInterpreterState_New(void)

interp->id_refcount = -1;

/* Don't get runtime from tstate since tstate can be NULL */
_PyRuntimeState *runtime = &_PyRuntime;
interp->runtime = runtime;

Expand All @@ -235,8 +240,10 @@ PyInterpreterState_New(void)
HEAD_LOCK(runtime);
if (interpreters->next_id < 0) {
/* overflow or Py_Initialize() not called! */
PyErr_SetString(PyExc_RuntimeError,
"failed to get an interpreter ID");
if (tstate != NULL) {
_PyErr_SetString(tstate, PyExc_RuntimeError,
"failed to get an interpreter ID");
}
PyMem_RawFree(interp);
interp = NULL;
}
Expand Down Expand Up @@ -268,8 +275,11 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
{
_PyRuntimeState *runtime = interp->runtime;

if (PySys_Audit("cpython.PyInterpreterState_Clear", NULL) < 0) {
PyErr_Clear();
/* Use the current Python thread state to call audit hooks,
not the current Python thread state of 'interp'. */
PyThreadState *tstate = _PyThreadState_GET();
if (_PySys_Audit(tstate, "cpython.PyInterpreterState_Clear", NULL) < 0) {
_PyErr_Clear(tstate);
}

HEAD_LOCK(runtime);
Expand Down Expand Up @@ -655,12 +665,13 @@ int
_PyState_AddModule(PyThreadState *tstate, PyObject* module, struct PyModuleDef* def)
{
if (!def) {
assert(PyErr_Occurred());
assert(_PyErr_Occurred(tstate));
return -1;
}
if (def->m_slots) {
PyErr_SetString(PyExc_SystemError,
"PyState_AddModule called on module with slots");
_PyErr_SetString(tstate,
PyExc_SystemError,
"PyState_AddModule called on module with slots");
return -1;
}

Expand Down Expand Up @@ -707,28 +718,29 @@ PyState_AddModule(PyObject* module, struct PyModuleDef* def)
int
PyState_RemoveModule(struct PyModuleDef* def)
{
PyInterpreterState *state;
Py_ssize_t index = def->m_base.m_index;
PyThreadState *tstate = _PyThreadState_GET();
PyInterpreterState *interp = tstate->interp;

if (def->m_slots) {
PyErr_SetString(PyExc_SystemError,
"PyState_RemoveModule called on module with slots");
_PyErr_SetString(tstate,
PyExc_SystemError,
"PyState_RemoveModule called on module with slots");
return -1;
}
state = _PyInterpreterState_GET_UNSAFE();

Py_ssize_t index = def->m_base.m_index;
if (index == 0) {
Py_FatalError("invalid module index");
return -1;
}
if (state->modules_by_index == NULL) {
if (interp->modules_by_index == NULL) {
Py_FatalError("Interpreters module-list not accessible.");
return -1;
}
if (index > PyList_GET_SIZE(state->modules_by_index)) {
if (index > PyList_GET_SIZE(interp->modules_by_index)) {
Py_FatalError("Module index out of bounds.");
return -1;
}

Py_INCREF(Py_None);
return PyList_SetItem(state->modules_by_index, index, Py_None);
return PyList_SetItem(interp->modules_by_index, index, Py_None);
}

/* Used by PyImport_Cleanup() */
Expand Down Expand Up @@ -1114,49 +1126,51 @@ PyThreadState_Next(PyThreadState *tstate) {
PyObject *
_PyThread_CurrentFrames(void)
{
PyObject *result;
PyInterpreterState *i;

if (PySys_Audit("sys._current_frames", NULL) < 0) {
PyThreadState *tstate = _PyThreadState_GET();
if (_PySys_Audit(tstate, "sys._current_frames", NULL) < 0) {
return NULL;
}

result = PyDict_New();
if (result == NULL)
PyObject *result = PyDict_New();
if (result == NULL) {
return NULL;
}

/* for i in all interpreters:
* for t in all of i's thread states:
* if t's frame isn't NULL, map t's id to its frame
* Because these lists can mutate even when the GIL is held, we
* need to grab head_mutex for the duration.
*/
_PyRuntimeState *runtime = &_PyRuntime;
_PyRuntimeState *runtime = tstate->interp->runtime;
HEAD_LOCK(runtime);
PyInterpreterState *i;
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
PyThreadState *t;
for (t = i->tstate_head; t != NULL; t = t->next) {
PyObject *id;
int stat;
struct _frame *frame = t->frame;
if (frame == NULL)
if (frame == NULL) {
continue;
id = PyLong_FromUnsignedLong(t->thread_id);
if (id == NULL)
goto Fail;
stat = PyDict_SetItem(result, id, (PyObject *)frame);
}
PyObject *id = PyLong_FromUnsignedLong(t->thread_id);
if (id == NULL) {
goto fail;
}
int stat = PyDict_SetItem(result, id, (PyObject *)frame);
Py_DECREF(id);
if (stat < 0)
goto Fail;
if (stat < 0) {
goto fail;
}
}
}
HEAD_UNLOCK(runtime);
return result;
goto done;

fail:
Py_CLEAR(result);

Fail:
done:
HEAD_UNLOCK(runtime);
Py_DECREF(result);
return NULL;
return result;
}

/* Python "auto thread state" API. */
Expand Down Expand Up @@ -1436,19 +1450,19 @@ _PyObject_CheckCrossInterpreterData(PyObject *obj)
}

static int
_check_xidata(_PyCrossInterpreterData *data)
_check_xidata(PyThreadState *tstate, _PyCrossInterpreterData *data)
{
// data->data can be anything, including NULL, so we don't check it.

// data->obj may be NULL, so we don't check it.

if (data->interp < 0) {
PyErr_SetString(PyExc_SystemError, "missing interp");
_PyErr_SetString(tstate, PyExc_SystemError, "missing interp");
return -1;
}

if (data->new_object == NULL) {
PyErr_SetString(PyExc_SystemError, "missing new_object func");
_PyErr_SetString(tstate, PyExc_SystemError, "missing new_object func");
return -1;
}

Expand All @@ -1460,9 +1474,9 @@ _check_xidata(_PyCrossInterpreterData *data)
int
_PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
{
// PyInterpreterState_Get() aborts if lookup fails, so we don't need
// to check the result for NULL.
PyInterpreterState *interp = PyInterpreterState_Get();
// PyThreadState_Get() aborts if tstate is NULL.
PyThreadState *tstate = PyThreadState_Get();
PyInterpreterState *interp = tstate->interp;

// Reset data before re-populating.
*data = (_PyCrossInterpreterData){0};
Expand All @@ -1483,7 +1497,7 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)

// Fill in the blanks and validate the result.
data->interp = interp->id;
if (_check_xidata(data) != 0) {
if (_check_xidata(tstate, data) != 0) {
_PyCrossInterpreterData_Release(data);
return -1;
}
Expand Down