Skip to content

Commit 6c6b955

Browse files
committed
flamenco, runtime: tidy up banks lock usage
1 parent b238fe5 commit 6c6b955

File tree

4 files changed

+43
-33
lines changed

4 files changed

+43
-33
lines changed

src/discof/exec/fd_exec_tile.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
9595

9696
static void
9797
execute_txn( fd_exec_tile_ctx_t * ctx ) {
98-
fd_banks_lock( ctx->banks );
9998
ctx->exec_res = fd_runtime_prepare_and_execute_txn(
10099
ctx->banks,
101100
ctx->txn_ctx,
@@ -105,7 +104,6 @@ execute_txn( fd_exec_tile_ctx_t * ctx ) {
105104
ctx->capture_ctx,
106105
1
107106
);
108-
fd_banks_unlock( ctx->banks );
109107
}
110108

111109
static void

src/discof/writer/fd_writer_tile.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,6 @@ after_frag( fd_writer_tile_ctx_t * ctx,
314314
}
315315
fd_exec_txn_ctx_t * txn_ctx = ctx->txn_ctx[ in_idx ];
316316

317-
fd_banks_lock( ctx->banks );
318317
ctx->bank = fd_banks_get_bank( ctx->banks, txn_ctx->slot );
319318
if( FD_UNLIKELY( !ctx->bank ) ) {
320319
FD_LOG_CRIT(( "Could not find bank for slot %lu", txn_ctx->slot ));
@@ -345,9 +344,6 @@ after_frag( fd_writer_tile_ctx_t * ctx,
345344
ctx->capture_ctx );
346345

347346
} FD_SPAD_FRAME_END;
348-
fd_banks_unlock( ctx->banks );
349-
} else {
350-
fd_banks_unlock( ctx->banks );
351347
}
352348

353349
/* Notify the replay tile that we are done with this txn. */

