The normal solution is to temporarily give the task holding a lock the same priority as the highest priority task that is waiting for that lock, so it can finish its work and free up the lock as soon as possible. The medium priority task won't run because it has lower priority than the boosted low priority task that holds the lock. Once the lock is freed the high priority task will run immediately, not the medium priority task (and the low priority task will drop back to low priority).
Super explanation - thanks.
So, " a mutex which "supports priority inversion" means that the RTOS will automatically do the above when the lock is set? I wonder if FreeRTOS does this?
I've never written code which cares what pre-empts what. I've used priorities just to better allocate CPU time. If I want to stop RTOS task switching, I stop task switching. Maybe there is a way to stop specific tasks being switched to ?
The DMA example was meant as an example of a job which must be protected with a mutex, or things will break.
This is where LWIP ends up when doing e.g. a socket write with the "lock core" mode set
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
SemaphoreHandle_t hMutex;
osStatus_t stat;
uint32_t rmtx;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
rmtx = (uint32_t)mutex_id & 1U;
stat = osOK;
if (IS_IRQ()) {
stat = osErrorISR;
}
else if (hMutex == NULL) {
stat = osErrorParameter;
}
else {
if (rmtx != 0U) {
if (xSemaphoreTakeRecursive (hMutex, timeout) != pdPASS) {
if (timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
}
else {
if (xSemaphoreTake (hMutex, timeout) != pdPASS) {
if (timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
}
}
return (stat);
}
This
https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html (https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html)
suggests that FreeRTOS does exactly the right thing, as the default behaviour. Learn something every day :)
I can also see that raising the priority in this way is going to break some code...
The normal solution is to temporarily give the task holding a lock the same priority as the highest priority task that is waiting for that lock, so it can finish its work and free up the lock as soon as possible. The medium priority task won't run because it has lower priority than the boosted low priority task that holds the lock. Once the lock is freed the high priority task will run immediately, not the medium priority task (and the low priority task will drop back to low priority).
Super explanation - thanks.
So, " a mutex which "supports priority inversion" means that the RTOS will automatically do the above when the lock is set? I wonder if FreeRTOS does this?
I've never written code which cares what pre-empts what. I've used priorities just to better allocate CPU time. If I want to stop RTOS task switching, I stop task switching. Maybe there is a way to stop specific tasks being switched to ?
The DMA example was meant as an example of a job which must be protected with a mutex, or things will break.
This is where LWIP ends up when doing e.g. a socket write with the "lock core" mode set
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout) {
SemaphoreHandle_t hMutex;
osStatus_t stat;
uint32_t rmtx;
hMutex = (SemaphoreHandle_t)((uint32_t)mutex_id & ~1U);
rmtx = (uint32_t)mutex_id & 1U;
stat = osOK;
if (IS_IRQ()) {
stat = osErrorISR;
}
else if (hMutex == NULL) {
stat = osErrorParameter;
}
else {
if (rmtx != 0U) {
if (xSemaphoreTakeRecursive (hMutex, timeout) != pdPASS) {
if (timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
}
else {
if (xSemaphoreTake (hMutex, timeout) != pdPASS) {
if (timeout != 0U) {
stat = osErrorTimeout;
} else {
stat = osErrorResource;
}
}
}
}
return (stat);
}
This
https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html (https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html)
suggests that FreeRTOS does exactly the right thing, as the default behaviour. Learn something every day :)
I can also see that raising the priority in this way is going to break some code...
There are other synchronization mechanisms too, take a look at this overview from the Windows DDK.
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-spin-locks (https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-spin-locks)
If this subject matter is somewhat new to you, I'd recommend getting a copy of Windows Internals, this is a great resource for anyone working with these concepts.
https://learn.microsoft.com/en-us/sysinternals/resources/windows-internals (https://learn.microsoft.com/en-us/sysinternals/resources/windows-internals)
or
https://www.amazon.com/Windows-Kernel-Programming-Pavel-Yosifovich/dp/1977593372/ref=sxin_10_mbs_w_global_sims?content-id=amzn1.sym.f6adc278-60fd-4516-8b02-0dbae28f44f1%3Aamzn1.sym.f6adc278-60fd-4516-8b02-0dbae28f44f1&crid=3MKJLADOE24BT&cv_ct_cx=windows+internals&keywords=windows+internals&pd_rd_i=1977593372&pd_rd_r=7b2f4a22-af5e-4abf-b37c-2b34e9df19d5&pd_rd_w=SRWBv&pd_rd_wg=fzPAS&pf_rd_p=f6adc278-60fd-4516-8b02-0dbae28f44f1&pf_rd_r=9Y56KB4JJD88WNMEJ0GN&qid=1675608796&sprefix=windows+inte%2Caps%2C486&sr=1-2-9e7645f9-2d19-4bff-863e-f6cdbe50f990 (https://www.amazon.com/Windows-Kernel-Programming-Pavel-Yosifovich/dp/1977593372/ref=sxin_10_mbs_w_global_sims?content-id=amzn1.sym.f6adc278-60fd-4516-8b02-0dbae28f44f1%3Aamzn1.sym.f6adc278-60fd-4516-8b02-0dbae28f44f1&crid=3MKJLADOE24BT&cv_ct_cx=windows+internals&keywords=windows+internals&pd_rd_i=1977593372&pd_rd_r=7b2f4a22-af5e-4abf-b37c-2b34e9df19d5&pd_rd_w=SRWBv&pd_rd_wg=fzPAS&pf_rd_p=f6adc278-60fd-4516-8b02-0dbae28f44f1&pf_rd_r=9Y56KB4JJD88WNMEJ0GN&qid=1675608796&sprefix=windows+inte%2Caps%2C486&sr=1-2-9e7645f9-2d19-4bff-863e-f6cdbe50f990)