我正在为音频设备驱动程序(它的软件,但模拟硬件设备)编写OSX内核扩展。
在开发过程中,可以方便地完全卸载现有的旧版本,然后从头开始构建和安装新版本。但是,如果没有重新启动系统,有时似乎无法进行此操作。
程序本身未运行且源文件已从/System/Library/Extensions/
目录中删除。
但是kextstat
显示了一个实例:
$ kextstat | grep 'com.foo.driver.bar'
219 0 0xfff123 0x5000 0x5000 com.foo.driver.bar (0.0.1) <102 5 4 3>
(...这意味着:)
Index Refs Address Size Wired Name (Version) <Linked Against>
因此我的驱动程序实例有0个引用,但kextunload
有时会失败,抱怨现有实例:
$ sudo kextunload -b com.foo.driver.bar
(kernel) Can't unload kext com.foo.driver.bar; classes have instances:
(kernel) Kext com.foo.driver.bar class FooBarDriver has 1 instance.
(kernel) Kext com.foo.driver.bar class com_foo_driver_bar has 1 instance.
Failed to unload com.foo.driver.bar - (libkern/kext) kext is in use or retained (cannot unload).
当发生这种情况时,没有办法“强行”卸载kext(我知道)。
我是否正确地猜测这个单一实例仍然存在,因为运行的OS内核在内存中保存了引用?这似乎不对,因为kextunload
总会失败。那么为什么kextunload
有时只需要重新启动系统来“完全”卸载所有驱动程序实例?
答案 0 :(得分:11)
为IOKit kext运行kextunload
(如果没有其他关键字依赖于它)会导致内核尝试terminate()
该文件夹中I / O Kit注册表中任何类的实例。然后它会稍等一下,检查一下这个kext的类是否还有实例。如果没有,它将卸载kext。如果实例仍然存在,则kextunload
失败(终止的实例会终止;但是,我的意思是I / O工具包匹配不会在其提供商上重新运行)。
所以不知何故,你仍然以实时实例结束。
一种可能是您的对象拒绝terminate()
。如果他们的客户端不会放弃控制权,例如,您无法卸载顶部装有文件系统的磁盘的驱动程序。不响应终止消息的用户空间客户端是另一个例子。
否则,实例会终止,但不会被释放。因为它们似乎是你的两个主要驱动程序类,如果你没有任何用户客户端不会放弃他们的声明,我会打算走出困境并建议你可能有一个循环引用。如果不是这样,你只需要寻找与retain()
不匹配的release()
。我提供了一些关于如何跟踪这些问题的提示in this answer。
如果实例终止并取消注册,它们将不再出现在ioreg
命令行工具的输出中,因此这是检查这两种情况中哪一种适用的简单方法。