Skip to content

尾行模式(End Line Mode)下日志输出存在死锁风险 #223

Description

@zyzyzyzzyy

其实就是shellTask打印数据和logWrite里对于两个互斥锁的使用顺序相反
我暂时的解决办法是按照shellWriteEndLine()重新写一个 log_write() 避免嵌套锁(推荐),直接操作输出,复制其功能但不获取 shell锁。

问题描述

在启用 SHELL_SUPPORT_END_LINE 时,logWrite()shellHandler() 存在AB-BA 死锁风险。

死锁场景分析

任务A (日志输出) 任务B (Shell处理)
1. logWrite() 获取 log锁 1. shellHandler() 获取 shell锁
2. 调用 log->write()shellWriteEndLine() 2. 执行命令过程中调用 logPrintln()
3. shellWriteEndLine() 等待 shell锁 3. logWrite() 等待 log锁
死锁! 死锁!

代码路径

路径A (Log → Shell):

// log.c: logWriteBuffer()
logLock(log);                    // ① 获取 log锁
    logList[i]->write(buffer, len);  // 调用 log_write()
        // shell_port.c: log_write()
        shellWriteEndLine(&app_shell, data, len);
            SHELL_LOCK(shell);       // ② 尝试获取 shell锁 → 阻塞等待
logUnlock(log);

路径B (Shell → Log):

// shell.c: shellHandler()
SHELL_LOCK(shell);               // ① 获取 shell锁
    // 处理按键或命令...
    logSwitchLevel() / 其他命令
        logPrintln("...");       // ② 尝试获取 log锁 → 阻塞等待
SHELL_UNLOCK(shell);

触发条件

  1. Shell 正在执行耗时较长的命令(持有 shell锁)
  2. 该命令让出 CPU(如 vTaskDelay() 或被高优先级任务抢占)
  3. 其他任务调用日志输出(如 logInfo()),持有 log锁并等待 shell锁
  4. Shell 任务恢复执行,需要打印日志,等待 log锁
  5. 死锁形成

相关代码

  • log.c: logWriteBuffer() - 持有 log锁调用 write
  • shell.c: shellWriteEndLine() - 需要 shell锁
  • shell.c: shellHandler() - 持有 shell锁,可能调用日志

环境信息

  • letter-shell 版本: 3.2.3
  • 使用场景: FreeRTOS + 多任务日志输出 + 尾行模式

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions