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 0 : #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. Tower derives it from vote account 37 : last_vote_slot; Alpenglow from the block footer reward certs. 38 : 0 until the first real figure is computed. */ 39 : int delinquent_known; 40 : ulong delinquent_stake_lamports; 41 : ulong cluster_active_stake_lamports; 42 : 43 : /* Snapshot status */ 44 : int snap_active; /* 1 while snapmk tile is writing */ 45 : ulong snap_finished_full; 46 : ulong snap_finished_incr; 47 : ulong snap_full_interval_blocks; /* 0: periodic fulls disabled */ 48 : ulong snap_incr_interval_blocks; /* 0: periodic incrementals disabled */ 49 : ulong snap_produced_incr_cnt; /* incrementals produced, never found */ 50 : }; 51 : 52 : typedef struct fd_wait_info fd_wait_info_t; 53 : 54 : struct fd_wait_info_box { 55 : ulong magic; /* ==FD_WAIT_INFO_MAGIC */ 56 : ulong seq; /* lsb==1 implies active write */ 57 : fd_wait_info_t info; 58 : }; 59 : 60 : typedef struct fd_wait_info_box fd_wait_info_box_t; 61 : 62 : FD_PROTOTYPES_BEGIN 63 : 64 : static inline void * 65 0 : fd_wait_info_box_new( void * shmem ) { 66 0 : fd_wait_info_box_t * wi = (fd_wait_info_box_t *)shmem; 67 0 : if( FD_UNLIKELY( !wi ) ) { 68 0 : FD_LOG_WARNING(( "NULL shmem" )); 69 0 : return NULL; 70 0 : } 71 0 : fd_memset( wi, 0, sizeof(fd_wait_info_box_t) ); 72 0 : FD_VOLATILE( wi->magic ) = FD_WAIT_INFO_MAGIC; 73 0 : return (void *)wi; 74 0 : } 75 : 76 : static inline fd_wait_info_box_t * 77 0 : fd_wait_info_box_join( void * shwi ) { 78 0 : if( FD_UNLIKELY( !shwi ) ) { 79 0 : FD_LOG_WARNING(( "NULL shwi" )); 80 0 : return NULL; 81 0 : } 82 0 : fd_wait_info_box_t * wi = (fd_wait_info_box_t *)shwi; 83 0 : if( FD_UNLIKELY( wi->magic!=FD_WAIT_INFO_MAGIC ) ) { 84 0 : FD_LOG_WARNING(( "bad magic" )); 85 0 : return NULL; 86 0 : } 87 0 : return wi; 88 0 : } 89 : 90 : /* fd_wait_info_seq reads the sequence counter. */ 91 : 92 : static inline ulong 93 0 : fd_wait_info_seq( fd_wait_info_box_t const * src ) { 94 0 : FD_COMPILER_MFENCE(); 95 0 : ulong seq = FD_VOLATILE_CONST( src->seq ); 96 0 : FD_COMPILER_MFENCE(); 97 0 : return seq; 98 0 : } 99 : 100 : /* fd_wait_info_try_read attempts a single consistent read. 101 : Returns dst on success, NULL if a write was in progress. */ 102 : 103 : static inline fd_wait_info_t * 104 : fd_wait_info_try_read( fd_wait_info_t * dst, 105 0 : fd_wait_info_box_t const * src ) { 106 0 : ulong seq0 = fd_wait_info_seq( src ); 107 0 : if( FD_UNLIKELY( seq0 & 1UL ) ) return NULL; 108 0 : memcpy( dst, &src->info, sizeof(fd_wait_info_t) ); 109 0 : ulong seq1 = fd_wait_info_seq( src ); 110 0 : if( FD_LIKELY( seq0==seq1 ) ) return dst; 111 0 : return NULL; 112 0 : } 113 : 114 : static inline void 115 0 : fd_wait_info_write_begin( fd_wait_info_box_t * dst ) { 116 0 : FD_COMPILER_MFENCE(); 117 0 : FD_VOLATILE( dst->seq ) = dst->seq + 1UL; 118 0 : FD_COMPILER_MFENCE(); 119 0 : } 120 : 121 : static inline void 122 0 : fd_wait_info_write_end( fd_wait_info_box_t * dst ) { 123 0 : FD_COMPILER_MFENCE(); 124 0 : FD_VOLATILE( dst->seq ) = dst->seq + 1UL; 125 0 : FD_COMPILER_MFENCE(); 126 0 : } 127 : 128 : FD_PROTOTYPES_END 129 : 130 : #endif /* HEADER_fd_src_disco_wait_info_fd_wait_info_h */