Skip to content

Commit

Permalink
feat(maitake): add WaitQueue (#191)
Browse files Browse the repository at this point in the history
this branch adds a `WaitQueue` type in `maitake::wait`. this allows
multiple tasks to wait for an event, and be woken either one at a time
(in FIFO fashion), or all at once.

there are additional APIs we could add here, but this is a good starting
place. there probably should be docs examples but i'm lazy.

Signed-off-by: Eliza Weisman <[email protected]>
  • Loading branch information
hawkw authored Jun 5, 2022
1 parent 233d2c8 commit 85d5b00
Show file tree
Hide file tree
Showing 12 changed files with 1,364 additions and 18 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ jobs:
run: rustup show
- uses: actions/checkout@v2
- name: run tests
run: cargo test -p maitake --no-default-features
# don't run doctests with `no-default-features`, as some of them
# require liballoc.
run: cargo test -p maitake --no-default-features --tests --lib

# run loom tests
maitake_loom:
Expand Down
46 changes: 46 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bin/loom
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -x

RUSTFLAGS="--cfg loom ${RUSTFLAGS}" \
LOOM_LOG="${LOOM_LOG:-info}" \
LOOM_LOG="${LOOM_LOG:-debug}" \
LOOM_LOCATION=true \
cargo test \
--profile loom \
Expand Down
10 changes: 5 additions & 5 deletions bitfield/src/bitfield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,11 @@ macro_rules! bitfield {
#[automatically_derived]
impl core::fmt::Debug for $Name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if f.alternate() {
f.debug_tuple(stringify!($Name)).field(&format_args!("{}", self)).finish()
} else {
f.debug_tuple(stringify!($Name)).field(&format_args!("{:#b}", self.0)).finish()
}
let mut dbg = f.debug_struct(stringify!($Name));
$(
dbg.field(stringify!($Field), &self.get(Self::$Field));
)+
dbg.finish()

}
}
Expand Down
5 changes: 4 additions & 1 deletion maitake/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ git = "https://github.com/tokio-rs/tracing"
[dev-dependencies]
futures-util = "0.3"

[target.'cfg(not(loom))'.dev-dependencies]
tracing-subscriber = { git = "https://github.com/tokio-rs/tracing", features = ["ansi", "fmt"] }

[target.'cfg(loom)'.dev-dependencies]
loom = { version = "0.5.5", features = ["futures"] }
loom = { version = "0.5.5", features = ["futures", "checkpoint"] }
tracing_01 = { package = "tracing", version = "0.1", default_features = false }
tracing_subscriber_03 = { package = "tracing-subscriber", version = "0.3.11", features = ["fmt"] }

Expand Down
2 changes: 1 addition & 1 deletion maitake/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![cfg_attr(docsrs, doc = include_str!("../README.md"))]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg, doc_cfg_hide))]
#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))]
#![cfg_attr(docsrs, doc(cfg_hide(docsrs, loom)))]
#![cfg_attr(not(test), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc;
Expand Down
39 changes: 37 additions & 2 deletions maitake/src/loom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,42 @@ pub(crate) use self::inner::*;

#[cfg(loom)]
mod inner {
#![allow(dead_code)]

#[cfg(feature = "alloc")]
pub use loom::alloc;
pub use loom::{cell, future, hint, model, sync, thread};
pub(crate) use loom::alloc;
pub(crate) use loom::{cell, future, hint, model, thread};

pub(crate) mod sync {
pub(crate) use loom::sync::*;

pub(crate) mod spin {
pub(crate) use loom::sync::MutexGuard;

/// Mock version of mycelium's spinlock, but using
/// `loom::sync::Mutex`. The API is slightly different, since the
/// mycelium mutex does not support poisoning.
#[derive(Debug)]
pub(crate) struct Mutex<T>(loom::sync::Mutex<T>);

impl<T> Mutex<T> {
#[track_caller]
pub(crate) fn new(t: T) -> Self {
Self(loom::sync::Mutex::new(t))
}

#[track_caller]
pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
self.0.try_lock().ok()
}

#[track_caller]
pub fn lock(&self) -> MutexGuard<'_, T> {
self.0.lock().expect("loom mutex will never poison")
}
}
}
}
}

#[cfg(not(loom))]
Expand All @@ -15,6 +48,8 @@ mod inner {
#[cfg(feature = "alloc")]
pub use alloc::sync::*;
pub use core::sync::*;

pub use mycelium_util::sync::spin;
}

