-
Notifications
You must be signed in to change notification settings - Fork 68
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
Better Mutex #52
Comments
I've been thinking about your latter two questions a lot, and came to roughly the same conclusion. I've been avoiding writing cs-based APIs for some things based on the (almost certainly misguided) concern that I already know interrupts are disabled, but it's exactly the two cases you laid out here. One note: I've never used them, but I'm dimly aware that you can have re-entrant ISRs by manually re-enabling interrupts in an ISR, so the function to enable interrupts by consuming a CS should be callable there, too, but I think that shakes out for free.
I would recommend making the API follow exactly from other places rather than trying to be too clever. Principle of least surprise, do one thing and do it well, and all that. |
Actually, just noticed something: interrupt::free(|cs1| {
interrupt::free(|cs2| {
interrupt::hypothetical_enable(cs1);
some_mutex.lock(&cs2);
});
}); I don't think this is going to work unfortunately ... |
Or even: fn main(cs1: CriticalSection) -> ! {
interrupt::free(|cs2| {
interrupt::hypothetical_enable(cs1);
some_mutex.lock(&cs2);
});
// ..
} But maybe it would be a new privileged type, such as: pub struct CriticalPrologue {
cs: CriticalSection,
}
impl Deref for CriticalPrologue {
type Target = CriticalSection;
fn deref(&self) -> &Self::Target { &self.cs }
}
pub fn hypothetical_enable(cp: CriticalPrologue) {
// ...
} |
Yeah, different kinds of tokens was also what I was thinking about but not sure if that's a good idea ... Also, it really feels like |
Actually, no: fn main(other_cs: CriticalPrologue) {
interrupt::free(|cs| {
interrupt::enable(other_cs);
// now what
});
} |
Would this be too heavy-handed a solution? pub struct CriticalPrologue<'a>(&'a CriticalSection);
impl<'a> Deref for CriticalPrologue<'a> {
type Target = CriticalSection;
fn deref(&self) -> &Self::Target { &self.0 }
}
mod interrupt {
pub fn free<T, F: FnOnce(&CriticalSection) -> T + 'static>(f: F) -> T {
f(&CriticalSection)
}
} The error message isn't great but it would seem to provide the right guarantee. Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6ac82256d10cf44359bef766ef4a1a71 |
When commenting out the bad main in your example, it still does not compile? TBH, I don't see how there even could be a borrow-checker based solution here, I think this problem is inherent. If I'm not mistaken, this is pretty much analogous to the reason why And while there might be other dirty tricks to prevent a function call below a certain other function, I don't think that's worth it. The common pattern in most embedded rust applications, to just do all initialization inside an |
Oh my, I really thought I had checked that. No wonder I was so confused how that worked -- it didn't.
All this brouhaha to try and save a single |
We're currently relying on the mutex type from
bare-metal
which is actually being removed upstream so now is a good time to think about adding a similar mechanism here and maybe improving it. For starters, I'd want the mutex to actually hand out&mut _
references because 99% of use-cases need this.It would be interesting to explore the concept of a critical-section handle a bit more:
cs
-handle as an argument as nothing could interrupt them?cs
-handle in the beginning? Interrupts are disabled so it would be sound. Then, later aninterrupt::enable()
function should consume the handle when enabling interrupts for the first time. Is there a problem I'm missing?The text was updated successfully, but these errors were encountered: