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