]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-76785: Drop PyInterpreterID_Type (gh-117101)
authorEric Snow <ericsnowcurrently@gmail.com>
Thu, 21 Mar 2024 17:15:02 +0000 (11:15 -0600)
committerGitHub <noreply@github.com>
Thu, 21 Mar 2024 17:15:02 +0000 (17:15 +0000)
I added it quite a while ago as a strategy for managing interpreter lifetimes relative to the PEP 554 (now 734) implementation.  Relatively recently I refactored that implementation to no longer rely on InterpreterID objects.  Thus now I'm removing it.

18 files changed:
Include/cpython/interpreteridobject.h [deleted file]
Include/internal/pycore_interp.h
Include/interpreteridobject.h [deleted file]
Lib/test/test_capi/test_misc.py
Makefile.pre.in
Modules/_interpreters_common.h
Modules/_testcapimodule.c
Modules/_testinternalcapi.c
Modules/_xxinterpchannelsmodule.c
Modules/_xxsubinterpretersmodule.c
Objects/interpreteridobject.c [deleted file]
Objects/object.c
PCbuild/_freeze_module.vcxproj
PCbuild/_freeze_module.vcxproj.filters
PCbuild/pythoncore.vcxproj
PCbuild/pythoncore.vcxproj.filters
Python/pystate.c
Tools/c-analyzer/cpython/globals-to-fix.tsv

diff --git a/Include/cpython/interpreteridobject.h b/Include/cpython/interpreteridobject.h
deleted file mode 100644 (file)
index d425c90..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef Py_CPYTHON_INTERPRETERIDOBJECT_H
-#  error "this header file must not be included directly"
-#endif
-
-/* Interpreter ID Object */
-
-PyAPI_DATA(PyTypeObject) PyInterpreterID_Type;
-
-PyAPI_FUNC(PyObject *) PyInterpreterID_New(int64_t);
-PyAPI_FUNC(PyObject *) PyInterpreterState_GetIDObject(PyInterpreterState *);
-
-#ifdef Py_BUILD_CORE
-extern int64_t _PyInterpreterID_GetID(PyObject *);
-#endif
index b28e8a3ff45f3fa9466693ba776c05d8af09da03..b8d0fdcce11ba8a388677b1a51a0ca00aaf18464 100644 (file)
@@ -295,12 +295,11 @@ _PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tst
 }
 
 
-extern int64_t _PyInterpreterState_ObjectToID(PyObject *);
 
-// Export for the _xxinterpchannels module.
+// Exports for the _testinternalcapi module.
+PyAPI_FUNC(int64_t) _PyInterpreterState_ObjectToID(PyObject *);
 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 *);
 PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *);
diff --git a/Include/interpreteridobject.h b/Include/interpreteridobject.h
deleted file mode 100644 (file)
index 8432632..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef Py_INTERPRETERIDOBJECT_H
-#define Py_INTERPRETERIDOBJECT_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef Py_LIMITED_API
-#  define Py_CPYTHON_INTERPRETERIDOBJECT_H
-#  include "cpython/interpreteridobject.h"
-#  undef Py_CPYTHON_INTERPRETERIDOBJECT_H
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* !Py_INTERPRETERIDOBJECT_H */
index fe5e19d46d8b6c19fb1bc2f3b38e405bd41f9707..55a1ab6d6d935906931f956dcfc08162fd91c0fb 100644 (file)
@@ -2207,132 +2207,264 @@ class SubinterpreterTest(unittest.TestCase):
 @requires_subinterpreters
 class InterpreterIDTests(unittest.TestCase):
 
-    InterpreterID = _testcapi.get_interpreterid_type()
-
-    def new_interpreter(self):
-        def ensure_destroyed(interpid):
+    def add_interp_cleanup(self, interpid):
+        def ensure_destroyed():
             try:
                 _interpreters.destroy(interpid)
             except _interpreters.InterpreterNotFoundError:
                 pass
+        self.addCleanup(ensure_destroyed)
+
+    def new_interpreter(self):
         id = _interpreters.create()
-        self.addCleanup(lambda: ensure_destroyed(id))
+        self.add_interp_cleanup(id)
         return id
 
-    def test_with_int(self):
-        id = self.InterpreterID(10, force=True)
-
-        self.assertEqual(int(id), 10)
+    def test_conversion_int(self):
+        convert = _testinternalcapi.normalize_interp_id
+        interpid = convert(10)
+        self.assertEqual(interpid, 10)
 
-    def test_coerce_id(self):
-        class Int(str):
+    def test_conversion_coerced(self):
+        convert = _testinternalcapi.normalize_interp_id
+        class MyInt(str):
             def __index__(self):
                 return 10
+        interpid = convert(MyInt())
+        self.assertEqual(interpid, 10)
 
-        id = self.InterpreterID(Int(), force=True)
-        self.assertEqual(int(id), 10)
+    def test_conversion_from_interpreter(self):
+        convert = _testinternalcapi.normalize_interp_id
+        interpid = self.new_interpreter()
+        converted = convert(interpid)
+        self.assertEqual(converted, interpid)
+
+    def test_conversion_bad(self):
+        convert = _testinternalcapi.normalize_interp_id
 
