Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_fd_borrowed_account_h 2 : #define HEADER_fd_src_flamenco_runtime_fd_borrowed_account_h 3 : 4 : #include "../../ballet/txn/fd_txn.h" 5 : #include "../types/fd_types.h" 6 : #include "../../funk/fd_funk_rec.h" 7 : 8 : /* TODO This should be called fd_txn_acct. */ 9 : 10 : struct __attribute__((aligned(8UL))) fd_borrowed_account { 11 : ulong magic; 12 : 13 : fd_pubkey_t pubkey[1]; 14 : 15 : fd_account_meta_t const * const_meta; 16 : uchar const * const_data; 17 : fd_funk_rec_t const * const_rec; 18 : 19 : fd_account_meta_t * meta; 20 : uchar * data; 21 : fd_funk_rec_t * rec; 22 : 23 : fd_account_meta_t const * orig_meta; 24 : uchar const * orig_data; 25 : fd_funk_rec_t const * orig_rec; 26 : 27 : ulong starting_dlen; 28 : ulong starting_lamports; 29 : 30 : ulong starting_owner_dlen; 31 : 32 : /* Provide read/write mutual exclusion semantics. 33 : Used for single-threaded logic only, thus not comparable to a 34 : data synchronization lock. */ 35 : 36 : ushort refcnt_excl; 37 : ushort refcnt_shared; 38 : }; 39 : typedef struct fd_borrowed_account fd_borrowed_account_t; 40 4928817 : #define FD_BORROWED_ACCOUNT_FOOTPRINT (sizeof(fd_borrowed_account_t)) 41 : #define FD_BORROWED_ACCOUNT_ALIGN (8UL) 42 6535815 : #define FD_BORROWED_ACCOUNT_MAGIC (0xF15EDF1C51F51AA1UL) 43 : 44 3736509 : #define FD_BORROWED_ACCOUNT_DECL(_x) fd_borrowed_account_t _x[1]; fd_borrowed_account_init(_x); 45 : 46 : /* This macro provides the same scoping guarantees as the Agave client's 47 : borrowed account semantics. It allows for implict/explicit dropping of 48 : borrowed accounts' write locks. It's usage mirrors the use of 49 : FD_SCRATCH_SCOPE_{BEGIN,END}. It is also safe to use the original 50 : acquire/release api within the scoped macro in case you don't want 51 : variables to go out of scope. An example of this is in the extend 52 : instruction within the bpf loader. 53 : Equivalent to Agave's instruction_context::try_borrow_instruction_account() 54 : https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L647 */ 55 : 56 61761 : #define FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( _ctx, _idx, _account ) do { \ 57 61761 : if( FD_UNLIKELY( _idx>=(_ctx)->instr->acct_cnt ) ) { \ 58 273 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; \ 59 273 : } \ 60 61761 : fd_borrowed_account_t * _account = NULL; \ 61 61488 : int _err = fd_instr_borrowed_account_view_idx( _ctx, _idx, &_account ); \ 62 61488 : if( FD_UNLIKELY( _err != FD_ACC_MGR_SUCCESS ) ) { \ 63 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; \ 64 0 : } \ 65 61488 : int _acquire_result = fd_borrowed_account_acquire_write(_account); \ 66 61488 : if( FD_UNLIKELY( !_acquire_result ) ) { \ 67 237 : return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED; \ 68 237 : } \ 69 61488 : fd_borrowed_account_t * __fd_borrowed_lock_guard_ ## __LINE__ \ 70 61251 : __attribute__((cleanup(fd_borrowed_account_release_write_private))) \ 71 61251 : __attribute__((unused)) = _account; \ 72 61251 : do 73 61251 : #define FD_BORROWED_ACCOUNT_DROP( _account_check ) while(0); (void)_account_check; } while(0) 74 : 75 : FD_PROTOTYPES_BEGIN 76 : 77 : fd_borrowed_account_t * 78 : fd_borrowed_account_init( void * ptr ); 79 : 80 : void 81 : fd_borrowed_account_resize( fd_borrowed_account_t * borrowed_account, 82 : ulong dlen ); 83 : 84 : FD_FN_PURE static inline ulong 85 0 : fd_borrowed_account_raw_size( fd_borrowed_account_t const * borrowed_account ) { 86 0 : ulong dlen = ( borrowed_account->const_meta != NULL ) ? borrowed_account->const_meta->dlen : 0; 87 0 : return sizeof(fd_account_meta_t) + dlen; 88 0 : } 89 : 90 : fd_borrowed_account_t * 91 : fd_borrowed_account_make_modifiable( fd_borrowed_account_t * borrowed_account, 92 : void * buf ); 93 : 94 : void * 95 : fd_borrowed_account_restore( fd_borrowed_account_t * borrowed_account ); 96 : 97 : void * 98 : fd_borrowed_account_destroy( fd_borrowed_account_t * borrowed_account ); 99 : 100 : /* fd_borrowed_account_acquire_{read,write}_is_safe returns 1 if 101 : fd_borrowed_account_acquire_{read,write} will be successful for the 102 : given borrowed account. If a lock is already held, returns 0. */ 103 : 104 : FD_FN_PURE static inline int 105 135999 : fd_borrowed_account_acquire_write_is_safe( fd_borrowed_account_t const * rw ) { 106 135999 : return (!rw->refcnt_excl) & (!rw->refcnt_shared); 107 135999 : } 108 : 109 : FD_FN_PURE static inline int 110 1920 : fd_borrowed_account_acquire_read_is_safe( fd_borrowed_account_t const * rw ) { 111 1920 : return (!rw->refcnt_excl); 112 1920 : } 113 : 114 : /* fd_borrowed_account_acquire_write acquires write/exclusive access. 115 : Causes all other write or read acquire attempts will fail. Returns 1 116 : on success, 0 on failure. */ 117 : 118 : static inline int 119 74748 : fd_borrowed_account_acquire_write( fd_borrowed_account_t * rw ) { 120 74748 : if( FD_UNLIKELY( !fd_borrowed_account_acquire_write_is_safe( rw ) ) ) { 121 237 : return 0; 122 237 : } 123 74511 : rw->refcnt_excl = (ushort)1; 124 74511 : return 1; 125 74748 : } 126 : 127 : /* fd_borrowed_account_release_write{_private} releases a write/exclusive 128 : access handle. The private version should only be used by the try borrow 129 : scoping macro. */ 130 : 131 : static inline void 132 71973 : fd_borrowed_account_release_write( fd_borrowed_account_t * rw ) { 133 71973 : FD_TEST( rw->refcnt_excl==1U ); 134 71973 : rw->refcnt_excl = (ushort)0; 135 71973 : } 136 : 137 : static inline void 138 61251 : fd_borrowed_account_release_write_private(fd_borrowed_account_t ** rw ) { 139 : /* Only release if it is not yet released */ 140 61251 : if( !fd_borrowed_account_acquire_write_is_safe( *rw ) ) { 141 61185 : fd_borrowed_account_release_write( *rw ); 142 61185 : } 143 61251 : rw = NULL; 144 61251 : } 145 : 146 : /* fd_borrowed_account_acquire_read acquires read/shared access. Causes 147 : write attempts to fail. Further attempts to read will succeed. */ 148 : 149 : static inline int 150 1920 : fd_borrowed_account_acquire_read( fd_borrowed_account_t * rw ) { 151 1920 : if( FD_UNLIKELY( !fd_borrowed_account_acquire_read_is_safe( rw ) ) ) 152 0 : return 0; 153 1920 : rw->refcnt_shared = (ushort)( rw->refcnt_shared + 1U ); 154 1920 : return 1; 155 1920 : } 156 : 157 : /* fd_borrowed_account_release_read releases a read/shared access 158 : handle. */ 159 : 160 : static inline void 161 546 : fd_borrowed_account_release_read( fd_borrowed_account_t * rw ) { 162 546 : FD_TEST( rw->refcnt_shared>0U ); 163 546 : rw->refcnt_shared--; 164 546 : } 165 : 166 : FD_PROTOTYPES_END 167 : 168 : #endif /* HEADER_fd_src_flamenco_runtime_fd_borrowed_account_h */