mirror of
https://github.com/python/cpython.git
synced 2025-11-20 02:50:14 +00:00
Merge branch 'main' of https://github.com/python/cpython
This commit is contained in:
commit
26f23daa1e
38 changed files with 1321 additions and 139 deletions
|
|
@ -469,6 +469,9 @@ _Py_atomic_store_int_release(int *obj, int value);
|
|||
static inline int
|
||||
_Py_atomic_load_int_acquire(const int *obj);
|
||||
|
||||
static inline uint32_t
|
||||
_Py_atomic_load_uint32_acquire(const uint32_t *obj);
|
||||
|
||||
|
||||
// --- _Py_atomic_fence ------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -495,6 +495,9 @@ static inline int
|
|||
_Py_atomic_load_int_acquire(const int *obj)
|
||||
{ return __atomic_load_n(obj, __ATOMIC_ACQUIRE); }
|
||||
|
||||
static inline uint32_t
|
||||
_Py_atomic_load_uint32_acquire(const uint32_t *obj)
|
||||
{ return __atomic_load_n(obj, __ATOMIC_ACQUIRE); }
|
||||
|
||||
// --- _Py_atomic_fence ------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -938,6 +938,17 @@ _Py_atomic_load_int_acquire(const int *obj)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
_Py_atomic_load_uint32_acquire(const uint32_t *obj)
|
||||
{
|
||||
#if defined(_M_X64) || defined(_M_IX86)
|
||||
return *(uint32_t volatile *)obj;
|
||||
#elif defined(_M_ARM64)
|
||||
return (int)__ldar32((uint32_t volatile *)obj);
|
||||
#else
|
||||
# error "no implementation of _Py_atomic_load_uint32_acquire"
|
||||
#endif
|
||||
}
|
||||
|
||||
// --- _Py_atomic_fence ------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -870,6 +870,13 @@ _Py_atomic_load_int_acquire(const int *obj)
|
|||
memory_order_acquire);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
_Py_atomic_load_uint32_acquire(const uint32_t *obj)
|
||||
{
|
||||
_Py_USING_STD;
|
||||
return atomic_load_explicit((const _Atomic(uint32_t)*)obj,
|
||||
memory_order_acquire);
|
||||
}
|
||||
|
||||
|
||||
// --- _Py_atomic_fence ------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -96,6 +96,15 @@ extern "C" {
|
|||
_PyCriticalSection_End(&_cs); \
|
||||
}
|
||||
|
||||
# define Py_XBEGIN_CRITICAL_SECTION(op) \
|
||||
{ \
|
||||
_PyCriticalSection _cs_opt = {0}; \
|
||||
_PyCriticalSection_XBegin(&_cs_opt, _PyObject_CAST(op))
|
||||
|
||||
# define Py_XEND_CRITICAL_SECTION() \
|
||||
_PyCriticalSection_XEnd(&_cs_opt); \
|
||||
}
|
||||
|
||||
# define Py_BEGIN_CRITICAL_SECTION2(a, b) \
|
||||
{ \
|
||||
_PyCriticalSection2 _cs2; \
|
||||
|
|
@ -131,6 +140,8 @@ extern "C" {
|
|||
// The critical section APIs are no-ops with the GIL.
|
||||
# define Py_BEGIN_CRITICAL_SECTION(op)
|
||||
# define Py_END_CRITICAL_SECTION()
|
||||
# define Py_XBEGIN_CRITICAL_SECTION(op)
|
||||
# define Py_XEND_CRITICAL_SECTION()
|
||||
# define Py_BEGIN_CRITICAL_SECTION2(a, b)
|
||||
# define Py_END_CRITICAL_SECTION2()
|
||||
# define _Py_CRITICAL_SECTION_ASSERT_MUTEX_LOCKED(mutex)
|
||||
|
|
@ -187,6 +198,16 @@ _PyCriticalSection_Begin(_PyCriticalSection *c, PyMutex *m)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection_XBegin(_PyCriticalSection *c, PyObject *op)
|
||||
{
|
||||
#ifdef Py_GIL_DISABLED
|
||||
if (op != NULL) {
|
||||
_PyCriticalSection_Begin(c, &_PyObject_CAST(op)->ob_mutex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Removes the top-most critical section from the thread's stack of critical
|
||||
// sections. If the new top-most critical section is inactive, then it is
|
||||
// resumed.
|
||||
|
|
@ -209,6 +230,14 @@ _PyCriticalSection_End(_PyCriticalSection *c)
|
|||
_PyCriticalSection_Pop(c);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection_XEnd(_PyCriticalSection *c)
|
||||
{
|
||||
if (c->mutex) {
|
||||
_PyCriticalSection_End(c);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection2_Begin(_PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2)
|
||||
{
|
||||
|
|
@ -264,7 +293,8 @@ _PyCriticalSection_SuspendAll(PyThreadState *tstate);
|
|||
#ifdef Py_GIL_DISABLED
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection_AssertHeld(PyMutex *mutex) {
|
||||
_PyCriticalSection_AssertHeld(PyMutex *mutex)
|
||||
{
|
||||
#ifdef Py_DEBUG
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
uintptr_t prev = tstate->critical_section;
|
||||
|
|
|
|||
|
|
@ -742,6 +742,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
|
|||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_abc_impl));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_abstract_));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_active));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_align_));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_annotation));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_anonymous_));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_argtypes_));
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ struct _Py_global_strings {
|
|||
STRUCT_FOR_ID(_abc_impl)
|
||||
STRUCT_FOR_ID(_abstract_)
|
||||
STRUCT_FOR_ID(_active)
|
||||
STRUCT_FOR_ID(_align_)
|
||||
STRUCT_FOR_ID(_annotation)
|
||||
STRUCT_FOR_ID(_anonymous_)
|
||||
STRUCT_FOR_ID(_argtypes_)
|
||||
|
|
|
|||
|
|
@ -251,6 +251,39 @@ PyAPI_FUNC(void) _PyRWMutex_RUnlock(_PyRWMutex *rwmutex);
|
|||
PyAPI_FUNC(void) _PyRWMutex_Lock(_PyRWMutex *rwmutex);
|
||||
PyAPI_FUNC(void) _PyRWMutex_Unlock(_PyRWMutex *rwmutex);
|
||||
|
||||
// Similar to linux seqlock: https://en.wikipedia.org/wiki/Seqlock
|
||||
// We use a sequence number to lock the writer, an even sequence means we're unlocked, an odd
|
||||
// sequence means we're locked. Readers will read the sequence before attempting to read the
|
||||
// underlying data and then read the sequence number again after reading the data. If the
|
||||
// sequence has not changed the data is valid.
|
||||
//
|
||||
// Differs a little bit in that we use CAS on sequence as the lock, instead of a seperate spin lock.
|
||||
// The writer can also detect that the undelering data has not changed and abandon the write
|
||||
// and restore the previous sequence.
|
||||
typedef struct {
|
||||
uint32_t sequence;
|
||||
} _PySeqLock;
|
||||
|
||||
// Lock the sequence lock for the writer
|
||||
PyAPI_FUNC(void) _PySeqLock_LockWrite(_PySeqLock *seqlock);
|
||||
|
||||
// Unlock the sequence lock and move to the next sequence number.
|
||||
PyAPI_FUNC(void) _PySeqLock_UnlockWrite(_PySeqLock *seqlock);
|
||||
|
||||
// Abandon the current update indicating that no mutations have occured
|
||||
// and restore the previous sequence value.
|
||||
PyAPI_FUNC(void) _PySeqLock_AbandonWrite(_PySeqLock *seqlock);
|
||||
|
||||
// Begin a read operation and return the current sequence number.
|
||||
PyAPI_FUNC(uint32_t) _PySeqLock_BeginRead(_PySeqLock *seqlock);
|
||||
|
||||
// End the read operation and confirm that the sequence number has not changed.
|
||||
// Returns 1 if the read was successful or 0 if the read should be re-tried.
|
||||
PyAPI_FUNC(uint32_t) _PySeqLock_EndRead(_PySeqLock *seqlock, uint32_t previous);
|
||||
|
||||
// Check if the lock was held during a fork and clear the lock. Returns 1
|
||||
// if the lock was held and any associated datat should be cleared.
|
||||
PyAPI_FUNC(uint32_t) _PySeqLock_AfterFork(_PySeqLock *seqlock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
1
Include/internal/pycore_runtime_init_generated.h
generated
1
Include/internal/pycore_runtime_init_generated.h
generated
|
|
@ -740,6 +740,7 @@ extern "C" {
|
|||
INIT_ID(_abc_impl), \
|
||||
INIT_ID(_abstract_), \
|
||||
INIT_ID(_active), \
|
||||
INIT_ID(_align_), \
|
||||
INIT_ID(_annotation), \
|
||||
INIT_ID(_anonymous_), \
|
||||
INIT_ID(_argtypes_), \
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#include "pycore_moduleobject.h" // PyModuleObject
|
||||
#include "pycore_lock.h" // PyMutex
|
||||
|
||||
|
||||
/* state */
|
||||
|
|
@ -21,6 +22,7 @@ struct _types_runtime_state {
|
|||
// bpo-42745: next_version_tag remains shared by all interpreters
|
||||
// because of static types.
|
||||
unsigned int next_version_tag;
|
||||
PyMutex type_mutex;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -28,6 +30,9 @@ struct _types_runtime_state {
|
|||
// see _PyType_Lookup().
|
||||
struct type_cache_entry {
|
||||
unsigned int version; // initialized from type->tp_version_tag
|
||||
#ifdef Py_GIL_DISABLED
|
||||
_PySeqLock sequence;
|
||||
#endif
|
||||
PyObject *name; // reference to exactly a str or None
|
||||
PyObject *value; // borrowed reference or NULL
|
||||
};
|
||||
|
|
@ -74,7 +79,7 @@ struct types_state {
|
|||
extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
|
||||
extern void _PyTypes_FiniTypes(PyInterpreterState *);
|
||||
extern void _PyTypes_Fini(PyInterpreterState *);
|
||||
|
||||
extern void _PyTypes_AfterFork(void);
|
||||
|
||||
/* other API */
|
||||
|
||||
|
|
|
|||
|
|
@ -534,6 +534,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
|
|||
string = &_Py_ID(_active);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
_PyUnicode_InternInPlace(interp, &string);
|
||||
string = &_Py_ID(_align_);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
_PyUnicode_InternInPlace(interp, &string);
|
||||
string = &_Py_ID(_annotation);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
_PyUnicode_InternInPlace(interp, &string);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue