summaryrefslogtreecommitdiffstats
path: root/Python/lock.c
diff options
context:
space:
mode:
authorThomas Wouters <thomas@python.org>2024-02-15 20:53:06 (GMT)
committerThomas Wouters <thomas@python.org>2024-02-15 20:53:06 (GMT)
commit26f23daa1ea30dea368f00c2131017cef2586adc (patch)
tree7baca7617b71747da914ebb655a6e00f46a56a00 /Python/lock.c
parentc08c0679055d96c0397cf128bf7cc8134538b36a (diff)
parentae460d450ab854ca66d509ef6971cfe1b6312405 (diff)
downloadcpython-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.c71
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;
+}