随手记——静态Flag变量使用不规范导致的重大流程错误
Posted 穿越临界点
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随手记——静态Flag变量使用不规范导致的重大流程错误相关的知识,希望对你有一定的参考价值。
在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习。我的使命就是过滤掉大量的无效信息,将知识体系化,以短平快的方式直达问题本质,把大家从大海捞针的痛苦中解脱出来。
1 问题引入
1.1 问题表象
问题出在使用PCIe设备的应用层,而且该问题是一个很偶现的问题。该问题出现时的表象是业务模块获取到的PCIe Bar空间基地址为NULL,并产生了任务异常(额,居然没判空就用了)。
1.2 问题背景
为了能够将该问题表述清楚,需要交代一下问题出现时的场景。
如下图所示,硬件上分为两个处理器,一个主处理器,一个从处理器。主处理器上p0进程为主进程,控制着主要的时序逻辑;主处理器p1进程负责主处理器上连接的PCIe设备的用户态服务。从处理器p0进程负责从处理器上连接的PCIe设备的用户态服务;从处理器p1进程负责业务逻辑,并且依赖PCIe的服务。
任务异常就出现在从处理器的p1进程上。
2 问题分析和定位
查看业务层代码发现从处理器p1进程出现任务异常的原因:是主处理器p0进程通过一系列流程(简化之后就是上图的Msg3消息)告诉了从处理器p1进程所有PCIe任务已经初始化完成,可以进行下一步操作。因此,从处理器p1就进行了下一步操作,这步操作就是向从处理器p0进程获取PCIe设备的BAR空间基址。但是,问题出现了,获取到的基址为NULL,并且直接引用了这个地址导致任务异常。
那第一个思路肯定是现在就去确认当前的PCIe设备BAR空间是否真的是NULL,手动查看之后发现并不是NULL;而且查看从处理器p0进程初始化PCIe的打印,发现BAR空间基址也是正常的。
那么,真相只有一个——从处理器p1进程获取BAR空间基址的时间点过早(偶现)——一个典型的时序问题。
根据这个思路,我们再看上图。满足Msg3发送的条件是Msg1和Msg2发送成功(其实,还有好多业务条件也需要满足,前期也查询了这些业务条件都没有问题才开始怀疑到这里的,定位问题的真实场景往往都是道阻且长)。所以,只需要出一个定位版本持续压力就可以定位Msg2是否有问题了。
定位版本中只需要在发送Msg3前判断从处理器p0维护的BAR空间基址是否为NULL就可以了。定位发现,果然出现了NULL的情况。那么可以断定Msg2出现了问题。
时序问题,要么是事件触发错误(比如丢消息),要么是状态记录错误(比如状态转换缺失环节)。
由于系统对各个消息进行了监控,发现Msg2消息在历史上发送过,因此,不是丢消息,而是Msg2还没发送,Msg3就发送了。
这就表明是状态机的状态转换出现了问题。
先给出正确的状态迁移图。
主处理器上的PCIe设备初始化状态和从处理器上的PCIe设备初始化状态都记录在主处理器的主进程中。不同的PCIe设备的初始化都是并行的,因此,各自的状态迁移也是并行发生,如下图所示。
汇总的状态迁移过程如下所示。