Skip to main content

storage_device/
buffer_allocator.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::buffer::{
6    Buffer, BufferAllocator as BufferAllocatorTrait, OwnedBuffer, round_down, round_up,
7};
8use event_listener::{Event, EventListener, Listener as _};
9use fuchsia_sync::Mutex;
10use futures::{Future, FutureExt as _};
11use std::collections::BTreeMap;
12use std::ops::Range;
13use std::pin::Pin;
14use std::sync::Arc;
15use std::task::{Context, Poll};
16
17#[cfg(target_os = "fuchsia")]
18mod buffer_source {
19    use fuchsia_runtime::vmar_root_self;
20    use std::ops::Range;
21    use std::sync::Arc;
22    use storage_ptr_slice::MutPtrByteSlice;
23
24    /// A buffer source backed by a VMO.
25    #[derive(Debug)]
26    pub struct BufferSource {
27        base: *mut u8,
28        size: usize,
29        vmo: Arc<zx::Vmo>,
30    }
31
32    // SAFETY: This is required for the *mut u8 which is just the base address of the VMO mapping
33    // and doesn't stop us making BufferSource Send and Sync.
34    unsafe impl Send for BufferSource {}
35    unsafe impl Sync for BufferSource {}
36
37    impl BufferSource {
38        pub fn new(size: usize) -> Self {
39            let vmo = Arc::new(zx::Vmo::create(size as u64).unwrap());
40            let name = zx::Name::new("transfer-buf").unwrap();
41            vmo.set_name(&name).unwrap();
42            let flags = zx::VmarFlags::PERM_READ
43                | zx::VmarFlags::PERM_WRITE
44                | zx::VmarFlags::MAP_RANGE
45                | zx::VmarFlags::REQUIRE_NON_RESIZABLE;
46            let base = vmar_root_self().map(0, &vmo, 0, size, flags).unwrap() as *mut u8;
47            Self { base, size, vmo }
48        }
49
50        pub fn slice(&self) -> *mut [u8] {
51            std::ptr::slice_from_raw_parts_mut(self.base, self.size)
52        }
53
54        pub fn size(&self) -> usize {
55            self.size
56        }
57
58        pub fn vmo(&self) -> &Arc<zx::Vmo> {
59            &self.vmo
60        }
61
62        /// Returns a mutable pointer slice for the given range.
63        ///
64        /// # Safety
65        ///
66        /// The caller must ensure that no other active references or pointer slices overlap with
67        /// this range.
68        pub(super) unsafe fn subslice_ptr(&self, range: &Range<usize>) -> MutPtrByteSlice<'_> {
69            assert!(range.start < self.size && range.end <= self.size);
70            // SAFETY: The base pointer is valid for `size` bytes, and `range` is within bounds.
71            // The caller guarantees exclusivity.
72            unsafe {
73                MutPtrByteSlice::new(std::ptr::slice_from_raw_parts_mut(
74                    self.base.add(range.start),
75                    range.len(),
76                ))
77            }
78        }
79
80        /// Returns a mutable pointer slice with an arbitrary lifetime `'a` for the given range.
81        ///
82        /// # Safety
83        ///
84        /// The caller must ensure that no other active references or pointer slices overlap with
85        /// this range, and that `self` remains valid and mapped in memory for the entire lifetime
86        /// `'a`.
87        pub(super) unsafe fn subslice_ptr_unbounded<'a>(
88            &self,
89            range: &Range<usize>,
90        ) -> MutPtrByteSlice<'a> {
91            assert!(range.start < self.size && range.end <= self.size);
92            // SAFETY: The base pointer is valid for `size` bytes, and `range` is within bounds.
93            // The caller guarantees exclusivity and memory liveness for `'a`.
94            unsafe {
95                MutPtrByteSlice::new(std::ptr::slice_from_raw_parts_mut(
96                    self.base.add(range.start),
97                    range.len(),
98                ))
99            }
100        }
101
102        /// Commits the range in memory to avoid future page faults.
103        pub fn commit_range(&self, range: Range<usize>) -> Result<(), zx::Status> {
104            self.vmo.op_range(zx::VmoOp::COMMIT, range.start as u64, range.len() as u64)
105        }
106
107        /// Zeroes out the range so the kerne can reclaim the pages.
108        ///
109        /// # Safety
110        ///
111        /// The range must not be allocated.
112        pub(super) unsafe fn clean_range(&self, range: Range<usize>) {
113            let _ = self.vmo.op_range(zx::VmoOp::ZERO, range.start as u64, range.len() as u64);
114        }
115    }
116
117    impl Drop for BufferSource {
118        fn drop(&mut self) {
119            // SAFETY: This balances the `map` in `new` above.
120            unsafe {
121                let _ = vmar_root_self().unmap(self.base as usize, self.size);
122            }
123        }
124    }
125}
126
127#[cfg(not(target_os = "fuchsia"))]
128mod buffer_source {
129    use std::cell::UnsafeCell;
130    use std::ops::Range;
131    use std::pin::Pin;
132    use storage_ptr_slice::MutPtrByteSlice;
133
134    /// A basic heap-backed buffer source.
135    #[derive(Debug)]
136    pub struct BufferSource {
137        // We use an UnsafeCell here because we need interior mutability of the buffer (to hand out
138        // mutable slices to it in |buffer()|), but don't want to pay the cost of wrapping the
139        // buffer in a Mutex. We must guarantee that the Buffer objects we hand out don't overlap,
140        // but that is already a requirement for correctness.
141        data: UnsafeCell<Pin<Vec<u8>>>,
142    }
143
144    // Safe because none of the fields in BufferSource are modified, except the contents of `data`,
145    // but that is managed by the BufferAllocator.
146    unsafe impl Sync for BufferSource {}
147
148    impl BufferSource {
149        pub fn new(size: usize) -> Self {
150            Self { data: UnsafeCell::new(Pin::new(vec![0 as u8; size])) }
151        }
152
153        pub fn size(&self) -> usize {
154            // Safe because the reference goes out of scope as soon as we use it.
155            unsafe { (&*self.data.get()).len() }
156        }
157
158        /// Returns a mutable pointer slice for the given range.
159        ///
160        /// # Safety
161        ///
162        /// The caller must ensure that no other active references or pointer slices overlap with
163        /// this range.
164        pub(super) unsafe fn subslice_ptr(&self, range: &Range<usize>) -> MutPtrByteSlice<'_> {
165            assert!(range.start < self.size() && range.end <= self.size());
166            // SAFETY: The data vector is valid for `size()` bytes, and `range` is within bounds.
167            // The caller guarantees exclusivity.
168            unsafe {
169                let ptr = (&mut *self.data.get()).as_mut_ptr().add(range.start);
170                MutPtrByteSlice::new(std::ptr::slice_from_raw_parts_mut(ptr, range.len()))
171            }
172        }
173
174        /// Returns a mutable pointer slice with an arbitrary lifetime `'a` for the given range.
175        ///
176        /// # Safety
177        ///
178        /// The caller must ensure that no other active references or pointer slices overlap with
179        /// this range, and that `self` remains valid and mapped in memory for the entire lifetime
180        /// `'a`.
181        pub(super) unsafe fn subslice_ptr_unbounded<'a>(
182            &self,
183            range: &Range<usize>,
184        ) -> MutPtrByteSlice<'a> {
185            assert!(range.start < self.size() && range.end <= self.size());
186            // SAFETY: The data vector is valid for `size()` bytes, and `range` is within bounds.
187            // The caller guarantees exclusivity and memory liveness for `'a`.
188            unsafe {
189                let ptr = (&mut *self.data.get()).as_mut_ptr().add(range.start);
190                MutPtrByteSlice::new(std::ptr::slice_from_raw_parts_mut(ptr, range.len()))
191            }
192        }
193
194        /// Zeroes out the range.
195        ///
196        /// # Safety
197        ///
198        /// The range must not be allocated.
199        pub(super) unsafe fn clean_range(&self, range: Range<usize>) {
200            // SAFETY: The caller guarantees the range is not allocated.
201            unsafe { self.subslice_ptr(&range) }.fill(0);
202        }
203    }
204}
205
206pub use buffer_source::BufferSource;
207
208// Stores a list of offsets into a BufferSource. The size of the free ranges is determined by which
209// FreeList we are looking at.
210// FreeLists are sorted.
211type FreeList = Vec<usize>;
212
213#[derive(Debug)]
214struct Inner {
215    // The index corresponds to the order of free memory blocks in the free list.
216    free_lists: Vec<FreeList>,
217    // Maps offsets to allocated length (the actual length, not the size requested by the client).
218    allocation_map: BTreeMap<usize, usize>,
219}
220
221/// BufferAllocator creates Buffer objects to be used for block device I/O requests.
222///
223/// This is implemented through a simple buddy allocation scheme.
224#[derive(Debug)]
225pub struct BufferAllocator {
226    block_size: usize,
227    source: BufferSource,
228    inner: Mutex<Inner>,
229    event: Event,
230}
231
232// Returns the smallest order which is at least `size` bytes.
233fn order(size: usize, block_size: usize) -> usize {
234    if size <= block_size {
235        return 0;
236    }
237    let nblocks = round_up(size, block_size) / block_size;
238    nblocks.next_power_of_two().trailing_zeros() as usize
239}
240
241// Returns the largest order which is no more than `size` bytes.
242fn order_fit(size: usize, block_size: usize) -> usize {
243    assert!(size >= block_size);
244    let nblocks = round_up(size, block_size) / block_size;
245    if nblocks.is_power_of_two() {
246        nblocks.trailing_zeros() as usize
247    } else {
248        nblocks.next_power_of_two().trailing_zeros() as usize - 1
249    }
250}
251
252fn size_for_order(order: usize, block_size: usize) -> usize {
253    block_size * (1 << (order as u32))
254}
255
256fn initial_free_lists(size: usize, block_size: usize) -> Vec<FreeList> {
257    let size = round_down(size, block_size);
258    assert!(block_size <= size);
259    assert!(block_size.is_power_of_two());
260    let max_order = order_fit(size, block_size);
261    let mut free_lists = Vec::with_capacity(max_order + 1);
262    for _ in 0..=max_order {
263        free_lists.push(FreeList::new())
264    }
265    let mut offset = 0;
266    while offset < size {
267        let order = order_fit(size - offset, block_size);
268        let size = size_for_order(order, block_size);
269        free_lists[order].push(offset);
270        offset += size;
271    }
272    free_lists
273}
274
275/// A future which will resolve to an allocated [`Buffer`].
276pub struct BufferFuture<'a> {
277    allocator: &'a BufferAllocator,
278    size: usize,
279    listener: Option<EventListener>,
280}
281
282impl<'a> Future for BufferFuture<'a> {
283    type Output = Buffer<'a>;
284
285    fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
286        if let Some(listener) = self.listener.as_mut() {
287            futures::ready!(listener.poll_unpin(context));
288        }
289        // Loop because we need to deal with the case where `listener` is ready immediately upon
290        // creation, in which case we ought to retry the allocation.
291        loop {
292            match self.allocator.try_allocate_buffer(self.size) {
293                Ok(buffer) => return Poll::Ready(buffer),
294                Err(mut listener) => {
295                    if listener.poll_unpin(context).is_pending() {
296                        self.listener = Some(listener);
297                        return Poll::Pending;
298                    }
299                }
300            }
301        }
302    }
303}
304
305impl BufferAllocator {
306    pub fn new(block_size: usize, source: BufferSource) -> Self {
307        let free_lists = initial_free_lists(source.size(), block_size);
308        Self {
309            block_size,
310            source,
311            inner: Mutex::new(Inner { free_lists, allocation_map: BTreeMap::new() }),
312            event: Event::new(),
313        }
314    }
315
316    pub fn block_size(&self) -> usize {
317        self.block_size
318    }
319
320    pub fn buffer_source(&self) -> &BufferSource {
321        &self.source
322    }
323
324    /// Takes the buffer source from the allocator and consumes the allocator.
325    pub fn take_buffer_source(self) -> BufferSource {
326        self.source
327    }
328
329    /// Allocates a Buffer with capacity for `size` bytes. Blocks until there are enough bytes
330    /// available to satisfy the request.
331    ///
332    /// The allocated buffer will be block-aligned and the padding up to block alignment can also
333    /// be used by the buffer.
334    ///
335    /// Allocation is O(lg(N) + M), where N = size and M = number of allocations.
336    ///
337    /// # Panics
338    ///
339    /// Panics if `size` exceeds the pool size (`self.buffer_source().size()`).
340    pub fn allocate_buffer(&self, size: usize) -> BufferFuture<'_> {
341        BufferFuture { allocator: self, size, listener: None }
342    }
343
344    /// Allocates a Buffer with capacity for `size` bytes synchronously. Blocks the current thread
345    /// until enough memory is available.
346    ///
347    /// # Panics
348    ///
349    /// Panics if `size` exceeds the pool size (`self.buffer_source().size()`).
350    pub fn allocate_buffer_sync(&self, size: usize) -> Buffer<'_> {
351        loop {
352            match self.try_allocate_buffer(size) {
353                Ok(buffer) => return buffer,
354                Err(listener) => listener.wait(),
355            }
356        }
357    }
358
359    /// Allocates an OwnedBuffer with capacity for `size` bytes synchronously. Blocks the current
360    /// thread until enough memory is available.
361    ///
362    /// # Panics
363    ///
364    /// Panics if `size` exceeds the pool size (`self.buffer_source().size()`).
365    pub fn allocate_buffer_sync_owned(self: &Arc<Self>, size: usize) -> OwnedBuffer {
366        loop {
367            match self.try_allocate_buffer_owned(size) {
368                Ok(buffer) => return buffer,
369                Err(listener) => listener.wait(),
370            }
371        }
372    }
373
374    /// Allocates an OwnedBuffer non-blockingly, returning an EventListener if memory is
375    /// unavailable.
376    ///
377    /// # Panics
378    ///
379    /// Panics if `size` exceeds the pool size (`self.buffer_source().size()`).
380    pub fn try_allocate_buffer_owned(
381        self: &Arc<Self>,
382        size: usize,
383    ) -> Result<OwnedBuffer, EventListener> {
384        let buffer = self.try_allocate_buffer(size)?;
385        let range = buffer.range();
386        // SAFETY: `try_allocate_buffer` guarantees that `range` does not overlap with any other
387        // active allocations. We hold `Arc<Self>` (`self.clone()`), which guarantees that
388        // `self.source` remains valid and mapped in memory for the entire `'static` existence of
389        // `OwnedBuffer`.
390        let slice = unsafe { self.source.subslice_ptr_unbounded(&range) };
391        std::mem::forget(buffer);
392        Ok(OwnedBuffer::new(slice, range, self.clone() as Arc<dyn BufferAllocatorTrait>))
393    }
394
395    /// Like `allocate_buffer`, but returns an EventListener if the allocation cannot be satisfied.
396    /// The listener will signal when the caller should try again.
397    ///
398    /// # Panics
399    ///
400    /// Panics if `size` exceeds the pool size (`self.buffer_source().size()`).
401    pub fn try_allocate_buffer(&self, size: usize) -> Result<Buffer<'_>, EventListener> {
402        if size > self.source.size() {
403            panic!("Allocation of {} bytes would exceed limit {}", size, self.source.size());
404        }
405        let mut inner = self.inner.lock();
406        let requested_order = order(size, self.block_size());
407        assert!(requested_order < inner.free_lists.len());
408        // Pick the smallest possible order with a free entry.
409        let mut order = {
410            let mut idx = requested_order;
411            loop {
412                if idx >= inner.free_lists.len() {
413                    return Err(self.event.listen());
414                }
415                if !inner.free_lists[idx].is_empty() {
416                    break idx;
417                }
418                idx += 1;
419            }
420        };
421
422        // Split the free region until it's the right size.
423        let offset = inner.free_lists[order].pop().unwrap();
424        while order > requested_order {
425            order -= 1;
426            assert!(inner.free_lists[order].is_empty());
427            inner.free_lists[order].push(offset + self.size_for_order(order));
428        }
429
430        inner.allocation_map.insert(offset, self.size_for_order(order));
431        let range = offset..offset + size;
432        log::debug!(range:?, bytes_used = self.size_for_order(order); "Allocated");
433
434        // SAFETY: The allocator guarantees that this range does not overlap with any other
435        // active allocations. `self` guarantees `self.source` remains valid for `'a`.
436        Ok(Buffer::new(unsafe { self.source.subslice_ptr(&range) }, range, self))
437    }
438}
439
440impl BufferAllocatorTrait for BufferAllocator {
441    fn free_buffer(&self, range: Range<usize>) {
442        self.free_buffer(range);
443    }
444}
445
446impl BufferAllocator {
447    /// Deallocation is O(lg(N) + M), where N = size and M = number of allocations.
448    #[doc(hidden)]
449    pub(super) fn free_buffer(&self, range: Range<usize>) {
450        let mut inner = self.inner.lock();
451        let mut offset = range.start;
452        let size = inner
453            .allocation_map
454            .remove(&offset)
455            .unwrap_or_else(|| panic!("No allocation record found for {:?}", range));
456        assert!(range.end - range.start <= size);
457        log::debug!(range:?, bytes_used = size; "Freeing");
458
459        // Merge as many free slots as we can.
460        let mut order = order(size, self.block_size());
461        while order < inner.free_lists.len() - 1 {
462            let buddy = self.find_buddy(offset, order);
463            let idx = if let Ok(idx) = inner.free_lists[order].binary_search(&buddy) {
464                idx
465            } else {
466                break;
467            };
468            inner.free_lists[order].remove(idx);
469            offset = std::cmp::min(offset, buddy);
470            order += 1;
471        }
472
473        let idx = match inner.free_lists[order].binary_search(&offset) {
474            Ok(_) => panic!("Unexpectedly found {} in free list {}", offset, order),
475            Err(idx) => idx,
476        };
477        inner.free_lists[order].insert(idx, offset);
478
479        // Notify all stuck tasks.  This might be inefficient, but it's simple and correct.
480        self.event.notify(usize::MAX);
481    }
482
483    fn size_for_order(&self, order: usize) -> usize {
484        size_for_order(order, self.block_size)
485    }
486
487    fn find_buddy(&self, offset: usize, order: usize) -> usize {
488        offset ^ self.size_for_order(order)
489    }
490
491    /// Zeroes out all unnallocated ranges in the transfer buffer.
492    pub fn clean_transfer_buffer(&self) {
493        let inner = self.inner.lock();
494        for (n, free_list) in inner.free_lists.iter().enumerate() {
495            for offset in free_list {
496                // SAFETY: The range is not allocated.
497                unsafe {
498                    self.source.clean_range(*offset..(*offset + size_for_order(n, self.block_size)))
499                };
500            }
501        }
502    }
503}
504
505#[cfg(test)]
506mod tests {
507    use crate::buffer_allocator::{BufferAllocator, BufferSource, order};
508    use fuchsia_async as fasync;
509    use futures::future::join_all;
510    use futures::pin_mut;
511    use rand::seq::IndexedRandom;
512    use rand::{Rng, rng};
513    use std::sync::Arc;
514    use std::sync::atomic::{AtomicBool, Ordering};
515
516    #[fuchsia::test]
517    async fn test_odd_sized_buffer_source() {
518        let source = BufferSource::new(123);
519        let allocator = BufferAllocator::new(2, source);
520
521        // 123 == 64 + 32 + 16 + 8 + 2 + 1. (The last byte is unusable.)
522        let sizes = vec![64, 32, 16, 8, 2];
523        let mut bufs = vec![];
524        for size in sizes.iter() {
525            bufs.push(allocator.allocate_buffer(*size).await);
526        }
527        for (expected_size, buf) in sizes.iter().zip(bufs.iter()) {
528            assert_eq!(*expected_size, buf.len());
529        }
530        assert!(allocator.try_allocate_buffer(2).is_err());
531    }
532
533    #[fuchsia::test]
534    async fn test_allocate_buffer_read_write() {
535        let source = BufferSource::new(1024 * 1024);
536        let allocator = BufferAllocator::new(8192, source);
537
538        let mut buf = allocator.allocate_buffer(8192).await;
539        buf.as_mut_slice().fill(0xaa as u8);
540        let mut vec = vec![0 as u8; 8192];
541        vec.copy_from_slice(buf.as_slice());
542        assert_eq!(vec, vec![0xaa as u8; 8192]);
543    }
544
545    #[fuchsia::test]
546    async fn test_allocate_buffer_consecutive_calls_do_not_overlap() {
547        let source = BufferSource::new(1024 * 1024);
548        let allocator = BufferAllocator::new(8192, source);
549
550        let buf1 = allocator.allocate_buffer(8192).await;
551        let buf2 = allocator.allocate_buffer(8192).await;
552        assert!(buf1.range().end <= buf2.range().start || buf2.range().end <= buf1.range().start);
553    }
554
555    #[fuchsia::test]
556    async fn test_allocate_many_buffers() {
557        let source = BufferSource::new(1024 * 1024);
558        let allocator = BufferAllocator::new(8192, source);
559
560        for _ in 0..10 {
561            let _ = allocator.allocate_buffer(8192).await;
562        }
563    }
564
565    #[fuchsia::test]
566    async fn test_allocate_small_buffers_dont_overlap() {
567        let source = BufferSource::new(1024 * 1024);
568        let allocator = BufferAllocator::new(8192, source);
569
570        let buf1 = allocator.allocate_buffer(1).await;
571        let buf2 = allocator.allocate_buffer(1).await;
572        assert!(buf1.range().end <= buf2.range().start || buf2.range().end <= buf1.range().start);
573    }
574
575    #[fuchsia::test]
576    async fn test_allocate_large_buffer() {
577        let source = BufferSource::new(1024 * 1024);
578        let allocator = BufferAllocator::new(8192, source);
579
580        let mut buf = allocator.allocate_buffer(1024 * 1024).await;
581        assert_eq!(buf.len(), 1024 * 1024);
582        buf.as_mut_slice().fill(0xaa as u8);
583        let mut vec = vec![0 as u8; 1024 * 1024];
584        vec.copy_from_slice(buf.as_slice());
585        assert_eq!(vec, vec![0xaa as u8; 1024 * 1024]);
586    }
587
588    #[fuchsia::test]
589    async fn test_allocate_large_buffer_after_smaller_buffers() {
590        let source = BufferSource::new(1024 * 1024);
591        let allocator = BufferAllocator::new(8192, source);
592
593        {
594            let mut buffers = vec![];
595            while let Ok(buffer) = allocator.try_allocate_buffer(8192) {
596                buffers.push(buffer);
597            }
598        }
599        let buf = allocator.allocate_buffer(1024 * 1024).await;
600        assert_eq!(buf.len(), 1024 * 1024);
601    }
602
603    #[fuchsia::test]
604    async fn test_allocate_at_limits() {
605        let source = BufferSource::new(1024 * 1024);
606        let allocator = BufferAllocator::new(8192, source);
607
608        let mut buffers = vec![];
609        while let Ok(buffer) = allocator.try_allocate_buffer(8192) {
610            buffers.push(buffer);
611        }
612        // Deallocate a single buffer, and reallocate a single one back.
613        buffers.pop();
614        let buf = allocator.allocate_buffer(8192).await;
615        assert_eq!(buf.len(), 8192);
616    }
617
618    #[fuchsia::test(threads = 10)]
619    async fn test_random_allocs_deallocs() {
620        let source = BufferSource::new(16 * 1024 * 1024);
621        let bs = 512;
622        let allocator = Arc::new(BufferAllocator::new(bs, source));
623
624        join_all((0..10).map(|_| {
625            let allocator = allocator.clone();
626            fasync::Task::spawn(async move {
627                let mut rng = rng();
628                enum Op {
629                    Alloc,
630                    Dealloc,
631                }
632                let ops = vec![Op::Alloc, Op::Dealloc];
633                let mut buffers = vec![];
634                for _ in 0..1000 {
635                    match ops.choose(&mut rng).unwrap() {
636                        Op::Alloc => {
637                            // Rather than a uniform distribution 1..64K, first pick an order and
638                            // then pick a size within that. For example, we might pick order 3,
639                            // which would give us 8 * 512..16 * 512 as our possible range.
640                            // This way we don't bias towards larger allocations too much.
641                            let order: usize = rng.random_range(order(1, bs)..order(65536 + 1, bs));
642                            let size: usize = rng.random_range(
643                                bs * 2_usize.pow(order as u32)..bs * 2_usize.pow(order as u32 + 1),
644                            );
645                            if let Ok(mut buf) = allocator.try_allocate_buffer(size) {
646                                let val = rng.random::<u8>();
647                                buf.as_mut_slice().fill(val);
648                                for v in buf.as_slice() {
649                                    assert_eq!(v, &val);
650                                }
651                                buffers.push(buf);
652                            }
653                        }
654                        Op::Dealloc if !buffers.is_empty() => {
655                            let idx = rng.random_range(0..buffers.len());
656                            buffers.remove(idx);
657                        }
658                        _ => {}
659                    };
660                }
661            })
662        }))
663        .await;
664    }
665
666    #[fuchsia::test]
667    async fn test_buffer_refs() {
668        let source = BufferSource::new(1024 * 1024);
669        let allocator = BufferAllocator::new(512, source);
670
671        // Allocate one buffer first so that `buf` is not starting at offset 0. This helps catch
672        // bugs.
673        let _buf = allocator.allocate_buffer(512).await;
674        let mut buf = allocator.allocate_buffer(4096).await;
675        let base = buf.range().start;
676        {
677            let mut bref = buf.subslice_mut(1000..2000);
678            assert_eq!(bref.len(), 1000);
679            assert_eq!(bref.range(), base + 1000..base + 2000);
680            bref.as_mut_slice().fill(0xbb);
681            {
682                let mut bref2 = bref.reborrow().subslice_mut(0..100);
683                assert_eq!(bref2.len(), 100);
684                assert_eq!(bref2.range(), base + 1000..base + 1100);
685                bref2.as_mut_slice().fill(0xaa);
686            }
687            {
688                let mut bref2 = bref.reborrow().subslice_mut(900..1000);
689                assert_eq!(bref2.len(), 100);
690                assert_eq!(bref2.range(), base + 1900..base + 2000);
691                bref2.as_mut_slice().fill(0xcc);
692            }
693            assert_eq!(bref.as_slice()[..100], vec![0xaa; 100]);
694            assert_eq!(bref.as_slice()[100..900], vec![0xbb; 800]);
695
696            let bref = bref.subslice_mut(900..);
697            assert_eq!(bref.len(), 100);
698            assert_eq!(bref.as_slice(), vec![0xcc; 100]);
699        }
700        {
701            let bref = buf.as_ref();
702            assert_eq!(bref.len(), 4096);
703            assert_eq!(bref.range(), base..base + 4096);
704            assert_eq!(bref.as_slice()[0..1000], vec![0x00; 1000]);
705            {
706                let bref2 = bref.subslice(1000..2000);
707                assert_eq!(bref2.len(), 1000);
708                assert_eq!(bref2.range(), base + 1000..base + 2000);
709                assert_eq!(bref2.as_slice()[..100], vec![0xaa; 100]);
710                assert_eq!(bref2.as_slice()[100..900], vec![0xbb; 800]);
711                assert_eq!(bref2.as_slice()[900..1000], vec![0xcc; 100]);
712            }
713
714            let bref = bref.subslice(2048..);
715            assert_eq!(bref.len(), 2048);
716            assert_eq!(bref.as_slice(), vec![0x00; 2048]);
717        }
718    }
719
720    #[fuchsia::test]
721    async fn test_buffer_split() {
722        let source = BufferSource::new(1024 * 1024);
723        let allocator = BufferAllocator::new(512, source);
724
725        // Allocate one buffer first so that `buf` is not starting at offset 0. This helps catch
726        // bugs.
727        let _buf = allocator.allocate_buffer(512).await;
728        let mut buf = allocator.allocate_buffer(4096).await;
729        let base = buf.range().start;
730        {
731            let bref = buf.as_mut();
732            let (mut s1, mut s2) = bref.split_at_mut(2048);
733            assert_eq!(s1.len(), 2048);
734            assert_eq!(s1.range(), base..base + 2048);
735            s1.as_mut_slice().fill(0xaa);
736            assert_eq!(s2.len(), 2048);
737            assert_eq!(s2.range(), base + 2048..base + 4096);
738            s2.as_mut_slice().fill(0xbb);
739        }
740        {
741            let bref = buf.as_ref();
742            let (s1, s2) = bref.split_at(1);
743            let (s2, s3) = s2.split_at(2047);
744            let (s3, s4) = s3.split_at(0);
745            assert_eq!(s1.len(), 1);
746            assert_eq!(s1.range(), base..base + 1);
747            assert_eq!(s2.len(), 2047);
748            assert_eq!(s2.range(), base + 1..base + 2048);
749            assert_eq!(s3.len(), 0);
750            assert_eq!(s3.range(), base + 2048..base + 2048);
751            assert_eq!(s4.len(), 2048);
752            assert_eq!(s4.range(), base + 2048..base + 4096);
753            assert_eq!(s1.as_slice(), vec![0xaa; 1]);
754            assert_eq!(s2.as_slice(), vec![0xaa; 2047]);
755            assert_eq!(s3.as_slice(), &[] as &[u8]);
756            assert_eq!(s4.as_slice(), vec![0xbb; 2048]);
757        }
758    }
759
760    #[fuchsia::test]
761    async fn test_blocking_allocation() {
762        let source = BufferSource::new(1024 * 1024);
763        let allocator = Arc::new(BufferAllocator::new(512, source));
764
765        let buf1 = allocator.allocate_buffer(512 * 1024).await;
766        let buf2 = allocator.allocate_buffer(512 * 1024).await;
767        let bufs_dropped = Arc::new(AtomicBool::new(false));
768
769        // buf3_fut should block until both buf1 and buf2 are done.
770        let allocator_clone = allocator.clone();
771        let bufs_dropped_clone = bufs_dropped.clone();
772        let buf3_fut = async move {
773            allocator_clone.allocate_buffer(1024 * 1024).await;
774            assert!(bufs_dropped_clone.load(Ordering::Relaxed), "Allocation finished early");
775        };
776        pin_mut!(buf3_fut);
777
778        // Each of buf_futs should block until buf3_fut is done, and they should proceed in order.
779        let mut buf_futs = vec![];
780        for _ in 0..16 {
781            let allocator_clone = allocator.clone();
782            let bufs_dropped_clone = bufs_dropped.clone();
783            let fut = async move {
784                allocator_clone.allocate_buffer(64 * 1024).await;
785                // We can't say with certainty that buf3 proceeded first, nor can we ensure these
786                // allocations proceed in order, but we can make sure that at least buf1/buf2 were
787                // done (since they exhausted the pool).
788                assert!(bufs_dropped_clone.load(Ordering::Relaxed), "Allocation finished early");
789            };
790            buf_futs.push(fut);
791        }
792
793        futures::join!(buf3_fut, join_all(buf_futs), async move {
794            std::mem::drop(buf1);
795            std::mem::drop(buf2);
796            bufs_dropped.store(true, Ordering::Relaxed);
797        });
798    }
799
800    #[fuchsia::test]
801    async fn test_clean_entire_transfer_buffer() {
802        const BUFFER_SIZE: usize = 4096;
803        let source = BufferSource::new(BUFFER_SIZE);
804        let allocator = Arc::new(BufferAllocator::new(512, source));
805
806        let mut buf = allocator.allocate_buffer(BUFFER_SIZE).await;
807        buf.as_mut_slice().fill(0xaa);
808        std::mem::drop(buf);
809
810        allocator.clean_transfer_buffer();
811        let buf = allocator.allocate_buffer(BUFFER_SIZE).await;
812        assert_eq!(buf.as_slice(), vec![0; BUFFER_SIZE]);
813    }
814
815    #[fuchsia::test]
816    async fn test_clean_transfer_buffer_around_allocation() {
817        let source = BufferSource::new(4096);
818        let allocator = Arc::new(BufferAllocator::new(512, source));
819
820        let mut buf1 = allocator.allocate_buffer(1024).await;
821        buf1.as_mut_slice().fill(0xaa);
822        let mut buf2 = allocator.allocate_buffer(1024).await;
823        buf2.as_mut_slice().fill(0xbb);
824        assert_eq!(buf2.range().start, 1024);
825        let mut buf3 = allocator.allocate_buffer(2048).await;
826        buf3.as_mut_slice().fill(0xcc);
827        std::mem::drop(buf1);
828        std::mem::drop(buf3);
829
830        allocator.clean_transfer_buffer();
831
832        let buf1 = allocator.allocate_buffer(1024).await;
833        assert_eq!(buf1.as_slice(), vec![0; 1024]);
834
835        assert_eq!(buf2.as_slice(), vec![0xbb; 1024]);
836
837        let buf3 = allocator.allocate_buffer(2048).await;
838        assert_eq!(buf3.as_slice(), vec![0; 2048]);
839    }
840
841    #[fuchsia::test]
842    async fn test_safe_buffer_apis() {
843        let source = BufferSource::new(4096);
844        let allocator = BufferAllocator::new(512, source);
845
846        let mut buf = allocator.allocate_buffer(4096).await;
847
848        // Test copy_from_slice and copy_to_slice
849        let input_data = vec![0x33_u8; 4096];
850        buf.copy_from_slice(&input_data);
851        let mut output_data = vec![0_u8; 4096];
852        buf.copy_to_slice(&mut output_data);
853        assert_eq!(input_data, output_data);
854
855        // Test fill
856        buf.fill(0x55);
857        buf.copy_to_slice(&mut output_data);
858        assert_eq!(output_data, vec![0x55; 4096]);
859
860        // Test subslice
861        {
862            let mut sub_mut = buf.as_mut().subslice_mut(1024..2048);
863            assert_eq!(sub_mut.len(), 1024);
864            sub_mut.fill(0xaa);
865        }
866
867        {
868            let bref = buf.as_ref();
869            let sub_ref = bref.subslice(1024..2048);
870            assert_eq!(sub_ref.len(), 1024);
871            let mut sub_output = vec![0_u8; 1024];
872            sub_ref.copy_to_slice(&mut sub_output);
873            assert_eq!(sub_output, vec![0xaa; 1024]);
874        }
875
876        // Test split_at and split_at_mut
877        {
878            let (mut left_mut, mut right_mut) = buf.as_mut().split_at_mut(2048);
879            assert_eq!(left_mut.len(), 2048);
880            assert_eq!(right_mut.len(), 2048);
881            left_mut.fill(0x11);
882            right_mut.fill(0x22);
883        }
884
885        {
886            let bref = buf.as_ref();
887            let (left_ref, right_ref) = bref.split_at(2048);
888            let mut left_out = vec![0_u8; 2048];
889            let mut right_out = vec![0_u8; 2048];
890            left_ref.copy_to_slice(&mut left_out);
891            right_ref.copy_to_slice(&mut right_out);
892            assert_eq!(left_out, vec![0x11; 2048]);
893            assert_eq!(right_out, vec![0x22; 2048]);
894        }
895    }
896
897    #[fuchsia::test]
898    async fn test_owned_buffer() {
899        let source = BufferSource::new(4096);
900        let allocator = Arc::new(BufferAllocator::new(512, source));
901
902        let mut owned_buf = allocator.allocate_buffer_sync_owned(2048);
903        assert_eq!(owned_buf.len(), 2048);
904        owned_buf.as_mut_slice().fill(0xcc);
905        assert_eq!(owned_buf.as_slice(), vec![0xcc; 2048]);
906
907        // Allocating remaining 2048 bytes should succeed.
908        let owned_buf2 = allocator.try_allocate_buffer_owned(2048).expect("Must succeed");
909        assert_eq!(owned_buf2.len(), 2048);
910
911        // Pool is full (4096 bytes used). Next allocation should return an EventListener.
912        assert!(allocator.try_allocate_buffer_owned(512).is_err());
913
914        // Dropping owned_buf should free its 2048 bytes back to the allocator.
915        std::mem::drop(owned_buf);
916
917        // Now allocation of 2048 bytes should succeed again.
918        let mut owned_buf3 = allocator.try_allocate_buffer_owned(2048).expect("Must succeed");
919        owned_buf3.as_mut_slice().fill(0xdd);
920        assert_eq!(owned_buf3.as_slice(), vec![0xdd; 2048]);
921    }
922
923    #[fuchsia::test]
924    async fn test_allocate_buffer_sync() {
925        let source = BufferSource::new(4096);
926        let allocator = BufferAllocator::new(512, source);
927
928        let mut buf = allocator.allocate_buffer_sync(2048);
929        assert_eq!(buf.len(), 2048);
930        buf.as_mut_slice().fill(0xee);
931        assert_eq!(buf.as_slice(), vec![0xee; 2048]);
932
933        std::mem::drop(buf);
934
935        let mut buf2 = allocator.allocate_buffer_sync(4096);
936        assert_eq!(buf2.len(), 4096);
937        buf2.as_mut_slice().fill(0xff);
938        assert_eq!(buf2.as_slice(), vec![0xff; 4096]);
939    }
940}