Skip to content

Commit ffbfaa4

Browse files
HaavardReirlubos
authored andcommitted
Bluetooth: GATT DM: Schedule host cbs in work q
Moves host calls in discovery manager callbacks to be scheduled in either a GATT DM-specific work queue or the system work queue depending on a new Kconfig option `BT_GATT_DM_WORKQ_CHOICE`. This is done to improve robustness and avoid possible concurrency issues. Using the system work queue will not increase the memory footprint, but is marked as experimental as the callbacks can potentially block, which is not recommended in the syswq. Signed-off-by: Håvard Reierstad <[email protected]>
1 parent 7cee631 commit ffbfaa4

File tree

3 files changed

+100
-17
lines changed

3 files changed

+100
-17
lines changed

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ Bluetooth® LE
191191
The SoftDevice Controller driver uses a devicetree node named ``bt_hci_sdc`` with a devicetree binding compatible with ``nordic,bt-hci-sdc``.
192192
The Zephyr Bluetooth LE Controller uses a devicetree node named ``bt_hci_controller`` with a devicetree binding compatible with ``zephyr,bt-hci-ll-sw-split``.
193193
Applications using the Zephyr Bluetooth Controller need to be updated (see the :ref:`migration guide <migration_2.8>`).
194+
* Host calls in GATT Discovery Manager (DM) callbacks are now scheduled in a workqueue.
195+
The :kconfig:option:`BT_GATT_DM_WORKQ_CHOICE` Kconfig option allows you to select the workqueue implementation.
196+
You can select either a workqueue specific to GATT DM (default) or the system workqueue.
197+
You can use the system workqueue if creating a new thread is not viable due to memory constraints, but it is not recommended to have potential blocking calls in the system workqueue.
194198

195199
Bluetooth Mesh
196200
--------------

subsys/bluetooth/Kconfig.discovery

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,51 @@ menuconfig BT_GATT_DM
1111

1212
if BT_GATT_DM
1313

14+
choice BT_GATT_DM_WORKQ_CHOICE
15+
prompt "GATT Discovery Manager workqueue selection"
16+
default BT_GATT_DM_WORKQ_OWN
17+
help
18+
Select the workqueue implementation for GATT Discovery Manager.
19+
20+
config BT_GATT_DM_WORKQ_OWN
21+
bool "Use own workqueue"
22+
help
23+
Use own workqueue for GATT Discovery Manager.
24+
25+
config BT_GATT_DM_WORKQ_SYS
26+
bool "Use system workqueue"
27+
select EXPERIMENTAL
28+
help
29+
Use system workqueue for GATT Discovery Manager. Can be used if creating a new thread
30+
is not viable due to memory constraints, but it is not recommended to have potential
31+
blocking calls in the system workqueue.
32+
33+
endchoice
34+
35+
if BT_GATT_DM_WORKQ_OWN
36+
37+
config BT_GATT_DM_WORKQ_STACK_SIZE
38+
# Hidden option for workqueue stack size. Should be derived from system
39+
# requirements.
40+
int
41+
default 1300 if BT_GATT_CACHING
42+
default 1140 if BT_TINYCRYPT_ECC
43+
default 1024
44+
45+
config BT_GATT_DM_WORKQ_PRIO
46+
int "GATT Discovery Manager workqueue priority."
47+
default 10
48+
help
49+
Priority level for the GATT Discovery Manager workqueue.
50+
51+
config BT_GATT_DM_WORKQ_INIT_PRIO
52+
int "GATT Discovery Manager workqueue init priority"
53+
default 50
54+
help
55+
Init priority level to setup the GATT Discovery Manager workqueue.
56+
57+
endif # BT_GATT_DM_WORKQ_OWN
58+
1459
config BT_GATT_DM_MAX_ATTRS
1560
int "Maximum number of attributes that can be present in the discovered service"
1661
default 35

subsys/bluetooth/gatt_dm.c

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ LOG_MODULE_REGISTER(bt_gatt_dm, CONFIG_BT_GATT_DM_LOG_LEVEL);
2222
BUILD_ASSERT(sizeof(struct bt_gatt_service_val) % DATA_ALIGN == 0);
2323
BUILD_ASSERT(sizeof(struct bt_gatt_chrc) % DATA_ALIGN == 0);
2424

