From 9a963abfc8b27c6fdfb5b6b4b38e5905d6a360a7 Mon Sep 17 00:00:00 2001 From: Xudong Zheng <7pkvm5aw@slicealias.com> Date: Mon, 17 Jul 2023 17:16:04 -0400 Subject: [PATCH] refactor: use low priority workqueue for underglow and battery reporting Blocking operations on the high priority system workqueue may result in deadlocks, particularly when Bluetooth is in use. --- app/CMakeLists.txt | 1 + app/Kconfig | 8 ++++++++ app/include/zmk/workqueue.h | 1 + app/src/battery.c | 14 +++++--------- app/src/rgb_underglow.c | 3 ++- app/src/workqueue.c | 27 +++++++++++++++++++++++++++ 6 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 app/include/zmk/workqueue.h create mode 100644 app/src/workqueue.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 4c1c63c2..efa34905 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -87,6 +87,7 @@ target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/usb.c) target_sources_ifdef(CONFIG_ZMK_USB app PRIVATE src/usb_hid.c) target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c) target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c) +target_sources(app PRIVATE src/workqueue.c) target_sources(app PRIVATE src/main.c) add_subdirectory(src/display/) diff --git a/app/Kconfig b/app/Kconfig index fe019918..89a128b5 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -504,6 +504,14 @@ config ZMK_BATTERY_REPORT_INTERVAL int "Battery level report interval in seconds" default 60 +config ZMK_LOW_PRIORITY_THREAD_STACK_SIZE + int "Low priority thread stack size" + default 768 + +config ZMK_LOW_PRIORITY_THREAD_PRIORITY + int "Low priority thread priority" + default 10 + #Advanced endmenu diff --git a/app/include/zmk/workqueue.h b/app/include/zmk/workqueue.h new file mode 100644 index 00000000..41e94580 --- /dev/null +++ b/app/include/zmk/workqueue.h @@ -0,0 +1 @@ +struct k_work_q *zmk_workqueue_lowprio_work_q(); diff --git a/app/src/battery.c b/app/src/battery.c index 540f7c3e..87a25e08 100644 --- a/app/src/battery.c +++ b/app/src/battery.c @@ -18,6 +18,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include static uint8_t last_state_of_charge = 0; @@ -77,7 +78,9 @@ static void zmk_battery_work(struct k_work *work) { K_WORK_DEFINE(battery_work, zmk_battery_work); -static void zmk_battery_timer(struct k_timer *timer) { k_work_submit(&battery_work); } +static void zmk_battery_timer(struct k_timer *timer) { + k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &battery_work); +} K_TIMER_DEFINE(battery_timer, zmk_battery_timer, NULL); @@ -97,14 +100,7 @@ static int zmk_battery_init(const struct device *_arg) { return -ENODEV; } - int rc = zmk_battery_update(battery); - - if (rc != 0) { - LOG_DBG("Failed to update battery value: %d.", rc); - return rc; - } - - k_timer_start(&battery_timer, K_MINUTES(1), K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); + k_timer_start(&battery_timer, K_NO_WAIT, K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL)); return 0; } diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 7b649174..08ba2fb2 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -24,6 +24,7 @@ #include #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -203,7 +204,7 @@ static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) { return; } - k_work_submit(&underglow_work); + k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &underglow_work); } K_TIMER_DEFINE(underglow_tick, zmk_rgb_underglow_tick_handler, NULL); diff --git a/app/src/workqueue.c b/app/src/workqueue.c new file mode 100644 index 00000000..a9a8bce5 --- /dev/null +++ b/app/src/workqueue.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#include + +K_THREAD_STACK_DEFINE(lowprio_q_stack, CONFIG_ZMK_LOW_PRIORITY_THREAD_STACK_SIZE); + +static struct k_work_q lowprio_work_q; + +struct k_work_q *zmk_workqueue_lowprio_work_q() { + return &lowprio_work_q; +} + +static int workqueue_init() { + static const struct k_work_queue_config queue_config = {.name = "Low Priority Work Queue"}; + k_work_queue_start(&lowprio_work_q, lowprio_q_stack, K_THREAD_STACK_SIZEOF(lowprio_q_stack), + CONFIG_ZMK_LOW_PRIORITY_THREAD_PRIORITY, &queue_config); + return 0; +} + +SYS_INIT(workqueue_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);