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 bcfa450f21.

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

This reverts commit bda918bf65.

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

This reverts commit b05b711a2c.

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

This reverts commit ef4ac967e2.
This commit is contained in:
Victor Stinner 2019-03-04 14:21:28 +01:00 committed by GitHub
parent f4b0a1c0da
commit 4d61e6e3b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 582 additions and 751 deletions

View File

@ -221,7 +221,7 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(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 #endif
/* Masks and values used by FORMAT_VALUE opcode. */ /* Masks and values used by FORMAT_VALUE opcode. */

View File

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

View File

@ -30,13 +30,9 @@ typedef struct {
(_PyMainInterpreterConfig){.install_signal_handlers = -1} (_PyMainInterpreterConfig){.install_signal_handlers = -1}
/* Note: _PyMainInterpreterConfig_INIT sets other fields to 0/NULL */ /* 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(_PyCoreConfig *) _PyInterpreterState_GetCoreConfig(PyInterpreterState *);
PyAPI_FUNC(_PyMainInterpreterConfig *) _PyInterpreterState_GetMainConfig(PyInterpreterState *); PyAPI_FUNC(_PyMainInterpreterConfig *) _PyInterpreterState_GetMainConfig(PyInterpreterState *);
PyAPI_FUNC(PyObject *) _PyInterpreterState_GetMainModule(PyInterpreterState *);
/* State unique per thread */ /* State unique per thread */
@ -218,65 +214,6 @@ PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *);
typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -58,10 +58,10 @@ typedef struct _Py_atomic_int {
atomic_thread_fence(ORDER) atomic_thread_fence(ORDER)
#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, 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) \ #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 */ /* Use builtin atomic operations in GCC >= 4.7 */
#elif defined(HAVE_BUILTIN_ATOMIC) #elif defined(HAVE_BUILTIN_ATOMIC)
@ -92,14 +92,14 @@ typedef struct _Py_atomic_int {
(assert((ORDER) == __ATOMIC_RELAXED \ (assert((ORDER) == __ATOMIC_RELAXED \
|| (ORDER) == __ATOMIC_SEQ_CST \ || (ORDER) == __ATOMIC_SEQ_CST \
|| (ORDER) == __ATOMIC_RELEASE), \ || (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) \ #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
(assert((ORDER) == __ATOMIC_RELAXED \ (assert((ORDER) == __ATOMIC_RELAXED \
|| (ORDER) == __ATOMIC_SEQ_CST \ || (ORDER) == __ATOMIC_SEQ_CST \
|| (ORDER) == __ATOMIC_ACQUIRE \ || (ORDER) == __ATOMIC_ACQUIRE \
|| (ORDER) == __ATOMIC_CONSUME), \ || (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 /* Only support GCC (for expression statements) and x86 (for simple
* atomic semantics) and MSVC x86/x64/ARM */ * 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 #else
#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *(ATOMIC_VAL) #define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *ATOMIC_VAL
#endif #endif
inline int _Py_atomic_load_32bit(volatile int* value, int order) { 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) \ #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
if (sizeof((ATOMIC_VAL)->_value) == 8) { \ if (sizeof(*ATOMIC_VAL._value) == 8) { \
_Py_atomic_store_64bit((volatile long long*)&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) } else { \ _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) } _Py_atomic_store_32bit((volatile long*)ATOMIC_VAL._value, NEW_VAL, ORDER) }
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
( \ ( \
sizeof((ATOMIC_VAL)->_value) == 8 ? \ sizeof(*(ATOMIC_VAL._value)) == 8 ? \
_Py_atomic_load_64bit((volatile long long*)&((ATOMIC_VAL)->_value), ORDER) : \ _Py_atomic_load_64bit((volatile long long*)ATOMIC_VAL._value, ORDER) : \
_Py_atomic_load_32bit((volatile long*)&((ATOMIC_VAL)->_value), ORDER) \ _Py_atomic_load_32bit((volatile long*)ATOMIC_VAL._value, ORDER) \
) )
#elif defined(_M_ARM) || defined(_M_ARM64) #elif defined(_M_ARM) || defined(_M_ARM64)
typedef enum _Py_memory_order { typedef enum _Py_memory_order {
@ -391,13 +391,13 @@ typedef struct _Py_atomic_int {
#define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) \ #define _Py_atomic_store_64bit(ATOMIC_VAL, NEW_VAL, ORDER) \
switch (ORDER) { \ switch (ORDER) { \
case _Py_memory_order_acquire: \ 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; \ break; \
case _Py_memory_order_release: \ 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; \ break; \
default: \ default: \
_InterlockedExchange64((__int64 volatile*)&((ATOMIC_VAL)->_value), (__int64)NEW_VAL); \ _InterlockedExchange64((__int64 volatile*)ATOMIC_VAL, (__int64)NEW_VAL); \
break; \ break; \
} }
#else #else
@ -407,13 +407,13 @@ typedef struct _Py_atomic_int {
#define _Py_atomic_store_32bit(ATOMIC_VAL, NEW_VAL, ORDER) \ #define _Py_atomic_store_32bit(ATOMIC_VAL, NEW_VAL, ORDER) \
switch (ORDER) { \ switch (ORDER) { \
case _Py_memory_order_acquire: \ 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; \ break; \
case _Py_memory_order_release: \ 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; \ break; \
default: \ default: \
_InterlockedExchange((volatile long*)&((ATOMIC_VAL)->_value), (int)NEW_VAL); \ _InterlockedExchange((volatile long*)ATOMIC_VAL, (int)NEW_VAL); \
break; \ break; \
} }
@ -454,7 +454,7 @@ inline intptr_t _Py_atomic_load_64bit(volatile uintptr_t* value, int order) {
} }
#else #else
#define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *(ATOMIC_VAL) #define _Py_atomic_load_64bit(ATOMIC_VAL, ORDER) *ATOMIC_VAL
#endif #endif
inline int _Py_atomic_load_32bit(volatile int* value, int order) { 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) \ #define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
if (sizeof((ATOMIC_VAL)->_value) == 8) { \ if (sizeof(*ATOMIC_VAL._value) == 8) { \
_Py_atomic_store_64bit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) } else { \ _Py_atomic_store_64bit(ATOMIC_VAL._value, NEW_VAL, ORDER) } else { \
_Py_atomic_store_32bit(&((ATOMIC_VAL)->_value), NEW_VAL, ORDER) } _Py_atomic_store_32bit(ATOMIC_VAL._value, NEW_VAL, ORDER) }
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ #define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
( \ ( \
sizeof((ATOMIC_VAL)->_value) == 8 ? \ sizeof(*(ATOMIC_VAL._value)) == 8 ? \
_Py_atomic_load_64bit(&((ATOMIC_VAL)->_value), ORDER) : \ _Py_atomic_load_64bit(ATOMIC_VAL._value, ORDER) : \
_Py_atomic_load_32bit(&((ATOMIC_VAL)->_value), ORDER) \ _Py_atomic_load_32bit(ATOMIC_VAL._value, ORDER) \
) )
#endif #endif
#else /* !gcc x86 !_msc_ver */ #else /* !gcc x86 !_msc_ver */

View File

@ -11,12 +11,8 @@ extern "C" {
#include "pycore_atomic.h" #include "pycore_atomic.h"
#include "pythread.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 { struct _pending_calls {
unsigned long main_thread;
PyThread_type_lock lock; PyThread_type_lock lock;
/* Request for running pending calls. */ /* Request for running pending calls. */
_Py_atomic_int calls_to_do; _Py_atomic_int calls_to_do;
@ -26,7 +22,6 @@ struct _pending_calls {
int async_exc; int async_exc;
#define NPENDINGCALLS 32 #define NPENDINGCALLS 32
struct { struct {
unsigned long thread_id;
int (*func)(void *); int (*func)(void *);
void *arg; void *arg;
} calls[NPENDINGCALLS]; } calls[NPENDINGCALLS];
@ -34,13 +29,6 @@ struct _pending_calls {
int last; 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" #include "pycore_gil.h"
struct _ceval_runtime_state { struct _ceval_runtime_state {
@ -51,8 +39,12 @@ struct _ceval_runtime_state {
c_tracefunc. This speeds up the if statement in c_tracefunc. This speeds up the if statement in
PyEval_EvalFrameEx() after fast_next_opcode. */ PyEval_EvalFrameEx() after fast_next_opcode. */
int tracing_possible; 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 */ /* Request for dropping the GIL */
_Py_atomic_int gil_drop_request; _Py_atomic_int gil_drop_request;
struct _pending_calls pending;
/* Request for checking signals. */ /* Request for checking signals. */
_Py_atomic_int signals_pending; _Py_atomic_int signals_pending;
struct _gil_runtime_state gil; struct _gil_runtime_state gil;

View File

@ -11,7 +11,6 @@ extern "C" {
#include "pystate.h" #include "pystate.h"
#include "pythread.h" #include "pythread.h"
#include "pycore_atomic.h"
#include "pycore_ceval.h" #include "pycore_ceval.h"
#include "pycore_pathconfig.h" #include "pycore_pathconfig.h"
#include "pycore_pymem.h" #include "pycore_pymem.h"
@ -30,11 +29,8 @@ struct _is {
int64_t id; int64_t id;
int64_t id_refcount; int64_t id_refcount;
int requires_idref;
PyThread_type_lock id_mutex; PyThread_type_lock id_mutex;
int finalizing;
PyObject *modules; PyObject *modules;
PyObject *modules_by_index; PyObject *modules_by_index;
PyObject *sysdict; PyObject *sysdict;
@ -82,8 +78,6 @@ struct _is {
PyObject *pyexitmodule; PyObject *pyexitmodule;
uint64_t tstate_next_unique_id; uint64_t tstate_next_unique_id;
struct _ceval_interpreter_state ceval;
}; };
PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(PY_INT64_T); 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 *); 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 */ /* cross-interpreter data registry */
/* For now we use a global registry of shareable classes. An /* For now we use a global registry of shareable classes. An
alternative would be to add a tp_* slot for a class's alternative would be to add a tp_* slot for a class's
crossinterpdatafunc. It would be simpler and more efficient. */ 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;
struct _xidregitem { struct _xidregitem {
@ -159,8 +207,6 @@ typedef struct pyruntimestate {
struct _xidregitem *head; struct _xidregitem *head;
} xidregistry; } xidregistry;
unsigned long main_thread;
#define NEXITFUNCS 32 #define NEXITFUNCS 32
void (*exitfuncs[NEXITFUNCS])(void); void (*exitfuncs[NEXITFUNCS])(void);
int nexitfuncs; int nexitfuncs;

View File

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

View File

@ -391,7 +391,6 @@ OBJECT_OBJS= \
Objects/floatobject.o \ Objects/floatobject.o \
Objects/frameobject.o \ Objects/frameobject.o \
Objects/funcobject.o \ Objects/funcobject.o \
Objects/interpreteridobject.o \
Objects/iterobject.o \ Objects/iterobject.o \
Objects/listobject.o \ Objects/listobject.o \
Objects/longobject.o \ Objects/longobject.o \
@ -978,7 +977,6 @@ PYTHON_HEADERS= \
$(srcdir)/Include/funcobject.h \ $(srcdir)/Include/funcobject.h \
$(srcdir)/Include/genobject.h \ $(srcdir)/Include/genobject.h \
$(srcdir)/Include/import.h \ $(srcdir)/Include/import.h \
$(srcdir)/Include/interpreteridobject.h \
$(srcdir)/Include/intrcheck.h \ $(srcdir)/Include/intrcheck.h \
$(srcdir)/Include/iterobject.h \ $(srcdir)/Include/iterobject.h \
$(srcdir)/Include/listobject.h \ $(srcdir)/Include/listobject.h \
@ -1041,7 +1039,6 @@ PYTHON_HEADERS= \
$(srcdir)/Include/cpython/abstract.h \ $(srcdir)/Include/cpython/abstract.h \
$(srcdir)/Include/cpython/coreconfig.h \ $(srcdir)/Include/cpython/coreconfig.h \
$(srcdir)/Include/cpython/dictobject.h \ $(srcdir)/Include/cpython/dictobject.h \
$(srcdir)/Include/cpython/interpreteridobject.h \
$(srcdir)/Include/cpython/object.h \ $(srcdir)/Include/cpython/object.h \
$(srcdir)/Include/cpython/objimpl.h \ $(srcdir)/Include/cpython/objimpl.h \
$(srcdir)/Include/cpython/pyerrors.h \ $(srcdir)/Include/cpython/pyerrors.h \

View File

@ -2445,7 +2445,6 @@ pending_threadfunc(PyObject *self, PyObject *arg)
Py_INCREF(callable); Py_INCREF(callable);
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
/* XXX Use the internal _Py_AddPendingCall(). */
r = Py_AddPendingCall(&_pending_callback, callable); r = Py_AddPendingCall(&_pending_callback, callable);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS

View File

@ -4,7 +4,7 @@
#include "Python.h" #include "Python.h"
#include "frameobject.h" #include "frameobject.h"
#include "interpreteridobject.h" #include "pycore_pystate.h"
static char * static char *
@ -31,6 +31,38 @@ _get_current(void)
return _PyInterpreterState_Get(); 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 ***********************************************/ /* data-sharing-specific code ***********************************************/
@ -39,8 +71,6 @@ struct _sharednsitem {
_PyCrossInterpreterData data; _PyCrossInterpreterData data;
}; };
static void _sharednsitem_clear(struct _sharednsitem *); // forward
static int static int
_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value) _sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
{ {
@ -49,7 +79,6 @@ _sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
return -1; return -1;
} }
if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) { if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
_sharednsitem_clear(item);
return -1; return -1;
} }
return 0; return 0;
@ -60,7 +89,6 @@ _sharednsitem_clear(struct _sharednsitem *item)
{ {
if (item->name != NULL) { if (item->name != NULL) {
PyMem_Free(item->name); PyMem_Free(item->name);
item->name = NULL;
} }
_PyCrossInterpreterData_Release(&item->data); _PyCrossInterpreterData_Release(&item->data);
} }
@ -1311,13 +1339,13 @@ _channel_send(_channels *channels, int64_t id, PyObject *obj)
return -1; return -1;
} }
if (_PyObject_GetCrossInterpreterData(obj, data) != 0) { if (_PyObject_GetCrossInterpreterData(obj, data) != 0) {
PyThread_release_lock(mutex);
PyMem_Free(data); PyMem_Free(data);
PyThread_release_lock(mutex);
return -1; return -1;
} }
// Add the data to the channel. // 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); PyThread_release_lock(mutex);
if (res != 0) { if (res != 0) {
_PyCrossInterpreterData_Release(data); _PyCrossInterpreterData_Release(data);
@ -1345,7 +1373,7 @@ _channel_recv(_channels *channels, int64_t id)
// Past this point we are responsible for releasing the mutex. // Past this point we are responsible for releasing the mutex.
// Pop off the next item from the channel. // 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); PyThread_release_lock(mutex);
if (data == NULL) { if (data == NULL) {
if (!PyErr_Occurred()) { 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. // Past this point we are responsible for releasing the mutex.
// Close one or both of the two ends. // 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); PyThread_release_lock(mutex);
return res; return res;
} }
@ -1453,7 +1481,7 @@ channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
cid = ((channelid *)id)->id; cid = ((channelid *)id)->id;
} }
else { else {
cid = _Py_CoerceID(id); cid = _coerce_id(id);
if (cid < 0) { if (cid < 0) {
return NULL; return NULL;
} }
@ -1847,7 +1875,7 @@ _run_script(PyInterpreterState *interp, const char *codestr,
PyObject *excval = NULL; PyObject *excval = NULL;
PyObject *tb = NULL; PyObject *tb = NULL;
PyObject *main_mod = _PyInterpreterState_GetMainModule(interp); PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
if (main_mod == NULL) { if (main_mod == NULL) {
goto error; goto error;
} }
@ -1946,6 +1974,272 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
return result; 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 ********************************************************/ /* module level code ********************************************************/
@ -1989,16 +2283,17 @@ interp_create(PyObject *self, PyObject *args)
PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed"); PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
return NULL; return NULL;
} }
PyObject *idobj = _PyInterpreterState_GetIDObject(tstate->interp); if (_PyInterpreterState_IDInitref(tstate->interp) != 0) {
if (idobj == NULL) { goto error;
// XXX Possible GILState issues? };
save_tstate = PyThreadState_Swap(tstate); return _get_id(tstate->interp);
Py_EndInterpreter(tstate);
PyThreadState_Swap(save_tstate); error:
return NULL; // XXX Possible GILState issues?
} save_tstate = PyThreadState_Swap(tstate);
_PyInterpreterState_RequireIDRef(tstate->interp, 1); Py_EndInterpreter(tstate);
return idobj; PyThreadState_Swap(save_tstate);
return NULL;
} }
PyDoc_STRVAR(create_doc, PyDoc_STRVAR(create_doc,
@ -2023,7 +2318,7 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
} }
// Look up the interpreter. // Look up the interpreter.
PyInterpreterState *interp = _PyInterpreterID_LookUp(id); PyInterpreterState *interp = _look_up(id);
if (interp == NULL) { if (interp == NULL) {
return NULL; return NULL;
} }
@ -2079,7 +2374,7 @@ interp_list_all(PyObject *self, PyObject *Py_UNUSED(ignored))
interp = PyInterpreterState_Head(); interp = PyInterpreterState_Head();
while (interp != NULL) { while (interp != NULL) {
id = _PyInterpreterState_GetIDObject(interp); id = _get_id(interp);
if (id == NULL) { if (id == NULL) {
Py_DECREF(ids); Py_DECREF(ids);
return NULL; return NULL;
@ -2111,7 +2406,7 @@ interp_get_current(PyObject *self, PyObject *Py_UNUSED(ignored))
if (interp == NULL) { if (interp == NULL) {
return NULL; return NULL;
} }
return _PyInterpreterState_GetIDObject(interp); return _get_id(interp);
} }
PyDoc_STRVAR(get_current_doc, 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. // Currently, 0 is always the main interpreter.
PY_INT64_T id = 0; PY_INT64_T id = 0;
return _PyInterpreterID_New(id); return (PyObject *)newinterpid(&InterpreterIDtype, id, 0);
} }
PyDoc_STRVAR(get_main_doc, PyDoc_STRVAR(get_main_doc,
@ -2151,7 +2446,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
} }
// Look up the interpreter. // Look up the interpreter.
PyInterpreterState *interp = _PyInterpreterID_LookUp(id); PyInterpreterState *interp = _look_up(id);
if (interp == NULL) { if (interp == NULL) {
return NULL; return NULL;
} }
@ -2221,7 +2516,7 @@ interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
return NULL; return NULL;
} }
PyInterpreterState *interp = _PyInterpreterID_LookUp(id); PyInterpreterState *interp = _look_up(id);
if (interp == NULL) { if (interp == NULL) {
return NULL; return NULL;
} }
@ -2273,7 +2568,7 @@ channel_destroy(PyObject *self, PyObject *args, PyObject *kwds)
"O:channel_destroy", kwlist, &id)) { "O:channel_destroy", kwlist, &id)) {
return NULL; return NULL;
} }
int64_t cid = _Py_CoerceID(id); int64_t cid = _coerce_id(id);
if (cid < 0) { if (cid < 0) {
return NULL; return NULL;
} }
@ -2337,7 +2632,7 @@ channel_send(PyObject *self, PyObject *args, PyObject *kwds)
"OO:channel_send", kwlist, &id, &obj)) { "OO:channel_send", kwlist, &id, &obj)) {
return NULL; return NULL;
} }
int64_t cid = _Py_CoerceID(id); int64_t cid = _coerce_id(id);
if (cid < 0) { if (cid < 0) {
return NULL; return NULL;
} }
@ -2362,7 +2657,7 @@ channel_recv(PyObject *self, PyObject *args, PyObject *kwds)
"O:channel_recv", kwlist, &id)) { "O:channel_recv", kwlist, &id)) {
return NULL; return NULL;
} }
int64_t cid = _Py_CoerceID(id); int64_t cid = _coerce_id(id);
if (cid < 0) { if (cid < 0) {
return NULL; return NULL;
} }
@ -2388,7 +2683,7 @@ channel_close(PyObject *self, PyObject *args, PyObject *kwds)
&id, &send, &recv, &force)) { &id, &send, &recv, &force)) {
return NULL; return NULL;
} }
int64_t cid = _Py_CoerceID(id); int64_t cid = _coerce_id(id);
if (cid < 0) { if (cid < 0) {
return NULL; return NULL;
} }
@ -2440,7 +2735,7 @@ channel_release(PyObject *self, PyObject *args, PyObject *kwds)
&id, &send, &recv, &force)) { &id, &send, &recv, &force)) {
return NULL; return NULL;
} }
int64_t cid = _Py_CoerceID(id); int64_t cid = _coerce_id(id);
if (cid < 0) { if (cid < 0) {
return NULL; return NULL;
} }
@ -2542,6 +2837,10 @@ PyInit__xxsubinterpreters(void)
if (PyType_Ready(&ChannelIDtype) != 0) { if (PyType_Ready(&ChannelIDtype) != 0) {
return NULL; return NULL;
} }
InterpreterIDtype.tp_base = &PyLong_Type;
if (PyType_Ready(&InterpreterIDtype) != 0) {
return NULL;
}
/* Create the module */ /* Create the module */
PyObject *module = PyModule_Create(&interpretersmodule); PyObject *module = PyModule_Create(&interpretersmodule);
@ -2563,12 +2862,12 @@ PyInit__xxsubinterpreters(void)
if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) { if (PyDict_SetItemString(ns, "ChannelID", (PyObject *)&ChannelIDtype) != 0) {
return NULL; return NULL;
} }
Py_INCREF(&_PyInterpreterID_Type); Py_INCREF(&InterpreterIDtype);
if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&_PyInterpreterID_Type) != 0) { if (PyDict_SetItemString(ns, "InterpreterID", (PyObject *)&InterpreterIDtype) != 0) {
return NULL; return NULL;
} }
if (_PyCrossInterpreterData_RegisterClass(&ChannelIDtype, _channelid_shared)) { if (_PyCrossInterpreterData_Register_Class(&ChannelIDtype, _channelid_shared)) {
return NULL; return NULL;
} }

View File

@ -19,7 +19,6 @@
#include <process.h> #include <process.h>
#endif #endif
#endif #endif
#include "internal/pycore_pystate.h"
#ifdef HAVE_SIGNAL_H #ifdef HAVE_SIGNAL_H
#include <signal.h> #include <signal.h>
@ -296,10 +295,8 @@ trip_signal(int sig_num)
{ {
/* Py_AddPendingCall() isn't signal-safe, but we /* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */ still use it for this exceptional case. */
_Py_AddPendingCall(_PyRuntime.interpreters.main, Py_AddPendingCall(report_wakeup_send_error,
main_thread, (void *)(intptr_t) last_error);
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 /* Py_AddPendingCall() isn't signal-safe, but we
still use it for this exceptional case. */ still use it for this exceptional case. */
_Py_AddPendingCall(_PyRuntime.interpreters.main, Py_AddPendingCall(report_wakeup_write_error,
main_thread, (void *)(intptr_t)errno);
report_wakeup_write_error,
(void *)(intptr_t)errno);
} }
} }
} }

View File

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

View File

@ -5,7 +5,6 @@
#include "pycore_pystate.h" #include "pycore_pystate.h"
#include "pycore_context.h" #include "pycore_context.h"
#include "frameobject.h" #include "frameobject.h"
#include "interpreteridobject.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -1807,7 +1806,6 @@ _PyTypes_Init(void)
INIT_TYPE(&PySeqIter_Type, "sequence iterator"); INIT_TYPE(&PySeqIter_Type, "sequence iterator");
INIT_TYPE(&PyCoro_Type, "coroutine"); INIT_TYPE(&PyCoro_Type, "coroutine");
INIT_TYPE(&_PyCoroWrapper_Type, "coroutine wrapper"); INIT_TYPE(&_PyCoroWrapper_Type, "coroutine wrapper");
INIT_TYPE(&_PyInterpreterID_Type, "interpreter ID");
return _Py_INIT_OK(); return _Py_INIT_OK();
#undef INIT_TYPE #undef INIT_TYPE

