首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

MAC OS X 设备驱动开发通译(I/O Kit Device Driver Design Guidlines) (二)libkern C++运行时

2012-06-21 
MAC OS X 设备驱动开发翻译(I/O Kit Device Driver Design Guidlines) (二)libkern C++运行时无比蛋疼的开

MAC OS X 设备驱动开发翻译(I/O Kit Device Driver Design Guidlines) (二)libkern C++运行时

无比蛋疼的开始了新的翻译生活。。。

为了防止看完==忘完,特译此文档,仅供参考备忘,有撒肺腑感言只管讲,有错必纠,如需转载,请注明出处,谢谢合作

桑Q VERY MUCH


第一章:libkern C++运行时

在设计Mac OS X内核时,苹果滴攻城狮们选择使用C++ 的限制子集,因为被排除的特性--异常,多重继承,模板以及运行时类型信息(RTTI), 对于高性能多线程的内核来说不够强大。但是由于某种形式的RTTI实际中又是需要的,苹果就设计了一个增强版的运行时赋予类型系统。libkern库实现了这个系统,提供了下列特性:

    动态的对象分配以及对象构造/析构对象自省以及动态的对象转型运行时对象计数(追踪每个类中当前实例的数量)二进制兼容守护者


    这些特性的首要代理人就是OSMetaClass类。这个类是与OSObject类对等的类,所有的设备驱动的类都是源自这个类。本章对OSMetaClass以及OSMetaClassBase类的API以及服务做了一定深度的展开讲述并探讨了如何在你的代码中最好的利用它们。OSMetaClass以及OSMetaClassBase类的API定义在OSMetaClass.h文件中。


    运行时系统的创建


    libkern库只要加载/卸载了内核扩展程序时,它就会构建并更新它的C++运行时系统。在libkern或者I/O Kit库中的类自身都是OSMetaClass类的一个对象。OSMetaClass类指定了四个实例变量来表述类实例:

    类名基类类的大小当前实例的数量

    当内核加载了一个内核扩展应用时(KEXT),它需要先把前3位的信息注册到运行时系统。系统实际上是一个包含两个互设索引字典的元类数据库。

    类字典包括与OSMetaClass对象配对的类名键。 这对于libkern对象的动态创建(包括驱动实例)至关重要。模块字典包含与一个OSMetaClass对象组成的数组配对的KEXT-二进制名。这对于内核扩展模块能够安全卸载至关重要。

    下图向我们展示了libkern运行时是如何在KEXT加载到内核中时向这些字典写入类信息的


    MAC OS X 设备驱动开发通译(I/O Kit Device Driver Design Guidlines) (二)libkern C++运行时

    当加载内核扩展时加载器执行元类的注册有三个阶段:

    1. 加载前 加载器调用OSMetaClass类的成员方法 preModLoad 。这个方法获得了一个锁以确保当加载多个内核扩展程序时只有一个线程在执行操作。同时它还在注册的准备阶段生成了KEXT二进制类的一些全局信息。
      加载中 加载器会调用每个被(作为类定义一部分的)OSMetaClass宏所创建的静态构造器。因此,每个类的OSMetaClass构造器都会被调用。构造器的参数是三个OSMetaClass数据成员:类名,指向基类的指针以及类的大小。加载器会更新这个类字典以及模块字典,用KEXT-二进制名以及类名作为键并把刚创建的OSMetaClass对象插入到这些字典中。它还会把所有基类继承关系指针串起来。
      加载后 当所有静态构造器都被调用后,加载器会调用OSMetaClass的成员函数 postModLoad 。这个函数会释放锁并从加载中返回结果代码。要是代码显示有错误,例如构造器形式错误,那么加载尝试将会终止。

    注意:尽管OSMetaClass用于注册元类信息的成员函数被声明为public,但你不应在你的代码中调用这些函数,尤其是 preModLoad 跟 postModLoad

    只要内核代码创建了一个继承自OSObject的类的实例时,libkern运行时赋予类型系统就会与OSMetaClass对象相关联的实例计数,当一个实例被释放时则减少一个计数。运行时系统使用这套机制以确保当内核扩展应用被卸载后系统中不再存有属于该应用的存活对象。(当然,要是代码不恰当的保持/释放了对象,这就可能导致应当被卸载的KEXT的残留,并引起内存溢出。溢出的对象引用会导致开发周期中让人蛋疼的,相当耗费资源的延迟)。


    当KEXT二进制文件中的所有类的实例计数归零时,内核卸载器等个一分钟(以保证二进制文件稍后不会再被使用)再从内核中将这个二进制文件卸载。在卸载前,卸载器会调用二进制文件中的所有类的静态构造器来移除所有该类在运行时系统中的引用。


    对象的创建以及销毁

    由于异常被排除在内核的C++有限子集之外,所以你不可能在毫无风险的情况下简单的实现一个通常意义上的C++构造器以及析构器。构造器以及析构器被定义为不返回任何值(例如错误码)。通常,当它们碰到问题时,它们会抛出一个异常。但是由于异常在内核的C++运行时不被支持,所以就没办法直到分配或者释放时所发生的错误。


    上述情况引出了一个libkern C++运行时系统的设计特性,使用OSMetaClass宏来指定一个类的构造,即运行时赋予类型系统的元类数据结构以及函数接口。宏还定义了主要的构造函数以及析构函数。这些宏创建的构造函数得到保证,证明其不会发生错误,因为它们自身并不做任何分配任务。取而代之的是,运行时系统会延迟实际的对象分配,直到它们执行初始化时(即调用 init 成员函数时)。因为 init 函数定义为返回一个布尔值,这就让碰到错误时返回错误成为可能。


    OSMetaClass构造函数宏的使用

    当创建基于OSObject类的C++类时,你的代码必须调用一对基于OSMetaClass类的宏。调用位置放在介于声明与类实现的第一条语句之间。这些宏对你的类至关重要,因为它们会为libkern运行时赋予类型设施提供与之相关的元类信息,并为你的类定义构造函数以及析构函数。

    对于实际的类(非抽象类)来说,第一个宏,OSDeclareDefaultStrutors 声明了C++的构造函数;通常把这条宏作为类头文件中的类声明的第一条语句。例如: