Skip to content

Commit

Permalink
gh-112075: Make PyDictKeysObject thread-safe (#114741)
Browse files Browse the repository at this point in the history
Adds locking for shared PyDictKeysObject's for dictionaries
  • Loading branch information
DinoV authored Feb 21, 2024
1 parent 145bc2d commit 176df09
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 93 deletions.
6 changes: 6 additions & 0 deletions Include/cpython/pyatomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,9 @@ _Py_atomic_load_ptr_acquire(const void *obj);
static inline void
_Py_atomic_store_ptr_release(void *obj, void *value);

static inline void
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value);

static inline void
_Py_atomic_store_int_release(int *obj, int value);

Expand All @@ -484,6 +487,9 @@ _Py_atomic_load_uint64_acquire(const uint64_t *obj);
static inline uint32_t
_Py_atomic_load_uint32_acquire(const uint32_t *obj);

static inline Py_ssize_t
_Py_atomic_load_ssize_acquire(const Py_ssize_t *obj);


// --- _Py_atomic_fence ------------------------------------------------------

Expand Down
8 changes: 8 additions & 0 deletions Include/cpython/pyatomic_gcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,10 @@ static inline void
_Py_atomic_store_int_release(int *obj, int value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }

static inline void
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value)
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }

static inline int
_Py_atomic_load_int_acquire(const int *obj)
{ return __atomic_load_n(obj, __ATOMIC_ACQUIRE); }
Expand All @@ -516,6 +520,10 @@ static inline uint32_t
_Py_atomic_load_uint32_acquire(const uint32_t *obj)
{ return __atomic_load_n(obj, __ATOMIC_ACQUIRE); }

static inline Py_ssize_t
_Py_atomic_load_ssize_acquire(const Py_ssize_t *obj)
{ return __atomic_load_n(obj, __ATOMIC_ACQUIRE); }

// --- _Py_atomic_fence ------------------------------------------------------

static inline void
Expand Down
24 changes: 24 additions & 0 deletions Include/cpython/pyatomic_msc.h
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,18 @@ _Py_atomic_store_int_release(int *obj, int value)
#endif
}

static inline void
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value)
{
#if defined(_M_X64) || defined(_M_IX86)
*(Py_ssize_t volatile *)obj = value;
#elif defined(_M_ARM64)
__stlr64((unsigned __int64 volatile *)obj, (unsigned __int64)value);
#else
# error "no implementation of _Py_atomic_store_ssize_release"
#endif
}

static inline int
_Py_atomic_load_int_acquire(const int *obj)
{
Expand Down Expand Up @@ -990,6 +1002,18 @@ _Py_atomic_load_uint32_acquire(const uint32_t *obj)
#endif
}

static inline Py_ssize_t
_Py_atomic_load_ssize_acquire(const Py_ssize_t *obj)
{
#if defined(_M_X64) || defined(_M_IX86)
return *(Py_ssize_t volatile *)obj;
#elif defined(_M_ARM64)
return (Py_ssize_t)__ldar64((unsigned __int64 volatile *)obj);
#else
# error "no implementation of _Py_atomic_load_ssize_acquire"
#endif
}

// --- _Py_atomic_fence ------------------------------------------------------

static inline void
Expand Down
16 changes: 15 additions & 1 deletion Include/cpython/pyatomic_std.h
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,14 @@ _Py_atomic_store_int_release(int *obj, int value)
memory_order_release);
}

static inline void
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value)
{
_Py_USING_STD;
atomic_store_explicit((_Atomic(Py_ssize_t)*)obj, value,
memory_order_release);
}

static inline int
_Py_atomic_load_int_acquire(const int *obj)
{
Expand Down Expand Up @@ -908,7 +916,13 @@ _Py_atomic_load_uint32_acquire(const uint32_t *obj)
{
_Py_USING_STD;
return atomic_load_explicit((const _Atomic(uint32_t)*)obj,
memory_order_acquire);
}

static inline Py_ssize_t
_Py_atomic_load_ssize_acquire(const Py_ssize_t *obj)
{
_Py_USING_STD;
return atomic_load_explicit((const _Atomic(Py_ssize_t)*)obj,
}


Expand Down
6 changes: 6 additions & 0 deletions Include/internal/pycore_dict.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ struct _dictkeysobject {
/* Kind of keys */
uint8_t dk_kind;

#ifdef Py_GIL_DISABLED
/* Lock used to protect shared keys */
PyMutex dk_mutex;
#endif

/* Version number -- Reset to 0 by any modification to keys */
uint32_t dk_version;

Expand All @@ -145,6 +150,7 @@ struct _dictkeysobject {
/* Number of used entries in dk_entries. */
Py_ssize_t dk_nentries;


/* Actual hash table of dk_size entries. It holds indices in dk_entries,
or DKIX_EMPTY(-1) or DKIX_DUMMY(-2).
Expand Down
Loading

0 comments on commit 176df09

Please sign in to comment.