发布时间:2010-2-12 10:12
分类名称:Private
经过2个多星期对ePass1kng的ngp11模块的代码学习,有了一些认识,孔子曰稳定战果后再继续攻城略地(孔子:@#$@#%我哪说过…..), 所以做一个阶段性总结以备忘和交流。
P11中的类大约可以分为以下两大类:
如CSlot,CP11Session,CdataObject等
如SlotMgr, CPKContext, IPCClient, File System系统等. 系统通过SlotMgr管理多个CSlot, CSlot管理token上的session和object,并作句柄映射.
上层通过直接访问PKI接口访问本模块提供的服务,本模块通过共享内存(图中红色部分)的方式访问下层模块的服务(SlotD) P11模块中,IPCClient类的一个实例作为消息转发器,可以在两种场景下使用:
ngCommander类作为主动请求场景下(如上所述)IPCClient的一个代理,缓存并向IPCClient提交数据,然后等待slotD端有响 应后返回结果.
实现了FAT8文件系统,特性是文件分块并组成链表,与块状存储相比,优点是碎片较少,缺点是当读取次数远大于写的次数时,性能较差.
我们的epass1knd是属于这种情况吧?选择FAT8是基于什么考虑呢?1)
一般链表的结构类似下图
FAT表的结构是
用指针还是用index来指示下一节点位置本质是一样的,但是FAT节点的数据在那里?答案是node所在的位置本身暗示了数据所在位置,比如它是FAT 表第n项, 它代表的数据就是文件系统中的第n个簇. 另外需要一个地方记录所有链表(也就是文件)的起始结点,在我们的FAT8文件系统中它就是从0簇开始的那个文件.
限于水平,经验以及对系统的认识,以下建议有可能不合实际,甚至可能是错误的.如果是这样的话,请让我知道.
查看以上几个流程图,函数大都需要与多个对象交互,这对系统的设计来说是很不利的.因为对整个对象类模型来说,外面知道的元素越多,就可能在编码中使用的 元素越多,就越不利于系统的修改. 以C_OpenSession函数为例,它所必需知道的是slot ID(是函数参数之一),和SlotMgr(它维护了slot id到实际slot对象之间的映射),其他任何事物对他应该是透明的(它甚至不应该知道系统中是否到底有没有CSlot这种东西).它应该把创建 session的请求提交给slotMgr, slotMgr的函数内部取得slot对象,把请求传递给slot, slot得到请求后,查看是否有token,如果存在传递给token,token实际创建session. (Session在逻辑上来讲应该是token维护的吧?) 所有实体(函数和对象)都只需要知道它必须要知道的东西.
查看 P11模块中的类实现,有很多以Is开头的函数,例如IsSO, IsUser等,实现了这样的函数,外部的使用方式肯定是if……else…..或switch case形式,这就使token在各个状态下的功能代码分散到 了代码各处. Token的可能状态如下图所示:
显然是一个有限状态机,可以实现不同的类来表示它不同的状态,状态转换在token类中实现,实际处理的功能代码在状态类中实现(如下图),例如类 User有LogIn函数,它简单返回CKR_USER_ALREADY_LOGGED_IN错误.
在使用共享内存的IPC机制中,类IPCClient有n个互斥量(以下简称锁),用来锁定内存以便访问(读和写),一般来说,一块可读写的共享资源需要 两个锁,分别表示可读和可写,以便互斥访问和数据同步.可以封装一个CsharedMemory类,提供read和write接口,在read函数内获取 可读锁,完成后设置可写锁.write函数内获取可写锁,写完后设置可读锁.对使用者来说,只需要简单的调用read和write函数即可.简化了使用者 的工作量,并减少了可能出现的错误.否则,所有使用者需要互相协商锁的名称,并需要知道何时加锁何时不加,这些信息只需要共享资源本身知道即 可。(另:P11模块中确实存在一个CsharedMemory类,但只是创建共享内存,互斥和同步还是需要外部来进行.而且貌似无人使用.) 再如CSlot类提供了LockMutex和UnlockMutex函数,这个比上述情况前进了一步,我依然认为加锁是CSlot类自己的事情。
//于华章注://
关于共享内存的读写互斥,我以前研究过,是一个典型的“单写多读”问题,要达到以下效果:
“单写/多读”问题包括以下四个同步原则:
- 当一个线程正在写入数据时,其它任何线程不能写入数据;
- 当一个线程正在写入数据时,其它任何线程不能读取数据;
- 当一个线程正在读取数据时,其它任何线程不能写入数据;
- 当一个线程正在读取数据时,其它任何线程可以读取数据。
关于这个问题,可以参见论坛上的一个帖子:
//weitao comment//
对于并发这一块,也有一些小体会,可以总结出不少的现成锁模式可以套用:
*SpinLock自旋锁 在需要等待的时间不是很长的情况下在用户态等待,而不是转入内核态,防止环境切换,效率较高
*Self-recursive Lock 单一线程可以成功的递归获取锁
*Condition Lock 条件锁,在满足一定条件下才能获取锁
*Readers/Writer Lock 即为文中所描述的“单写多读”
还有一些惯用法如"双检查加锁优化"等等,有时间专门写一篇并发编程方面的小东西
P11模块极度缺乏文档,已有的文档有的也早已过时,跟不上现有代码的发展和演变。我认为如果需要补文档的话需要考虑以下几个方面: 对类或模块的使用者和维护者来说,需要知道它实现了哪些功能,需要跟哪些类(或模块)协作,协作的协议是什么。每个函数做了什么,要达到什么目的,对对象 的状态造成了什么改变。至于怎么作的则不太需要说明,否则需要维护文档与代码的一致性,而代码本身说明了怎么做的。
在研发内部好像是不能互相发bug report的,其实我以前经常给其他研发人员(甚至常常给自己)发bug report,一是记录曾经出现了什么问题以备忘,二是有可能发现问题的当时腾不出时间来修改代码。强烈建议bug track系统增加类似功能,并鼓励开发人员使用此功能。 造成现在这种情况的一个可能是每个模块没有专人维护,代码由大家一起维护。其实某个模块由专人维护是有很多好处的。好处之一是研发人员很容易把自己代入类 的角色中,在与其他类的交互中极力为自己(所维护的类和模块)争取好处,并明确自己的责任(与CRC卡片方法类似,CRC是 Class,Responsibilities,Collaboration的缩写)。某一个模块可以大家轮换维护,即某一个角色大家可以轮换来扮演,使 设计更为合理。 例如让我扮演CkeyObject这个角色,根据系统现有实现,我就会说:太过分了吧?我这个key只管自己的生成,对于加密来说,我只是一个参数,加密 工作就不要交给我来做了吧?应该有一个算法类或者什么东西来做这件事情。一个功能,如果大家都不认为是自己的责任,那么就应该构造一个新的类来做。
(请关注后续部分)