But what if you want to share a GPIO pin because it has two functions depending on the mode of operation? Think about using a pin to configure and FPGA which after configuration gets a different function.
using rtic you can instantiate shared resources in the init, those resources can be accessed by different tasks. if the task run on the same priority no special care is required; otherwise you have to provide some kind of resouce contention mechanism, mutex or the like (I still have to test the resource sharing part... so take this with a grain of salt)
But that looks like you can do different things with the pin at the same time which is potentially unsafe. But I think I'll need to do more reading first on how you can transfer control over a resource from one task to the other while doing the check at compile time. Or there has to be some runtime mechanism other than writing the code by yourself. Earlier on I already commented about how Linux deal with peripherals; a peripheral (which can also be a single device on an I2C bus) gets locked by a process for as long as it has an open file descriptor for the device. However, such a mechanism also implies the need for some kind of recovery mechanism in case something goes wrong and a process keep locking a device.
But that looks like you can do different things with the pin at the same time which is potentially unsafe. But I think I'll need to do more reading first on how you can transfer control over a resource from one task to the other while doing the check at compile time. Or there has to be some runtime mechanism other than writing the code by yourself. Earlier on I already commented about how Linux deal with peripherals; a peripheral (which can also be a single device on an I2C bus) gets locked by a process for as long as it has an open file descriptor for the device. However, such a mechanism also implies the need for some kind of recovery mechanism in case something goes wrong and a process keep locking a device.rtic is not preemptive, just interrupts and priority levels, so at the same priority it is impossible that the pin is accessed -at the same time-.
At the same priority you get executed after the other interrupt has finished.
using rtic you can instantiate shared resources in the init, those resources can be accessed by different tasks. if the task run on the same priority no special care is required; otherwise you have to provide some kind of resouce contention mechanism, mutex or the like (I still have to test the resource sharing part... so take this with a grain of salt)
But that looks like you can do different things with the pin at the same time which is potentially unsafe. But I think I'll need to do more reading first on how you can transfer control over a resource from one task to the other while doing the check at compile time. Or there has to be some runtime mechanism other than writing the code by yourself. Earlier on I already commented about how Linux deal with peripherals; a peripheral (which can also be a single device on an I2C bus) gets locked by a process for as long as it has an open file descriptor for the device. However, such a mechanism also implies the need for some kind of recovery mechanism in case something goes wrong and a process keep locking a device.rtic is not preemptive, just interrupts and priority levels, so at the same priority it is impossible that the pin is accessed -at the same time-.
At the same priority you get executed after the other interrupt has finished.But I assume there are two concurrent parallel processes that have access to the same pin where each process can do what it wants given the chance. If that is the case, that it is something you might want to avoid. So only process A or process B can access a pin while the process is alive (=an active task whether it gets execution time or not).
what if you want to share a GPIO pin
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
Imagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
Imagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.
It seems to me it would be a programming error rather than a deficiency in the language (which i know, is the whole point of the discussion, that believing that new languange = no bugs is delusional)
How do you define "race condition" here? Such details matter. It is impossible to "simultaneously" write a pin in a single-core microcontroller from two places. Writing a pin is always a correct and allowed operation. The only question is, is it functionally correct?
Maybe expanding on NorthGuy's example: there is a self-test code that acquires ownership to the pin. This code does not normally run, but due to a bug, this process is accidentally triggered. It does not actually actively drive the pin to '1' (or maybe does it just once), but just acquires the ownership.
Simple: you don't know when and where in the execution path the protection interrupt fires. If the protection interrupt fires just before the normal interrupt sets the pin to turn the fet on, then the protection interrupt has no effect. There is no way you can prove correct operation of this particular system.
But what if you want to share a GPIO pin because it has two functions depending on the mode of operation? Think about using a pin to configure and FPGA which after configuration gets a different function.
Mutex and ownership seem to perform the same function.
How do you define "race condition" here? Such details matter. It is impossible to "simultaneously" write a pin in a single-core microcontroller from two places. Writing a pin is always a correct and allowed operation. The only question is, is it functionally correct?
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
What I'm after is resource locking (by process). Not resource sharing!
Simple: you don't know when and where in the execution path the protection interrupt fires. If the protection interrupt fires just before the normal interrupt sets the pin to turn the fet on, then the protection interrupt has no effect. There is no way you can prove correct operation of this particular system.
You can do something about it. For example, after the "main" process turns the FET on, it can check if there was a fault condition and turn it back off if needed. This is enough to solve the problem in C, but not in Rust.
Or, you can eliminate the race condition by disabling interrupts in the "main" making (fault check)+(FET setting) an atomic operation. This will work in C. This will work in Rust too (if you are given an ability to disable interrupts).
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
Imagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
Imagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.
The real error there is attempting to guarantee all that in software running on a conventional processor.
Either do it in hardware, or use a processor plus software that states the hard real-time guarantees at compile time. Both are practical.
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
Imagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.
The real error there is attempting to guarantee all that in software running on a conventional processor.
Either do it in hardware, or use a processor plus software that states the hard real-time guarantees at compile time. Both are practical.I have to agree with this. Now of course we can use methods to decrease the probability of an error with common hardware, but we still can't *guarantee* much, and attempts at doing so are, for the most part, going to be vain.
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
Imagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.
The real error there is attempting to guarantee all that in software running on a conventional processor.
Either do it in hardware, or use a processor plus software that states the hard real-time guarantees at compile time. Both are practical.
I have to agree with this. Now of course we can use methods to decrease the probability of an error with common hardware, but we still can't *guarantee* much, and attempts at doing so are, for the most part, going to be vain.
One of the things I think is "wrong" (or at least vain) with Rust or other similar languages is that they focus on trying to guarantee stuff using conventional hardware and software architectures, which are notoriously bad for certain things.
You'd need to explicitly create some mechanism to share access to this peripheral between the two threads, and that means taking care of concurrency. This does require a different way of thinking about this kind of situation, but it forces you to be aware of it and consider the details, which I don't think is a bad thing.
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
Imagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.
The real error there is attempting to guarantee all that in software running on a conventional processor.
Either do it in hardware, or use a processor plus software that states the hard real-time guarantees at compile time. Both are practical.I have to agree with this. Now of course we can use methods to decrease the probability of an error with common hardware, but we still can't *guarantee* much, and attempts at doing so are, for the most part, going to be vain.You are both digging too deep into the given (poor) example. You have to look at it on a higher level where a software solution is appropriate.
Where safety/reliability is at stake, it can help to add protective layers in both hardware and software where it is sensible to do so. Again, if a certain programming language is more suitable than another, it could help to reduce engineering costs and create a better product in one go.
You'd need to explicitly create some mechanism to share access to this peripheral between the two threads, and that means taking care of concurrency. This does require a different way of thinking about this kind of situation, but it forces you to be aware of it and consider the details, which I don't think is a bad thing.
What kind of mechanism and how would I create it?
What rtic ensures for you is that while a task is accessing the pin no other task at the same priority level can interfere with that in between the operation.
You need to protect your pin from "simultaenous" access only by higher priority tasks
Imagine you have a FET fed which uses 300V to drive an inductive load. The inductor current is rising slowly. If it gets too high the inductor will saturate, FET will die violent death taking most of the board along. So, you have a comparator which monitors the inductor current and invokes the highest priority interrupt if the current climbs above certain critical value. The code in the ISR is supposed to turn the FET off and prevent the disaster - a safety feature, so to say.
So, you write this in Rust. The interrupt gets invoked, your code tries to take ownership of the pin, but it cannot because a task at one of the lower IRQLs had the ownership of the pin when the critical interrupt was invoked. Boom!
Here's an example of a very bad bug which wouldn't be possible if there were no pin ownership. Thus, Rust has created a new "class of errors" which didn't exist before.
The real error there is attempting to guarantee all that in software running on a conventional processor.
Either do it in hardware, or use a processor plus software that states the hard real-time guarantees at compile time. Both are practical.
I have to agree with this. Now of course we can use methods to decrease the probability of an error with common hardware, but we still can't *guarantee* much, and attempts at doing so are, for the most part, going to be vain.
One of the things I think is "wrong" (or at least vain) with Rust or other similar languages is that they focus on trying to guarantee stuff using conventional hardware and software architectures, which are notoriously bad for certain things.
The guarantees given by Rust seem to me to be valuable, and a useful advance over C.
Nobody in their right mind imagines they extend to real time properties. That's why the example being discussed is so inappropriate.
Regarding sharing hardware resources, such as peripherals, I'm personally in favor of architectures in which one peripheral is only accessed from one task. You avoid a large number of problems this way.
What kind of mechanism and how would I create it?
What kind of mechanism and how would I create it?You'd use a different architecture for this, and avoid accessing peripherals in interrupt context. Probably you should just monitor the action inside the task that is doing the switching and already owns the pin. You could also use an AtomicBool (which is Sync and Send, so can have and access references to it in multiple threads) to set a flag that you monitor for this condition in another task. Or better yet, since your contrived example is mostly in hardware anyway, just satisfy it in hardware by having the comparator output force the FET off with a hard pulldown or something rather than relying on the software to do it.