mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-18 00:00:09 +02:00
util: add const fn support for internal LinkedList. (#2805)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use crate::park::{Park, Unpark};
|
||||
use crate::runtime;
|
||||
use crate::runtime::task::{self, JoinHandle, Schedule, Task};
|
||||
use crate::util::linked_list::LinkedList;
|
||||
use crate::util::linked_list::{Link, LinkedList};
|
||||
use crate::util::{waker_ref, Wake};
|
||||
|
||||
use std::cell::RefCell;
|
||||
@@ -42,7 +42,7 @@ pub(crate) struct Spawner {
|
||||
|
||||
struct Tasks {
|
||||
/// Collection of all active tasks spawned onto this executor.
|
||||
owned: LinkedList<Task<Arc<Shared>>>,
|
||||
owned: LinkedList<Task<Arc<Shared>>, <Task<Arc<Shared>> as Link>::Target>,
|
||||
|
||||
/// Local run queue.
|
||||
///
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::runtime::task::{self, Schedule, Task};
|
||||
use crate::util::linked_list::LinkedList;
|
||||
use crate::util::linked_list::{Link, LinkedList};
|
||||
use crate::util::TryLock;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
@@ -72,7 +72,7 @@ struct Inner {
|
||||
|
||||
struct Core {
|
||||
queue: VecDeque<task::Notified<Runtime>>,
|
||||
tasks: LinkedList<Task<Runtime>>,
|
||||
tasks: LinkedList<Task<Runtime>, <Task<Runtime> as Link>::Target>,
|
||||
}
|
||||
|
||||
static CURRENT: TryLock<Option<Runtime>> = TryLock::new(None);
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::runtime;
|
||||
use crate::runtime::park::{Parker, Unparker};
|
||||
use crate::runtime::thread_pool::{AtomicCell, Idle};
|
||||
use crate::runtime::{queue, task};
|
||||
use crate::util::linked_list::LinkedList;
|
||||
use crate::util::linked_list::{Link, LinkedList};
|
||||
use crate::util::FastRand;
|
||||
|
||||
use std::cell::RefCell;
|
||||
@@ -53,7 +53,7 @@ struct Core {
|
||||
is_shutdown: bool,
|
||||
|
||||
/// Tasks owned by the core
|
||||
tasks: LinkedList<Task>,
|
||||
tasks: LinkedList<Task, <Task as Link>::Target>,
|
||||
|
||||
/// Parker
|
||||
///
|
||||
|
||||
@@ -36,7 +36,7 @@ pub(crate) struct Semaphore {
|
||||
}
|
||||
|
||||
struct Waitlist {
|
||||
queue: LinkedList<Waiter>,
|
||||
queue: LinkedList<Waiter, <Waiter as linked_list::Link>::Target>,
|
||||
closed: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ struct Tail {
|
||||
closed: bool,
|
||||
|
||||
/// Receivers waiting for a value
|
||||
waiters: LinkedList<Waiter>,
|
||||
waiters: LinkedList<Waiter, <Waiter as linked_list::Link>::Target>,
|
||||
}
|
||||
|
||||
/// Slot in the buffer
|
||||
|
||||
@@ -10,6 +10,8 @@ use std::ptr::NonNull;
|
||||
use std::sync::atomic::Ordering::SeqCst;
|
||||
use std::task::{Context, Poll, Waker};
|
||||
|
||||
type WaitList = LinkedList<Waiter, <Waiter as linked_list::Link>::Target>;
|
||||
|
||||
/// Notify a single task to wake up.
|
||||
///
|
||||
/// `Notify` provides a basic mechanism to notify a single task of an event.
|
||||
@@ -101,7 +103,7 @@ use std::task::{Context, Poll, Waker};
|
||||
#[derive(Debug)]
|
||||
pub struct Notify {
|
||||
state: AtomicU8,
|
||||
waiters: Mutex<LinkedList<Waiter>>,
|
||||
waiters: Mutex<WaitList>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -285,7 +287,7 @@ impl Default for Notify {
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_locked(waiters: &mut LinkedList<Waiter>, state: &AtomicU8, curr: u8) -> Option<Waker> {
|
||||
fn notify_locked(waiters: &mut WaitList, state: &AtomicU8, curr: u8) -> Option<Waker> {
|
||||
loop {
|
||||
match curr {
|
||||
EMPTY | NOTIFIED => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Runs `!Send` futures on the current thread.
|
||||
use crate::runtime::task::{self, JoinHandle, Task};
|
||||
use crate::sync::AtomicWaker;
|
||||
use crate::util::linked_list::LinkedList;
|
||||
use crate::util::linked_list::{Link, LinkedList};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::VecDeque;
|
||||
@@ -132,7 +132,7 @@ struct Context {
|
||||
|
||||
struct Tasks {
|
||||
/// Collection of all active tasks spawned onto this executor.
|
||||
owned: LinkedList<Task<Arc<Shared>>>,
|
||||
owned: LinkedList<Task<Arc<Shared>>, <Task<Arc<Shared>> as Link>::Target>,
|
||||
|
||||
/// Local run queue sender and receiver.
|
||||
queue: VecDeque<task::Notified<Arc<Shared>>>,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
//! specified node is actually contained by the list.
|
||||
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::ManuallyDrop;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
@@ -12,16 +13,19 @@ use core::ptr::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<T: Link> {
|
||||
pub(crate) struct LinkedList<L, T> {
|
||||
/// Linked list head
|
||||
head: Option<NonNull<T::Target>>,
|
||||
head: Option<NonNull<T>>,
|
||||
|
||||
/// Linked list tail
|
||||
tail: Option<NonNull<T::Target>>,
|
||||
tail: Option<NonNull<T>>,
|
||||
|
||||
/// Node type marker.
|
||||
_marker: PhantomData<*const L>,
|
||||
}
|
||||
|
||||
unsafe impl<T: Link> Send for LinkedList<T> where T::Target: Send {}
|
||||
unsafe impl<T: Link> Sync for LinkedList<T> where T::Target: Sync {}
|
||||
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 {}
|
||||
|
||||
/// Defines how a type is tracked within a linked list.
|
||||
///
|
||||
@@ -66,27 +70,31 @@ unsafe impl<T: Sync> Sync for Pointers<T> {}
|
||||
|
||||
// ===== impl LinkedList =====
|
||||
|
||||
impl<T: Link> LinkedList<T> {
|
||||
/// Creates an empty linked list
|
||||
pub(crate) fn new() -> LinkedList<T> {
|
||||
impl<L, T> LinkedList<L, T> {
|
||||
/// Creates an empty linked list.
|
||||
#[allow(dead_code)] // NOTE: This will get removed with: https://github.com/tokio-rs/tokio/pull/2790
|
||||
pub(crate) const fn new() -> LinkedList<L, T> {
|
||||
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: T::Handle) {
|
||||
pub(crate) fn push_front(&mut self, val: L::Handle) {
|
||||
// The value should not be dropped, it is being inserted into the list
|
||||
let val = ManuallyDrop::new(val);
|
||||
let ptr = T::as_raw(&*val);
|
||||
let ptr = L::as_raw(&*val);
|
||||
assert_ne!(self.head, Some(ptr));
|
||||
unsafe {
|
||||
T::pointers(ptr).as_mut().next = self.head;
|
||||
T::pointers(ptr).as_mut().prev = None;
|
||||
L::pointers(ptr).as_mut().next = self.head;
|
||||
L::pointers(ptr).as_mut().prev = None;
|
||||
|
||||
if let Some(head) = self.head {
|
||||
T::pointers(head).as_mut().prev = Some(ptr);
|
||||
L::pointers(head).as_mut().prev = Some(ptr);
|
||||
}
|
||||
|
||||
self.head = Some(ptr);
|
||||
@@ -99,21 +107,21 @@ impl<T: Link> LinkedList<T> {
|
||||
|
||||
/// Removes the last element from a list and returns it, or None if it is
|
||||
/// empty.
|
||||
pub(crate) fn pop_back(&mut self) -> Option<T::Handle> {
|
||||
pub(crate) fn pop_back(&mut self) -> Option<L::Handle> {
|
||||
unsafe {
|
||||
let last = self.tail?;
|
||||
self.tail = T::pointers(last).as_ref().prev;
|
||||
self.tail = L::pointers(last).as_ref().prev;
|
||||
|
||||
if let Some(prev) = T::pointers(last).as_ref().prev {
|
||||
T::pointers(prev).as_mut().next = None;
|
||||
if let Some(prev) = L::pointers(last).as_ref().prev {
|
||||
L::pointers(prev).as_mut().next = None;
|
||||
} else {
|
||||
self.head = None
|
||||
}
|
||||
|
||||
T::pointers(last).as_mut().prev = None;
|
||||
T::pointers(last).as_mut().next = None;
|
||||
L::pointers(last).as_mut().prev = None;
|
||||
L::pointers(last).as_mut().next = None;
|
||||
|
||||
Some(T::from_raw(last))
|
||||
Some(L::from_raw(last))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,38 +141,38 @@ impl<T: Link> LinkedList<T> {
|
||||
///
|
||||
/// The caller **must** ensure that `node` is currently contained by
|
||||
/// `self` or not contained by any other list.
|
||||
pub(crate) unsafe fn remove(&mut self, node: NonNull<T::Target>) -> Option<T::Handle> {
|
||||
if let Some(prev) = T::pointers(node).as_ref().prev {
|
||||
debug_assert_eq!(T::pointers(prev).as_ref().next, Some(node));
|
||||
T::pointers(prev).as_mut().next = T::pointers(node).as_ref().next;
|
||||
pub(crate) unsafe fn remove(&mut self, node: NonNull<L::Target>) -> Option<L::Handle> {
|
||||
if let Some(prev) = L::pointers(node).as_ref().prev {
|
||||
debug_assert_eq!(L::pointers(prev).as_ref().next, Some(node));
|
||||
L::pointers(prev).as_mut().next = L::pointers(node).as_ref().next;
|
||||
} else {
|
||||
if self.head != Some(node) {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.head = T::pointers(node).as_ref().next;
|
||||
self.head = L::pointers(node).as_ref().next;
|
||||
}
|
||||
|
||||
if let Some(next) = T::pointers(node).as_ref().next {
|
||||
debug_assert_eq!(T::pointers(next).as_ref().prev, Some(node));
|
||||
T::pointers(next).as_mut().prev = T::pointers(node).as_ref().prev;
|
||||
if let Some(next) = L::pointers(node).as_ref().next {
|
||||
debug_assert_eq!(L::pointers(next).as_ref().prev, Some(node));
|
||||
L::pointers(next).as_mut().prev = L::pointers(node).as_ref().prev;
|
||||
} else {
|
||||
// This might be the last item in the list
|
||||
if self.tail != Some(node) {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.tail = T::pointers(node).as_ref().prev;
|
||||
self.tail = L::pointers(node).as_ref().prev;
|
||||
}
|
||||
|
||||
T::pointers(node).as_mut().next = None;
|
||||
T::pointers(node).as_mut().prev = None;
|
||||
L::pointers(node).as_mut().next = None;
|
||||
L::pointers(node).as_mut().prev = None;
|
||||
|
||||
Some(T::from_raw(node))
|
||||
Some(L::from_raw(node))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Link> fmt::Debug for LinkedList<T> {
|
||||
impl<L: Link> fmt::Debug for LinkedList<L, L::Target> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("LinkedList")
|
||||
.field("head", &self.head)
|
||||
@@ -174,8 +182,8 @@ impl<T: Link> fmt::Debug for LinkedList<T> {
|
||||
}
|
||||
|
||||
cfg_sync! {
|
||||
impl<T: Link> LinkedList<T> {
|
||||
pub(crate) fn last(&self) -> Option<&T::Target> {
|
||||
impl<L: Link> LinkedList<L, L::Target> {
|
||||
pub(crate) fn last(&self) -> Option<&L::Target> {
|
||||
let tail = self.tail.as_ref()?;
|
||||
unsafe {
|
||||
Some(&*tail.as_ptr())
|
||||
@@ -192,8 +200,8 @@ cfg_rt_threaded! {
|
||||
_p: core::marker::PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl<T: Link> LinkedList<T> {
|
||||
pub(crate) fn iter(&self) -> Iter<'_, T> {
|
||||
impl<L: Link> LinkedList<L, L::Target> {
|
||||
pub(crate) fn iter(&self) -> Iter<'_, L> {
|
||||
Iter {
|
||||
curr: self.head,
|
||||
_p: core::marker::PhantomData,
|
||||
@@ -277,7 +285,7 @@ mod tests {
|
||||
r.as_ref().get_ref().into()
|
||||
}
|
||||
|
||||
fn collect_list(list: &mut LinkedList<&'_ Entry>) -> Vec<i32> {
|
||||
fn collect_list(list: &mut LinkedList<&'_ Entry, <&'_ Entry as Link>::Target>) -> Vec<i32> {
|
||||
let mut ret = vec![];
|
||||
|
||||
while let Some(entry) = list.pop_back() {
|
||||
@@ -287,7 +295,10 @@ mod tests {
|
||||
ret
|
||||
}
|
||||
|
||||
fn push_all<'a>(list: &mut LinkedList<&'a Entry>, entries: &[Pin<&'a Entry>]) {
|
||||
fn push_all<'a>(
|
||||
list: &mut LinkedList<&'a Entry, <&'_ Entry as Link>::Target>,
|
||||
entries: &[Pin<&'a Entry>],
|
||||
) {
|
||||
for entry in entries.iter() {
|
||||
list.push_front(*entry);
|
||||
}
|
||||
@@ -307,6 +318,11 @@ mod tests {
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_new() {
|
||||
const _: LinkedList<&Entry, <&Entry as Link>::Target> = LinkedList::new();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_and_drain() {
|
||||
let a = entry(5);
|
||||
@@ -332,7 +348,7 @@ mod tests {
|
||||
let a = entry(5);
|
||||
let b = entry(7);
|
||||
|
||||
let mut list = LinkedList::<&Entry>::new();
|
||||
let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
|
||||
|
||||
list.push_front(a.as_ref());
|
||||
|
||||
@@ -489,7 +505,7 @@ mod tests {
|
||||
|
||||
unsafe {
|
||||
// Remove missing
|
||||
let mut list = LinkedList::<&Entry>::new();
|
||||
let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
|
||||
|
||||
list.push_front(b.as_ref());
|
||||
list.push_front(a.as_ref());
|
||||
@@ -503,7 +519,7 @@ mod tests {
|
||||
let a = entry(5);
|
||||
let b = entry(7);
|
||||
|
||||
let mut list = LinkedList::<&Entry>::new();
|
||||
let mut list = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
|
||||
|
||||
assert_eq!(0, list.iter().count());
|
||||
|
||||
@@ -543,7 +559,7 @@ mod tests {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut ll = LinkedList::<&Entry>::new();
|
||||
let mut ll = LinkedList::<&Entry, <&Entry as Link>::Target>::new();
|
||||
let mut reference = VecDeque::new();
|
||||
|
||||
let entries: Vec<_> = (0..ops.len()).map(|i| entry(i as i32)).collect();
|
||||
|
||||
Reference in New Issue
Block a user