mirror of https://github.com/python/cpython
gh-76785: Clean Up Interpreter ID Conversions (gh-117048)
Mostly we unify the two different implementations of the conversion code (from PyObject * to int64_t. We also drop the PyArg_ParseTuple()-style converter function, as well as rename and move PyInterpreterID_LookUp().
This commit is contained in:
parent
e728303532
commit
bbee57fa8c
|
@ -8,4 +8,7 @@ PyAPI_DATA(PyTypeObject) PyInterpreterID_Type;
|
|||
|
||||
PyAPI_FUNC(PyObject *) PyInterpreterID_New(int64_t);
|
||||
PyAPI_FUNC(PyObject *) PyInterpreterState_GetIDObject(PyInterpreterState *);
|
||||
PyAPI_FUNC(PyInterpreterState *) PyInterpreterID_LookUp(PyObject *);
|
||||
|
||||
#ifdef Py_BUILD_CORE
|
||||
extern int64_t _PyInterpreterID_GetID(PyObject *);
|
||||
#endif
|
||||
|
|
|
@ -295,8 +295,11 @@ _PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tst
|
|||
}
|
||||
|
||||
|
||||
extern int64_t _PyInterpreterState_ObjectToID(PyObject *);
|
||||
|
||||
// Export for the _xxinterpchannels module.
|
||||
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(int64_t);
|
||||
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpIDObject(PyObject *);
|
||||
|
||||
PyAPI_FUNC(int) _PyInterpreterState_IDInitref(PyInterpreterState *);
|
||||
PyAPI_FUNC(int) _PyInterpreterState_IDIncref(PyInterpreterState *);
|
||||
|
|
|
@ -2303,7 +2303,7 @@ class InterpreterIDTests(unittest.TestCase):
|
|||
|
||||
def test_linked_lifecycle(self):
|
||||
id1 = _interpreters.create()
|
||||
_testcapi.unlink_interpreter_refcount(id1)
|
||||
_testinternalcapi.unlink_interpreter_refcount(id1)
|
||||
self.assertEqual(
|
||||
_testinternalcapi.get_interpreter_refcount(id1),
|
||||
0)
|
||||
|
@ -2319,7 +2319,7 @@ class InterpreterIDTests(unittest.TestCase):
|
|||
_testinternalcapi.get_interpreter_refcount(id1),
|
||||
0)
|
||||
|
||||
_testcapi.link_interpreter_refcount(id1)
|
||||
_testinternalcapi.link_interpreter_refcount(id1)
|
||||
self.assertEqual(
|
||||
_testinternalcapi.get_interpreter_refcount(id1),
|
||||
0)
|
||||
|
|
|
@ -1455,30 +1455,6 @@ get_interpreterid_type(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
return Py_NewRef(&PyInterpreterID_Type);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
link_interpreter_refcount(PyObject *self, PyObject *idobj)
|
||||
{
|
||||
PyInterpreterState *interp = PyInterpreterID_LookUp(idobj);
|
||||
if (interp == NULL) {
|
||||
assert(PyErr_Occurred());
|
||||
return NULL;
|
||||
}
|
||||
_PyInterpreterState_RequireIDRef(interp, 1);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
unlink_interpreter_refcount(PyObject *self, PyObject *idobj)
|
||||
{
|
||||
PyInterpreterState *interp = PyInterpreterID_LookUp(idobj);
|
||||
if (interp == NULL) {
|
||||
assert(PyErr_Occurred());
|
||||
return NULL;
|
||||
}
|
||||
_PyInterpreterState_RequireIDRef(interp, 0);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef ml;
|
||||
|
||||
static PyObject *
|
||||
|
@ -3324,8 +3300,6 @@ static PyMethodDef TestMethods[] = {
|
|||
{"test_current_tstate_matches", test_current_tstate_matches, METH_NOARGS},
|
||||
{"run_in_subinterp", run_in_subinterp, METH_VARARGS},
|
||||
{"get_interpreterid_type", get_interpreterid_type, METH_NOARGS},
|
||||
{"link_interpreter_refcount", link_interpreter_refcount, METH_O},
|
||||
{"unlink_interpreter_refcount", unlink_interpreter_refcount, METH_O},
|
||||
{"create_cfunction", create_cfunction, METH_NOARGS},
|
||||
{"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_VARARGS,
|
||||
PyDoc_STR("set_error_class(error_class) -> None")},
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
|
||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||
|
||||
#include "interpreteridobject.h" // PyInterpreterID_LookUp()
|
||||
|
||||
#include "clinic/_testinternalcapi.c.h"
|
||||
|
||||
// Include test definitions from _testinternalcapi/
|
||||
|
@ -1112,7 +1110,7 @@ pending_identify(PyObject *self, PyObject *args)
|
|||
if (!PyArg_ParseTuple(args, "O:pending_identify", &interpid)) {
|
||||
return NULL;
|
||||
}
|
||||
PyInterpreterState *interp = PyInterpreterID_LookUp(interpid);
|
||||
PyInterpreterState *interp = _PyInterpreterState_LookUpIDObject(interpid);
|
||||
if (interp == NULL) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_ValueError, "interpreter not found");
|
||||
|
@ -1480,13 +1478,37 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
static PyObject *
|
||||
get_interpreter_refcount(PyObject *self, PyObject *idobj)
|
||||
{
|
||||
PyInterpreterState *interp = PyInterpreterID_LookUp(idobj);
|
||||
PyInterpreterState *interp = _PyInterpreterState_LookUpIDObject(idobj);
|
||||
if (interp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return PyLong_FromLongLong(interp->id_refcount);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
link_interpreter_refcount(PyObject *self, PyObject *idobj)
|
||||
{
|
||||
PyInterpreterState *interp = _PyInterpreterState_LookUpIDObject(idobj);
|
||||
if (interp == NULL) {
|
||||
assert(PyErr_Occurred());
|
||||
return NULL;
|
||||
}
|
||||
_PyInterpreterState_RequireIDRef(interp, 1);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
unlink_interpreter_refcount(PyObject *self, PyObject *idobj)
|
||||
{
|
||||
PyInterpreterState *interp = _PyInterpreterState_LookUpIDObject(idobj);
|
||||
if (interp == NULL) {
|
||||
assert(PyErr_Occurred());
|
||||
return NULL;
|
||||
}
|
||||
_PyInterpreterState_RequireIDRef(interp, 0);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_xid_capsule_destructor(PyObject *capsule)
|
||||
|
@ -1728,6 +1750,8 @@ static PyMethodDef module_functions[] = {
|
|||
_PyCFunction_CAST(run_in_subinterp_with_config),
|
||||
METH_VARARGS | METH_KEYWORDS},
|
||||
{"get_interpreter_refcount", get_interpreter_refcount, METH_O},
|
||||
{"link_interpreter_refcount", link_interpreter_refcount, METH_O},
|
||||
{"unlink_interpreter_refcount", unlink_interpreter_refcount, METH_O},
|
||||
{"compile_perf_trampoline_entry", compile_perf_trampoline_entry, METH_VARARGS},
|
||||
{"perf_trampoline_set_persist_after_fork", perf_trampoline_set_persist_after_fork, METH_VARARGS},
|
||||
{"get_crossinterp_data", get_crossinterp_data, METH_VARARGS},
|
||||
|
|
|
@ -35,83 +35,8 @@ _get_current_interp(void)
|
|||
return PyInterpreterState_Get();
|
||||
}
|
||||
|
||||
static int64_t
|
||||
pylong_to_interpid(PyObject *idobj)
|
||||
{
|
||||
assert(PyLong_CheckExact(idobj));
|
||||
#define look_up_interp _PyInterpreterState_LookUpIDObject
|
||||
|
||||
if (_PyLong_IsNegative((PyLongObject *)idobj)) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"interpreter ID must be a non-negative int, got %R",
|
||||
idobj);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int overflow;
|
||||
long long id = PyLong_AsLongLongAndOverflow(idobj, &overflow);
|
||||
if (id == -1) {
|
||||
if (!overflow) {
|
||||
assert(PyErr_Occurred());
|
||||
return -1;
|
||||
}
|
||||
assert(!PyErr_Occurred());
|
||||
// For now, we don't worry about if LLONG_MAX < INT64_MAX.
|
||||
goto bad_id;
|
||||
}
|
||||
#if LLONG_MAX > INT64_MAX
|
||||
if (id > INT64_MAX) {
|
||||
goto bad_id;
|
||||
}
|
||||
#endif
|
||||
return (int64_t)id;
|
||||
|
||||
bad_id:
|
||||
PyErr_Format(PyExc_RuntimeError,
|
||||
"unrecognized interpreter ID %O", idobj);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
convert_interpid_obj(PyObject *arg)
|
||||
{
|
||||
int64_t id = -1;
|
||||
if (_PyIndex_Check(arg)) {
|
||||
PyObject *idobj = PyNumber_Long(arg);
|
||||
if (idobj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
id = pylong_to_interpid(idobj);
|
||||
Py_DECREF(idobj);
|
||||
if (id < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"interpreter ID must be an int, got %.100s",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
static PyInterpreterState *
|
||||
look_up_interp(PyObject *arg)
|
||||
{
|
||||
int64_t id = convert_interpid_obj(arg);
|
||||
if (id < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return _PyInterpreterState_LookUpID(id);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
interpid_to_pylong(int64_t id)
|
||||
{
|
||||
assert(id < LLONG_MAX);
|
||||
return PyLong_FromLongLong(id);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_interpid_obj(PyInterpreterState *interp)
|
||||
|
@ -123,7 +48,8 @@ get_interpid_obj(PyInterpreterState *interp)
|
|||
if (id < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return interpid_to_pylong(id);
|
||||
assert(id < LLONG_MAX);
|
||||
return PyLong_FromLongLong(id);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -699,7 +625,7 @@ interp_set___main___attrs(PyObject *self, PyObject *args)
|
|||
}
|
||||
|
||||
// Look up the interpreter.
|
||||
PyInterpreterState *interp = PyInterpreterID_LookUp(id);
|
||||
PyInterpreterState *interp = look_up_interp(id);
|
||||
if (interp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* InterpreterID object */
|
||||
|
||||
#include "Python.h"
|
||||
#include "pycore_abstract.h" // _PyIndex_Check()
|
||||
#include "pycore_interp.h" // _PyInterpreterState_LookUpID()
|
||||
#include "interpreteridobject.h"
|
||||
|
||||
|
@ -11,6 +10,21 @@ typedef struct interpid {
|
|||
int64_t id;
|
||||
} interpid;
|
||||
|
||||
int64_t
|
||||
_PyInterpreterID_GetID(PyObject *self)
|
||||
{
|
||||
if (!PyObject_TypeCheck(self, &PyInterpreterID_Type)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"expected an InterpreterID, got %R",
|
||||
self);
|
||||
return -1;
|
||||
|
||||
}
|
||||
int64_t id = ((interpid *)self)->id;
|
||||
assert(id >= 0);
|
||||
return id;
|
||||
}
|
||||
|
||||
static interpid *
|
||||
newinterpid(PyTypeObject *cls, int64_t id, int force)
|
||||
{
|
||||
|
@ -42,43 +56,19 @@ newinterpid(PyTypeObject *cls, int64_t id, int force)
|
|||
return self;
|
||||
}
|
||||
|
||||
static int
|
||||
interp_id_converter(PyObject *arg, void *ptr)
|
||||
{
|
||||
int64_t id;
|
||||
if (PyObject_TypeCheck(arg, &PyInterpreterID_Type)) {
|
||||
id = ((interpid *)arg)->id;
|
||||
}
|
||||
else if (_PyIndex_Check(arg)) {
|
||||
id = PyLong_AsLongLong(arg);
|
||||
if (id == -1 && PyErr_Occurred()) {
|
||||
return 0;
|
||||
}
|
||||
if (id < 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"interpreter ID must be a non-negative int, got %R", arg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"interpreter ID must be an int, got %.100s",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
return 0;
|
||||
}
|
||||
*(int64_t *)ptr = id;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *kwlist[] = {"id", "force", NULL};
|
||||
int64_t id;
|
||||
PyObject *idobj;
|
||||
int force = 0;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds,
|
||||
"O&|$p:InterpreterID.__init__", kwlist,
|
||||
interp_id_converter, &id, &force)) {
|
||||
"O|$p:InterpreterID.__init__", kwlist,
|
||||
&idobj, &force)) {
|
||||
return NULL;
|
||||
}
|
||||
int64_t id = _PyInterpreterState_ObjectToID(idobj);
|
||||
if (id < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -282,13 +272,3 @@ PyInterpreterState_GetIDObject(PyInterpreterState *interp)
|
|||
}
|
||||
return (PyObject *)newinterpid(&PyInterpreterID_Type, id, 0);
|
||||
}
|
||||
|
||||
PyInterpreterState *
|
||||
PyInterpreterID_LookUp(PyObject *requested_id)
|
||||
{
|
||||
int64_t id;
|
||||
if (!interp_id_converter(requested_id, &id)) {
|
||||
return NULL;
|
||||
}
|
||||
return _PyInterpreterState_LookUpID(id);
|
||||
}
|
||||
|
|
103
Python/pystate.c
103
Python/pystate.c
|
@ -2,6 +2,8 @@
|
|||
/* Thread and interpreter state structures and their interfaces */
|
||||
|
||||
#include "Python.h"
|
||||
#include "interpreteridobject.h" // PyInterpreterID_Type
|
||||
#include "pycore_abstract.h" // _PyIndex_Check()
|
||||
#include "pycore_ceval.h"
|
||||
#include "pycore_code.h" // stats
|
||||
#include "pycore_critical_section.h" // _PyCriticalSection_Resume()
|
||||
|
@ -1064,6 +1066,73 @@ _PyInterpreterState_FailIfRunningMain(PyInterpreterState *interp)
|
|||
// accessors
|
||||
//----------
|
||||
|
||||
PyObject *
|
||||
PyUnstable_InterpreterState_GetMainModule(PyInterpreterState *interp)
|
||||
{
|
||||
PyObject *modules = _PyImport_GetModules(interp);
|
||||
if (modules == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "interpreter not initialized");
|
||||
return NULL;
|
||||
}
|
||||
return PyMapping_GetItemString(modules, "__main__");
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyInterpreterState_GetDict(PyInterpreterState *interp)
|
||||
{
|
||||
if (interp->dict == NULL) {
|
||||
interp->dict = PyDict_New();
|
||||
if (interp->dict == NULL) {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
/* Returning NULL means no per-interpreter dict is available. */
|
||||
return interp->dict;
|
||||
}
|
||||
|
||||
|
||||
//----------
|
||||
// interp ID
|
||||
//----------
|
||||
|
||||
int64_t
|
||||
_PyInterpreterState_ObjectToID(PyObject *idobj)
|
||||
{
|
||||
if (PyObject_TypeCheck(idobj, &PyInterpreterID_Type)) {
|
||||
return _PyInterpreterID_GetID(idobj);
|
||||
}
|
||||
|
||||
if (!_PyIndex_Check(idobj)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"interpreter ID must be an int, got %.100s",
|
||||
Py_TYPE(idobj)->tp_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This may raise OverflowError.
|
||||
// For now, we don't worry about if LLONG_MAX < INT64_MAX.
|
||||
long long id = PyLong_AsLongLong(idobj);
|
||||
if (id == -1 && PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (id < 0) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"interpreter ID must be a non-negative int, got %R",
|
||||
idobj);
|
||||
return -1;
|
||||
}
|
||||
#if LLONG_MAX > INT64_MAX
|
||||
else if (id > INT64_MAX) {
|
||||
PyErr_SetString(PyExc_OverflowError, "int too big to convert");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
return (int64_t)id;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t
|
||||
PyInterpreterState_GetID(PyInterpreterState *interp)
|
||||
{
|
||||
|
@ -1142,30 +1211,6 @@ _PyInterpreterState_RequireIDRef(PyInterpreterState *interp, int required)
|
|||
interp->requires_idref = required ? 1 : 0;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyUnstable_InterpreterState_GetMainModule(PyInterpreterState *interp)
|
||||
{
|
||||
PyObject *modules = _PyImport_GetModules(interp);
|
||||
if (modules == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "interpreter not initialized");
|
||||
return NULL;
|
||||
}
|
||||
return PyMapping_GetItemString(modules, "__main__");
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyInterpreterState_GetDict(PyInterpreterState *interp)
|
||||
{
|
||||
if (interp->dict == NULL) {
|
||||
interp->dict = PyDict_New();
|
||||
if (interp->dict == NULL) {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
/* Returning NULL means no per-interpreter dict is available. */
|
||||
return interp->dict;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------
|
||||
// look up an interpreter state
|
||||
|
@ -1227,6 +1272,16 @@ _PyInterpreterState_LookUpID(int64_t requested_id)
|
|||
return interp;
|
||||
}
|
||||
|
||||
PyInterpreterState *
|
||||
_PyInterpreterState_LookUpIDObject(PyObject *requested_id)
|
||||
{
|
||||
int64_t id = _PyInterpreterState_ObjectToID(requested_id);
|
||||
if (id < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return _PyInterpreterState_LookUpID(id);
|
||||
}
|
||||
|
||||
|
||||
/********************************/
|
||||
/* the per-thread runtime state */
|
||||
|
|
Loading…
Reference in New Issue