src/flamenco/runtime/fd_bank.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,12 @@ fd_banks_init_bank( fd_banks_t * banks, ulong slot ) {
435435
fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
436436
fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
437437

438+
fd_rwlock_write( &banks->rwlock );
439+
438440
fd_bank_t * bank = fd_banks_pool_ele_acquire( bank_pool );
439441
if( FD_UNLIKELY( bank==NULL ) ) {
440442
FD_LOG_WARNING(( "Failed to acquire bank" ));
443+
fd_rwlock_unwrite( &banks->rwlock );
441444
return NULL;
442445
}
443446

@@ -484,6 +487,7 @@ fd_banks_init_bank( fd_banks_t * banks, ulong slot ) {
484487
banks->root = slot;
485488
banks->root_idx = fd_banks_pool_idx( bank_pool, bank );
486489

490+
fd_rwlock_unwrite( &banks->rwlock );
487491
return bank;
488492
}
489493

@@ -492,18 +496,21 @@ fd_banks_get_bank( fd_banks_t * banks, ulong slot ) {
492496
fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
493497
fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
494498

499+
fd_rwlock_read( &banks->rwlock );
495500
ulong idx = fd_banks_map_idx_query_const( bank_map, &slot, ULONG_MAX, bank_pool );
496501
if( FD_UNLIKELY( idx==ULONG_MAX ) ) {
497502
FD_LOG_DEBUG(( "Failed to get bank idx for slot %lu", slot ));
503+
fd_rwlock_unread( &banks->rwlock );
498504
return NULL;
499505
}
500506

501507
fd_bank_t * bank = fd_banks_pool_ele( bank_pool, idx );
502508
if( FD_UNLIKELY( !bank ) ) {
503509
FD_LOG_WARNING(( "Failed to get bank for slot %lu", slot ));
510+
fd_rwlock_unread( &banks->rwlock );
504511
return NULL;
505512
}
506-
513+
fd_rwlock_unread( &banks->rwlock );
507514
return bank;
508515
}
509516

@@ -866,6 +873,7 @@ fd_banks_publish( fd_banks_t * banks, ulong slot ) {
866873
void
867874
fd_banks_clear_bank( fd_banks_t * banks, fd_bank_t * bank ) {
868875

876+
fd_rwlock_read( &banks->rwlock );
869877
/* Get the parent bank. */
870878
fd_bank_t * parent_bank = fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank->parent_idx );
871879

@@ -877,7 +885,7 @@ fd_banks_clear_bank( fd_banks_t * banks, fd_bank_t * bank ) {
877885
/* assign the bank to the idx corresponding to the parent. */ \
878886
fd_bank_##name##_pool_idx_release( name##_pool, bank->name##_pool_idx ); \
879887
bank->name##_dirty = 0; \
880-
bank->name##_pool_idx = !!parent_bank ? parent_bank->name##_pool_idx : fd_bank_##name##_pool_idx_null( name##_pool ); \
888+
bank->name##_pool_idx = parent_bank ? parent_bank->name##_pool_idx : fd_bank_##name##_pool_idx_null( name##_pool ); \
881889
}
882890

883891
#define HAS_COW_0(type, name, footprint) \
@@ -889,24 +897,31 @@ fd_banks_clear_bank( fd_banks_t * banks, fd_bank_t * bank ) {
889897
#undef X
890898
#undef HAS_COW_0
891899
#undef HAS_COW_1
900+
901+
fd_rwlock_unread( &banks->rwlock );
892902
}
893903

894904
fd_bank_t *
895905
fd_banks_rekey_root_bank( fd_banks_t * banks, ulong slot ) {
896906

907+
fd_rwlock_write( &banks->rwlock );
908+
897909
if( FD_UNLIKELY( !banks ) ) {
898910
FD_LOG_WARNING(( "Banks is NULL" ));
911+
fd_rwlock_unwrite( &banks->rwlock );
899912
return NULL;
900913
}
901914

902915
if( FD_UNLIKELY( banks->root_idx==fd_banks_pool_idx_null( fd_banks_get_bank_pool( banks ) ) ) ) {
903916
FD_LOG_WARNING(( "Root bank does not exist" ));
917+
fd_rwlock_unwrite( &banks->rwlock );
904918
return NULL;
905919
}
906920

907921
fd_bank_t * bank = fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), banks->root_idx );
908922
if( FD_UNLIKELY( !bank ) ) {
909923
FD_LOG_WARNING(( "Failed to get root bank" ));
924+
fd_rwlock_unwrite( &banks->rwlock );
910925
return NULL;
911926
}
912927

@@ -915,16 +930,19 @@ fd_banks_rekey_root_bank( fd_banks_t * banks, ulong slot ) {
915930
bank = fd_banks_map_ele_remove( fd_banks_get_bank_map( banks ), &bank->slot_, NULL, fd_banks_get_bank_pool( banks ) );
916931
if( FD_UNLIKELY( !bank ) ) {
917932
FD_LOG_WARNING(( "Failed to remove root bank" ));
933+
fd_rwlock_unwrite( &banks->rwlock );
918934
return NULL;
919935
}
920936

921937
bank->slot_ = slot;
922938

923939
if( FD_UNLIKELY( !fd_banks_map_ele_insert( fd_banks_get_bank_map( banks ), bank, fd_banks_get_bank_pool( banks ) ) ) ) {
924940
FD_LOG_WARNING(( "Failed to insert root bank" ));
941+
fd_rwlock_unwrite( &banks->rwlock );
925942
return NULL;
926943
}
927944

945+
fd_rwlock_unwrite( &banks->rwlock );
928946
return bank;
929947
}
930948

@@ -983,21 +1001,26 @@ fd_banks_publish_prepare( fd_banks_t * banks,
9831001
fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
9841002
fd_banks_map_t * bank_map = fd_banks_get_bank_map( banks );
9851003

1004+
fd_rwlock_read( &banks->rwlock );
1005+
9861006
fd_bank_t * root = fd_banks_root( banks );
9871007
if( FD_UNLIKELY( !root ) ) {
9881008
FD_LOG_WARNING(( "failed to get root bank" ));
1009+
fd_rwlock_unread( &banks->rwlock );
9891010
return 0;
9901011
}
9911012

9921013
/* Early exit if target is the same as the old root. */
9931014
if( FD_UNLIKELY( fd_bank_slot_get( root )==target_slot ) ) {
9941015
FD_LOG_WARNING(( "target slot %lu is the same as the old root slot %lu", target_slot, fd_bank_slot_get( root ) ));
1016+
fd_rwlock_unread( &banks->rwlock );
9951017
return 0;
9961018
}
9971019

9981020
fd_bank_t * target_bank = fd_banks_map_ele_query( bank_map, &target_slot, NULL, bank_pool );
9991021
if( FD_UNLIKELY( !target_bank ) ) {
10001022
FD_LOG_WARNING(( "failed to get bank for target slot %lu", target_slot ));
1023+
fd_rwlock_unread( &banks->rwlock );
10011024
return 0;
10021025
}
10031026

@@ -1101,5 +1124,6 @@ fd_banks_publish_prepare( fd_banks_t * banks,
11011124
curr = rooted_child_bank;
11021125
}
11031126

1127+
fd_rwlock_unread( &banks->rwlock );
11041128
return advanced_publishable_block;
11051129
}

src/flamenco/runtime/fd_bank.h

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,16 @@ struct fd_banks {
436436
ulong root; /* root slot */
437437
ulong root_idx; /* root idx */
438438

439-
fd_rwlock_t rwlock; /* rwlock for fd_banks_t */
439+
/* This lock is only used to serialize banks fork tree reads with
440+
respect to fork tree writes. In other words, tree traversals
441+
cannot happen at the same time as a tree pruning operation or a
442+
tree insertion operation. So the public APIs on banks take either
443+
a read lock or a write lock depending on what they do on the fork
444+
tree. For example, publishing takes a write lock, and bank lookups
445+
take a read lock. Notably, individual banks can still be
446+
concurrently accessed or modified, and this lock does not offer
447+
synchronization on individual fields within a bank. */
448+
fd_rwlock_t rwlock;
440449

441450
ulong pool_offset; /* offset of pool from banks */
442451
ulong map_offset; /* offset of map from banks */
@@ -621,28 +630,6 @@ FD_BANKS_ITER(X)
621630
#undef HAS_COW_0
622631
#undef HAS_COW_1
623632

624-
/* FIXME: these locks do not fundamentally fix the minority fork racy
625-
publishing issue. Remove these once we have refcnts.
626-
627-
fd_banks_lock() and fd_banks_unlock() are locks to be acquired and
628-
freed around accessing or modifying a specific bank. This is only
629-
required if there is concurrent access to a bank while operations on
630-
its underlying map are being performed.
631-
632-
Under the hood, this is a wrapper around fd_banks_t's rwlock.
633-
This is done so a caller can safely read/write a specific bank.
634-
Otherwise, we run the risk of accessing/modifying a bank that may be
635-
freed. This is acquiring and freeing a read lock around fd_banks_t. */
636-
637-
static inline void
638-
fd_banks_lock( fd_banks_t * banks ) {
639-
fd_rwlock_read( &banks->rwlock );
640-
}
641-
642-
static inline void
643-
fd_banks_unlock( fd_banks_t * banks ) {
644-
fd_rwlock_unread( &banks->rwlock );
645-
}
646633

647634
/* fd_banks_root returns the current root slot for the bank. */
648635

@@ -716,7 +703,12 @@ fd_banks_init_bank( fd_banks_t * banks,
716703
ulong slot );
717704

718705
/* fd_bank_get_bank() returns a bank for a given slot. If said bank
719-
does not exist, NULL is returned. */
706+
does not exist, NULL is returned.
707+
708+
The returned pointer is valid so long as the underlying bank does not
709+
get pruned by a publishing operation. Higher level components are
710+
responsible for ensuring that publishing does not happen while a bank
711+
is being accessed. This is done through the reference counter. */
720712

721713
fd_bank_t *
722714
fd_banks_get_bank( fd_banks_t * banks,
@@ -756,7 +748,7 @@ fd_banks_publish( fd_banks_t * banks,
756748
757749
This function will memset all non-CoW fields to 0.
758750
759-
For all non-CoW fields, we will reset the indices to its parent. */
751+
For all CoW fields, we will reset the indices to its parent. */
760752

761753
void
762754
fd_banks_clear_bank( fd_banks_t * banks,

0 commit comments

Comments
 (0)