This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Is using a Queue for application messages thread safe? CC2640

Other Parts Discussed in Thread: CC2640

Hey TI CC26xx team and fellow community members, I'm reading up on the CC2640 & TI-RTOS and have a question that's been stumping me and a coworker:

Is TI's recommended use of the TI-RTOS Queue for handling application messages thread safe?  Specifically when messages are being pushed to the queue by a mix of HWI, SWI, and task contexts. The example projects' implementations using Util_enqueueMsg and Util_dequeueMsg uses non-atomic APIs of the TI-RTOS's Queue module.  

The CC2640 Software Developer's Guide and published examples recommend we use a TI/RTOS Queue for application messages.  (Section 4.3.3 Callbacks") The recommended architecture uses the Queue in a multiple-writer/single-reader model, where callbacks running in a variety of contexts can push events to the queue. The main Application tasks is the sole receiver of messages, popping them from the queue. The software examples shipped with the stack, including SimpleBLEPeripheral and glucose_sensor, use this recommended model and leverage two queue wrapper functions called Util_enqueueMsg and Util_dequeueMsg. 

In SimpleBLEPeripheral, the SimpleBLEPeripheral_enqueueMsg function calls "Util_enqueueMsg" and the taskFxn calls "Util_dequeueMsg". Both of these Util functions use the non-atomic versions of the TI-RTOS Queue API. (Queue_enqueue and Queue_dequeue)

The "glucose_sensor" example also uses "Util_enqueueMsg" to enqueue events in callbacks both from key presses (debounce Clock callback SWI from board_key.c) and also other callbacks from the GAP Peripheral Role task. In the case of this glucose project, couldn't there be task-unsafe conflict where the "GlucoseSensor_stateChangeCB" is in the middle of using the non-atomic Util_enqueueMsg, when it's preempted by the "GlucoseSensor_keyPressHandler" callback which also will use Util_enqueueMsg? 

Robert Tivy (3168) mentions here, that to use the TI-RTOS Queue in a multiple-writer/single-reader model, the atomic APIs must be used (Queue_get and Queue_put) : e2e.ti.com/.../1766272

If this is the case, I could modify the Util.c file to use the atomic APIs, but the CC2640 SDG contains the note shown in the image above: "No blocking RTOS function calls or protocol stack APIs should be performed in a callback function"

Any help/feedback here would be appreciated.  Are the example projects somehow using the Queue in a thread-safe way that we're overlooking?  

@svendbt, do you have any thoughts on this? You mention the atomic version of the Queue APIs here: e2e.ti.com/.../1675218

  • Hi Ray,

    Great find, thanks for the detailed analysis and bringing this to our attention.

    We have found this issue internally and have been testing a fix for it using the safe queue operations. Using the safe queue operations (get and put instead of enqueue and dequeue) we have seen any issues disappear.

    The blurb from the SDG that you reference:
    "No blocking RTOS function calls or protocol stack APIs should be performed in a callback function"

    Is more referring to calls that will lock the system for a long time like a blocking UART read, etc. We have not seen any timing issues when changing the functions within util.c to use the safe queue operations.

    In summary, we recommend moving to get/put within util.c and anywhere else your code uses Queues. This will be patched in a future release.
  • Thanks Sean, we'll implement the fix that you recommended.
  • Hi Ray,

    In addition to the changes Sean recommended above, you should also disable/enable Hwis around the Queue_empty call as seen in the following e2e post: e2e.ti.com/.../1994563
  • Hey Rachel, thank you for the reference.

    In Util_dequeueMsg of your patch, why is it only HWI interrupts that are disabled? Couldn't a SWI also interrupt this critical section?
  • Hi Ray,

    Hwi_disable will also block Swis and tasks. Look at this thread for more information: e2e.ti.com/.../277476
  • I wrote two commercial RTOS's and disabling of HWI (and SWI) usually is a good thing as it prevents a lot of "bad things" from happening.

    I have discovered that that BEST solution is to NOT do what TI did and provide functions that are not thread safe. To do so creates havoc.

    There are a lot of reasons you want to disable interrupts and disable task switching in an RTOS. They are long and very complex (the biggest one is avoiding priority inversion). There are also a LOT of reasons NEVER to provide functions in your RTOS that are not thread-safe.