Skip to content

[Bug] [Smart][serial/tty] board 阶段注册 tty 时 workqueue 未建导致挂死,所有 Smart+board 阶段注册串口的架构均受影响 #11718

Description

@loongson-gz

RT-Thread Version

master

Affected area

RT-Smart

Hardware/BSP vendor

Loongson

Architecture

Not applicable / Other

Board and hardware details

LS2K0300

Develop Toolchain

GCC

Describe the bug

问题现象

LoongArch/LS2K300 启用 RT-Thread Smart 模式后,启动过程在 tty 注册期间挂死——没有任何输出,CPU 卡死。

机理:时序倒挂

问题出在 RT-Thread 的初始化阶段分级与 tty 注册时机的错位。完整链条:

// dev_serial.c —— 公共代码,任何开 Smart 的架构都走这里
rt_err_t rt_hw_serial_register(...)
{
    ...
#if defined(RT_USING_SMART)
    rt_hw_serial_register_tty(serial);   // ← 注册 tty,依赖 workqueue
#endif
    return ret;
}
步骤 阶段 说明
rt_hw_uart_init()rt_hw_serial_register()rt_hw_serial_register_tty() board 阶段rt_hw_board_init 内) LS2K300 在 main.crt_hw_board_init 里注册
_tty_workqueue_init(创建 _ttyworkq INIT_PREV_EXPORT rt_components_board_init() 触发,晚于 uart 注册
_tty_pending_flush(修复新增) INIT_COMPONENT_EXPORT 保证在 workqueue 建好之后 flush

LS2K300 的 rt_hw_board_init() 里 uart 注册在 rt_components_board_init() 之前

// bsp/loongarch/ls2k300_dev/applications/main.c
void rt_hw_board_init(void)
{
    ...
    rt_hw_uart_init();              // ← board 阶段注册串口 → 调 tty 注册
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
    ...
    rt_components_board_init();     // ← 之后才跑 INIT_PREV(建 workqueue)
}

lwp_tty_create() 内部调用 cv_init() / rt_wqueue_init() / rt_mutex_init()需要调度器/定时器/workqueue 就绪。board 阶段直接调用时 _ttyworkq 还是 NULL → 挂死。

修复方案

在公共 serial_tty.c 里加延迟注册机制:

rt_err_t rt_hw_serial_register_tty(struct rt_serial_device *serial)
{
    /* workqueue 未建时挂 pending 链表,延后到 COMPONENT 阶段再注册 */
    if (_ttyworkq == RT_NULL)
    {
        rt_hw_serial_register_tty_defer(serial);
        return RT_EOK;
    }
    ...
}

static int _tty_pending_flush(void)
{
    /* COMPONENT 阶段 workqueue 已就绪,flush pending 链表 */
    while ((node = rt_slist_first(&_tty_pending)))
    {
        ...
        rt_hw_serial_register_tty(pn->serial);
        ...
    }
    return RT_EOK;
}
INIT_COMPONENT_EXPORT(_tty_pending_flush);

关键设计:

  1. _ttyworkq == RT_NULL 守卫:只对"workqueue 未建时注册"的架构走延迟路径;晚注册的架构 _ttyworkq != NULL,直接走原路径,行为完全不变——对其他架构 no-op
  2. pending 链表 + INIT_COMPONENT_EXPORT flush:COMPONENT 阶段保证在 PREV 阶段(workqueue 创建)之后执行,时序正确。
  3. 补丁改的是公共层 serial_tty.c,不是 LoongArch 私有代码——所有开 Smart 的架构一旦暴露此问题,直接受益。

跨架构影响:这是公共缺陷,不是 LoongArch 独有

逐一核对各架构后的结论:

1. 非 Smart BSP(raspi4-64、qemu-vexpress-a9 等)—— 真不需要

它们的 .configRT_USING_SMART 未开,#if defined(RT_USING_SMART) 那段根本不编译,从不调用 rt_hw_serial_register_tty,自然没有 workqueue 依赖。这是"不需要"的唯一正确情形。

2. 开了 Smart 的 BSP(k230 等)—— 同样会踩,只是没暴露

k230 的配置和时序与 LS2K300 完全相同:

// bsp/k230/.config:122
CONFIG_RT_USING_SMART=y
// bsp/k230/board/board.c:113
rt_hw_uart_init();            // board 阶段
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();  // 之后才建 workqueue
#endif

k230 完全相同的时序:board 阶段注册串口 → 开 Smart → 调 rt_hw_serial_register_tty → workqueue 未建。如果它真正走通 tty 注册路径(lwp_tty_create 真执行),会踩一模一样的挂死。d1、d1s、bl808、cv18xx 同理——它们没爆是因为还没走到那条路径,不是不需要

3. 补丁修的是公共缺陷,对所有 Smart 架构生效

复现环境

  • BSP: bsp/loongarch/ls2k300_dev
  • 配置: CONFIG_RT_USING_SMART=y
  • 现象: 启动过程在 tty 注册期间挂死,无任何输出

参考

  • 修复 commit: 908b3702d serial/tty: 延迟 tty 注册,避免 board 阶段 workqueue 未就绪
  • 关键代码位置:
    • components/drivers/serial/dev_serial.c:1408#if RT_USING_SMARTrt_hw_serial_register_tty
    • components/drivers/serial/serial_tty.c_tty_workqueue_init = INIT_PREV_EXPORT;_tty_pending_flush = INIT_COMPONENT_EXPORT)
    • bsp/k230/board/board.c:113(k230 相同时序,潜在踩坑)

Other additional context

No response

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    BSPBSP: LoongsonBSP related with LoongsonRT-SmartRT-Thread Smart related PR or issuesbugThis PR/issue is a bug in the current code.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions