Closed Alexis211 closed 8 months ago
Reading through the changes, I must say I kind of like them. The overall feeling is it is kind of elegant and nice.
I do have few details to discuss, though:
lazy-cell
feature instead? Nevertheless, as long as this is a nightly-only feature, it probably should be marked as such ‒ something like experimental-lazy-cell
, so people know the stability guarantee doesn't hold.As for the old build… I think you can still build the crate if you delete the lock file. The lock file is not used when the crate is just a dependency.
How far away from stabilization are the features you use? Is it worth waiting for them, or can we rely on them not changing much?
The thread_local
feature has been in Nightly for a very long time, it doesn't look like it will be ready for stabilization anytime soon, but it also doesn't look like it is changing a lot. I think this is the main feature that is gating no_std support in our case. See rust-lang/rust#29594
The lazy_cell
feature is much more recent (<1 year, see rust-lang/rust#109736), and it looks like the design is still under debate, so maybe it's not a so good idea after all to rely on it. I pushed a new version that achieves the same result using RefCell<Option<_>>
instead of LazyCell<_>
, it's just a bit less elegant because we need explicit testing for initialization in LocalNode::with
, but it works. This should have near-zero impact on performance.
Eventually, it would be nice to use these in normal std build too, if they prove faster. In that regard, the no-std feature flag seems a bit misleading. Maybe something like lazy-cell feature instead? Nevertheless, as long as this is a nightly-only feature, it probably should be marked as such ‒ something like experimental-lazy-cell, so people know the stability guarantee doesn't hold.
I pushed a commit that renames the feature flag experimental-thread-local
, but then there is the question of support for std::sync::RwLock
. Currently it is disabled when experimental-thread-local
is enabled, but I was thinking maybe we could have a feature rwlock
that enables the std::sync::RwLock
support, and set it as a default feature. What do you think?
I think the CI needs to be adjusted a bit. Currently, it tries to run the no-std in stable / beta, which fails.
I pushed a commit that replaces all occurences of --all-features
in the CI scripts with an explcit list of features without experimental-thread-support
.
I think adjusting documentation would also be in place.
Yes, I didn't think of it. I'll do this last, when the other questions are resolved.
I think I fixed pretty much everything and added some documentation. Concerning the rw-lock thing, could you check that I did what you were expecting? Especially the conditional compilation in src/strategy/mod.rs
.
Thanks :)
Sorry for the delay on my end; this looks good. But the CI tests are currently failing due to some problem in proc-macro2 vs. newest nightly compiler. It is already resolved on master, so a rebase might help.
Also, when I do cargo test --features experimental-thread-local
(on nightly compiler, with dependencies updated), it fails. It seems the mod tests
sections weren't updated to use alloc::whatever
instead of std::whatever
and can't find things like Vec or String.
I fixed compilation of the tests when running cargo test --features experimental-thread-local
, but unfortunately the tests fail or hang. It looks like the thread local variable is not working correctly, for instance if I focus on the rcu
test, I can get outputs like this:
$ cargo test --features experimental-thread-local rcu
Finished test [unoptimized + debuginfo] target(s) in 0.04s
Running unittests src/lib.rs (target/debug/deps/arc_swap-834f36c9a23df4c3)
running 1 test
test tests_default::rcu ... FAILED
failures:
---- tests_default::rcu stdout ----
thread '<unnamed>' panicked at src/debt/list.rs:253:47:
already borrowed: BorrowMutError
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread '<unnamed>' panicked at src/debt/list.rs:253:47:
already borrowed: BorrowMutError
thread '<unnamed>' panicked at src/debt/list.rs:253:47:
already borrowed: BorrowMutError
thread '<unnamed>' panicked at src/debt/list.rs:253:47:
already borrowed: BorrowMutError
thread '<unnamed>' panicked at src/debt/list.rs:253:47:
already borrowed: BorrowMutError
thread 'tests_default::rcu' panicked at src/lib.rs:1236:1:
called `Result::unwrap()` on an `Err` value: Any { .. }
failures:
tests_default::rcu
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 31 filtered out; finished in 0.00s
error: test failed, to rerun pass `--lib`
Looking at a stack trace, it looks like there is a recursive function that calls LocalNode::with
within itself, leading to double-borrowing. I'll try to investigate if I have time.
Alright, I fixed the tests by using OnceCell
instead of RefCell
. All tests are working now with --feature experimental-thread-local
, I just had to disable the rcu_panic
test because panic::catch_unwind
is not available in no-std mode.
OK.
Before I go ahead and merge it, do you want to do some cleanup of the history? Because there's a lot of „changes due to review“ commits (which are kind of annoying in future browsing of the history, bisects, etc) instead some kind of per-topic commits. I can either squash it as a whole to a single commit, or you can sort it into something „nice“.
If you don't want to keep the current history, I think it's fine to just squash everything in a single commit.
Thank you, I've done a release.
This PR proposes a non-invasive, relatively minimal implementation of
no_std
support for thearc-swap
crate. The aim of this PR is to enableno_std
without much effort for specific use-cases such as embedded or os dev, which are often already using a nightly compiler anyways, without disturbing the existing functionning of the crate. I saw the previous PR for no_std support (#56) which was not merged due to lack of activity. If possible I'd like to do the necessary work so that we can have no_std support in arc-swap soon.This PR is minimally invaisve: if the
no-std
feature is not enabled then the build is pretty much exactly the same. The crate could successfully be compiled with Rust as low asv1.38.0
(same as before, see below).Compiling with the
no-std
feature requires a nightly Rust compiler, due to the use of unstable featuresthread_local
andlazy_cell
. No additionnal dependencies are added. Suppor forRwLock
is dropped inno_std
mode.This PR does not require additionnal OS dependencies and does not introducing more locking or synchronization points (it doesn't use the
static_init
crate as in #56). Due to lesser requirements, it is probably usefull on more platforms than #56, as long as support for compiler-generated thread local variables is available. FWIW, thetls-mode=emulated
makes it quite easy to add support for these thread-local variables on a variety of platforms even without OS/kernel support, without having to delve into the intricacies of linkers and symbol relocation (example in C from the Clang source code).To answer questions from the other thread (PR #56):
In this PR, we are using only the experimental
#[thread_local]
tag of the nightly compiler. This compiles down to LLVM thread local primitives, which are supposedly one of the fastest possible underlying implementation for std'sthread_local!
macro, so no performance penalty on that side is to be expected. Custom implementations can also be made easily without locks. The thread local variable itself that is used byarc-swap
is aLazyCell
which is notSync
, so there is no mutex or synchronizaton penalty on initialization.This is the case with this PR, albeit the lowest supported version is 1.38.0, which is not related to changes in this PR. Versions <=1.37.0 failed with the following error, which was already the case on the master branch:
Not an issue in this PR.
Unfortunately, this is not doable easily in the current state of the Rust ecosystem, at least not with a lot of additional effort. This PR is a minimal try to land
no_std
support in thearc-swap
crate as simply as possible, so it naturally comes with some restriction. I tried to have as little restrictions as possible, and basically there are only two conditions for this to be used: use a nightly compiler, and have support for compiler-generated thread local variables.I'd be glad to have your comments and advice on how we can make this into something that can be merged into
arc-swap
.