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

jcsbanks
Posts: 305
Joined: Tue Mar 28, 2017 8:03 pm

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

Postby jcsbanks » Tue Aug 14, 2018 10:33 pm

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.

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

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

Postby ESP_Angus » Wed Aug 15, 2018 1:21 am

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.)

jcsbanks
Posts: 305
Joined: Tue Mar 28, 2017 8:03 pm

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

Postby jcsbanks » Sat Aug 18, 2018 3:32 pm

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.

ESP_Sprite
Posts: 9764
Joined: Thu Nov 26, 2015 4:08 am

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

Postby ESP_Sprite » Sun Aug 19, 2018 3:41 am

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?

jcsbanks
Posts: 305
Joined: Tue Mar 28, 2017 8:03 pm

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

Postby jcsbanks » Sun Aug 19, 2018 2:27 pm

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.

jcsbanks
Posts: 305
Joined: Tue Mar 28, 2017 8:03 pm

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

Postby jcsbanks » Tue Aug 21, 2018 9:36 pm

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.

Who is online

Users browsing this forum: Majestic-12 [Bot] and 96 guests