Line data Source code
1 : #ifndef HEADER_fd_src_disco_wait_info_fd_wait_info_h 2 : #define HEADER_fd_src_disco_wait_info_fd_wait_info_h 3 : 4 : /* fd_wait_info provides a shared topology object that holds the data 5 : the `wait` command needs to determine a safe restart window. 6 : 7 : Expects a single producer and one or more consumers. Readers never 8 : block: they retry against a sequence (seq) counter the writer 9 : increments before and after each update. 10 : 11 : The sequence uses FD_VOLATILE + FD_COMPILER_MFENCE rather than C11 12 : atomics. This is sufficient on x86-64 (TSO): stores are globally 13 : visible in program order, so compiler fences alone provide the 14 : acquire/release semantics the sequence requires. Single producer 15 : means no CAS is needed on the write side. */ 16 : 17 : #include "../../util/log/fd_log.h" 18 : 19 21 : #define FD_WAIT_INFO_MAGIC (0xf17eda2c57490000UL) /* firedancer wait_info (wi) ver 0 */ 20 : 21 : struct fd_wait_info { 22 : /* Health */ 23 : int caught_up; 24 : 25 : /* Leader gap */ 26 : ulong reset_slot; 27 : ulong tip_slot; /* highest slot seen from the cluster, 0 if unknown */ 28 : ulong leader_highwater_slot; /* highest slot led, 0 if none */ 29 : int next_leader_known; /* 0: leader schedule unavailable */ 30 : ulong next_leader_slot; /* 0: no upcoming leader slots */ 31 : ulong leader_slot; /* non-zero when actively leading */ 32 : ulong epoch_end_slot; 33 : ulong slots_per_epoch; 34 : ulong ns_per_slot; 35 : 36 : /* Delinquent stake, derived from the block footer reward certs. 37 : 0 until the first real figure is computed. */ 38 : int delinquent_known; 39 : ulong delinquent_stake_lamports; 40 : ulong cluster_active_stake_lamports; 41 : 42 : /* Snapshot status */ 43 : int snap_active; /* 1 while snapmk tile is writing */ 44 : ulong snap_finished_full; 45 : ulong snap_finished_incr; 46 : ulong snap_full_interval_blocks; /* 0: periodic fulls disabled */ 47 : ulong snap_incr_interval_blocks; /* 0: periodic incrementals disabled */ 48 : ulong snap_produced_incr_cnt; /* incrementals produced, never found */ 49 : }; 50 : 51 : typedef struct fd_wait_info fd_wait_info_t; 52 : 53 : struct fd_wait_info_box { 54 : ulong magic; /* ==FD_WAIT_INFO_MAGIC */ 55 : ulong seq; /* lsb==1 implies active write */ 56 : fd_wait_info_t info; 57 : }; 58 : 59 : typedef struct fd_wait_info_box fd_wait_info_box_t; 60 : 61 : FD_PROTOTYPES_BEGIN 62 : 63 : static inline void * 64 24 : fd_wait_info_box_new( void * shmem ) { 65 24 : fd_wait_info_box_t * wi = (fd_wait_info_box_t *)shmem; 66 24 : if( FD_UNLIKELY( !wi ) ) { 67 3 : FD_LOG_WARNING(( "NULL shmem" )); 68 3 : return NULL; 69 3 : } 70 21 : fd_memset( wi, 0, sizeof(fd_wait_info_box_t) ); 71 21 : FD_VOLATILE( wi->magic ) = FD_WAIT_INFO_MAGIC; 72 21 : return (void *)wi; 73 24 : } 74 : 75 : static inline fd_wait_info_box_t * 76 27 : fd_wait_info_box_join( void * shwi ) { 77 27 : if( FD_UNLIKELY( !shwi ) ) { 78 3 : FD_LOG_WARNING(( "NULL shwi" )); 79 3 : return NULL; 80 3 : } 81 24 : fd_wait_info_box_t * wi = (fd_wait_info_box_t *)shwi; 82 24 : if( FD_UNLIKELY( wi->magic!=FD_WAIT_INFO_MAGIC ) ) { 83 3 : FD_LOG_WARNING(( "bad magic" )); 84 3 : return NULL; 85 3 : } 86 21 : return wi; 87 24 : } 88 : 89 : /* fd_wait_info_seq reads the sequence counter. */ 90 : 91 : static inline ulong 92 6479197 : fd_wait_info_seq( fd_wait_info_box_t const * src ) { 93 6479197 : FD_COMPILER_MFENCE(); 94 6479197 : ulong seq = FD_VOLATILE_CONST( src->seq ); 95 6479197 : FD_COMPILER_MFENCE(); 96 6479197 : return seq; 97 6479197 : } 98 : 99 : /* fd_wait_info_try_read attempts a single consistent read. 100 : Returns dst on success, NULL if a write was in progress. */ 101 : 102 : static inline fd_wait_info_t * 103 : fd_wait_info_try_read( fd_wait_info_t * dst, 104 3000014 : fd_wait_info_box_t const * src ) { 105 3000014 : ulong seq0 = fd_wait_info_seq( src ); 106 3000014 : if( FD_UNLIKELY( seq0 & 1UL ) ) return NULL; 107 3000011 : memcpy( dst, &src->info, sizeof(fd_wait_info_t) ); 108 3000011 : ulong seq1 = fd_wait_info_seq( src ); 109 3000011 : if( FD_LIKELY( seq0==seq1 ) ) return dst; 110 2 : return NULL; 111 3000011 : } 112 : 113 : static inline void 114 12200 : fd_wait_info_write_begin( fd_wait_info_box_t * dst ) { 115 12200 : FD_COMPILER_MFENCE(); 116 12200 : FD_VOLATILE( dst->seq ) = dst->seq + 1UL; 117 12200 : FD_COMPILER_MFENCE(); 118 12200 : } 119 : 120 : static inline void 121 12200 : fd_wait_info_write_end( fd_wait_info_box_t * dst ) { 122 12200 : FD_COMPILER_MFENCE(); 123 12200 : FD_VOLATILE( dst->seq ) = dst->seq + 1UL; 124 12200 : FD_COMPILER_MFENCE(); 125 12200 : } 126 : 127 : FD_PROTOTYPES_END 128 : 129 : #endif /* HEADER_fd_src_disco_wait_info_fd_wait_info_h */