]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-76785: Clean Up Interpreter ID Conversions (gh-117048)
authorEric Snow <ericsnowcurrently@gmail.com>
Thu, 21 Mar 2024 15:56:12 +0000 (09:56 -0600)
committerGitHub <noreply@github.com>
Thu, 21 Mar 2024 15:56:12 +0000 (09:56 -0600)
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().

Include/cpython/interpreteridobject.h
Include/internal/pycore_interp.h
Lib/test/test_capi/test_misc.py
Modules/_testcapimodule.c
Modules/_testinternalcapi.c
Modules/_xxsubinterpretersmodule.c
Objects/interpreteridobject.c
Python/pystate.c

index 4ab9ad5d315f80661f3808ba3ad48bbd510aa0cf..d425c909806e44ba0e86f1f8c622c7d32ea70382 100644 (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
index 942f47340b3966c7ba9da570b1e548740d8c7ef8..b28e8a3ff45f3fa9466693ba776c05d8af09da03 100644 (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 *);
index 5b4f67e7f5f58d9c9f8b7775d916a450879c4bff..fe5e19d46d8b6c19fb1bc2f3b38e405bd41f9707 100644 (file)
@@ -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)
index b73085bb8f67ce1340433fda1271d0abd7f53df5..e68d083955d64afb0e9e369072d307d154243857 100644 (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")},
index 1c10dd02138f3a4606731f55ed29567f14787ce4..f73a29e5afe80159f5f067303189193578583443 100644 (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},
index 28c2f9c08bc0dafe9febf4e74d6ee729b2393ceb..606b2a36481ce2371923f9b00dadf6caeaf28a2b 100644 (file)
@@ -35,83 +35,8 @@ _get_current_interp(void)
     return PyInterpreterState_Get();
 }
 
-static int64_t
-pylong_to_interpid(PyObject *idobj)
-{
-    assert(PyLong_CheckExact(idobj));
-
-    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);
-}
-
+#define look_up_interp _PyInterpreterState_LookUpIDObject
 
-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;
     }
index 16e27b64c0c9c2daf0a430be8e27f4d61b3c014e..4844d6a9bf781cb8e120bf06a20b35782e499d84 100644 (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);
-}
index 5a334e8721e63b01636120e5fa8c11d9c96a66b8..5332b8a827d7e8c2736cb07abbbf1d9f820700c1 100644 (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 */