Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_fd_rwlock_h 2 : #define HEADER_fd_src_flamenco_fd_rwlock_h 3 : 4 : /* A very simple read-write spin lock. */ 5 : 6 : #include "../util/fd_util_base.h" 7 : #include "../util/sanitize/fd_tsa.h" 8 : 9 : #define FD_RWLOCK_WRITE_LOCK ((ushort)0xFFFF) 10 : 11 : struct FD_CAPABILITY("fd_rwlock") fd_rwlock { 12 : ushort value; /* Bits 0..16 are 13 : 14 : 0: Unlocked 15 : 1..=0xFFFE: Locked by N readers 16 : 0xFFFF: Write locked */ 17 : }; 18 : 19 : typedef struct fd_rwlock fd_rwlock_t; 20 : 21 : static inline fd_rwlock_t * 22 110904 : fd_rwlock_new( fd_rwlock_t * lock ) FD_NO_THREAD_SAFETY_ANALYSIS { 23 110904 : lock->value = 0; 24 110904 : return lock; 25 110904 : } 26 : 27 : static inline void 28 87486 : fd_rwlock_write( fd_rwlock_t * lock ) FD_ACQUIRE( lock ) FD_NO_THREAD_SAFETY_ANALYSIS { 29 87486 : # if FD_HAS_THREADS 30 87486 : for(;;) { 31 87486 : ushort value = lock->value; 32 87486 : if( FD_LIKELY( !value ) ) { 33 87505 : if( FD_LIKELY( FD_ATOMIC_CAS( &lock->value, 0, 0xFFFF )==0 ) ) { 34 87505 : FD_COMPILER_MFENCE(); 35 87505 : return; 36 87505 : } 37 87483 : } 38 >1844*10^16 : FD_SPIN_PAUSE(); 39 >1844*10^16 : } 40 : # else 41 : lock->value = 0xFFFF; 42 : FD_COMPILER_MFENCE(); 43 : # endif 44 87486 : } 45 : 46 : static inline void 47 116247 : fd_rwlock_unwrite( fd_rwlock_t * lock ) FD_RELEASE( lock ) FD_NO_THREAD_SAFETY_ANALYSIS { 48 116247 : FD_COMPILER_MFENCE(); 49 116247 : FD_VOLATILE( lock->value ) = 0; 50 116247 : } 51 : 52 : static inline void 53 1404 : fd_rwlock_demote( fd_rwlock_t * lock ) FD_RELEASE( lock ) FD_ACQUIRE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS { 54 1404 : FD_COMPILER_MFENCE(); 55 1404 : FD_VOLATILE( lock->value ) = 1; 56 1404 : } 57 : 58 : static inline void 59 47412 : fd_rwlock_read( fd_rwlock_t * lock ) FD_ACQUIRE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS { 60 47412 : # if FD_HAS_THREADS 61 47412 : for(;;) { 62 47411 : ushort value = lock->value; 63 47412 : if( FD_LIKELY( value<0xFFFE ) ) { 64 47425 : if( FD_LIKELY( FD_ATOMIC_CAS( &lock->value, value, value+1 )==value ) ) { 65 47425 : FD_COMPILER_MFENCE(); 66 47425 : return; 67 47425 : } 68 47412 : } 69 >1844*10^16 : FD_SPIN_PAUSE(); 70 >1844*10^16 : } 71 : # else 72 : lock->value++; 73 : FD_COMPILER_MFENCE(); 74 : # endif 75 47412 : } 76 : 77 : /* fd_rwlock_tryread attempts to acquire a shared read lock without 78 : spinning. Returns 1 on success, 0 on failure (lock is write-held 79 : or contended). */ 80 : 81 : static inline int 82 5400 : fd_rwlock_tryread( fd_rwlock_t * lock ) FD_TRY_ACQUIRE_SHARED(1, lock) FD_NO_THREAD_SAFETY_ANALYSIS { 83 5400 : # if FD_HAS_THREADS 84 5400 : ushort value = lock->value; 85 5400 : if( FD_UNLIKELY( value>=0xFFFE ) ) return 0; 86 5400 : if( FD_UNLIKELY( FD_ATOMIC_CAS( &lock->value, value, (ushort)(value+1) )!=value ) ) return 0; 87 5400 : FD_COMPILER_MFENCE(); 88 5400 : return 1; 89 : # else 90 : lock->value++; 91 : FD_COMPILER_MFENCE(); 92 : return 1; 93 : # endif 94 5400 : } 95 : 96 : static inline int 97 0 : fd_rwlock_trywrite( fd_rwlock_t * lock ) FD_TRY_ACQUIRE(1, lock) FD_NO_THREAD_SAFETY_ANALYSIS { 98 0 : # if FD_HAS_THREADS 99 0 : if( FD_UNLIKELY( FD_ATOMIC_CAS( &lock->value, 0, FD_RWLOCK_WRITE_LOCK )!=0 ) ) return 0; 100 0 : FD_COMPILER_MFENCE(); 101 0 : return 1; 102 : # else 103 : if( FD_UNLIKELY( lock->value ) ) return 0; 104 : lock->value = FD_RWLOCK_WRITE_LOCK; 105 : FD_COMPILER_MFENCE(); 106 : return 1; 107 : # endif 108 0 : } 109 : 110 : static inline void 111 54185 : fd_rwlock_unread( fd_rwlock_t * lock ) FD_RELEASE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS { 112 54185 : FD_COMPILER_MFENCE(); 113 54185 : # if FD_HAS_THREADS 114 54185 : FD_ATOMIC_FETCH_AND_SUB( &lock->value, 1 ); 115 : # else 116 : lock->value--; 117 : # endif 118 54185 : } 119 : 120 : #endif /* HEADER_fd_src_flamenco_fd_rwlock_h */