修复了程序在启动时偶尔崩溃的问题
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
//SERVERHOST = 192.168.0.223
|
||||
//SERVERPORT = 9000
|
||||
ProcessConfig = pPowerManger
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
log_level = INFO
|
||||
log_file = ./logfile.log
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "开始测试pPowerManger程序启动稳定性..."
|
||||
|
||||
LOOP_COUNT=0
|
||||
while true; do
|
||||
LOOP_COUNT=$((LOOP_COUNT + 1))
|
||||
echo "\n===== 第 $LOOP_COUNT 次循环 ====="
|
||||
|
||||
# 启动pPowerManger程序
|
||||
echo "启动pPowerManger..."
|
||||
./pPowerManger pPowerManger.moos &
|
||||
PROCESS_ID=$!
|
||||
|
||||
# 等待5秒让程序启动
|
||||
sleep 0.1
|
||||
|
||||
# 检查程序是否还在运行
|
||||
if kill -0 $PROCESS_ID 2>/dev/null; then
|
||||
echo "程序启动成功,PID: $PROCESS_ID"
|
||||
|
||||
# 等待2秒后关闭程序
|
||||
sleep 2
|
||||
echo "关闭程序..."
|
||||
kill $PROCESS_ID
|
||||
|
||||
# 等待1秒让程序彻底关闭
|
||||
sleep 0.1
|
||||
else
|
||||
echo "程序启动失败!"
|
||||
echo "故障发生在第 $LOOP_COUNT 次循环"
|
||||
exit 0.1
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 核心配置
|
||||
CRASH_LOG_DIR="./crash_logs"
|
||||
RUN_DURATION=2
|
||||
GDB_TIMEOUT=$((RUN_DURATION + 2)) # 延长超时,确保GDB完全初始化
|
||||
MAX_LOOP=0
|
||||
# 强制捕获所有致命信号
|
||||
CRASH_SIGNALS=("SIGSEGV" "SIGABRT" "SIGILL" "SIGFPE" "SIGBUS")
|
||||
|
||||
# 创建日志目录
|
||||
mkdir -p ${CRASH_LOG_DIR}
|
||||
rm -f ${CRASH_LOG_DIR}/* # 清空旧日志(可选)
|
||||
|
||||
# 清理进程函数
|
||||
cleanup() {
|
||||
pkill -9 gdb >/dev/null 2>&1
|
||||
pkill -9 pPowerManger >/dev/null 2>&1
|
||||
sleep 0.2
|
||||
}
|
||||
|
||||
# 检查是否是真崩溃(从日志+系统日志双重验证)
|
||||
is_real_crash() {
|
||||
local log_file=$1
|
||||
local loop=$2
|
||||
# 1. 检查GDB日志中的崩溃关键字
|
||||
if grep -qiE "segmentation fault|sigsegv|crash detected|backtrace" "${log_file}"; then
|
||||
return 0
|
||||
fi
|
||||
# 2. 检查系统dmesg中的段错误记录(终极验证)
|
||||
if dmesg | grep -i "pPowerManger.*segfault" | grep -i "loop_${loop}"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# 打印系统级崩溃日志(dmesg)
|
||||
print_system_crash_log() {
|
||||
local loop=$1
|
||||
echo -e "\033[33m===== 系统级崩溃日志(dmesg)=====\033[0m"
|
||||
dmesg | grep -A 5 -B 2 "pPowerManger.*segfault" | tail -10
|
||||
echo -e "\033[33m===================================\033[0m"
|
||||
}
|
||||
|
||||
echo -e "🔍 启动pPowerManger稳定性测试(强制捕获段错误)\n"
|
||||
echo "📂 崩溃日志目录: ${CRASH_LOG_DIR}"
|
||||
echo "⏱ 程序运行时长: ${RUN_DURATION}秒"
|
||||
echo "📌 捕获信号: ${CRASH_SIGNALS[*]}"
|
||||
echo -e "========================================\n"
|
||||
|
||||
cleanup # 初始清理
|
||||
LOOP_COUNT=0
|
||||
|
||||
while true; do
|
||||
LOOP_COUNT=$((LOOP_COUNT + 1))
|
||||
if [ ${MAX_LOOP} -ne 0 ] && [ ${LOOP_COUNT} -gt ${MAX_LOOP} ]; then
|
||||
echo -e "\n✅ 测试完成(${MAX_LOOP}次循环无崩溃)"
|
||||
cleanup
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo -e "===== 第 ${LOOP_COUNT} 次循环 ====="
|
||||
CRASH_LOG="${CRASH_LOG_DIR}/crash_loop_${LOOP_COUNT}.log"
|
||||
GDB_CMD="${CRASH_LOG_DIR}/gdb_cmds_${LOOP_COUNT}.gdb"
|
||||
|
||||
# 生成强化版GDB脚本:强制捕获所有信号,优先初始化信号处理
|
||||
cat > ${GDB_CMD} << EOF
|
||||
# 核心:GDB启动后先设置信号捕获,再启动程序
|
||||
set args pPowerManger.moos
|
||||
set timeout ${GDB_TIMEOUT}
|
||||
set print pretty on
|
||||
set print frame-arguments all
|
||||
set logging file ${CRASH_LOG}.gdb_raw
|
||||
set logging on # 开启GDB原始日志(双重保障)
|
||||
|
||||
# 强制捕获所有致命信号
|
||||
EOF
|
||||
|
||||
# 为每个崩溃信号添加捕获规则(追加到GDB脚本)
|
||||
for sig in "${CRASH_SIGNALS[@]}"; do
|
||||
cat >> ${GDB_CMD} << EOF
|
||||
handle ${sig} stop print pass nostop # 即使子线程崩溃也捕获
|
||||
EOF
|
||||
done
|
||||
|
||||
# 追加程序启动和崩溃处理逻辑
|
||||
cat >> ${GDB_CMD} << EOF
|
||||
# 延迟10ms启动程序,确保GDB完全初始化
|
||||
sleep 0.01
|
||||
run
|
||||
|
||||
# 崩溃后强制打印所有信息(无论是否主线程)
|
||||
if \$exitcode != 0 || \$signal_number != 0
|
||||
echo "\n====================================="
|
||||
echo " CRASH DETECTED"
|
||||
echo "====================================="
|
||||
echo "Loop: ${LOOP_COUNT}"
|
||||
echo "Exit code: \$exitcode"
|
||||
echo "Signal: \$signal_name (\$signal_number)"
|
||||
echo "====================================="
|
||||
thread apply all bt full # 打印所有线程的调用栈(关键!)
|
||||
info threads
|
||||
info proc mappings # 打印内存映射(排查内存越界)
|
||||
info locals
|
||||
info registers
|
||||
endif
|
||||
|
||||
set logging off
|
||||
quit
|
||||
EOF
|
||||
|
||||
# 核心:用nohup+GDB启动,避免输出丢失;同时记录进程ID
|
||||
echo "启动程序(GDB强化模式)..."
|
||||
nohup timeout ${GDB_TIMEOUT} gdb -batch -x ${GDB_CMD} ./pPowerManger > ${CRASH_LOG} 2>&1 &
|
||||
GDB_PID=$!
|
||||
wait ${GDB_PID} # 等待GDB执行完成
|
||||
|
||||
# 双重验证:检查是否真崩溃
|
||||
if is_real_crash ${CRASH_LOG} ${LOOP_COUNT}; then
|
||||
# 捕获到真崩溃
|
||||
echo -e "\033[31m❌ 第 ${LOOP_COUNT} 次循环捕获到段错误!\033[0m"
|
||||
echo -e "\033[31m📄 崩溃日志: ${CRASH_LOG}\033[0m"
|
||||
print_system_crash_log ${LOOP_COUNT}
|
||||
|
||||
# 打印最关键的调用栈(所有线程)
|
||||
echo -e "\033[31m===== 所有线程崩溃调用栈 =====\033[0m"
|
||||
grep -A 50 "thread apply all bt full" ${CRASH_LOG} | grep -v "No stack frame"
|
||||
echo -e "\033[31m==============================\033[0m"
|
||||
|
||||
cleanup
|
||||
echo -e "\n🛑 测试终止,完整日志在 ${CRASH_LOG}"
|
||||
exit 1
|
||||
else
|
||||
# 无崩溃(正常退出/启动失败)
|
||||
if grep -qi "Program exited normally" ${CRASH_LOG}; then
|
||||
echo "✅ 程序正常运行${RUN_DURATION}秒后退出"
|
||||
else
|
||||
echo "⚠️ 程序启动失败(非段错误),继续循环"
|
||||
# 保留启动失败日志(方便排查)
|
||||
mv ${CRASH_LOG} ${CRASH_LOG}.start_fail
|
||||
fi
|
||||
rm -f ${GDB_CMD} ${CRASH_LOG}.gdb_raw
|
||||
fi
|
||||
|
||||
cleanup
|
||||
echo -e "第 ${LOOP_COUNT} 次循环完成\n"
|
||||
sleep 0.5
|
||||
done
|
||||
Reference in New Issue
Block a user