From 89c94918045a89c749e41e7c4ca268877390ddd0 Mon Sep 17 00:00:00 2001 From: Aleksander Wasaznik Date: Thu, 14 Mar 2024 14:07:15 +0100 Subject: [PATCH] Bluetooth: testlib: add `bt_testlib_conn_wait_free` This function waits for a free connection slot. It should be used to slow down a busy loop trying to obtains a connection slot. Signed-off-by: Aleksander Wasaznik --- .../common/testlib/include/testlib/conn.h | 14 +++++++ .../bluetooth/common/testlib/src/conn_wait.c | 41 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/tests/bluetooth/common/testlib/include/testlib/conn.h b/tests/bluetooth/common/testlib/include/testlib/conn.h index ac371586b5..4f89fd20b0 100644 --- a/tests/bluetooth/common/testlib/include/testlib/conn.h +++ b/tests/bluetooth/common/testlib/include/testlib/conn.h @@ -105,4 +105,18 @@ void bt_testlib_conn_unref(struct bt_conn **connp); */ struct bt_conn *bt_testlib_conn_unindex(enum bt_conn_type conn_type, uint8_t conn_index); +/** + * @brief Wait until there is a free connection slot + * + * Thread-safe. + * + * Returns when there already is a free connection slot or a + * connection slot is recycled. + * + * @note The free connection slots may have been taken by the + * time this function returns. Call this function in a loop if + * needed. + */ +void bt_testlib_conn_wait_free(void); + #endif /* ZEPHYR_TESTS_BLUETOOTH_COMMON_TESTLIB_INCLUDE_TESTLIB_CONN_H_ */ diff --git a/tests/bluetooth/common/testlib/src/conn_wait.c b/tests/bluetooth/common/testlib/src/conn_wait.c index fdcaa4680d..de1c72779c 100644 --- a/tests/bluetooth/common/testlib/src/conn_wait.c +++ b/tests/bluetooth/common/testlib/src/conn_wait.c @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -19,6 +20,7 @@ LOG_MODULE_REGISTER(bt_testlib_conn_wait, LOG_LEVEL_DBG); static K_MUTEX_DEFINE(conn_wait_mutex); +static K_CONDVAR_DEFINE(conn_recycled); static K_CONDVAR_DEFINE(something_changed); static void on_change(struct bt_conn *conn, uint8_t err) @@ -28,9 +30,17 @@ static void on_change(struct bt_conn *conn, uint8_t err) k_mutex_unlock(&conn_wait_mutex); } +static void on_conn_recycled(void) +{ + k_mutex_lock(&conn_wait_mutex, K_FOREVER); + k_condvar_broadcast(&conn_recycled); + k_mutex_unlock(&conn_wait_mutex); +} + BT_CONN_CB_DEFINE(conn_callbacks) = { .connected = on_change, .disconnected = on_change, + .recycled = on_conn_recycled, }; static enum bt_conn_state bt_conn_state(struct bt_conn *conn) @@ -66,3 +76,34 @@ int bt_testlib_wait_disconnected(struct bt_conn *conn) k_mutex_unlock(&conn_wait_mutex); return 0; } + +void bt_testlib_conn_wait_free(void) +{ + if (!IS_ENABLED(CONFIG_BT_CONN)) { + __ASSERT_NO_MSG(false); + return; + } + + /* The mutex must be held duing the initial check loop to buffer + * any `conn_cb.released` events. + * + * This ensures that any connection slots that become free + * during the loop execution are detected. + */ + k_mutex_lock(&conn_wait_mutex, K_FOREVER); + + for (size_t i = 0; i < CONFIG_BT_MAX_CONN; i++) { + struct bt_conn *conn = bt_testlib_conn_unindex(BT_CONN_TYPE_LE, i); + + if (!conn) { + goto done; + } + + bt_testlib_conn_unref(&conn); + } + + k_condvar_wait(&conn_recycled, &conn_wait_mutex, K_FOREVER); + +done: + k_mutex_unlock(&conn_wait_mutex); +}