-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor events API to avoid heap/dynamic allocations #1722
Refactor events API to avoid heap/dynamic allocations #1722
Conversation
be2dc89
to
554ae26
Compare
0e01ac3
to
f40ff67
Compare
1e5b9fe
to
51025ac
Compare
51025ac
to
fd29240
Compare
a827778
to
286a9ba
Compare
3d64dcb
to
daba812
Compare
I have been testing this full time for the last week on a split with keymap including hold-taps, combos and BLE profile change events with no issues. (Also mouse keys as a bonus, with this patch to get it working on this PR.) Among changes covered here, I haven't tested with sticky keys, key toggles, key repeat, layer state and USB status change events, WPM events, sensor/encoders. |
daba812
to
8c09aa8
Compare
I've just flashed to my revxlp RP2040 last night with a keymap that includes combos, sticky keys, caps word, etc. and will daily that with this change the next week as well. First day of use was uneventful. |
8c09aa8
to
f85339f
Compare
cd578eb
to
d35e98f
Compare
d35e98f
to
d3237c7
Compare
* Move to local/stack allocated event API that doesn't require dynamic allocation/freeing. * Disable heap, we no longer use alloc/free unless using LVGL. * Tons of refactors all over to account for the new event approach.
28b5a6d
to
da46109
Compare
app/include/zmk/event_manager.h
Outdated
#define ZMK_EVENT_RAISE(ev) \ | ||
((__ASSERT((uint8_t *)&(ev).header - (uint8_t *)&ev == 0, \ | ||
"header must be first element of event")), \ | ||
zmk_event_manager_raise(&(ev).header)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zmk_event_manager_raise(&(ev).header)); | |
zmk_event_manager_raise(&(ev).header)) |
If these should be usable in expressions like return ZMK_EVENT_RAISE(ev)
, then they shouldn't end in a semicolon. That will prevent other things that should work like
result = ZMK_EVENT_RAISE(ev) ? OK : ERROR;
and it also allows
int test(void) {
return ZMK_EVENT_RAISE(ev) // no semicolon
}
to compile, which just feels weird.
app/include/zmk/event_manager.h
Outdated
zmk_event_manager_raise_after((zmk_event_t *)ev, &zmk_listener_##mod); | ||
((__ASSERT((uint8_t *)&(ev).header - (uint8_t *)&ev == 0, \ | ||
"header must be first element of event")), \ | ||
zmk_event_manager_raise_after(&(ev).header, &zmk_listener_##mod)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zmk_event_manager_raise_after(&(ev).header, &zmk_listener_##mod)); | |
zmk_event_manager_raise_after(&(ev).header, &zmk_listener_##mod)) |
app/include/zmk/event_manager.h
Outdated
#define ZMK_EVENT_RELEASE(ev) zmk_event_manager_release((zmk_event_t *)ev); | ||
((__ASSERT((uint8_t *)&(ev).header - (uint8_t *)&ev == 0, \ | ||
"header must be first element of event")), \ | ||
zmk_event_manager_raise_at(&(ev).header, &zmk_listener_##mod)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zmk_event_manager_raise_at(&(ev).header, &zmk_listener_##mod)); | |
zmk_event_manager_raise_at(&(ev).header, &zmk_listener_##mod)) |
app/include/zmk/event_manager.h
Outdated
|
||
#define ZMK_EVENT_FREE(ev) k_free((void *)ev); | ||
#define ZMK_EVENT_RELEASE(ev) zmk_event_manager_release((zmk_event_t *)&ev); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define ZMK_EVENT_RELEASE(ev) zmk_event_manager_release((zmk_event_t *)&ev); | |
#define ZMK_EVENT_RELEASE(ev) zmk_event_manager_release((zmk_event_t *)&ev) |
Also, I think we want to add the assert and use &ev.header
instead of a cast here too?
app/include/zmk/event_manager.h
Outdated
((__ASSERT((uint8_t *)&(ev).header - (uint8_t *)&ev == 0, \ | ||
"header must be first element of event")), \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend creating a macro like
#define ZMK_ASSERT_IS_EVENT(ev) \
(__ASSERT((uint8_t *)&(ev).header - (uint8_t *)&ev == 0, \
"header must be first element of event"))
to simplify this. (Feel free to come up with a better name for this, as "is event" isn't strictly accurate since it only checks the header member, not the type.)
* Fix up some lingering events API tweaks for heap-less event manager.
da46109
to
dc0775c
Compare
Ok, this is a semi-major core refactor to address one of the major nits I had with the initial design for the event manager API I added to ZMK, mainly that it depending on dynamic memory allocation for alloc/free of the event structs. As a result, we need to use some large, arbitrary heap pool in ZMK to be sure we have enough allocated for whatever odd combination of events get raised/captured in the system.
This PR moves to stack allocated event structures, and change the expectation that anyone wanting to capture an even should copy it into a locally allocated storage for it's use as needed. See updates to hold-tap, combos, etc that demonstrate this kind of change.
This potentially disrupts any open behavior PRs, so need to consider the timing of the merge of this, but want to get this reviewed for the general approach now, since this I believe is ready, after I found and fixed the final bug in combos I'd introduced.