LCOV - code coverage report
Current view: top level - flamenco - fd_rwlock.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 55 59 93.2 %
Date: 2026-10-22 18:10:43 Functions: 25 1440 1.7 %

          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        2088 : #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       65361 : fd_rwlock_new( fd_rwlock_t * lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      23       65361 :   atomic_store_explicit( &lock->value, 0, memory_order_relaxed );
      24       65361 :   return lock;
      25       65361 : }
      26             : 
      27             : static inline void
      28      267338 : fd_rwlock_write( fd_rwlock_t * lock ) FD_ACQUIRE( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      29      267338 :   for(;;) {
      30      267333 :     ushort value = atomic_load_explicit( &lock->value, memory_order_relaxed );
      31      267333 :     fd_racesan_hook( "rwlock_write:pre_cas" );
      32      267336 :     if( FD_LIKELY( !value ) ) {
      33      267336 :       ushort expected = 0;
      34      267927 :       if( FD_LIKELY( atomic_compare_exchange_weak_explicit( &lock->value, &expected, FD_RWLOCK_WRITE_LOCK, memory_order_acquire, memory_order_relaxed ) ) ) {
      35      267927 :         fd_racesan_hook( "rwlock_write:post_acquire" );
      36      267927 :         return;
      37      267927 :       }
      38      267336 :     }
      39 >1844*10^16 :     FD_SPIN_PAUSE();
      40 >1844*10^16 :   }
      41      267338 : }
      42             : 
      43             : static inline void
      44      268043 : fd_rwlock_unwrite( fd_rwlock_t * lock ) FD_RELEASE( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      45      268043 :   fd_racesan_hook( "rwlock_unwrite:pre_release" );
      46      268043 :   atomic_store_explicit( &lock->value, 0, memory_order_release );
      47      268043 : }
      48             : 
      49             : static inline void
      50           0 : fd_rwlock_demote( fd_rwlock_t * lock ) FD_RELEASE( lock ) FD_ACQUIRE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      51           0 :   fd_racesan_hook( "rwlock_demote:pre_release" );
      52           0 :   atomic_store_explicit( &lock->value, 1, memory_order_release );
      53           0 : }
      54             : 
      55             : static inline void
      56       11330 : fd_rwlock_read( fd_rwlock_t * lock ) FD_ACQUIRE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      57       11330 :   for(;;) {
      58       11330 :     ushort value = atomic_load_explicit( &lock->value, memory_order_relaxed );
      59       11330 :     fd_racesan_hook( "rwlock_read:pre_cas" );
      60       11330 :     if( FD_LIKELY( value<0xFFFE ) ) {
      61       11330 :       ushort expected = value;
      62       11330 :       if( FD_LIKELY( atomic_compare_exchange_weak_explicit( &lock->value, &expected, (ushort)(value+1), memory_order_acquire, memory_order_relaxed ) ) ) {
      63       11327 :         fd_racesan_hook( "rwlock_read:post_acquire" );
      64       11327 :         return;
      65       11327 :       }
      66       11330 :     }
      67           3 :     FD_SPIN_PAUSE();
      68           3 :   }
      69       11330 : }
      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         113 : fd_rwlock_tryread( fd_rwlock_t * lock ) FD_TRY_ACQUIRE_SHARED(1, lock) FD_NO_THREAD_SAFETY_ANALYSIS {
      77         113 :   ushort value = atomic_load_explicit( &lock->value, memory_order_relaxed );
      78         113 :   fd_racesan_hook( "rwlock_tryread:pre_cas" );
      79         113 :   if( FD_UNLIKELY( value>=0xFFFE ) ) return 0;
      80         113 :   ushort expected = value;
      81         113 :   if( FD_UNLIKELY( !atomic_compare_exchange_strong_explicit( &lock->value, &expected, (ushort)(value+1), memory_order_acquire, memory_order_relaxed ) ) ) return 0;
      82         113 :   return 1;
      83         113 : }
      84             : 
      85             : static inline int
      86        4688 : fd_rwlock_trywrite( fd_rwlock_t * lock ) FD_TRY_ACQUIRE(1, lock) FD_NO_THREAD_SAFETY_ANALYSIS {
      87        4688 :   fd_racesan_hook( "rwlock_trywrite:pre_cas" );
      88        4688 :   ushort expected = 0;
      89        4688 :   if( FD_UNLIKELY( !atomic_compare_exchange_strong_explicit( &lock->value, &expected, FD_RWLOCK_WRITE_LOCK, memory_order_acquire, memory_order_relaxed ) ) ) return 0;
      90        4688 :   return 1;
      91        4688 : }
      92             : 
      93             : static inline void
      94       16127 : fd_rwlock_unread( fd_rwlock_t * lock ) FD_RELEASE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      95       16127 :   fd_racesan_hook( "rwlock_unread:pre_release" );
      96       16127 :   atomic_fetch_sub_explicit( &lock->value, 1, memory_order_release );
      97       16127 : }
      98             : 
      99             : #endif /* HEADER_fd_src_flamenco_fd_rwlock_h */

Generated by: LCOV version 1.14