pub(crate) use core::sync::atomic;
Expand Down
14 changes: 14 additions & 0 deletions maitake/src/scheduler/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ mod alloc {
static SCHEDULER: Lazy<StaticScheduler> = Lazy::new(StaticScheduler::new);
static IT_WORKED: AtomicBool = AtomicBool::new(false);

crate::util::trace_init();

SCHEDULER.spawn(async {
Yield::once().await;
IT_WORKED.store(true, Ordering::Release);
Expand All @@ -69,6 +71,7 @@ mod alloc {

const TASKS: usize = 10;

crate::util::trace_init();
for _ in 0..TASKS {
SCHEDULER.spawn(async {
Yield::once().await;
Expand All @@ -89,6 +92,7 @@ mod alloc {
static SCHEDULER: Lazy<StaticScheduler> = Lazy::new(StaticScheduler::new);
static COMPLETED: AtomicUsize = AtomicUsize::new(0);

crate::util::trace_init();
let chan = Chan::new(1);

SCHEDULER.spawn({
Expand All @@ -114,6 +118,7 @@ mod alloc {
static SCHEDULER: Lazy<StaticScheduler> = Lazy::new(StaticScheduler::new);
static COMPLETED: AtomicUsize = AtomicUsize::new(0);

crate::util::trace_init();
let chan = Chan::new(1);

SCHEDULER.spawn({
Expand Down Expand Up @@ -142,6 +147,8 @@ mod alloc {

const TASKS: usize = 10;

crate::util::trace_init();

for i in 0..TASKS {
SCHEDULER.spawn(async {
Yield::new(i).await;
Expand Down Expand Up @@ -196,6 +203,8 @@ mod custom_storage {
static SCHEDULER: StaticScheduler = unsafe { StaticScheduler::new_with_static_stub(&STUB) };
static IT_WORKED: AtomicBool = AtomicBool::new(false);

crate::util::trace_init();

MyBoxTask::spawn(&SCHEDULER, async {
Yield::once().await;
IT_WORKED.store(true, Ordering::Release);
Expand All @@ -217,6 +226,8 @@ mod custom_storage {

const TASKS: usize = 10;

crate::util::trace_init();

for _ in 0..TASKS {
MyBoxTask::spawn(&SCHEDULER, async {
Yield::once().await;
Expand All @@ -238,6 +249,7 @@ mod custom_storage {
static SCHEDULER: StaticScheduler = unsafe { StaticScheduler::new_with_static_stub(&STUB) };
static COMPLETED: AtomicUsize = AtomicUsize::new(0);

crate::util::trace_init();
let chan = Chan::new(1);

MyBoxTask::spawn(&SCHEDULER, {
Expand All @@ -264,6 +276,7 @@ mod custom_storage {
static SCHEDULER: StaticScheduler = unsafe { StaticScheduler::new_with_static_stub(&STUB) };
static COMPLETED: AtomicUsize = AtomicUsize::new(0);

crate::util::trace_init();
let chan = Chan::new(1);

MyBoxTask::spawn(&SCHEDULER, {
Expand Down Expand Up @@ -291,6 +304,7 @@ mod custom_storage {
static SCHEDULER: StaticScheduler = unsafe { StaticScheduler::new_with_static_stub(&STUB) };
static COMPLETED: AtomicUsize = AtomicUsize::new(0);

crate::util::trace_init();
const TASKS: usize = 10;

for i in 0..TASKS {
Expand Down
21 changes: 19 additions & 2 deletions maitake/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ macro_rules! test_dbg {
($e:expr) => {
match $e {
e => {
crate::util::tracing::debug!("{} = {:?}", stringify!($e), &e);
crate::util::tracing::debug!(
location = %core::panic::Location::caller(),
"{} = {:?}",
stringify!($e),
&e
);
e
}
}
Expand All @@ -33,7 +38,10 @@ macro_rules! test_trace {
#[cfg(test)]
macro_rules! test_trace {
($($args:tt)+) => {
crate::util::tracing::debug!($($args)+);
crate::util::tracing::debug!(
location = %core::panic::Location::caller(),
$($args)+
);
};
}

Expand Down Expand Up @@ -87,3 +95,12 @@ pub(crate) unsafe fn non_null<T>(ptr: *mut T) -> NonNull<T> {
unsafe fn non_null<T>(ptr: *mut T) -> NonNull<T> {
NonNull::new_unchecked(ptr)
}

#[cfg(all(test, not(loom)))]
pub(crate) fn trace_init() {
use tracing_subscriber::filter::LevelFilter;
let _ = tracing_subscriber::fmt()
.with_max_level(LevelFilter::TRACE)
.with_test_writer()
.try_init();
}
14 changes: 9 additions & 5 deletions maitake/src/wait.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
//! Waiter cells and queues to allow tasks to wait for notifications.
//!
//! This module implements two types of structure for waiting: a [`WaitCell`],
//! which stores a *single* waiting task, and a wait *queue*, which
//! which stores a *single* waiting task, and a [`WaitQueue`], which
//! stores a queue of waiting tasks.
pub(crate) mod cell;
pub use cell::WaitCell;
pub mod queue;

pub use self::cell::WaitCell;
#[doc(inline)]
pub use self::queue::WaitQueue;

use core::task::Poll;

/// An error indicating that a [`WaitCell`] or queue was closed while attempting
/// register a waiter.
#[derive(Clone, Debug, PartialEq, Eq)]
/// An error indicating that a [`WaitCell`] or [`WaitQueue`] was closed while
/// attempting register a waiter.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Closed(());

pub type WaitResult = Result<(), Closed>;
Expand Down
Loading

0 comments on commit 85d5b00

Please sign in to comment.