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

Possible race condition in att_mtu_throughput example?

I´m trying to build an application similar to the peripheral side of the app_mtu_throughput example. I need to send a large buffer via notifications to the server.

I'm using an nRF52832 with an S132 and SDK 15.2.0

As I understand it, the att_mtu_throughput example kickstarts the notification process by calling char_notification_send, where it fills the tx buffer of the soft device by calling sd_ble_gatts_hvx until it returns NRF_ERROR_RESOURCES. After that, it sets p_ctx->busy to true and exits the loop. The next time a packet (or several) is sent, a BLE_GATTS_EVT_HVN_TX_COMPLETE event is reported, and if p_ctx->busy was true it means the loop has stopped, so it has to call char_notification_send to fill the buffer up again.

What if all the packets are sent between the call to sd_ble_gatts_hvx that returned NRF_ERROR_RESOURCES and setting p_ctx->busy to true? Then no BLE_GATTS_EVT_HVN_TX_COMPLETE event will observe p_ctx->busy to be true, and the loop would never be restarted. See the example code below.

static void on_tx_complete(nrf_ble_amts_t * p_ctx)
{
    if (p_ctx->busy)
    {
        p_ctx->busy = false;
        char_notification_send(p_ctx);
    }
}

static void char_notification_send(nrf_ble_amts_t * p_ctx)
{
    // (...)
    
    uint32_t err_code = NRF_SUCCESS;
    while (err_code == NRF_SUCCESS)
    {
        // (...)

        err_code = sd_ble_gatts_hvx(p_ctx->conn_handle, &hvx_param); /* FROM HERE */

        if (err_code == NRF_ERROR_RESOURCES)
        {
            // Wait for BLE_GATTS_EVT_HVN_TX_COMPLETE.
            /* TO HERE */ p_ctx->busy = true;
            break;
        }
        
        // (...)
    }
}

If the buffer is emptied between the call to sd_ble_gatts_hvx and p_ctx->busy = true then the loop never restarts. Note that the code is initially run from the main loop, so the Soft Device can interrupt the routine whenever it needs to.

I've never seen the example fail, but I'm worried about a similar implementation failing in the field. How could I make sure that the buffer is not emptied on that critical section? Are there timing restrictions that ensure that that can never happen that I'm not aware of?

Thank you!

Parents Reply Children
No Data
Related