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

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