Hello,
I'm writing here because i would like to have some opinion from experienced users about the "priority inheritance" of embOS tasks, it's use and it's limitations.
In my opinion it would be a very useful feature to handle prioritized access to resources, but we found that you have to be very careful when you use some OS API.
Here the story...
We're using embOS for our multitasking application.
In our application, one task have to access to a peripheral "P" in "precise" time slots, within a calculated jitter.
This task has to run in real time, so its priority has been increased higher than the others.
In the following days, we had to add some features to our application, including one that needs access to the same peripheral P, but in a relaxed way, by a lower priority task.
We need mutual exclusion to access P, so I've decided to use a "resource semaphore".
I know that embOS handles the problem of priority inversion for me, by the use of priority inheritance.
So I was pretty confident that I would not had any problem, and the jitter would been under control.
Infact this worked very well, until we decided to "optimize" the peripheral driver...
We inserted an "OS_Delay(T)" inside a "busy-wait" loop, executed in the section protected by resource semaphore.
This delay didn't change the peripheral access time, but release the CPU to other tasks.
Surprisingly, we found that, sometime, the higher priority task was deleyed much longer than we aspect, because tasks with lower priority were running instead of it.
Working on this, we ended with the below example. It shows that priority inheritance fails if we call the API "OS_Delay()" inside the section protected by the resource semaphore.
If you want, run this example, and you'll see that the first "asm("NOP");" of HPTask will be executed. The resource semaphore section lasts for more than expected, showing priority inversion.
If you comment out the "OS_Delay(10);" line in the LPTask, you'll see that the second "asm("NOP");" of HPTask will be executed, showing that "priority inheritance" works as it has to do.
My questions are:
- In this example priority inheritance is working the right way?
- Are there other APIs that have the same behaviour of OS_Delay() for this example?
Thank you :-),
Alberto
Display All
I'm writing here because i would like to have some opinion from experienced users about the "priority inheritance" of embOS tasks, it's use and it's limitations.
In my opinion it would be a very useful feature to handle prioritized access to resources, but we found that you have to be very careful when you use some OS API.
Here the story...
We're using embOS for our multitasking application.
In our application, one task have to access to a peripheral "P" in "precise" time slots, within a calculated jitter.
This task has to run in real time, so its priority has been increased higher than the others.
In the following days, we had to add some features to our application, including one that needs access to the same peripheral P, but in a relaxed way, by a lower priority task.
We need mutual exclusion to access P, so I've decided to use a "resource semaphore".
I know that embOS handles the problem of priority inversion for me, by the use of priority inheritance.
So I was pretty confident that I would not had any problem, and the jitter would been under control.
Infact this worked very well, until we decided to "optimize" the peripheral driver...
We inserted an "OS_Delay(T)" inside a "busy-wait" loop, executed in the section protected by resource semaphore.
This delay didn't change the peripheral access time, but release the CPU to other tasks.
Surprisingly, we found that, sometime, the higher priority task was deleyed much longer than we aspect, because tasks with lower priority were running instead of it.
Working on this, we ended with the below example. It shows that priority inheritance fails if we call the API "OS_Delay()" inside the section protected by the resource semaphore.
If you want, run this example, and you'll see that the first "asm("NOP");" of HPTask will be executed. The resource semaphore section lasts for more than expected, showing priority inversion.
If you comment out the "OS_Delay(10);" line in the LPTask, you'll see that the second "asm("NOP");" of HPTask will be executed, showing that "priority inheritance" works as it has to do.
My questions are:
- In this example priority inheritance is working the right way?
- Are there other APIs that have the same behaviour of OS_Delay() for this example?
Thank you :-),
Alberto
Brainfuck Source Code
- /*********************************************************************
- * *
- * OS version: 4.10 *
- * *
- **********************************************************************
- ----------------------------------------------------------------------
- --------- END-OF-HEADER --------------------------------------------*/
- #include "RTOS.h"
- OS_STACKPTR int StackHP[128], StackMP[128], StackLP[128]; /* Task stacks */
- OS_TASK TCBHP, TCBMP, TCBLP; /* Task-control-blocks */
- OS_RSEMA Resource;
- static void LPTask(void) {
- OS_DelayUntil(1000);
- OS_Use(&Resource);
- while(OS_GetTime() < 4000);
- OS_Delay(10);
- while(OS_GetTime() < 6000);
- OS_Unuse(&Resource);
- //end
- while (1) {
- OS_Delay (1000);
- }
- }
- static void HPTask(void) {
- OS_DelayUntil(2000);
- OS_Use(&Resource);
- OS_Unuse(&Resource);
- if (OS_GetTime() >= 10000){
- asm("NOP");
- }
- else{
- asm("NOP");
- }
- //end
- while (1) {
- OS_Delay (1000);
- }
- }
- static void MPTask(void) {
- OS_DelayUntil(3000);
- while(OS_GetTime() < 10000);
- //end
- while (1) {
- OS_Delay (1000);
- }
- }
- /*********************************************************************
- *
- * main
- *
- *********************************************************************/
- int main(void) {
- OS_IncDI(); /* Initially disable interrupts */
- OS_InitKern(); /* Initialize OS */
- OS_InitHW(); /* Initialize Hardware for OS */
- OS_CREATERSEMA(&Resource);
- /* You need to create at least one task before calling OS_Start() */
- OS_CREATETASK(&TCBHP, "HP Task", HPTask, 100, StackHP);
- OS_CREATETASK(&TCBMP, "MP Task", MPTask, 75, StackMP);
- OS_CREATETASK(&TCBLP, "LP Task", LPTask, 50, StackLP);
- OS_Start(); /* Start multitasking */
- return 0;
- }