Skip to content

fix[utest]: reset finish flags in the mailbox testcase so it can run twice - #11963

Open
sexenteen wants to merge 2 commits into
RT-Thread:masterfrom
sexenteen:fix/issue-6565-mailbox-utest-rerun
Open

sexenteen wants to merge 2 commits into
RT-Thread:masterfrom
sexenteen:fix/issue-6565-mailbox-utest-rerun

Conversation

@sexenteen

@sexenteen sexenteen commented Nov 1, 2026 •

Copy link
Copy Markdown

拉取/合并请求描述:(PR description)

[

为什么提交这份PR (why to submit this PR)

Fixes #6565 (the remaining half - see the note at the end).

core.ipc_mailbox fails when it is run a second time in the same boot. Reproduced on
bsp/qemu-vexpress-a9 with RT_USING_UTESTCASES=y and RT_UTEST_MAILBOX=y:

msh />utest_run core.ipc_mailbox      -> [  PASSED  ] testcase (core.ipc_mailbox)
msh />utest_run core.ipc_mailbox      -> [  ASSERT  ] at (mailbox_tc.c); func:
                                         (thread1_recv_static_mb:242); msg: ((1) is true)
                                         (rt_object_get_type(&mb->parent.parent) ==
                                          RT_Object_Class_MailBox) assertion failed
                                          at function:_rt_mb_recv, line number:2884

Cause: the four *_thread_finish flags are only ever set to 1 by the worker threads, never
cleared. On the second run the test body's wait loop

while (static_mb_recv_thread_finish != 1 || static_mb_send_thread_finish != 1)

falls through immediately, so rt_mb_detach() is called while the worker threads started by
this run are still blocked in rt_mb_recv(). They are then resumed with an error and keep
using a mailbox that has already been detached, which trips the object-type assertion in
_rt_mb_recv(). The dynamic variant has the same pattern and would fail the same way.

你的解决方案是什么 (what is your solution)

Clear the flags in utest_tc_init(), which the utest framework calls before each run of the
testcase:

static rt_err_t utest_tc_init(void)
{
    static_mb_recv_thread_finish = 0;
    static_mb_send_thread_finish = 0;
    dynamic_mb_recv_thread_finish = 0;
    dynamic_mb_send_thread_finish = 0;

    return RT_EOK;
}

Only src/utest/mailbox_tc.c is touched (+11/-0). This matches what has already been said in
#6565: part of the testcases were written without considering that they can be executed twice,
leaving variables/resources not reset or released.

请提供验证的bsp和config (provide the config and bsp)

Verification (utest_run core.ipc_mailbox executed three times in one session, after the fix):

run 1 -> [  PASSED  ] testcase (core.ipc_mailbox)
run 2 -> [  PASSED  ] testcase (core.ipc_mailbox)
run 3 -> [  PASSED  ] testcase (core.ipc_mailbox)

The same build without the fix fails on run 2 as shown above. scons -j4 passes and
tools/ci/clang_format_check.py reports "clang-format check success" for the changed file.

Not covered: other BSPs / real hardware (only qemu-vexpress-a9 was tested), and running the
whole utest suite (utest_run without arguments) - only the mailbox testcase was exercised.

Note on the rest of #6565: the other reported problem, thread_tc.c's test_thread_suspend
suspending another thread (which hits RT_ASSERT(thread == rt_thread_self())), was already
confirmed by the maintainers as a testcase problem and that test is already disabled, so it is
not touched here.
]

当前拉取/合并请求的状态 Intent for your PR

必须选择一项 Choose one (Mandatory):

  • 本拉取/合并请求是一个草稿版本 This PR is for a code-review and is intended to get feedback
  • 本拉取/合并请求是一个成熟版本 This PR is mature, and ready to be integrated into the repo

代码质量 Code Quality:

