Update rw_spinlock impl to mirror github.com/pdimov's impl

This commit is contained in:
Christian Mazakas
2023-03-17 14:20:39 -07:00
parent 3df435d4d3
commit e4b32f7f5e

View File

@ -21,7 +21,11 @@ private:
// bit 31: locked exclusive // bit 31: locked exclusive
// bit 30: writer pending // bit 30: writer pending
// bit 29..: reader lock count // bit 29..0: reader lock count
static constexpr std::uint32_t locked_exclusive_mask = 1u << 31; // 0x8000'0000
static constexpr std::uint32_t writer_pending_mask = 1u << 30; // 0x4000'0000
static constexpr std::uint32_t reader_lock_count_mask = writer_pending_mask - 1; // 0x3FFF'FFFF
std::atomic<std::uint32_t> state_ = {}; std::atomic<std::uint32_t> state_ = {};
@ -36,7 +40,7 @@ public:
{ {
std::uint32_t st = state_.load( std::memory_order_relaxed ); std::uint32_t st = state_.load( std::memory_order_relaxed );
if( st >= 0x3FFF'FFFF ) if( st >= reader_lock_count_mask )
{ {
// either bit 31 set, bit 30 set, or reader count is max // either bit 31 set, bit 30 set, or reader count is max
return false; return false;
@ -54,7 +58,7 @@ public:
{ {
std::uint32_t st = state_.load( std::memory_order_relaxed ); std::uint32_t st = state_.load( std::memory_order_relaxed );
if( st < 0x3FFF'FFFF ) if( st < reader_lock_count_mask )
{ {
std::uint32_t newst = st + 1; std::uint32_t newst = st + 1;
if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return; if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return;
@ -81,19 +85,19 @@ public:
{ {
std::uint32_t st = state_.load( std::memory_order_relaxed ); std::uint32_t st = state_.load( std::memory_order_relaxed );
if( st & 0x8000'0000 ) if( st & locked_exclusive_mask )
{ {
// locked exclusive // locked exclusive
return false; return false;
} }
if( st & 0x3FFF'FFFF ) if( st & reader_lock_count_mask )
{ {
// locked shared // locked shared
return false; return false;
} }
std::uint32_t newst = 0x8000'0000; std::uint32_t newst = locked_exclusive_mask;
return state_.compare_exchange_strong( st, newst, std::memory_order_acquire, std::memory_order_relaxed ); return state_.compare_exchange_strong( st, newst, std::memory_order_acquire, std::memory_order_relaxed );
} }
@ -105,18 +109,18 @@ public:
{ {
std::uint32_t st = state_.load( std::memory_order_relaxed ); std::uint32_t st = state_.load( std::memory_order_relaxed );
if( st & 0x8000'0000 ) if( st & locked_exclusive_mask )
{ {
// locked exclusive, spin // locked exclusive, spin
} }
else if( ( st & 0x3FFF'FFFF ) == 0 ) else if( ( st & reader_lock_count_mask ) == 0 )
{ {
// not locked exclusive, not locked shared, try to lock // not locked exclusive, not locked shared, try to lock
std::uint32_t newst = 0x8000'0000; std::uint32_t newst = locked_exclusive_mask;
if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return; if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return;
} }
else if( st & 0x4000'000 ) else if( st & writer_pending_mask )
{ {
// writer pending bit already set, nothing to do // writer pending bit already set, nothing to do
} }
@ -124,7 +128,7 @@ public:
{ {
// locked shared, set writer pending bit // locked shared, set writer pending bit
std::uint32_t newst = st | 0x4000'0000; std::uint32_t newst = st | writer_pending_mask;
state_.compare_exchange_weak( st, newst, std::memory_order_relaxed, std::memory_order_relaxed ); state_.compare_exchange_weak( st, newst, std::memory_order_relaxed, std::memory_order_relaxed );
} }
@ -138,19 +142,19 @@ public:
for( ;; ) for( ;; )
{ {
if( st & 0x8000'0000 ) if( st & locked_exclusive_mask )
{ {
// locked exclusive, nothing to do // locked exclusive, nothing to do
break; break;
} }
else if( ( st & 0x3FFF'FFFF ) == 0 ) else if( ( st & reader_lock_count_mask ) == 0 )
{ {
// lock free, try to take it // lock free, try to take it
std::uint32_t newst = 0x8000'0000; std::uint32_t newst = locked_exclusive_mask;
if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return; if( state_.compare_exchange_weak( st, newst, std::memory_order_acquire, std::memory_order_relaxed ) ) return;
} }
else if( ( st & 0x4000'0000 ) == 0 ) else if( ( st & writer_pending_mask ) == 0 )
{ {
// writer pending bit already clear, nothing to do // writer pending bit already clear, nothing to do
break; break;
@ -159,7 +163,7 @@ public:
{ {
// clear writer pending bit // clear writer pending bit
std::uint32_t newst = st & ~0x4000'0000u; std::uint32_t newst = st & ~writer_pending_mask;
if( state_.compare_exchange_weak( st, newst, std::memory_order_relaxed, std::memory_order_relaxed ) ) break; if( state_.compare_exchange_weak( st, newst, std::memory_order_relaxed, std::memory_order_relaxed ) ) break;
} }
} }