This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Possible race in NUS service - are there limitation on where to call ble_nus_data_send() from?

In my previous question, where I wanted to atomically send a large bulk of data, the solution was to keep track of p_bus->free_buffers, in order to calculate the amount of available space in the SD.

I've noticed that p_bus->free_buffers is modified from two routines in ble_nus.c:

  • on_hvx_tx_complete() - invoked from an SD interrupt service routine (high priority), and increments  p_bus->free_buffers:
    p_bus->free_buffers += p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count;
  • ble_nus_data_send() - which in my application is periodically called from main(), and decrements  p_bus->free_buffers:
    p_bus->free_buffers -= 1;

Questions:

  • Isn't this a race condition? The inc/dec operations themselves are not atomic, and the integer p_bus->free_buffers is modified from two different execution contexts.
  • If it is a race condition, what is the best way of mitigating it? Should I only call ble_nus_send_data() from an SD interrupt handler?
  • Hi, 

    It is difficult for me to tell if this is a race condition or not, but it seems likely. Do they interrupt each other when the code runs? You can use an SD interrupt handler, probably the easiest way. 

    Best regards,

    Simon

  • Do they interrupt each other when the code runs?

    Probably - the method called from main() runs in application scheduler context (i.e. main context), and is triggered by a timer.

    Can you please elaborate on the "use SD interrupt handler"? Do you mean posting the timer event to an SD IRQ?

    Alternatively, does nRF have an atomic increment/decrement operation, which does not include disabling all interrupts? 

  • Hi

    Sorry for the obscure answer. If you want to protect writes to the variable the easiest way would probably be to use a critical region (disable interrupts before updating it and enable them afterwards), like calling the ble_nus_send_data() from an interrupt handler. You could have a look through \components\libraries\atomic\nrf_atomic.h as well to see if any of the operations does what you need, but I'd recommend disabling interrupts.

    Best regards,

    Simon

Related