Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,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_ifdef(CONFIG_ZMK_LOW_PRIORITY_WORK_QUEUE app PRIVATE src/workqueue.c)
target_sources(app PRIVATE src/workqueue.c)
target_sources(app PRIVATE src/main.c)

add_subdirectory(src/display/)
Expand Down
19 changes: 19 additions & 0 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,25 @@ config ZMK_LOW_PRIORITY_THREAD_PRIORITY

endif # ZMK_LOW_PRIORITY_WORK_QUEUE

choice ZMK_MAIN_WORK_QUEUE
prompt "Main Work Queue Selection"

config ZMK_MAIN_WORK_QUEUE_SYSTEM
bool "System Work Queue"
help
Use the system work queue. This is a high priority non-preemptible queue,
so it may prevent other high priority work from being services in a
timely manner.

config ZMK_MAIN_WORK_QUEUE_MAIN
bool "Main Thread Work Queue"
help
Use the a work queue processed by the main thread. This is a high priority
but preemptible queue, so it may be interrupted to have other high priority
work serviced in a timely manner.

endchoice

endmenu # Advanced

endmenu # ZMK
Expand Down
6 changes: 5 additions & 1 deletion app/Kconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
# SPDX-License-Identifier: MIT

config SYSTEM_WORKQUEUE_STACK_SIZE
default 1536 if ZMK_BLE
default 512

config MAIN_STACK_SIZE
default 2048 if SOC_RP2040
default 2048 if ZMK_BLE
default 1536 if ZMK_BLE

