Git Product home page Git Product logo

Comments (10)

jonas-schievink avatar jonas-schievink commented on May 22, 2024 1

This is AtomicUsize

from bare-metal.

pftbest avatar pftbest commented on May 22, 2024 1

@Ten0

Here is a real example with your code https://godbolt.org/z/GsYx1q

you can see that

    // Wait for the flag
    while FOO.get() == 0 {
        // nop
    }

is compiled to

    // Wait for the flag
    if FOO.get() == 0 {
        loop {
            // nop
        }
    }

Compiler assumes there is no data races in the code, so value of FOO can never change inside the loop. Which means no need to read it every time we can check it only once.

from bare-metal.

adamgreig avatar adamgreig commented on May 22, 2024 1

This exact problem actually can occur with the bare-metal Mutex, which is why we added documentation in #34 after discussion in #33 (comment). In the cortex-m crate, compiler fences or memory clobbers are used when entering and leaving critical sections to ensure the compiler does not move accesses outside the the critical section, as otherwise @pftbest's example above would miscompile the same way.

from bare-metal.

Ten0 avatar Ten0 commented on May 22, 2024

This is AtomicUsize

But is this available on all single-core platforms, e.g. Cortex M0? I thought it wasn't (https://rust-embedded.github.io/book/concurrency/index.html#atomic-access). Also if it does synchronization across cores, it's not exactly the same thing as I'm proposing: atomics across interrupts on the same core, with no cross-core synchronization overhead.

from bare-metal.

jonas-schievink avatar jonas-schievink commented on May 22, 2024

The atomic types are available everywhere (if not, that's a bug in Rust or LLVM), but CAS operations might not be. load and store are always available.

You still need to synchronize access between interrupt handlers and idle. As written, SingleCoreAtomicUsize causes data races between every get and set, which is undefined behavior.

from bare-metal.

Ten0 avatar Ten0 commented on May 22, 2024

The atomic types are available everywhere (if not, that's a bug in Rust or LLVM), but CAS operations might not be. load and store are always available.

Thanks, I will double check this.

You still need to synchronize access between interrupt handlers and idle. As written, SingleCoreAtomicUsize causes data races between every get and set, which is undefined behavior.

I don't understand what data race you're talking about. Could you give an example of a scenario where the data race would trigger, and how it's UB?

Also, I'm unsure how I can get AtomicUsize to have the behaviour I was looking for: for platforms that do support multi-core (e.g your typical computer), how would you trigger a no-cross-core-synchronization read or write from an AtomicUsize? Just using Ordering::Relaxed?

from bare-metal.

jonas-schievink avatar jonas-schievink commented on May 22, 2024

The unsafe impl Sync allows use of SingleCoreAtomicUsize across threads, but there is no inner synchronization, so any usage of get or set from more than one thread would be a data race, as the stores and loads happen unsynchronized with each other.

This is still the case if you replace "thread" with "interrupt handler". For example, the compiler might assume that a value loaded by subsequent gets stays the same if there is no set inbetween. This is wrong in the presence of interrupts.

The Relaxed ordering is all you need as long as you only need to synchronize accesses of the AtomicUsize itself, not any other data (the other orderings are used when writing lock free data structures with atomics, and affect how the compiler synchronizes non-atomic accesses to the actual data stored in the data structure).

from bare-metal.

Ten0 avatar Ten0 commented on May 22, 2024

Thanks a lot for the explanation 👍 I think I understood almost all of it now! :)

The compiler might assume that a value loaded by subsequent gets stays the same if there is no set inbetween. This is wrong in the presence of interrupts.

From the UnsafeCell documentation:

UnsafeCell is a type that wraps some T and indicates unsafe interior operations on the wrapped type. Types with an UnsafeCell field are considered to have an 'unsafe interior'.
The compiler makes optimizations based on the knowledge that &T is not mutably aliased or mutated, and that &mut T is unique. UnsafeCell is the only core language feature to work around the restriction that &T may not be mutated.

I thought this explained it prevented that kind of optimizations.and enforced actually re-reading the value everytime it's asked.
Does it actually only force re-read if the compiler detects it might have changed due to some mutable aliasing, but in the same execution flow?

from bare-metal.

jonas-schievink avatar jonas-schievink commented on May 22, 2024

That was just an example of an assumption that a compiler might make. You'd have to ask that question in terms of Rust's language semantics to get a complete answer, and I'm not sure how the precise answer looks there.

from bare-metal.

Ten0 avatar Ten0 commented on May 22, 2024

Great, thank you for all the examples and references!
Closing this as it's already in core.

from bare-metal.

Related Issues (11)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.