Skip to content
Merged
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
29 changes: 16 additions & 13 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -368,12 +368,15 @@ jobs:
miri::cpu=${{ matrix.cpu }}
with:
recipe: "miri::test"
# quiescent is especially sensitive to concurrency violations and memory model issues so we run it
# again with and without strict provenance enabled and on many different random schedules
# The permissive provenance build runs with real arc-swap and could therefore catch issues which the strict can't.
# We run under extra schedules to make that effect stand out as much as possible (shuttle/loom can't test with the
# arc-swap in place either, so this is the closest we can get to fixing that coverage gap)
- name: "quiescent/permissive"
# The quiescent code is especially sensitive to concurrency violations
# and memory-model issues so we run it again with and without strict
# provenance enabled and on many different random schedules. The
# permissive-provenance build runs with real arc-swap and could
# therefore catch issues which the strict run can't. We run under
# extra schedules to make that effect stand out as much as possible
# (shuttle/loom can't test with arc-swap in place either, so this is
# the closest we can get to fixing that coverage gap).
- name: "concurrency/permissive"
uses: *just
env:
JUST_VARS: >-
Expand All @@ -382,16 +385,16 @@ jobs:
miri::provenance=permissive
with:
recipe: "miri::test"
recipe_args: "--package=dataplane-quiescent"
- name: "quiescent/strict"
recipe_args: "--package=dataplane-concurrency"
- name: "concurrency/strict"
uses: *just
env:
JUST_VARS: >-
miri::cpu=${{ matrix.cpu }}
miri::provenance=strict
with:
recipe: "miri::test"
recipe_args: "--package=dataplane-quiescent --features=_strict_provenance"
recipe_args: "--package=dataplane-concurrency --features=_strict_provenance"
- *tmate

wasm:
Expand Down Expand Up @@ -521,12 +524,12 @@ jobs:
# The `loom` feature flips `concurrency::sync` to loom's
# primitives workspace-wide, which breaks crates that rely on
# `Weak`, `Arc::downgrade`, etc. (those aren't in
# `loom::sync`). Scope the loom build to only the quiescent
# package so workspace feature unification doesn't poison
# unrelated crates.
# `loom::sync`). Scope the loom build to only the concurrency
# package (which hosts the quiescent tests) so workspace
# feature unification doesn't poison unrelated crates.
- build: *release-build
features: "loom"
test_package: "quiescent"
test_package: "concurrency"
- build: *release-build
features: "shuttle"
test_package: ""
Expand Down
15 changes: 3 additions & 12 deletions Cargo.lock

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

