【问题标题】:HIDManager Wierd CFRunLoop TerminationHIDManager 奇怪的 CFRunLoop 终止
【发布时间】:2012-02-06 23:32:52
【问题描述】:

我已经创建了设备匹配和设备移除回调,并且需要运行 CFRunLoop 以在设备插入和移除时调用这些回调。

但问题是,DeviceMatching 回调需要大量处理时间并且取决于要附加的设备,所以我想通过在有限的时间内运行 CFRunLoop 来检测设备是否被移除,并且设备移除回调发生.

但是,它工作了 2 次,然后它抛出 exe_bad_access。


  IOHIDManagerSetDeviceMatching( tIOHIDManagerRef, matchingCFDictRef );
  if( matchingCFDictRef ) {
        CFRelease( matchingCFDictRef );
  }
  IOHIDManagerRegisterDeviceMatchingCallback(tIOHIDManagerRef,
                                                 Handle_DeviceMatchingCallback,NULL);
  IOHIDManagerRegisterDeviceRemovalCallback(tIOHIDManagerRef, Handle_RemovalCallback, NULL);

  IOHIDManagerScheduleWithRunLoop(tIOHIDManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
      CFRunLoopRun();

设备添加回调

static void Handle_DeviceMatchingCallback(void* inContext, IOReturn inResult, 
                             void* inSender, IOHIDDeviceRef  inIOHIDDeviceRef) {
      //DO SOME HEAVY PROCESSING

      //NOW WE NEED TO CHECK IF DEVICE IS STILL CONNECTED
     [[NSRunLoop currentRunLoop]  runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];

      //DO POST PROCESSING

}

设备移除回调:

static void Handle_RemovalCallback( void* inContext,IOReturn  inResult,
                        void*  inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
     //NOW THIS GET's INVOKED, after keeping in run loop

}

以下是生成matchingCFDictRef的代码

CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

    CFNumberRef vendorIDCFNumRef  = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &vendorId );
    CFNumberRef productIDCFNumRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &productId );

    CFDictionarySetValue( matchDict, CFSTR( kIOHIDVendorIDKey  ), vendorIDCFNumRef );
    CFDictionarySetValue( matchDict, CFSTR( kIOHIDProductIDKey ), productIDCFNumRef );

    CFRelease( vendorIDCFNumRef );
    CFRelease( productIDCFNumRef );

【问题讨论】:

  • 哪一行产生异常?堆栈是什么?
  • CFRunLoopRun(); (我还在堆栈跟踪中看到 CFRunLoop 调用 CFGetTypeID)
  • 堆栈包含第一个代码块的方法,然后是CFRunLoop,然后是CFGetTypeID

标签: objective-c macos device-driver hid


【解决方案1】:

如何生成matchingCFDictRef?虽然通常的约定会建议 IOHIDManager 应该保留或复制它,但它可能不是。我现在会尝试删除CFRelease,看看是否会有所改善。

CFGetTypeID 中的崩溃表明它正在尝试使用已释放的 CF 对象。您可以做一些事情来尝试调试它是哪一个:

  • 打开NSZombie。即使这是一个 CF 对象,它也可能工作(许多 CF 对象是免费桥接的,并且仍然可以工作)。
  • 在调试器中,检查参数CFGetType。根据您的处理器,请参阅Inspecting Obj-C parameters in gdb 以获取正确的寄存器。 (此页面是否适用于 ObjC 无关紧要;您只需要与 arg0 相关的全部内容。)

【讨论】:

  • 如果我打开 NSZombie,它可以工作,但我在控制台中看不到任何登录信息或 Instruments 中的任何消息。
  • 这样就离开了调试器。检查传递给 CFGetType 的对象的地址,并将其与您知道的对象进行比较。
  • 请查看我的其他回复
  • 能否告诉我如何检查堆栈跟踪中的地址
  • 它不在堆栈跟踪中。您需要在调试器中检查它,如上面“检查 gdb 中的 Obj-C 参数”链接中所述。
【解决方案2】:

以下是生成matchingCFDictRef的代码

CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

    CFNumberRef vendorIDCFNumRef  = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &vendorId );
    CFNumberRef productIDCFNumRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &productId );

    CFDictionarySetValue( matchDict, CFSTR( kIOHIDVendorIDKey  ), vendorIDCFNumRef );
    CFDictionarySetValue( matchDict, CFSTR( kIOHIDProductIDKey ), productIDCFNumRef );

    CFRelease( vendorIDCFNumRef );
    CFRelease( productIDCFNumRef );

现在,我看到了不同的堆栈跟踪,从 CFRunLoop 调用,虽然我仍然在符号中看到 GetTypeID

0x00007fff8534407a  <+0023>  jne    0x7fff8534409f <IOHIDDeviceScheduleWithRunLoop+60>
0x00007fff8534407c  <+0025>  mov    0x18(%rdi),%rdi
0x00007fff85344080  <+0029>  mov    (%rdi),%rax
0x00007fff85344083  <+0032>  lea    0x58(%r12),%rsi
0x00007fff85344088  <+0037>  callq  *0x40(%rax)
0x00007fff8534408b  <+0040>  test   %eax,%eax
0x00007fff8534408d  <+0042>  jne    0x7fff85344148 <IOHIDDeviceScheduleWithRunLoop+229>
0x00007fff85344093  <+0048>  cmpq   $0x0,0x58(%r12)
0x00007fff85344099  <+0054>  je     0x7fff85344148 <IOHIDDeviceScheduleWithRunLoop+229>
0x00007fff8534409f  <+0060>  mov    0x58(%r12),%rdi
0x00007fff853440a4  <+0065>  callq  0x7fff85368f36 <dyld_stub_CFGetTypeID>
0x00007fff853440a9  <+0070>  mov    %rax,%rbx
0x00007fff853440ac  <+0073>  callq  0x7fff85369008 <dyld_stub_CFRunLoopSourceGetTypeID>
0x00007fff853440b1  <+0078>  cmp    %rax,%rbx
0x00007fff853440b4  <+0081>  jne    0x7fff853440cc <IOHIDDeviceScheduleWithRunLoop+105>

我发现 IOHIDDeviceScheduleWithRunLoop 在 0x00007fff85344080 mov (%rdi),%rax 处中断(请使用 0x00007fff85344080 搜索)

在参考文档的帮助下,我看到它是第一个参数,意思是 tIOHIDManagerRef,我创建了 IOHIDManagerRef tIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone );

但是,如何从上面的堆栈跟踪中看到它的地址?

【讨论】:

  • 我会尝试删除供应商和产品 ID 上的 CFRelease
猜你喜欢
  • 1970-01-01
  • 2015-08-09
  • 2017-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-26
相关资源
最近更新 更多