@@ -4,6 +4,8 @@ use rand::Rng;
44
55use rustc_target:: abi:: { Align , Size } ;
66
7+ use crate :: concurrency:: VClock ;
8+
79const MAX_POOL_SIZE : usize = 64 ;
810
911// Just use fair coins, until we have evidence that other numbers are better.
@@ -21,42 +23,57 @@ pub struct ReusePool {
2123 ///
2224 /// Each of these maps has at most MAX_POOL_SIZE elements, and since alignment is limited to
2325 /// less than 64 different possible value, that bounds the overall size of the pool.
24- pool : Vec < Vec < ( u64 , Size ) > > ,
26+ ///
27+ /// We also store the clock from the thread that donated this pool element,
28+ /// to ensure synchronization with the thread that picks up this address.
29+ pool : Vec < Vec < ( u64 , Size , VClock ) > > ,
2530}
2631
2732impl ReusePool {
2833 pub fn new ( ) -> Self {
2934 ReusePool { pool : vec ! [ ] }
3035 }
3136
32- fn subpool ( & mut self , align : Align ) -> & mut Vec < ( u64 , Size ) > {
37+ fn subpool ( & mut self , align : Align ) -> & mut Vec < ( u64 , Size , VClock ) > {
3338 let pool_idx: usize = align. bytes ( ) . trailing_zeros ( ) . try_into ( ) . unwrap ( ) ;
3439 if self . pool . len ( ) <= pool_idx {
3540 self . pool . resize ( pool_idx + 1 , Vec :: new ( ) ) ;
3641 }
3742 & mut self . pool [ pool_idx]
3843 }
3944
40- pub fn add_addr ( & mut self , rng : & mut impl Rng , addr : u64 , size : Size , align : Align ) {
45+ pub fn add_addr (
46+ & mut self ,
47+ rng : & mut impl Rng ,
48+ addr : u64 ,
49+ size : Size ,
50+ align : Align ,
51+ clock : impl FnOnce ( ) -> VClock ,
52+ ) {
4153 // Let's see if we even want to remember this address.
4254 if !rng. gen_bool ( ADDR_REMEMBER_CHANCE ) {
4355 return ;
4456 }
4557 // Determine the pool to add this to, and where in the pool to put it.
4658 let subpool = self . subpool ( align) ;
47- let pos = subpool. partition_point ( |( _addr, other_size) | * other_size < size) ;
59+ let pos = subpool. partition_point ( |( _addr, other_size, _ ) | * other_size < size) ;
4860 // Make sure the pool does not grow too big.
4961 if subpool. len ( ) >= MAX_POOL_SIZE {
5062 // Pool full. Replace existing element, or last one if this would be even bigger.
5163 let clamped_pos = pos. min ( subpool. len ( ) - 1 ) ;
52- subpool[ clamped_pos] = ( addr, size) ;
64+ subpool[ clamped_pos] = ( addr, size, clock ( ) ) ;
5365 return ;
5466 }
5567 // Add address to pool, at the right position.
56- subpool. insert ( pos, ( addr, size) ) ;
68+ subpool. insert ( pos, ( addr, size, clock ( ) ) ) ;
5769 }
5870
59- pub fn take_addr ( & mut self , rng : & mut impl Rng , size : Size , align : Align ) -> Option < u64 > {
71+ pub fn take_addr (
72+ & mut self ,
73+ rng : & mut impl Rng ,
74+ size : Size ,
75+ align : Align ,
76+ ) -> Option < ( u64 , VClock ) > {
6077 // Determine whether we'll even attempt a reuse.
6178 if !rng. gen_bool ( ADDR_TAKE_CHANCE ) {
6279 return None ;
@@ -65,9 +82,9 @@ impl ReusePool {
6582 let subpool = self . subpool ( align) ;
6683 // Let's see if we can find something of the right size. We want to find the full range of
6784 // such items, beginning with the first, so we can't use `binary_search_by_key`.
68- let begin = subpool. partition_point ( |( _addr, other_size) | * other_size < size) ;
85+ let begin = subpool. partition_point ( |( _addr, other_size, _ ) | * other_size < size) ;
6986 let mut end = begin;
70- while let Some ( ( _addr, other_size) ) = subpool. get ( end) {
87+ while let Some ( ( _addr, other_size, _ ) ) = subpool. get ( end) {
7188 if * other_size != size {
7289 break ;
7390 }
@@ -80,8 +97,8 @@ impl ReusePool {
8097 // Pick a random element with the desired size.
8198 let idx = rng. gen_range ( begin..end) ;
8299 // Remove it from the pool and return.
83- let ( chosen_addr, chosen_size) = subpool. remove ( idx) ;
100+ let ( chosen_addr, chosen_size, clock ) = subpool. remove ( idx) ;
84101 debug_assert ! ( chosen_size >= size && chosen_addr % align. bytes( ) == 0 ) ;
85- Some ( chosen_addr)
102+ Some ( ( chosen_addr, clock ) )
86103 }
87104}
0 commit comments