Page 1 of 1

Avoiding race condition between interrupt on one core and task on the other core

Posted: Tue Aug 14, 2018 10:33 pm
by jcsbanks
Apart from pinning the task that initialises the interrupt and the task that races with the interrupt to the same core, which works, I wondered if there is a more elegant solution?

In a single core situation it seems sufficient to have a critical section around the code in the task, and then the task and interrupt cannot race each other.

I would not of course want to let an interrupt wait to get a lock/mutex.

Re: Avoiding race condition between interrupt on one core and task on the other core

Posted: Wed Aug 15, 2018 1:21 am
by ESP_Angus
There is a (it seems undocumented, will see about changing this) spinlock ("portmux") macro called:

Code: Select all

/** @brief Acquire a portmux spinlock with a timeout
 *
 * @param mux Pointer to portmux to acquire.
 * @param timeout_cycles Timeout to spin, in CPU cycles. Pass portMUX_NO_TIMEOUT to wait forever,
 * portMUX_TRY_LOCK to try a single time to acquire the lock.
 *
 * @return true if mutex is successfully acquired, false on timeout.
 */
bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles);
You can use this to try and take a spinlock in a situation where you don't want to block (or don't want to block for too long).

Note that portmuxes spin with interrupts disabled in tasks as well, so it's never recommended to hold one for too long in either a task or an ISR (this means it may be OK to use the non-timeout variant in your ISR as well, provided you know you won't hold it for an overly long time.)

Re: Avoiding race condition between interrupt on one core and task on the other core

Posted: Sat Aug 18, 2018 3:32 pm
by jcsbanks
Interestingly, when I try this, I get an assert "coreID == mux->owner" failed when doing vPortCPUReleaseMutex with tasks distributed between the cores.

This suggests that it is not core safe?

On a side note, I'd also got caught out by a race between the cores when using the high resolution timer to do callbacks because the high resolution timer was on a different core.

Re: Avoiding race condition between interrupt on one core and task on the other core

Posted: Sun Aug 19, 2018 3:41 am
by ESP_Sprite
You will get that if you try to release the mux on a different core than it was taken. Could that be something you're doing?

Re: Avoiding race condition between interrupt on one core and task on the other core

Posted: Sun Aug 19, 2018 2:27 pm
by jcsbanks
I think I mixed up the purpose of what ESP_Angus was suggesting. I added a critical section in my interrupt as well as my task and now can distribute the tasks freely between the cores.

Re: Avoiding race condition between interrupt on one core and task on the other core

Posted: Tue Aug 21, 2018 9:36 pm
by jcsbanks
I think I was mistaken again... and thought it was OK because of how tasks were allocated in that build but the problem reoccurred and only pinning tasks to the same core avoids the problem.

I am hoping the new CAN driver will behave and will not try further to work around the old one.