[Python-checkins] Revert: bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). (GH-11617) (GH-12159)

Victor Stinner webhook-mailer at python.org
Mon Mar 4 08:21:32 EST 2019


https://github.com/python/cpython/commit/4d61e6e3b802399be62a521d6fa785698cb670b5
commit: 4d61e6e3b802399be62a521d6fa785698cb670b5
branch: master
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2019-03-04T14:21:28+01:00
summary:

Revert: bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). (GH-11617) (GH-12159)

* Revert "bpo-36097: Use only public C-API in the_xxsubinterpreters module (adding as necessary). (#12003)"

This reverts commit bcfa450f210074e16feb761ae5b3e966a2532fcf.

* Revert "bpo-33608: Simplify ceval's DISPATCH by hoisting eval_breaker ahead of time. (gh-12062)"

This reverts commit bda918bf65a88560ec453aaba0758a9c0d49b449.

* Revert "bpo-33608: Use _Py_AddPendingCall() in _PyCrossInterpreterData_Release(). (gh-12024)"

This reverts commit b05b711a2cef6c6c381e01069dedac372e0b9fb2.

* Revert "bpo-33608: Factor out a private, per-interpreter _Py_AddPendingCall(). (GH-11617)"

This reverts commit ef4ac967e2f3a9a18330cc6abe14adb4bc3d0465.

files:
D Include/cpython/interpreteridobject.h
D Include/interpreteridobject.h
D Objects/interpreteridobject.c
M Include/ceval.h
M Include/cpython/pystate.h
M Include/internal/pycore_atomic.h
M Include/internal/pycore_ceval.h
M Include/internal/pycore_pystate.h
M Makefile.pre.in
M Modules/_testcapimodule.c
M Modules/_xxsubinterpretersmodule.c
M Modules/signalmodule.c
M Objects/object.c
M PCbuild/pythoncore.vcxproj
M PCbuild/pythoncore.vcxproj.filters
M Python/ceval.c
M Python/ceval_gil.h
M Python/pylifecycle.c
M Python/pystate.c
M setup.py

diff --git a/Include/ceval.h b/Include/ceval.h
index 9c6d420bc234..11283c0a570b 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -221,7 +221,7 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
 #ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
 PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
-PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyInterpreterState *);
+PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void);
 #endif
 
 /* Masks and values used by FORMAT_VALUE opcode. */
diff --git a/Include/cpython/interpreteridobject.h b/Include/cpython/interpreteridobject.h
deleted file mode 100644
index cb72c2b0895a..000000000000
--- a/Include/cpython/interpreteridobject.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef Py_CPYTHON_INTERPRETERIDOBJECT_H
-#  error "this header file must not be included directly"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Interpreter ID Object */
-
-PyAPI_DATA(PyTypeObject) _PyInterpreterID_Type;
-
-PyAPI_FUNC(PyObject *) _PyInterpreterID_New(int64_t);
-PyAPI_FUNC(PyObject *) _PyInterpreterState_GetIDObject(PyInterpreterState *);
-PyAPI_FUNC(PyInterpreterState *) _PyInterpreterID_LookUp(PyObject *);
-
-PyAPI_FUNC(int64_t) _Py_CoerceID(PyObject *);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index 5439d07e6af3..3fca78f9ddf2 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -30,13 +30,9 @@ typedef struct {
     (_PyMainInterpreterConfig){.install_signal_handlers = -1}
 /* Note: _PyMainInterpreterConfig_INIT sets other fields to 0/NULL */
 
-PyAPI_FUNC(int) _PyInterpreterState_RequiresIDRef(PyInterpreterState *);
-PyAPI_FUNC(void) _PyInterpreterState_RequireIDRef(PyInterpreterState *, int);
-
 PyAPI_FUNC(_PyCoreConfig *) _PyInterpreterState_GetCoreConfig(PyInterpreterState *);
 PyAPI_FUNC(_PyMainInterpreterConfig *) _PyInterpreterState_GetMainConfig(PyInterpreterState *);
 
-PyAPI_FUNC(PyObject *) _PyInterpreterState_GetMainModule(PyInterpreterState *);
 
 /* State unique per thread */
 
@@ -218,65 +214,6 @@ PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *);
 
 typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_);
 
-/* cross-interpreter data */
-
-struct _xid;
-
-// _PyCrossInterpreterData is similar to Py_buffer as an effectively
-// opaque struct that holds data outside the object machinery.  This
-// is necessary to pass safely between interpreters in the same process.
-typedef struct _xid {
-    // data is the cross-interpreter-safe derivation of a Python object
-    // (see _PyObject_GetCrossInterpreterData).  It will be NULL if the
-    // new_object func (below) encodes the data.
-    void *data;
-    // obj is the Python object from which the data was derived.  This
-    // is non-NULL only if the data remains bound to the object in some
-    // way, such that the object must be "released" (via a decref) when
-    // the data is released.  In that case the code that sets the field,
-    // likely a registered "crossinterpdatafunc", is responsible for
-    // ensuring it owns the reference (i.e. incref).
-    PyObject *obj;
-    // interp is the ID of the owning interpreter of the original
-    // object.  It corresponds to the active interpreter when
-    // _PyObject_GetCrossInterpreterData() was called.  This should only
-    // be set by the cross-interpreter machinery.
-    //
-    // We use the ID rather than the PyInterpreterState to avoid issues
-    // with deleted interpreters.  Note that IDs are never re-used, so
-    // each one will always correspond to a specific interpreter
-    // (whether still alive or not).
-    int64_t interp;
-    // new_object is a function that returns a new object in the current
-    // interpreter given the data.  The resulting object (a new
-    // reference) will be equivalent to the original object.  This field
-    // is required.
-    PyObject *(*new_object)(struct _xid *);
-    // free is called when the data is released.  If it is NULL then
-    // nothing will be done to free the data.  For some types this is
-    // okay (e.g. bytes) and for those types this field should be set
-    // to NULL.  However, for most the data was allocated just for
-    // cross-interpreter use, so it must be freed when
-    // _PyCrossInterpreterData_Release is called or the memory will
-    // leak.  In that case, at the very least this field should be set
-    // to PyMem_RawFree (the default if not explicitly set to NULL).
-    // The call will happen with the original interpreter activated.
-    void (*free)(void *);
-} _PyCrossInterpreterData;
-
-PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *);
-PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *);
-PyAPI_FUNC(void) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *);
-
-PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *);
-
-/* cross-interpreter data registry */
-
-typedef int (*crossinterpdatafunc)(PyObject *, struct _xid *);
-
-PyAPI_FUNC(int) _PyCrossInterpreterData_RegisterClass(PyTypeObject *, crossinterpdatafunc);
-PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/Include/internal/pycore_atomic.h b/Include/internal/pycore_atomic.h
index 7aa7eed6f7c2..5669f71b941f 100644
--- a/Include/internal/pycore_atomic.h
+++ b/Include/internal/pycore_atomic.h
@@ -58,10 +58,10 @@ typedef struct _Py_atomic_int {
     atomic_thread_fence(ORDER)
 
 #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
-    atomic_store_explicit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER)
+    atomic_store_explicit(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER)
 
 #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
-    atomic_load_explicit(&((ATOMIC_VAL)->_value), ORDER)
+    atomic_load_explicit(&(ATOMIC_VAL)->_value, ORDER)
 
 /* Use builtin atomic operations in GCC >= 4.7 */
 #elif defined(HAVE_BUILTIN_ATOMIC)
@@ -92,14 +92,14 @@ typedef struct _Py_atomic_int {
     (assert((ORDER) == __ATOMIC_RELAXED                       \
             || (ORDER) == __ATOMIC_SEQ_CST                    \
             || (ORDER) == __ATOMIC_RELEASE),                  \
-     __atomic_store_n(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER))
+     __atomic_store_n(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER))
 
 #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER)           \
     (assert((ORDER) == __ATOMIC_RELAXED                       \
             || (ORDER) == __ATOMIC_SEQ_CST                    \
             || (ORDER) == __ATOMIC_ACQUIRE                    \
             || (ORDER) == __ATOMIC_CONSUME),                  \
-     __atomic_load_n(&((ATOMIC_VAL)->_value), ORDER))
+     __atomic_load_n(&(ATOMIC_VAL)->_value, ORDER))
 
 /* Only support GCC (for expression statements) and x86 (for simple
  * atomic semantics) and MSVC x86/x64/ARM */
@@ -324,7 +324,7 @@ inline intptr_t _Py_atomic_load_64bit(volatile uintptr_t* value, int order) {
 }
 
 #else
-#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *(ATOMIC_VAL)
+#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *ATOMIC_VAL
 #endif
 
 inline int _Py_atomic_load_32bit(volatile int* value, int order) {
@@ -359,15 +359,15 @@ inline int _Py_atomic_load_32bit(volatile int* value, int order) {
 }
 
 #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
-  if (sizeof((ATOMIC_VAL)->_value) == 8) { \
-    _Py_atomic_store_64bit((volatile long long*)&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) } else { \
-    _Py_atomic_store_32bit((volatile long*)&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) }
+  if (sizeof(*ATOMIC_VAL._value) == 8) { \
+    _Py_atomic_store_64bit((volatile long long*)ATOMIC_VAL._value, NEW_VAL, ORDER) } else { \
+    _Py_atomic_store_32bit((volatile long*)ATOMIC_VAL._value, NEW_VAL, ORDER) }
 
 #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
   ( \
-    sizeof((ATOMIC_VAL)->_value) == 8 ? \
-    _Py_atomic_load_64bit((volatile long long*)&((ATOMIC_VAL)->_value), ORDER) : \
-    _Py_atomic_load_32bit((volatile long*)&((ATOMIC_VAL)->_value), ORDER) \
+    sizeof(*(ATOMIC_VAL._value)) == 8 ? \
+    _Py_atomic_load_64bit((volatile long long*)ATOMIC_VAL._value, ORDER) : \
+    _Py_atomic_load_32bit((volatile long*)ATOMIC_VAL._value, ORDER) \
   )
 #elif defined(_M_ARM) || defined(_M_ARM64)
 typedef enum _Py_memory_order {
@@ -391,13 +391,13 @@ typedef struct _Py_atomic_int {
 #define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) \
     switch (ORDER) { \
     case _Py_memory_order_acquire: \
-      _InterlockedExchange64_acq((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \
+      _InterlockedExchange64_acq((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
       break; \
     case _Py_memory_order_release: \
-      _InterlockedExchange64_rel((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \
+      _InterlockedExchange64_rel((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
       break; \
     default: \
-      _InterlockedExchange64((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \
+      _InterlockedExchange64((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
       break; \
   }
 #else
@@ -407,13 +407,13 @@ typedef struct _Py_atomic_int {
 #define _Py_atomic_store_32bit(ATOMIC_VAL, NEW_VAL, ORDER) \
   switch (ORDER) { \
   case _Py_memory_order_acquire: \
-    _InterlockedExchange_acq((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \
+    _InterlockedExchange_acq((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
     break; \
   case _Py_memory_order_release: \
-    _InterlockedExchange_rel((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \
+    _InterlockedExchange_rel((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
     break; \
   default: \
-    _InterlockedExchange((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \
+    _InterlockedExchange((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
     break; \
   }
 
@@ -454,7 +454,7 @@ inline intptr_t _Py_atomic_load_64bit(volatile uintptr_t* value, int order) {
 }
 
 #else
-#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *(ATOMIC_VAL)
+#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *ATOMIC_VAL
 #endif
 
 inline int _Py_atomic_load_32bit(volatile int* value, int order) {
@@ -489,15 +489,15 @@ inline int _Py_atomic_load_32bit(volatile int* value, int order) {
 }
 
 #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
-  if (sizeof((ATOMIC_VAL)->_value) == 8) { \
-    _Py_atomic_store_64bit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) } else { \
-    _Py_atomic_store_32bit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) }
+  if (sizeof(*ATOMIC_VAL._value) == 8) { \
+    _Py_atomic_store_64bit(ATOMIC_VAL._value, NEW_VAL, ORDER) } else { \
+    _Py_atomic_store_32bit(ATOMIC_VAL._value, NEW_VAL, ORDER) }
 
 #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
   ( \
-    sizeof((ATOMIC_VAL)->_value) == 8 ? \
-    _Py_atomic_load_64bit(&((ATOMIC_VAL)->_value), ORDER) : \
-    _Py_atomic_load_32bit(&((ATOMIC_VAL)->_value), ORDER) \
+    sizeof(*(ATOMIC_VAL._value)) == 8 ? \
+    _Py_atomic_load_64bit(ATOMIC_VAL._value, ORDER) : \
+    _Py_atomic_load_32bit(ATOMIC_VAL._value, ORDER) \
   )
 #endif
 #else  /* !gcc x86  !_msc_ver */
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 5a80f6fee06e..b9f2d7d17585 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -11,12 +11,8 @@ extern "C" {
 #include "pycore_atomic.h"
 #include "pythread.h"
 
-struct _is;  // See PyInterpreterState in cpython/pystate.h.
-
-PyAPI_FUNC(int) _Py_AddPendingCall(struct _is*, unsigned long, int (*)(void *), void *);
-PyAPI_FUNC(int) _Py_MakePendingCalls(struct _is*);
-
 struct _pending_calls {
+    unsigned long main_thread;
     PyThread_type_lock lock;
     /* Request for running pending calls. */
     _Py_atomic_int calls_to_do;
@@ -26,7 +22,6 @@ struct _pending_calls {
     int async_exc;
 #define NPENDINGCALLS 32
     struct {
-        unsigned long thread_id;
         int (*func)(void *);
         void *arg;
     } calls[NPENDINGCALLS];
@@ -34,13 +29,6 @@ struct _pending_calls {
     int last;
 };
 
-struct _ceval_interpreter_state {
-    /* This single variable consolidates all requests to break out of
-       the fast path in the eval loop. */
-    _Py_atomic_int eval_breaker;
-    struct _pending_calls pending;
-};
-
 #include "pycore_gil.h"
 
 struct _ceval_runtime_state {
@@ -51,8 +39,12 @@ struct _ceval_runtime_state {
        c_tracefunc.  This speeds up the if statement in
        PyEval_EvalFrameEx() after fast_next_opcode. */
     int tracing_possible;
+    /* This single variable consolidates all requests to break out of
+       the fast path in the eval loop. */
+    _Py_atomic_int eval_breaker;
     /* Request for dropping the GIL */
     _Py_atomic_int gil_drop_request;
+    struct _pending_calls pending;
     /* Request for checking signals. */
     _Py_atomic_int signals_pending;
     struct _gil_runtime_state gil;
diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h
index 7e78297da69a..7796223b59e6 100644
--- a/Include/internal/pycore_pystate.h
+++ b/Include/internal/pycore_pystate.h
@@ -11,7 +11,6 @@ extern "C" {
 #include "pystate.h"
 #include "pythread.h"
 
-#include "pycore_atomic.h"
 #include "pycore_ceval.h"
 #include "pycore_pathconfig.h"
 #include "pycore_pymem.h"
@@ -30,11 +29,8 @@ struct _is {
 
     int64_t id;
     int64_t id_refcount;
-    int requires_idref;
     PyThread_type_lock id_mutex;
 
-    int finalizing;
-
     PyObject *modules;
     PyObject *modules_by_index;
     PyObject *sysdict;
@@ -82,8 +78,6 @@ struct _is {
     PyObject *pyexitmodule;
 
     uint64_t tstate_next_unique_id;
-
-    struct _ceval_interpreter_state ceval;
 };
 
 PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(PY_INT64_T);
@@ -93,12 +87,66 @@ PyAPI_FUNC(void) _PyInterpreterState_IDIncref(struct _is *);
 PyAPI_FUNC(void) _PyInterpreterState_IDDecref(struct _is *);
 
 
+/* cross-interpreter data */
+
+struct _xid;
+
+// _PyCrossInterpreterData is similar to Py_buffer as an effectively
+// opaque struct that holds data outside the object machinery.  This
+// is necessary to pass safely between interpreters in the same process.
+typedef struct _xid {
+    // data is the cross-interpreter-safe derivation of a Python object
+    // (see _PyObject_GetCrossInterpreterData).  It will be NULL if the
+    // new_object func (below) encodes the data.
+    void *data;
+    // obj is the Python object from which the data was derived.  This
+    // is non-NULL only if the data remains bound to the object in some
+    // way, such that the object must be "released" (via a decref) when
+    // the data is released.  In that case the code that sets the field,
+    // likely a registered "crossinterpdatafunc", is responsible for
+    // ensuring it owns the reference (i.e. incref).
+    PyObject *obj;
+    // interp is the ID of the owning interpreter of the original
+    // object.  It corresponds to the active interpreter when
+    // _PyObject_GetCrossInterpreterData() was called.  This should only
+    // be set by the cross-interpreter machinery.
+    //
+    // We use the ID rather than the PyInterpreterState to avoid issues
+    // with deleted interpreters.
+    int64_t interp;
+    // new_object is a function that returns a new object in the current
+    // interpreter given the data.  The resulting object (a new
+    // reference) will be equivalent to the original object.  This field
+    // is required.
+    PyObject *(*new_object)(struct _xid *);
+    // free is called when the data is released.  If it is NULL then
+    // nothing will be done to free the data.  For some types this is
+    // okay (e.g. bytes) and for those types this field should be set
+    // to NULL.  However, for most the data was allocated just for
+    // cross-interpreter use, so it must be freed when
+    // _PyCrossInterpreterData_Release is called or the memory will
+    // leak.  In that case, at the very least this field should be set
+    // to PyMem_RawFree (the default if not explicitly set to NULL).
+    // The call will happen with the original interpreter activated.
+    void (*free)(void *);
+} _PyCrossInterpreterData;
+
+typedef int (*crossinterpdatafunc)(PyObject *, _PyCrossInterpreterData *);
+PyAPI_FUNC(int) _PyObject_CheckCrossInterpreterData(PyObject *);
+
+PyAPI_FUNC(int) _PyObject_GetCrossInterpreterData(PyObject *, _PyCrossInterpreterData *);
+PyAPI_FUNC(PyObject *) _PyCrossInterpreterData_NewObject(_PyCrossInterpreterData *);
+PyAPI_FUNC(void) _PyCrossInterpreterData_Release(_PyCrossInterpreterData *);
+
 /* cross-interpreter data registry */
 
 /* For now we use a global registry of shareable classes.  An
    alternative would be to add a tp_* slot for a class's
    crossinterpdatafunc. It would be simpler and more efficient. */
 
+PyAPI_FUNC(int) _PyCrossInterpreterData_Register_Class(PyTypeObject *, crossinterpdatafunc);
+PyAPI_FUNC(crossinterpdatafunc) _PyCrossInterpreterData_Lookup(PyObject *);
+
 struct _xidregitem;
 
 struct _xidregitem {
@@ -159,8 +207,6 @@ typedef struct pyruntimestate {
         struct _xidregitem *head;
     } xidregistry;
 
-    unsigned long main_thread;
-
 #define NEXITFUNCS 32
     void (*exitfuncs[NEXITFUNCS])(void);
     int nexitfuncs;
diff --git a/Include/interpreteridobject.h b/Include/interpreteridobject.h
deleted file mode 100644
index e744fcdc9ff1..000000000000
--- 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/Makefile.pre.in b/Makefile.pre.in
index 8042e8e81a05..135c3230292b 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -391,7 +391,6 @@ OBJECT_OBJS=	\
 		Objects/floatobject.o \
 		Objects/frameobject.o \
 		Objects/funcobject.o \
-		Objects/interpreteridobject.o \
 		Objects/iterobject.o \
 		Objects/listobject.o \
 		Objects/longobject.o \
@@ -978,7 +977,6 @@ PYTHON_HEADERS= \
 		$(srcdir)/Include/funcobject.h \
 		$(srcdir)/Include/genobject.h \
 		$(srcdir)/Include/import.h \
-		$(srcdir)/Include/interpreteridobject.h \
 		$(srcdir)/Include/intrcheck.h \
 		$(srcdir)/Include/iterobject.h \
 		$(srcdir)/Include/listobject.h \
@@ -1041,7 +1039,6 @@ PYTHON_HEADERS= \
 		$(srcdir)/Include/cpython/abstract.h \
 		$(srcdir)/Include/cpython/coreconfig.h \
 		$(srcdir)/Include/cpython/dictobject.h \
-		$(srcdir)/Include/cpython/interpreteridobject.h \
 		$(srcdir)/Include/cpython/object.h \
 		$(srcdir)/Include/cpython/objimpl.h \
 		$(srcdir)/Include/cpython/pyerrors.h \
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 5b0da783e5e2..350ef771630e 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -2445,7 +2445,6 @@ pending_threadfunc(PyObject *self, PyObject *arg)
     Py_INCREF(callable);
 
     Py_BEGIN_ALLOW_THREADS
-    /* XXX Use the internal _Py_AddPendingCall(). */
     r = Py_AddPendingCall(&_pending_callback, callable);
     Py_END_ALLOW_THREADS
 
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 1cf43b7ac76e..79c9def72629 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -4,7 +4,7 @@
 
 #include "Python.h"
 #include "frameobject.h"
-#include "interpreteridobject.h"
+#include "pycore_pystate.h"
 
 
 static char *
@@ -31,6 +31,38 @@ _get_current(void)
     return _PyInterpreterState_Get();
 }
 
+static int64_t
+_coerce_id(PyObject *orig)
+{
+    PyObject *pyid = PyNumber_Long(orig);
+    if (pyid == NULL) {
+        if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+            PyErr_Format(PyExc_TypeError,
+                         "'id' must be a non-negative int, got %R", orig);
+        }
+        else {
+            PyErr_Format(PyExc_ValueError,
+                         "'id' must be a non-negative int, got %R", orig);
+        }
+        return -1;
+    }
+    int64_t id = PyLong_AsLongLong(pyid);
+    Py_DECREF(pyid);
+    if (id == -1 && PyErr_Occurred() != NULL) {
+        if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
+            PyErr_Format(PyExc_ValueError,
+                         "'id' must be a non-negative int, got %R", orig);
+        }
+        return -1;
+    }
+    if (id < 0) {
+        PyErr_Format(PyExc_ValueError,
+                     "'id' must be a non-negative int, got %R", orig);
+        return -1;
+    }
+    return id;
+}
+
 
 /* data-sharing-specific code ***********************************************/
 
@@ -39,8 +71,6 @@ struct _sharednsitem {
     _PyCrossInterpreterData data;
 };
 
-static void _sharednsitem_clear(struct _sharednsitem *);  // forward
-
 static int
 _sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
 {
@@ -49,7 +79,6 @@ _sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
         return -1;
     }
     if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
-        _sharednsitem_clear(item);
         return -1;
     }
     return 0;
@@ -60,7 +89,6 @@ _sharednsitem_clear(struct _sharednsitem *item)
 {
     if (item->name != NULL) {
         PyMem_Free(item->name);
-        item->name = NULL;
     }
     _PyCrossInterpreterData_Release(&item->data);
 }
@@ -1311,13 +1339,13 @@ _channel_send(_channels *channels, int64_t id, PyObject *obj)
         return -1;
     }
     if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
-        PyThread_release_lock(mutex);
         PyMem_Free(data);
+        PyThread_release_lock(mutex);
         return -1;
     }
 
     // Add the data to the channel.
-    int res = _channel_add(chan, PyInterpreterState_GetID(interp), data);
+    int res = _channel_add(chan, interp->id, data);
     PyThread_release_lock(mutex);
     if (res != 0) {
         _PyCrossInterpreterData_Release(data);
@@ -1345,7 +1373,7 @@ _channel_recv(_channels *channels, int64_t id)
     // Past this point we are responsible for releasing the mutex.
 
     // Pop off the next item from the channel.
-    _PyCrossInterpreterData *data = _channel_next(chan, PyInterpreterState_GetID(interp));
+    _PyCrossInterpreterData *data = _channel_next(chan, interp->id);
     PyThread_release_lock(mutex);
     if (data == NULL) {
         if (!PyErr_Occurred()) {
@@ -1382,7 +1410,7 @@ _channel_drop(_channels *channels, int64_t id, int send, int recv)
     // Past this point we are responsible for releasing the mutex.
 
     // Close one or both of the two ends.
-    int res = _channel_close_interpreter(chan, PyInterpreterState_GetID(interp), send-recv);
+    int res = _channel_close_interpreter(chan, interp->id, send-recv);
     PyThread_release_lock(mutex);
     return res;
 }
@@ -1453,7 +1481,7 @@ channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
         cid = ((channelid *)id)->id;
     }
     else {
-        cid = _Py_CoerceID(id);
+        cid = _coerce_id(id);
         if (cid < 0) {
             return NULL;
         }
@@ -1847,7 +1875,7 @@ _run_script(PyInterpreterState *interp, const char *codestr,
     PyObject *excval = NULL;
     PyObject *tb = NULL;
 
-    PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
+    PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
     if (main_mod == NULL) {
         goto error;
     }
@@ -1946,6 +1974,272 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
     return result;
 }
 
+/* InterpreterID class */
+
+static PyTypeObject InterpreterIDtype;
+
+typedef struct interpid {
+    PyObject_HEAD
+    int64_t id;
+} interpid;
+
+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;
+        }
+    }
+
+    interpid *self = PyObject_New(interpid, cls);
+    if (self == NULL) {
+        return NULL;
+    }
+    self->id = id;
+
+    if (interp != NULL) {
+        _PyInterpreterState_IDIncref(interp);
+    }
+    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;
+    }
+
+    // Coerce and check the ID.
+    int64_t id;
+    if (PyObject_TypeCheck(idobj, &InterpreterIDtype)) {
+        id = ((interpid *)idobj)->id;
+    }
+    else {
+        id = _coerce_id(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);
+}
+
+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, &InterpreterIDtype)) {
+        Py_RETURN_NOTIMPLEMENTED;
+    }
+
+    interpid *id = (interpid *)self;
+    int equal;
+    if (PyObject_TypeCheck(other, &InterpreterIDtype)) {
+        interpid *otherid = (interpid *)other;
+        equal = (id->id == otherid->id);
+    }
+    else {
+        other = PyNumber_Long(other);
+        if (other == NULL) {
+            PyErr_Clear();
+            Py_RETURN_NOTIMPLEMENTED;
+        }
+        int64_t otherid = PyLong_AsLongLong(other);
+        Py_DECREF(other);
+        if (otherid == -1 && PyErr_Occurred() != NULL) {
+            return NULL;
+        }
+        if (otherid < 0) {
+            equal = 0;
+        }
+        else {
+            equal = (id->id == otherid);
+        }
+    }
+
+    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.");
+
+static PyTypeObject InterpreterIDtype = {
+    PyVarObject_HEAD_INIT(&PyType_Type, 0)
+    "interpreters.InterpreterID",   /* tp_name */
+    sizeof(interpid),               /* tp_basicsize */
+    0,                              /* tp_itemsize */
+    (destructor)interpid_dealloc,   /* tp_dealloc */
+    0,                              /* tp_print */
+    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 |
+        Py_TPFLAGS_LONG_SUBCLASS,   /* 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 */
+};
+
+static PyObject *
+_get_id(PyInterpreterState *interp)
+{
+    PY_INT64_T id = PyInterpreterState_GetID(interp);
+    if (id < 0) {
+        return NULL;
+    }
+    return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
+}
+
+static PyInterpreterState *
+_look_up(PyObject *requested_id)
+{
+    int64_t id;
+    if (PyObject_TypeCheck(requested_id, &InterpreterIDtype)) {
+        id = ((interpid *)requested_id)->id;
+    }
+    else {
+        id = PyLong_AsLongLong(requested_id);
+        if (id == -1 && PyErr_Occurred() != NULL) {
+            return NULL;
+        }
+        assert(id <= INT64_MAX);
+    }
+    return _PyInterpreterState_LookUpID(id);
+}
+
 
 /* module level code ********************************************************/
 
@@ -1989,16 +2283,17 @@ interp_create(PyObject *self, PyObject *args)
         PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
         return NULL;
     }
-    PyObject *idobj = _PyInterpreterState_GetIDObject(tstate->interp);
-    if (idobj == NULL) {
-        // XXX Possible GILState issues?
-        save_tstate = PyThreadState_Swap(tstate);
-        Py_EndInterpreter(tstate);
-        PyThreadState_Swap(save_tstate);
-        return NULL;
-    }
-    _PyInterpreterState_RequireIDRef(tstate->interp, 1);
-    return idobj;
+    if (_PyInterpreterState_IDInitref(tstate->interp) != 0) {
+        goto error;
+    };
+    return _get_id(tstate->interp);
+
+error:
+    // XXX Possible GILState issues?
+    save_tstate = PyThreadState_Swap(tstate);
+    Py_EndInterpreter(tstate);
+    PyThreadState_Swap(save_tstate);
+    return NULL;
 }
 
 PyDoc_STRVAR(create_doc,
@@ -2023,7 +2318,7 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
     }
 
     // Look up the interpreter.
-    PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
+    PyInterpreterState *interp = _look_up(id);
     if (interp == NULL) {
         return NULL;
     }
@@ -2079,7 +2374,7 @@ interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
 
     interp = PyInterpreterState_Head();
     while (interp != NULL) {
-        id = _PyInterpreterState_GetIDObject(interp);
+        id = _get_id(interp);
         if (id == NULL) {
             Py_DECREF(ids);
             return NULL;
@@ -2111,7 +2406,7 @@ interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
     if (interp == NULL) {
         return NULL;
     }
-    return _PyInterpreterState_GetIDObject(interp);
+    return _get_id(interp);
 }
 
 PyDoc_STRVAR(get_current_doc,
@@ -2125,7 +2420,7 @@ interp_get_main(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
     // Currently, 0 is always the main interpreter.
     PY_INT64_T id = 0;
-    return _PyInterpreterID_New(id);
+    return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
 }
 
 PyDoc_STRVAR(get_main_doc,
@@ -2151,7 +2446,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
     }
 
     // Look up the interpreter.
-    PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
+    PyInterpreterState *interp = _look_up(id);
     if (interp == NULL) {
         return NULL;
     }
@@ -2221,7 +2516,7 @@ interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
         return NULL;
     }
 
-    PyInterpreterState *interp = _PyInterpreterID_LookUp(id);
+    PyInterpreterState *interp = _look_up(id);
     if (interp == NULL) {
         return NULL;
     }
@@ -2273,7 +2568,7 @@ channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
                                      "O:channel_destroy", kwlist, &id)) {
         return NULL;
     }
-    int64_t cid = _Py_CoerceID(id);
+    int64_t cid = _coerce_id(id);
     if (cid < 0) {
         return NULL;
     }
@@ -2337,7 +2632,7 @@ channel_send(PyObject *self, PyObject *args, PyObject *kwds)
                                      "OO:channel_send", kwlist, &id, &obj)) {
         return NULL;
     }
-    int64_t cid = _Py_CoerceID(id);
+    int64_t cid = _coerce_id(id);
     if (cid < 0) {
         return NULL;
     }
@@ -2362,7 +2657,7 @@ channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
                                      "O:channel_recv", kwlist, &id)) {
         return NULL;
     }
-    int64_t cid = _Py_CoerceID(id);
+    int64_t cid = _coerce_id(id);
     if (cid < 0) {
         return NULL;
     }
@@ -2388,7 +2683,7 @@ channel_close(PyObject *self, PyObject *args, PyObject *kwds)
                                      &id, &send, &recv, &force)) {
         return NULL;
     }
-    int64_t cid = _Py_CoerceID(id);
+    int64_t cid = _coerce_id(id);
     if (cid < 0) {
         return NULL;
     }
@@ -2440,7 +2735,7 @@ channel_release(PyObject *self, PyObject *args, PyObject *kwds)
                                      &id, &send, &recv, &force)) {
         return NULL;
     }
-    int64_t cid = _Py_CoerceID(id);
+    int64_t cid = _coerce_id(id);
     if (cid < 0) {
         return NULL;
     }
@@ -2542,6 +2837,10 @@ PyInit__xxsubinterpreters(void)
     if (PyType_Ready(&ChannelIDtype) != 0) {
         return NULL;
     }
+    InterpreterIDtype.tp_base = &PyLong_Type;
+    if (PyType_Ready(&InterpreterIDtype) != 0) {
+        return NULL;
+    }
 
     /* Create the module */
     PyObject *module = PyModule_Create(&interpretersmodule);
@@ -2563,12 +2862,12 @@ PyInit__xxsubinterpreters(void)
     if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
         return NULL;
     }
-    Py_INCREF(&_PyInterpreterID_Type);
-    if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&_PyInterpreterID_Type) != 0) {
+    Py_INCREF(&InterpreterIDtype);
+    if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&InterpreterIDtype) != 0) {
         return NULL;
     }
 
-    if (_PyCrossInterpreterData_RegisterClass(&ChannelIDtype, _channelid_shared)) {
+    if (_PyCrossInterpreterData_Register_Class(&ChannelIDtype, _channelid_shared)) {
         return NULL;
     }
 
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index ac3b6c7c5617..f29720bcaf36 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -19,7 +19,6 @@
 #include <process.h>
 #endif
 #endif
-#include "internal/pycore_pystate.h"
 
 #ifdef HAVE_SIGNAL_H
 #include <signal.h>
@@ -296,10 +295,8 @@ trip_signal(int sig_num)
                 {
                     /* Py_AddPendingCall() isn't signal-safe, but we
                        still use it for this exceptional case. */
-                    _Py_AddPendingCall(_PyRuntime.interpreters.main,
-                                       main_thread,
-                                       report_wakeup_send_error,
-                                       (void *)(intptr_t) last_error);
+                    Py_AddPendingCall(report_wakeup_send_error,
+                                      (void *)(intptr_t) last_error);
                 }
             }
         }
@@ -316,10 +313,8 @@ trip_signal(int sig_num)
                 {
                     /* Py_AddPendingCall() isn't signal-safe, but we
                        still use it for this exceptional case. */
-                    _Py_AddPendingCall(_PyRuntime.interpreters.main,
-                                       main_thread,
-                                       report_wakeup_write_error,
-                                       (void *)(intptr_t)errno);
+                    Py_AddPendingCall(report_wakeup_write_error,
+                                      (void *)(intptr_t)errno);
                 }
             }
         }
diff --git a/Objects/interpreteridobject.c b/Objects/interpreteridobject.c
deleted file mode 100644
index dd142b043d0a..000000000000
--- a/Objects/interpreteridobject.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/* InterpreterID object */
-
-#include "Python.h"
-#include "internal/pycore_pystate.h"
-#include "interpreteridobject.h"
-
-
-int64_t
-_Py_CoerceID(PyObject *orig)
-{
-    PyObject *pyid = PyNumber_Long(orig);
-    if (pyid == NULL) {
-        if (PyErr_ExceptionMatches(PyExc_TypeError)) {
-            PyErr_Format(PyExc_TypeError,
-                         "'id' must be a non-negative int, got %R", orig);
-        }
-        else {
-            PyErr_Format(PyExc_ValueError,
-                         "'id' must be a non-negative int, got %R", orig);
-        }
-        return -1;
-    }
-    int64_t id = PyLong_AsLongLong(pyid);
-    Py_DECREF(pyid);
-    if (id == -1 && PyErr_Occurred() != NULL) {
-        if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
-            PyErr_Format(PyExc_ValueError,
-                         "'id' must be a non-negative int, got %R", orig);
-        }
-        return -1;
-    }
-    if (id < 0) {
-        PyErr_Format(PyExc_ValueError,
-                     "'id' must be a non-negative int, got %R", orig);
-        return -1;
-    }
-    return id;
-}
-
-typedef struct interpid {
-    PyObject_HEAD
-    int64_t id;
-} interpid;
-
-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;
-        }
-    }
-
-    interpid *self = PyObject_New(interpid, cls);
-    if (self == NULL) {
-        return NULL;
-    }
-    self->id = id;
-
-    if (interp != NULL) {
-        _PyInterpreterState_IDIncref(interp);
-    }
-    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;
-    }
-
-    // Coerce and check the ID.
-    int64_t id;
-    if (PyObject_TypeCheck(idobj, &_PyInterpreterID_Type)) {
-        id = ((interpid *)idobj)->id;
-    }
-    else {
-        id = _Py_CoerceID(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 {
-        other = PyNumber_Long(other);
-        if (other == NULL) {
-            PyErr_Clear();
-            Py_RETURN_NOTIMPLEMENTED;
-        }
-        int64_t otherid = PyLong_AsLongLong(other);
-        Py_DECREF(other);
-        if (otherid == -1 && PyErr_Occurred() != NULL) {
-            return NULL;
-        }
-        if (otherid < 0) {
-            equal = 0;
-        }
-        else {
-            equal = (id->id == otherid);
-        }
-    }
-
-    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_print */
-    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 |
-        Py_TPFLAGS_LONG_SUBCLASS,   /* 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 */
-    &PyLong_Type,                   /* 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;
-    };
-    PY_INT64_T id = PyInterpreterState_GetID(interp);
-    if (id < 0) {
-        return NULL;
-    }
-    return (PyObject *)newinterpid(&_PyInterpreterID_Type, id, 0);
-}
-
-PyInterpreterState *
-_PyInterpreterID_LookUp(PyObject *requested_id)
-{
-    int64_t id;
-    if (PyObject_TypeCheck(requested_id, &_PyInterpreterID_Type)) {
-        id = ((interpid *)requested_id)->id;
-    }
-    else {
-        id = PyLong_AsLongLong(requested_id);
-        if (id == -1 && PyErr_Occurred() != NULL) {
-            return NULL;
-        }
-        assert(id <= INT64_MAX);
-    }
-    return _PyInterpreterState_LookUpID(id);
-}
diff --git a/Objects/object.c b/Objects/object.c
index b446d598130a..cf5264b5d80b 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -5,7 +5,6 @@
 #include "pycore_pystate.h"
 #include "pycore_context.h"
 #include "frameobject.h"
-#include "interpreteridobject.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -1807,7 +1806,6 @@ _PyTypes_Init(void)
     INIT_TYPE(&PySeqIter_Type, "sequence iterator");
     INIT_TYPE(&PyCoro_Type, "coroutine");
     INIT_TYPE(&_PyCoroWrapper_Type, "coroutine wrapper");
-    INIT_TYPE(&_PyInterpreterID_Type, "interpreter ID");
     return _Py_INIT_OK();
 
 #undef INIT_TYPE
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index c9ff2f88d8e0..bff7b95a84ae 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -154,7 +154,6 @@
     <ClInclude Include="..\Include\internal\pycore_pystate.h" />
     <ClInclude Include="..\Include\internal\pycore_tupleobject.h" />
     <ClInclude Include="..\Include\internal\pycore_warnings.h" />
-    <ClInclude Include="..\Include\interpreteridobject.h" />
     <ClInclude Include="..\Include\intrcheck.h" />
     <ClInclude Include="..\Include\iterobject.h" />
     <ClInclude Include="..\Include\listobject.h" />
@@ -351,7 +350,6 @@
     <ClCompile Include="..\Objects\frameobject.c" />
     <ClCompile Include="..\Objects\funcobject.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 5dfa193f048a..03030744b155 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -483,9 +483,6 @@
     <ClInclude Include="..\Include\namespaceobject.h">
       <Filter>Include</Filter>
     </ClInclude>
-    <ClInclude Include="..\Include\interpreteridobject.h">
-      <Filter>Include</Filter>
-    </ClInclude>
     <ClInclude Include="..\Modules\hashtable.h">
       <Filter>Modules</Filter>
     </ClInclude>
@@ -1046,9 +1043,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/ceval.c b/Python/ceval.c
index be75ade909d7..b311248c6a20 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -96,61 +96,61 @@ static long dxp[256];
 /* This can set eval_breaker to 0 even though gil_drop_request became
    1.  We believe this is all right because the eval loop will release
    the GIL eventually anyway. */
-#define COMPUTE_EVAL_BREAKER(interp) \
+#define COMPUTE_EVAL_BREAKER() \
     _Py_atomic_store_relaxed( \
-        &interp->ceval.eval_breaker, \
+        &_PyRuntime.ceval.eval_breaker, \
         GIL_REQUEST | \
         _Py_atomic_load_relaxed(&_PyRuntime.ceval.signals_pending) | \
-        _Py_atomic_load_relaxed(&interp->ceval.pending.calls_to_do) | \
-        interp->ceval.pending.async_exc)
+        _Py_atomic_load_relaxed(&_PyRuntime.ceval.pending.calls_to_do) | \
+        _PyRuntime.ceval.pending.async_exc)
 
-#define SET_GIL_DROP_REQUEST(interp) \
+#define SET_GIL_DROP_REQUEST() \
     do { \
         _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 1); \
-        _Py_atomic_store_relaxed(&interp->ceval.eval_breaker, 1); \
+        _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
     } while (0)
 
-#define RESET_GIL_DROP_REQUEST(interp) \
+#define RESET_GIL_DROP_REQUEST() \
     do { \
         _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 0); \
-        COMPUTE_EVAL_BREAKER(interp); \
+        COMPUTE_EVAL_BREAKER(); \
     } while (0)
 
 /* Pending calls are only modified under pending_lock */
-#define SIGNAL_PENDING_CALLS(interp) \
+#define SIGNAL_PENDING_CALLS() \
     do { \
-        _Py_atomic_store_relaxed(&interp->ceval.pending.calls_to_do, 1); \
-        _Py_atomic_store_relaxed(&interp->ceval.eval_breaker, 1); \
+        _Py_atomic_store_relaxed(&_PyRuntime.ceval.pending.calls_to_do, 1); \
+        _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
     } while (0)
 
-#define UNSIGNAL_PENDING_CALLS(interp) \
+#define UNSIGNAL_PENDING_CALLS() \
     do { \
-        _Py_atomic_store_relaxed(&interp->ceval.pending.calls_to_do, 0); \
-        COMPUTE_EVAL_BREAKER(interp); \
+        _Py_atomic_store_relaxed(&_PyRuntime.ceval.pending.calls_to_do, 0); \
+        COMPUTE_EVAL_BREAKER(); \
     } while (0)
 
 #define SIGNAL_PENDING_SIGNALS() \
     do { \
         _Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 1); \
-        _Py_atomic_store_relaxed(&_PyRuntime.interpreters.main->ceval.eval_breaker, 1); \
+        _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
     } while (0)
 
 #define UNSIGNAL_PENDING_SIGNALS() \
     do { \
         _Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 0); \
-        COMPUTE_EVAL_BREAKER(_PyRuntime.interpreters.main); \
+        COMPUTE_EVAL_BREAKER(); \
     } while (0)
 
-#define SIGNAL_ASYNC_EXC(interp) \
+#define SIGNAL_ASYNC_EXC() \
     do { \
-        interp->ceval.pending.async_exc = 1; \
-        _Py_atomic_store_relaxed(&interp->ceval.eval_breaker, 1); \
+        _PyRuntime.ceval.pending.async_exc = 1; \
+        _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
     } while (0)
 
-#define UNSIGNAL_ASYNC_EXC(interp) \
+#define UNSIGNAL_ASYNC_EXC() \
     do { \
-        interp->ceval.pending.async_exc = 0; \
-        COMPUTE_EVAL_BREAKER(interp); \
+        _PyRuntime.ceval.pending.async_exc = 0; \
+        COMPUTE_EVAL_BREAKER(); \
     } while (0)
 
 
@@ -174,6 +174,9 @@ PyEval_InitThreads(void)
     PyThread_init_thread();
     create_gil();
     take_gil(_PyThreadState_GET());
+    _PyRuntime.ceval.pending.main_thread = PyThread_get_thread_ident();
+    if (!_PyRuntime.ceval.pending.lock)
+        _PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
 }
 
 void