我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:

  • 已经仔细查看过代码改动的对比 Already check the difference between PR and old code
  • 代码风格正确,包括缩进空格,命名及其他风格 Style guide is adhered to, including spacing, naming and other styles
  • 没有垃圾代码,代码尽量精简,不包含#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up
  • 所有变更均有原因及合理的,并且不会影响到其他软件组件代码或BSP All modifications are justified and not affect other components or BSP
  • 对难懂代码均提供对应的注释 I've commented appropriately where code is tricky
  • 代码是高质量的 Code in this PR is of high quality
  • 已经使用clang-format 源码格式化工具确保格式符合RT-Thread代码规范 This PR has been formatted with clang-format and complies with RT-Thread code specification
  • 如果是新增bsp, 已经添加ci检查到.github/ALL_BSP_COMPILE.json 详细请参考链接BSP自查

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread!

为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。
To ensure your code complies with RT-Thread's coding style, please run the code formatting workflow by following the steps below (If the formatting of CI fails to run).


🛠 操作步骤 | Steps

  1. 前往 Actions 页面 | Go to the Actions page
    点击进入工作流 → | Click to open workflow →

  2. 点击 Run workflow | Click Run workflow

  • Use workflow from 保持默认分支(通常为 master)
    Keep the default branch (usually master) in Use workflow from
  • 在 branch 输入框填写 PR 分支 fix/issue-6565-mailbox-utest-rerun
    Enter PR branch fix/issue-6565-mailbox-utest-rerun in the branch field
  • 设置需排除的文件/目录(目录请以"/"结尾)
    Set files/directories to exclude (directories should end with "/")
  1. 等待工作流完成 | Wait for the workflow to complete
    格式化后的代码将作为独立提交推送至你的分支。
    The formatting changes will be pushed to your branch as a separate commit.

完成后,提交将自动更新至 fix/issue-6565-mailbox-utest-rerun 分支,关联的 Pull Request 也会同步更新。
Once completed, commits will be pushed to the fix/issue-6565-mailbox-utest-rerun branch automatically, and the related Pull Request will be updated.

如有问题欢迎联系我们,再次感谢您的贡献!💐
If you have any questions, feel free to reach out. Thanks again for your contribution!

@github-actions github-actions Bot added the Kernel PR has src relate code label Nov 1, 2026
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

📌 Code Review Assignment

🏷️ Tag: kernel

Reviewers: @GorrayLi @ReviewSun @hamburger-os @lianux-mm @wdfk-prog @xu18838022837

Changed Files (Click to expand)
  • src/utest/mailbox_tc.c

📊 Current Review Status (Last Updated: 2026-11-02 15:53 CST)


📝 Review Instructions

  1. 维护者可以通过单击此处来刷新审查状态: 🔄 刷新状态
    Maintainers can refresh the review status by clicking here: 🔄 Refresh Status

  2. 确认审核通过后评论 LGTM/lgtm
    Comment LGTM/lgtm after confirming approval

  3. PR合并前需至少一位维护者确认
    PR must be confirmed by at least one maintainer before merging

ℹ️ 刷新CI状态操作需要具备仓库写入权限。
ℹ️ Refresh CI status operation requires repository Write permission.

@Yunlk

Yunlk commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

独立复现了一遍,现象和根因都对得上。补一组"第一次 / 第二次"的干净对照数据。

环境

bsp/qemu-vexpress-a9,QEMU 11.0.0,arm-none-eabi-gcc 15.2.1,master 1c801efa。
配置:CONFIG_RT_USING_UTESTCASES=y + CONFIG_RT_UTEST_MAILBOX=y,CONFIG_RT_UTEST_USING_AUTO_RUN 必须关掉(见最后一段)。

复现方式

msh 里分两次执行 utest_run core.ipc_mailbox。我这里没有可脚本化的串口输入,改用等价方式:一个临时 app 在开机后直接调用两次 utest_testcase_run(2, argv),中间隔 1 秒。

结果

第一次:

[I/utest] [----------] [ testcase ] (core.ipc_mailbox) started
[I/utest] [  PASSED  ] [ result   ] testcase (core.ipc_mailbox)
[I/utest] [----------] [ testcase ] (core.ipc_mailbox) finished
[I/utest] [  PASSED  ] [ result   ] 1 tests.

