|
|
|
|
|
by megous
1799 days ago
|
|
Issues with ISRs are different. They'll sorta appear when rust is used inside the Linux kernel, too. For example, can rust make sure some kind of function is not called at any level when called from certain kind of context (say atomic context). Can rust help detect/prevent you from accessing some multi-register SFRs or memory locations from main context without making you disable interrupts first in the main context? And this constraint is only relevant if the SFR or said memory location is ever accessed from some ISR, and the access is not atomic, otherwise disabling interrupts is not necessary. Do you have to wrap all these accesses and keep track of all this manually just like in C or does rust have some concept of "colored" functions, so that you're forced to wrap accesses to certain memory locations only if these accesses are shared between differently colored functions. I'm not a rust person either. Just wondering how rust would help me with the most complicated aspects of concurrency in low level programming. Allocating/deallocating memory and keeping track of it is easy compared to this. |
|
In your case, you could implement something like an InterruptDisabler<T>, and use it to wrap an object which has the methods to access these registers. When you wanted to access these registers, you would do something like "my_interrupt_disabler.disable_interrupts()", which would disable interrupts and return an InterruptDisablerGuard<T>, which then would you to access the T. Once that InterruptDisablerGuard<T> gets out of scope, the compiler automatically calls the drop() method from the Drop trait on it, and that method could enable interrupts again. You cannot access the inner object without going through the guard, and you cannot get the guard without disabling interrupts.
And that's only one possible implementation. Another one would be to have something like an "interrupts disabled" token which is returned by a "disable interrupts" function, which is consumed (that is, destroyed) by an "enable interrupts" function, and which is !Send and !Sync (so it cannot be passed to another thread). The methods which access these registers would require you to give them a reference to the token, so they could only be called if you somehow obtained the token, which could only be done by disabling interrupts in the current thread. And for when you're within the interrupt handler itself, the low-level code which calls it could manufacture one of these tokens and pass a reference to it to the interrupt handler, so it would be able to access the registers without calling the "disable interrupts" function.
Of course, both of these ideas still require you to decide which registers are safe to call with interrupts enabled, and which registers are not, when creating the objects which represent the register blocks. Rust can help the developer, but it's not a panacea.