Skip to content

Conversation

@rodrigopex
Copy link
Contributor

@rodrigopex rodrigopex commented Oct 23, 2025

There is no easy way to offload the listener execution to a separate thread. So, when the pub function is called from an ISR, the publication process can take a long time to execute, increasing interrupt latency. Based on that, a new kind of listener emerged.

Introducing the Async Listeners. They look like (setup as one) a regular listener, but they are executed within a work queue context (system work queue by default), offering distinct advantages:

  • Asynchrony: it gains the ability to run some urgent/heavy workload in a separate context.
  • Prioritization: typically executed before other application observers, as they run within the system work queue context, which is cooperative.
  • Reliability: Ensures no message loss during execution. They use the exact mechanism as Message Subscribers.

Tests coverage

zbus.c file tests coverage with the command west twister --coverage -p qemu_x86 -T tests/subsys/zbus/ -T samples/subsys/zbus.

image

Related issues

Fixes #88499

@rodrigopex rodrigopex force-pushed the zbus_async_listener branch 7 times, most recently from 91882cf to 03737fe Compare October 24, 2025 12:27
@rodrigopex rodrigopex self-assigned this Oct 24, 2025
@rodrigopex rodrigopex force-pushed the zbus_async_listener branch 2 times, most recently from d37fc4f to 524c97a Compare October 24, 2025 14:16
@rodrigopex rodrigopex added Enhancement Changes/Updates/Additions to existing features area: Zbus labels Oct 24, 2025
@rodrigopex rodrigopex moved this to In Progress in ZBus 2030 Oct 24, 2025
@rodrigopex rodrigopex force-pushed the zbus_async_listener branch 2 times, most recently from 8a3cf7d to d898a30 Compare October 24, 2025 18:20
@rodrigopex rodrigopex marked this pull request as ready for review October 24, 2025 20:35
@zephyrbot zephyrbot added area: Samples Samples area: Tests Issues related to a particular existing or missing test labels Oct 24, 2025
Copy link
Contributor

@wkhadgar wkhadgar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Game changing feature here! Looking forward to having this on the upstream. Just some questions and suggestions to make this even nicer 🚀

@rodrigopex rodrigopex force-pushed the zbus_async_listener branch 2 times, most recently from 1e7f0ec to f825fe0 Compare November 3, 2025 12:24
@rodrigopex rodrigopex requested a review from wkhadgar November 3, 2025 12:24
nandojve
nandojve previously approved these changes Nov 3, 2025
Copy link
Member

@nandojve nandojve left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

Copy link
Contributor

@wkhadgar wkhadgar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! Just one small suggestion to the Kconfig option description, considering that async listeners are not enabled by default

Add a new type of observer: Async Listeners. They are executed within the
system work queue context, offering distinct advantages:

- Asychrouness: obviously it gains the ability of run some urgent/light
  work load in a separate context.
- Prioritization: Async Listeners typically execute before other
  application observers, as they run within the system work queue context
  which is cooperative.
- Reliability: Ensures no message loss during execution. They use the same
  mechanism as Message Subscribers.

Signed-off-by: Rodrigo Peixoto <rodrigopex@gmail.com>
Add test for async listeners.

Signed-off-by: Rodrigo Peixoto <rodrigopex@gmail.com>
The tests are failing in architectures that support SMP. Filtering them to
make CI happy, as done in zephyrproject-rtos#97827. Issue zephyrproject-rtos#98217 was created to address that
separately for all tests.

Signed-off-by: Rodrigo Peixoto <rodrigopex@gmail.com>
Add a sample for async listeners.

Signed-off-by: Rodrigo Peixoto <rodrigopex@gmail.com>
Add the async linstener to the hello_world sample.

Signed-off-by: Rodrigo Peixoto <rodrigopex@gmail.com>
Add documentation for async listeners.

Signed-off-by: Rodrigo Peixoto <rodrigopex@gmail.com>
@sonarqubecloud
Copy link

@nashif nashif merged commit 9463d9a into zephyrproject-rtos:main Nov 21, 2025
26 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in ZBus 2030 Nov 21, 2025
@aescolar
Copy link
Member

@rodrigopex
Copy link
Contributor Author

Note failures in main https://github.com/zephyrproject-rtos/zephyr/actions/runs/19577249151/job/56065786557#step:12:854

@aescolar, that should not be happening. The SMP is being filtered from the zbus async listeners tests.

