Mutual exclusion between task and interrupt

npkz wrote on Monday, March 27, 2017:

Hello people,

there is a thing (amongst many) I don’t completely understand regarding mutual exclusion between tasks and interrupts. If we have something like this:

… access to shared data…

… access to shared data…

Since interrupts have higher priorities than taks, would that mean in this case that if interrupt happens while TaskA is inside of critical section, ISR will start executing and since inside of ISR we don’t have a critical section, data race is possible to happen?

I assumed that this was going to happen, so I decided to put SemTakeFromISR() and SemGiveFromISR() around accessing shared data part in ISR. However, in ISR after some time SemTakeFromISR() doesn’t return pdPASS, and I get deadlock, since it’s waiting for semaphore to be released from the TaskA which has lower priority.

Do I understand this right or maybe the problem is more complicated? I suppose there is some general solution to these kind of problems.


aseris wrote on Monday, March 27, 2017:

The interrupts which can happened during critical section enabled can’t use FREERTOS API. see configMAX_SYSCALL_INTERRUPT_PRIORITY config.

It is not good strategy to wait for sema/mutex inside ISR

I recommend to draw a flowchart of required logic and re do it in way without dead locks.

richard_damon wrote on Monday, March 27, 2017:

A semaphoretake inside an ISR does NOT block the ISR to wait for the semaphore to be raised, it just returns an error code that the take failed (note, the FromISR routines do NOT take a timeout parameter, but a pointer to a variable to indicate if they woke up a task),

If you need to protect a data structure from an ISR, then you need to use a critical secton. This is what FreeRTOS does internally. These critical sections should be kept very short to avoid excessive interfearance with interrupt activity. If the access needs to be more complicated, so you need to use a semaphore (or better a mutex) to protect the update, then you should rework the ISR to trigger a task or call back hook via the service task to perform the update for the ISR and the ISR do the minimal work to provide that task with the data it needs.

npkz wrote on Monday, March 27, 2017:

Thanks for answers guys. So, Damon, if I understood you well, all that needs to be done is the first thing I already described. Create critical section in TaskA, and do nothing considering mutual exclusion inside of ISR since FreeRTOS will internally take care of that?

rtel wrote on Monday, March 27, 2017:

When Richard Damon talks about a critical section, he is not talking
about protecting code with a semaphore as you did in your original post,
he is talking about using the taskENTER_CRITICAL() and
taskEXIT_CRITICAL() function. They
will disable interrupts, hence your problem goes away, because the
interrupt that attempts to access the shared resource won’t even run.

If the code that needs to be protected is too long to keep interrupts
disabled while it is being accessed then just set a flag while the code
needs to be protected, and have the interrupt code check the flag is not
set before it accesses the shared resource.

npkz wrote on Monday, March 27, 2017:

Ok, I understand now. So, basically what I have described in original post, the thing with mutexes in TaskA means absolutely nothing in this context? I mean if I don’t have any other Task that shares the same data…

richarddamon wrote on Monday, March 27, 2017:

Yes, Mutexes, and semaphores being used for exclusion, are basically a Task-to-Task entity, and don’t affect interrupts, as the ISR cant ‘wait’ and let the task finish the operation. If you need to block out an interupt for a short period of time, This can be done with a critical section (which blocks all interrupts that are allowed in interract with the FreeRTOS API), or if it is just a single interrupt you need to worry about, on most machines you could turn off that one interrupt (FreeRTOS doesn’t provide code for that, as it is very processor specific, and generally to write the ISR in the first place you needed to look up that code, which is normal provided by the chip manufacturer.

Sometimes, rather than having to actually block the ISR, you can split the ISR into two pieces, one that runs from the interrupt which does minimal work to service the interrupt and passes the information to the second half that runs as part of a task that the interrupt signals. If it is just this second part you need the sharing control with, now, since it is running as a task, you can use the mutex or semaphore.

npkz wrote on Tuesday, March 28, 2017:

Thanks most kind for your help, I’ve got it now.