-    def test_bad_id(self):
         for badid in [
             object(),
             10.0,
             '10',
             b'10',
         ]:
-            with self.subTest(badid):
+            with self.subTest(f'bad: {badid!r}'):
                 with self.assertRaises(TypeError):
-                    self.InterpreterID(badid)
+                    convert(badid)
 
         badid = -1
-        with self.subTest(badid):
+        with self.subTest(f'bad: {badid!r}'):
             with self.assertRaises(ValueError):
-                self.InterpreterID(badid)
+                convert(badid)
 
         badid = 2**64
-        with self.subTest(badid):
+        with self.subTest(f'bad: {badid!r}'):
             with self.assertRaises(OverflowError):
-                self.InterpreterID(badid)
+                convert(badid)
 
-    def test_exists(self):
-        id = self.new_interpreter()
-        with self.assertRaises(_interpreters.InterpreterNotFoundError):
-            self.InterpreterID(int(id) + 1)  # unforced
+    def test_lookup_exists(self):
+        interpid = self.new_interpreter()
+        self.assertTrue(
+            _testinternalcapi.interpreter_exists(interpid))
 
-    def test_does_not_exist(self):
-        id = self.new_interpreter()
-        with self.assertRaises(_interpreters.InterpreterNotFoundError):
-            self.InterpreterID(int(id) + 1)  # unforced
+    def test_lookup_does_not_exist(self):
+        interpid = _testinternalcapi.unused_interpreter_id()
+        self.assertFalse(
+            _testinternalcapi.interpreter_exists(interpid))
 
