Critical section entry/exit – which facility to use where

I’m adding protection against multiple tasks accessing/modify mutating data structures (e.g. linked lists) concurrently and I’m wondering what mechanisms it is best practice to use and when. I see the following possibilities:
  1. Take and give a recursive mutex.
  2. vTaskSuspendAll and xTaskResumeAll. The documentation doesn’t state whether this is recursive, but I can wrap it to make it so if necessary.
  3. taskENTERCRITICAL and task EXITCRITICAL.
  4. cpuirqsave and cpuirqrestore from the ARM Cortex library.
My thinking is along these lines:
  • use #4 if the data is access/modified by an ISR with a higher priority than configMAXSYSCALLINTERRUPT_PRIORITY;
  • use #3 if the data is accessed/modified by an ISR with a priority less than or equal to configMAXSYSCALLINTERRUPT_PRIORITY;
  • otherwise use #2 if the critical section is short and guaranteed not to block;
  • otherwise use #1.
Is that right? Are there any other considerations I shold be aware of?

Critical section entry/exit – which facility to use where

  1. Take and give a recursive mutex.
Probably a bit heavy for linked list, assuming the linked list is fast.
  1. vTaskSuspendAll and xTaskResumeAll. The documentation doesn’s state whether this is recursive, but I can wrap it to make it so if necessary.
Yes, this is recursive. Suspending the scheduler is fast and deterministic, resuming the scheduler can take longer because, if tasks were moved out of the blocked state while the scheduler was suspended then they will have been placed into a pending list, and moved from the pending list into their respective ready lists when the scheduler is resumed. So this method is fast in most cases, but could be slightly slower occasionally if tasks are unblocked while the scheduler is suspended. Note that suspending the scheduler does NOT mask interrupts, they keep executing, so this does not protect the linked list if interrupts also access the list. It also means that only interrupts can ever move tasks out of the Blocked state (and into the above mentioned pending list) while the scheduler is suspended. If non of your interrupts can do that then this is a good method.
  1. taskENTERCRITICAL and task EXITCRITICAL.
This is the fastest method – very fast to enter a critical section and very fast to exit, so is the ideal method if the section being protected is very short. It does however mask interrupts up to configMAXSYSCALLINTERRUPT_PRIORITY.
  1. cpuirqsave and cpuirqrestore from the ARM Cortex library.
Would be very wary about using that method if it modifies the BASEPRI register as BASEPRI is under the control of FreeRTOS. If it only updates the global interrupt enable bit then that should be ok but keep in mind it will mask all your interrupts, whereas FreeRTOS critical sections only mask some. Given all the above, I think your statements are basically correct.

Critical section entry/exit – which facility to use where

Barry, thanks for your response. One bit I didn’t quite understand:
It also means that only interrupts can ever move tasks out of the Blocked state (and into the above mentioned pending list) while the scheduler is suspended. If non of your interrupts can do that then this is a good method.
I do have interrupts that unblock tasks, e.g. when a DMA transfer to/from the SD card interface completes. As I understand it, this doesn’t stop me using vTaskSuspendAll and xTaskResumeAll to implement critical sections. The (only?) drawback is that a task that is unblocked while the scheduler is suspended will have to be moved once to the pending list (when the ISR calls vTaskNotifyGiveFromISR) and then from the pending list to the ready list when xTaskResumeAll is called. So not quite as fast as if it moved direct to the ready list. Is that right?

Critical section entry/exit – which facility to use where

Yes, that is right. The reason I said the only thing that can unblock tasks while the scheduler is suspended is interrupts is because, if the scheduler is suspended, then no task other than the task that suspended the scheduler will ever be running.