async-executor/src/lib.rs

920 lines
25 KiB
Rust
Raw Normal View History

2020-08-26 21:46:09 +00:00
//! Async executors.
2020-07-23 10:03:03 +00:00
//!
//! # Examples
//!
//! ```
2020-08-26 21:46:09 +00:00
//! use async_executor::Executor;
//! use futures_lite::future;
2020-07-23 10:03:03 +00:00
//!
2020-08-26 21:46:09 +00:00
//! // Create a new executor.
2020-07-23 10:03:03 +00:00
//! let ex = Executor::new();
//!
2020-08-26 21:46:09 +00:00
//! // Spawn a task.
//! let task = ex.spawn(async {
//! println!("Hello world");
//! });
//!
2020-12-08 19:18:06 +00:00
//! // Run the executor until the task completes.
2020-08-26 21:46:09 +00:00
//! future::block_on(ex.run(task));
2020-07-23 10:03:03 +00:00
//! ```
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
use std::fmt;
2020-07-23 10:03:03 +00:00
use std::future::Future;
2020-08-26 21:46:09 +00:00
use std::marker::PhantomData;
use std::panic::{RefUnwindSafe, UnwindSafe};
use std::rc::Rc;
2020-09-14 13:51:17 +00:00
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, RwLock, TryLockError};
2020-09-19 20:38:11 +00:00
use std::task::{Poll, Waker};
2020-07-23 10:03:03 +00:00
use async_lock::OnceCell;
2020-09-19 20:38:11 +00:00
use async_task::Runnable;
2020-08-26 21:46:09 +00:00
use concurrent_queue::ConcurrentQueue;
2020-10-09 12:49:25 +00:00
use futures_lite::{future, prelude::*};
2021-04-18 13:39:34 +00:00
use slab::Slab;
2020-07-23 10:03:03 +00:00
2020-09-19 20:38:11 +00:00
#[doc(no_inline)]
pub use async_task::Task;
2020-08-26 21:46:09 +00:00
/// An async executor.
2020-07-23 10:03:03 +00:00
///
/// # Examples
///
2020-08-26 21:46:09 +00:00
/// A multi-threaded executor:
///
2020-07-23 10:03:03 +00:00
/// ```
/// use async_channel::unbounded;
/// use async_executor::Executor;
/// use easy_parallel::Parallel;
/// use futures_lite::future;
///
/// let ex = Executor::new();
/// let (signal, shutdown) = unbounded::<()>();
///
/// Parallel::new()
/// // Run four executor threads.
2020-08-26 21:46:09 +00:00
/// .each(0..4, |_| future::block_on(ex.run(shutdown.recv())))
2020-07-23 10:03:03 +00:00
/// // Run the main future on the current thread.
/// .finish(|| future::block_on(async {
/// println!("Hello world!");
/// drop(signal);
/// }));
/// ```
2020-09-20 14:30:35 +00:00
pub struct Executor<'a> {
/// The executor state.
state: OnceCell<Arc<State>>,
2020-09-20 14:30:35 +00:00
/// Makes the `'a` lifetime invariant.
_marker: PhantomData<std::cell::UnsafeCell<&'a ()>>,
2020-07-23 10:03:03 +00:00
}
2020-09-20 14:30:35 +00:00
unsafe impl Send for Executor<'_> {}
unsafe impl Sync for Executor<'_> {}
impl UnwindSafe for Executor<'_> {}
impl RefUnwindSafe for Executor<'_> {}
2020-09-19 20:38:11 +00:00
impl fmt::Debug for Executor<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
debug_executor(self, "Executor", f)
}
}
2020-09-20 14:30:35 +00:00
impl<'a> Executor<'a> {
2020-08-26 21:46:09 +00:00
/// Creates a new executor.
2020-07-23 10:03:03 +00:00
///
/// # Examples
///
/// ```
/// use async_executor::Executor;
2020-07-23 10:03:03 +00:00
///
/// let ex = Executor::new();
2020-07-23 10:03:03 +00:00
/// ```
2020-09-20 14:30:35 +00:00
pub const fn new() -> Executor<'a> {
2020-07-23 10:03:03 +00:00
Executor {
state: OnceCell::new(),
2020-09-20 14:30:35 +00:00
_marker: PhantomData,
2020-07-23 10:03:03 +00:00
}
}
2020-11-10 14:54:01 +00:00
/// Returns `true` if there are no unfinished tasks.
///
/// # Examples
///
/// ```
/// use async_executor::Executor;
///
/// let ex = Executor::new();
/// assert!(ex.is_empty());
///
/// let task = ex.spawn(async {
/// println!("Hello world");
/// });
/// assert!(!ex.is_empty());
///
/// assert!(ex.try_tick());
/// assert!(ex.is_empty());
/// ```
pub fn is_empty(&self) -> bool {
self.state().active.lock().unwrap().is_empty()
}
2020-07-23 10:03:03 +00:00
/// Spawns a task onto the executor.
///
/// # Examples
///
/// ```
/// use async_executor::Executor;
///
/// let ex = Executor::new();
///
/// let task = ex.spawn(async {
/// println!("Hello world");
/// });
/// ```
2020-09-20 14:30:35 +00:00
pub fn spawn<T: Send + 'a>(&self, future: impl Future<Output = T> + Send + 'a) -> Task<T> {
2020-09-20 00:36:54 +00:00
let mut active = self.state().active.lock().unwrap();
2020-09-20 00:38:56 +00:00
// Remove the task from the set of active tasks when the future finishes.
2021-04-18 13:39:34 +00:00
let index = active.vacant_entry().key();
2020-09-20 00:36:54 +00:00
let state = self.state().clone();
let future = async move {
2021-12-30 00:36:58 +00:00
let _guard = CallOnDrop(move || drop(state.active.lock().unwrap().try_remove(index)));
2020-09-20 00:36:54 +00:00
future.await
};
2020-09-20 00:38:56 +00:00
// Create the task and register it in the set of active tasks.
2020-09-20 14:30:35 +00:00
let (runnable, task) = unsafe { async_task::spawn_unchecked(future, self.schedule()) };
2020-09-20 00:36:54 +00:00
active.insert(runnable.waker());
2020-09-20 00:38:56 +00:00
2020-09-20 00:36:54 +00:00
runnable.schedule();
task
2020-07-23 10:03:03 +00:00
}
2020-08-29 16:26:28 +00:00
/// Attempts to run a task if at least one is scheduled.
///
/// Running a scheduled task means simply polling its future once.
///
/// # Examples
///
/// ```
/// use async_executor::Executor;
///
/// let ex = Executor::new();
/// assert!(!ex.try_tick()); // no tasks to run
///
/// let task = ex.spawn(async {
/// println!("Hello world");
/// });
/// assert!(ex.try_tick()); // a task was found
/// ```
pub fn try_tick(&self) -> bool {
match self.state().queue.pop() {
Err(_) => false,
2020-08-29 17:15:42 +00:00
Ok(runnable) => {
2020-08-29 16:26:28 +00:00
// Notify another ticker now to pick up where this ticker left off, just in case
// running the task takes a long time.
self.state().notify();
// Run the task.
2020-08-29 17:15:42 +00:00
runnable.run();
2020-08-29 16:26:28 +00:00
true
}
}
}
2020-11-10 14:54:01 +00:00
/// Runs a single task.
2020-08-29 16:26:28 +00:00
///
/// Running a task means simply polling its future once.
///
/// If no tasks are scheduled when this method is called, it will wait until one is scheduled.
///
/// # Examples
///
/// ```
/// use async_executor::Executor;
/// use futures_lite::future;
///
/// let ex = Executor::new();
///
/// let task = ex.spawn(async {
/// println!("Hello world");
/// });
/// future::block_on(ex.tick()); // runs the task
/// ```
pub async fn tick(&self) {
2020-08-29 17:15:42 +00:00
let state = self.state();
2020-08-29 17:57:21 +00:00
let runnable = Ticker::new(state).runnable().await;
2020-08-29 17:15:42 +00:00
runnable.run();
2020-08-29 16:26:28 +00:00
}
2020-07-23 10:03:03 +00:00
/// Runs the executor until the given future completes.
///
/// # Examples
///
/// ```
/// use async_executor::Executor;
2020-08-26 21:46:09 +00:00
/// use futures_lite::future;
2020-07-23 10:03:03 +00:00
///
/// let ex = Executor::new();
///
/// let task = ex.spawn(async { 1 + 2 });
2020-08-26 21:46:09 +00:00
/// let res = future::block_on(ex.run(async { task.await * 2 }));
2020-07-23 10:03:03 +00:00
///
/// assert_eq!(res, 6);
/// ```
2020-08-26 21:46:09 +00:00
pub async fn run<T>(&self, future: impl Future<Output = T>) -> T {
2020-08-29 16:26:28 +00:00
let runner = Runner::new(self.state());
2020-08-29 17:15:42 +00:00
// A future that runs tasks forever.
let run_forever = async {
loop {
for _ in 0..200 {
let runnable = runner.runnable().await;
runnable.run();
}
future::yield_now().await;
2020-08-29 16:26:28 +00:00
}
2020-08-29 17:15:42 +00:00
};
2020-07-23 10:03:03 +00:00
2020-08-29 17:15:42 +00:00
// Run `future` and `run_forever` concurrently until `future` completes.
future.or(run_forever).await
2020-08-26 21:46:09 +00:00
}
2020-09-19 20:40:06 +00:00
/// Returns a function that schedules a runnable task when it gets woken up.
fn schedule(&self) -> impl Fn(Runnable) + Send + Sync + 'static {
let state = self.state().clone();
// TODO(stjepang): If possible, push into the current local queue and notify the ticker.
move |runnable| {
state.queue.push(runnable).unwrap();
state.notify();
}
}
/// Returns a reference to the inner state.
fn state(&self) -> &Arc<State> {
self.state.get_or_init_blocking(|| Arc::new(State::new()))
2020-09-19 20:40:06 +00:00
}
}
2020-09-20 14:30:35 +00:00
impl Drop for Executor<'_> {
2020-09-19 20:40:06 +00:00
fn drop(&mut self) {
if let Some(state) = self.state.get() {
let mut active = state.active.lock().unwrap();
2021-04-18 13:39:34 +00:00
for w in active.drain() {
w.wake();
2020-09-19 20:40:06 +00:00
}
drop(active);
while state.queue.pop().is_ok() {}
}
}
}
2020-09-20 14:30:35 +00:00
impl<'a> Default for Executor<'a> {
fn default() -> Executor<'a> {
2020-09-19 20:40:06 +00:00
Executor::new()
}
}
/// A thread-local executor.
///
/// The executor can only be run on the thread that created it.
///
/// # Examples
///
/// ```
/// use async_executor::LocalExecutor;
/// use futures_lite::future;
///
/// let local_ex = LocalExecutor::new();
///
/// future::block_on(local_ex.run(async {
/// println!("Hello world!");
/// }));
/// ```
2020-09-20 14:30:35 +00:00
pub struct LocalExecutor<'a> {
2020-09-19 20:40:06 +00:00
/// The inner executor.
inner: Executor<'a>,
2020-09-19 20:40:06 +00:00
2020-09-20 14:30:35 +00:00
/// Makes the type `!Send` and `!Sync`.
2020-09-19 20:40:06 +00:00
_marker: PhantomData<Rc<()>>,
}
2020-09-20 14:30:35 +00:00
impl UnwindSafe for LocalExecutor<'_> {}
impl RefUnwindSafe for LocalExecutor<'_> {}
2020-09-19 20:40:06 +00:00
impl fmt::Debug for LocalExecutor<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
debug_executor(&self.inner, "LocalExecutor", f)
}
}
2020-09-20 14:30:35 +00:00
impl<'a> LocalExecutor<'a> {
2020-09-19 20:40:06 +00:00
/// Creates a single-threaded executor.
///
/// # Examples
///
/// ```
/// use async_executor::LocalExecutor;
///
/// let local_ex = LocalExecutor::new();
/// ```
2020-09-20 14:30:35 +00:00
pub const fn new() -> LocalExecutor<'a> {
2020-09-19 20:40:06 +00:00
LocalExecutor {
inner: Executor::new(),
2020-09-19 20:40:06 +00:00
_marker: PhantomData,
}
}
2020-11-10 14:54:01 +00:00
/// Returns `true` if there are no unfinished tasks.
///
/// # Examples
///
/// ```
/// use async_executor::LocalExecutor;
///
/// let local_ex = LocalExecutor::new();
/// assert!(local_ex.is_empty());
///
/// let task = local_ex.spawn(async {
/// println!("Hello world");
/// });
/// assert!(!local_ex.is_empty());
///
/// assert!(local_ex.try_tick());
/// assert!(local_ex.is_empty());
/// ```
pub fn is_empty(&self) -> bool {
self.inner().is_empty()
}
2020-09-19 20:40:06 +00:00
/// Spawns a task onto the executor.
///
/// # Examples
///
/// ```
/// use async_executor::LocalExecutor;
///
/// let local_ex = LocalExecutor::new();
///
/// let task = local_ex.spawn(async {
/// println!("Hello world");
/// });
/// ```
2020-09-20 14:30:35 +00:00
pub fn spawn<T: 'a>(&self, future: impl Future<Output = T> + 'a) -> Task<T> {
2020-09-20 00:36:54 +00:00
let mut active = self.inner().state().active.lock().unwrap();
2020-09-20 00:38:56 +00:00
// Remove the task from the set of active tasks when the future finishes.
2021-04-18 13:39:34 +00:00
let index = active.vacant_entry().key();
2020-09-20 00:36:54 +00:00
let state = self.inner().state().clone();
let future = async move {
2021-12-30 00:36:58 +00:00
let _guard = CallOnDrop(move || drop(state.active.lock().unwrap().try_remove(index)));
2020-09-20 00:36:54 +00:00
future.await
};
2020-09-20 00:38:56 +00:00
// Create the task and register it in the set of active tasks.
2020-09-20 14:30:35 +00:00
let (runnable, task) = unsafe { async_task::spawn_unchecked(future, self.schedule()) };
2020-09-20 00:36:54 +00:00
active.insert(runnable.waker());
2020-09-20 00:38:56 +00:00
2020-09-20 00:36:54 +00:00
runnable.schedule();
task
2020-09-19 20:40:06 +00:00
}
/// Attempts to run a task if at least one is scheduled.
///
/// Running a scheduled task means simply polling its future once.
///
/// # Examples
///
/// ```
/// use async_executor::LocalExecutor;
///
/// let ex = LocalExecutor::new();
/// assert!(!ex.try_tick()); // no tasks to run
///
/// let task = ex.spawn(async {
/// println!("Hello world");
/// });
/// assert!(ex.try_tick()); // a task was found
/// ```
pub fn try_tick(&self) -> bool {
self.inner().try_tick()
}
2020-11-10 14:54:01 +00:00
/// Runs a single task.
2020-09-19 20:40:06 +00:00
///
/// Running a task means simply polling its future once.
///
/// If no tasks are scheduled when this method is called, it will wait until one is scheduled.
///
/// # Examples
///
/// ```
/// use async_executor::LocalExecutor;
/// use futures_lite::future;
///
/// let ex = LocalExecutor::new();
///
/// let task = ex.spawn(async {
/// println!("Hello world");
/// });
/// future::block_on(ex.tick()); // runs the task
/// ```
pub async fn tick(&self) {
self.inner().tick().await
}
/// Runs the executor until the given future completes.
///
/// # Examples
///
/// ```
/// use async_executor::LocalExecutor;
/// use futures_lite::future;
///
/// let local_ex = LocalExecutor::new();
///
/// let task = local_ex.spawn(async { 1 + 2 });
/// let res = future::block_on(local_ex.run(async { task.await * 2 }));
///
/// assert_eq!(res, 6);
/// ```
pub async fn run<T>(&self, future: impl Future<Output = T>) -> T {
self.inner().run(future).await
}
2020-09-20 00:36:54 +00:00
/// Returns a function that schedules a runnable task when it gets woken up.
fn schedule(&self) -> impl Fn(Runnable) + Send + Sync + 'static {
let state = self.inner().state().clone();
move |runnable| {
state.queue.push(runnable).unwrap();
state.notify();
}
}
2020-09-19 20:40:06 +00:00
/// Returns a reference to the inner executor.
2020-09-20 14:30:35 +00:00
fn inner(&self) -> &Executor<'a> {
&self.inner
2020-09-19 20:40:06 +00:00
}
}
2020-09-20 14:30:35 +00:00
impl<'a> Default for LocalExecutor<'a> {
fn default() -> LocalExecutor<'a> {
2020-09-19 20:40:06 +00:00
LocalExecutor::new()
}
}
/// The state of a executor.
struct State {
/// The global queue.
queue: ConcurrentQueue<Runnable>,
/// Local queues created by runners.
local_queues: RwLock<Vec<Arc<ConcurrentQueue<Runnable>>>>,
/// Set to `true` when a sleeping ticker is notified or no tickers are sleeping.
notified: AtomicBool,
/// A list of sleeping tickers.
sleepers: Mutex<Sleepers>,
2020-09-20 00:36:54 +00:00
/// Currently active tasks.
2021-04-18 13:39:34 +00:00
active: Mutex<Slab<Waker>>,
2020-09-19 20:40:06 +00:00
}
impl State {
/// Creates state for a new executor.
fn new() -> State {
State {
queue: ConcurrentQueue::unbounded(),
local_queues: RwLock::new(Vec::new()),
notified: AtomicBool::new(true),
sleepers: Mutex::new(Sleepers {
count: 0,
wakers: Vec::new(),
free_ids: Vec::new(),
}),
2021-04-18 13:39:34 +00:00
active: Mutex::new(Slab::new()),
2020-09-19 20:40:06 +00:00
}
}
/// Notifies a sleeping ticker.
#[inline]
fn notify(&self) {
if self
2020-09-19 20:40:06 +00:00
.notified
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
2020-09-19 20:40:06 +00:00
{
let waker = self.sleepers.lock().unwrap().notify();
if let Some(w) = waker {
w.wake();
}
2020-08-26 21:46:09 +00:00
}
}
2020-09-19 20:40:06 +00:00
}
2020-08-26 21:46:09 +00:00
2020-09-19 20:40:06 +00:00
/// A list of sleeping tickers.
struct Sleepers {
/// Number of sleeping tickers (both notified and unnotified).
count: usize,
2020-09-19 20:38:11 +00:00
2020-09-19 20:40:06 +00:00
/// IDs and wakers of sleeping unnotified tickers.
///
/// A sleeping ticker is notified when its waker is missing from this list.
wakers: Vec<(usize, Waker)>,
2020-09-19 20:38:11 +00:00
2020-09-19 20:40:06 +00:00
/// Reclaimed IDs.
free_ids: Vec<usize>,
2020-07-23 10:03:03 +00:00
}
2020-09-19 20:40:06 +00:00
impl Sleepers {
/// Inserts a new sleeping ticker.
fn insert(&mut self, waker: &Waker) -> usize {
let id = match self.free_ids.pop() {
Some(id) => id,
None => self.count + 1,
};
self.count += 1;
self.wakers.push((id, waker.clone()));
id
}
/// Re-inserts a sleeping ticker's waker if it was notified.
///
/// Returns `true` if the ticker was notified.
fn update(&mut self, id: usize, waker: &Waker) -> bool {
for item in &mut self.wakers {
if item.0 == id {
if !item.1.will_wake(waker) {
item.1 = waker.clone();
2020-09-19 20:38:11 +00:00
}
2020-09-19 20:40:06 +00:00
return false;
2020-09-19 20:38:11 +00:00
}
2020-09-19 20:40:06 +00:00
}
2020-09-19 20:38:11 +00:00
2020-09-19 20:40:06 +00:00
self.wakers.push((id, waker.clone()));
true
}
/// Removes a previously inserted sleeping ticker.
///
/// Returns `true` if the ticker was notified.
fn remove(&mut self, id: usize) -> bool {
self.count -= 1;
self.free_ids.push(id);
for i in (0..self.wakers.len()).rev() {
if self.wakers[i].0 == id {
self.wakers.remove(i);
return false;
}
2020-09-19 20:38:11 +00:00
}
2020-09-19 20:40:06 +00:00
true
2020-08-29 16:26:28 +00:00
}
2020-09-19 20:40:06 +00:00
/// Returns `true` if a sleeping ticker is notified or no tickers are sleeping.
fn is_notified(&self) -> bool {
self.count == 0 || self.count > self.wakers.len()
}
/// Returns notification waker for a sleeping ticker.
///
/// If a ticker was notified already or there are no tickers, `None` will be returned.
fn notify(&mut self) -> Option<Waker> {
if self.wakers.len() == self.count {
self.wakers.pop().map(|item| item.1)
} else {
None
}
2020-07-23 10:03:03 +00:00
}
}
2020-08-29 17:57:21 +00:00
/// Runs task one by one.
2020-08-26 21:46:09 +00:00
struct Ticker<'a> {
/// The executor state.
state: &'a State,
/// Set to a non-zero sleeper ID when in sleeping state.
///
2020-08-26 21:46:09 +00:00
/// States a ticker can be in:
/// 1) Woken.
/// 2a) Sleeping and unnotified.
/// 2b) Sleeping and notified.
2020-09-14 13:51:17 +00:00
sleeping: AtomicUsize,
2020-08-26 21:46:09 +00:00
}
impl Ticker<'_> {
2020-08-29 17:57:21 +00:00
/// Creates a ticker.
2020-08-26 21:46:09 +00:00
fn new(state: &State) -> Ticker<'_> {
2020-08-29 16:26:28 +00:00
Ticker {
2020-08-26 21:46:09 +00:00
state,
2020-09-14 13:51:17 +00:00
sleeping: AtomicUsize::new(0),
2020-08-29 16:26:28 +00:00
}
2020-08-26 21:46:09 +00:00
}
/// Moves the ticker into sleeping and unnotified state.
///
2020-08-26 21:46:09 +00:00
/// Returns `false` if the ticker was already sleeping and unnotified.
fn sleep(&self, waker: &Waker) -> bool {
let mut sleepers = self.state.sleepers.lock().unwrap();
match self.sleeping.load(Ordering::SeqCst) {
2020-08-26 21:46:09 +00:00
// Move to sleeping state.
2020-09-14 13:51:17 +00:00
0 => self
.sleeping
.store(sleepers.insert(waker), Ordering::SeqCst),
2020-08-26 21:46:09 +00:00
// Already sleeping, check if notified.
id => {
2020-08-26 21:46:09 +00:00
if !sleepers.update(id, waker) {
return false;
}
}
}
2020-08-26 21:46:09 +00:00
self.state
.notified
.swap(sleepers.is_notified(), Ordering::SeqCst);
true
}
2020-08-26 21:46:09 +00:00
/// Moves the ticker into woken state.
fn wake(&self) {
let id = self.sleeping.swap(0, Ordering::SeqCst);
if id != 0 {
2020-08-26 21:46:09 +00:00
let mut sleepers = self.state.sleepers.lock().unwrap();
sleepers.remove(id);
self.state
.notified
.swap(sleepers.is_notified(), Ordering::SeqCst);
}
}
2020-08-29 17:57:21 +00:00
/// Waits for the next runnable task to run.
async fn runnable(&self) -> Runnable {
self.runnable_with(|| self.state.queue.pop().ok()).await
}
/// Waits for the next runnable task to run, given a function that searches for a task.
async fn runnable_with(&self, mut search: impl FnMut() -> Option<Runnable>) -> Runnable {
2020-08-29 17:15:42 +00:00
future::poll_fn(|cx| {
loop {
match search() {
None => {
// Move to sleeping and unnotified state.
if !self.sleep(cx.waker()) {
// If already sleeping and unnotified, return.
return Poll::Pending;
}
2020-08-29 16:26:28 +00:00
}
2020-08-29 17:15:42 +00:00
Some(r) => {
// Wake up.
self.wake();
2020-08-29 16:26:28 +00:00
2020-08-29 17:15:42 +00:00
// Notify another ticker now to pick up where this ticker left off, just in
// case running the task takes a long time.
self.state.notify();
2020-08-29 16:26:28 +00:00
2020-08-29 17:15:42 +00:00
return Poll::Ready(r);
}
2020-08-29 16:26:28 +00:00
}
}
2020-08-29 17:15:42 +00:00
})
.await
2020-08-29 16:26:28 +00:00
}
}
impl Drop for Ticker<'_> {
fn drop(&mut self) {
// If this ticker is in sleeping state, it must be removed from the sleepers list.
let id = self.sleeping.swap(0, Ordering::SeqCst);
if id != 0 {
2020-08-29 16:26:28 +00:00
let mut sleepers = self.state.sleepers.lock().unwrap();
let notified = sleepers.remove(id);
self.state
.notified
.swap(sleepers.is_notified(), Ordering::SeqCst);
// If this ticker was notified, then notify another ticker.
if notified {
drop(sleepers);
self.state.notify();
}
}
}
}
2020-08-29 17:57:21 +00:00
/// A worker in a work-stealing executor.
2020-08-29 16:26:28 +00:00
///
2020-08-29 17:57:21 +00:00
/// This is just a ticker that also has an associated local queue for improved cache locality.
2020-08-29 16:26:28 +00:00
struct Runner<'a> {
2020-08-29 17:57:21 +00:00
/// The executor state.
2020-08-29 16:26:28 +00:00
state: &'a State,
2020-08-29 17:57:21 +00:00
/// Inner ticker.
2020-08-29 16:26:28 +00:00
ticker: Ticker<'a>,
2020-08-29 17:57:21 +00:00
/// The local queue.
local: Arc<ConcurrentQueue<Runnable>>,
2020-08-29 16:26:28 +00:00
2020-08-29 17:57:21 +00:00
/// Bumped every time a runnable task is found.
ticks: AtomicUsize,
2020-08-29 16:26:28 +00:00
}
impl Runner<'_> {
/// Creates a runner and registers it in the executor state.
fn new(state: &State) -> Runner<'_> {
let runner = Runner {
state,
ticker: Ticker::new(state),
2020-08-29 17:57:21 +00:00
local: Arc::new(ConcurrentQueue::bounded(512)),
ticks: AtomicUsize::new(0),
2020-08-29 16:26:28 +00:00
};
2020-08-29 17:57:21 +00:00
state
.local_queues
.write()
.unwrap()
.push(runner.local.clone());
2020-08-29 16:26:28 +00:00
runner
}
2020-08-29 17:57:21 +00:00
/// Waits for the next runnable task to run.
2020-08-29 17:15:42 +00:00
async fn runnable(&self) -> Runnable {
let runnable = self
.ticker
2020-08-29 17:57:21 +00:00
.runnable_with(|| {
// Try the local queue.
if let Ok(r) = self.local.pop() {
2020-08-29 17:15:42 +00:00
return Some(r);
2020-08-26 21:46:09 +00:00
}
2020-08-29 17:15:42 +00:00
// Try stealing from the global queue.
if let Ok(r) = self.state.queue.pop() {
2020-08-29 17:57:21 +00:00
steal(&self.state.queue, &self.local);
2020-08-29 17:15:42 +00:00
return Some(r);
2020-08-26 21:46:09 +00:00
}
2020-08-29 17:57:21 +00:00
// Try stealing from other runners.
let local_queues = self.state.local_queues.read().unwrap();
2020-08-26 21:46:09 +00:00
2020-08-29 17:15:42 +00:00
// Pick a random starting point in the iterator list and rotate the list.
2020-08-29 17:57:21 +00:00
let n = local_queues.len();
2020-08-29 17:15:42 +00:00
let start = fastrand::usize(..n);
2020-08-29 17:57:21 +00:00
let iter = local_queues
.iter()
.chain(local_queues.iter())
.skip(start)
.take(n);
// Remove this runner's local queue.
let iter = iter.filter(|local| !Arc::ptr_eq(local, &self.local));
// Try stealing from each local queue in the list.
for local in iter {
steal(local, &self.local);
if let Ok(r) = self.local.pop() {
2020-08-29 17:15:42 +00:00
return Some(r);
}
}
2020-08-26 21:46:09 +00:00
2020-08-29 17:15:42 +00:00
None
})
.await;
2020-08-26 21:46:09 +00:00
2020-08-29 17:57:21 +00:00
// Bump the tick counter.
let ticks = self.ticks.fetch_add(1, Ordering::SeqCst);
2020-08-29 17:15:42 +00:00
if ticks % 64 == 0 {
2020-08-29 17:57:21 +00:00
// Steal tasks from the global queue to ensure fair task scheduling.
steal(&self.state.queue, &self.local);
2020-08-26 21:46:09 +00:00
}
2020-08-29 17:15:42 +00:00
runnable
2020-08-26 21:46:09 +00:00
}
}
2020-08-29 16:26:28 +00:00
impl Drop for Runner<'_> {
2020-08-26 21:46:09 +00:00
fn drop(&mut self) {
2020-08-29 17:57:21 +00:00
// Remove the local queue.
2020-08-26 21:46:09 +00:00
self.state
2020-08-29 17:57:21 +00:00
.local_queues
2020-08-26 21:46:09 +00:00
.write()
.unwrap()
2020-08-29 17:57:21 +00:00
.retain(|local| !Arc::ptr_eq(local, &self.local));
2020-08-26 21:46:09 +00:00
2020-08-29 17:57:21 +00:00
// Re-schedule remaining tasks in the local queue.
while let Ok(r) = self.local.pop() {
2020-08-26 21:46:09 +00:00
r.schedule();
}
}
}
2020-08-26 21:46:09 +00:00
/// Steals some items from one queue into another.
fn steal<T>(src: &ConcurrentQueue<T>, dest: &ConcurrentQueue<T>) {
// Half of `src`'s length rounded up.
let mut count = (src.len() + 1) / 2;
if count > 0 {
// Don't steal more than fits into the queue.
if let Some(cap) = dest.capacity() {
count = count.min(cap - dest.len());
}
// Steal tasks.
for _ in 0..count {
if let Ok(t) = src.pop() {
assert!(dest.push(t).is_ok());
} else {
break;
}
}
}
}
/// Debug implementation for `Executor` and `LocalExecutor`.
fn debug_executor(executor: &Executor<'_>, name: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Get a reference to the state.
let state = match executor.state.get() {
Some(state) => state,
None => {
// The executor has not been initialized.
struct Uninitialized;
impl fmt::Debug for Uninitialized {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<uninitialized>")
}
}
return f.debug_tuple(name).field(&Uninitialized).finish();
}
};
/// Debug wrapper for the number of active tasks.
struct ActiveTasks<'a>(&'a Mutex<Slab<Waker>>);
impl fmt::Debug for ActiveTasks<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0.try_lock() {
Ok(lock) => fmt::Debug::fmt(&lock.len(), f),
Err(TryLockError::WouldBlock) => f.write_str("<locked>"),
Err(TryLockError::Poisoned(_)) => f.write_str("<poisoned>"),
}
}
}
/// Debug wrapper for the local runners.
struct LocalRunners<'a>(&'a RwLock<Vec<Arc<ConcurrentQueue<Runnable>>>>);
impl fmt::Debug for LocalRunners<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0.try_read() {
Ok(lock) => f
.debug_list()
.entries(lock.iter().map(|queue| queue.len()))
.finish(),
Err(TryLockError::WouldBlock) => f.write_str("<locked>"),
Err(TryLockError::Poisoned(_)) => f.write_str("<poisoned>"),
}
}
}
/// Debug wrapper for the sleepers.
struct SleepCount<'a>(&'a Mutex<Sleepers>);
impl fmt::Debug for SleepCount<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0.try_lock() {
Ok(lock) => fmt::Debug::fmt(&lock.count, f),
Err(TryLockError::WouldBlock) => f.write_str("<locked>"),
Err(TryLockError::Poisoned(_)) => f.write_str("<poisoned>"),
}
}
}
f.debug_struct(name)
.field("active", &ActiveTasks(&state.active))
.field("global_tasks", &state.queue.len())
.field("local_runners", &LocalRunners(&state.local_queues))
.field("sleepers", &SleepCount(&state.sleepers))
.finish()
}
2020-09-19 20:38:11 +00:00
/// Runs a closure when dropped.
struct CallOnDrop<F: Fn()>(F);
impl<F: Fn()> Drop for CallOnDrop<F> {
fn drop(&mut self) {
(self.0)();
}
}