@@ -4,19 +4,23 @@ use crate::util::linear_scan::Region;
44use crate :: vm:: VMBinding ;
55use std:: sync:: atomic:: AtomicBool ;
66use std:: sync:: atomic:: Ordering ;
7+ #[ cfg( feature = "ms_block_list_sanity" ) ]
8+ use std:: sync:: Mutex ;
79
810/// List of blocks owned by the allocator
911#[ repr( C ) ]
1012pub struct BlockList {
11- pub first : Option < Block > ,
12- pub last : Option < Block > ,
13- pub size : usize ,
14- pub lock : AtomicBool ,
13+ first : Option < Block > ,
14+ last : Option < Block > ,
15+ size : usize ,
16+ lock : AtomicBool ,
17+ #[ cfg( feature = "ms_block_list_sanity" ) ]
18+ sanity_list : Mutex < Vec < Block > > ,
1519}
1620
1721impl std:: fmt:: Debug for BlockList {
1822 fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
19- write ! ( f, "BlockList {:?}" , self . iter( ) . collect:: <Vec <Block >>( ) )
23+ write ! ( f, "{:?}" , self . iter( ) . collect:: <Vec <Block >>( ) )
2024 }
2125}
2226
@@ -27,12 +31,52 @@ impl BlockList {
2731 last : None ,
2832 size,
2933 lock : AtomicBool :: new ( false ) ,
34+ #[ cfg( feature = "ms_block_list_sanity" ) ]
35+ sanity_list : Mutex :: new ( vec ! [ ] ) ,
36+ }
37+ }
38+
39+ // fn access_block_list<R: Copy, F: FnOnce() -> R>(&self, access_func: F) -> R {
40+ // #[cfg(feature = "ms_block_list_sanity")]
41+ // let mut sanity_list = self.sanity_list.lock().unwrap();
42+
43+ // let ret = access_func();
44+
45+ // // Verify the block list is the same as the sanity list
46+ // #[cfg(feature = "ms_block_list_sanity")]
47+ // {
48+ // if !sanity_list.iter().map(|b| *b).eq(BlockListIterator { cursor: self.first }) {
49+ // eprintln!("Sanity block list: {:?}", &mut sanity_list as &mut Vec<Block>);
50+ // eprintln!("Actual block list: {:?}", self);
51+ // panic!("Incorrect block list");
52+ // }
53+ // }
54+
55+ // ret
56+ // }
57+ #[ cfg( feature = "ms_block_list_sanity" ) ]
58+ fn verify_block_list ( & self , sanity_list : & mut Vec < Block > ) {
59+ if !sanity_list. iter ( ) . map ( |b| * b) . eq ( BlockListIterator { cursor : self . first } ) {
60+ eprintln ! ( "Sanity block list: {:?}" , sanity_list) ;
61+ eprintln ! ( "First {:?}" , sanity_list. get( 0 ) ) ;
62+ eprintln ! ( "Actual block list: {:?}" , self ) ;
63+ eprintln ! ( "First {:?}" , self . first) ;
64+ panic ! ( "Incorrect block list" ) ;
3065 }
3166 }
3267
3368 /// List has no blocks
3469 pub fn is_empty ( & self ) -> bool {
35- self . first . is_none ( )
70+ let ret = self . first . is_none ( ) ;
71+
72+ #[ cfg( feature = "ms_block_list_sanity" ) ]
73+ {
74+ let mut sanity_list = self . sanity_list . lock ( ) . unwrap ( ) ;
75+ self . verify_block_list ( & mut sanity_list) ;
76+ assert_eq ! ( sanity_list. is_empty( ) , ret) ;
77+ }
78+
79+ ret
3680 }
3781
3882 /// Remove a block from the list
@@ -57,11 +101,22 @@ impl BlockList {
57101 next. store_prev_block ( prev) ;
58102 }
59103 }
104+
105+ #[ cfg( feature = "ms_block_list_sanity" ) ]
106+ {
107+ let mut sanity_list = self . sanity_list . lock ( ) . unwrap ( ) ;
108+ if let Some ( ( index, _) ) = sanity_list. iter ( ) . enumerate ( ) . find ( |& ( _, & val) | val == block) {
109+ sanity_list. remove ( index) ;
110+ } else {
111+ panic ! ( "Cannot find {:?} in the block list" , block) ;
112+ }
113+ self . verify_block_list ( & mut sanity_list) ;
114+ }
60115 }
61116
62117 /// Pop the first block in the list
63118 pub fn pop ( & mut self ) -> Option < Block > {
64- if let Some ( head) = self . first {
119+ let ret = if let Some ( head) = self . first {
65120 if let Some ( next) = head. load_next_block ( ) {
66121 self . first = Some ( next) ;
67122 next. clear_prev_block ( ) ;
@@ -75,7 +130,21 @@ impl BlockList {
75130 Some ( head)
76131 } else {
77132 None
133+ } ;
134+
135+ #[ cfg( feature = "ms_block_list_sanity" ) ]
136+ {
137+ let mut sanity_list = self . sanity_list . lock ( ) . unwrap ( ) ;
138+ let sanity_ret = if sanity_list. is_empty ( ) {
139+ None
140+ } else {
141+ Some ( sanity_list. remove ( 0 ) ) // pop first
142+ } ;
143+ self . verify_block_list ( & mut sanity_list) ;
144+ assert_eq ! ( sanity_ret, ret) ;
78145 }
146+
147+ ret
79148 }
80149
81150 /// Push block to the front of the list
@@ -93,10 +162,28 @@ impl BlockList {
93162 self . first = Some ( block) ;
94163 }
95164 block. store_block_list ( self ) ;
165+
166+ #[ cfg( feature = "ms_block_list_sanity" ) ]
167+ {
168+ let mut sanity_list = self . sanity_list . lock ( ) . unwrap ( ) ;
169+ sanity_list. insert ( 0 , block) ; // push front
170+ self . verify_block_list ( & mut sanity_list) ;
171+ }
96172 }
97173
98174 /// Moves all the blocks of `other` into `self`, leaving `other` empty.
99175 pub fn append ( & mut self , other : & mut BlockList ) {
176+ #[ cfg( feature = "ms_block_list_sanity" ) ]
177+ {
178+ // Check before merging
179+ let mut sanity_list = self . sanity_list . lock ( ) . unwrap ( ) ;
180+ self . verify_block_list ( & mut sanity_list) ;
181+ let mut sanity_list_other = other. sanity_list . lock ( ) . unwrap ( ) ;
182+ other. verify_block_list ( & mut sanity_list_other) ;
183+ }
184+ #[ cfg( feature = "ms_block_list_sanity" ) ]
185+ let mut sanity_list_in_other = other. sanity_list . lock ( ) . unwrap ( ) . clone ( ) ;
186+
100187 debug_assert_eq ! ( self . size, other. size) ;
101188 if !other. is_empty ( ) {
102189 debug_assert ! (
@@ -128,12 +215,25 @@ impl BlockList {
128215 }
129216 other. reset ( ) ;
130217 }
218+
219+ #[ cfg( feature = "ms_block_list_sanity" ) ]
220+ {
221+ let mut sanity_list = self . sanity_list . lock ( ) . unwrap ( ) ;
222+ sanity_list. append ( & mut sanity_list_in_other) ;
223+ self . verify_block_list ( & mut sanity_list) ;
224+ }
131225 }
132226
133227 /// Remove all blocks
134228 fn reset ( & mut self ) {
135229 self . first = None ;
136230 self . last = None ;
231+
232+ #[ cfg( feature = "ms_block_list_sanity" ) ]
233+ {
234+ let mut sanity_list = self . sanity_list . lock ( ) . unwrap ( ) ;
235+ sanity_list. clear ( ) ;
236+ }
137237 }
138238
139239 /// Lock the list. The MiMalloc allocator mostly uses thread-local block lists, and those operations on the list
@@ -172,6 +272,24 @@ impl BlockList {
172272 }
173273 }
174274 }
275+
276+ /// Get the size of this block list.
277+ pub fn size ( & self ) -> usize {
278+ let ret = self . size ;
279+
280+ #[ cfg( feature = "ms_block_list_sanity" ) ]
281+ {
282+ let mut sanity_list = self . sanity_list . lock ( ) . unwrap ( ) ;
283+ self . verify_block_list ( & mut sanity_list) ;
284+ }
285+
286+ ret
287+ }
288+
289+ /// Get the first block in the list.
290+ pub fn first ( & self ) -> Option < Block > {
291+ self . first
292+ }
175293}
176294
177295pub struct BlockListIterator {
0 commit comments