7 changes: 0 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ members = [
"nat",
"net",
"pipeline",
"quiescent",
"rekon",
"routing",
"stats",
Expand Down Expand Up @@ -81,7 +80,6 @@ mgmt = { path = "./mgmt", package = "dataplane-mgmt", features = [] }
nat = { path = "./nat", package = "dataplane-nat", features = [] }
net = { path = "./net", package = "dataplane-net", features = [] }
pipeline = { path = "./pipeline", package = "dataplane-pipeline", features = [] }
quiescent = { path = "./quiescent", package = "dataplane-quiescent", features = [] }
rekon = { path = "./rekon", package = "dataplane-rekon", features = [] }
routing = { path = "./routing", package = "dataplane-routing", features = [] }
stats = { path = "./stats", package = "dataplane-stats", features = [] }
Expand Down Expand Up @@ -339,11 +337,6 @@ package = "dataplane-tracectl"
miri = false # hopeless + pointless
wasm = false # hopeless + pointless

[workspace.metadata.package.quiescent]
package = "dataplane-quiescent"
miri = true
wasm = false # works but pointless

[workspace.metadata.package.vpcmap]
package = "dataplane-vpcmap"
miri = true
Expand Down
13 changes: 12 additions & 1 deletion concurrency/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,19 @@ version.workspace = true
loom = ["dep:loom", "concurrency-macros/loom"]
shuttle = ["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
# strict-provenance; arc_swap uses hazard pointers that strict-provenance
# rejects, so the production slot can't be miri-checked under strict
# provenance.
_strict_provenance = []

[dependencies]
arc-swap = { workspace = true }
concurrency-macros = { workspace = true, features = [] }
loom = { workspace = true, optional = true, features = [] }
shuttle = { workspace = true, optional = true, features = [] }
concurrency-macros = { workspace = true, features = [] }
static_assertions = { workspace = true }

[dev-dependencies]
bolero = { workspace = true, features = ["std"] }
File renamed without changes.
3 changes: 3 additions & 0 deletions concurrency/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ compile_error!("silence_clippy manually enabled, should only be enabled by --all

#[allow(unused_imports)]
pub use macros::*;

pub mod quiescent;
pub mod slot;
Comment thread
daniel-noland marked this conversation as resolved.
19 changes: 4 additions & 15 deletions quiescent/src/lib.rs → concurrency/src/quiescent.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Open Network Fabric Authors

#![doc = include_str!("../README.md")]
#![forbid(unsafe_code)]
#![deny(
missing_docs,
clippy::pedantic,
clippy::unwrap_used,
clippy::expect_used,
clippy::panic
)]

mod slot;
#![doc = include_str!("../QUIESCENT.md")]

use core::cell::{Cell, RefCell};
use core::marker::PhantomData;
use core::num::NonZero;

use concurrency::sync::{
use crate::slot::Slot;
use crate::sync::{
Arc, Mutex,
atomic::{AtomicU64, Ordering},
};

use crate::slot::Slot;

struct Versioned<T> {
/// Monotonic version stamp assigned by the Publisher.
version: Version,
Expand Down Expand Up @@ -102,7 +91,7 @@ impl Domain {
// any subsequent `retired.clear()` decrement of the
// matching `Versioned` is now ordered after the
// Subscriber's prior `cached = None` decrement.
concurrency::sync::atomic::fence(Ordering::Acquire);
crate::sync::atomic::fence(Ordering::Acquire);
return false;
}
let observed = cell.load();
Expand Down
20 changes: 10 additions & 10 deletions quiescent/src/slot.rs → concurrency/src/slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,46 +21,46 @@
// fallback implementation.
cfg_select! {
any(feature = "loom", feature = "shuttle", feature = "_strict_provenance") => {
use concurrency::sync::{Arc, Mutex};
use crate::sync::{Arc, Mutex};

pub(crate) struct Slot<T>(Mutex<Arc<T>>);
pub struct Slot<T>(Mutex<Arc<T>>);

impl<T> Slot<T> {
pub(crate) fn from_pointee(value: T) -> Self {
pub fn from_pointee(value: T) -> Self {
Self(Mutex::new(Arc::new(value)))
}

pub(crate) fn load_full(&self) -> Arc<T> {
pub fn load_full(&self) -> Arc<T> {
#[allow(clippy::expect_used)] // poisoned only in unrecoverable cases
Arc::clone(&self.0.lock().expect("slot mutex poisoned"))
}

pub(crate) fn swap(&self, new: Arc<T>) -> Arc<T> {
pub fn swap(&self, new: Arc<T>) -> Arc<T> {
#[allow(clippy::expect_used)]
let mut guard = self.0.lock().expect("slot mutex poisoned");
core::mem::replace(&mut *guard, new)
}
}
}
_ => {
use concurrency::sync::Arc;
use crate::sync::Arc;
use arc_swap::ArcSwap;

pub(crate) struct Slot<T>(ArcSwap<T>);
pub struct Slot<T>(ArcSwap<T>);

impl<T> Slot<T> {
#[inline]
pub(crate) fn from_pointee(value: T) -> Self {
pub fn from_pointee(value: T) -> Self {
Self(ArcSwap::from_pointee(value))
}

#[inline]
pub(crate) fn load_full(&self) -> Arc<T> {
pub fn load_full(&self) -> Arc<T> {
self.0.load_full()
}

#[inline]
pub(crate) fn swap(&self, new: Arc<T>) -> Arc<T> {
pub fn swap(&self, new: Arc<T>) -> Arc<T> {
self.0.swap(new)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

use loom::thread;

use dataplane_quiescent::{Publisher, channel};
use dataplane_concurrency::quiescent::{Publisher, channel};

/// Run `body` with a `&'static` reference to a freshly-constructed
/// `Publisher`. After `body` returns, recover the `Box` and drop the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

use bolero::TypeGenerator;
use dataplane_quiescent::channel;
use dataplane_concurrency::quiescent::channel;

// ---------- ops & state ----------

Expand Down Expand Up @@ -171,7 +171,7 @@ fn protocol_invariants() {
/// gap on a function that only differs from the auto-derive in name.
#[test]
fn factory_clone_uses_explicit_impl() {
let publisher = dataplane_quiescent::channel(0u32);
let publisher = dataplane_concurrency::quiescent::channel(0u32);
let factory = publisher.factory();
#[allow(clippy::clone_on_copy)]
let _factory_clone = factory.clone();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

use dataplane_quiescent::channel;
use dataplane_concurrency::quiescent::channel;

// ---------- helpers ----------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
use std::panic::RefUnwindSafe;

use bolero::TypeGenerator;
use concurrency::sync::Arc;
use concurrency::sync::atomic::{AtomicUsize, Ordering};
use concurrency::thread;
use dataplane_concurrency::sync::Arc;
use dataplane_concurrency::sync::atomic::{AtomicUsize, Ordering};
use dataplane_concurrency::thread;

use dataplane_quiescent::{Subscriber, channel};
use dataplane_concurrency::quiescent::{Subscriber, channel};

// ---------- ops & plan ----------

Expand Down
13 changes: 12 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,18 @@ _cargo_feature_flags := \
_cargo_profile_flag := if profile == "debug" { "" } else { "--profile " + profile }

# filters for nextest
filter := if features == "shuttle" { "shuttle" } else if features == "loom" { "-E 'binary(loom)'" } else { "" }
#
# Under `shuttle`, isolate the bolero x shuttle suite (a `shuttle`
# substring matches both the test binary and the test-name
# convention).
#
# Under `loom`, the legacy filter `-E 'binary(loom)'` matched the
# old `dataplane-quiescent` `loom` test binary. After absorbing
# the crate, the binary is `quiescent_loom` (and later test files
# add more); an empty filter lets nextest walk every archived
# binary. Tests that don't apply under loom are cfg-gated out and
# compile to zero entries.
filter := if features == "shuttle" { "shuttle" } else { "" }

# instrumentation mode (none/coverage)
instrument := "none"
Expand Down
29 changes: 0 additions & 29 deletions quiescent/Cargo.toml

This file was deleted.

Loading