-    def test_destroyed(self):
-        id = _interpreters.create()
-        _interpreters.destroy(id)
-        with self.assertRaises(_interpreters.InterpreterNotFoundError):
-            self.InterpreterID(id)  # unforced
-
-    def test_str(self):
-        id = self.InterpreterID(10, force=True)
-        self.assertEqual(str(id), '10')
-
-    def test_repr(self):
-        id = self.InterpreterID(10, force=True)
-        self.assertEqual(repr(id), 'InterpreterID(10)')
-
-    def test_equality(self):
-        id1 = self.new_interpreter()
-        id2 = self.InterpreterID(id1)
-        id3 = self.InterpreterID(
-                self.new_interpreter())
-
-        self.assertTrue(id2 == id2)  # identity
-        self.assertTrue(id2 == id1)  # int-equivalent
-        self.assertTrue(id1 == id2)  # reversed
-        self.assertTrue(id2 == int(id2))
-        self.assertTrue(id2 == float(int(id2)))
-        self.assertTrue(float(int(id2)) == id2)
-        self.assertFalse(id2 == float(int(id2)) + 0.1)
-        self.assertFalse(id2 == str(int(id2)))
-        self.assertFalse(id2 == 2**1000)
-        self.assertFalse(id2 == float('inf'))
-        self.assertFalse(id2 == 'spam')
-        self.assertFalse(id2 == id3)
-
-        self.assertFalse(id2 != id2)
-        self.assertFalse(id2 != id1)
-        self.assertFalse(id1 != id2)
-        self.assertTrue(id2 != id3)
-
-    def test_linked_lifecycle(self):
-        id1 = _interpreters.create()
-        _testinternalcapi.unlink_interpreter_refcount(id1)
+    def test_lookup_destroyed(self):
+        interpid = _interpreters.create()
+        _interpreters.destroy(interpid)
+        self.assertFalse(
+            _testinternalcapi.interpreter_exists(interpid))
+
+    def test_linked_lifecycle_does_not_exist(self):
+        exists = _testinternalcapi.interpreter_exists
+        is_linked = _testinternalcapi.interpreter_refcount_linked
+        link = _testinternalcapi.link_interpreter_refcount
+        unlink = _testinternalcapi.unlink_interpreter_refcount
+        get_refcount = _testinternalcapi.get_interpreter_refcount
+        incref = _testinternalcapi.interpreter_incref
+        decref = _testinternalcapi.interpreter_decref
+
+        with self.subTest('never existed'):
+            interpid = _testinternalcapi.unused_interpreter_id()
+            self.assertFalse(
+                exists(interpid))
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                is_linked(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                link(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                unlink(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                get_refcount(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                incref(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                decref(interpid)
+
+        with self.subTest('destroyed'):
+            interpid = _interpreters.create()
+            _interpreters.destroy(interpid)
+            self.assertFalse(
+                exists(interpid))
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                is_linked(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                link(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                unlink(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                get_refcount(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                incref(interpid)
+            with self.assertRaises(_interpreters.InterpreterNotFoundError):
+                decref(interpid)
+
+    def test_linked_lifecycle_initial(self):
+        is_linked = _testinternalcapi.interpreter_refcount_linked
+        get_refcount = _testinternalcapi.get_interpreter_refcount
+
+        # A new interpreter will start out not linked, with a refcount of 0.
+        interpid = _testinternalcapi.new_interpreter()
+        self.add_interp_cleanup(interpid)
+        linked = is_linked(interpid)
+        refcount = get_refcount(interpid)
+
+        self.assertFalse(linked)
+        self.assertEqual(refcount, 0)
+
+    def test_linked_lifecycle_never_linked(self):
+        exists = _testinternalcapi.interpreter_exists
+        is_linked = _testinternalcapi.interpreter_refcount_linked
+        get_refcount = _testinternalcapi.get_interpreter_refcount
+        incref = _testinternalcapi.interpreter_incref
+        decref = _testinternalcapi.interpreter_decref
+
+        interpid = _testinternalcapi.new_interpreter()
+        self.add_interp_cleanup(interpid)
+
+        # Incref will not automatically link it.
+        incref(interpid)
+        self.assertFalse(
+            is_linked(interpid))
+        self.assertEqual(
+            1, get_refcount(interpid))
+
+        # It isn't linked so it isn't destroyed.
+        decref(interpid)
+        self.assertTrue(
+            exists(interpid))
+        self.assertFalse(
+            is_linked(interpid))
+        self.assertEqual(
+            0, get_refcount(interpid))
+
+    def test_linked_lifecycle_link_unlink(self):
+        exists = _testinternalcapi.interpreter_exists
+        is_linked = _testinternalcapi.interpreter_refcount_linked
+        link = _testinternalcapi.link_interpreter_refcount
+        unlink = _testinternalcapi.unlink_interpreter_refcount
+
+        interpid = _testinternalcapi.new_interpreter()
+        self.add_interp_cleanup(interpid)
+
+        # Linking at refcount 0 does not destroy the interpreter.
+        link(interpid)
+        self.assertTrue(
+            exists(interpid))
+        self.assertTrue(
+            is_linked(interpid))
+
+        # Unlinking at refcount 0 does not destroy the interpreter.
+        unlink(interpid)
+        self.assertTrue(
+            exists(interpid))
+        self.assertFalse(
+            is_linked(interpid))
+
+    def test_linked_lifecycle_link_incref_decref(self):
+        exists = _testinternalcapi.interpreter_exists
+        is_linked = _testinternalcapi.interpreter_refcount_linked
+        link = _testinternalcapi.link_interpreter_refcount
+        get_refcount = _testinternalcapi.get_interpreter_refcount
+        incref = _testinternalcapi.interpreter_incref
+        decref = _testinternalcapi.interpreter_decref
+
+        interpid = _testinternalcapi.new_interpreter()
+        self.add_interp_cleanup(interpid)
+
+        # Linking it will not change the refcount.
+        link(interpid)
+        self.assertTrue(
+            is_linked(interpid))
         self.assertEqual(
-            _testinternalcapi.get_interpreter_refcount(id1),
-            0)
+            0, get_refcount(interpid))
 
-        id2 = self.InterpreterID(id1)
+        # Decref with a refcount of 0 is not allowed.
+        incref(interpid)
         self.assertEqual(
-            _testinternalcapi.get_interpreter_refcount(id1),
-            1)
+            1, get_refcount(interpid))
 
-        # The interpreter isn't linked to ID objects, so it isn't destroyed.
-        del id2
+        # When linked, decref back to 0 destroys the interpreter.
+        decref(interpid)
+        self.assertFalse(
+            exists(interpid))
+
+    def test_linked_lifecycle_incref_link(self):
+        is_linked = _testinternalcapi.interpreter_refcount_linked
+        link = _testinternalcapi.link_interpreter_refcount
+        get_refcount = _testinternalcapi.get_interpreter_refcount
+        incref = _testinternalcapi.interpreter_incref
+
+        interpid = _testinternalcapi.new_interpreter()
+        self.add_interp_cleanup(interpid)
+
+        incref(interpid)
         self.assertEqual(
-            _testinternalcapi.get_interpreter_refcount(id1),
-            0)
+            1, get_refcount(interpid))
 
-        _testinternalcapi.link_interpreter_refcount(id1)
+        # Linking it will not reset the refcount.
+        link(interpid)
+        self.assertTrue(
+            is_linked(interpid))
         self.assertEqual(
-            _testinternalcapi.get_interpreter_refcount(id1),
-            0)
+            1, get_refcount(interpid))
+
+    def test_linked_lifecycle_link_incref_unlink_decref(self):
+        exists = _testinternalcapi.interpreter_exists
+        is_linked = _testinternalcapi.interpreter_refcount_linked
+        link = _testinternalcapi.link_interpreter_refcount
+        unlink = _testinternalcapi.unlink_interpreter_refcount
+        get_refcount = _testinternalcapi.get_interpreter_refcount
+        incref = _testinternalcapi.interpreter_incref
+        decref = _testinternalcapi.interpreter_decref
+
+        interpid = _testinternalcapi.new_interpreter()
+        self.add_interp_cleanup(interpid)
 
-        id3 = self.InterpreterID(id1)
+        link(interpid)
+        self.assertTrue(
+            is_linked(interpid))
+
+        incref(interpid)
+        self.assertEqual(
+            1, get_refcount(interpid))
+
+        # Unlinking it will not change the refcount.
+        unlink(interpid)
+        self.assertFalse(
+            is_linked(interpid))
         self.assertEqual(
-            _testinternalcapi.get_interpreter_refcount(id1),
-            1)
+            1, get_refcount(interpid))
 
-        # The interpreter is linked now so is destroyed.
-        del id3
-        with self.assertRaises(_interpreters.InterpreterNotFoundError):
-            _testinternalcapi.get_interpreter_refcount(id1)
+        # Unlinked: decref back to 0 does not destroys the interpreter.
+        decref(interpid)
+        self.assertTrue(
+            exists(interpid))
+        self.assertEqual(
+            0, get_refcount(interpid))
 
 
 class BuiltinStaticTypesTests(unittest.TestCase):
index cacf14a52cb68e1dd2936bac034749224114378a..c454f31aae1e57bca17595ee8845c46b46f2d6e5 100644 (file)
@@ -507,7 +507,6 @@ OBJECT_OBJS=        \
                Objects/floatobject.o \
                Objects/frameobject.o \
                Objects/funcobject.o \
-               Objects/interpreteridobject.o \
                Objects/iterobject.o \
                Objects/listobject.o \
                Objects/longobject.o \
@@ -1003,7 +1002,6 @@ PYTHON_HEADERS= \
                $(srcdir)/Include/frameobject.h \
                $(srcdir)/Include/genericaliasobject.h \
                $(srcdir)/Include/import.h \
-               $(srcdir)/Include/interpreteridobject.h \
                $(srcdir)/Include/intrcheck.h \
                $(srcdir)/Include/iterobject.h \
                $(srcdir)/Include/listobject.h \
@@ -1077,7 +1075,6 @@ PYTHON_HEADERS= \
                $(srcdir)/Include/cpython/genobject.h \
                $(srcdir)/Include/cpython/import.h \
                $(srcdir)/Include/cpython/initconfig.h \
-               $(srcdir)/Include/cpython/interpreteridobject.h \
                $(srcdir)/Include/cpython/listobject.h \
                $(srcdir)/Include/cpython/longintrepr.h \
                $(srcdir)/Include/cpython/longobject.h \
index 07120f6ccc7207d5677d885c5398a8a59819e4c0..de9a60ce657e0cfa386f564b9fc523ce232a32fc 100644 (file)
@@ -19,3 +19,20 @@ clear_xid_class(PyTypeObject *cls)
     return _PyCrossInterpreterData_UnregisterClass(cls);
 }
 #endif
+
+
+#ifdef RETURNS_INTERPID_OBJECT
+static PyObject *
+get_interpid_obj(PyInterpreterState *interp)
+{
+    if (_PyInterpreterState_IDInitref(interp) != 0) {
+        return NULL;
+    };
+    int64_t id = PyInterpreterState_GetID(interp);
+    if (id < 0) {
+        return NULL;
+    }
+    assert(id < LLONG_MAX);
+    return PyLong_FromLongLong(id);
+}
+#endif
index e68d083955d64afb0e9e369072d307d154243857..16b5e1d257eed2245b825e9db31ffcb31bcdcd70 100644 (file)
@@ -13,7 +13,6 @@
 #include "_testcapi/parts.h"
 
 #include "frameobject.h"          // PyFrame_New()
-#include "interpreteridobject.h"  // PyInterpreterID_Type
 #include "marshal.h"              // PyMarshal_WriteLongToFile()
 
 #include <float.h>                // FLT_MAX
@@ -1449,12 +1448,6 @@ run_in_subinterp(PyObject *self, PyObject *args)
     return PyLong_FromLong(r);
 }
 
-static PyObject *
-get_interpreterid_type(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
-    return Py_NewRef(&PyInterpreterID_Type);
-}
-
 static PyMethodDef ml;
 
 static PyObject *
@@ -3299,7 +3292,6 @@ static PyMethodDef TestMethods[] = {
     {"crash_no_current_thread", crash_no_current_thread,         METH_NOARGS},
     {"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},
     {"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 f73a29e5afe80159f5f067303189193578583443..e1717f7a66b1de26eef4306157781cb5b7c80203 100644 (file)
@@ -1475,6 +1475,83 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
 }
 
 
+static PyObject *
+normalize_interp_id(PyObject *self, PyObject *idobj)
+{
+    int64_t interpid = _PyInterpreterState_ObjectToID(idobj);
+    if (interpid < 0) {
+        return NULL;
+    }
+    return PyLong_FromLongLong(interpid);
+}
+
+static PyObject *
+unused_interpreter_id(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    int64_t interpid = INT64_MAX;
+    assert(interpid > _PyRuntime.interpreters.next_id);
+    return PyLong_FromLongLong(interpid);
+}
+
+static PyObject *
+new_interpreter(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    // Unlike _interpreters.create(), we do not automatically link
+    // the interpreter to its refcount.
+    PyThreadState *save_tstate = PyThreadState_Get();
+    const PyInterpreterConfig config = \
+            (PyInterpreterConfig)_PyInterpreterConfig_INIT;
+    PyThreadState *tstate = NULL;
+    PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config);
+    PyThreadState_Swap(save_tstate);
+    if (PyStatus_Exception(status)) {
+        _PyErr_SetFromPyStatus(status);
+        return NULL;
+    }
+    PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
+
+    if (_PyInterpreterState_IDInitref(interp) < 0) {
+        goto error;
+    }
+
+    int64_t interpid = PyInterpreterState_GetID(interp);
+    if (interpid < 0) {
+        goto error;
+    }
+    PyObject *idobj = PyLong_FromLongLong(interpid);
+    if (idobj == NULL) {
+        goto error;
+    }
+
+    PyThreadState_Swap(tstate);
+    PyThreadState_Clear(tstate);
+    PyThreadState_Swap(save_tstate);
+    PyThreadState_Delete(tstate);
+
+    return idobj;
+
+error:
+    save_tstate = PyThreadState_Swap(tstate);
+    Py_EndInterpreter(tstate);
+    PyThreadState_Swap(save_tstate);
+    return NULL;
+}
+
+static PyObject *
+interpreter_exists(PyObject *self, PyObject *idobj)
+{
+    PyInterpreterState *interp = _PyInterpreterState_LookUpIDObject(idobj);
+    if (interp == NULL) {
+        if (PyErr_ExceptionMatches(PyExc_InterpreterNotFoundError)) {
+            PyErr_Clear();
+            Py_RETURN_FALSE;
+        }
+        assert(PyErr_Occurred());
+        return NULL;
+    }
+    Py_RETURN_TRUE;
+}
+
 static PyObject *
 get_interpreter_refcount(PyObject *self, PyObject *idobj)
 {
@@ -1509,6 +1586,41 @@ unlink_interpreter_refcount(PyObject *self, PyObject *idobj)
     Py_RETURN_NONE;
 }
 
+static PyObject *
+interpreter_refcount_linked(PyObject *self, PyObject *idobj)
+{
+    PyInterpreterState *interp = _PyInterpreterState_LookUpIDObject(idobj);
+    if (interp == NULL) {
+        return NULL;
+    }
+    if (_PyInterpreterState_RequiresIDRef(interp)) {
+        Py_RETURN_TRUE;
+    }
+    Py_RETURN_FALSE;
+}
+
+static PyObject *
+interpreter_incref(PyObject *self, PyObject *idobj)
+{
+    PyInterpreterState *interp = _PyInterpreterState_LookUpIDObject(idobj);
+    if (interp == NULL) {
+        return NULL;
+    }
+    _PyInterpreterState_IDIncref(interp);
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+interpreter_decref(PyObject *self, PyObject *idobj)
+{
+    PyInterpreterState *interp = _PyInterpreterState_LookUpIDObject(idobj);
+    if (interp == NULL) {
+        return NULL;
+    }
+    _PyInterpreterState_IDDecref(interp);
+    Py_RETURN_NONE;
+}
+
 
 static void
 _xid_capsule_destructor(PyObject *capsule)
@@ -1749,9 +1861,16 @@ static PyMethodDef module_functions[] = {
     {"run_in_subinterp_with_config",
      _PyCFunction_CAST(run_in_subinterp_with_config),
      METH_VARARGS | METH_KEYWORDS},
+    {"normalize_interp_id", normalize_interp_id, METH_O},
+    {"unused_interpreter_id", unused_interpreter_id, METH_NOARGS},
+    {"new_interpreter", new_interpreter, METH_NOARGS},
+    {"interpreter_exists", interpreter_exists, METH_O},
     {"get_interpreter_refcount", get_interpreter_refcount, METH_O},
     {"link_interpreter_refcount", link_interpreter_refcount,     METH_O},
     {"unlink_interpreter_refcount", unlink_interpreter_refcount, METH_O},
+    {"interpreter_refcount_linked", interpreter_refcount_linked, METH_O},
+    {"interpreter_incref", interpreter_incref, METH_O},
+    {"interpreter_decref", interpreter_decref, 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 28ec00a159d6cd2f518506b79e025189d7b39cb0..b63a3aab8263bc3d182554b803664e35781f89a9 100644 (file)
@@ -6,7 +6,6 @@
 #endif
 
 #include "Python.h"
-#include "interpreteridobject.h"
 #include "pycore_crossinterp.h"   // struct _xid
 #include "pycore_interp.h"        // _PyInterpreterState_LookUpID()
 
@@ -18,7 +17,9 @@
 #endif
 
 #define REGISTERS_HEAP_TYPES
+#define RETURNS_INTERPID_OBJECT
 #include "_interpreters_common.h"
+#undef RETURNS_INTERPID_OBJECT
 #undef REGISTERS_HEAP_TYPES
 
 
@@ -2908,7 +2909,7 @@ channelsmod_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
             goto except;
         }
         if (res) {
-            interpid_obj = PyInterpreterState_GetIDObject(interp);
+            interpid_obj = get_interpid_obj(interp);
             if (interpid_obj == NULL) {
                 goto except;
             }
index 606b2a36481ce2371923f9b00dadf6caeaf28a2b..befa225c9183c5ab5c3da77a8d387bc69a3d9862 100644 (file)
 #include "pycore_pyerrors.h"      // _Py_excinfo
 #include "pycore_pystate.h"       // _PyInterpreterState_SetRunningMain()
 
-#include "interpreteridobject.h"
 #include "marshal.h"              // PyMarshal_ReadObjectFromString()
 
+#define RETURNS_INTERPID_OBJECT
 #include "_interpreters_common.h"
+#undef RETURNS_INTERPID_OBJECT
 
 
 #define MODULE_NAME _xxsubinterpreters
@@ -38,20 +39,6 @@ _get_current_interp(void)
 #define look_up_interp _PyInterpreterState_LookUpIDObject
 
 
-static PyObject *
-get_interpid_obj(PyInterpreterState *interp)
-{
-    if (_PyInterpreterState_IDInitref(interp) != 0) {
-        return NULL;
-    };
-    int64_t id = PyInterpreterState_GetID(interp);
-    if (id < 0) {
-        return NULL;
-    }
-    assert(id < LLONG_MAX);
-    return PyLong_FromLongLong(id);
-}
-
 static PyObject *
 _get_current_module(void)
 {
diff --git a/Objects/interpreteridobject.c b/Objects/interpreteridobject.c
deleted file mode 100644 (file)
index 4844d6a..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/* InterpreterID object */
-
-#include "Python.h"
-#include "pycore_interp.h"        // _PyInterpreterState_LookUpID()
-#include "interpreteridobject.h"
-
-
-typedef struct interpid {
-    PyObject_HEAD
-    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)
-{
-    PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
-    if (interp == NULL) {
-        if (force) {
-            PyErr_Clear();
-        }
-        else {
-            return NULL;
-        }
-    }
-
-    if (interp != NULL) {
-        if (_PyInterpreterState_IDIncref(interp) < 0) {
-            return NULL;
-        }
-    }
-
-    interpid *self = PyObject_New(interpid, cls);
-    if (self == NULL) {
-        if (interp != NULL) {
-            _PyInterpreterState_IDDecref(interp);
-        }
-        return NULL;
-    }
-    self->id = id;
-
-    return self;
-}
-
-static PyObject *
-interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
-{
-    static char *kwlist[] = {"id", "force", NULL};
-    PyObject *idobj;
-    int force = 0;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds,
-                                     "O|$p:InterpreterID.__init__", kwlist,
-                                     &idobj, &force)) {
-        return NULL;
-    }
-    int64_t id = _PyInterpreterState_ObjectToID(idobj);
-    if (id < 0) {
-        return NULL;
-    }
-
-    return (PyObject *)newinterpid(cls, id, force);
-}
-
-static void
-interpid_dealloc(PyObject *v)
-{
-    int64_t id = ((interpid *)v)->id;
-    PyInterpreterState *interp = _PyInterpreterState_LookUpID(id);
-    if (interp != NULL) {
-        _PyInterpreterState_IDDecref(interp);
-    }
-    else {
-        // already deleted
-        PyErr_Clear();
-    }
-    Py_TYPE(v)->tp_free(v);
-}
-
-static PyObject *
-interpid_repr(PyObject *self)
-{
-    PyTypeObject *type = Py_TYPE(self);
-    const char *name = _PyType_Name(type);
-    interpid *id = (interpid *)self;
-    return PyUnicode_FromFormat("%s(%" PRId64 ")", name, id->id);
-}
-
-static PyObject *
-interpid_str(PyObject *self)
-{
-    interpid *id = (interpid *)self;
-    return PyUnicode_FromFormat("%" PRId64 "", id->id);
-}
-
-static PyObject *
-interpid_int(PyObject *self)
-{
-    interpid *id = (interpid *)self;
-    return PyLong_FromLongLong(id->id);
-}
-
-static PyNumberMethods interpid_as_number = {
-     0,                       /* nb_add */
-     0,                       /* nb_subtract */
-     0,                       /* nb_multiply */
-     0,                       /* nb_remainder */
-     0,                       /* nb_divmod */
-     0,                       /* nb_power */
-     0,                       /* nb_negative */
-     0,                       /* nb_positive */
-     0,                       /* nb_absolute */
-     0,                       /* nb_bool */
-     0,                       /* nb_invert */
-     0,                       /* nb_lshift */
-     0,                       /* nb_rshift */
-     0,                       /* nb_and */
-     0,                       /* nb_xor */
-     0,                       /* nb_or */
-     (unaryfunc)interpid_int, /* nb_int */
-     0,                       /* nb_reserved */
-     0,                       /* nb_float */
-
-     0,                       /* nb_inplace_add */
-     0,                       /* nb_inplace_subtract */
-     0,                       /* nb_inplace_multiply */
-     0,                       /* nb_inplace_remainder */
-     0,                       /* nb_inplace_power */
-     0,                       /* nb_inplace_lshift */
-     0,                       /* nb_inplace_rshift */
-     0,                       /* nb_inplace_and */
-     0,                       /* nb_inplace_xor */
-     0,                       /* nb_inplace_or */
-
-     0,                       /* nb_floor_divide */
-     0,                       /* nb_true_divide */
-     0,                       /* nb_inplace_floor_divide */
-     0,                       /* nb_inplace_true_divide */
-
-     (unaryfunc)interpid_int, /* nb_index */
-};
-
-static Py_hash_t
-interpid_hash(PyObject *self)
-{
-    interpid *id = (interpid *)self;
-    PyObject *obj = PyLong_FromLongLong(id->id);
-    if (obj == NULL) {
-        return -1;
-    }
-    Py_hash_t hash = PyObject_Hash(obj);
-    Py_DECREF(obj);
-    return hash;
-}
-
-static PyObject *
-interpid_richcompare(PyObject *self, PyObject *other, int op)
-{
-    if (op != Py_EQ && op != Py_NE) {
-        Py_RETURN_NOTIMPLEMENTED;
-    }
-
-    if (!PyObject_TypeCheck(self, &PyInterpreterID_Type)) {
-        Py_RETURN_NOTIMPLEMENTED;
-    }
-
-    interpid *id = (interpid *)self;
-    int equal;
-    if (PyObject_TypeCheck(other, &PyInterpreterID_Type)) {
-        interpid *otherid = (interpid *)other;
-        equal = (id->id == otherid->id);
-    }
-    else if (PyLong_CheckExact(other)) {
-        /* Fast path */
-        int overflow;
-        long long otherid = PyLong_AsLongLongAndOverflow(other, &overflow);
-        if (otherid == -1 && PyErr_Occurred()) {
-            return NULL;
-        }
-        equal = !overflow && (otherid >= 0) && (id->id == otherid);
-    }
-    else if (PyNumber_Check(other)) {
-        PyObject *pyid = PyLong_FromLongLong(id->id);
-        if (pyid == NULL) {
-            return NULL;
-        }
-        PyObject *res = PyObject_RichCompare(pyid, other, op);
-        Py_DECREF(pyid);
-        return res;
-    }
-    else {
-        Py_RETURN_NOTIMPLEMENTED;
-    }
-
-    if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
-        Py_RETURN_TRUE;
-    }
-    Py_RETURN_FALSE;
-}
-
-PyDoc_STRVAR(interpid_doc,
-"A interpreter ID identifies a interpreter and may be used as an int.");
-
-PyTypeObject PyInterpreterID_Type = {
-    PyVarObject_HEAD_INIT(&PyType_Type, 0)
-    "InterpreterID",   /* tp_name */
-    sizeof(interpid),               /* tp_basicsize */
-    0,                              /* tp_itemsize */
-    (destructor)interpid_dealloc,   /* tp_dealloc */
-    0,                              /* tp_vectorcall_offset */
-    0,                              /* tp_getattr */
-    0,                              /* tp_setattr */
-    0,                              /* tp_as_async */
-    (reprfunc)interpid_repr,        /* tp_repr */
-    &interpid_as_number,            /* tp_as_number */
-    0,                              /* tp_as_sequence */
-    0,                              /* tp_as_mapping */
-    interpid_hash,                  /* tp_hash */
-    0,                              /* tp_call */
-    (reprfunc)interpid_str,         /* tp_str */
-    0,                              /* tp_getattro */
-    0,                              /* tp_setattro */
-    0,                              /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    interpid_doc,                   /* tp_doc */
-    0,                              /* tp_traverse */
-    0,                              /* tp_clear */
-    interpid_richcompare,           /* tp_richcompare */
-    0,                              /* tp_weaklistoffset */
-    0,                              /* tp_iter */
-    0,                              /* tp_iternext */
-    0,                              /* tp_methods */
-    0,                              /* tp_members */
-    0,                              /* tp_getset */
-    0,                              /* tp_base */
-    0,                              /* tp_dict */
-    0,                              /* tp_descr_get */
-    0,                              /* tp_descr_set */
-    0,                              /* tp_dictoffset */
-    0,                              /* tp_init */
-    0,                              /* tp_alloc */
-    interpid_new,                   /* tp_new */
-};
-
-PyObject *PyInterpreterID_New(int64_t id)
-{
-    return (PyObject *)newinterpid(&PyInterpreterID_Type, id, 0);
-}
-
-PyObject *
-PyInterpreterState_GetIDObject(PyInterpreterState *interp)
-{
-    if (_PyInterpreterState_IDInitref(interp) != 0) {
-        return NULL;
-    };
-    int64_t id = PyInterpreterState_GetID(interp);
-    if (id < 0) {
-        return NULL;
-    }
-    return (PyObject *)newinterpid(&PyInterpreterID_Type, id, 0);
-}
index 0d03292c9115cd8a6b634d81241302004e4cbdc0..b4f0fd4d7db941cbeb8c937bbba261f05a2552ab 100644 (file)
@@ -24,8 +24,6 @@
 #include "pycore_typevarobject.h" // _PyTypeAlias_Type, _Py_initialize_generic
 #include "pycore_unionobject.h"   // _PyUnion_Type
 
-#include "interpreteridobject.h"  // _PyInterpreterID_Type
-
 #ifdef Py_LIMITED_API
    // Prevent recursive call _Py_IncRef() <=> Py_INCREF()
 #  error "Py_LIMITED_API macro must not be defined"
@@ -2240,7 +2238,6 @@ static PyTypeObject* static_types[] = {
     &PyGen_Type,
     &PyGetSetDescr_Type,
     &PyInstanceMethod_Type,
-    &PyInterpreterID_Type,
     &PyListIter_Type,
     &PyListRevIter_Type,
     &PyList_Type,
index bce92c91f1ca0d9c566f585f4defc5855d9a013f..82471e0f140ec3cf7d3cab90a8a730b7271538db 100644 (file)
     <ClCompile Include="..\Objects\funcobject.c" />
     <ClCompile Include="..\Objects\genericaliasobject.c" />
     <ClCompile Include="..\Objects\genobject.c" />
-    <ClCompile Include="..\Objects\interpreteridobject.c" />
     <ClCompile Include="..\Objects\iterobject.c" />
     <ClCompile Include="..\Objects\listobject.c" />
     <ClCompile Include="..\Objects\longobject.c" />
index 5b34440af9322b508569457ecff8fb04e485dcea..97c52fdadf7c057768a71dd60ad16617b2e9c6fa 100644 (file)
     <ClCompile Include="..\Python\lock.c">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="..\Objects\interpreteridobject.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="..\PC\invalid_parameter_handler.c">
       <Filter>Source Files</Filter>
     </ClCompile>
index 9131ce87db6c84b012ed1cfdd9bb99c6a04af1bd..c944bbafdba7e595ca814ff4725a207b42d4d5d8 100644 (file)
     <ClInclude Include="..\Include\cpython\genobject.h" />
     <ClInclude Include="..\Include\cpython\import.h" />
     <ClInclude Include="..\Include\cpython\initconfig.h" />
-    <ClInclude Include="..\Include\cpython\interpreteridobject.h" />
     <ClInclude Include="..\Include\cpython\listobject.h" />
     <ClInclude Include="..\Include\cpython\longintrepr.h" />
     <ClInclude Include="..\Include\cpython\longobject.h" />
     <ClInclude Include="..\Include\internal\pycore_unicodeobject_generated.h" />
     <ClInclude Include="..\Include\internal\pycore_warnings.h" />
     <ClInclude Include="..\Include\internal\pycore_weakref.h" />
-    <ClInclude Include="..\Include\interpreteridobject.h" />
     <ClInclude Include="..\Include\intrcheck.h" />
     <ClInclude Include="..\Include\iterobject.h" />
     <ClInclude Include="..\Include\listobject.h" />
     <ClCompile Include="..\Objects\funcobject.c" />
     <ClCompile Include="..\Objects\genericaliasobject.c" />
     <ClCompile Include="..\Objects\genobject.c" />
-    <ClCompile Include="..\Objects\interpreteridobject.c" />
     <ClCompile Include="..\Objects\iterobject.c" />
     <ClCompile Include="..\Objects\listobject.c" />
     <ClCompile Include="..\Objects\longobject.c" />
index 27bd1121663398f5baa2fc2acca8448ac5477062..0afad125ce1e97781f2f67a8801ae55636eb1744 100644 (file)
     <ClInclude Include="..\Include\pyhash.h">
       <Filter>Include</Filter>
     </ClInclude>
-    <ClInclude Include="..\Include\interpreteridobject.h">
-      <Filter>Include</Filter>
-    </ClInclude>
     <ClInclude Include="..\Modules\hashtable.h">
       <Filter>Modules</Filter>
     </ClInclude>
     <ClInclude Include="..\Include\cpython\genobject.h">
       <Filter>Include</Filter>
     </ClInclude>
-    <ClInclude Include="..\Include\cpython\interpreteridobject.h">
-      <Filter>Include\cpython</Filter>
-    </ClInclude>
     <ClInclude Include="..\Include\cpython\pythonrun.h">
       <Filter>Include\cpython</Filter>
     </ClInclude>
     <ClCompile Include="..\Objects\namespaceobject.c">
       <Filter>Objects</Filter>
     </ClCompile>
-    <ClCompile Include="..\Objects\interpreteridobject.c">
-      <Filter>Objects</Filter>
-    </ClCompile>
     <ClCompile Include="..\Modules\_opcode.c">
       <Filter>Modules</Filter>
     </ClCompile>
index 6d63eac22a470ca9b57ac77adae947296e76a7ff..3ef405105a8d46631387f9c5430f0f7a6e7e558a 100644 (file)
@@ -2,7 +2,6 @@
 /* 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
@@ -1131,10 +1130,6 @@ PyInterpreterState_GetDict(PyInterpreterState *interp)
 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",
index 686a3d3160cc906c35249964cab56a59e03adc06..92fab9b399863680d8aeb164af61cd93dd35c09a 100644 (file)
@@ -54,7 +54,6 @@ Objects/genobject.c   -       _PyAsyncGenASend_Type   -
 Objects/genobject.c    -       _PyAsyncGenAThrow_Type  -
 Objects/genobject.c    -       _PyAsyncGenWrappedValue_Type    -
 Objects/genobject.c    -       _PyCoroWrapper_Type     -
-Objects/interpreteridobject.c  -       PyInterpreterID_Type    -
 Objects/iterobject.c   -       PyCallIter_Type -
 Objects/iterobject.c   -       PySeqIter_Type  -
 Objects/iterobject.c   -       _PyAnextAwaitable_Type  -