OSX Kext无法正确释放

Ind*_*oad 4 macos memory-management device-driver kernel-extension

我已经基于Wagerlabs代码(使用驱动程序用户客户机应用程序模型)为热插拔SCSI设备编写了设备驱动程序kext,并且一切正常。唯一剩下的担心是,驱动程序似乎没有被一致地释放,尤其是在应用程序崩溃的情况下。例如,当我尝试卸载kext时,即使在断开设备连接和关闭应用程序的情况下,仍然存在驱动程序和用户客户端的突出实例(驱动程序通常超过用户客户端)。

我已经登录了诸如之类的驱动程序功能free(),当我关闭计算机时,可以看到它们正在执行,因此这些实例显然仍可以终止。确保驱动程序实例终止并释放的“正确”方法是什么,即使主机应用程序崩溃,终止不当或通常不计划的事情?

pmd*_*mdj 5

如果在没有用户客户端应用程序运行的情况下拥有用户客户端类实例,那么与释放用户客户端实例相比,您肯定会保留用户客户端实例的频率更高。例如,您可能在主驱动程序类中保留了对客户端实例的保留引用。在用户客户端类的stop()方法中,确保从驱动程序中删除该客户端实例。

需要注意的另一件事:确保从内置IOService方法的覆盖版本中调用超类实现,例如stop()free()等不这样做通常会使IO Kit处于不一致状态。

最后,调试I / O Kit驱动程序中的保留泄漏的一种有用技术是通过使用日志记录版本覆盖方法来实际记录保留和释放:

void MyClass::taggedRetain(const void* tag) const
{
    OSReportWithBacktrace(
        "MyClass" CLASS_OBJECT_FORMAT_STRING "::taggedRetain(tag=%p)\n", CLASS_OBJECT_FORMAT(this), tag);
    IOService::taggedRetain(tag);
}
void MyClass::taggedRelease(const void * tag) const
{
    OSReportWithBacktrace(
        "MyClass" CLASS_OBJECT_FORMAT_STRING "::taggedRelease(tag=%p)\n", CLASS_OBJECT_FORMAT(this), tag);
    int count = getRetainCount();
    IOService::taggedRelease(tag);
    if (count == 1)
        printf(
            "MyClass::taggedRelease(tag=%p) final done\n", tag);
    else
        printf(
            "MyClass" CLASS_OBJECT_FORMAT_STRING "::taggedRelease(tag=%p) done\n", CLASS_OBJECT_FORMAT(this), tag);
}
Run Code Online (Sandbox Code Playgroud)

此代码中的宏在标头中定义如下:

#define CLASS_OBJECT_FORMAT_STRING "[%s@%p:%dx]"
#define CLASS_OBJECT_FORMAT(obj) myClassName(obj), obj, myRefCount(obj)

inline int myRefCount(const OSObject* obj)
{
    return obj ? obj->getRetainCount() : 0;
}

inline const char* myClassName(const OSObject* obj)
{
    if (!obj) return "(null)";
    return obj->getMetaClass()->getClassName();
}
#endif
Run Code Online (Sandbox Code Playgroud)

我解释说,taggedRetain()taggedRelease()是实际的底层实现retain()release()-如果你忽略了后者,你将不会看到任何保留和释放从OSCollections到来,因为它们使用标记的版本(与非空标签)。

OSReportWithBacktrace()不幸的是,由回溯产生的回溯只是一堆十六进制指针,但是您可以使用gdb查找这些回溯。

无论如何,通过记录对象的保留和释放,您可以遍历所有保留,并确保它们与正确位置的释放匹配。注意周期!