View File

@ -154,7 +154,6 @@
<ClInclude Include="..\Include\internal\pycore_pystate.h" /> <ClInclude Include="..\Include\internal\pycore_pystate.h" />
<ClInclude Include="..\Include\internal\pycore_tupleobject.h" /> <ClInclude Include="..\Include\internal\pycore_tupleobject.h" />
<ClInclude Include="..\Include\internal\pycore_warnings.h" /> <ClInclude Include="..\Include\internal\pycore_warnings.h" />
<ClInclude Include="..\Include\interpreteridobject.h" />
<ClInclude Include="..\Include\intrcheck.h" /> <ClInclude Include="..\Include\intrcheck.h" />
<ClInclude Include="..\Include\iterobject.h" /> <ClInclude Include="..\Include\iterobject.h" />
<ClInclude Include="..\Include\listobject.h" /> <ClInclude Include="..\Include\listobject.h" />
@ -351,7 +350,6 @@
<ClCompile Include="..\Objects\frameobject.c" /> <ClCompile Include="..\Objects\frameobject.c" />
<ClCompile Include="..\Objects\funcobject.c" /> <ClCompile Include="..\Objects\funcobject.c" />
<ClCompile Include="..\Objects\genobject.c" /> <ClCompile Include="..\Objects\genobject.c" />
<ClCompile Include="..\Objects\interpreteridobject.c" />
<ClCompile Include="..\Objects\iterobject.c" /> <ClCompile Include="..\Objects\iterobject.c" />
<ClCompile Include="..\Objects\listobject.c" /> <ClCompile Include="..\Objects\listobject.c" />
<ClCompile Include="..\Objects\longobject.c" /> <ClCompile Include="..\Objects\longobject.c" />

