-
Notifications
You must be signed in to change notification settings - Fork 101
Address Multi-Core Soundness by abolishing Send and Sync #419
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
Address Multi-Core Soundness by abolishing Send and Sync #419
Conversation
I’ll ask one possibly naive question: Why do we need a separate model to represent multi-core behavior in bare metal programs, when this is not necessary for desktop CPUs with multiple cores? Is this due to the operating system abstracting away the reality of disjoint sets of resources between CPU cores in hosted environments? For microcontrollers, we’ve taken the metaphor that “threads” can mean:
In desktop PCs, there is no difference to Rust between moving data between threads on the same CPU/Core, or to threads on another CPU/Core. Is this a model we should be aiming to upstream to Rust proper, perhaps as an uncommon but existent component of core? Or is it only relevant where the context details of actual execution matters, and should live within the embedded domain? |
Correct. While APIs exist that allow making threads not share resources, and make processes do share resources, the "default" is that all threads within a program do share all of the program's resources, and this is the only use case intended to be modeled by
For now, I don't think this is of much general interest. The proposed traits are very embedded-specific and I don't see how they can be made more general (nor do I think they should). While there's certainly a use case for making shared memory and IPC in general safe to use, that would likely require different traits specific to the exposed mechanism. |
I think that this RFC is missing a key section: what types will implement |
I like this RFC; it keeps the common case (single core) simple and correct for existing and future code, we could still use Send and Sync with future RTOSs that could correctly handle multiple threads on one or multiple cores, and for today's multi-core programs, treating them as separate processes that need to use some form of IPC to communicate seems to map well to hosted Rust semantics. My understanding is that bare-metal multi-core programs already have distinct entry points for each core, often with distinct binaries for each core too? So treating them as separate processes seems fine. We'll definitely want some sort of IPC for sharing data between those cores, but it doesn't have to be the same primitives we use for single-core synchronisation. I think this RFC would also work without |
You're right, I've added some more text expanding on how they're expected to be used.
Yeah, you can either build a single image (SMP) or distinct images that can opt into sharing certain
That's true. I've added that to the alternatives. |
Now, because `S` implements `Sync`, `&S` will implement `Send`. This is simply | ||
the languages definition of these traits and nothing we can change. Now a big | ||
problem can arise when tranferring `&S` across core boundaries: Cores can have | ||
private memory regions that are not accessible by other cores. If `T: Send` is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the purpose of being able to fluently read this RFC, I would put one of the more popular cases as an example right after this sentence, or in braces. I had to stop here and look ahead what exactly was meant by this.
[summary]: #summary | ||
|
||
Change how we model multi-core MCUs in the following ways: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A notice here that this RFC is about Asymmetric MP and not SMP would be helpful to set the context before reading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is about both, since it is independent of the application model. Basically it just spells out a few facts about multi-core MCUs in general.
While reading this, I had the same thought as @jamesmunns. One of THE key features of compiling a Rust program is that the compiler stops you from sharing or sending data across thread boundaries. Unless you resolve the issue that the compiler wants to see The RFC addresses important issues, but right now, compiler enforcement will only kick in when the traits are set where they should be set. Users using provided libraries that implement what the RFC demands will be reminded when they use the API wrong. But it won't stop them to use Send/Sync wrongly in other places of the program. Just a wild thought, but maybe a good companion to this RFC would be some global that "disables" Send/Sync for a specific memory region. // Private memory regions live here
#![amp_range(0x8000-0x9000)] No idea if its possible to have something like that, though. |
I'm not completely sure what you're referring to here. Do you mean someone could write a library that provides an incorrect unsafe abstraction by taking any
The compiler doesn't know anything about where variables go, only the linker does (and we heavily rely on correctly written linker scripts even today). I'm not sure how this would work since those traits are implemented for types, not type-address-tuples. |
Would it be accurate to summarize the above two texts as the following?:
|
Wasn't my most well-though out comment, true. Please disregard most of it. What about creation of raw pointers. Could the compiler theoretically make use of the address used for casting (e.g. to check if this will point to a private region)? |
EDIT: Actually this doesn't work if |
That sounds about right, yeah. The mechanism can also choose to only make a subset of all global resources available, of course. |
Not necessarily. I've learned from the SiFive guys that their RISC-V cores all start from the same entry point and the bootstrapping code running on each core is in charge of figuring out which core it currently is running on and act accordingly, e.g. by disabling itself or by jumping into the core specific code. I would presume there're quite a few implementations working like that. |
Aren't
and
saying the exact opposite? |
@therealprof I believe in those quotes the former was describing multi-core, similar to disjoint processes; while the latter was describing a single core with interrupts, similar to disjoint threads. |
@therealprof What James said; I've pushed a commit that should clarify that. |
Co-Authored-By: Hanno Braun <[email protected]>
I'd like to suggest considering the following cases:
|
I'd personally rename |
It seems to me that ultimately Rust should support something like |
Updated the RFC to remove |
As per our discussion yesterday, this RFC is now entering Final Comment Period, with the disposition to merge. As this issue has been open for more than two weeks already, I would like to merge this on 2020-02-18 (the date of our next meeting) if there are no blocking objections. @rust-embedded/all, please provide a final review, and approve or reject this RFC. |
bors r+ Thanks all! |
419: Address Multi-Core Soundness by abolishing Send and Sync r=jamesmunns a=jonas-schievink # Summary Change how we model multi-core MCUs in the following ways: * Stop using `Send` and `Sync` to model anything related to cross-core interactions since those traits are unfit for the purpose. * Declare that `Send` is not sufficient to transfer resources between cores, since memory addresses can have different meanings on different cores. * Mutexes based on critical sections become declared sound due to the above: They can only turn `Send` data `Sync`, but neither allows cross-core interactions anymore. * Punt on how to deal with cross-core communication and data sharing for now, and leave it to the ecosystem. [Rendered](https://github.com/jonas-schievink/wg/blob/multi-core-soundness/rfcs/0000-multi-core-soundness.md) [`bare-metal`]: https://github.com/rust-embedded/bare-metal Co-authored-by: Jonas Schievink <[email protected]>
Build succeeded |
Summary
Change how we model multi-core MCUs in the following ways:
Send
andSync
to model anything related to cross-coreinteractions since those traits are unfit for the purpose.
Send
is not sufficient to transfer resources between cores,since memory addresses can have different meanings on different cores.
They can only turn
Send
dataSync
, but neither allows cross-coreinteractions anymore.
and leave it to the ecosystem.
Rendered