Bluetooth: Host: Added Recycled evt notifying conn object is available
- Which allow listeners to attempt to use the freed connection object to perform actions as e.g: start connectable advertisements. - Refactored bt_conn_unref() so it does not access conn struct after decrementing its reference count. Signed-off-by: Luis Ubieda <luisf@croxel.com>
This commit is contained in:
committed by
Fabio Baltieri
parent
4c88deaa82
commit
efb5d8372d
@@ -1000,6 +1000,20 @@ struct bt_conn_cb {
|
||||
*/
|
||||
void (*disconnected)(struct bt_conn *conn, uint8_t reason);
|
||||
|
||||
/** @brief A connection object has been returned to the pool.
|
||||
*
|
||||
* This callback notifies the application that it might be able to
|
||||
* allocate a connection object. No guarantee, first come, first serve.
|
||||
*
|
||||
* Use this to e.g. re-start connectable advertising or scanning.
|
||||
*
|
||||
* Treat this callback as an ISR, as it originates from
|
||||
* @ref bt_conn_unref which is used by the BT stack. Making
|
||||
* Bluetooth API calls in this context is error-prone and strongly
|
||||
* discouraged.
|
||||
*/
|
||||
void (*recycled)(void);
|
||||
|
||||
/** @brief LE connection parameter update request.
|
||||
*
|
||||
* This callback notifies the application that a remote device
|
||||
|
||||
@@ -85,6 +85,8 @@ static void conn_tx_destroy(struct bt_conn *conn, struct bt_conn_tx *tx)
|
||||
static void tx_complete_work(struct k_work *work);
|
||||
#endif /* CONFIG_BT_CONN_TX */
|
||||
|
||||
static void notify_recycled_conn_slot(void);
|
||||
|
||||
/* Group Connected BT_CONN only in this */
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
/* Peripheral timeout to initialize Connection Parameter Update procedure */
|
||||
@@ -1311,15 +1313,38 @@ struct bt_conn *bt_conn_ref(struct bt_conn *conn)
|
||||
void bt_conn_unref(struct bt_conn *conn)
|
||||
{
|
||||
atomic_val_t old;
|
||||
bool deallocated;
|
||||
enum bt_conn_type conn_type;
|
||||
uint8_t conn_role;
|
||||
uint16_t conn_handle;
|
||||
|
||||
__ASSERT(conn, "Invalid connection reference");
|
||||
|
||||
/* Storing parameters of interest so we don't access the object
|
||||
* after decrementing its ref-count
|
||||
*/
|
||||
conn_type = conn->type;
|
||||
conn_role = conn->role;
|
||||
conn_handle = conn->handle;
|
||||
|
||||
old = atomic_dec(&conn->ref);
|
||||
/* Prevent from accessing connection object */
|
||||
conn = NULL;
|
||||
deallocated = (atomic_get(&old) == 1);
|
||||
|
||||
LOG_DBG("handle %u ref %ld -> %ld", conn->handle, old, atomic_get(&conn->ref));
|
||||
LOG_DBG("handle %u ref %ld -> %ld", conn_handle, old, (old - 1));
|
||||
|
||||
__ASSERT(old > 0, "Conn reference counter is 0");
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn->type == BT_CONN_TYPE_LE &&
|
||||
conn->role == BT_CONN_ROLE_PERIPHERAL && atomic_get(&conn->ref) == 0) {
|
||||
/* Slot has been freed and can be taken. No guarantees are made on requests
|
||||
* to claim connection object as only the first claim will be served.
|
||||
*/
|
||||
if (deallocated) {
|
||||
notify_recycled_conn_slot();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn_type == BT_CONN_TYPE_LE &&
|
||||
conn_role == BT_CONN_ROLE_PERIPHERAL && deallocated) {
|
||||
bt_le_adv_resume();
|
||||
}
|
||||
}
|
||||
@@ -1431,6 +1456,23 @@ static void tx_complete_work(struct k_work *work)
|
||||
}
|
||||
#endif /* CONFIG_BT_CONN_TX */
|
||||
|
||||
static void notify_recycled_conn_slot(void)
|
||||
{
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
for (struct bt_conn_cb *cb = callback_list; cb; cb = cb->_next) {
|
||||
if (cb->recycled) {
|
||||
cb->recycled();
|
||||
}
|
||||
}
|
||||
|
||||
STRUCT_SECTION_FOREACH(bt_conn_cb, cb) {
|
||||
if (cb->recycled) {
|
||||
cb->recycled();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Group Connected BT_CONN only in this */
|
||||
#if defined(CONFIG_BT_CONN)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user