Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.lock

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

19 changes: 18 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ repository = "https://github.com/githedgehog/dataplane/"
#
# 1. correctly documenting what each package actually depends on,
# 2. allowing builds under different environments (e.g. cross-compilation, wasm, miri, and so on).
#
# Exceptions: see `tokio = { ..., features = ["parking_lot"] }` below. Each exception has a comment
# justifying why it is workspace-wide.

# Internal
args = { path = "./args", package = "dataplane-args", features = [] }
Expand Down Expand Up @@ -110,6 +113,7 @@ chrono = { version = "0.4.44", default-features = false, features = [] }
clap = { version = "4.6.1", default-features = true, features = [] }
color-eyre = { version = "0.6.5", default-features = false, features = [] }
colored = { version = "3.1.1", default-features = false, features = [] }
crossbeam-utils = { version = "0.8.21", default-features = false, features = [] }
ctrlc = { version = "3.5.2", default-features = false, features = [] }
dashmap = { version = "6.1.0", default-features = false, features = [] }
derive_builder = { version = "0.20.2", default-features = false, features = [] }
Expand Down Expand Up @@ -158,6 +162,7 @@ pci-ids = { version = "0.2.6", default-features = false, features = [] }
prefix-trie = { version = "0.8.4", default-features = false, features = [] }
pretty_assertions = { version = "1.4.1", default-features = false, features = [] }
priority-queue = { version = "2.7.0", default-features = false, features = [] }
proc-macro-crate = { version = "3.5.0", default-features = false, features = [] }
proc-macro2 = { version = "1.0.106", default-features = false, features = [] }
procfs = { version = "0.18.0", default-features = false, features = [] }
pyroscope = { version = "2.0.3", default-features = false, features = [] }
Expand All @@ -183,7 +188,13 @@ strum_macros = { version = "0.28.0", default-features = false, features = [] }
syn = { version = "2.0.117", default-features = false, features = [] }
thiserror = { version = "2.0.18", default-features = false, features = [] }
thread_local = { version = "1.1.9", default-features = false, features = [] }
tokio = { version = "1.52.3", default-features = false, features = [] }
# Exception to the "no workspace-wide features" rule above. `tokio/parking_lot` is
# not an additive feature in the usual sense -- it picks the lock implementation
# tokio uses internally for its runtime. Production builds already pull
# parking_lot in via `concurrency::sync`, so the only thing scoping this
# per-crate would buy is divergent runtime behaviour between test binaries
# and the real dataplane. Keep it global.
tokio = { version = "1.52.3", default-features = false, features = ["parking_lot"] }
tokio-util = { version = "0.7.18", default-features = false, features = [] }
tonic = { version = "0.14.6", default-features = false, features = [] }
tracing = { version = "0.1.44", default-features = false, features = [] }
Expand Down Expand Up @@ -247,6 +258,12 @@ package = "dataplane-cli"
miri = true
wasm = false # split

[workspace.metadata.package.concurrency]
package = "dataplane-concurrency"
miri = true # must ALWAYS work
# NOTE: concurrency should likely be dependency gated as `cfg(unix)` or `cfg(not(target_arch = "wasm32"))`
wasm = false # hopeless + pointless

[workspace.metadata.package.dataplane]
package = "dataplane"
miri = false # hopeless + pointless
Expand Down
3 changes: 2 additions & 1 deletion common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ publish.workspace = true
repository.workspace = true

[dependencies]
left-right = { workspace = true }
arc-swap = { workspace = true }
concurrency = { workspace = true }
left-right = { workspace = true }
31 changes: 29 additions & 2 deletions common/src/cliprovider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
//! A trait for a type that can provide CLI data

use arc_swap::{ArcSwap, ArcSwapOption};
use concurrency::slot::{Slot, SlotOption};
use concurrency::sync::Arc;
use left_right::ReadHandle;
use std::fmt::Display;
use std::sync::Arc;

