callback を登録解除できない IOKit のバグ
- Apple
- 開発
IOKit で HID デバイスからデータを受け取るには IOHIDDeviceRegisterInputReportCallback()
で callback を登録する。逆に callback の登録を解除したいときは専用の関数があるわけではなく Apple の資料によると
Note: To unregister pass NULL for the callback.
登録するときと同じ関数を、(callback: NULL)
で呼べばいいらしい。
...と知ってからずっと試しているけど、どんな書き方をしても解除したはずの古い context で callback が呼ばれてしまい、アプリケーションがクラッシュ。
どうしようもないので IOKit のソースコードを読んでみることに。
void __IOHIDDeviceRegisterInputReportCallback(IOHIDDeviceRef device,
uint8_t * report,
CFIndex reportLength,
IOHIDReportCallback callback,
IOHIDReportWithTimeStampCallback callbackWithTimeStamp,
void * context)
{
IOHIDDeviceReportCallbackInfo info = {context, callback, callbackWithTimeStamp, device};
CFDataRef infoRef = NULL;
CFRetain(device);
if (!context)
os_log(_IOHIDLog(), "called with a null context");
if (!device->inputReportCallbackSet) {
device->inputReportCallbackSet = CFSetCreateMutable(NULL, 0, &__callbackBaseSetCallbacks);
}
require(device->inputReportCallbackSet, cleanup);
// adding or modifying a callback
infoRef = CFDataCreate(CFGetAllocator(device), (const UInt8 *) &info, sizeof(info));
require(infoRef, cleanup);
if (callback || callbackWithTimeStamp) {
CFSetAddValue(device->inputReportCallbackSet, infoRef);
if (device->deviceTimeStampedInterface) {
(*device->deviceTimeStampedInterface)->
setInputReportWithTimeStampCallback(device->deviceInterface,
report,
reportLength,
__IOHIDDeviceInputReportWithTimeStampCallback,
device,
0);
}
else {
(*device->deviceInterface)->setInputReportCallback(device->deviceInterface,
report,
reportLength,
__IOHIDDeviceInputReportCallback,
device,
0);
}
}
else {
CFSetRemoveValue(device->inputReportCallbackSet, infoRef);
}
cleanup:
CFRELEASE_IF_NOT_NULL(infoRef);
CFRelease(device);
}
確かに CFSetRemoveValue()
で取り除こうとしているようだけど callback 込みで比較しているからどうやっても取り除かれないという...
Apple に報告する元気は残っていない。
Share
リンクも共有もお気軽に。記事を書くモチベーションの向上に役立てます。