summaryrefslogtreecommitdiffstats
path: root/tokio/src/util/slab/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tokio/src/util/slab/mod.rs')
-rw-r--r--tokio/src/util/slab/mod.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/tokio/src/util/slab/mod.rs b/tokio/src/util/slab/mod.rs
new file mode 100644
index 00000000..e9b53c53
--- /dev/null
+++ b/tokio/src/util/slab/mod.rs
@@ -0,0 +1,109 @@
+//! A lock-free concurrent slab.
+
+mod addr;
+pub(crate) use addr::Address;
+
+mod entry;
+pub(crate) use entry::Entry;
+
+mod generation;
+pub(crate) use generation::Generation;
+
+mod page;
+
+mod shard;
+use shard::Shard;
+
+mod slot;
+use slot::Slot;
+
+mod stack;
+use stack::TransferStack;
+
+#[cfg(all(loom, test))]
+mod tests;
+
+use crate::loom::sync::Mutex;
+use crate::util::bit;
+
+use std::fmt;
+
+#[cfg(target_pointer_width = "64")]
+const MAX_THREADS: usize = 4096;
+
+#[cfg(target_pointer_width = "32")]
+const MAX_THREADS: usize = 2048;
+
+/// Max number of pages per slab
+const MAX_PAGES: usize = bit::pointer_width() as usize / 4;
+
+cfg_not_loom! {
+ /// Size of first page
+ const INITIAL_PAGE_SIZE: usize = 32;
+}
+
+cfg_loom! {
+ const INITIAL_PAGE_SIZE: usize = 2;
+}
+
+/// A sharded slab.
+pub(crate) struct Slab<T> {
+ // Signal shard for now. Eventually there will be more.
+ shard: Shard<T>,
+ local: Mutex<()>,
+}
+
+unsafe impl<T: Send> Send for Slab<T> {}
+unsafe impl<T: Sync> Sync for Slab<T> {}
+
+impl<T: Entry> Slab<T> {
+ /// Returns a new slab with the default configuration parameters.
+ pub(crate) fn new() -> Slab<T> {
+ Slab {
+ shard: Shard::new(),
+ local: Mutex::new(()),
+ }
+ }
+
+ /// allocs a value into the slab, returning a key that can be used to
+ /// access it.
+ ///
+ /// If this function returns `None`, then the shard for the current thread
+ /// is full and no items can be added until some are removed, or the maximum
+ /// number of shards has been reached.
+ pub(crate) fn alloc(&self) -> Option<Address> {
+ // we must lock the slab to alloc an item.
+ let _local = self.local.lock().unwrap();
+ self.shard.alloc()
+ }
+
+ /// Removes the value associated with the given key from the slab.
+ pub(crate) fn remove(&self, idx: Address) {
+ // try to lock the slab so that we can use `remove_local`.
+ let lock = self.local.try_lock();
+
+ // if we were able to lock the slab, we are "local" and can use the fast
+ // path; otherwise, we will use `remove_remote`.
+ if lock.is_ok() {
+ self.shard.remove_local(idx)
+ } else {
+ self.shard.remove_remote(idx)
+ }
+ }
+
+ /// Return a reference to the value associated with the given key.
+ ///
+ /// If the slab does not contain a value for the given key, `None` is
+ /// returned instead.
+ pub(crate) fn get(&self, token: Address) -> Option<&T> {
+ self.shard.get(token)
+ }
+}
+
+impl<T> fmt::Debug for Slab<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Slab")
+ .field("shard", &self.shard)
+ .finish()
+ }
+}