/// A trait for types that can produce contents for the cli
pub trait CliDataProvider {
Expand Down Expand Up @@ -72,9 +73,35 @@ where
T: CliDataProvider,
{
fn provide(&self) -> String {
// No type annotation on `p`: `arc_swap::ArcSwapOption` always
// yields `std::sync::Arc<T>`, which is not the same type as
// `concurrency::sync::Arc<T>` under the `loom` backend.
// Letting inference do its job keeps this `impl` compiling on
// every backend.
self.load()
.as_ref()
.map(|p: &Arc<T>| p.provide())
.map(|p| p.provide())
.unwrap_or_else(|| "(none)".to_string())
}
}

impl<T> CliDataProvider for Slot<T>
where
T: CliDataProvider,
{
fn provide(&self) -> String {
self.load_full().provide()
}
}

impl<T> CliDataProvider for SlotOption<T>
where
T: CliDataProvider,
{
fn provide(&self) -> String {
self.load_full()
.as_ref()
.map(|p| p.provide())
.unwrap_or_else(|| "(none)".to_string())
}
}
Expand Down
18 changes: 18 additions & 0 deletions concurrency/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,25 @@ publish.workspace = true
version.workspace = true

[features]
default = ["parking_lot"]
loom = ["dep:loom", "concurrency-macros/loom"]
parking_lot = ["dep:parking_lot"]
# `shuttle*` are three views of one backend, not three backends:
#
# * `shuttle` -- shuttle with the random scheduler (the default
# for first-time users -- you almost always want
# this one).
# * `shuttle_pct` -- shuttle with the PCT scheduler. Use when you
# want to bias toward rare interleavings.
# * `shuttle_dfs` -- shuttle with the DFS scheduler. Use for
# exhaustive small-state exploration.
#
# All three share the same `dep:shuttle` machinery; only the scheduler
# selected at runtime differs. See the `concurrency_mode` macro and
# `concurrency::stress` (added in a later PR) for the dispatch.
shuttle = ["dep:shuttle", "concurrency-macros/shuttle"]
shuttle_pct = ["dep:shuttle", "concurrency-macros/shuttle"]
shuttle_dfs = ["dep:shuttle", "concurrency-macros/shuttle"]
silence_clippy = ["concurrency-macros/silence_clippy"] # Do not manually enable this feature, let --all-features do it for you
# Force the Mutex-based slot fallback even without a model checker.
# Intended for the CI miri job that exercises the fallback slot under
Expand All @@ -20,6 +37,7 @@ _strict_provenance = []
arc-swap = { workspace = true }
concurrency-macros = { workspace = true, features = [] }
loom = { workspace = true, optional = true, features = [] }
parking_lot = { workspace = true, optional = true, features = [] }
shuttle = { workspace = true, optional = true, features = [] }
static_assertions = { workspace = true }

Expand Down
32 changes: 9 additions & 23 deletions concurrency/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,28 @@
#![allow(missing_docs)]

pub mod macros;
pub mod sync;

#[cfg(all(miri, any(feature = "shuttle", feature = "loom")))]
compile_error!("miri does not meaningfully support 'loom' or 'shuttle'");

#[cfg(not(any(feature = "loom", feature = "shuttle")))]
pub use std::sync;

#[cfg(not(any(feature = "loom", feature = "shuttle")))]
pub use std::thread;

#[cfg(all(
#[cfg(not(any(
feature = "loom",
not(feature = "shuttle"),
not(feature = "silence_clippy")
))]
pub use loom::sync;
feature = "shuttle",
feature = "shuttle_pct",
feature = "shuttle_dfs"
)))]
pub use std::thread;

#[cfg(all(
feature = "loom",
not(feature = "shuttle"),
not(any(feature = "shuttle", feature = "shuttle_pct", feature = "shuttle_dfs")),
not(feature = "silence_clippy")
))]
pub use loom::thread;

#[cfg(all(
feature = "shuttle",
not(feature = "loom"),
not(feature = "silence_clippy")
))]
pub use shuttle::sync;

