我已经写了基于上有所为热插拔SCSI设备的设备驱动程序的KEXT, Wagerlabs代码 (使用驱动程序,用户客户端应用程序模型),一切正常。 剩下的唯一担心的是,司机似乎未得到一致释放,特别是如果应用程序崩溃。 例如,当我尝试卸载的kext,即使断开设备和关闭的程序,还有司机和用户客户端(与司机通常在数量上超过了用户客户端)的优秀实例。
我已经在驱动程序中的功能类似日志free()
,而当我关闭电脑,我可以看到这些被执行,因此实例可以明显地仍然被终止。 什么是“正确”的方式,以确保驱动程序实例被终止和释放,即使主机应用程序崩溃,不当终止或东西一般不会去计划?
如果你有没有用户客户端应用程序运行时,那么你肯定是保留用户的客户机实例用户客户端类的实例往往比你释放他们。 例如,你可能会保持在主驱动程序类的残留参考客户机实例。 在您的用户客户端类的stop()
方法,确保从驱动程序删除客户机实例。
另一件要注意:确保你从你的重写的版本调用父类实现内置IOService方法,如stop()
free()
等。如果不这样做,通常会把IO包成不一致的状态。
最后,一个用于调试的有用的技术保留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);
}
在该代码中的宏是在报头定义如下:
#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
我要说明的是taggedRetain()
和taggedRelease()
是实际的底层实现的retain()
和release()
-如果你忽略了后者,你将不会看到任何保留和释放从OSCollections的到来,因为他们使用的标记版本(有一个非空标签)。
所产生的回溯OSReportWithBacktrace()
是不幸的只是一堆六角三分的,但你可以看看那些了用gdb。
在任何情况下,通过记录保留和释放你的对象,你可以通过所有保留,并确保他们在正确的地方释放匹配。 当心周期!