View File

@ -483,9 +483,6 @@
<ClInclude Include="..\Include\namespaceobject.h"> <ClInclude Include="..\Include\namespaceobject.h">
<Filter>Include</Filter> <Filter>Include</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Include\interpreteridobject.h">
<Filter>Include</Filter>
</ClInclude>
<ClInclude Include="..\Modules\hashtable.h"> <ClInclude Include="..\Modules\hashtable.h">
<Filter>Modules</Filter> <Filter>Modules</Filter>
</ClInclude> </ClInclude>
@ -1046,9 +1043,6 @@
<ClCompile Include="..\Objects\namespaceobject.c"> <ClCompile Include="..\Objects\namespaceobject.c">
<Filter>Objects</Filter> <Filter>Objects</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Objects\interpreteridobject.c">
<Filter>Objects</Filter>
</ClCompile>
<ClCompile Include="..\Modules\_opcode.c"> <ClCompile Include="..\Modules\_opcode.c">
<Filter>Modules</Filter> <Filter>Modules</Filter>
</ClCompile> </ClCompile>

View File

@ -96,61 +96,61 @@ static long dxp[256];
/* This can set eval_breaker to 0 even though gil_drop_request became /* 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 1. We believe this is all right because the eval loop will release
the GIL eventually anyway. */ the GIL eventually anyway. */
#define COMPUTE_EVAL_BREAKER(interp) \ #define COMPUTE_EVAL_BREAKER() \
_Py_atomic_store_relaxed( \ _Py_atomic_store_relaxed( \
&interp->ceval.eval_breaker, \ &_PyRuntime.ceval.eval_breaker, \
GIL_REQUEST | \ GIL_REQUEST | \
_Py_atomic_load_relaxed(&_PyRuntime.ceval.signals_pending) | \ _Py_atomic_load_relaxed(&_PyRuntime.ceval.signals_pending) | \
_Py_atomic_load_relaxed(&interp->ceval.pending.calls_to_do) | \ _Py_atomic_load_relaxed(&_PyRuntime.ceval.pending.calls_to_do) | \
interp->ceval.pending.async_exc) _PyRuntime.ceval.pending.async_exc)
#define SET_GIL_DROP_REQUEST(interp) \ #define SET_GIL_DROP_REQUEST() \
do { \ do { \
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 1); \ _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) } while (0)
#define RESET_GIL_DROP_REQUEST(interp) \ #define RESET_GIL_DROP_REQUEST() \
do { \ do { \
_Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 0); \ _Py_atomic_store_relaxed(&_PyRuntime.ceval.gil_drop_request, 0); \
COMPUTE_EVAL_BREAKER(interp); \ COMPUTE_EVAL_BREAKER(); \
} while (0) } while (0)
/* Pending calls are only modified under pending_lock */ /* Pending calls are only modified under pending_lock */
#define SIGNAL_PENDING_CALLS(interp) \ #define SIGNAL_PENDING_CALLS() \
do { \ do { \
_Py_atomic_store_relaxed(&interp->ceval.pending.calls_to_do, 1); \ _Py_atomic_store_relaxed(&_PyRuntime.ceval.pending.calls_to_do, 1); \
_Py_atomic_store_relaxed(&interp->ceval.eval_breaker, 1); \ _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
} while (0) } while (0)
#define UNSIGNAL_PENDING_CALLS(interp) \ #define UNSIGNAL_PENDING_CALLS() \
do { \ do { \
_Py_atomic_store_relaxed(&interp->ceval.pending.calls_to_do, 0); \ _Py_atomic_store_relaxed(&_PyRuntime.ceval.pending.calls_to_do, 0); \
COMPUTE_EVAL_BREAKER(interp); \ COMPUTE_EVAL_BREAKER(); \
} while (0) } while (0)
#define SIGNAL_PENDING_SIGNALS() \ #define SIGNAL_PENDING_SIGNALS() \
do { \ do { \
_Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 1); \ _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) } while (0)
#define UNSIGNAL_PENDING_SIGNALS() \ #define UNSIGNAL_PENDING_SIGNALS() \
do { \ do { \
_Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 0); \ _Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 0); \
COMPUTE_EVAL_BREAKER(_PyRuntime.interpreters.main); \ COMPUTE_EVAL_BREAKER(); \
} while (0) } while (0)
#define SIGNAL_ASYNC_EXC(interp) \ #define SIGNAL_ASYNC_EXC() \
do { \ do { \
interp->ceval.pending.async_exc = 1; \ _PyRuntime.ceval.pending.async_exc = 1; \
_Py_atomic_store_relaxed(&interp->ceval.eval_breaker, 1); \ _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
} while (0) } while (0)
#define UNSIGNAL_ASYNC_EXC(interp) \ #define UNSIGNAL_ASYNC_EXC() \
do { \ do { \
interp->ceval.pending.async_exc = 0; \ _PyRuntime.ceval.pending.async_exc = 0; \
COMPUTE_EVAL_BREAKER(interp); \ COMPUTE_EVAL_BREAKER(); \
} while (0) } while (0)
@ -174,6 +174,9 @@ PyEval_InitThreads(void)
PyThread_init_thread(); PyThread_init_thread();
create_gil(); create_gil();
take_gil(_PyThreadState_GET()); 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 void
@ -240,11 +243,9 @@ PyEval_ReInitThreads(void)
if (!gil_created()) if (!gil_created())
return; return;
recreate_gil(); recreate_gil();
// This will be reset in make_pending_calls() below. _PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
current_tstate->interp->ceval.pending.lock = NULL;
take_gil(current_tstate); 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 */ /* Destroy all threads except the current one */
_PyThreadState_DeleteExcept(current_tstate); _PyThreadState_DeleteExcept(current_tstate);
@ -254,9 +255,9 @@ PyEval_ReInitThreads(void)
raised. */ raised. */
void void
_PyEval_SignalAsyncExc(PyInterpreterState *interp) _PyEval_SignalAsyncExc(void)
{ {
SIGNAL_ASYNC_EXC(interp); SIGNAL_ASYNC_EXC();
} }
PyThreadState * PyThreadState *
@ -322,58 +323,17 @@ _PyEval_SignalReceived(void)
SIGNAL_PENDING_SIGNALS(); 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 /* This implementation is thread-safe. It allows
scheduling to be made from any thread, and even from an executing scheduling to be made from any thread, and even from an executing
callback. callback.
*/ */
int 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 /* try a few times for the lock. Since this mechanism is used
* for signal handling (on the main thread), there is a (slim) * for signal handling (on the main thread), there is a (slim)
* chance that a signal is delivered on the same thread while we * 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 * We also check for lock being NULL, in the unlikely case that
* this function is called before any bytecode evaluation takes place. * this function is called before any bytecode evaluation takes place.
*/ */
PyThread_type_lock lock = interp->ceval.pending.lock;
if (lock != NULL) { if (lock != NULL) {
int i;
for (i = 0; i<100; i++) { for (i = 0; i<100; i++) {
if (PyThread_acquire_lock(lock, NOWAIT_LOCK)) if (PyThread_acquire_lock(lock, NOWAIT_LOCK))
break; break;
@ -396,21 +354,17 @@ _Py_AddPendingCall(PyInterpreterState *interp, unsigned long thread_id, int (*fu
return -1; return -1;
} }
int result = -1; i = _PyRuntime.ceval.pending.last;
if (interp->finalizing) { j = (i + 1) % NPENDINGCALLS;
PyObject *exc, *val, *tb; if (j == _PyRuntime.ceval.pending.first) {
PyErr_Fetch(&exc, &val, &tb); result = -1; /* Queue full */
PyErr_SetString(PyExc_SystemError, "Py_AddPendingCall: cannot add pending calls (interpreter shutting down)"); } else {
PyErr_Print(); _PyRuntime.ceval.pending.calls[i].func = func;
PyErr_Restore(exc, val, tb); _PyRuntime.ceval.pending.calls[i].arg = arg;
goto done; _PyRuntime.ceval.pending.last = j;
} }
result = _add_pending_call(interp, thread_id, func, arg);
/* signal main loop */ /* signal main loop */
SIGNAL_PENDING_CALLS(interp); SIGNAL_PENDING_CALLS();
done:
if (lock != NULL) if (lock != NULL)
PyThread_release_lock(lock); PyThread_release_lock(lock);
return result; return result;
@ -420,7 +374,9 @@ static int
handle_signals(void) handle_signals(void)
{ {
/* Only handle signals on main thread. */ /* 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; return 0;
} }
/* /*
@ -440,10 +396,17 @@ handle_signals(void)
} }
static int static int
make_pending_calls(PyInterpreterState *interp) make_pending_calls(void)
{ {
static int busy = 0; 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 */ /* don't perform recursive pending calls */
if (busy) { if (busy) {
return 0; return 0;
@ -451,13 +414,13 @@ make_pending_calls(PyInterpreterState *interp)
busy = 1; busy = 1;
/* unsignal before starting to call callbacks, so that any callback /* unsignal before starting to call callbacks, so that any callback
added in-between re-signals */ added in-between re-signals */
UNSIGNAL_PENDING_CALLS(interp); UNSIGNAL_PENDING_CALLS();
int res = 0; int res = 0;
if (!interp->ceval.pending.lock) { if (!_PyRuntime.ceval.pending.lock) {
/* initial allocation of the lock */ /* initial allocation of the lock */
interp->ceval.pending.lock = PyThread_allocate_lock(); _PyRuntime.ceval.pending.lock = PyThread_allocate_lock();
if (interp->ceval.pending.lock == NULL) { if (_PyRuntime.ceval.pending.lock == NULL) {
res = -1; res = -1;
goto error; goto error;
} }
@ -465,18 +428,24 @@ make_pending_calls(PyInterpreterState *interp)
/* perform a bounded number of calls, in case of recursion */ /* perform a bounded number of calls, in case of recursion */
for (int i=0; i<NPENDINGCALLS; i++) { for (int i=0; i<NPENDINGCALLS; i++) {
int (*func)(void *) = NULL; int j;
int (*func)(void *);
void *arg = NULL; void *arg = NULL;
/* pop one item off the queue while holding the lock */ /* pop one item off the queue while holding the lock */
PyThread_acquire_lock(interp->ceval.pending.lock, WAIT_LOCK); PyThread_acquire_lock(_PyRuntime.ceval.pending.lock, WAIT_LOCK);
_pop_pending_call(interp, &func, &arg); j = _PyRuntime.ceval.pending.first;
PyThread_release_lock(interp->ceval.pending.lock); if (j == _PyRuntime.ceval.pending.last) {
func = NULL; /* Queue empty */
/* having released the lock, perform the callback */ } else {
if (func == NULL) { func = _PyRuntime.ceval.pending.calls[j].func;
break; 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)
break;
res = func(arg); res = func(arg);
if (res) { if (res) {
goto error; goto error;
@ -488,18 +457,10 @@ make_pending_calls(PyInterpreterState *interp)
error: error:
busy = 0; busy = 0;
SIGNAL_PENDING_CALLS(interp); /* We're not done yet */ SIGNAL_PENDING_CALLS();
return res; return res;
} }
int
_Py_MakePendingCalls(PyInterpreterState *interp)
{
assert(PyGILState_Check());
return make_pending_calls(interp);
}
/* Py_MakePendingCalls() is a simple wrapper for the sake /* Py_MakePendingCalls() is a simple wrapper for the sake
of backward-compatibility. */ of backward-compatibility. */
int int
@ -514,8 +475,12 @@ Py_MakePendingCalls(void)
return res; return res;
} }
PyInterpreterState *interp = _PyRuntime.interpreters.main; res = make_pending_calls();
return make_pending_calls(interp); if (res != 0) {
return res;
}
return 0;
} }
/* The interpreter's recursion limit */ /* The interpreter's recursion limit */
@ -637,7 +602,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
PyObject **fastlocals, **freevars; PyObject **fastlocals, **freevars;
PyObject *retval = NULL; /* Return value */ PyObject *retval = NULL; /* Return value */
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
_Py_atomic_int *eval_breaker = &tstate->interp->ceval.eval_breaker;
PyCodeObject *co; PyCodeObject *co;
/* when tracing we set things up so that /* when tracing we set things up so that
@ -723,7 +687,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
#define DISPATCH() \ #define DISPATCH() \
{ \ { \
if (!_Py_atomic_load_relaxed(eval_breaker)) { \ if (!_Py_atomic_load_relaxed(&_PyRuntime.ceval.eval_breaker)) { \
FAST_DISPATCH(); \ FAST_DISPATCH(); \
} \ } \
continue; \ continue; \
@ -1025,7 +989,7 @@ main_loop:
async I/O handler); see Py_AddPendingCall() and async I/O handler); see Py_AddPendingCall() and
Py_MakePendingCalls() above. */ Py_MakePendingCalls() above. */
if (_Py_atomic_load_relaxed(eval_breaker)) { if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.eval_breaker)) {
opcode = _Py_OPCODE(*next_instr); opcode = _Py_OPCODE(*next_instr);
if (opcode == SETUP_FINALLY || if (opcode == SETUP_FINALLY ||
opcode == SETUP_WITH || opcode == SETUP_WITH ||
@ -1058,9 +1022,9 @@ main_loop:
} }
} }
if (_Py_atomic_load_relaxed( 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; goto error;
} }
} }
@ -1092,7 +1056,7 @@ main_loop:
if (tstate->async_exc != NULL) { if (tstate->async_exc != NULL) {
PyObject *exc = tstate->async_exc; PyObject *exc = tstate->async_exc;
tstate->async_exc = NULL; tstate->async_exc = NULL;
UNSIGNAL_ASYNC_EXC(tstate->interp); UNSIGNAL_ASYNC_EXC();
PyErr_SetNone(exc); PyErr_SetNone(exc);
Py_DECREF(exc); Py_DECREF(exc);
goto error; goto error;

View File

@ -176,7 +176,7 @@ static void drop_gil(PyThreadState *tstate)
&_PyRuntime.ceval.gil.last_holder) &_PyRuntime.ceval.gil.last_holder)
) == tstate) ) == tstate)
{ {
RESET_GIL_DROP_REQUEST(tstate->interp); RESET_GIL_DROP_REQUEST();
/* NOTE: if COND_WAIT does not atomically start waiting when /* NOTE: if COND_WAIT does not atomically start waiting when
releasing the mutex, another thread can run through, take releasing the mutex, another thread can run through, take
the GIL and drop it again, and reset the condition the GIL and drop it again, and reset the condition
@ -213,7 +213,7 @@ static void take_gil(PyThreadState *tstate)
if (timed_out && if (timed_out &&
_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked) && _Py_atomic_load_relaxed(&_PyRuntime.ceval.gil.locked) &&
_PyRuntime.ceval.gil.switch_number == saved_switchnum) { _PyRuntime.ceval.gil.switch_number == saved_switchnum) {
SET_GIL_DROP_REQUEST(tstate->interp); SET_GIL_DROP_REQUEST();
} }
} }
_ready: _ready:
@ -239,10 +239,10 @@ _ready:
MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex); MUTEX_UNLOCK(_PyRuntime.ceval.gil.switch_mutex);
#endif #endif
if (_Py_atomic_load_relaxed(&_PyRuntime.ceval.gil_drop_request)) { 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) { if (tstate->async_exc != NULL) {
_PyEval_SignalAsyncExc(tstate->interp); _PyEval_SignalAsyncExc();
} }
MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex); MUTEX_UNLOCK(_PyRuntime.ceval.gil.mutex);

View File

@ -1460,32 +1460,8 @@ Py_EndInterpreter(PyThreadState *tstate)
if (tstate->frame != NULL) if (tstate->frame != NULL)
Py_FatalError("Py_EndInterpreter: thread still has a frame"); 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(); 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); call_py_exitfuncs(interp);
if (tstate != interp->tstate_head || tstate->next != NULL) if (tstate != interp->tstate_head || tstate->next != NULL)

View File

@ -133,19 +133,28 @@ PyInterpreterState_New(void)
return NULL; return NULL;
} }
memset(interp, 0, sizeof(*interp));
interp->id_refcount = -1; 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->check_interval = 100;
interp->num_threads = 0;
interp->ceval.pending.lock = PyThread_allocate_lock(); interp->pythread_stacksize = 0;
if (interp->ceval.pending.lock == NULL) { interp->codec_search_path = NULL;
PyErr_SetString(PyExc_RuntimeError, interp->codec_search_cache = NULL;
"failed to create interpreter ceval pending mutex"); interp->codec_error_registry = NULL;
return NULL; interp->codecs_initialized = 0;
} interp->fscodec_initialized = 0;
interp->core_config = _PyCoreConfig_INIT; interp->core_config = _PyCoreConfig_INIT;
interp->config = _PyMainInterpreterConfig_INIT; interp->config = _PyMainInterpreterConfig_INIT;
interp->importlib = NULL;
interp->import_func = NULL;
interp->eval_frame = _PyEval_EvalFrameDefault; interp->eval_frame = _PyEval_EvalFrameDefault;
interp->co_extra_user_count = 0;
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
#if HAVE_DECL_RTLD_NOW #if HAVE_DECL_RTLD_NOW
interp->dlopenflags = RTLD_NOW; interp->dlopenflags = RTLD_NOW;
@ -153,10 +162,13 @@ PyInterpreterState_New(void)
interp->dlopenflags = RTLD_LAZY; interp->dlopenflags = RTLD_LAZY;
#endif #endif
#endif #endif
#ifdef HAVE_FORK
if (_PyRuntime.main_thread == 0) { interp->before_forkers = NULL;
_PyRuntime.main_thread = PyThread_get_thread_ident(); interp->after_forkers_parent = NULL;
} interp->after_forkers_child = NULL;
#endif
interp->pyexitfunc = NULL;
interp->pyexitmodule = NULL;
HEAD_LOCK(); HEAD_LOCK();
if (_PyRuntime.interpreters.next_id < 0) { 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_parent);
Py_CLEAR(interp->after_forkers_child); Py_CLEAR(interp->after_forkers_child);
#endif #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) { if (interp->id_mutex != NULL) {
PyThread_free_lock(interp->id_mutex); PyThread_free_lock(interp->id_mutex);
} }
if (interp->ceval.pending.lock != NULL) {
PyThread_free_lock(interp->ceval.pending.lock);
}
PyMem_RawFree(interp); PyMem_RawFree(interp);
} }
@ -328,37 +334,26 @@ PyInterpreterState_GetID(PyInterpreterState *interp)
} }
static PyInterpreterState *
interp_look_up_id(PY_INT64_T requested_id)
{
PyInterpreterState *interp = PyInterpreterState_Head();
while (interp != NULL) {
PY_INT64_T id = PyInterpreterState_GetID(interp);
if (id < 0) {
return NULL;
}
if (requested_id == id) {
return interp;
}
interp = PyInterpreterState_Next(interp);
}
return NULL;
}
PyInterpreterState * PyInterpreterState *
_PyInterpreterState_LookUpID(PY_INT64_T requested_id) _PyInterpreterState_LookUpID(PY_INT64_T requested_id)
{ {
PyInterpreterState *interp = NULL; if (requested_id < 0)
if (requested_id >= 0) { goto error;
HEAD_UNLOCK();
interp = interp_look_up_id(requested_id); PyInterpreterState *interp = PyInterpreterState_Head();
HEAD_UNLOCK(); while (interp != NULL) {
PY_INT64_T id = PyInterpreterState_GetID(interp);
if (id < 0)
return NULL;
if (requested_id == id)
return interp;
interp = PyInterpreterState_Next(interp);
} }
if (interp == NULL && !PyErr_Occurred()) {
PyErr_Format(PyExc_RuntimeError, error:
"unrecognized interpreter ID %lld", requested_id); PyErr_Format(PyExc_RuntimeError,
} "unrecognized interpreter ID %lld", requested_id);
return interp; return NULL;
} }
@ -403,7 +398,7 @@ _PyInterpreterState_IDDecref(PyInterpreterState *interp)
int64_t refcount = interp->id_refcount; int64_t refcount = interp->id_refcount;
PyThread_release_lock(interp->id_mutex); PyThread_release_lock(interp->id_mutex);
if (refcount == 0 && interp->requires_idref) { if (refcount == 0) {
// XXX Using the "head" thread isn't strictly correct. // XXX Using the "head" thread isn't strictly correct.
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp); PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
// XXX Possible GILState issues? // 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 * _PyCoreConfig *
_PyInterpreterState_GetCoreConfig(PyInterpreterState *interp) _PyInterpreterState_GetCoreConfig(PyInterpreterState *interp)
{ {
@ -437,16 +420,6 @@ _PyInterpreterState_GetMainConfig(PyInterpreterState *interp)
return &interp->config; 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 */ /* Default implementation for _PyThreadState_GetFrame */
static struct _frame * static struct _frame *
threadstate_getframe(PyThreadState *self) threadstate_getframe(PyThreadState *self)
@ -899,7 +872,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
p->async_exc = exc; p->async_exc = exc;
HEAD_UNLOCK(); HEAD_UNLOCK();
Py_XDECREF(old_exc); Py_XDECREF(old_exc);
_PyEval_SignalAsyncExc(interp); _PyEval_SignalAsyncExc();
return 1; return 1;
} }
} }
@ -1313,7 +1286,7 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
return 0; return 0;
} }
static int static void
_release_xidata(void *arg) _release_xidata(void *arg)
{ {
_PyCrossInterpreterData *data = (_PyCrossInterpreterData *)arg; _PyCrossInterpreterData *data = (_PyCrossInterpreterData *)arg;
@ -1321,8 +1294,30 @@ _release_xidata(void *arg)
data->free(data->data); data->free(data->data);
} }
Py_XDECREF(data->obj); 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 void
@ -1333,7 +1328,7 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
return; return;
} }
// Get the original interpreter. // Switch to the original interpreter.
PyInterpreterState *interp = _PyInterpreterState_LookUpID(data->interp); PyInterpreterState *interp = _PyInterpreterState_LookUpID(data->interp);
if (interp == NULL) { if (interp == NULL) {
// The intepreter was already destroyed. // The intepreter was already destroyed.
@ -1342,24 +1337,9 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
} }
return; 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. // "Release" the data and/or the object.
_PyCrossInterpreterData *copied = PyMem_Malloc(sizeof(_PyCrossInterpreterData)); _call_in_interpreter(interp, _release_xidata, data);
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?
}
} }
PyObject * PyObject *
@ -1392,7 +1372,7 @@ _register_xidata(PyTypeObject *cls, crossinterpdatafunc getdata)
static void _register_builtins_for_crossinterpreter_data(void); static void _register_builtins_for_crossinterpreter_data(void);
int int
_PyCrossInterpreterData_RegisterClass(PyTypeObject *cls, _PyCrossInterpreterData_Register_Class(PyTypeObject *cls,
crossinterpdatafunc getdata) crossinterpdatafunc getdata)
{ {
if (!PyType_Check(cls)) { if (!PyType_Check(cls)) {

View File

@ -784,7 +784,9 @@ class PyBuildExt(build_ext):
self.add(Extension('syslog', ['syslogmodule.c'])) self.add(Extension('syslog', ['syslogmodule.c']))
# Python interface to subinterpreter C-API. # 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 # Here ends the simple stuff. From here on, modules need certain