Line data Source code
1 : #include "fd_funk.h"
2 : #include <stdio.h>
3 :
4 : ulong
5 220794 : fd_funk_align( void ) {
6 220794 : return alignof(fd_funk_t);
7 220794 : }
8 :
9 : ulong
10 220794 : fd_funk_footprint( void ) {
11 220794 : return sizeof(fd_funk_t);
12 220794 : }
13 :
14 : /* TODO: Consider letter user just passing a join of alloc to use,
15 : inferring the backing wksp and cgroup_hint from that and then
16 : allocating exclusively from that? */
17 :
18 : void *
19 : fd_funk_new( void * shmem,
20 : ulong wksp_tag,
21 : ulong seed,
22 : ulong txn_max,
23 110589 : ulong rec_max ) {
24 110589 : fd_funk_t * funk = (fd_funk_t *)shmem;
25 :
26 110589 : if( FD_UNLIKELY( !funk ) ) {
27 3 : FD_LOG_WARNING(( "NULL funk" ));
28 3 : return NULL;
29 3 : }
30 :
31 110586 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)funk, fd_funk_align() ) ) ) {
32 3 : FD_LOG_WARNING(( "misaligned funk" ));
33 3 : return NULL;
34 3 : }
35 :
36 110583 : if( FD_UNLIKELY( !wksp_tag ) ) {
37 3 : FD_LOG_WARNING(( "bad wksp_tag" ));
38 3 : return NULL;
39 3 : }
40 :
41 110580 : fd_wksp_t * wksp = fd_wksp_containing( funk );
42 110580 : if( FD_UNLIKELY( !wksp ) ) {
43 3 : FD_LOG_WARNING(( "shmem must be part of a workspace" ));
44 3 : return NULL;
45 3 : }
46 :
47 110577 : if( txn_max>FD_FUNK_TXN_IDX_NULL ) { /* See note in fd_funk.h about this limit */
48 3 : FD_LOG_WARNING(( "txn_max too large for index compression" ));
49 3 : return NULL;
50 3 : }
51 :
52 110574 : void * txn_shmem = fd_wksp_alloc_laddr( wksp, fd_funk_txn_map_align(), fd_funk_txn_map_footprint( txn_max ), wksp_tag );
53 110574 : if( FD_UNLIKELY( !txn_shmem ) ) {
54 3 : FD_LOG_WARNING(( "txn_max too large for workspace" ));
55 3 : return NULL;
56 3 : }
57 :
58 110571 : void * txn_shmap = fd_funk_txn_map_new( txn_shmem, txn_max, seed );
59 110571 : if( FD_UNLIKELY( !txn_shmap ) ) {
60 0 : FD_LOG_WARNING(( "fd_funk_txn_map_new failed" ));
61 0 : fd_wksp_free_laddr( txn_shmem );
62 0 : return NULL;
63 0 : }
64 :
65 110571 : fd_funk_txn_t * txn_map = fd_funk_txn_map_join( txn_shmap );
66 110571 : if( FD_UNLIKELY( !txn_map ) ) {
67 0 : FD_LOG_WARNING(( "fd_funk_txn_map_join failed" ));
68 0 : fd_wksp_free_laddr( fd_funk_txn_map_delete( txn_shmap ) );
69 0 : return NULL;
70 0 : }
71 :
72 110571 : void * rec_shmem = fd_wksp_alloc_laddr( wksp, fd_funk_rec_map_align(), fd_funk_rec_map_footprint( rec_max ), wksp_tag );
73 110571 : if( FD_UNLIKELY( !rec_shmem ) ) {
74 3 : FD_LOG_WARNING(( "rec_max too large for workspace" ));
75 3 : fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
76 3 : return NULL;
77 3 : }
78 :
79 110568 : void * rec_shmap = fd_funk_rec_map_new( rec_shmem, rec_max, seed );
80 110568 : if( FD_UNLIKELY( !rec_shmap ) ) {
81 0 : FD_LOG_WARNING(( "fd_funk_rec_map_new failed" ));
82 0 : fd_wksp_free_laddr( rec_shmem );
83 0 : fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
84 0 : return NULL;
85 0 : }
86 :
87 110568 : fd_funk_rec_t * rec_map = fd_funk_rec_map_join( rec_shmap );
88 110568 : if( FD_UNLIKELY( !rec_map ) ) {
89 0 : FD_LOG_WARNING(( "fd_funk_rec_map_join failed" ));
90 0 : fd_wksp_free_laddr( fd_funk_rec_map_delete( rec_shmap ) );
91 0 : fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
92 0 : return NULL;
93 0 : }
94 :
95 110568 : void * alloc_shmem = fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), wksp_tag );
96 110568 : if( FD_UNLIKELY( !alloc_shmem ) ) {
97 0 : FD_LOG_WARNING(( "fd_alloc too large for workspace" ));
98 0 : fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( rec_map ) ) );
99 0 : fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
100 0 : return NULL;
101 0 : }
102 :
103 110568 : void * alloc_shalloc = fd_alloc_new( alloc_shmem, wksp_tag );
104 110568 : if( FD_UNLIKELY( !alloc_shalloc ) ) {
105 0 : FD_LOG_WARNING(( "fd_allow_new failed" ));
106 0 : fd_wksp_free_laddr( alloc_shalloc );
107 0 : fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( rec_map ) ) );
108 0 : fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
109 0 : return NULL;
110 0 : }
111 :
112 110568 : fd_alloc_t * alloc = fd_alloc_join( alloc_shalloc, 0UL ); /* TODO: Consider letting user pass the cgroup hint? */
113 110568 : if( FD_UNLIKELY( !alloc ) ) {
114 0 : FD_LOG_WARNING(( "fd_alloc_join failed" ));
115 0 : fd_wksp_free_laddr( fd_alloc_delete( alloc_shalloc ) );
116 0 : fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( rec_map ) ) );
117 0 : fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
118 0 : return NULL;
119 0 : }
120 :
121 110568 : fd_memset( funk, 0, fd_funk_footprint() );
122 :
123 110568 : funk->funk_gaddr = fd_wksp_gaddr_fast( wksp, funk );
124 110568 : funk->wksp_tag = wksp_tag;
125 110568 : funk->seed = seed;
126 110568 : funk->cycle_tag = 3UL; /* various verify functions use tags 0-2 */
127 :
128 110568 : funk->txn_max = txn_max;
129 110568 : funk->txn_map_gaddr = fd_wksp_gaddr_fast( wksp, txn_map ); /* Note that this persists the join until delete */
130 110568 : funk->child_head_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
131 110568 : funk->child_tail_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
132 :
133 110568 : fd_funk_txn_xid_set_root( funk->root );
134 110568 : fd_funk_txn_xid_set_root( funk->last_publish );
135 :
136 110568 : funk->rec_max = rec_max;
137 110568 : funk->rec_map_gaddr = fd_wksp_gaddr_fast( wksp, rec_map ); /* Note that this persists the join until delete */
138 110568 : funk->rec_head_idx = FD_FUNK_REC_IDX_NULL;
139 110568 : funk->rec_tail_idx = FD_FUNK_REC_IDX_NULL;
140 :
141 110568 : funk->alloc_gaddr = fd_wksp_gaddr_fast( wksp, alloc ); /* Note that this persists the join until delete */
142 :
143 110568 : ulong tmp_max;
144 110568 : fd_funk_partvec_t * partvec = (fd_funk_partvec_t *)fd_alloc_malloc_at_least( alloc, fd_funk_partvec_align(), fd_funk_partvec_footprint(0U), &tmp_max );
145 110568 : if( FD_UNLIKELY( !partvec ) ) {
146 0 : FD_LOG_WARNING(( "partvec alloc failed" ));
147 0 : fd_wksp_free_laddr( fd_alloc_delete( alloc_shalloc ) );
148 0 : fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( rec_map ) ) );
149 0 : fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
150 0 : return NULL;
151 0 : }
152 110568 : partvec->num_part = 0U;
153 110568 : funk->partvec_gaddr = fd_wksp_gaddr_fast( wksp, partvec );
154 :
155 110568 : FD_COMPILER_MFENCE();
156 110568 : FD_VOLATILE( funk->magic ) = FD_FUNK_MAGIC;
157 110568 : FD_COMPILER_MFENCE();
158 :
159 110568 : return (void *)funk;
160 110568 : }
161 :
162 : fd_funk_t *
163 110580 : fd_funk_join( void * shfunk ) {
164 110580 : fd_funk_t * funk = (fd_funk_t *)shfunk;
165 :
166 110580 : if( FD_UNLIKELY( !funk ) ) {
167 3 : FD_LOG_WARNING(( "NULL shfunk" ));
168 3 : return NULL;
169 3 : }
170 :
171 110577 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)funk, fd_funk_align() ) ) ) {
172 3 : FD_LOG_WARNING(( "misaligned shfunk" ));
173 3 : return NULL;
174 3 : }
175 :
176 110574 : fd_wksp_t * wksp = fd_wksp_containing( funk );
177 110574 : if( FD_UNLIKELY( !wksp ) ) {
178 3 : FD_LOG_WARNING(( "shfunk must be part of a workspace" ));
179 3 : return NULL;
180 3 : }
181 :
182 110571 : if( FD_UNLIKELY( funk->magic!=FD_FUNK_MAGIC ) ) {
183 3 : FD_LOG_WARNING(( "bad magic" ));
184 3 : return NULL;
185 3 : }
186 :
187 : #ifdef FD_FUNK_WKSP_PROTECT
188 : fd_wksp_mprotect( wksp, 1 );
189 : #endif
190 :
191 110568 : return funk;
192 110571 : }
193 :
194 : void *
195 110265 : fd_funk_leave( fd_funk_t * funk ) {
196 :
197 110265 : if( FD_UNLIKELY( !funk ) ) {
198 3 : FD_LOG_WARNING(( "NULL funk" ));
199 3 : return NULL;
200 3 : }
201 :
202 110262 : return (void *)funk;
203 110265 : }
204 :
205 : void *
206 110274 : fd_funk_delete( void * shfunk ) {
207 110274 : fd_funk_t * funk = (fd_funk_t *)shfunk;
208 :
209 110274 : if( FD_UNLIKELY( !funk ) ) {
210 3 : FD_LOG_WARNING(( "NULL shfunk" ));
211 3 : return NULL;
212 3 : }
213 :
214 110271 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)funk, fd_funk_align() ) ) ) {
215 3 : FD_LOG_WARNING(( "misaligned shfunk" ));
216 3 : return NULL;
217 3 : }
218 :
219 110268 : fd_wksp_t * wksp = fd_wksp_containing( funk );
220 110268 : if( FD_UNLIKELY( !wksp ) ) {
221 3 : FD_LOG_WARNING(( "shfunk must be part of a workspace" ));
222 3 : return NULL;
223 3 : }
224 :
225 110265 : if( FD_UNLIKELY( funk->magic!=FD_FUNK_MAGIC ) ) {
226 3 : FD_LOG_WARNING(( "bad magic" ));
227 3 : return NULL;
228 3 : }
229 :
230 : /* Free all value resources here */
231 :
232 110262 : fd_wksp_free_laddr( fd_alloc_delete ( fd_alloc_leave ( fd_funk_alloc ( funk, wksp ) ) ) );
233 110262 : fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( fd_funk_rec_map( funk, wksp ) ) ) );
234 110262 : fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( fd_funk_txn_map( funk, wksp ) ) ) );
235 :
236 110262 : FD_COMPILER_MFENCE();
237 110262 : FD_VOLATILE( funk->magic ) = 0UL;
238 110262 : FD_COMPILER_MFENCE();
239 :
240 110262 : return funk;
241 110265 : }
242 :
243 : int
244 22026408 : fd_funk_verify( fd_funk_t * funk ) {
245 :
246 748897872 : # define TEST(c) do { \
247 748897872 : if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: %s", #c )); return FD_FUNK_ERR_INVAL; } \
248 748897872 : } while(0)
249 :
250 22026408 : TEST( funk );
251 :
252 : /* Test metadata */
253 :
254 22026408 : TEST( funk->magic==FD_FUNK_MAGIC );
255 :
256 22026408 : ulong funk_gaddr = funk->funk_gaddr;
257 22026408 : TEST( funk_gaddr );
258 22026408 : fd_wksp_t * wksp = fd_funk_wksp( funk );
259 22026408 : TEST( wksp );
260 22026408 : TEST( fd_wksp_laddr_fast( wksp, funk_gaddr )==(void *)funk );
261 22026408 : TEST( fd_wksp_gaddr_fast( wksp, funk )==funk_gaddr );
262 :
263 22026408 : ulong wksp_tag = fd_funk_wksp_tag( funk );
264 22026408 : TEST( !!wksp_tag );
265 :
266 22026408 : ulong seed = funk->seed; /* seed can be anything */
267 :
268 22026408 : TEST( funk->cycle_tag>2UL );
269 :
270 : /* Test transaction map */
271 :
272 22026408 : ulong txn_max = funk->txn_max;
273 22026408 : TEST( txn_max<=FD_FUNK_TXN_IDX_NULL );
274 :
275 22026408 : ulong txn_map_gaddr = funk->txn_map_gaddr;
276 22026408 : TEST( txn_map_gaddr );
277 22026408 : TEST( fd_wksp_tag( wksp, txn_map_gaddr-1UL )==wksp_tag ); /* When txn_max is 0, txn_map_gaddr can be first byte after alloc */
278 22026408 : fd_funk_txn_t * txn_map = fd_funk_txn_map( funk, wksp );
279 22026408 : TEST( txn_map );
280 22026408 : TEST( txn_max==fd_funk_txn_map_key_max( txn_map ) );
281 22026408 : TEST( seed ==fd_funk_txn_map_seed ( txn_map ) );
282 :
283 22026408 : ulong child_head_idx = fd_funk_txn_idx( funk->child_head_cidx );
284 22026408 : ulong child_tail_idx = fd_funk_txn_idx( funk->child_tail_cidx );
285 :
286 22026408 : int null_child_head = fd_funk_txn_idx_is_null( child_head_idx );
287 22026408 : int null_child_tail = fd_funk_txn_idx_is_null( child_tail_idx );
288 :
289 22026408 : if( !txn_max ) TEST( null_child_head & null_child_tail );
290 22026402 : else {
291 22026402 : if( null_child_head ) TEST( null_child_tail );
292 15354951 : else TEST( child_head_idx<txn_max );
293 :
294 22026402 : if( null_child_tail ) TEST( null_child_head );
295 15354951 : else TEST( child_tail_idx<txn_max );
296 22026402 : }
297 :
298 22026408 : if( !txn_max ) TEST( fd_funk_txn_idx_is_null( child_tail_idx ) );
299 :
300 22026408 : fd_funk_txn_xid_t const * root = fd_funk_root( funk );
301 22026408 : TEST( root ); /* Practically guaranteed */
302 22026408 : TEST( fd_funk_txn_xid_eq_root( root ) );
303 :
304 22026408 : fd_funk_txn_xid_t * last_publish = funk->last_publish;
305 22026408 : TEST( last_publish ); /* Practically guaranteed */
306 : /* (*last_publish) only be root at creation and anything but root
307 : post creation. But we don't which situation applies here so this
308 : could be anything. */
309 :
310 22026408 : TEST( !fd_funk_txn_verify( funk ) );
311 :
312 : /* Test record map */
313 :
314 22026408 : ulong rec_max = funk->rec_max;
315 22026408 : TEST( rec_max<=FD_FUNK_TXN_IDX_NULL );
316 :
317 22026408 : ulong rec_map_gaddr = funk->rec_map_gaddr;
318 22026408 : TEST( rec_map_gaddr );
319 22026408 : TEST( fd_wksp_tag( wksp, rec_map_gaddr-1UL )==wksp_tag ); /* When rec_max is zero, rec_map_gaddr can be first byte after alloc */
320 22026408 : fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
321 22026408 : TEST( rec_map );
322 22026408 : TEST( rec_max==fd_funk_rec_map_key_max( rec_map ) );
323 22026408 : TEST( seed ==fd_funk_rec_map_seed ( rec_map ) );
324 :
325 22026408 : ulong rec_head_idx = funk->rec_head_idx;
326 22026408 : ulong rec_tail_idx = funk->rec_tail_idx;
327 :
328 22026408 : int null_rec_head = fd_funk_rec_idx_is_null( rec_head_idx );
329 22026408 : int null_rec_tail = fd_funk_rec_idx_is_null( rec_tail_idx );
330 :
331 22026408 : if( !rec_max ) TEST( null_rec_head & null_rec_tail );
332 22026402 : else {
333 22026402 : if( null_rec_head ) TEST( null_rec_tail );
334 18863784 : else TEST( rec_head_idx<rec_max );
335 :
336 22026402 : if( null_rec_tail ) TEST( null_rec_head );
337 18863784 : else TEST( rec_tail_idx<rec_max );
338 22026402 : }
339 :
340 22026408 : if( !rec_max ) TEST( fd_funk_rec_idx_is_null( rec_tail_idx ) );
341 :
342 22026408 : TEST( !fd_funk_rec_verify( funk ) );
343 22026408 : TEST( !fd_funk_part_verify( funk ) );
344 :
345 : /* Test values */
346 :
347 22026408 : ulong alloc_gaddr = funk->alloc_gaddr;
348 22026408 : TEST( alloc_gaddr );
349 22026408 : TEST( fd_wksp_tag( wksp, alloc_gaddr )==wksp_tag );
350 22026408 : fd_alloc_t * alloc = fd_funk_alloc( funk, wksp );
351 22026408 : TEST( alloc );
352 :
353 22026408 : TEST( !fd_funk_val_verify( funk ) );
354 :
355 22026408 : # undef TEST
356 :
357 22026408 : return FD_FUNK_SUCCESS;
358 22026408 : }
359 :
360 : static char *
361 0 : fd_smart_size( ulong sz, char * tmp, size_t tmpsz ) {
362 0 : if( sz <= (1UL<<7) )
363 0 : snprintf( tmp, tmpsz, "%lu B", sz );
364 0 : else if( sz <= (1UL<<17) )
365 0 : snprintf( tmp, tmpsz, "%.3f KB", ((double)sz/((double)(1UL<<10))) );
366 0 : else if( sz <= (1UL<<27) )
367 0 : snprintf( tmp, tmpsz, "%.3f MB", ((double)sz/((double)(1UL<<20))) );
368 0 : else
369 0 : snprintf( tmp, tmpsz, "%.3f GB", ((double)sz/((double)(1UL<<30))) );
370 0 : return tmp;
371 0 : }
372 :
373 : void
374 0 : fd_funk_log_mem_usage( fd_funk_t * funk ) {
375 0 : char tmp1[100];
376 0 : char tmp2[100];
377 :
378 0 : FD_LOG_NOTICE(( "funk base footprint: %s",
379 0 : fd_smart_size( fd_funk_footprint(), tmp1, sizeof(tmp1) ) ));
380 0 : fd_wksp_t * wksp = fd_funk_wksp( funk );
381 0 : fd_funk_txn_t const * txn_map = fd_funk_txn_map( funk, wksp );
382 0 : FD_LOG_NOTICE(( "txn table footprint: %s (%lu entries used out of %lu, %lu%%)",
383 0 : fd_smart_size( fd_funk_txn_map_footprint( funk->txn_max ), tmp1, sizeof(tmp1) ),
384 0 : fd_funk_txn_map_key_cnt( txn_map ),
385 0 : fd_funk_txn_map_key_max( txn_map ),
386 0 : (100U*fd_funk_txn_map_key_cnt( txn_map )) / fd_funk_txn_map_key_max( txn_map ) ));
387 0 : fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
388 0 : FD_LOG_NOTICE(( "rec table footprint: %s (%lu entries used out of %lu, %lu%%)",
389 0 : fd_smart_size( fd_funk_rec_map_footprint( funk->rec_max ), tmp1, sizeof(tmp1) ),
390 0 : fd_funk_rec_map_key_cnt( rec_map ),
391 0 : fd_funk_rec_map_key_max( rec_map ),
392 0 : (100U*fd_funk_rec_map_key_cnt( rec_map )) / fd_funk_rec_map_key_max( rec_map ) ));
393 0 : ulong val_cnt = 0;
394 0 : ulong val_min = ULONG_MAX;
395 0 : ulong val_max = 0;
396 0 : ulong val_used = 0;
397 0 : ulong val_alloc = 0;
398 0 : for( fd_funk_rec_map_iter_t iter = fd_funk_rec_map_iter_init( rec_map );
399 0 : !fd_funk_rec_map_iter_done( rec_map, iter );
400 0 : iter = fd_funk_rec_map_iter_next( rec_map, iter ) ) {
401 0 : fd_funk_rec_t * rec = fd_funk_rec_map_iter_ele( rec_map, iter );
402 0 : val_cnt ++;
403 0 : val_min = fd_ulong_min( val_min, rec->val_sz );
404 0 : val_max = fd_ulong_max( val_max, rec->val_sz );
405 0 : val_used += rec->val_sz;
406 0 : val_alloc += rec->val_max;
407 0 : }
408 0 : FD_LOG_NOTICE(( " rec count: %lu, min size: %lu, avg_size: %lu, max_size: %lu, total_size: %s, total_allocated: %s",
409 0 : val_cnt, val_min, val_used/val_cnt, val_max,
410 0 : fd_smart_size( val_used, tmp1, sizeof(tmp1) ),
411 0 : fd_smart_size( val_alloc, tmp2, sizeof(tmp2) ) ));
412 0 : FD_LOG_NOTICE(( "part vec footprint: %s",
413 0 : fd_smart_size( fd_funk_partvec_footprint(0U), tmp1, sizeof(tmp1) ) ));
414 0 : }
415 :
416 : #include "../flamenco/fd_rwlock.h"
417 : static fd_rwlock_t lock[ 1 ] = {0};
418 :
419 : void
420 1570863 : fd_funk_start_write( fd_funk_t * funk ) {
421 1570863 : fd_rwlock_write( lock );
422 : #ifdef FD_FUNK_WKSP_PROTECT
423 : fd_wksp_mprotect( fd_funk_wksp( funk ), 0 );
424 : #endif
425 1570863 : # if FD_HAS_THREADS
426 1570863 : register ulong oldval;
427 1570863 : for(;;) {
428 1570863 : oldval = funk->write_lock;
429 1570863 : if( FD_LIKELY( FD_ATOMIC_CAS( &funk->write_lock, oldval, oldval+1U) == oldval ) ) break;
430 0 : FD_SPIN_PAUSE();
431 0 : }
432 1570863 : if( FD_UNLIKELY(oldval&1UL) ) {
433 0 : FD_LOG_CRIT(( "attempt to lock funky when it is already locked" ));
434 0 : }
435 1570863 : FD_COMPILER_MFENCE();
436 : # else
437 : (void)funk;
438 : # endif
439 1570863 : }
440 :
441 : void
442 1570863 : fd_funk_end_write( fd_funk_t * funk ) {
443 1570863 : # if FD_HAS_THREADS
444 1570863 : FD_COMPILER_MFENCE();
445 1570863 : register ulong oldval;
446 1570863 : for(;;) {
447 1570863 : oldval = funk->write_lock;
448 1570863 : if( FD_LIKELY( FD_ATOMIC_CAS( &funk->write_lock, oldval, oldval+1U) == oldval ) ) break;
449 0 : FD_SPIN_PAUSE();
450 0 : }
451 1570863 : if( FD_UNLIKELY(!(oldval&1UL)) ) {
452 0 : FD_LOG_CRIT(( "attempt to unlock funky when it is already unlocked" ));
453 0 : }
454 : # else
455 : (void)funk;
456 : # endif
457 : #ifdef FD_FUNK_WKSP_PROTECT
458 : fd_wksp_mprotect( fd_funk_wksp( funk ), 1 );
459 : #endif
460 1570863 : fd_rwlock_unwrite( lock );
461 1570863 : }
462 :
463 : void
464 734828787 : fd_funk_check_write( fd_funk_t * funk ) {
465 734828787 : ulong val = funk->write_lock;
466 734828787 : if( FD_UNLIKELY(!(val&1UL)) ) FD_LOG_CRIT(( "missing call to fd_funk_start_write" ));
467 734828787 : }
468 :
469 : void
470 0 : fd_funk_speed_load_mode( fd_funk_t * funk, int flag ) {
471 0 : funk->speed_load = flag;
472 0 : }
|