@@ -4,19 +4,23 @@ use crate::util::linear_scan::Region;
4
4
use crate :: vm:: VMBinding ;
5
5
use std:: sync:: atomic:: AtomicBool ;
6
6
use std:: sync:: atomic:: Ordering ;
7
+ #[ cfg( feature = "ms_block_list_sanity" ) ]
8
+ use std:: sync:: Mutex ;
7
9
8
10
/// List of blocks owned by the allocator
9
11
#[ repr( C ) ]
10
12
pub 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 > > ,
15
19
}
16
20
17
21
impl std:: fmt:: Debug for BlockList {
18
22
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 >>( ) )
20
24
}
21
25
}
22
26
@@ -27,12 +31,52 @@ impl BlockList {
27
31
last : None ,
28
32
size,
29
33
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" ) ;
30
65
}
31
66
}
32
67
33
68
/// List has no blocks
34
69
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
36
80
}
37
81
38
82
/// Remove a block from the list
@@ -57,11 +101,22 @@ impl BlockList {
57
101
next. store_prev_block ( prev) ;
58
102
}
59
103
}
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
+ }
60
115
}
61
116
62
117
/// Pop the first block in the list
63
118
pub fn pop ( & mut self ) -> Option < Block > {
64
- if let Some ( head) = self . first {
119
+ let ret = if let Some ( head) = self . first {
65
120
if let Some ( next) = head. load_next_block ( ) {
66
121
self . first = Some ( next) ;
67
122
next. clear_prev_block ( ) ;
@@ -75,7 +130,21 @@ impl BlockList {
75
130
Some ( head)
76
131
} else {
77
132
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) ;
78
145
}
146
+
147
+ ret
79
148
}
80
149
81
150
/// Push block to the front of the list
@@ -93,10 +162,28 @@ impl BlockList {
93
162
self . first = Some ( block) ;
94
163
}
95
164
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
+ }
96
172
}
97
173
98
174
/// Moves all the blocks of `other` into `self`, leaving `other` empty.
99
175
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
+
100
187
debug_assert_eq ! ( self . size, other. size) ;
101
188
if !other. is_empty ( ) {
102
189
debug_assert ! (
@@ -128,12 +215,25 @@ impl BlockList {
128
215
}
129
216
other. reset ( ) ;
130
217
}
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
+ }
131
225
}
132
226
133
227
/// Remove all blocks
134
228
fn reset ( & mut self ) {
135
229
self . first = None ;
136
230
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
+ }
137
237
}
138
238
139
239
/// Lock the list. The MiMalloc allocator mostly uses thread-local block lists, and those operations on the list
@@ -172,6 +272,24 @@ impl BlockList {
172
272
}
173
273
}
174
274
}
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
+ }
175
293
}
176
294
177
295
pub struct BlockListIterator {
0 commit comments