#[cfg(all(
feature = "shuttle",
any(feature = "shuttle", feature = "shuttle_pct", feature = "shuttle_dfs"),
not(feature = "loom"),
not(feature = "silence_clippy")
))]
Expand All @@ -57,9 +46,6 @@ compile_error!("Cannot enable both 'loom' and 'shuttle' features at the same tim
//////////////////////
// This is a workaround to silence clippy warnings when both loom and shuttle
// features are enabled in the clippy checks which uses --all-features.
#[cfg(all(feature = "shuttle", feature = "loom", feature = "silence_clippy"))]
pub use std::sync;

#[cfg(all(feature = "shuttle", feature = "loom", feature = "silence_clippy"))]
pub use std::thread;
//////////////////////
Expand Down
24 changes: 20 additions & 4 deletions concurrency/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
/// }
/// }
/// ```
#[cfg(all(feature = "shuttle", not(feature = "silence_clippy")))]
#[cfg(all(
any(feature = "shuttle", feature = "shuttle_pct", feature = "shuttle_dfs"),
not(feature = "silence_clippy")
))]
#[macro_export]
macro_rules! with_shuttle {
($($item:item)*) => {
Expand All @@ -39,7 +42,10 @@ macro_rules! with_shuttle {
/// }
/// }
/// ```
#[cfg(any(not(feature = "shuttle"), feature = "silence_clippy"))]
#[cfg(any(
not(any(feature = "shuttle", feature = "shuttle_pct", feature = "shuttle_dfs")),
feature = "silence_clippy"
))]
#[macro_export]
macro_rules! with_shuttle {
($($item:item)*) => {};
Expand Down Expand Up @@ -103,7 +109,12 @@ macro_rules! with_loom {
/// }
/// }
/// ```
#[cfg(not(any(feature = "loom", feature = "shuttle")))]
#[cfg(not(any(
feature = "loom",
feature = "shuttle",
feature = "shuttle_pct",
feature = "shuttle_dfs"
)))]
#[macro_export]
macro_rules! with_std {
($($item:item)*) => {
Expand Down Expand Up @@ -153,7 +164,12 @@ macro_rules! with_std {
/// ```
#[cfg(all(
not(feature = "silence_clippy"),
any(feature = "loom", feature = "shuttle")
any(
feature = "loom",
feature = "shuttle",
feature = "shuttle_pct",
feature = "shuttle_dfs"
)
))]
#[macro_export]
macro_rules! with_std {
Expand Down
25 changes: 18 additions & 7 deletions concurrency/src/quiescent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,28 @@ impl Domain {

fn register(&self) -> Epoch {
let epoch = Epoch::new();
#[allow(clippy::expect_used)] // the mutex is poisoned only in unrecoverable error cases
self.active
.lock()
.expect("qsbr mutex poisoned")
.push(Arc::clone(&epoch.cell));
let guard = self.active.lock();
// Loom still exposes `LockResult<MutexGuard>` raw; the
// poison-as-panic wrapper for loom lands in a subsequent PR
// and drops this `.expect`.
#[cfg(feature = "loom")]
#[allow(clippy::expect_used)]
// the mutex is poisoned only in unrecoverable error cases
let mut guard = guard.expect("qsbr mutex poisoned");
#[cfg(not(feature = "loom"))]
let mut guard = guard;
guard.push(Arc::clone(&epoch.cell));
epoch
}

fn min_observed(&self) -> Option<Version> {
#[allow(clippy::expect_used)] // the mutex is poisoned only in unrecoverable error cases
let mut active = self.active.lock().expect("qsbr mutex poisoned");
let guard = self.active.lock();
#[cfg(feature = "loom")]
#[allow(clippy::expect_used)]
// the mutex is poisoned only in unrecoverable error cases
let mut active = guard.expect("qsbr mutex poisoned");
#[cfg(not(feature = "loom"))]
let mut active = guard;
let mut min = u64::MAX;
let mut any_in_flight = false;
active.retain(|cell| {
Expand Down
Loading
Loading