Line data Source code
1 : #include "fd_dcache_private.h" 2 : 3 : ulong 4 : fd_dcache_req_data_sz( ulong mtu, 5 : ulong depth, 6 : ulong burst, 7 3000087 : int compact ) { 8 : 9 3000087 : if( FD_UNLIKELY( !mtu ) ) return 0UL; /* zero mtu (technically unnecessary) */ 10 2953977 : if( FD_UNLIKELY( !depth ) ) return 0UL; /* zero depth */ 11 2908773 : if( FD_UNLIKELY( !burst ) ) return 0UL; /* zero burst */ 12 : 13 2863176 : ulong slot_footprint = FD_DCACHE_SLOT_FOOTPRINT( mtu ); 14 2863176 : if( FD_UNLIKELY( !slot_footprint ) ) return 0UL; /* overflow */ 15 : 16 2863176 : ulong slot_cnt = depth + burst; 17 2863176 : if( FD_UNLIKELY( slot_cnt<depth ) ) return 0UL; /* overflow */ 18 2863176 : slot_cnt += (ulong)!!compact; 19 2863176 : if( FD_UNLIKELY( !slot_cnt ) ) return 0UL; /* overflow (technically unnecessary) */ 20 2863176 : if( FD_UNLIKELY( slot_cnt>(ULONG_MAX/slot_footprint) ) ) return 0UL; /* overflow */ 21 : 22 2863176 : return slot_footprint*slot_cnt; 23 2863176 : } 24 : 25 : ulong 26 93 : fd_dcache_align( void ) { 27 93 : return FD_DCACHE_ALIGN; 28 93 : } 29 : 30 : ulong 31 : fd_dcache_footprint( ulong data_sz, 32 3000114 : ulong app_sz ) { 33 : 34 3000114 : ulong data_footprint = fd_ulong_align_up( data_sz, FD_DCACHE_ALIGN ); 35 3000114 : if( FD_UNLIKELY( data_footprint<data_sz ) ) return 0UL; /* overflow */ 36 : 37 3000111 : ulong app_footprint = fd_ulong_align_up( app_sz, FD_DCACHE_ALIGN ); 38 3000111 : if( FD_UNLIKELY( app_footprint<app_sz ) ) return 0UL; /* overflow */ 39 : 40 3000108 : ulong footprint = data_footprint + app_footprint; /* data and app */ 41 3000108 : if( FD_UNLIKELY( footprint<data_footprint ) ) return 0UL; /* overflow */ 42 : 43 3000108 : footprint += sizeof(fd_dcache_private_hdr_t); /* header and guard */ 44 3000108 : if( FD_UNLIKELY( footprint<sizeof(fd_dcache_private_hdr_t) ) ) return 0UL; /* overflow */ 45 : 46 3000108 : return footprint; 47 3000108 : } 48 : 49 : void * 50 : fd_dcache_new( void * shmem, 51 : ulong data_sz, 52 30 : ulong app_sz ) { 53 : 54 30 : if( FD_UNLIKELY( !shmem ) ) { 55 3 : FD_LOG_WARNING(( "NULL shmem" )); 56 3 : return NULL; 57 3 : } 58 : 59 27 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_dcache_align() ) ) ) { 60 3 : FD_LOG_WARNING(( "misaligned shmem" )); 61 3 : return NULL; 62 3 : } 63 : 64 24 : ulong footprint = fd_dcache_footprint( data_sz, app_sz ); 65 24 : if( FD_UNLIKELY( !footprint ) ) { 66 6 : FD_LOG_WARNING(( "bad data_sz (%lu) or app_sz (%lu)", data_sz, app_sz )); 67 6 : return NULL; 68 6 : } 69 : 70 18 : fd_memset( shmem, 0, sizeof(fd_dcache_private_hdr_t ) ); 71 : 72 18 : fd_dcache_private_hdr_t * hdr = (fd_dcache_private_hdr_t *)shmem; 73 : 74 18 : hdr->data_sz = data_sz; 75 18 : hdr->app_sz = app_sz; 76 18 : hdr->app_off = sizeof(fd_dcache_private_hdr_t) + fd_ulong_align_up( data_sz, FD_DCACHE_ALIGN ); 77 : 78 18 : fd_memset( (uchar*)shmem+hdr->app_off, 0, app_sz ); 79 : 80 18 : FD_COMPILER_MFENCE(); 81 18 : FD_VOLATILE( hdr->magic ) = FD_DCACHE_MAGIC; 82 18 : FD_COMPILER_MFENCE(); 83 : 84 18 : return shmem; 85 24 : } 86 : 87 : uchar * 88 81 : fd_dcache_join( void * shdcache ) { 89 : 90 81 : if( FD_UNLIKELY( !shdcache ) ) { 91 3 : FD_LOG_WARNING(( "NULL shdcache" )); 92 3 : return NULL; 93 3 : } 94 : 95 78 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shdcache, fd_dcache_align() ) ) ) { 96 3 : FD_LOG_WARNING(( "misaligned shdcache" )); 97 3 : return NULL; 98 3 : } 99 : 100 75 : fd_dcache_private_hdr_t * hdr = (fd_dcache_private_hdr_t *)shdcache; 101 75 : if( FD_UNLIKELY( hdr->magic!=FD_DCACHE_MAGIC ) ) { 102 0 : FD_LOG_WARNING(( "bad magic" )); 103 0 : return NULL; 104 0 : } 105 : 106 75 : return fd_dcache_private_dcache( hdr ); 107 75 : } 108 : 109 : void * 110 78 : fd_dcache_leave( uchar const * dcache ) { 111 : 112 78 : if( FD_UNLIKELY( !dcache ) ) { 113 3 : FD_LOG_WARNING(( "NULL dcache" )); 114 3 : return NULL; 115 3 : } 116 : 117 75 : return (void *)fd_dcache_private_hdr_const( dcache ); /* Kinda ugly const cast */ 118 78 : } 119 : 120 : void * 121 21 : fd_dcache_delete( void * shdcache ) { 122 : 123 21 : if( FD_UNLIKELY( !shdcache ) ) { 124 3 : FD_LOG_WARNING(( "NULL shdcache" )); 125 3 : return NULL; 126 3 : } 127 : 128 18 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shdcache, fd_dcache_align() ) ) ) { 129 3 : FD_LOG_WARNING(( "misaligned shdcache" )); 130 3 : return NULL; 131 3 : } 132 : 133 15 : fd_dcache_private_hdr_t * hdr = (fd_dcache_private_hdr_t *)shdcache; 134 15 : if( FD_UNLIKELY( hdr->magic != FD_DCACHE_MAGIC ) ) { 135 0 : FD_LOG_WARNING(( "bad magic" )); 136 0 : return NULL; 137 0 : } 138 : 139 15 : FD_COMPILER_MFENCE(); 140 15 : FD_VOLATILE( hdr->magic ) = 0UL; 141 15 : FD_COMPILER_MFENCE(); 142 : 143 15 : return shdcache; 144 15 : } 145 : 146 : ulong 147 1206853 : fd_dcache_data_sz( uchar const * dcache ) { 148 1206853 : return fd_dcache_private_hdr_const( dcache )->data_sz; 149 1206853 : } 150 : 151 : ulong 152 6 : fd_dcache_app_sz( uchar const * dcache ) { 153 6 : return fd_dcache_private_hdr_const( dcache )->app_sz; 154 6 : } 155 : 156 : uchar const * 157 15 : fd_dcache_app_laddr_const( uchar const * dcache ) { 158 15 : fd_dcache_private_hdr_t const * hdr = fd_dcache_private_hdr_const( dcache ); 159 15 : return (uchar const *)(((ulong)hdr) + hdr->app_off); 160 15 : } 161 : 162 : uchar * 163 6 : fd_dcache_app_laddr( uchar * dcache ) { 164 6 : fd_dcache_private_hdr_t * hdr = fd_dcache_private_hdr( dcache ); 165 6 : return (uchar *)(((ulong)hdr) + hdr->app_off); 166 6 : } 167 : 168 : int 169 : fd_dcache_compact_is_safe( void const * base, 170 : void const * dcache, 171 : ulong mtu, 172 33 : ulong depth ) { 173 : 174 : /* Validate base */ 175 : 176 33 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)base, 2UL*FD_CHUNK_SZ ) ) ) { 177 3 : FD_LOG_WARNING(( "base is not double chunk aligned" )); 178 3 : return 0; 179 3 : } 180 : 181 30 : if( FD_UNLIKELY( (ulong)dcache < (ulong)base ) ) { 182 3 : FD_LOG_WARNING(( "dcache before base" )); 183 3 : return 0; 184 3 : } 185 : 186 : /* Validate dcache */ 187 : 188 27 : if( FD_UNLIKELY( !dcache ) ) { 189 3 : FD_LOG_WARNING(( "NULL dcache" )); 190 3 : return 0; 191 3 : } 192 : 193 24 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)dcache, 2UL*FD_CHUNK_SZ ) ) ) { /* Should be impossible if valid join */ 194 3 : FD_LOG_WARNING(( "bad dcache (alignment)" )); 195 3 : return 0; 196 3 : } 197 : 198 21 : ulong data_sz = fd_dcache_data_sz( (uchar const *)dcache ); 199 21 : if( FD_UNLIKELY( ((ulong)dcache + (ulong)data_sz) < (ulong)dcache ) ) { /* Should be impossible if valid join */ 200 0 : FD_LOG_WARNING(( "bad dcache (data_sz)" )); 201 0 : return 0; 202 0 : } 203 : 204 21 : ulong chunk0 = ((ulong)dcache - (ulong)base) >> FD_CHUNK_LG_SZ; /* No overflow */ 205 21 : ulong chunk1 = ((ulong)dcache + data_sz - (ulong)base) >> FD_CHUNK_LG_SZ; /* No overflow */ 206 : 207 21 : if( FD_UNLIKELY( chunk1>(ulong)UINT_MAX ) ) { 208 0 : FD_LOG_WARNING(( "base to dcache address space span too large" )); 209 0 : return 0; 210 0 : } 211 : 212 : /* At this point, complete chunks in dcache cover [chunk0,chunk1) 213 : relative to the base address and any range of chunks in the dcache 214 : can be losslessly compressed into two 32-bit values. */ 215 : 216 : /* Validate mtu */ 217 : 218 21 : if( FD_UNLIKELY( !mtu ) ) { 219 3 : FD_LOG_WARNING(( "zero mtu" )); 220 3 : return 0; 221 3 : } 222 : 223 18 : ulong mtu_up = mtu + (2UL*FD_CHUNK_SZ-1UL); 224 : 225 18 : if( FD_UNLIKELY( mtu_up < mtu ) ) { 226 3 : FD_LOG_WARNING(( "too large mtu" )); 227 3 : return 0; 228 3 : } 229 : 230 15 : ulong chunk_mtu = (mtu_up >> (1+FD_CHUNK_LG_SZ)) << 1; /* >0 */ 231 : 232 : /* At this point, mtu is non-zero, chunk_mtu is non-zero and a 233 : sufficient number of chunks to cover an mtu frag. Further, the 234 : fd_dcache_chunk_next calculation is guaranteed overflow safe for 235 : any size in [0,mtu]. */ 236 : 237 : /* Validate depth */ 238 : 239 15 : if( FD_UNLIKELY( !depth ) ) { 240 3 : FD_LOG_WARNING(( "zero depth" )); 241 3 : return 0; 242 3 : } 243 : 244 12 : ulong overhead = 2UL*chunk_mtu-1UL; /* no overflow chunk_sz >> 1, chunk_mtu << ULONG_MAX/2 */ 245 12 : ulong depth_max = (ULONG_MAX-overhead) / chunk_mtu; /* no overflow as overhead < ULONG_MAX */ 246 : 247 12 : if( FD_UNLIKELY( depth > depth_max ) ) { 248 0 : FD_LOG_WARNING(( "too large depth" )); 249 0 : return 0; 250 0 : } 251 : 252 12 : ulong chunk_req = depth*chunk_mtu + overhead; /* (depth+2)*chunk_mtu-1, no overflow */ 253 : 254 12 : if( FD_UNLIKELY( (chunk1-chunk0) < chunk_req ) ) { 255 0 : FD_LOG_WARNING(( "too small dcache" )); 256 0 : return 0; 257 0 : } 258 : 259 12 : return 1; 260 12 : } 261 :