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