LCOV - code coverage report
Current view: top level - flamenco - fd_rwlock.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 55 72 76.4 %
Date: 2026-03-31 06:22:16 Functions: 41 1808 2.3 %

          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             : 
      10             : #define FD_RWLOCK_WRITE_LOCK ((ushort)0xFFFF)
      11             : 
      12             : struct FD_CAPABILITY("fd_rwlock") fd_rwlock {
      13             :   ushort value; /* Bits 0..16 are
      14             : 
      15             :                     0: Unlocked
      16             :                     1..=0xFFFE: Locked by N readers
      17             :                     0xFFFF: Write locked */
      18             : };
      19             : 
      20             : typedef struct fd_rwlock fd_rwlock_t;
      21             : 
      22             : static inline fd_rwlock_t *
      23      109629 : fd_rwlock_new( fd_rwlock_t * lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      24      109629 :   lock->value = 0;
      25      109629 :   return lock;
      26      109629 : }
      27             : 
      28             : static inline void
      29      576414 : fd_rwlock_write( fd_rwlock_t * lock ) FD_ACQUIRE( lock )  FD_NO_THREAD_SAFETY_ANALYSIS {
      30      576414 : # if FD_HAS_THREADS
      31      576414 :   for(;;) {
      32      576414 :     ushort value = lock->value;
      33      576414 :     fd_racesan_hook( "rwlock_write:pre_cas" );
      34      576414 :     if( FD_LIKELY( !value ) ) {
      35      576414 :       if( FD_LIKELY( FD_ATOMIC_CAS( &lock->value, 0, 0xFFFF )==0 ) ) {
      36      576414 :         FD_COMPILER_MFENCE();
      37      576414 :         fd_racesan_hook( "rwlock_write:post_acquire" );
      38      576414 :         return;
      39      576414 :       }
      40      576414 :     }
      41           0 :     FD_SPIN_PAUSE();
      42           0 :   }
      43             : # else
      44             :   lock->value = 0xFFFF;
      45             :   FD_COMPILER_MFENCE();
      46             : # endif
      47      576414 : }
      48             : 
      49             : static inline void
      50      576333 : fd_rwlock_unwrite( fd_rwlock_t * lock ) FD_RELEASE( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      51      576333 :   fd_racesan_hook( "rwlock_unwrite:pre_release" );
      52      576333 :   FD_COMPILER_MFENCE();
      53      576333 :   FD_VOLATILE( lock->value ) = 0;
      54      576333 : }
      55             : 
      56             : static inline void
      57          81 : fd_rwlock_demote( fd_rwlock_t * lock ) FD_RELEASE( lock ) FD_ACQUIRE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
      58          81 :   fd_racesan_hook( "rwlock_demote:pre_release" );
      59          81 :   FD_COMPILER_MFENCE();
      60          81 :   FD_VOLATILE( lock->value ) = 1;
      61          81 : }
      62             : 
      63             : static inline void
      64        1236 : fd_rwlock_read( fd_rwlock_t * lock ) FD_ACQUIRE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS  {
      65        1236 : # if FD_HAS_THREADS
      66        1236 :   for(;;) {
      67        1236 :     ushort value = lock->value;
      68        1236 :     fd_racesan_hook( "rwlock_read:pre_cas" );
      69        1236 :     if( FD_LIKELY( value<0xFFFE ) ) {
      70        1236 :       if( FD_LIKELY( FD_ATOMIC_CAS( &lock->value, value, value+1 )==value ) ) {
      71        1236 :         FD_COMPILER_MFENCE();
      72        1236 :         fd_racesan_hook( "rwlock_read:post_acquire" );
      73        1236 :         return;
      74        1236 :       }
      75        1236 :     }
      76           0 :     FD_SPIN_PAUSE();
      77           0 :   }
      78             : # else
      79             :   lock->value++;
      80             :   FD_COMPILER_MFENCE();
      81             : # endif
      82        1236 : }
      83             : 
      84             : /* fd_rwlock_tryread attempts to acquire a shared read lock without
      85             :    spinning.  Returns 1 on success, 0 on failure (lock is write-held
      86             :    or contended). */
      87             : 
      88             : static inline int
      89          54 : fd_rwlock_tryread( fd_rwlock_t * lock ) FD_TRY_ACQUIRE_SHARED(1, lock) FD_NO_THREAD_SAFETY_ANALYSIS {
      90          54 : # if FD_HAS_THREADS
      91          54 :   ushort value = lock->value;
      92          54 :   fd_racesan_hook( "rwlock_tryread:pre_cas" );
      93          54 :   if( FD_UNLIKELY( value>=0xFFFE ) ) return 0;
      94          54 :   if( FD_UNLIKELY( FD_ATOMIC_CAS( &lock->value, value, (ushort)(value+1) )!=value ) ) return 0;
      95          54 :   FD_COMPILER_MFENCE();
      96          54 :   return 1;
      97             : # else
      98             :   lock->value++;
      99             :   FD_COMPILER_MFENCE();
     100             :   return 1;
     101             : # endif
     102          54 : }
     103             : 
     104             : static inline int
     105           0 : fd_rwlock_trywrite( fd_rwlock_t * lock ) FD_TRY_ACQUIRE(1, lock) FD_NO_THREAD_SAFETY_ANALYSIS {
     106           0 : # if FD_HAS_THREADS
     107           0 :   fd_racesan_hook( "rwlock_trywrite:pre_cas" );
     108           0 :   if( FD_UNLIKELY( FD_ATOMIC_CAS( &lock->value, 0, FD_RWLOCK_WRITE_LOCK )!=0 ) ) return 0;
     109           0 :   FD_COMPILER_MFENCE();
     110           0 :   return 1;
     111           0 : # else
     112           0 :   if( FD_UNLIKELY( lock->value ) ) return 0;
     113           0 :   lock->value = FD_RWLOCK_WRITE_LOCK;
     114           0 :   FD_COMPILER_MFENCE();
     115           0 :   return 1;
     116           0 : # endif
     117           0 : }
     118             : 
     119             : static inline void
     120        1371 : fd_rwlock_unread( fd_rwlock_t * lock ) FD_RELEASE_SHARED( lock ) FD_NO_THREAD_SAFETY_ANALYSIS {
     121        1371 :   fd_racesan_hook( "rwlock_unread:pre_release" );
     122        1371 :   FD_COMPILER_MFENCE();
     123        1371 : # if FD_HAS_THREADS
     124        1371 :   FD_ATOMIC_FETCH_AND_SUB( &lock->value, 1 );
     125             : # else
     126             :   lock->value--;
     127             : # endif
     128        1371 : }
     129             : 
     130             : #endif /* HEADER_fd_src_flamenco_fd_rwlock_h */

Generated by: LCOV version 1.14