其实就是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);
触发条件
- Shell 正在执行耗时较长的命令(持有 shell锁)
- 该命令让出 CPU(如
vTaskDelay() 或被高优先级任务抢占)
- 其他任务调用日志输出(如
logInfo()),持有 log锁并等待 shell锁
- Shell 任务恢复执行,需要打印日志,等待 log锁
- 死锁形成
相关代码
log.c: logWriteBuffer() - 持有 log锁调用 write
shell.c: shellWriteEndLine() - 需要 shell锁
shell.c: shellHandler() - 持有 shell锁,可能调用日志
环境信息
- letter-shell 版本: 3.2.3
- 使用场景: FreeRTOS + 多任务日志输出 + 尾行模式
其实就是shellTask打印数据和logWrite里对于两个互斥锁的使用顺序相反
我暂时的解决办法是按照shellWriteEndLine()重新写一个 log_write() 避免嵌套锁(推荐),直接操作输出,复制其功能但不获取 shell锁。
问题描述
在启用
SHELL_SUPPORT_END_LINE时,logWrite()与shellHandler()存在AB-BA 死锁风险。死锁场景分析
logWrite()获取 log锁shellHandler()获取 shell锁log->write()→shellWriteEndLine()logPrintln()shellWriteEndLine()等待 shell锁logWrite()等待 log锁代码路径
路径A (Log → Shell):
路径B (Shell → Log):
触发条件
vTaskDelay()或被高优先级任务抢占)logInfo()),持有 log锁并等待 shell锁相关代码
log.c: logWriteBuffer()- 持有 log锁调用 writeshell.c: shellWriteEndLine()- 需要 shell锁shell.c: shellHandler()- 持有 shell锁,可能调用日志环境信息