tokio: remove needless generic type on LinkedList (#8188)

This commit is contained in:
Tim Vilgot Mikael Fredenberg
2026-06-19 23:28:28 +08:00
committed by GitHub
parent 7892f6020d
commit daa653d94f
20 changed files with 114 additions and 143 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ pub(super) struct Synced {
is_shutdown: bool,
// List of all registrations tracked by the set
registrations: LinkedList<Arc<ScheduledIo>, ScheduledIo>,
registrations: LinkedList<Arc<ScheduledIo>>,
// Registrations that are pending drop. When a `Registration` is dropped, it
// stores its `ScheduledIo` in this list. The I/O driver is responsible for
+1 -3
View File
@@ -107,12 +107,10 @@ pub(crate) struct ScheduledIo {
waiters: Mutex<Waiters>,
}
type WaitList = LinkedList<Waiter, <Waiter as linked_list::Link>::Target>;
#[derive(Debug, Default)]
struct Waiters {
/// List of all current waiters.
list: WaitList,
list: LinkedList<Waiter>,
/// Waker used for `AsyncRead`.
reader: Option<Waker>,
+5 -7
View File
@@ -9,8 +9,8 @@
use crate::future::Future;
use crate::loom::cell::UnsafeCell;
use crate::runtime::task::{JoinHandle, LocalNotified, Notified, Schedule, SpawnLocation, Task};
use crate::util::linked_list::{Link, LinkedList};
use crate::util::sharded_list;
use crate::util::linked_list::LinkedList;
use crate::util::sharded_list::ShardedList;
use crate::loom::sync::atomic::{AtomicBool, Ordering};
use std::marker::PhantomData;
@@ -56,13 +56,11 @@ cfg_not_has_atomic_u64! {
}
pub(crate) struct OwnedTasks<S: 'static> {
list: List<S>,
list: ShardedList<Task<S>>,
pub(crate) id: NonZeroU64,
closed: AtomicBool,
}
type List<S> = sharded_list::ShardedList<Task<S>, <Task<S> as Link>::Target>;
pub(crate) struct LocalOwnedTasks<S: 'static> {
inner: UnsafeCell<OwnedTasksInner<S>>,
pub(crate) id: NonZeroU64,
@@ -70,7 +68,7 @@ pub(crate) struct LocalOwnedTasks<S: 'static> {
}
struct OwnedTasksInner<S: 'static> {
list: LinkedList<Task<S>, <Task<S> as Link>::Target>,
list: LinkedList<Task<S>>,
closed: bool,
}
@@ -78,7 +76,7 @@ impl<S: 'static> OwnedTasks<S> {
pub(crate) fn new(num_cores: usize) -> Self {
let shard_size = Self::gen_shared_list_size(num_cores);
Self {
list: List::new(shard_size),
list: ShardedList::new(shard_size),
closed: AtomicBool::new(false),
id: get_next_id(),
}
-2
View File
@@ -322,8 +322,6 @@ pub(crate) struct TimerHandle {
inner: NonNull<TimerShared>,
}
pub(super) type EntryList = crate::util::linked_list::LinkedList<TimerShared, TimerShared>;
/// The shared state structure of a timer. This structure is shared between the
/// frontend (`Entry`) and driver backend.
///
+1 -1
View File
@@ -8,7 +8,7 @@
mod entry;
pub(crate) use entry::TimerEntry;
use entry::{EntryList, TimerHandle, TimerShared, MAX_SAFE_MILLIS_DURATION};
use entry::{TimerHandle, TimerShared, MAX_SAFE_MILLIS_DURATION};
mod handle;
pub(crate) use self::handle::Handle;
+5 -4
View File
@@ -1,4 +1,5 @@
use crate::runtime::time::{EntryList, TimerHandle, TimerShared};
use crate::runtime::time::{TimerHandle, TimerShared};
use crate::util::linked_list::LinkedList;
use std::{array, fmt, ptr::NonNull};
@@ -16,7 +17,7 @@ pub(crate) struct Level {
occupied: u64,
/// Slots. We access these via the EntryInner `current_list` as well, so this needs to be an `UnsafeCell`.
slot: [EntryList; LEVEL_MULT],
slot: [LinkedList<TimerShared>; LEVEL_MULT],
}
/// Indicates when a slot must be processed next.
@@ -42,7 +43,7 @@ impl Level {
Level {
level,
occupied: 0,
slot: array::from_fn(|_| EntryList::default()),
slot: array::from_fn(|_| LinkedList::default()),
}
}
@@ -140,7 +141,7 @@ impl Level {
}
}
pub(crate) fn take_slot(&mut self, slot: usize) -> EntryList {
pub(crate) fn take_slot(&mut self, slot: usize) -> LinkedList<TimerShared> {
self.occupied &= !occupied_bit(slot);
std::mem::take(&mut self.slot[slot])
+4 -4
View File
@@ -1,5 +1,6 @@
use crate::runtime::time::{TimerHandle, TimerShared};
use crate::time::error::InsertError;
use crate::util::linked_list::LinkedList;
mod level;
pub(crate) use self::level::Expiration;
@@ -8,7 +9,6 @@ use self::level::Level;
use std::ptr::NonNull;
use super::entry::STATE_DEREGISTERED;
use super::EntryList;
/// Timing wheel implementation.
///
@@ -36,7 +36,7 @@ pub(crate) struct Wheel {
levels: Box<[Level; NUM_LEVELS]>,
/// Entries queued for firing
pending: EntryList,
pending: LinkedList<TimerShared>,
}
/// Number of levels. Each level has 64 slots. By using 6 levels with 64 slots
@@ -54,7 +54,7 @@ impl Wheel {
Wheel {
elapsed: 0,
levels: levels.try_into().unwrap(),
pending: EntryList::new(),
pending: LinkedList::new(),
}
}
@@ -263,7 +263,7 @@ impl Wheel {
}
/// Obtains the list of entries that need processing for the given expiration.
fn take_entries(&mut self, expiration: &Expiration) -> EntryList {
fn take_entries(&mut self, expiration: &Expiration) -> LinkedList<TimerShared> {
self.levels[expiration.level].take_slot(expiration.slot)
}
@@ -1,12 +1,10 @@
use super::{CancellationQueueEntry, Entry, EntryHandle};
use super::{CancellationQueueEntry, EntryHandle};
use crate::loom::sync::{Arc, Mutex};
use crate::util::linked_list;
type EntryList = linked_list::LinkedList<CancellationQueueEntry, Entry>;
use crate::util::linked_list::LinkedList;
#[derive(Debug, Default)]
struct Inner {
list: EntryList,
list: LinkedList<CancellationQueueEntry>,
}
impl Drop for Inner {
@@ -21,7 +19,7 @@ impl Drop for Inner {
impl Inner {
fn new() -> Self {
Self {
list: EntryList::new(),
list: LinkedList::new(),
}
}
-2
View File
@@ -6,8 +6,6 @@ use std::marker::PhantomPinned;
use std::ptr::NonNull;
use std::task::{Context, Poll, Waker};
pub(super) type EntryList = linked_list::LinkedList<Entry, Entry>;
#[derive(Debug, Default)]
struct State {
cancelled: bool,
+1 -2
View File
@@ -5,8 +5,7 @@ pub(crate) mod cancellation_queue;
mod entry;
pub(crate) use entry::Handle as EntryHandle;
use entry::{CancellationQueueEntry, RegistrationQueueEntry, WakeQueueEntry};
use entry::{Entry, EntryList};
use entry::{CancellationQueueEntry, Entry, RegistrationQueueEntry, WakeQueueEntry};
mod registration_queue;
pub(crate) use registration_queue::RegistrationQueue;
@@ -1,12 +1,10 @@
use super::{Entry, EntryHandle, RegistrationQueueEntry};
use crate::util::linked_list;
type EntryList = linked_list::LinkedList<RegistrationQueueEntry, Entry>;
use super::{EntryHandle, RegistrationQueueEntry};
use crate::util::linked_list::LinkedList;
/// A queue of entries that need to be registered in the timer wheel.
#[derive(Debug)]
pub(crate) struct RegistrationQueue {
list: EntryList,
list: LinkedList<RegistrationQueueEntry>,
}
impl Drop for RegistrationQueue {
@@ -21,7 +19,7 @@ impl Drop for RegistrationQueue {
impl RegistrationQueue {
pub(crate) fn new() -> Self {
Self {
list: EntryList::new(),
list: LinkedList::new(),
}
}
@@ -29,7 +27,7 @@ impl RegistrationQueue {
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// - [`Entry::extra_pointers`] of `hdl` must not being used.
/// - `Entry::extra_pointers` of `hdl` must not being used.
pub(crate) unsafe fn push_front(&mut self, hdl: EntryHandle) {
self.list.push_front(hdl);
}
+5 -7
View File
@@ -1,12 +1,10 @@
use super::{Entry, EntryHandle, WakeQueueEntry};
use crate::util::linked_list;
type EntryList = linked_list::LinkedList<WakeQueueEntry, Entry>;
use super::{EntryHandle, WakeQueueEntry};
use crate::util::linked_list::LinkedList;
/// A queue of entries that need to be woken up.
#[derive(Debug)]
pub(crate) struct WakeQueue {
list: EntryList,
list: LinkedList<WakeQueueEntry>,
}
impl Drop for WakeQueue {
@@ -21,7 +19,7 @@ impl Drop for WakeQueue {
impl WakeQueue {
pub(crate) fn new() -> Self {
Self {
list: EntryList::new(),
list: LinkedList::new(),
}
}
@@ -33,7 +31,7 @@ impl WakeQueue {
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// - [`Entry::extra_pointers`] of `hdl` must not being used.
/// - `Entry::extra_pointers` of `hdl` must not being used.
pub(crate) unsafe fn push_front(&mut self, hdl: EntryHandle) {
self.list.push_front(hdl);
}
+6 -4
View File
@@ -1,4 +1,6 @@
use super::{EntryHandle, EntryList};
use crate::util::linked_list::LinkedList;
use super::{Entry, EntryHandle};
use std::ptr::NonNull;
use std::{array, fmt};
@@ -16,7 +18,7 @@ pub(crate) struct Level {
occupied: u64,
/// Slots. We access these via the EntryInner `current_list` as well, so this needs to be an `UnsafeCell`.
slot: [EntryList; LEVEL_MULT],
slot: [LinkedList<Entry>; LEVEL_MULT],
}
/// Indicates when a slot must be processed next.
@@ -42,7 +44,7 @@ impl Level {
Level {
level,
occupied: 0,
slot: array::from_fn(|_| EntryList::default()),
slot: array::from_fn(|_| LinkedList::default()),
}
}
@@ -142,7 +144,7 @@ impl Level {
}
}
pub(crate) fn take_slot(&mut self, slot: usize) -> EntryList {
pub(crate) fn take_slot(&mut self, slot: usize) -> LinkedList<Entry> {
self.occupied &= !occupied_bit(slot);
std::mem::take(&mut self.slot[slot])
+4 -2
View File
@@ -3,7 +3,9 @@ pub(crate) use self::level::Expiration;
use self::level::Level;
use super::cancellation_queue::Sender;
use super::{EntryHandle, EntryList, WakeQueue};
use super::{Entry, EntryHandle, WakeQueue};
use crate::util::linked_list::LinkedList;
/// Hashed timing wheel implementation.
///
@@ -202,7 +204,7 @@ impl Wheel {
}
/// Obtains the list of entries that need processing for the given expiration.
fn take_entries(&mut self, expiration: &Expiration) -> EntryList {
fn take_entries(&mut self, expiration: &Expiration) -> LinkedList<Entry> {
self.levels[expiration.level].take_slot(expiration.slot)
}
+1 -1
View File
@@ -41,7 +41,7 @@ pub(crate) struct Semaphore {
}
struct Waitlist {
queue: LinkedList<Waiter, <Waiter as linked_list::Link>::Target>,
queue: LinkedList<Waiter>,
closed: bool,
}
+3 -3
View File
@@ -370,7 +370,7 @@ struct Tail {
closed: bool,
/// Receivers waiting for a value.
waiters: LinkedList<Waiter, <Waiter as linked_list::Link>::Target>,
waiters: LinkedList<Waiter>,
}
/// Slot in the buffer.
@@ -943,7 +943,7 @@ fn new_receiver<T>(shared: Arc<Shared<T>>) -> Receiver<T> {
/// and gates the access to it on the `Shared.tail` mutex. It also empties
/// the list on drop.
struct WaitersList<'a, T> {
list: GuardedLinkedList<Waiter, <Waiter as linked_list::Link>::Target>,
list: GuardedLinkedList<Waiter>,
is_empty: bool,
shared: &'a Shared<T>,
}
@@ -961,7 +961,7 @@ impl<'a, T> Drop for WaitersList<'a, T> {
impl<'a, T> WaitersList<'a, T> {
fn new(
unguarded_list: LinkedList<Waiter, <Waiter as linked_list::Link>::Target>,
unguarded_list: LinkedList<Waiter>,
guard: Pin<&'a Waiter>,
shared: &'a Shared<T>,
) -> Self {
+7 -10
View File
@@ -20,9 +20,6 @@ use std::sync::atomic::Ordering::{self, Acquire, Relaxed, Release, SeqCst};
use std::sync::Arc;
use std::task::{Context, Poll, Waker};
type WaitList = LinkedList<Waiter, <Waiter as linked_list::Link>::Target>;
type GuardedWaitList = GuardedLinkedList<Waiter, <Waiter as linked_list::Link>::Target>;
/// Notifies a single task to wake up.
///
/// `Notify` provides a basic mechanism to notify a single task of an event.
@@ -211,7 +208,7 @@ pub struct Notify {
// - number of times `notify_waiters` was called can
// be modified only if `waiters` lock is held
state: AtomicUsize,
waiters: Mutex<WaitList>,
waiters: Mutex<LinkedList<Waiter>>,
}
#[derive(Debug)]
@@ -327,14 +324,14 @@ enum Notification {
/// and gates the access to it on `notify.waiters` mutex. It also empties
/// the list on drop.
struct NotifyWaitersList<'a> {
list: GuardedWaitList,
list: GuardedLinkedList<Waiter>,
is_empty: bool,
notify: &'a Notify,
}
impl<'a> NotifyWaitersList<'a> {
fn new(
unguarded_list: WaitList,
unguarded_list: LinkedList<Waiter>,
guard: Pin<&'a Waiter>,
notify: &'a Notify,
) -> NotifyWaitersList<'a> {
@@ -349,7 +346,7 @@ impl<'a> NotifyWaitersList<'a> {
/// Removes the last element from the guarded list. Modifying this list
/// requires an exclusive access to the main list in `Notify`.
fn pop_back_locked(&mut self, _waiters: &mut WaitList) -> Option<NonNull<Waiter>> {
fn pop_back_locked(&mut self, _waiters: &mut LinkedList<Waiter>) -> Option<NonNull<Waiter>> {
let result = self.list.pop_back();
if result.is_none() {
// Save information about emptiness to avoid waiting for lock
@@ -747,7 +744,7 @@ impl Notify {
fn inner_notify_waiters<'a>(
&'a self,
curr: usize,
mut waiters: crate::loom::sync::MutexGuard<'a, LinkedList<Waiter, Waiter>>,
mut waiters: crate::loom::sync::MutexGuard<'a, LinkedList<Waiter>>,
) {
if matches!(get_state(curr), EMPTY | NOTIFIED) {
// There are no waiting tasks. All we need to do is increment the
@@ -842,7 +839,7 @@ impl UnwindSafe for Notify {}
impl RefUnwindSafe for Notify {}
fn notify_locked(
waiters: &mut WaitList,
waiters: &mut LinkedList<Waiter>,
state: &AtomicUsize,
curr: usize,
strategy: NotifyOneStrategy,
@@ -1403,7 +1400,7 @@ fn is_unpin<T: Unpin>() {}
/// While this guard is held, the `Notify` instance's waiter list is locked.
pub(crate) struct NotifyGuard<'a> {
guarded_notify: &'a Notify,
guarded_waiters: crate::loom::sync::MutexGuard<'a, WaitList>,
guarded_waiters: crate::loom::sync::MutexGuard<'a, LinkedList<Waiter>>,
current_state: usize,
}
+9 -9
View File
@@ -13,12 +13,9 @@ use std::task::{Context, Waker};
use crate::loom::cell::UnsafeCell;
use crate::loom::sync::{Arc, Mutex};
use crate::util::linked_list::{self, Link};
use crate::util::linked_list::{self, Link, LinkedList};
use crate::util::{waker_ref, Wake};
type LinkedList<T> =
linked_list::LinkedList<ListEntry<T>, <ListEntry<T> as linked_list::Link>::Target>;
/// This is the main handle to the collection.
pub(crate) struct IdleNotifiedSet<T> {
lists: Arc<Lists<T>>,
@@ -47,8 +44,8 @@ type Lists<T> = Mutex<ListsInner<T>>;
/// the destructor of the `IdleNotifiedSet` will clear the two lists, so once
/// that object is destroyed, no ref-cycles will remain.
struct ListsInner<T> {
notified: LinkedList<T>,
idle: LinkedList<T>,
notified: LinkedList<ListEntry<T>>,
idle: LinkedList<ListEntry<T>>,
/// Whenever an element in the `notified` list is woken, this waker will be
/// notified and consumed, if it exists.
waker: Option<Waker>,
@@ -233,7 +230,7 @@ impl<T> IdleNotifiedSet<T> {
/// Call a function on every element in this list.
pub(crate) fn for_each<F: FnMut(&mut T)>(&mut self, mut func: F) {
fn get_ptrs<T>(list: &mut LinkedList<T>, ptrs: &mut Vec<*mut T>) {
fn get_ptrs<T>(list: &mut LinkedList<ListEntry<T>>, ptrs: &mut Vec<*mut T>) {
let mut node = list.last();
while let Some(entry) = node {
@@ -291,7 +288,7 @@ impl<T> IdleNotifiedSet<T> {
// has `my_list` set to `Neither` and that the value has not yet been
// dropped.
struct AllEntries<T, F: FnMut(T)> {
all_entries: LinkedList<T>,
all_entries: LinkedList<ListEntry<T>>,
func: F,
}
@@ -346,7 +343,10 @@ impl<T> IdleNotifiedSet<T> {
///
/// The mutex for the entries must be held, and the target list must be such
/// that setting `my_list` to `Neither` is ok.
unsafe fn move_to_new_list<T>(from: &mut LinkedList<T>, to: &mut LinkedList<T>) {
unsafe fn move_to_new_list<T>(
from: &mut LinkedList<ListEntry<T>>,
to: &mut LinkedList<ListEntry<T>>,
) {
while let Some(entry) = from.pop_back() {
entry.my_list.with_mut(|ptr| {
// Safety: pointer is accessed while holding the mutex.
+37 -51
View File
@@ -15,7 +15,7 @@
use core::cell::UnsafeCell;
use core::fmt;
use core::marker::{PhantomData, PhantomPinned};
use core::marker::PhantomPinned;
use core::mem::ManuallyDrop;
use core::ptr::{self, NonNull};
@@ -23,19 +23,16 @@ use core::ptr::{self, NonNull};
///
/// Currently, the list is not emptied on drop. It is the caller's
/// responsibility to ensure the list is empty before dropping it.
pub(crate) struct LinkedList<L, T> {
pub(crate) struct LinkedList<L: Link> {
/// Linked list head
head: Option<NonNull<T>>,
head: Option<NonNull<L::Target>>,
/// Linked list tail
tail: Option<NonNull<T>>,
/// Node type marker.
_marker: PhantomData<*const L>,
tail: Option<NonNull<L::Target>>,
}
unsafe impl<L: Link> Send for LinkedList<L, L::Target> where L::Target: Send {}
unsafe impl<L: Link> Sync for LinkedList<L, L::Target> where L::Target: Sync {}
unsafe impl<L: Link> Send for LinkedList<L> where L::Target: Send {}
unsafe impl<L: Link> Sync for LinkedList<L> where L::Target: Sync {}
/// Defines how a type is tracked within a linked list.
///
@@ -57,7 +54,6 @@ pub(crate) unsafe trait Link {
type Target;
/// Convert the handle to a raw pointer without consuming the handle.
#[allow(clippy::wrong_self_convention)]
fn as_raw(handle: &Self::Handle) -> NonNull<Self::Target>;
/// Convert the raw pointer to a handle
@@ -112,18 +108,15 @@ unsafe impl<T: Sync> Sync for Pointers<T> {}
// ===== impl LinkedList =====
impl<L, T> LinkedList<L, T> {
impl<L: Link> LinkedList<L> {
/// Creates an empty linked list.
pub(crate) const fn new() -> LinkedList<L, T> {
pub(crate) const fn new() -> LinkedList<L> {
LinkedList {
head: None,
tail: None,
_marker: PhantomData,
}
}
}
impl<L: Link> LinkedList<L, L::Target> {
/// Adds an element first in the list.
pub(crate) fn push_front(&mut self, val: L::Handle) {
// The value should not be dropped, it is being inserted into the list
@@ -241,7 +234,7 @@ impl<L: Link> LinkedList<L, L::Target> {
}
}
impl<L: Link> fmt::Debug for LinkedList<L, L::Target> {
impl<L: Link> fmt::Debug for LinkedList<L> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LinkedList")
.field("head", &self.head)
@@ -257,14 +250,14 @@ impl<L: Link> fmt::Debug for LinkedList<L, L::Target> {
feature = "signal",
feature = "sync",
))]
impl<L: Link> LinkedList<L, L::Target> {
impl<L: Link> LinkedList<L> {
pub(crate) fn last(&self) -> Option<&L::Target> {
let tail = self.tail.as_ref()?;
unsafe { Some(&*tail.as_ptr()) }
}
}
impl<L: Link> Default for LinkedList<L, L::Target> {
impl<L: Link> Default for LinkedList<L> {
fn default() -> Self {
Self::new()
}
@@ -273,16 +266,16 @@ impl<L: Link> Default for LinkedList<L, L::Target> {
// ===== impl DrainFilter =====
cfg_io_driver_impl! {
pub(crate) struct DrainFilter<'a, T: Link, F> {
list: &'a mut LinkedList<T, T::Target>,
pub(crate) struct DrainFilter<'a, L: Link, F> {
list: &'a mut LinkedList<L>,
filter: F,
curr: Option<NonNull<T::Target>>,
curr: Option<NonNull<L::Target>>,
}
impl<T: Link> LinkedList<T, T::Target> {
pub(crate) fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F>
impl<L: Link> LinkedList<L> {
pub(crate) fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, L, F>
where
F: FnMut(&T::Target) -> bool,
F: FnMut(&L::Target) -> bool,
{
let curr = self.head;
DrainFilter {
@@ -293,17 +286,16 @@ cfg_io_driver_impl! {
}
}
impl<'a, T, F> Iterator for DrainFilter<'a, T, F>
impl<'a, L: Link, F> Iterator for DrainFilter<'a, L, F>
where
T: Link,
F: FnMut(&T::Target) -> bool,
F: FnMut(&L::Target) -> bool,
{
type Item = T::Handle;
type Item = L::Handle;
fn next(&mut self) -> Option<Self::Item> {
while let Some(curr) = self.curr {
// safety: the pointer references data contained by the list
self.curr = unsafe { T::pointers(curr).as_ref() }.get_next();
self.curr = unsafe { L::pointers(curr).as_ref() }.get_next();
// safety: the value is still owned by the linked list.
if (self.filter)(unsafe { &mut *curr.as_ptr() }) {
@@ -317,18 +309,18 @@ cfg_io_driver_impl! {
}
cfg_taskdump! {
impl<T: Link> LinkedList<T, T::Target> {
impl<L: Link> LinkedList<L> {
pub(crate) fn for_each<F>(&mut self, mut f: F)
where
F: FnMut(&T::Handle),
F: FnMut(&L::Handle),
{
let mut next = self.head;
while let Some(curr) = next {
unsafe {
let handle = ManuallyDrop::new(T::from_raw(curr));
let handle = ManuallyDrop::new(L::from_raw(curr));
f(&handle);
next = T::pointers(curr).as_ref().get_next();
next = L::pointers(curr).as_ref().get_next();
}
}
}
@@ -352,19 +344,16 @@ feature! {
///
/// If a list is empty, then both pointers of the guard node are pointing
/// at the guard node itself.
pub(crate) struct GuardedLinkedList<L, T> {
pub(crate) struct GuardedLinkedList<L: Link> {
/// Pointer to the guard node.
guard: NonNull<T>,
/// Node type marker.
_marker: PhantomData<*const L>,
guard: NonNull<L::Target>,
}
impl<L: Link> LinkedList<L, L::Target> {
impl<L: Link> LinkedList<L> {
/// Turns a linked list into the guarded version by linking the guard node
/// with the head and tail nodes. Like with other nodes, you should guarantee
/// that the guard node is pinned in memory.
pub(crate) fn into_guarded(self, guard_handle: L::Handle) -> GuardedLinkedList<L, L::Target> {
pub(crate) fn into_guarded(self, guard_handle: L::Handle) -> GuardedLinkedList<L> {
// `guard_handle` is a NonNull pointer, we don't have to care about dropping it.
let guard = L::as_raw(&guard_handle);
@@ -386,11 +375,11 @@ feature! {
}
}
GuardedLinkedList { guard, _marker: PhantomData }
GuardedLinkedList { guard }
}
}
impl<L: Link> GuardedLinkedList<L, L::Target> {
impl<L: Link> GuardedLinkedList<L> {
fn tail(&self) -> Option<NonNull<L::Target>> {
let tail_ptr = unsafe {
L::pointers(self.guard).as_ref().get_prev().unwrap()
@@ -515,7 +504,7 @@ pub(crate) mod tests {
r.as_ref().get_ref().into()
}
fn collect_list(list: &mut LinkedList<&'_ Entry, <&'_ Entry as Link>::Target>) -> Vec<i32> {
fn collect_list(list: &mut LinkedList<&'_ Entry>) -> Vec<i32> {
let mut ret = vec![];
while let Some(entry) = list.pop_back() {
@@ -525,10 +514,7 @@ pub(crate) mod tests {
ret
}
fn push_all<'a>(
list: &mut LinkedList<&'a Entry, <&'_ Entry as Link>::Target>,
entries: &[Pin<&'a Entry>],
) {
fn push_all<'a>(list: &mut LinkedList<&'a Entry>, entries: &[Pin<&'a Entry>]) {
for entry in entries.iter() {
list.push_front(*entry);
}
@@ -552,7 +538,7 @@ pub(crate) mod tests {
#[test]
fn const_new() {
const _: LinkedList<&Entry, <&Entry as Link>::Target> = LinkedList::new();
const _: LinkedList<&Entry> = LinkedList::new();
}
#[test]
@@ -580,7 +566,7 @@ pub(crate) mod tests {
let a = entry(5);
let b = entry(7);
let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
let mut list = LinkedList::<&Entry>::new();
list.push_front(a.as_ref());
@@ -737,7 +723,7 @@ pub(crate) mod tests {
unsafe {
// Remove missing
let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
let mut list = LinkedList::<&Entry>::new();
list.push_front(b.as_ref());
list.push_front(a.as_ref());
@@ -766,7 +752,7 @@ pub(crate) mod tests {
})
.collect::<Vec<_>>();
let mut ll = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
let mut ll = LinkedList::<&Entry>::new();
let mut reference = VecDeque::new();
let entries: Vec<_> = (0..ops.len()).map(|i| entry(i as i32)).collect();
+15 -17
View File
@@ -12,8 +12,8 @@ use super::linked_list::{Link, LinkedList};
/// responsibility to ensure the list is empty before dropping it.
///
/// Note: Due to its inner sharded design, the order of nodes cannot be guaranteed.
pub(crate) struct ShardedList<L, T> {
lists: Box<[Mutex<LinkedList<L, T>>]>,
pub(crate) struct ShardedList<L: ShardedListItem> {
lists: Box<[Mutex<LinkedList<L>>]>,
added: MetricAtomicU64,
count: MetricAtomicUsize,
shard_mask: usize,
@@ -32,7 +32,15 @@ pub(crate) unsafe trait ShardedListItem: Link {
unsafe fn get_shard_id(target: NonNull<Self::Target>) -> usize;
}
impl<L, T> ShardedList<L, T> {
/// Used to get the lock of shard.
pub(crate) struct ShardGuard<'a, L: Link> {
lock: MutexGuard<'a, LinkedList<L>>,
added: &'a MetricAtomicU64,
count: &'a MetricAtomicUsize,
id: usize,
}
impl<L: ShardedListItem> ShardedList<L> {
/// Creates a new and empty sharded linked list with the specified size.
pub(crate) fn new(sharded_size: usize) -> Self {
assert!(sharded_size.is_power_of_two());
@@ -46,17 +54,7 @@ impl<L, T> ShardedList<L, T> {
shard_mask,
}
}
}
/// Used to get the lock of shard.
pub(crate) struct ShardGuard<'a, L, T> {
lock: MutexGuard<'a, LinkedList<L, T>>,
added: &'a MetricAtomicU64,
count: &'a MetricAtomicUsize,
id: usize,
}
impl<L: ShardedListItem> ShardedList<L, L::Target> {
/// Removes the last element from a list specified by `shard_id` and returns it, or None if it is
/// empty.
pub(crate) fn pop_back(&self, shard_id: usize) -> Option<L::Handle> {
@@ -89,7 +87,7 @@ impl<L: ShardedListItem> ShardedList<L, L::Target> {
}
/// Gets the lock of `ShardedList`, makes us have the write permission.
pub(crate) fn lock_shard(&self, val: &L::Handle) -> ShardGuard<'_, L, L::Target> {
pub(crate) fn lock_shard(&self, val: &L::Handle) -> ShardGuard<'_, L> {
let id = unsafe { L::get_shard_id(L::as_raw(val)) };
ShardGuard {
lock: self.shard_inner(id),
@@ -126,13 +124,13 @@ impl<L: ShardedListItem> ShardedList<L, L::Target> {
}
#[inline]
fn shard_inner(&self, id: usize) -> MutexGuard<'_, LinkedList<L, <L as Link>::Target>> {
fn shard_inner(&self, id: usize) -> MutexGuard<'_, LinkedList<L>> {
// Safety: This modulo operation ensures that the index is not out of bounds.
unsafe { self.lists.get_unchecked(id & self.shard_mask).lock() }
}
}
impl<'a, L: ShardedListItem> ShardGuard<'a, L, L::Target> {
impl<'a, L: ShardedListItem> ShardGuard<'a, L> {
/// Push a value to this shard.
pub(crate) fn push(mut self, val: L::Handle) {
let id = unsafe { L::get_shard_id(L::as_raw(&val)) };
@@ -144,7 +142,7 @@ impl<'a, L: ShardedListItem> ShardGuard<'a, L, L::Target> {
}
cfg_taskdump! {
impl<L: ShardedListItem> ShardedList<L, L::Target> {
impl<L: ShardedListItem> ShardedList<L> {
pub(crate) fn for_each<F>(&self, mut f: F)
where
F: FnMut(&L::Handle),