diff options
author | Thomas Wouters <thomas@python.org> | 2024-02-15 20:53:06 (GMT) |
---|---|---|
committer | Thomas Wouters <thomas@python.org> | 2024-02-15 20:53:06 (GMT) |
commit | 26f23daa1ea30dea368f00c2131017cef2586adc (patch) | |
tree | 7baca7617b71747da914ebb655a6e00f46a56a00 /Python/lock.c | |
parent | c08c0679055d96c0397cf128bf7cc8134538b36a (diff) | |
parent | ae460d450ab854ca66d509ef6971cfe1b6312405 (diff) | |
download | cpython-26f23daa1ea30dea368f00c2131017cef2586adc.zip cpython-26f23daa1ea30dea368f00c2131017cef2586adc.tar.gz cpython-26f23daa1ea30dea368f00c2131017cef2586adc.tar.bz2 |
Merge branch 'main' of https://github.com/python/cpython
Diffstat (limited to 'Python/lock.c')
-rw-r--r-- | Python/lock.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/Python/lock.c b/Python/lock.c index f0ff117..bf01436 100644 --- a/Python/lock.c +++ b/Python/lock.c @@ -459,3 +459,74 @@ _PyRWMutex_Unlock(_PyRWMutex *rwmutex) _PyParkingLot_UnparkAll(&rwmutex->bits); } } + +#define SEQLOCK_IS_UPDATING(sequence) (sequence & 0x01) + +void _PySeqLock_LockWrite(_PySeqLock *seqlock) +{ + // lock the entry by setting by moving to an odd sequence number + uint32_t prev = _Py_atomic_load_uint32_relaxed(&seqlock->sequence); + while (1) { + if (SEQLOCK_IS_UPDATING(prev)) { + // Someone else is currently updating the cache + _Py_yield(); + prev = _Py_atomic_load_uint32_relaxed(&seqlock->sequence); + } + else if (_Py_atomic_compare_exchange_uint32(&seqlock->sequence, &prev, prev + 1)) { + // We've locked the cache + break; + } + else { + _Py_yield(); + } + } +} + +void _PySeqLock_AbandonWrite(_PySeqLock *seqlock) +{ + uint32_t new_seq = seqlock->sequence - 1; + assert(!SEQLOCK_IS_UPDATING(new_seq)); + _Py_atomic_store_uint32(&seqlock->sequence, new_seq); +} + +void _PySeqLock_UnlockWrite(_PySeqLock *seqlock) +{ + uint32_t new_seq = seqlock->sequence + 1; + assert(!SEQLOCK_IS_UPDATING(new_seq)); + _Py_atomic_store_uint32(&seqlock->sequence, new_seq); +} + +uint32_t _PySeqLock_BeginRead(_PySeqLock *seqlock) +{ + uint32_t sequence = _Py_atomic_load_uint32_acquire(&seqlock->sequence); + while (SEQLOCK_IS_UPDATING(sequence)) { + _Py_yield(); + sequence = _Py_atomic_load_uint32_acquire(&seqlock->sequence); + } + + return sequence; +} + +uint32_t _PySeqLock_EndRead(_PySeqLock *seqlock, uint32_t previous) +{ + // Synchronize again and validate that the entry hasn't been updated + // while we were readying the values. + if (_Py_atomic_load_uint32_acquire(&seqlock->sequence) == previous) { + return 1; + } + + _Py_yield(); + return 0; +} + +uint32_t _PySeqLock_AfterFork(_PySeqLock *seqlock) +{ + // Synchronize again and validate that the entry hasn't been updated + // while we were readying the values. + if (SEQLOCK_IS_UPDATING(seqlock->sequence)) { + seqlock->sequence = 0; + return 1; + } + + return 0; +} |