@@ -240,11 +243,9 @@ PyEval_ReInitThreads(void)
     if (!gil_created())
         return;
     recreate_gil();
-    // This will be reset in make_pending_calls() below.
-    current_tstate->interp->ceval.pending.lock = NULL;
-
+    _PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
     take_gil(current_tstate);
-    _PyRuntime.main_thread = PyThread_get_thread_ident();
+    _PyRuntime.ceval.pending.main_thread = PyThread_get_thread_ident();
 
     /* Destroy all threads except the current one */
     _PyThreadState_DeleteExcept(current_tstate);
@@ -254,9 +255,9 @@ PyEval_ReInitThreads(void)
    raised. */
 
 void
-_PyEval_SignalAsyncExc(PyInterpreterState *interp)
+_PyEval_SignalAsyncExc(void)
 {
-    SIGNAL_ASYNC_EXC(interp);
+    SIGNAL_ASYNC_EXC();
 }
 
 PyThreadState *
@@ -322,58 +323,17 @@ _PyEval_SignalReceived(void)
     SIGNAL_PENDING_SIGNALS();
 }
 
-static int
-_add_pending_call(PyInterpreterState *interp, unsigned long thread_id, int (*func)(void *), void *arg)
-{
-    int i = interp->ceval.pending.last;
-    int j = (i + 1) % NPENDINGCALLS;
-    if (j == interp->ceval.pending.first) {
-        return -1; /* Queue full */
-    }
-    interp->ceval.pending.calls[i].thread_id = thread_id;
-    interp->ceval.pending.calls[i].func = func;
-    interp->ceval.pending.calls[i].arg = arg;
-    interp->ceval.pending.last = j;
-    return 0;
-}
-
-/* pop one item off the queue while holding the lock */
-static void
-_pop_pending_call(PyInterpreterState *interp, int (**func)(void *), void **arg)
-{
-    int i = interp->ceval.pending.first;
-    if (i == interp->ceval.pending.last) {
-        return; /* Queue empty */
-    }
-
-    *func = interp->ceval.pending.calls[i].func;
-    *arg = interp->ceval.pending.calls[i].arg;
-    interp->ceval.pending.first = (i + 1) % NPENDINGCALLS;
-
-    unsigned long thread_id = interp->ceval.pending.calls[i].thread_id;
-    if (thread_id && PyThread_get_thread_ident() != thread_id) {
-        // Thread mismatch, so move it to the end of the list
-        // and start over.
-        _Py_AddPendingCall(interp, thread_id, *func, *arg);
-        return;
-    }
-}
-
-int
-Py_AddPendingCall(int (*func)(void *), void *arg)
-{
-    PyInterpreterState *interp = _PyRuntime.interpreters.main;
-    return _Py_AddPendingCall(interp, _PyRuntime.main_thread, func, arg);
-}
-
 /* This implementation is thread-safe.  It allows
    scheduling to be made from any thread, and even from an executing
    callback.
  */
 
 int
-_Py_AddPendingCall(PyInterpreterState *interp, unsigned long thread_id, int (*func)(void *), void *arg)
+Py_AddPendingCall(int (*func)(void *), void *arg)
 {
+    int i, j, result=0;
+    PyThread_type_lock lock = _PyRuntime.ceval.pending.lock;
+
     /* try a few times for the lock.  Since this mechanism is used
      * for signal handling (on the main thread), there is a (slim)
      * chance that a signal is delivered on the same thread while we
@@ -385,9 +345,7 @@ _Py_AddPendingCall(PyInterpreterState *interp, unsigned long thread_id, int (*fu
      * We also check for lock being NULL, in the unlikely case that
      * this function is called before any bytecode evaluation takes place.
      */
-    PyThread_type_lock lock = interp->ceval.pending.lock;
     if (lock != NULL) {
-        int i;
         for (i = 0; i<100; i++) {
             if (PyThread_acquire_lock(lock, NOWAIT_LOCK))
                 break;
@@ -396,21 +354,17 @@ _Py_AddPendingCall(PyInterpreterState *interp, unsigned long thread_id, int (*fu
             return -1;
     }
 
-    int result = -1;
-    if (interp->finalizing) {
-        PyObject *exc, *val, *tb;
-        PyErr_Fetch(&exc, &val, &tb);
-        PyErr_SetString(PyExc_SystemError, "Py_AddPendingCall: cannot add pending calls (interpreter shutting down)");
-        PyErr_Print();
-        PyErr_Restore(exc, val, tb);
-        goto done;
+    i = _PyRuntime.ceval.pending.last;
+    j = (i + 1) % NPENDINGCALLS;
+    if (j == _PyRuntime.ceval.pending.first) {
+        result = -1; /* Queue full */
+    } else {
+        _PyRuntime.ceval.pending.calls[i].func = func;
+        _PyRuntime.ceval.pending.calls[i].arg = arg;
+        _PyRuntime.ceval.pending.last = j;
     }
-
-    result = _add_pending_call(interp, thread_id, func, arg);
     /* signal main loop */
-    SIGNAL_PENDING_CALLS(interp);
-
-done:
+    SIGNAL_PENDING_CALLS();
     if (lock != NULL)
         PyThread_release_lock(lock);
     return result;
@@ -420,7 +374,9 @@ static int
 handle_signals(void)
 {
     /* Only handle signals on main thread. */
-    if (PyThread_get_thread_ident() != _PyRuntime.main_thread) {
+    if (_PyRuntime.ceval.pending.main_thread &&
+        PyThread_get_thread_ident() != _PyRuntime.ceval.pending.main_thread)
+    {
         return 0;
     }
     /*
@@ -440,10 +396,17 @@ handle_signals(void)
 }
 
 static int
-make_pending_calls(PyInterpreterState *interp)
+make_pending_calls(void)
 {
     static int busy = 0;
 
+    /* only service pending calls on main thread */
+    if (_PyRuntime.ceval.pending.main_thread &&
+        PyThread_get_thread_ident() != _PyRuntime.ceval.pending.main_thread)
+    {
+        return 0;
+    }
+
     /* don't perform recursive pending calls */
     if (busy) {
         return 0;
@@ -451,13 +414,13 @@ make_pending_calls(PyInterpreterState *interp)
     busy = 1;
     /* unsignal before starting to call callbacks, so that any callback
        added in-between re-signals */
-    UNSIGNAL_PENDING_CALLS(interp);
+    UNSIGNAL_PENDING_CALLS();
     int res = 0;
 
-    if (!interp->ceval.pending.lock) {
+    if (!_PyRuntime.ceval.pending.lock) {
         /* initial allocation of the lock */
-        interp->ceval.pending.lock = PyThread_allocate_lock();
-        if (interp->ceval.pending.lock == NULL) {
+        _PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
+        if (_PyRuntime.ceval.pending.lock == NULL) {
             res = -1;
             goto error;
         }
@@ -465,18 +428,24 @@ make_pending_calls(PyInterpreterState *interp)
 
     /* perform a bounded number of calls, in case of recursion */
     for (int i=0; i<NPENDINGCALLS; i++) {
-        int (*func)(void *) = NULL;
+        int j;
+        int (*func)(void *);
         void *arg = NULL;
 
         /* pop one item off the queue while holding the lock */
-        PyThread_acquire_lock(interp->ceval.pending.lock, WAIT_LOCK);
-        _pop_pending_call(interp, &func, &arg);
-        PyThread_release_lock(interp->ceval.pending.lock);
-
+        PyThread_acquire_lock(_PyRuntime.ceval.pending.lock, WAIT_LOCK);
+        j = _PyRuntime.ceval.pending.first;
+        if (j == _PyRuntime.ceval.pending.last) {
+            func = NULL; /* Queue empty */
+        } else {
+            func = _PyRuntime.ceval.pending.calls[j].func;
+            arg = _PyRuntime.ceval.pending.calls[j].arg;
+            _PyRuntime.ceval.pending.first = (j + 1) % NPENDINGCALLS;
+        }
+        PyThread_release_lock(_PyRuntime.ceval.pending.lock);
         /* having released the lock, perform the callback */
-        if (func == NULL) {
+        if (func == NULL)
             break;
-        }
         res = func(arg);
         if (res) {
             goto error;
@@ -488,18 +457,10 @@ make_pending_calls(PyInterpreterState *interp)
 
 error:
     busy = 0;
-    SIGNAL_PENDING_CALLS(interp); /* We're not done yet */
+    SIGNAL_PENDING_CALLS();
     return res;
 }
 
-int
-_Py_MakePendingCalls(PyInterpreterState *interp)
-{
-    assert(PyGILState_Check());
-
-    return make_pending_calls(interp);
-}
-
 /* Py_MakePendingCalls() is a simple wrapper for the sake
    of backward-compatibility. */
 int
@@ -514,8 +475,12 @@ Py_MakePendingCalls(void)
         return res;
     }
 
-    PyInterpreterState *interp = _PyRuntime.interpreters.main;
-    return make_pending_calls(interp);
+    res = make_pending_calls();
+    if (res != 0) {
+        return res;
+    }
+
+    return 0;
 }
 
 /* The interpreter's recursion limit */
@@ -637,7 +602,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
     PyObject **fastlocals, **freevars;
     PyObject *retval = NULL;            /* Return value */
     PyThreadState *tstate = _PyThreadState_GET();
-    _Py_atomic_int *eval_breaker = &tstate->interp->ceval.eval_breaker;
     PyCodeObject *co;
 
     /* when tracing we set things up so that
@@ -723,7 +687,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
 
 #define DISPATCH() \
     { \
-        if (!_Py_atomic_load_relaxed(eval_breaker)) { \
+        if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.eval_breaker)) { \
                     FAST_DISPATCH(); \
         } \
         continue; \
@@ -1025,7 +989,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
            async I/O handler); see Py_AddPendingCall() and
            Py_MakePendingCalls() above. */
 
-        if (_Py_atomic_load_relaxed(eval_breaker)) {
+        if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.eval_breaker)) {
             opcode = _Py_OPCODE(*next_instr);
             if (opcode == SETUP_FINALLY ||
                 opcode == SETUP_WITH ||
@@ -1058,9 +1022,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
                 }
             }
             if (_Py_atomic_load_relaxed(
-                        &(tstate->interp->ceval.pending.calls_to_do)))
+                        &_PyRuntime.ceval.pending.calls_to_do))
             {
-                if (_Py_MakePendingCalls(tstate->interp) != 0) {
+                if (make_pending_calls() != 0) {
                     goto error;
                 }
             }
@@ -1092,7 +1056,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             if (tstate->async_exc != NULL) {
                 PyObject *exc = tstate->async_exc;
                 tstate->async_exc = NULL;
-                UNSIGNAL_ASYNC_EXC(tstate->interp);
+                UNSIGNAL_ASYNC_EXC();
                 PyErr_SetNone(exc);
                 Py_DECREF(exc);
                 goto error;
diff --git a/Python/ceval_gil.h b/Python/ceval_gil.h
index d9ad3616fa24..f2d5fdba0153 100644
--- a/Python/ceval_gil.h
+++ b/Python/ceval_gil.h
@@ -176,7 +176,7 @@ static void drop_gil(PyThreadState *tstate)
                     &_PyRuntime.ceval.gil.last_holder)
             ) == tstate)
         {
-        RESET_GIL_DROP_REQUEST(tstate->interp);
+        RESET_GIL_DROP_REQUEST();
             /* NOTE: if COND_WAIT does not atomically start waiting when
                releasing the mutex, another thread can run through, take
                the GIL and drop it again, and reset the condition
@@ -213,7 +213,7 @@ static void take_gil(PyThreadState *tstate)
         if (timed_out &&
             _Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked) &&
             _PyRuntime.ceval.gil.switch_number == saved_switchnum) {
-            SET_GIL_DROP_REQUEST(tstate->interp);
+            SET_GIL_DROP_REQUEST();
         }
     }
 _ready:
@@ -239,10 +239,10 @@ static void take_gil(PyThreadState *tstate)
     MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex);
 #endif
     if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request)) {
-        RESET_GIL_DROP_REQUEST(tstate->interp);
+        RESET_GIL_DROP_REQUEST();
     }
     if (tstate->async_exc != NULL) {
-        _PyEval_SignalAsyncExc(tstate->interp);
+        _PyEval_SignalAsyncExc();
     }
 
     MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex);
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 088e7aa9313d..a5cfc07c488e 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -1460,32 +1460,8 @@ Py_EndInterpreter(PyThreadState *tstate)
     if (tstate->frame != NULL)
         Py_FatalError("Py_EndInterpreter: thread still has a frame");
 
-    // Mark as finalizing.
-    if (interp->ceval.pending.lock != NULL) {
-        PyThread_acquire_lock(interp->ceval.pending.lock, 1);
-    }
-    interp->finalizing = 1;
-    if (interp->ceval.pending.lock != NULL) {
-        PyThread_release_lock(interp->ceval.pending.lock);
-    }
-
-    // Wrap up existing threads.
     wait_for_thread_shutdown();
 
-    // Make any pending calls.
-    if (_Py_atomic_load_relaxed(
-                &(interp->ceval.pending.calls_to_do)))
-    {
-        // XXX Ensure that the interpreter is running in the current thread?
-        if (_Py_MakePendingCalls(interp) < 0) {
-            PyObject *exc, *val, *tb;
-            PyErr_Fetch(&exc, &val, &tb);
-            PyErr_BadInternalCall();
-            _PyErr_ChainExceptions(exc, val, tb);
-            PyErr_Print();
-        }
-    }
-
     call_py_exitfuncs(interp);
 
     if (tstate != interp->tstate_head || tstate->next != NULL)
diff --git a/Python/pystate.c b/Python/pystate.c
index 99a01efa6c72..49497b7c3767 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -133,19 +133,28 @@ PyInterpreterState_New(void)
         return NULL;
     }
 
-    memset(interp, 0, sizeof(*interp));
     interp->id_refcount = -1;
+    interp->id_mutex = NULL;
+    interp->modules = NULL;
+    interp->modules_by_index = NULL;
+    interp->sysdict = NULL;
+    interp->builtins = NULL;
+    interp->builtins_copy = NULL;
+    interp->tstate_head = NULL;
     interp->check_interval = 100;
-
-    interp->ceval.pending.lock = PyThread_allocate_lock();
-    if (interp->ceval.pending.lock == NULL) {
-        PyErr_SetString(PyExc_RuntimeError,
-                        "failed to create interpreter ceval pending mutex");
-        return NULL;
-    }
+    interp->num_threads = 0;
+    interp->pythread_stacksize = 0;
+    interp->codec_search_path = NULL;
+    interp->codec_search_cache = NULL;
+    interp->codec_error_registry = NULL;
+    interp->codecs_initialized = 0;
+    interp->fscodec_initialized = 0;
     interp->core_config = _PyCoreConfig_INIT;
     interp->config = _PyMainInterpreterConfig_INIT;
+    interp->importlib = NULL;
+    interp->import_func = NULL;
     interp->eval_frame = _PyEval_EvalFrameDefault;
+    interp->co_extra_user_count = 0;
 #ifdef HAVE_DLOPEN
 #if HAVE_DECL_RTLD_NOW
     interp->dlopenflags = RTLD_NOW;
@@ -153,10 +162,13 @@ PyInterpreterState_New(void)
     interp->dlopenflags = RTLD_LAZY;
 #endif
 #endif
-
-    if (_PyRuntime.main_thread == 0) {
-        _PyRuntime.main_thread = PyThread_get_thread_ident();
-    }
+#ifdef HAVE_FORK
+    interp->before_forkers = NULL;
+    interp->after_forkers_parent = NULL;
+    interp->after_forkers_child = NULL;
+#endif
+    interp->pyexitfunc = NULL;
+    interp->pyexitmodule = NULL;
 
     HEAD_LOCK();
     if (_PyRuntime.interpreters.next_id < 0) {
@@ -211,9 +223,6 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
     Py_CLEAR(interp->after_forkers_parent);
     Py_CLEAR(interp->after_forkers_child);
 #endif
-    // XXX Once we have one allocator per interpreter (i.e.
-    // per-interpreter GC) we must ensure that all of the interpreter's
-    // objects have been cleaned up at the point.
 }
 
 
@@ -254,9 +263,6 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
     if (interp->id_mutex != NULL) {
         PyThread_free_lock(interp->id_mutex);
     }
-    if (interp->ceval.pending.lock != NULL) {
-        PyThread_free_lock(interp->ceval.pending.lock);
-    }
     PyMem_RawFree(interp);
 }
 
@@ -328,37 +334,26 @@ PyInterpreterState_GetID(PyInterpreterState *interp)
 }
 
 
-static PyInterpreterState *
-interp_look_up_id(PY_INT64_T requested_id)
+PyInterpreterState *
+_PyInterpreterState_LookUpID(PY_INT64_T requested_id)
 {
+    if (requested_id < 0)
+        goto error;
+
     PyInterpreterState *interp = PyInterpreterState_Head();
     while (interp != NULL) {
         PY_INT64_T id = PyInterpreterState_GetID(interp);
-        if (id < 0) {
+        if (id < 0)
             return NULL;
-        }
-        if (requested_id == id) {
+        if (requested_id == id)
             return interp;
-        }
         interp = PyInterpreterState_Next(interp);
     }
-    return NULL;
-}
 
-PyInterpreterState *
-_PyInterpreterState_LookUpID(PY_INT64_T requested_id)
-{
-    PyInterpreterState *interp = NULL;
-    if (requested_id >= 0) {
-        HEAD_UNLOCK();
-        interp = interp_look_up_id(requested_id);
-        HEAD_UNLOCK();
-    }
-    if (interp == NULL && !PyErr_Occurred()) {
-        PyErr_Format(PyExc_RuntimeError,
-                     "unrecognized interpreter ID %lld", requested_id);
-    }
-    return interp;
+error:
+    PyErr_Format(PyExc_RuntimeError,
+                 "unrecognized interpreter ID %lld", requested_id);
+    return NULL;
 }
 
 
@@ -403,7 +398,7 @@ _PyInterpreterState_IDDecref(PyInterpreterState *interp)
     int64_t refcount = interp->id_refcount;
     PyThread_release_lock(interp->id_mutex);
 
-    if (refcount == 0 && interp->requires_idref) {
+    if (refcount == 0) {
         // XXX Using the "head" thread isn't strictly correct.
         PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
         // XXX Possible GILState issues?
@@ -413,18 +408,6 @@ _PyInterpreterState_IDDecref(PyInterpreterState *interp)
     }
 }
 
-int
-_PyInterpreterState_RequiresIDRef(PyInterpreterState *interp)
-{
-    return interp->requires_idref;
-}
-
-void
-_PyInterpreterState_RequireIDRef(PyInterpreterState *interp, int required)
-{
-    interp->requires_idref = required ? 1 : 0;
-}
-
 _PyCoreConfig *
 _PyInterpreterState_GetCoreConfig(PyInterpreterState *interp)
 {
@@ -437,16 +420,6 @@ _PyInterpreterState_GetMainConfig(PyInterpreterState *interp)
     return &interp->config;
 }
 
-PyObject *
-_PyInterpreterState_GetMainModule(PyInterpreterState *interp)
-{
-    if (interp->modules == NULL) {
-        PyErr_SetString(PyExc_RuntimeError, "interpreter not initialized");
-        return NULL;
-    }
-    return PyMapping_GetItemString(interp->modules, "__main__");
-}
-
 /* Default implementation for _PyThreadState_GetFrame */
 static struct _frame *
 threadstate_getframe(PyThreadState *self)
@@ -899,7 +872,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
             p->async_exc = exc;
             HEAD_UNLOCK();
             Py_XDECREF(old_exc);
-            _PyEval_SignalAsyncExc(interp);
+            _PyEval_SignalAsyncExc();
             return 1;
         }
     }
@@ -1313,7 +1286,7 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
     return 0;
 }
 
-static int
+static void
 _release_xidata(void *arg)
 {
     _PyCrossInterpreterData *data = (_PyCrossInterpreterData *)arg;
@@ -1321,8 +1294,30 @@ _release_xidata(void *arg)
         data->free(data->data);
     }
     Py_XDECREF(data->obj);
-    PyMem_Free(data);
-    return 0;
+}
+
+static void
+_call_in_interpreter(PyInterpreterState *interp,
+                     void (*func)(void *), void *arg)
+{
+    /* We would use Py_AddPendingCall() if it weren't specific to the
+     * main interpreter (see bpo-33608).  In the meantime we take a
+     * naive approach.
+     */
+    PyThreadState *save_tstate = NULL;
+    if (interp != _PyInterpreterState_Get()) {
+        // XXX Using the "head" thread isn't strictly correct.
+        PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
+        // XXX Possible GILState issues?
+        save_tstate = PyThreadState_Swap(tstate);
+    }
+
+    func(arg);
+
+    // Switch back.
+    if (save_tstate != NULL) {
+        PyThreadState_Swap(save_tstate);
+    }
 }
 
 void
@@ -1333,7 +1328,7 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
         return;
     }
 
-    // Get the original interpreter.
+    // Switch to the original interpreter.
     PyInterpreterState *interp = _PyInterpreterState_LookUpID(data->interp);
     if (interp == NULL) {
         // The intepreter was already destroyed.
@@ -1342,24 +1337,9 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
         }
         return;
     }
-    // XXX There's an ever-so-slight race here...
-    if (interp->finalizing) {
-        // XXX Someone leaked some memory...
-        return;
-    }
 
     // "Release" the data and/or the object.
-    _PyCrossInterpreterData *copied = PyMem_Malloc(sizeof(_PyCrossInterpreterData));
-    if (copied == NULL) {
-        PyErr_SetString(PyExc_MemoryError,
-                        "Not enough memory to preserve cross-interpreter data");
-        PyErr_Print();
-        return;
-    }
-    memcpy(copied, data, sizeof(_PyCrossInterpreterData));
-    if (_Py_AddPendingCall(interp, 0, _release_xidata, copied) != 0) {
-        // XXX Queue full or couldn't get lock.  Try again somehow?
-    }
+    _call_in_interpreter(interp, _release_xidata, data);
 }
 
 PyObject *
@@ -1392,7 +1372,7 @@ _register_xidata(PyTypeObject *cls, crossinterpdatafunc getdata)
 static void _register_builtins_for_crossinterpreter_data(void);
 
 int
-_PyCrossInterpreterData_RegisterClass(PyTypeObject *cls,
+_PyCrossInterpreterData_Register_Class(PyTypeObject *cls,
                                        crossinterpdatafunc getdata)
 {
     if (!PyType_Check(cls)) {
diff --git a/setup.py b/setup.py
index c278f08b8e6d..b96961073b98 100644
--- a/setup.py
+++ b/setup.py
@@ -784,7 +784,9 @@ def detect_simple_extensions(self):
         self.add(Extension('syslog', ['syslogmodule.c']))
 
         # Python interface to subinterpreter C-API.
-        self.add(Extension('_xxsubinterpreters', ['_xxsubinterpretersmodule.c']))
+        self.add(Extension('_xxsubinterpreters',
+                           ['_xxsubinterpretersmodule.c'],
+                           define_macros=[('Py_BUILD_CORE', '')]))
 
         #
         # Here ends the simple stuff.  From here on, modules need certain



More information about the Python-checkins mailing list