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
Should CriticalSection
really be Clone
?
#42
Comments
CriticalSection
really Clone
?CriticalSection
really be Clone
?
CriticalSection not being Clone alone would not be enough for either of these, it'd take additional mechanisms that forbid Such a only-once-per-system CriticalSection would have different semantics from the current one; there may be a use case, but it's probably better called something different. (UniqueCriticalSection maybe?). |
If we pass a
I can't visualize how Ironically, We don't want a second One workaround I can think of is to use a |
I understood kelida to mean that a (I still think it's just a bad idea, though -- if you're in a position to consume the unclonable CS token, you could return from your free section just as well).
I didn't mean that enable_cs causes interrupt:free to nest, I meant that even if the existing interrupt::free(|cs1| {
interrupt::free(|cs2| {
enable_cs(cs2)
})
}) By nesting free, one can obtain two tokens -- and that's all good and correct, because while any of them is alive, interrupts are off. My point is that it's not just the I thus think that if there is a way forward with these use cases, it's through a separate But is it really useful? A constructor for My impression is that an interrupt-enabling function is generally unsafe (as long as anyone wants to depend on being inside an interrupt-free section). I have yet to see a case where enabling interrupts is actually a practical thing. (Not so incidentally, I recently made a PR for a big fat red warning in the IRQ enable routine of RIOT-OS -- if interrupt enabling were generally allowed, critical sections could never work with any kind of callback code any more). |
I don't actually have a problem with this, personally. But I want to show that it's possible to write msp430 applications with the
I want to provide safe abstractions to facilitate the use case of completely safe msp430 code. In all the code I've written, I used
Well, that could work too, instead of passing around
I wouldn't expose the constructor to user code. I would only provide |
I won't continue right now in looking at `UniqueCriticalSection` because
it appears right now to be a whack-a-mole of edge cases, but to sort out
the use cases, let me suggest something that may remove the need:
I want to provide safe abstractions to facilitate the use case of
completely safe msp430 code.
I'm unfamiliar with the workings of MSP430; with the Cortex MCUs I've
had my hands on it was always an option to just enable interrupts right
away (eg. in the safe wrapper for the main function), because all
*individual* interrupts are off already (and whatever enables them will
need to make sure that whatever the ISR accesses is actually initialized).
If that's not an option on the MSP430, maybe it's practical to have a
safe-only init function (inside which IRQs are all off, so even if code
does call `interrupt::free` it's a practical no-op as it restores to an
IRQ-off state), then unsafely enabling the interrupts in the caller of
the safe init function (part of the -rt if that distinction exists
there), and then calling a main.
Would that be an option for writing safe-only applications? (Otherwise
we can still continue sketching UniqueCriticalSection...)
…--
To use raw power is to make yourself infinitely vulnerable to greater powers.
-- Bene Gesserit axiom
|
Ahhh, I guess because of NVIC, all peripherals already have to have an interrupt enable bit. There is no guarantee in MSP430-land that individual peripherals will have an interrupt enable bit that's separate from the global interrupt enable (GIE) in the status register. The USB peripheral is one such example.
This was more of a minddump while it's on my mind, sorry :D! |
That example doesn't work because fn main(cs: CriticalSection) {
interrupt::free(|cs_ref| {
enable_cs(cs);
// Do bad stuff with cs_ref even though interrupts have been disabled
})
} The only way I can see of fixing this is to make |
My gut feeling is that this would be a really bad idea and cause many things to either stop compiling or subtly break. But it's just a feeling. I also don't want to diverge from how the rest of Rust embedded does things.
I guess the issue that there is no way to express in Rust "this type cannot be moved into a closure".
Do you see any problems w/ the following?: The safe wrapper around
Yea, I don't want to get rid of this feature either. |
Does any other embedded Rust ecosystem have some way to safely set interrupts? If they do then we can copy them.
Closest thing is
That works if
It's completely sound in MSP430 AFAIK. The unsoundness is with |
ARM enables interrupts before entering main. This works because thanks to NVIC, all peripherals have a local interrupt disable bit. There is no guarantee in msp430 world that peripherals will have a separate interrupt disable from GIE in the status register. As for RISCV, I'm not sure what the privileged spec guarantees here. IIRC
That works if init can pass variables to main, since I don't want init to put everything into global variables. They don't follow this model, this was an example of a way I thought we could work around the problem. And yes, it would involve judicious use of Right now, it does not seem possible to represent interrupt enable in purely safe code. A shame, but at least its easy enough not to abuse- after enabling interrupts in main, don't use the passed-in |
For MSP430 |
I guess the issue that there is no way to express in Rust "this type cannot be moved into a closure".
That way would be to have one more autotrait like Send that says "can safely be moved into a critical section, i.e., does not allow enabling interrupts". (Then, unlike the usual closure consumers that ask it to be Send before making it callable by another thread, free would ask the closure to be (auto-)WontEnableInterrupts).
Being highly specific, I don't see this happen before we get crate-defined autotraits, which I haven't seen any efforts towards (and it'd be pitfall heavy territory).
…---
On the MSP specifics, please leave a final note here to allow those interested to join the discussion.
|
Fair enough. In the context of this issue, we are removing |
7: Remove enable_cs due to unsoundness r=cr1901 a=YuhanLiin Breaking change. See rust-embedded/bare-metal#42 for discussion. Co-authored-by: YuhanLiin <yuhanliin+github@protonmail.com>
As for |
I personally think
CriticalSection
should not beClone
, because of two use case requiring that:interrupt::enable_cs
: Safely enable interrupts, consuming a critical section. This can't work if there can be another copy lying around.Mutex::borrow_mut
: I'm quite sure this would allow to mutably borrow data in a mutex, by taking a&mut CriticalSection
. This would only allow to mutably borrow one mutex as once, but I think it is still better thanMutex<RefCell<_>>
.All actual use cases ought to work by passing a
&CriticalSection
, although I don't think this needs to be used often. Should the size of&CriticalSection
be a problem, one could imagine aSharedCriticalSection
ZST borrowing aCriticalSection
.The text was updated successfully, but these errors were encountered: