LCOV - code coverage report
Current view: top level - flamenco - fd_rwlock.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 53 57 93.0 %
Date: 2026-06-29 05:51:35 Functions: 52 1272 4.1 %

          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             : #include "../util/racesan/fd_racesan_target.h"
       9             : #include <stdatomic.h>
      10             : 
      11             : #define FD_RWLOCK_WRITE_LOCK ((ushort)0xFFFF)
      12             : 
      13             : struct FD_CAPABILITY("fd_rwlock") fd_rwlock {
      14             :   atomic_ushort value; /* 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        4989 : fd_rwlock_new( fd_rwlock_t * lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      23        4989 :   atomic_store_explicit( &lock->value, 0, memory_order_relaxed );
      24        4989 :   return lock;
      25        4989 : }
      26             : 
      27             : static inline void
      28       72432 : fd_rwlock_write( fd_rwlock_t * lock ) FD_ACQUIRE( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      29       72432 :   for(;;) {
      30       72432 :     ushort value = atomic_load_explicit( &lock->value, memory_order_relaxed );
      31       72432 :     fd_racesan_hook( "rwlock_write:pre_cas" );
      32       72432 :     if( FD_LIKELY( !value ) ) {
      33       72432 :       ushort expected = 0;
      34       72432 :       if( FD_LIKELY( atomic_compare_exchange_weak_explicit( &lock->value, &expected, FD_RWLOCK_WRITE_LOCK, memory_order_acquire, memory_order_relaxed ) ) ) {
      35       72432 :         fd_racesan_hook( "rwlock_write:post_acquire" );
      36       72432 :         return;
      37       72432 :       }
      38       72432 :     }
      39           0 :     FD_SPIN_PAUSE();
      40           0 :   }
      41       72432 : }
      42             : 
      43             : static inline void
      44       72327 : fd_rwlock_unwrite( fd_rwlock_t * lock ) FD_RELEASE( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      45       72327 :   fd_racesan_hook( "rwlock_unwrite:pre_release" );
      46       72327 :   atomic_store_explicit( &lock->value, 0, memory_order_release );
      47       72327 : }
      48             : 
      49             : static inline void
      50         111 : fd_rwlock_demote( fd_rwlock_t * lock ) FD_RELEASE( lock ) FD_ACQUIRE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      51         111 :   fd_racesan_hook( "rwlock_demote:pre_release" );
      52         111 :   atomic_store_explicit( &lock->value, 1, memory_order_release );
      53         111 : }
      54             : 
      55             : static inline void
      56        5424 : fd_rwlock_read( fd_rwlock_t * lock ) FD_ACQUIRE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      57        5424 :   for(;;) {
      58        5424 :     ushort value = atomic_load_explicit( &lock->value, memory_order_relaxed );
      59        5424 :     fd_racesan_hook( "rwlock_read:pre_cas" );
      60        5424 :     if( FD_LIKELY( value<0xFFFE ) ) {
      61        5424 :       ushort expected = value;
      62        5424 :       if( FD_LIKELY( atomic_compare_exchange_weak_explicit( &lock->value, &expected, (ushort)(value+1), memory_order_acquire, memory_order_relaxed ) ) ) {
      63        5424 :         fd_racesan_hook( "rwlock_read:post_acquire" );
      64        5424 :         return;
      65        5424 :       }
      66        5424 :     }
      67           0 :     FD_SPIN_PAUSE();
      68           0 :   }
      69        5424 : }
      70             : 
      71             : /* fd_rwlock_tryread attempts to acquire a shared read lock without
      72             :    spinning.  Returns 1 on success, 0 on failure (lock is write-held
      73             :    or contended). */
      74             : 
      75             : static inline int
      76          66 : fd_rwlock_tryread( fd_rwlock_t * lock ) FD_TRY_ACQUIRE_SHARED(1, lock) FD_NO_THREAD_SAFETY_ANALYSIS {
      77          66 :   ushort value = atomic_load_explicit( &lock->value, memory_order_relaxed );
      78          66 :   fd_racesan_hook( "rwlock_tryread:pre_cas" );
      79          66 :   if( FD_UNLIKELY( value>=0xFFFE ) ) return 0;
      80          63 :   ushort expected = value;
      81          63 :   if( FD_UNLIKELY( !atomic_compare_exchange_strong_explicit( &lock->value, &expected, (ushort)(value+1), memory_order_acquire, memory_order_relaxed ) ) ) return 0;
      82          63 :   return 1;
      83          63 : }
      84             : 
      85             : static inline int
      86         114 : fd_rwlock_trywrite( fd_rwlock_t * lock ) FD_TRY_ACQUIRE(1, lock) FD_NO_THREAD_SAFETY_ANALYSIS {
      87         114 :   fd_racesan_hook( "rwlock_trywrite:pre_cas" );
      88         114 :   ushort expected = 0;
      89         114 :   if( FD_UNLIKELY( !atomic_compare_exchange_strong_explicit( &lock->value, &expected, FD_RWLOCK_WRITE_LOCK, memory_order_acquire, memory_order_relaxed ) ) ) return 0;
      90         102 :   return 1;
      91         114 : }
      92             : 
      93             : static inline void
      94        8052 : fd_rwlock_unread( fd_rwlock_t * lock ) FD_RELEASE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      95        8052 :   fd_racesan_hook( "rwlock_unread:pre_release" );
      96             :   atomic_fetch_sub_explicit( &lock->value, 1, memory_order_release );
      97        8052 : }
      98             : 
      99             : #endif /* HEADER_fd_src_flamenco_fd_rwlock_h */

Generated by: LCOV version 1.14