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:
Eric Snow 2024-03-21 09:56:12 -06:00 committed by GitHub
parent e728303532
commit bbee57fa8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 143 additions and 178 deletions

View file

@ -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

View file

@ -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 *);

View file

@ -2303,7 +2303,7 @@ def test_equality(self):
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 @@ def test_linked_lifecycle(self):
_testinternalcapi.get_interpreter_refcount(id1),
0)
_testcapi.link_interpreter_refcount(id1)
_testinternalcapi.link_interpreter_refcount(id1)
self.assertEqual(
_testinternalcapi.get_interpreter_refcount(id1),
0)

View file

@ -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")},

View file

@ -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},

View file

@ -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;
}

View file

@ -1,8 +1,7 @@
/* InterpreterID object */
#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_interp.h" // _PyInterpreterState_LookUpID()
#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);
}

View file

@ -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 */