.. Kenneth Lee 版权所有 2018-2020
:Authors: Kenneth Lee :Version: 1.0
抽离设计逻辑
今天有人来找我讨论一个程序怎么改。他这个程序包括三个Linux内核模块,有点类似 Linux的device-bus-driver的模型:包括一组engine,一个框架,和一组app:
.. figure:: _static/架构例子1.png
大概的意思是,app和engine都可以注册给框架,如果框架发现两者需求匹配,就会引起两 者的关联(attach),从而让app可以使用engine的能力。
他们在测试的时候发现,这个程序在执行复杂的随机插入,删除的过程后,有一定的几率 发生指针索引异常,所以他们想和我讨论一下怎么修改的问题。
给我讲这个背景的兄弟是大体是这样描述这个问题的:你看,insmod app1.ko的时候,它 注册给框架,这里加入到一个链表里,然后这个链表马上要查询,查询的时候如果遇到 engine1.ko插入进来,框架会进入这个流程,这时如果卸载engine1.ko,就会XXXX,这样 app1就索引不到engine1的这个指针了,然后我把这个加入链表的操作改到这里,那么……
我听了几分钟,就开始头脑发麻了。我说,你不要一上来给我说这个链表,那个结构的, 我们先来说说你说的这个东西的“情理”好不好?
我们有三个(种)对象。先看app和框架的关系:app注册给框架,app一定提供了数据(指 针)给框架,那么app.init_module()注册的时候,就必须把框架锁死在内存中,所以,框 架的注册函数必须module_get(THIS)把自己锁在内存中,如果这个过程不成功,注册函数 必须保证,app的数据没有交给框架,框架也没有被module_get()。这里的逻辑无懈可击 吧?
engine和框架的关系也是一样的。
好了,现在讨论app和engine同时插入的情况:怎么看这应该不正常,但不光我们不正常, Linux的其他内核模块也不会正常对吧?所以简单确认一下,就会发现,Linux已经有锁保 证module_init和module_exit()全部是串行的。两者的先后行为在这个上面也是无懈可击 的对吧?
最后是app和engine的关联:如果两者互相看到对方的数据了,两者肯定有对方的指针,谁 都不能简单被rmmod。如果把两者都module_get了,两个都卸不掉。那么我们很容易就得这 样决定:一旦attach,必须让其中一方把另一方module_get()了,然后没有被get的一方就 可以卸载,并在module_exit()中负责deatch对方的数据结构,让两者在数据上不再发生关 联,然后才module_put()对方。这样,这个逻辑也无懈可击吧?
好了,现在你可以跟我谈你那些链表的事情了……
你看,很多人问,为什么不直接写代码而要做设计。这就是原因——设计是可以分离代码逻 辑来单独讨论的。