等待 NMI 中断,目前我这样做:
while true; do
RES=$(cat /proc/interrupts | grep NMI)
RES=$(echo "$RES" | sed 's/[^0-9]*//g')
RES=$(echo "$RES" | sed 's/^0*//')
if [ "$RES" != "" ]; then
echo "DONE"
exit 0
fi
sleep 1
done
有没有更好的方法可以不用轮询或休眠来做到这一点?
无需轮询的等待NMI中断可以使用事件驱动的方式来实现。您可以使用信号处理程序来捕获 NMI 信号并在收到信号时执行所需的操作,而不是不断地检查 /proc/interrupts 文件。 遗憾的是,您不能在用户空间脚本中直接捕获 NMI 中断,因为 NMI 中断是为内核级代码保留的。但是,您可以编写一个内核模块来处理 NMI 中断,并在发生 NMI 时将信号传递给您的用户空间脚本。
这是你可以做的.. 第一:写一个内核模块来处理NMI中断。然后当 NMI 发生时,让内核模块向您的用户空间脚本发送一个信号(例如,SIGUSR1)。最后在您的脚本中,设置一个信号处理程序来捕获内核模块发送的信号并执行所需的操作。并检查以下示例:
handle_signal() {
echo "NMI interrupt received"
echo "DONE"
exit 0
}
trap 'handle_signal' SIGUSR1
start_nmi_module
while true; do
sleep 1
done
回复评论:
hmm,如果您无法修改内核或向机器添加模块,那么是的,您当前的方法可能是最佳选择。但是,你可以做一些优化来减少轮询的负载:
使用 awk 的例子:
while true; do
RES=$(awk '/NMI/ {for (i=2; i<=NF; i++) if ($i ~ /^[0-9]+$/) {sum+=$i}} END {print sum}' /proc/interrupts)
if [ "$RES" != "" ] && [ "$RES" -ne "0" ]; then
echo "DONE"
exit 0
fi
sleep 5
done
此脚本使用 awk 读取
/proc/interrupts
文件并对所有 CPU 的 NMI 中断计数求和。如果总计数不为零,则脚本以“DONE”退出。睡眠间隔已增加到 5 秒,因为它会降低频率和系统负载。
回答第二个问题:
很遗憾,但是,如果没有内核修改或访问内核模块,您实时处理 NMI 中断的选项是有限的。 但是,您可以尝试通过更改睡眠间隔来在延迟和负载之间取得平衡。例如,使用较小的睡眠间隔,例如 0.1 或类似的东西,或者可能是 0.5 秒。这将减少延迟处理、中断,同时不会过度增加系统负载。
while true; do
RES=$(awk '/NMI/ {for (i=2; i<=NF; i++) if ($i ~ /^[0-9]+$/) {sum+=$i}} END {print sum}' /proc/interrupts)
if [ "$RES" != "" ] && [ "$RES" -ne "0" ]; then
echo "DONE"
exit 0
fi
sleep 0.1
done
请记住,这仍然是一个轮询,响应时间和负载之间始终存在权衡。仔细选择睡眠间隔,您可以找到适合您具体情况的平衡点。
愚蠢的解决方案:由于内核也会记录 NMI,因此通过
syslogd
将内核消息重定向到一个单独的文件(或 FIFO),然后在该文件中为 NMI 事件进行 grep:
如果没有输出,你的进程就会阻塞;只有当有一些输出时,grep 才会做一些事情。确保行在输出到文件或 FIFO 之前没有被缓冲。