Skip to content

Commit d2dc7a6

Browse files
warnings about memory, and thread tests
1 parent bb5bb05 commit d2dc7a6

File tree

1 file changed

+45
-11
lines changed

1 file changed

+45
-11
lines changed

src/lib.rs

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! // Create a pool
88
//! let pool = BytePool::new();
99
//!
10-
//! // Allocate a buffer
10+
//! // Allocate a buffer with capacity 1024.
1111
//! let mut buf = pool.alloc(1024);
1212
//!
1313
//! // write some data into it
@@ -37,8 +37,9 @@ pub struct BytePool {
3737
list: Mutex<Vec<Vec<u8>>>,
3838
}
3939

40-
pub type RawBlock = Vec<u8>;
41-
40+
/// The value returned by an allocation of the pool.
41+
/// When it is dropped the memory gets returned into the pool, and is not zeroed.
42+
/// If that is a concern, you must clear the data yourself.
4243
pub struct Block<'a> {
4344
data: mem::ManuallyDrop<Vec<u8>>,
4445
pool: &'a BytePool,
@@ -66,6 +67,8 @@ impl BytePool {
6667

6768
/// Allocates a new `Block`, which represents a fixed sice byte slice.
6869
/// If `Block` is dropped, the memory is _not_ freed, but rather it is returned into the pool.
70+
/// The returned `Block` contains arbitrary data, and must be zeroed or overwritten,
71+
/// in cases this is needed.
6972
pub fn alloc(&self, size: usize) -> Block<'_> {
7073
assert!(size > 0, "Can not allocate empty blocks");
7174

@@ -75,9 +78,10 @@ impl BytePool {
7578
let start = if end > 4 { end - 4 } else { 0 };
7679

7780
for i in start..end {
78-
if lock[i].len() == size {
81+
if lock[i].capacity() == size {
7982
// found one, reuse it
80-
return Block::new(lock.remove(i), self);
83+
let data = lock.remove(i);
84+
return Block::new(data, self);
8185
}
8286
}
8387
drop(lock);
@@ -114,7 +118,10 @@ impl<'a> Block<'a> {
114118
assert!(new_size > 0);
115119
match new_size.cmp(&self.size()) {
116120
Greater => self.data.resize(new_size, 0u8),
117-
Less => self.data.truncate(new_size),
121+
Less => {
122+
self.data.truncate(new_size);
123+
self.shrink_to_fit();
124+
}
118125
Equal => {}
119126
}
120127
}
@@ -179,21 +186,48 @@ mod tests {
179186

180187
let _slice: &[u8] = &buf;
181188

182-
assert_eq!(buf.len(), 10);
183-
for el in buf.iter_mut() {
184-
*el = 1;
189+
assert_eq!(buf.capacity(), 10);
190+
for i in 0..10 {
191+
buf[i] = 1;
185192
}
186193

187194
buf.realloc(512);
188-
assert_eq!(buf.len(), 512);
195+
assert_eq!(buf.capacity(), 512);
189196
for el in buf.iter().take(10) {
190197
assert_eq!(*el, 1);
191198
}
192199

193200
buf.realloc(5);
194-
assert_eq!(buf.len(), 5);
201+
assert_eq!(buf.capacity(), 5);
195202
for el in buf.iter() {
196203
assert_eq!(*el, 1);
197204
}
198205
}
206+
207+
#[test]
208+
fn multi_thread() {
209+
let pool = std::sync::Arc::new(BytePool::new());
210+
211+
let pool1 = pool.clone();
212+
let h1 = std::thread::spawn(move || {
213+
for _ in 0..100 {
214+
let mut buf = pool1.alloc(64);
215+
buf[10] = 10;
216+
}
217+
});
218+
219+
let pool2 = pool.clone();
220+
let h2 = std::thread::spawn(move || {
221+
for _ in 0..100 {
222+
let mut buf = pool2.alloc(64);
223+
buf[10] = 10;
224+
}
225+
});
226+
227+
h1.join().unwrap();
228+
h2.join().unwrap();
229+
230+
// two threads allocating in parallel will need 2 buffers
231+
assert_eq!(pool.list.lock().unwrap().len(), 2);
232+
}
199233
}

0 commit comments

Comments
 (0)