# HID
if ZMK_HID_REPORT_TYPE_HKRO
Expand Down
12 changes: 12 additions & 0 deletions app/include/zmk/workqueue.h
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
/*
* Copyright (c) 2025 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#pragma once

struct k_work_q *zmk_main_work_q(void);

void zmk_main_work_queue_run(void);

struct k_work_q *zmk_workqueue_lowprio_work_q(void);
1 change: 1 addition & 0 deletions app/module/drivers/kscan/kscan_mock.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ static int kscan_mock_configure(const struct device *dev, kscan_callback_t callb
k_work_schedule(&data->work, K_MSEC(ZMK_MOCK_MSEC(ev))); \
} else if (cfg->exit_after) { \
LOG_DBG("Exiting"); \
k_msleep(1); \
exit(0); \
} \
} \
Expand Down
9 changes: 7 additions & 2 deletions app/src/activity.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/events/sensor_event.h>

#include <zmk/pm.h>
#include <zmk/workqueue.h>

#include <zmk/activity.h>

Expand Down Expand Up @@ -95,7 +96,9 @@ void activity_work_handler(struct k_work *work) {

K_WORK_DEFINE(activity_work, activity_work_handler);

void activity_expiry_function(struct k_timer *_timer) { k_work_submit(&activity_work); }
void activity_expiry_function(struct k_timer *_timer) {
k_work_submit_to_queue(zmk_main_work_q(), &activity_work);
}

K_TIMER_DEFINE(activity_timer, activity_expiry_function, NULL);

Expand All @@ -116,7 +119,9 @@ static void note_activity_work_cb(struct k_work *_work) { note_activity(); }

K_WORK_DEFINE(note_activity_work, note_activity_work_cb);

static void activity_input_listener(struct input_event *ev) { k_work_submit(&note_activity_work); }
static void activity_input_listener(struct input_event *ev) {
k_work_submit_to_queue(zmk_main_work_q(), &note_activity_work);
}

INPUT_CALLBACK_DEFINE(NULL, activity_input_listener);

Expand Down
4 changes: 3 additions & 1 deletion app/src/backlight.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <zmk/activity.h>
#include <zmk/backlight.h>
#include <zmk/usb.h>
#include <zmk/workqueue.h>
#include <zmk/event_manager.h>
#include <zmk/events/activity_state_changed.h>
#include <zmk/events/usb_conn_state_changed.h>
Expand Down Expand Up @@ -107,7 +108,8 @@ static int zmk_backlight_update_and_save(void) {
}

#if IS_ENABLED(CONFIG_SETTINGS)
int ret = k_work_reschedule(&backlight_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
int ret = k_work_reschedule_for_queue(zmk_main_work_q(), &backlight_save_work,
K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
return MIN(ret, 0);
#else
return 0;
Expand Down
3 changes: 2 additions & 1 deletion app/src/behavior_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <zmk/behavior_queue.h>
#include <zmk/behavior.h>
#include <zmk/workqueue.h>

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
Expand Down Expand Up @@ -51,7 +52,7 @@ static void behavior_queue_process_next(struct k_work *work) {
LOG_DBG("Processing next queued behavior in %dms", item.wait);

if (item.wait > 0) {
k_work_schedule(&queue_work, K_MSEC(item.wait));
k_work_schedule_for_queue(zmk_main_work_q(), &queue_work, K_MSEC(item.wait));
break;
}
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/behaviors/behavior_hold_tap.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <zmk/events/position_state_changed.h>
#include <zmk/events/keycode_state_changed.h>
#include <zmk/behavior.h>
#include <zmk/workqueue.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

Expand Down Expand Up @@ -635,7 +636,7 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
// if this behavior was queued we have to adjust the timer to only
// wait for the remaining time.
int32_t tapping_term_ms_left = (hold_tap->timestamp + cfg->tapping_term_ms) - k_uptime_get();
k_work_schedule(&hold_tap->work, K_MSEC(tapping_term_ms_left));
k_work_schedule_for_queue(zmk_main_work_q(), &hold_tap->work, K_MSEC(tapping_term_ms_left));

return ZMK_BEHAVIOR_OPAQUE;
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/behaviors/behavior_sticky_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <zmk/events/modifiers_state_changed.h>
#include <zmk/hid.h>
#include <zmk/keymap.h>
#include <zmk/workqueue.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

Expand Down Expand Up @@ -201,7 +202,7 @@ static int on_sticky_key_binding_released(struct zmk_behavior_binding *binding,
// adjust timer in case this behavior was queued by a hold-tap
int32_t ms_left = sticky_key->release_at - k_uptime_get();
if (ms_left > 0) {
k_work_schedule(&sticky_key->release_timer, K_MSEC(ms_left));
k_work_schedule_for_queue(zmk_main_work_q(), &sticky_key->release_timer, K_MSEC(ms_left));
}
return ZMK_BEHAVIOR_OPAQUE;
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/behaviors/behavior_tap_dance.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <zmk/events/position_state_changed.h>
#include <zmk/events/keycode_state_changed.h>
#include <zmk/hid.h>
#include <zmk/workqueue.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

Expand Down Expand Up @@ -104,7 +105,7 @@ static void reset_timer(struct active_tap_dance *tap_dance,
tap_dance->release_at = event.timestamp + tap_dance->config->tapping_term_ms;
int32_t ms_left = tap_dance->release_at - k_uptime_get();
if (ms_left > 0) {
k_work_schedule(&tap_dance->release_timer, K_MSEC(ms_left));
k_work_schedule_for_queue(zmk_main_work_q(), &tap_dance->release_timer, K_MSEC(ms_left));
LOG_DBG("Successfully reset timer at position %d", tap_dance->position);
}
}
Expand Down
12 changes: 7 additions & 5 deletions app/src/ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/split/bluetooth/uuid.h>
#include <zmk/event_manager.h>
#include <zmk/events/ble_active_profile_changed.h>
#include <zmk/workqueue.h>

#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
#include <zmk/events/keycode_state_changed.h>
Expand Down Expand Up @@ -111,7 +112,7 @@ void set_profile_address(uint8_t index, const bt_addr_le_t *addr) {
#if IS_ENABLED(CONFIG_SETTINGS)
settings_save_one(setting_name, &profiles[index], sizeof(struct zmk_ble_profile));
#endif
k_work_submit(&raise_profile_changed_event_work);
k_work_submit_to_queue(zmk_main_work_q(), &raise_profile_changed_event_work);
}

bool zmk_ble_active_profile_is_connected(void) {
Expand Down Expand Up @@ -260,7 +261,8 @@ static struct k_work_delayable ble_save_work;

static int ble_save_profile(void) {
#if IS_ENABLED(CONFIG_SETTINGS)
return k_work_reschedule(&ble_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
return k_work_reschedule_for_queue(zmk_main_work_q(), &ble_save_work,
K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
#else
return 0;
#endif
Expand Down Expand Up @@ -506,7 +508,7 @@ static void connected(struct bt_conn *conn, uint8_t err) {

if (is_conn_active_profile(conn)) {
LOG_DBG("Active profile connected");
k_work_submit(&raise_profile_changed_event_work);
k_work_submit_to_queue(zmk_main_work_q(), &raise_profile_changed_event_work);
}
}

Expand All @@ -527,11 +529,11 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) {

// We need to do this in a work callback, otherwise the advertising update will still see the
// connection for a profile as active, and not start advertising yet.
k_work_submit(&update_advertising_work);
k_work_submit_to_queue(zmk_main_work_q(), &update_advertising_work);

if (is_conn_active_profile(conn)) {
LOG_DBG("Active profile disconnected");
k_work_submit(&raise_profile_changed_event_work);
k_work_submit_to_queue(zmk_main_work_q(), &raise_profile_changed_event_work);
}
}

Expand Down
4 changes: 3 additions & 1 deletion app/src/combo.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <zmk/matrix.h>
#include <zmk/keymap.h>
#include <zmk/virtual_key_position.h>
#include <zmk/workqueue.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

Expand Down Expand Up @@ -413,7 +414,8 @@ static void update_timeout_task() {
k_work_cancel_delayable(&timeout_task);
return;
}
if (k_work_schedule(&timeout_task, K_MSEC(first_timeout - k_uptime_get())) >= 0) {
if (k_work_schedule_for_queue(zmk_main_work_q(), &timeout_task,
K_MSEC(first_timeout - k_uptime_get())) >= 0) {
timeout_task_timeout_at = first_timeout;
}
}
Expand Down
10 changes: 6 additions & 4 deletions app/src/display/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/event_manager.h>
#include <zmk/events/activity_state_changed.h>
#include <zmk/display/status_screen.h>
#include <zmk/workqueue.h>

static const struct device *display = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));

Expand Down Expand Up @@ -53,7 +54,7 @@ struct k_work_q *zmk_display_work_q() {
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED)
return &display_work_q;
#else
return &k_sys_work_q;
return zmk_main_work_q();
#endif
}

Expand Down Expand Up @@ -150,10 +151,11 @@ int zmk_display_init() {
CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_PRIORITY, NULL);
#endif

#if IS_ENABLED(CONFIG_ARCH_POSIX)
initialize_display(NULL);
#else
#if IS_ENABLED(CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED) || \
IS_ENABLED(CONFIG_ZMK_MAIN_WORK_QUEUE_SYSTEM)
k_work_submit_to_queue(zmk_display_work_q(), &init_work);
#else
initialize_display(NULL);
#endif

LOG_DBG("");
Expand Down
4 changes: 3 additions & 1 deletion app/src/endpoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <zmk/events/ble_active_profile_changed.h>
#include <zmk/events/usb_conn_state_changed.h>
#include <zmk/events/endpoint_changed.h>
#include <zmk/workqueue.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
Expand All @@ -42,7 +43,8 @@ static struct k_work_delayable endpoints_save_work;

static int endpoints_save_preferred(void) {
#if IS_ENABLED(CONFIG_SETTINGS)
return k_work_reschedule(&endpoints_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
return k_work_reschedule_for_queue(zmk_main_work_q(), &endpoints_save_work,
K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
#else
return 0;
#endif
Expand Down
6 changes: 4 additions & 2 deletions app/src/ext_power_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <zephyr/kernel.h>
#include <zephyr/settings/settings.h>
#include <zephyr/drivers/gpio.h>
#include <zmk/workqueue.h>

#include <drivers/ext_power.h>

Expand Down Expand Up @@ -49,7 +50,8 @@ static struct k_work_delayable ext_power_save_work;

int ext_power_save_state(void) {
#if IS_ENABLED(CONFIG_SETTINGS)
int ret = k_work_reschedule(&ext_power_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
int ret = k_work_reschedule_for_queue(zmk_main_work_q(), &ext_power_save_work,
K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
return MIN(ret, 0);
#else
return 0;
Expand Down Expand Up @@ -134,7 +136,7 @@ static int ext_power_settings_commit() {
if (!data->settings_init) {

data->status = true;
k_work_schedule(&ext_power_save_work, K_NO_WAIT);
k_work_schedule_for_queue(zmk_main_work_q(), &ext_power_save_work, K_NO_WAIT);

ext_power_enable(dev);
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/hid_indicators.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <zmk/events/hid_indicators_changed.h>
#include <zmk/events/endpoint_changed.h>
#include <zmk/split/central.h>
#include <zmk/workqueue.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

Expand Down Expand Up @@ -48,7 +49,7 @@ void zmk_hid_indicators_set_profile(zmk_hid_indicators_t indicators,
// or writes only one entry at a time, so it is safe to do these operations without a lock.
hid_indicators[profile] = indicators;

k_work_submit(&led_changed_work);
k_work_submit_to_queue(zmk_main_work_q(), &led_changed_work);
}

void zmk_hid_indicators_process_report(struct zmk_hid_led_report_body *report,
Expand Down
8 changes: 7 additions & 1 deletion app/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL);

#include <zmk/workqueue.h>

#if IS_ENABLED(CONFIG_ZMK_DISPLAY)

#include <zmk/display.h>
Expand All @@ -30,7 +32,7 @@ int main(void) {
#ifdef CONFIG_ZMK_DISPLAY
zmk_display_init();

#if IS_ENABLED(CONFIG_ARCH_POSIX)
#if IS_ENABLED(CONFIG_ARCH_POSIX) && !IS_ENABLED(CONFIG_ZMK_MAIN_WORK_QUEUE_MAIN)
// Workaround for an SDL display issue:
// https://github.com/zephyrproject-rtos/zephyr/issues/71410
while (1) {
Expand All @@ -41,5 +43,9 @@ int main(void) {

#endif /* CONFIG_ZMK_DISPLAY */

#if IS_ENABLED(CONFIG_ZMK_MAIN_WORK_QUEUE_MAIN)
zmk_main_work_queue_run();
#endif

return 0;
}
3 changes: 2 additions & 1 deletion app/src/physical_layouts.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/physical_layouts.h>
#include <zmk/event_manager.h>
#include <zmk/events/position_state_changed.h>
#include <zmk/workqueue.h>

ZMK_EVENT_IMPL(zmk_physical_layout_selection_changed);

Expand Down Expand Up @@ -192,7 +193,7 @@ static void zmk_physical_layout_kscan_callback(const struct device *dev, uint32_
.state = (pressed ? ZMK_KSCAN_EVENT_STATE_PRESSED : ZMK_KSCAN_EVENT_STATE_RELEASED)};

k_msgq_put(&physical_layouts_kscan_msgq, &ev, K_NO_WAIT);
k_work_submit(&msg_processor.work);
k_work_submit_to_queue(zmk_main_work_q(), &msg_processor.work);
}

static void zmk_physical_layouts_kscan_process_msgq(struct k_work *item) {
Expand Down
Loading