Dynamic Prioritization

I’m still facing a problem with Your prioritization. The priority cannot be defined for a specific task, it has to be done on a function-level.
Every task can make use of a critical function, You can take a look at the heap for example. The priority has to be raised there, every task is using it.
I suggest making use of a mutex that can be locked up to high priority. It’s very easy to implement, i’ve already made it. When calling mutex_lock_up() the current task is marked exclusive and interrupts are kept disabled until the mutex is released.

How is that different than calling vTaskSuspendAll() or taskENTER_CRITICAL()

1 Like

vTaskSuspendAll is working for sure, but it is too expensive. taskENTER_CRITICAL is what we call a spinlock, i’m only using it to make scheduling possible.

Happy to see You, happy weekend!

No, those are two different concepts.

Concerning your use case: Well, yes, it may be easy to implement, but I do not think it is worth rolling into the main branch, there will be unaccounted for side effects relating to priority inversion. I do not see very many use cases they may justify a new sync object semantics, can you sketch a case where you think this may be useful?

1 Like

For this, you may use a variation of a read-writer lock for which there are several implementations out there.

Yes, the most poular use-case is Tesla.
Your problem seems to be multiple customers that didn’t post they have a problem. It is not really possible to work with Your kernel right now.
Your customers problem may get that they are not able to access the heap from within an interrupt service routine, but this is something they have to live with. They can make use of our condition_variable instead.

Happy Weekend, RAc!

Even though there are lock-free heap implementations usable in ISRs there are other mechanisms not requiring dynamic allocations to transfer data from ISRs to tasks. I wouldn’t say the kernel is not usable, right :wink:
Also blocking locks can’t be used in ISRs.

1 Like

The intuitive way to use the heap is a mutex. It just isn’t possible at the moment with Your kernel. The mutex You have is not working on our heap with real-time-requirements. We really need something like a high-priority mutex. :wink:

Schönes Wochenende, Herr Schäfer!

Sorry Sven, but this kind of tone is not appropriate. FreeRTOS has been around for many many years now and has proven usuable in many real time systems. I have worked with it for more than 15 years in some fairly stringent timing requirements and got it to work.

You may want to reconsider your style of discourse.

edit: Also note that if you are using standard C memory allocation, you can taylor the serialization issue to your needs by a custom implementation of __malloc_lock()/_unlock.

2 Likes

Please don’t get me wrong, FreeRTOS is working fine. From my point of view there is only one function missing, that is mutex_lock_up() or vSemaphoreTakeBlocking() for example.

You see, if i disable interrupts i cannot lock the mutex anymore, because there may be a task-switch. If i lock the mutex and disable interrupts, the system-timer may interrupt when the mutex is locked. That’s the problem.

No. With interrupts disabled (at least FreeRTOS compliant interrupts using the MYX_SYSCALL semantic restriction which by definition must apply to the sys tick timer), the sys timer will NOT fire. You are getting something completly wrong here, or you do not explain your problem properly.

edit: What you probably MEANT to write is “and ENable interrupts…” Yes, that is by definition and the basis for predictive scheduling. The scheduler will of course work with a mutex locked and will select the highest priority runnable thread (task) and assign it the (or a) cpu. Why is that a problem?

1 Like

The problem is between these two lines:

vSemaphoreTake(heap_mutex);
taskENTER_CRITICAL();

The system timer may interrupt.
I suggest vSemaphoreTakeBlocking() leaving interrupts disabled after the task-switch.

Best regards,

Sven Bieg

1 Like

that would be a nuclear warhead type of syncronization, serving only a very few use cases but seriously affecting overall system throughput and responsiveness.

What does the already existing priority inheritance architecture not accomplish that you believe to need?

Note also that claiming the critical section with a mutex held may deadlock your system if you do not ensure that the task doing that will never get blocked suspended or blocked before returning the critical section.

1 Like

You are right, it is a critical mutex especially designed for the heap.
The concept of priority-inheritance is genious, i just can’t decide which task is more important than any other. I’m leaving the task-priority normal, that’s working fine.
The heap doesn’t have any dependencies and can unblock in constant low time. You probably remember my implementation?
The developer has to take care of this, but i guess it is easier to decide than the priority of a whole task.
You got me now? :slightly_smiling_face:

No, I am afraid I still do not see a valid use case for what you propose. Please keep in mind that dynamic memory management is just one piece of the puzzle that makes up an embedded system, and tailoring a sync primitive for it disregards the other pieces. Embedded systems that require hard real time behavior frequently do without dynamic memory management at all (for example, MISRA outlaws its usage altogether because static code analysis is incompatible with it).

Again, priority inheritance ensures that a hi pri thread waiting on a mutex will not be starved by lower priority threads, what is missing on top of that?

Maybe you can sketch some pseudo code that demonstrates where you think the problem is?

Finally, in the above code snippet you presented, the mutex is unneeded altogether because once you use the critical section, you effectively suspend all concurrency, so you do not need a mutex to begin with.

1 Like

Dynamic Prioritization doesn’t disregard Priority Inheritance, both concepts can work side by side. The heap is the only critical function i can imagine, also used by the kernel. The benefit of vSemaphoreTakeBlocking() is that concurrency is going on, only tasks that access the heap are suspended. Like You said, critical tasks may not even use the heap and can go on. FreeRTOS is using vTaskSuspenAll() at this point, which doesn’t look efficient.
The MISRA-standard may have brought us to the moon and back, but it is very hard to learn. Modern C++ with Objects and Handles is safe for me, i’m a hobby-programmer without any restrictions.
To Your question, priority-inheritance has solved NASAs problem, but not mine. It is also possible to recognize a mutex that is used by a high-priority-task and make it critical. If this isn’t possible, priority-inheritance will also fail.
FreeRTOS is working fine, maybe to slow for new high-perfomance customers.

Thank You very much for Your investigation, RAc!

What fails with using a mutex with a separate taskENTER_CRITICAL() call after?

If the system timer occurs, and switches to another task, if it tries to take that mutex, it will block and come back to you. If it doesn’t try to take that mutex, then it is just as if the timer interrupt occured just before the heap_mutex got taken.

if an ISR that is going to use the heap occurs at that point, it can use the heap, just as if that ISR happened just before the heap_mutex got taken.

What makes the occurrence of an interrupt between the giving of the mutex to the task and the taskENTER_CRITIAL actually cause a problem?

1 Like

My prediction fails. In the kernel we cannot know how many tasks are running and how long it takes to come back to the heap. It just doesn’t make sense to keep the heap locked while serving other tasks.

You are right that the application is working as expected, it only takes more cycles to get the same result.

It is not possible to switch a task in an ISR, so it is not possible to use a mutex and the heap here.

The problem is determinism. For me as a developer it is important to know how the application proceeds.

Best regards,

Sven Bieg

What took too long? It doesn’t matter how long the heap is locked, what matters is how long does something need to wait to get the heap.

If it is too slow with the separate lock and enter critical, it will be too slow with a combined operation, as that timer tick that delayed the task between the two operations could have delayed it getting the semaphore in the first place.

Note, it IS possible to change what task will run in an ISR, in fact, ISR that use FreeRTOS APIs that might unblock a task should normally check the flag if a scheduler operation is needed, and if so, cause a scheduling.

Also, if you aren’t going to try to use the heap in an ISR, there is no need to disable the interrupts, as any task that isn’t using the heap at the moment that delays the task, could have delayed it just before or after that heap operation, effectively making the heap busy for that additional time.

1 Like