tests:
  message_bus.zbus.async_listeners:
    tags: zbus
    filter: not CONFIG_SMP   <-- here
    integration_platforms:
      - qemu_x86
    platform_exclude:
      - qemu_leon3
    harness: console
    harness_config:
      type: one_line
      regex:
        - "^.*?E: could not deliver notification to observer . Error code -12"

  message_bus.zbus.async_listeners_alloc_static:
    tags: zbus
    filter: not CONFIG_SMP   <-- here
    integration_platforms:
      - qemu_x86
    platform_exclude:
      - qemu_leon3
    extra_configs:
      - CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC=y
      - CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC_DATA_SIZE=16
    harness: console
    harness_config:
      type: one_line
      regex:
        - "^.*?E: could not deliver notification to observer . Error code -12"

  message_bus.zbus.async_listeners.smp:
    tags: zbus
    filter: not CONFIG_SMP   <-- here
    integration_platforms:
      - qemu_x86
    platform_exclude:
      - qemu_leon3

  message_bus.zbus.async_listeners_alloc_static.smp:
    tags: zbus
    filter: not CONFIG_SMP   <-- here
    integration_platforms:
      - qemu_x86
    platform_exclude:
      - qemu_leon3
    extra_configs:
      - CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC=y
      - CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC_DATA_SIZE=16

@aescolar
Copy link
Member

@rodrigopex
These four tests are failing in main right now.
INFO - 1) message_bus.zbus.async_listeners on native_sim/native failed (rc=1)
INFO - 2) message_bus.zbus.async_listeners.smp on native_sim/native failed (rc=1)
INFO - 3) message_bus.zbus.async_listeners_alloc_static on native_sim/native failed (rc=1)
INFO - 4) message_bus.zbus.async_listeners_alloc_static.smp on native_sim/native failed (rc=1)
https://github.com/zephyrproject-rtos/zephyr/actions/runs/19594389377/job/56117056621#step:12:970
You can reproduce for ex. like

mkdir build && cd build
ZEPHYR_TOOLCHAIN_VARIANT=llvm cmake -GNinja -DBOARD=native_sim ../tests/subsys/zbus/async_listeners/
ninja
zephyr/zephyr.exe
*** Booting Zephyr OS build v4.3.0-929-g1d6e0d533a81 ***
Running TESTSUITE async_listener
===================================================================
START - test_01_specification
E: could not deliver notification to observer . Error code -12

    Assertion failed at CMAKE_SOURCE_DIR/src/main.c:114: async_listener_test_01_specification: k_msgq_num_used_get(&msgq_pong) not equal to pong_count

 FAIL - test_01_specification in 0.520 seconds

@aescolar
Copy link
Member

aescolar commented Nov 22, 2025

@rodrigopex disabling agressive optimizations makes the test pass. Running it with UBSAN, this is pointed out:

*** Booting Zephyr OS build v4.3.0-929-g1d6e0d533a81 ***
Running TESTSUITE async_listener
===================================================================
START - test_01_specification
E: could not deliver notification to observer . Error code -12
tests/subsys/zbus/async_listeners/src/main.c:37:11: runtime error: load of value 63, which is not a valid value for type 'bool'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior tests/subsys/zbus/async_listeners/src/main.c:37:11 
 PASS - test_01_specification in 0.520 seconds
===================================================================

Which may indicate the message pointer is incorrect or its content is corrupted.

@rodrigopex
Copy link
Contributor Author

@aescolar

I am in a Mac environment, and I cannot reproduce that.

Is it better to filter native_sim or remove the aggressive optimizations for the tests?

@aescolar
Copy link
Member

Is this the bug?

