pub(crate) mod slot; mod stack; pub(crate) useself::slot::Slot; use std::{fmt, marker::PhantomData};
/// A page address encodes the location of a slot within a shard (the page /// number and offset within that page) as a single linear value. #[repr(transparent)] pub(crate) struct Addr<C: cfg::Config = cfg::DefaultConfig> {
addr: usize,
_cfg: PhantomData<fn(C)>,
}
pub(crate) fn index(self) -> usize { // Since every page is twice as large as the previous page, and all page sizes // are powers of two, we can determine the page index that contains a given // address by counting leading zeros, which tells us what power of two // the offset fits into. // // First, we must shift down to the smallest page size, so that the last // offset on the first page becomes 0. let shifted = (self.addr + C::INITIAL_SZ) >> C::ADDR_INDEX_SHIFT; // Now, we can determine the number of twos places by counting the // number of leading zeros (unused twos places) in the number's binary // representation, and subtracting that count from the total number of bits in a word.
cfg::WIDTH - shifted.leading_zeros() as usize
}
pub(crate) struct Local { /// Index of the first slot on the local free list
head: UnsafeCell<usize>,
}
pub(crate) struct Shared<T, C> { /// The remote free list /// /// Slots freed from a remote thread are pushed onto this list.
remote: stack::TransferStack<C>, // Total size of the page. // // If the head index of the local or remote free list is greater than the size of the // page, then that free list is emtpy. If the head of both free lists is greater than `size` // then there are no slots left in that page.
size: usize,
prev_sz: usize,
slab: UnsafeCell<Option<Slots<T, C>>>,
}
/// Return the head of the freelist /// /// If there is space on the local list, it returns the head of the local list. Otherwise, it /// pops all the slots from the global list and returns the head of that list /// /// *Note*: The local list's head is reset when setting the new state in the slot pointed to be /// `head` returned from this function #[inline] fn pop(&self, local: &Local) -> Option<usize> { let head = local.head();
test_println!("-> local head {:?}", head);
// are there any items on the local free list? (fast path) let head = if head < self.size {
head
} else { // slow path: if the local free list is empty, pop all the items on // the remote free list. let head = self.remote.pop_all();
test_println!("-> remote head {:?}", head);
head?
};
// if the head is still null, both the local and remote free lists are // empty --- we can't fit any more items on this page. if head == Self::NULL {
test_println!("-> NULL! {:?}", head);
None
} else {
Some(head)
}
}
/// Returns `true` if storage is currently allocated for this page, `false` /// otherwise. #[inline] fn is_unallocated(&self) -> bool { self.slab.with(|s| unsafe { (*s).is_none() })
}
// Need this function separately, as we need to pass a function pointer to `filter_map` and // `Slot::value` just returns a `&T`, specifically a `&Option<T>` for this impl. fn make_ref(slot: &'a Slot<Option<T>, C>) -> Option<&'a T> {
slot.value().as_ref()
}
// do we need to allocate storage for this page? ifself.is_unallocated() { self.allocate();
}
let index = head + self.prev_sz;
let result = self.slab.with(|slab| { let slab = unsafe { &*(slab) }
.as_ref()
.expect("page must have been allocated to insert!"); let slot = &slab[head]; let result = init(index, slot)?;
local.set_head(slot.next());
Some(result)
})?;
test_println!("-> init_with: insert at offset: {}", index);
Some(result)
}
/// Allocates storage for the page's slots. #[cold] fn allocate(&self) {
test_println!("-> alloc new page ({})", self.size);
debug_assert!(self.is_unallocated());
letmut slab = Vec::with_capacity(self.size);
slab.extend((1..self.size).map(Slot::new));
slab.push(Slot::new(Self::NULL)); self.slab.with_mut(|s| { // safety: this mut access is safe — it only occurs to initially allocate the page, // which only happens on this thread; if the page has not yet been allocated, other // threads will not try to access it yet. unsafe {
*s = Some(slab.into_boxed_slice());
}
});
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.