Mailing List Archive

gh-76785: Drop PyInterpreterID_Type (gh-117101)
https://github.com/python/cpython/commit/617158e07811edfd6fd552a3d84b0beedd8f1d18
commit: 617158e07811edfd6fd552a3d84b0beedd8f1d18
branch: main
author: Eric Snow <ericsnowcurrently@gmail.com>
committer: ericsnowcurrently <ericsnowcurrently@gmail.com>
date: 2024-03-21T17:15:02Z
summary:

gh-76785: Drop PyInterpreterID_Type (gh-117101)

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.

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

diff --git a/Include/cpython/interpreteridobject.h b/Include/cpython/interpreteridobject.h
deleted file mode 100644
index d425c909806e44..00000000000000
--- a/Include/cpython/interpreteridobject.h
+++ /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
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index b28e8a3ff45f3f..b8d0fdcce11ba8 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -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
index 8432632f339e92..00000000000000
--- a/Include/interpreteridobject.h
+++ /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 */
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index fe5e19d46d8b6c..55a1ab6d6d9359 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -2207,132 +2207,264 @@ def test_module_state_shared_in_global(self):
@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):
diff --git a/Makefile.pre.in b/Makefile.pre.in
index cacf14a52cb68e..c454f31aae1e57 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -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 \
diff --git a/Modules/_interpreters_common.h b/Modules/_interpreters_common.h
index 07120f6ccc7207..de9a60ce657e0c 100644
--- a/Modules/_interpreters_common.h
+++ b/Modules/_interpreters_common.h
@@ -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
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index e68d083955d64a..16b5e1d257eed2 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -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")},
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index f73a29e5afe801..e1717f7a66b1de 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -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},
diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c
index 28ec00a159d6cd..b63a3aab8263bc 100644
--- a/Modules/_xxinterpchannelsmodule.c
+++ b/Modules/_xxinterpchannelsmodule.c
@@ -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;
}
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 606b2a36481ce2..befa225c9183c5 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -16,10 +16,11 @@
#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
index 4844d6a9bf781c..00000000000000
--- a/Objects/interpreteridobject.c
+++ /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);
-}
diff --git a/Objects/object.c b/Objects/object.c
index 0d03292c9115cd..b4f0fd4d7db941 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -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,
diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj
index bce92c91f1ca0d..82471e0f140ec3 100644
--- a/PCbuild/_freeze_module.vcxproj
+++ b/PCbuild/_freeze_module.vcxproj
@@ -142,7 +142,6 @@
<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" />
diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters
index 5b34440af9322b..97c52fdadf7c05 100644
--- a/PCbuild/_freeze_module.vcxproj.filters
+++ b/PCbuild/_freeze_module.vcxproj.filters
@@ -241,9 +241,6 @@
<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>
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 9131ce87db6c84..c944bbafdba7e5 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -154,7 +154,6 @@
<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" />
@@ -303,7 +302,6 @@
<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" />
@@ -504,7 +502,6 @@
<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" />
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 27bd1121663398..0afad125ce1e97 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -330,9 +330,6 @@
<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>
@@ -492,9 +489,6 @@
<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>
@@ -1475,9 +1469,6 @@
<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>
diff --git a/Python/pystate.c b/Python/pystate.c
index 6d63eac22a470c..3ef405105a8d46 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -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",
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index 686a3d3160cc90..92fab9b3998636 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -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 -

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-leave@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: list-python-checkins@lists.gossamer-threads.com