mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-31 19:24:33 +02:00
fix(ble_mesh): ensure the operation of adv busy is thread-safe
This commit is contained in:
@@ -159,19 +159,19 @@ extern bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh
|
|||||||
*
|
*
|
||||||
* @param target Address of atomic variable.
|
* @param target Address of atomic variable.
|
||||||
* @param excepted Value of excepted.
|
* @param excepted Value of excepted.
|
||||||
* @param new_val Write value if compare sunncess.
|
* @param new_val Write if target value is equal to expected one.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - true: write operation succeeded.
|
* - true: Target value updated.
|
||||||
* - false: write operation failed.
|
* - false: Target value not updated.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
|
||||||
static inline bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val)
|
static inline bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val)
|
||||||
{
|
{
|
||||||
return __atomic_compare_exchange_n(target, &excepted, &new_val, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
return __atomic_compare_exchange_n(target, &excepted, &new_val, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
extern bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val);
|
extern bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -170,13 +170,10 @@ bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val)
|
bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val)
|
||||||
{
|
{
|
||||||
bt_mesh_atomic_val_t ret = 0;
|
|
||||||
|
|
||||||
bt_mesh_atomic_lock();
|
bt_mesh_atomic_lock();
|
||||||
|
|
||||||
ret = *target;
|
|
||||||
if (*target == excepted) {
|
if (*target == excepted) {
|
||||||
*target = new_val;
|
*target = new_val;
|
||||||
bt_mesh_atomic_unlock();
|
bt_mesh_atomic_unlock();
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2017 Intel Corporation
|
* SPDX-FileCopyrightText: 2017 Intel Corporation
|
||||||
* SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -311,8 +311,7 @@ static void adv_thread(void *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* busy == 0 means this was canceled */
|
/* busy == 0 means this was canceled */
|
||||||
if (BLE_MESH_ADV(*buf)->busy) {
|
if (bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(*buf), 1, 0)) {
|
||||||
BLE_MESH_ADV(*buf)->busy = 0U;
|
|
||||||
#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF)
|
#if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF)
|
||||||
if (adv_send(*buf)) {
|
if (adv_send(*buf)) {
|
||||||
BT_WARN("Failed to send adv packet");
|
BT_WARN("Failed to send adv packet");
|
||||||
@@ -427,7 +426,7 @@ static void bt_mesh_unref_buf(bt_mesh_msg_t *msg)
|
|||||||
|
|
||||||
if (msg->arg) {
|
if (msg->arg) {
|
||||||
buf = (struct net_buf *)msg->arg;
|
buf = (struct net_buf *)msg->arg;
|
||||||
BLE_MESH_ADV(buf)->busy = 0U;
|
bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0);
|
||||||
if (buf->ref > 1U) {
|
if (buf->ref > 1U) {
|
||||||
buf->ref = 1U;
|
buf->ref = 1U;
|
||||||
}
|
}
|
||||||
@@ -471,7 +470,7 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb,
|
|||||||
|
|
||||||
BLE_MESH_ADV(buf)->cb = cb;
|
BLE_MESH_ADV(buf)->cb = cb;
|
||||||
BLE_MESH_ADV(buf)->cb_data = cb_data;
|
BLE_MESH_ADV(buf)->cb_data = cb_data;
|
||||||
BLE_MESH_ADV(buf)->busy = 1U;
|
bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1);
|
||||||
|
|
||||||
bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL);
|
bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL);
|
||||||
|
|
||||||
@@ -573,7 +572,7 @@ void bt_mesh_relay_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *c
|
|||||||
|
|
||||||
BLE_MESH_ADV(buf)->cb = cb;
|
BLE_MESH_ADV(buf)->cb = cb;
|
||||||
BLE_MESH_ADV(buf)->cb_data = cb_data;
|
BLE_MESH_ADV(buf)->cb_data = cb_data;
|
||||||
BLE_MESH_ADV(buf)->busy = 1U;
|
bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1);
|
||||||
|
|
||||||
msg.arg = (void *)net_buf_ref(buf);
|
msg.arg = (void *)net_buf_ref(buf);
|
||||||
msg.src = src;
|
msg.src = src;
|
||||||
@@ -736,7 +735,7 @@ static void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_
|
|||||||
|
|
||||||
BLE_MESH_ADV(buf)->cb = cb;
|
BLE_MESH_ADV(buf)->cb = cb;
|
||||||
BLE_MESH_ADV(buf)->cb_data = cb_data;
|
BLE_MESH_ADV(buf)->cb_data = cb_data;
|
||||||
BLE_MESH_ADV(buf)->busy = 1U;
|
bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1);
|
||||||
|
|
||||||
bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL);
|
bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL);
|
||||||
|
|
||||||
@@ -755,7 +754,7 @@ static void ble_adv_tx_reset(struct ble_adv_tx *tx, bool unref)
|
|||||||
}
|
}
|
||||||
bt_mesh_atomic_set(tx->flags, 0);
|
bt_mesh_atomic_set(tx->flags, 0);
|
||||||
memset(&tx->param, 0, sizeof(tx->param));
|
memset(&tx->param, 0, sizeof(tx->param));
|
||||||
BLE_MESH_ADV(tx->buf)->busy = 0U;
|
bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->buf), 0);
|
||||||
if (unref) {
|
if (unref) {
|
||||||
net_buf_unref(tx->buf);
|
net_buf_unref(tx->buf);
|
||||||
}
|
}
|
||||||
@@ -946,7 +945,8 @@ int bt_mesh_stop_ble_advertising(uint8_t index)
|
|||||||
/* busy 1, ref 1; busy 1, ref 2;
|
/* busy 1, ref 1; busy 1, ref 2;
|
||||||
* busy 0, ref 0; busy 0, ref 1;
|
* busy 0, ref 0; busy 0, ref 1;
|
||||||
*/
|
*/
|
||||||
if (BLE_MESH_ADV(tx->buf)->busy == 1U &&
|
|
||||||
|
if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(tx->buf)) &&
|
||||||
tx->buf->ref == 1U) {
|
tx->buf->ref == 1U) {
|
||||||
unref = false;
|
unref = false;
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2017 Intel Corporation
|
* SPDX-FileCopyrightText: 2017 Intel Corporation
|
||||||
* SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#ifndef _ADV_H_
|
#ifndef _ADV_H_
|
||||||
#define _ADV_H_
|
#define _ADV_H_
|
||||||
|
|
||||||
|
#include "mesh_atomic.h"
|
||||||
#include "mesh_access.h"
|
#include "mesh_access.h"
|
||||||
#include "mesh_bearer_adapt.h"
|
#include "mesh_bearer_adapt.h"
|
||||||
|
|
||||||
@@ -23,7 +24,8 @@ extern "C" {
|
|||||||
/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */
|
/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */
|
||||||
#define BLE_MESH_ADV_USER_DATA_SIZE 4
|
#define BLE_MESH_ADV_USER_DATA_SIZE 4
|
||||||
|
|
||||||
#define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf))
|
#define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf))
|
||||||
|
#define BLE_MESH_ADV_BUSY(buf) (BLE_MESH_ADV(buf)->busy)
|
||||||
|
|
||||||
typedef struct bt_mesh_msg {
|
typedef struct bt_mesh_msg {
|
||||||
bool relay; /* Flag indicates if the packet is a relayed one */
|
bool relay; /* Flag indicates if the packet is a relayed one */
|
||||||
@@ -45,8 +47,10 @@ struct bt_mesh_adv {
|
|||||||
const struct bt_mesh_send_cb *cb;
|
const struct bt_mesh_send_cb *cb;
|
||||||
void *cb_data;
|
void *cb_data;
|
||||||
|
|
||||||
uint8_t type:3,
|
uint8_t type:3;
|
||||||
busy:1;
|
|
||||||
|
bt_mesh_atomic_t busy;
|
||||||
|
|
||||||
uint8_t xmit;
|
uint8_t xmit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -174,7 +174,7 @@ static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason)
|
|||||||
/* Cancel the sending if necessary */
|
/* Cancel the sending if necessary */
|
||||||
if (frnd->pending_buf) {
|
if (frnd->pending_buf) {
|
||||||
bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 2U, BLE_MESH_BUF_REF_EQUAL);
|
bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 2U, BLE_MESH_BUF_REF_EQUAL);
|
||||||
BLE_MESH_ADV(frnd->last)->busy = 0U;
|
bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(frnd->last), 0);
|
||||||
} else {
|
} else {
|
||||||
bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 1U, BLE_MESH_BUF_REF_EQUAL);
|
bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 1U, BLE_MESH_BUF_REF_EQUAL);
|
||||||
}
|
}
|
||||||
|
@@ -285,7 +285,7 @@ static void free_segments(void)
|
|||||||
link.tx.buf[i] = NULL;
|
link.tx.buf[i] = NULL;
|
||||||
bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL);
|
bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL);
|
||||||
/* Mark as canceled */
|
/* Mark as canceled */
|
||||||
BLE_MESH_ADV(buf)->busy = 0U;
|
bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0);
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1327,7 +1327,7 @@ static void prov_retransmit(struct k_work *work)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BLE_MESH_ADV(buf)->busy) {
|
if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(buf))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2017 Intel Corporation
|
* SPDX-FileCopyrightText: 2017 Intel Corporation
|
||||||
* SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -257,7 +257,15 @@ static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx)
|
|||||||
{
|
{
|
||||||
bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 3U, BLE_MESH_BUF_REF_SMALL);
|
bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 3U, BLE_MESH_BUF_REF_SMALL);
|
||||||
|
|
||||||
BLE_MESH_ADV(tx->seg[seg_idx])->busy = 0U;
|
/**
|
||||||
|
* When cancelling a segment that is still in the adv sending queue, `tx->seg_pending`
|
||||||
|
* must else be decremented by one. More detailed information
|
||||||
|
* can be found in BLEMESH24-26.
|
||||||
|
*/
|
||||||
|
if (bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(tx->seg[seg_idx]), 1, 0)) {
|
||||||
|
tx->seg_pending--;
|
||||||
|
}
|
||||||
|
|
||||||
net_buf_unref(tx->seg[seg_idx]);
|
net_buf_unref(tx->seg[seg_idx]);
|
||||||
tx->seg[seg_idx] = NULL;
|
tx->seg[seg_idx] = NULL;
|
||||||
tx->nack_count--;
|
tx->nack_count--;
|
||||||
@@ -388,7 +396,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BLE_MESH_ADV(seg)->busy) {
|
if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) {
|
||||||
BT_DBG("Skipping segment that's still advertising");
|
BT_DBG("Skipping segment that's still advertising");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user