HIDManager 奇怪的 CFRunLoop 终止

发布于 2025-01-03 10:50:28 字数 2092 浏览 0 评论 0原文

我已经创建了设备匹配和设备删除回调,并且需要运行 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

}

以下是生成匹配CFDictRef的代码

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 );

I've created device matching and device removal callbacks, And need to run CFRunLoop to get those callbacks invoked whenever device plugged in and removed.

But the problem is, DeviceMatching callback takes a lot of processing time and depends on device to be attached, So I want to detect if device is removed by running the CFRunLoop for a limited time, and With that the device removal callback happens.

But, It works for 2 times and then it throws 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();

Device Add Callback

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

}

Device Removal Callback:

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

}

Following is the code for generating 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 );

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

两仪 2025-01-10 10:50:28

如何生成matchingCFDictRef?尽管正常约定建议 IOHIDManager 应保留或复制它,但也可能并非如此。我现在会尝试取出 CFRelease 看看是否会有所改善。

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

How do you generate matchingCFDictRef? Though normal conventions would suggest that IOHIDManager should retain or copy it, it's possible that it isn't. I would try taking out the CFRelease for now and see if that improves things.

The crash in CFGetTypeID indicates that it is trying to work with a CF object that has been freed. A few things you can do to try to debug which one it is:

  • Turn on NSZombie. It might work, even though this is a CF object (many CF objects are toll free bridged and will still work).
  • In the debugger, check the parameter to CFGetType. See Inspecting Obj-C parameters in gdb for the correct register depending on your processor. (It doesn't matter that this page is for ObjC; you just want the entires related to arg0.)
你不是我要的菜∠ 2025-01-10 10:50:28

以下是生成匹配CFDictRef的代码

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>

我发现它在0x00007fff85344080 <处中断;+0029> mov (%rdi),%rax, for IOHIDDeviceScheduleWithRunLoop ( 请使用 0x00007fff85344080 搜索)

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

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

Following is the code for generating 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 );

Now, I see different stack trace, called from CFRunLoop, Though I still see the GetTypeID in the symbols

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>

I see that it is breaking at 0x00007fff85344080 <+0029> mov (%rdi),%rax, for IOHIDDeviceScheduleWithRunLoop ( Please search with 0x00007fff85344080)

With the help of reference document, I see it is the first argument which means tIOHIDManagerRef, which I create IOHIDManagerRef tIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone );

But, How to see the address of it, from above stack trace ?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文