File tree 1 file changed +20
-11
lines changed
1 file changed +20
-11
lines changed Original file line number Diff line number Diff line change @@ -673,18 +673,27 @@ POOL_(acquire)( POOL_(t) * join,
673
673
674
674
ulong ele_nxt = POOL_ (private_idx )( ele0 [ ele_idx ].POOL_NEXT );
675
675
676
- if ( FD_UNLIKELY ( (ele_nxt >=ele_max ) & (!POOL_ (idx_is_null )( ele_nxt )) ) ) { /* opt for not corrupt */
677
- err = FD_POOL_ERR_CORRUPT ;
678
- break ;
679
- }
680
-
681
- ulong new_ver_top = POOL_ (private_vidx )( ver + 2UL , ele_nxt );
682
-
683
- if ( FD_LIKELY ( POOL_ (private_cas )( _v , ver_top , new_ver_top )== ver_top ) ) { /* opt for low contention */
684
- ele = ele0 + ele_idx ;
685
- break ;
676
+ if ( FD_UNLIKELY ( (ele_nxt >=ele_max ) & (!POOL_ (idx_is_null )( ele_nxt )) ) ) { /* ele_nxt is invalid, opt for valid */
677
+ /* It is possible that another thread acquired ele_idx and
678
+ repurposed ele_idx's POOL_NEXT (storing something in it that
679
+ isn't a valid pool value) between when we read ver_top and
680
+ when we read ele_idx's POOL_NEXT above. If so, the pool
681
+ version would be changed from what we read above. We thus
682
+ only signal ERR_CORRUPT if the version number hasn't changed
683
+ since we read it. */
684
+
685
+ if ( FD_UNLIKELY ( POOL_ (private_vidx_ver )( * _v )== ver ) ) {
686
+ err = FD_POOL_ERR_CORRUPT ;
687
+ break ;
688
+ }
689
+ } else { /* ele_nxt is valid */
690
+ ulong new_ver_top = POOL_ (private_vidx )( ver + 2UL , ele_nxt );
691
+
692
+ if ( FD_LIKELY ( POOL_ (private_cas )( _v , ver_top , new_ver_top )== ver_top ) ) { /* opt for low contention */
693
+ ele = ele0 + ele_idx ;
694
+ break ;
695
+ }
686
696
}
687
-
688
697
} else if ( FD_UNLIKELY ( !blocking ) ) { /* opt for blocking */
689
698
690
699
err = FD_POOL_ERR_AGAIN ;
You can’t perform that action at this time.
0 commit comments