LCOV - code coverage report
Current view: top level - flamenco - fd_rwlock.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 58 58 100.0 %
Date: 2026-09-17 04:28:31 Functions: 60 1488 4.0 %

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

Generated by: LCOV version 1.14