问题
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 );
回答1:
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 toarg0
.)
回答2:
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 ?
来源:https://stackoverflow.com/questions/9168936/hidmanager-wierd-cfrunloop-termination