25+
#if defined(CONFIG_BT_GATT_DM_WORKQ_OWN)
26+
K_THREAD_STACK_DEFINE(bt_gatt_dm_wq_stack_area, CONFIG_BT_GATT_DM_WORKQ_STACK_SIZE);
27+
static struct k_work_q bt_gatt_dm_wq;
28+
29+
static int gatt_dm_wq_init(void)
30+
{
31+
const struct k_work_queue_config cfg = {.name = "BT GATT DM WQ"};
32+
33+
k_work_queue_init(&bt_gatt_dm_wq);
34+
k_work_queue_start(&bt_gatt_dm_wq, bt_gatt_dm_wq_stack_area,
35+
K_THREAD_STACK_SIZEOF(bt_gatt_dm_wq_stack_area),
36+
CONFIG_BT_GATT_DM_WORKQ_PRIO, &cfg);
37+
return 0;
38+
}
39+
40+
SYS_INIT(gatt_dm_wq_init, POST_KERNEL, CONFIG_BT_GATT_DM_WORKQ_INIT_PRIO);
41+
#endif
42+
2543
/* Flags for parsed attribute array state */
2644
enum {
2745
STATE_ATTRS_LOCKED,
@@ -71,6 +89,9 @@ struct bt_gatt_dm {
7189

7290
/* Indicates that services should be searched by the UUID. */
7391
bool search_svc_by_uuid;
92+
93+
/* Work item used for discovery callbacks. */
94+
struct k_work discover_work;
7495
};
7596

7697
/* Currently only one instance is supported */
@@ -277,12 +298,27 @@ static void discovery_complete_error(struct bt_gatt_dm *dm, int err)
277298
}
278299
}
279300

301+
static void gatt_discover_work(struct k_work *work)
302+
{
303+
struct bt_gatt_dm *dm = CONTAINER_OF(work, struct bt_gatt_dm, discover_work);
304+
305+
if (!atomic_test_bit(dm->state_flags, STATE_ATTRS_LOCKED)) {
306+
LOG_WRN("Attributes not locked");
307+
return;
308+
}
309+
310+
int err = bt_gatt_discover(dm->conn, &(dm->discover_params));
311+
312+
if (err) {
313+
LOG_ERR("GATT discover failed, error: %d.", err);
314+
discovery_complete_error(dm, -ENOMEM);
315+
}
316+
}
317+
280318
static uint8_t discovery_process_service(struct bt_gatt_dm *dm,
281319
const struct bt_gatt_attr *attr,
282320
struct bt_gatt_discover_params *params)
283321
{
284-
int err;
285-
286322
if (!attr) {
287323
discovery_complete_not_found(dm);
288324
return BT_GATT_ITER_STOP;
@@ -336,13 +372,12 @@ static uint8_t discovery_process_service(struct bt_gatt_dm *dm,
336372
dm->discover_params.type = BT_GATT_DISCOVER_ATTRIBUTE;
337373
dm->discover_params.start_handle = cur_attr->handle + 1;
338374
LOG_DBG("Starting descriptors discovery");
339-
err = bt_gatt_discover(dm->conn, &(dm->discover_params));
340375

341-
if (err) {
342-
LOG_ERR("Descriptor discover failed, error: %d.", err);
343-
discovery_complete_error(dm, -ENOMEM);
344-
return BT_GATT_ITER_STOP;
345-
}
376+
#if defined(CONFIG_BT_GATT_DM_WORKQ_OWN)
377+
k_work_submit_to_queue(&bt_gatt_dm_wq, &dm->discover_work);
378+
#else
379+
k_work_submit(&dm->discover_work);
380+
#endif
346381

347382
return BT_GATT_ITER_STOP;
348383
}
@@ -360,15 +395,12 @@ static uint8_t discovery_process_attribute(struct bt_gatt_dm *dm,
360395
dm->attrs[0].handle + 1;
361396
dm->discover_params.type =
362397
BT_GATT_DISCOVER_CHARACTERISTIC;
363-
int err = bt_gatt_discover(dm->conn,
364-
&(dm->discover_params));
365-
366-
if (err) {
367-
LOG_ERR("Characteristic discover failed,"
368-
" error: %d.",
369-
err);
370-
discovery_complete_error(dm, err);
371-
}
398+
399+
#if defined(CONFIG_BT_GATT_DM_WORKQ_OWN)
400+
k_work_submit_to_queue(&bt_gatt_dm_wq, &dm->discover_work);
401+
#else
402+
k_work_submit(&dm->discover_work);
403+
#endif
372404
} else {
373405
discovery_complete(dm);
374406
}
@@ -645,6 +677,7 @@ int bt_gatt_dm_start(struct bt_conn *conn,
645677
dm->discover_params.start_handle = 0x0001;
646678
dm->discover_params.end_handle = 0xffff;
647679
dm->discover_params.type = BT_GATT_DISCOVER_PRIMARY;
680+
k_work_init(&dm->discover_work, gatt_discover_work);
648681

649682
err = bt_gatt_discover(conn, &dm->discover_params);
650683
if (err) {
@@ -706,6 +739,7 @@ int bt_gatt_dm_data_release(struct bt_gatt_dm *dm)
706739
return -EALREADY;
707740
}
708741

742+
k_work_cancel(&dm->discover_work);
709743
svc_attr_memory_release(dm);
710744
atomic_clear_bit(dm->state_flags, STATE_ATTRS_LOCKED);
711745

0 commit comments

Comments
 (0)