第二次:

[I/utest] [----------] [ testcase ] (core.ipc_mailbox) started
[E/utest] [  ASSERT  ] [ unit     ] at (mailbox_tc.c); func: (thread1_recv_static_mb:242); msg: ((1) is true)
(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox) assertion failed at function:_rt_mb_recv, line number:2884

断言原文是 uassert_false(1),落在 thread1_recv_static_mb() 第 242 行——即第二个 rt_mb_recv(&test_static_mb, ...) 返回了非 RT_EOK 或数据对不上。紧随其后的 _rt_mb_recv 对象类型断言是同一个问题的二次表现:此时 test_static_mb 已经被 rt_mb_detach() 掉了,而工作线程还在里面等。

根因确认:是四个标志没清

/* mailbox_tc.c:60-61 */
static uint8_t static_mb_recv_thread_finish, static_mb_send_thread_finish;
static uint8_t dynamic_mb_recv_thread_finish, dynamic_mb_send_thread_finish;

它们只在工作线程里置 1(:226、:251、:319、:344),没有任何地方清零;utest_tc_init() 原本直接 return RT_EOK。

第二次运行时,while (static_mb_recv_thread_finish != 1 || static_mb_send_thread_finish != 1)(:282)这个等待循环条件一开始就成立,于是测试体不等工作线程结束就继续往下走,接着 test_mailbox_deatch() 把 mailbox detach 掉,而工作线程还阻塞在 rt_mb_recv() 里——于是第 242 行拿到错误返回,随后撞上对象类型断言。

与 #11963 里 utest_tc_init() 清零四个标志的改法一致,我这边观察到的顺序也能对上。

一个可能影响别人复现的坑

CONFIG_RT_USING_CI_ACTION=y 会 select RT_UTEST_USING_AUTO_RUN(src/Kconfig:252-255),开机就自动把所有用例跑一遍。如果不关掉这个,你手动执行的"第一次"实际上是第二次,直接就会看到失败,容易误以为"第一次就挂"。

我第一次就是这么踩的:自动运行先跑了一次 PASSED,然后我的第一次手动运行就 FAILED 了。要拿到干净对照,需要同时确认 CONFIG_RT_UTEST_USING_AUTO_RUN 处于关闭状态——它是个独立选项,光取消 CI_ACTION 不一定够(要看配置是否被显式 select 过)。

复现用的临时 app 没有提交,需要的话我可以整理成 utest_run 之外的自动化形式。

@sexenteen

Copy link
Copy Markdown
Author

感谢独立复现,根因和改法能对上就很难得 👍

关于 RT_UTEST_USING_AUTO_RUN 的坑:我这边复现时没有开 RT_USING_CI_ACTION,只打开了
CONFIG_RT_USING_UTESTCASES + CONFIG_RT_UTEST_MAILBOX(RT_UTEST_USING_AUTO_RUN 保持关闭),
所以"第一次 PASSED、第二次 FAILED"是在干净状态下拿到的;修复后同一会话连跑三次都是 PASSED。

你的提醒很有价值 —— 我把它当成"复现前提"记下来了:如果 CI_ACTION/自动运行开着,开机那次会消耗掉"第一次"
(src/Kconfig:252-255 的 select RT_UTEST_USING_AUTO_RUN),后面手动跑的第一次其实已经是第二次,会直接看到失败。

另外:我已经把这个分支合到最新 master(现在是 08cad4ee,版本号 5.4.0),合并后重新验证过 ——
utest_run core.ipc_mailbox 连跑两次均 [ PASSED ]。你用的 1c801efa 上也应该同样成立。

你那个"临时 app 调用 utest_testcase_run() 两次"的做法对自动化很有价值,如果愿意整理成
utest_run 之外的自动化形式(比如 CI 里跑两次的回归),我认为可以单独提一个 PR。

This branch has not been deployed

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

Labels

Kernel PR has src relate code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

几处未知原因的rtthread utest问题

2 participants