diff --git a/tests/subsys/zbus/async_listeners/src/main.c b/tests/subsys/zbus/async_listeners/src/main.c
index fe284e41e96..ab196e3f8da 100644
--- a/tests/subsys/zbus/async_listeners/src/main.c
+++ b/tests/subsys/zbus/async_listeners/src/main.c
@@ -58,7 +58,7 @@ static void isr_burst_handler(const void *message)
        const struct msg_ping *msg = message;
 
        for (int i = 0; i < CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE; ++i) {
-               int err = zbus_chan_pub(&chan_ping, &msg, K_NO_WAIT);
+               int err = zbus_chan_pub(&chan_ping, msg, K_NO_WAIT);
 
                if (err) {
                        break;

@rodrigopex
Copy link
Contributor Author

Is this the bug?

diff --git a/tests/subsys/zbus/async_listeners/src/main.c b/tests/subsys/zbus/async_listeners/src/main.c
index fe284e41e96..ab196e3f8da 100644
--- a/tests/subsys/zbus/async_listeners/src/main.c
+++ b/tests/subsys/zbus/async_listeners/src/main.c
@@ -58,7 +58,7 @@ static void isr_burst_handler(const void *message)
        const struct msg_ping *msg = message;
 
        for (int i = 0; i < CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE; ++i) {
-               int err = zbus_chan_pub(&chan_ping, &msg, K_NO_WAIT);
+               int err = zbus_chan_pub(&chan_ping, msg, K_NO_WAIT);
 
                if (err) {
                        break;

Indeed! I will send a PR. I am wondering why the tests are passing for all the other architectures. That should be a huge coincidence.

Thanks a lot.

@aescolar
Copy link
Member

aescolar commented Nov 22, 2025

Is this the bug?

Indeed! I will send a PR. I am wondering why the tests are passing for all the other architectures. That should be a huge coincidence.

Thanks a lot.

I just did, hope you don't mind :)

@rodrigopex
Copy link
Contributor Author

I just did, hope you don't mind :)

Approved! I do not mind at all. I'm glad you found the issue. Thanks.

@rodrigopex rodrigopex deleted the zbus_async_listener branch November 22, 2025 14:14
@aescolar
Copy link
Member

By the way, note that the test message_bus.zbus.async_listeners.smp is building and running just the same as message_bus.zbus.async_listeners.smp .
Same for message_bus.zbus.async_listeners_alloc_static.smp and message_bus.zbus.async_listeners_alloc_static
So it seems a bit wasteful to build and run these twice.

@djiatsaf-st
Copy link
Contributor

Hello @rodrigopex
I noticed very unstable behavior on this test varying from one board (STM32) to another when running tests with twister, and I am not quite sure how to fix it.
The messages in the console arrive truncated, which prevents the tests from being valid because the regular expression does not match.
We have the following reason:
"reason":"patterns did not match (ordered)"

"name":"tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners",
            "arch":"arm",
            "platform":"nucleo_f207zg/stm32f207xx",
            "path":"tests/subsys/zbus/async_listeners",
            "run_id":"475bcb7d0a37f9b6f159871de5205cb4",
            "runnable":true,
            "retries":0,
            "toolchain":"zephyr",
            "dut":"0669FF545552867067035337",
            "status":"failed",
            "log":"onds\r\n===================================================================\r\nSTART - test_02_isolated_wqueue\r\n PASS - test_02_isolated_wqueue in 0.001 seconds\r\n===================================================================\r\nTESTSUITE async_listener succeeded\r\n\r\n------ TESTSUITE SUMMARY START ------\r\n\r\nSUITE PASS - 100.00% [async_listener]: pass = 2, fail = 0, skip = 0, total = 2 duration = 0.508 seconds\r\n - PASS - [async_listener.test_01_specification] duration = 0.507 seconds\r\n - PASS - [async_listener.test_02_isolated_wqueue] duration = 0.001 seconds\r\n\r\n------ TESTSUITE SUMMARY END ------\r\n\r\n===================================================================\r\nRunID: 66ec205a092f3ff87cc45c2318ea137b\r\nPROJECT EXECUTION SUCCESSFUL\r\n",
            "reason":"patterns did not match (ordered)",
            "execution_time":"2.69",
            "build_time":"25.17",
            "testcases":[
                {
                    "identifier":"message_bus.zbus.async_listeners",
                    "execution_time":"2.69",
                    "status":"failed"
                }
            ]

when running tests with twister,

./scripts/twister --device-testing --device-serial /dev/ttyACM0 -p nucleo_g071rb -T tests/subsys/zbus/async_listeners

We can also observe this result:  
INFO    - JOBS: 8
INFO    - Adding tasks to the queue...
INFO    - Added initial list of jobs to queue
ERROR   - HARNESS:Console: failed with 0 of 1 expected ordered patterns.
ERROR   - nucleo_g071rb/stm32g071xx message_bus.zbus.async_listeners_alloc_static      FAILED: patterns did not match (ordered)
ERROR   - see: /zephyrproject/zephyr/twister-out/nucleo_g071rb_stm32g071xx/zephyr/tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners_alloc_static/handler.log
ERROR   - HARNESS:Console: failed with 0 of 1 expected unordered patterns.    0, failed:    1, error:    0
ERROR   - nucleo_g071rb/stm32g071xx message_bus.zbus.async_listeners                   FAILED: patterns did not match (unordered)
ERROR   - see: /zephyrproject/zephyr/twister-out/nucleo_g071rb_stm32g071xx/zephyr/tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners/handler.log
WARNING - TS_END: END suite 'async_listener' without START detectedltered:    0, failed:    2, error:    0
WARNING - TS_SUM: END suite 'async_listener' without START detected
ERROR   - nucleo_g071rb/stm32g071xx message_bus.zbus.async_listeners_alloc_static.smp  FAILED: RunID mismatch
ERROR   - see: /zephyrproject/zephyr/twister-out/nucleo_g071rb_stm32g071xx/zephyr/tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners_alloc_static.smp/handler.log
WARNING - TS_END: END suite 'async_listener' without START detectedltered:    0, failed:    3, error:    0
WARNING - TS_SUM: END suite 'async_listener' without START detected
ERROR   - nucleo_g071rb/stm32g071xx message_bus.zbus.async_listeners.smp               FAILED: RunID mismatch
ERROR   - see: /zephyrproject/zephyr/twister-out/nucleo_g071rb_stm32g071xx/zephyr/tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners.smp/handler.log
INFO    - Total complete:    4/   4  100%  built (not run):    0, filtered:    0, failed:    4, error:    0
...
Hardware distribution summary:

| Board                     | ID   |   Counter |   Failures |
|---------------------------|------|-----------|------------|
| nucleo_g071rb/stm32g071xx |      |         4 |          4 |

  • tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners_alloc_static/handler.log
est_01_specification in 0.507 seconds
===================================================================
START - test_02_isolated_wqueue
 PASS - test_02_isolated_wqueue in 0.002 seconds
===================================================================
TESTSUITE async_listener succeeded

------ TESTSUITE SUMMARY START ------

SUITE PASS - 100.00% [async_listener]: pass = 2, fail = 0, skip = 0, total = 2 duration = 0.509 seconds
 - PASS - [async_listener.test_01_specification] duration = 0.507 seconds
 - PASS - [async_listener.test_02_isolated_wqueue] duration = 0.002 seconds

------ TESTSUITE SUMMARY END ------

===================================================================
RunID: d73cf4affc8d653a621875766f024673
PROJECT EXECUTION SUCCESSFUL
  • tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners/handler.log

E: could not deliver notification to observer . Error code -12

  • tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners_alloc_static.smp/handler.log
===========
START - test_02_isolated_wqueue
 PASS - test_02_isolated_wqueue in 0.002 seconds
===================================================================
TESTSUITE async_listener succeeded

------ TESTSUITE SUMMARY START ------

SUITE PASS - 100.00% [async_listener]: pass = 2, fail = 0, skip = 0, total = 2 duration = 0.509 seconds
 - PASS - [async_listener.test_01_specification] duration = 0.507 seconds
 - PASS - [async_listener.test_02_isolated_wqueue] duration = 0.002 seconds

------ TESTSUITE SUMMARY END ------

===================================================================
RunID: 0fc7ed5debd493659b4996b403d92c37
PROJECT EXECUTION SUCCESSFUL
  • tests/subsys/zbus/async_listeners/message_bus.zbus.async_listeners.smp/handler.log
t_02_isolated_wqueue in 0.002 seconds
===================================================================
TESTSUITE async_listener succeeded

------ TESTSUITE SUMMARY START ------

SUITE PASS - 100.00% [async_listener]: pass = 2, fail = 0, skip = 0, total = 2 duration = 0.509 seconds
 - PASS - [async_listener.test_01_specification] duration = 0.507 seconds
 - PASS - [async_listener.test_02_isolated_wqueue] duration = 0.002 seconds

------ TESTSUITE SUMMARY END ------

===================================================================
RunID: 26d16ddb3f04b921e100a02db9b18b23
PROJECT EXECUTION SUCCESSFUL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: Samples Samples area: Tests Issues related to a particular existing or missing test area: Zbus Enhancement Changes/Updates/Additions to existing features

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

ZBus Async Listeners

8 participants