Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an efficient implementation based on critical-section #148

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

notgull
Copy link
Member

@notgull notgull commented Nov 17, 2024

The current no-std implementation is somewhat ineffecient, potentially
broken and relies on some slow data structures. The main reason why we
use this implementation is because we don't have a way to "lock" the
linked list, since there's no way to lock things in no-std. However,
many embedded platforms have a concept of a "critical section" that can
be used to exclusively lock something.

This PR adds an option to the "std" implementation that replaces the
existing Mutex with a usage of the critical-section crate. This is
enabled with the "critical-section" feature. This allows us to have the
advantages of the std-based implementation without needing to rely on
std for platforms that don't have it.

@notgull notgull requested a review from fogti November 17, 2024 19:41
The current no-std implementation is somewhat ineffecient, potentially
broken and relies on some slow data structures. The main reason why we
use this implementation is because we don't have a way to "lock" the
linked list, since there's no way to lock things in no-std. However,
many embedded platforms have a concept of a "critical section" that can
be used to exclusively lock something.

This PR adds an option to the "std" implementation that replaces the
existing Mutex with a usage of the critical-section crate. This is
enabled with the "critical-section" feature. This allows us to have the
advantages of the std-based implementation without needing to rely on
std for platforms that don't have it.

Signed-off-by: John Nunley <dev@notgull.net>
Copy link
Member

@zeenix zeenix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool stuff! I had planned to look into critical-sections for async-broadcast but never got around to it. However, since a-b depends on event-listener, this is required anyway. I just have a confusion and a nitpick to offer. :)

src/std.rs Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
Since `std.rs` and `no_std.rs` no longer correspond to std and no_std,
I've renamed them based on the underlying algorithm used. `std.rs` is
now `intrusive.rs`, since it uses an intrusive linked list. `no_std.rs`
is now `slab.rs`, since it relies on a structure similar to the one used
in the `slab` crate.

Signed-off-by: John Nunley <dev@notgull.net>
Copy link
Member

@fogti fogti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, there is at least one small problem, tho.

src/intrusive.rs Outdated Show resolved Hide resolved
src/intrusive.rs Outdated
@@ -274,11 +337,13 @@ impl<T> Inner<T> {
}
}

#[cfg(all(feature = "std", not(feature = "critical-section")))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imo it would be a good idea to put ListLock into a separate file and mark the whole file with #[cfg(...)], this would make this easier to read.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've inlined the entire construct into with_inner.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh that's quite neat, thank you.

@@ -1359,7 +1365,7 @@ mod sync {
#[cfg(feature = "portable-atomic")]
pub(super) use portable_atomic_util::Arc;

#[cfg(all(feature = "std", not(loom)))]
#[cfg(all(feature = "std", not(feature = "critical-section"), not(loom)))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why wasn't the critical_section::Mutex import put here, too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because critical-section doesn't rely on loom intrinsically.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm std also doesn't rely on loom intrinsically; or how is that meant?/ what does that mean?

I just thought it should belong here because that part does accumulate definitions which are basically "alternatives" between different features used throughout the code, and the underlying Mutex impl imo is one of those "switchable" things (unfortunately not with a 1-to-1 common/shared sufficient API)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With std you need to replace std's primitives with loom, with critical-section you can just use a CS based on Loom.

@notgull notgull force-pushed the notgull/cs branch 2 times, most recently from a6bd06d to a90f8ff Compare November 23, 2024 19:00
src/intrusive.rs Outdated Show resolved Hide resolved
- Untangle imports.
- Inline the entirely of ListLock into with_inner().
- Add documentation for feature.

Signed-off-by: John Nunley <dev@notgull.net>
/// libstd-based implementation uses a normal Muetx to secure the data.
#[cfg(all(feature = "std", not(feature = "critical-section")))]
crate::sync::Mutex<Inner<T>>,
/// CS-based implementation uses a CS cell that wraps a RefCell.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should spell out critical section instead of CS at least once, otherwise it might lead to confusion.

};

#[cfg(feature = "critical-section")]
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary parentheses

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants