applications: nrf_audio: Move conn unref to after zbus publish - #30798
applications: nrf_audio: Move conn unref to after zbus publish#30798alexsven wants to merge 1 commit into
Conversation
CI InformationTo view the history of this post, click the 'edited' button above Inputs:Sources:sdk-nrf: PR head: 2c0ecba7b12d7678f8f5ec1f3033a94eb371f307 more detailssdk-nrf:
Github labels
List of changed files detected by CI (4)Outputs:ToolchainVersion: e214c2a47c Test Spec & Results: ✅ Success; ❌ Failure; 🟠 Queued; 🟡 Progress; ◻️ Skipped;
|
There was a problem hiding this comment.
Pull request overview
This PR adjusts Bluetooth disconnection event handling in the nRF Audio application so that the bt_conn pointer is less likely to be invalid when delivered via zbus, and updates consumers/documentation accordingly.
Changes:
- Move
bt_conn_unref()indisconnected_cb()to occur after publishing the zbusBT_MGMT_DISCONNECTEDevent. - Add defensive handling in unicast client/server disconnection listeners to retain the connection during processing.
- Document
bt_mgmt_msg.connlifetime expectations for zbus consumers.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| applications/nrf_audio/unicast_server/main.c | Adds disconnection-event conn validation / temporary ref management in the zbus listener. |
| applications/nrf_audio/unicast_client/main.c | Adds disconnection-event conn validation / temporary ref management in the zbus listener. |
| applications/nrf_audio/src/bluetooth/bt_management/bt_mgmt.c | Moves bt_conn_unref() to after zbus publish in disconnected_cb(). |
| applications/nrf_audio/include/zbus_common.h | Documents expected conn pointer lifetime for bt_mgmt zbus messages. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
5419c25 to
be4a550
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (1)
applications/nrf_audio/include/zbus_common.h:94
- These two lines have an extra leading space before the indentation tab, unlike the rest of this Doxygen block (
zbus_common.h:91-92,95-97). Remove it to keep the comment consistently indented and checkpatch-clean.
*
* If a listener needs to keep using this pointer beyond the immediate zbus listener
| ret = zbus_chan_pub(&bt_mgmt_chan, &msg, K_NO_WAIT); | ||
| ERR_CHK(ret); | ||
|
|
||
| if (IS_ENABLED(CONFIG_BT_CENTRAL)) { | ||
| bt_conn_unref(conn); | ||
| } |
There was a problem hiding this comment.
This isn't a thread safe solution.
bt_conn_unref(conn); may still be called before any of the subscribers for the message gets it. The only way to ensure that conn is valid in the callbacks, is that if bt_conn_ref is being called for each subscriber here. I'm not sure if that's possible though.
Is is possible to flush the channel, so that you can be sure that all callbacks are called before bt_conn_unref?
There was a problem hiding this comment.
We are aware that it is not thread safe, this was seen as the best possible solution as we don't necessarily control if the recipient of the message is a listeners or a subscriber.
There was a problem hiding this comment.
Oh, nvm, read a bit more up on zbus_chan_pub, and that is a synchronous API (i.e. the callbacks of the subscribers are called directly in this thread), so this should be working fine.
There was a problem hiding this comment.
@Thalley : That may well be the case for listeners, but I don't think that is the case for subscribers.
"Message subscribers, a thread-based observer that relies internally on a FIFO where the event dispatcher puts a copy of the message every time an observed channel is published or notified."
Another way which I believe is better:
When a subscriber needs to use the conn, do a:
struct bt_conn = bt_conn_ref(conn);
If bt_conn != NULL; then the ref is OK.
The only thing which may theoretically occur, is that the conn changes, so the same conn is actually re-used for a different conn.
- Move the unref of a conn pointer to after it has been published - Increases chance of the conn pointer being valid - Document that the conn pointer might be unvalid - Add checks to make sure conn pointer is valid where it is used - OCT-3490 Signed-off-by: Alexander Svensen <alexander.svensen@nordicsemi.no>
be4a550 to
2c0ecba
Compare
|
You can find the documentation preview for this PR here. |
| ret = zbus_chan_pub(&bt_mgmt_chan, &msg, K_NO_WAIT); | ||
| ERR_CHK(ret); | ||
|
|
||
| if (IS_ENABLED(CONFIG_BT_CENTRAL)) { | ||
| bt_conn_unref(conn); | ||
| } |
There was a problem hiding this comment.
Oh, nvm, read a bit more up on zbus_chan_pub, and that is a synchronous API (i.e. the callbacks of the subscribers are called directly in this thread), so this should be working fine.
| bt_conn_ref(msg->conn); | ||
|
|
||
| ret = bt_content_ctrl_conn_disconnected(msg->conn); | ||
| if (ret) { | ||
| LOG_ERR("Failed to handle disconnection in content control: %d", ret); | ||
| } | ||
|
|
||
| bt_conn_unref(msg->conn); |
There was a problem hiding this comment.
Since zbus_chan_pub is synchronous for ZBUS_LISTENER_DEFINE we don't need to do this bt_conn_ref and bt_conn_unref here, as the reference from the disconnected_cb is still valid.
It's only if the observer type was any other type that you'd (possibly) need this.
| bt_conn_ref(msg->conn); | |
| ret = bt_content_ctrl_conn_disconnected(msg->conn); | |
| if (ret) { | |
| LOG_ERR("Failed to handle disconnection in content control: %d", ret); | |
| } | |
| bt_conn_unref(msg->conn); | |
| ret = bt_content_ctrl_conn_disconnected(msg->conn); | |
| if (ret) { | |
| LOG_ERR("Failed to handle disconnection in content control: %d", ret); | |
| } |
| if (msg->conn == NULL) { | ||
| LOG_ERR("Disconnected event with NULL conn"); | ||
| return; | ||
| } | ||
|
|
||
| bt_conn_ref(msg->conn); | ||
| unicast_client_conn_disconnected(msg->conn); | ||
| bt_conn_unref(msg->conn); | ||
|
|
There was a problem hiding this comment.
| if (msg->conn == NULL) { | |
| LOG_ERR("Disconnected event with NULL conn"); | |
| return; | |
| } | |
| bt_conn_ref(msg->conn); | |
| unicast_client_conn_disconnected(msg->conn); | |
| bt_conn_unref(msg->conn); | |
| if (msg->conn == NULL) { | |
| LOG_ERR("Disconnected event with NULL conn"); | |
| return; | |
| } | |
| unicast_client_conn_disconnected(msg->conn); | |
| if (msg->conn == NULL) { | ||
| LOG_ERR("Disconnected event with NULL conn"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
For the same reason as mentioned elsewhere, this check is unnecessary if this is only triggered from disconnected_cb. It's fine to keep as is though
| return; | ||
| } | ||
|
|
||
| bt_conn_ref(msg->conn); |
There was a problem hiding this comment.
Need to check that the return from this is non-NULL.
- The same applies above.
Uh oh!
There was an error while loading. Please reload this page.