10

我正在为音频设备驱动程序(它是软件,但模拟硬件设备)编写 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 个 Refs,但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(据我所知)。

由于正在运行的操作系统内核在内存中保存了一个引用,我猜测这个单一实例是否仍然存在?这似乎不对,因为kextunload那样总是会失败。那么为什么kextunload有时只需要重新启动系统才能“完全”卸载所有驱动程序实例呢?

4

1 回答 1

11

为 IOKit kext运行kextunload将(如果没有其他 kext 依赖它)会导致内核尝试访问terminate()该 kext 中 I/O Kit 注册表中的任何类实例。然后它会稍等片刻,并检查该 kext 的任何类是否仍有实例。如果没有,它将卸载 kext。如果实例仍然存在,kextunload则失败(尽管终止的实例仍然终止;我的意思是 I/O 套件匹配不会在其提供程序上重新运行)。

所以不知何故,你仍然以实时实例结束。

  • 一种可能性是您的对象拒绝terminate(). 如果他们的客户端不会放弃控制,则可能会发生这种情况,例如,您无法卸载顶部已安装文件系统的磁盘的驱动程序。不响应终止消息的用户空间客户端是另一个示例。

  • 否则,实例会终止,但不会被释放。由于它们似乎属于您的两个主要驱动程序类,如果您没有任何用户客户不会放弃他们的要求,我将冒险并建议您可能有一个循环参考. 如果不是这样,您只需要寻找retain()与 a 不匹配的 s release()我在这个答案中给出了一些关于如何追踪这些的提示。

如果实例终止并取消注册,它们将不再出现在ioreg命令行工具的输出中,因此这是检查这两种情况中的哪一种适用于此处的一种简单方法。

于 2012-11-24T17:11:21.290 回答