Example #1
0
void IOKitEventPublisher::stop() {
  if (run_loop_ == nullptr) {
    // If there is no run loop then the publisher thread has not started.
    return;
  }

  // Stop the run loop.
  WriteLock lock(mutex_);
  CFRunLoopStop(run_loop_);

  // Stop the run loop before operating on containers.
  // Destroy the IOPort.
  if (port_ != nullptr) {
    auto source = IONotificationPortGetRunLoopSource(port_);
    if (CFRunLoopContainsSource(run_loop_, source, kCFRunLoopDefaultMode)) {
      CFRunLoopRemoveSource(run_loop_, source, kCFRunLoopDefaultMode);
    }
    // And destroy the port.
    IONotificationPortDestroy(port_);
    port_ = nullptr;
  }

  // Clear all devices and their notifications.
  for (const auto& device : devices_) {
    IOObjectRelease(device->notification);
  }
  devices_.clear();
}
void CheckRunLoopSource(int deviceIndex,char *caller,int line){
	CFRunLoopSourceRef currentSource;
	pRecDevice device;
	IOHIDDeviceInterface122** interface;
	
	device=PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
	if(!HIDIsValidDevice(device))PrintfExit("PsychHID: Invalid device.\n");
	interface=device->interface;
	if(interface==NULL)PrintfExit("PsychHID: No interface for device.\n");
	currentSource=(*interface)->getAsyncEventSource(interface);
	if(source[deviceIndex] != currentSource)printf("%s (%d): source[%d] %4.4lx != current source %4.4lx.\n"
			,caller,line,(int)deviceIndex,(unsigned long)source[deviceIndex],(unsigned long)currentSource);

	if(ready[deviceIndex] && (source[deviceIndex]!=NULL) && !CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode))
		printf("%d: %s(%d): \"ready\" but source not in CFRunLoop.\n",(int)deviceIndex,caller,line);
	if(!ready[deviceIndex] && (source[deviceIndex]!=NULL) && CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode))
		printf("%d: %s(%d): \"!ready\" yet source is in CFRunLoop.\n",(int)deviceIndex,caller,line);
}
/*
1. one must call CFRunLoopSourceInvalidate to kill the callback established by setInterruptReportHandlerCallback 
 before calling HIDReleaseDeviceList.

2. after calling setInterruptReportHandlerCallback to enable the callback and CFRunLoopSourceInvalidate to disable 
it, it is then impossible to re-enable the callback with that source. To later re-enable, simply remove the source, instead of
invalidating it. Once i've called CFRunLoopSourceInvalidate it appears that my only option is to release the interface by calling 
 HIDReleaseDeviceList and start over.
*/
PsychError PsychHIDReceiveReportsCleanup(void) 
{
// On a hunch, we now do both: remove the source and invalidate it. Alas, it makes no difference. I still get the CLEAR MEX crash.
	int deviceIndex;
	
	//printf("Clean up before PsychHID is flushed.\n");
	for(deviceIndex=0;deviceIndex<MAXDEVICEINDEXS;deviceIndex++) if(source[deviceIndex]!=NULL) {
                CheckRunLoopSource(deviceIndex,"PsychHIDReceiveReportsCleanup",__LINE__);
		CFRunLoopRemoveSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode);// kCFRunLoopDefaultMode
		if(0 && optionsPrintCrashers)printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex]
					,CFRunLoopSourceIsValid(source[deviceIndex])
					,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode));
		if(optionsPrintCrashers)printf("%d: CFRunLoopSourceInvalidate\n",deviceIndex);
		CFRunLoopSourceInvalidate(source[deviceIndex]);
		if(optionsPrintCrashers)printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex]
					,CFRunLoopSourceIsValid(source[deviceIndex])
					,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode));
		ready[deviceIndex]=0;
		CheckRunLoopSource(deviceIndex,"PsychHIDReceiveReportsCleanup",__LINE__);
		source[deviceIndex]=NULL;
	}			
	return 0;
}
PsychError ReceiveReportsStop(int deviceIndex)
{
	CheckRunLoopSource(deviceIndex,"ReceiveReportsStop",__LINE__);
	if(ready[deviceIndex]){
		// Rob Yepez, at Apple, suggested that it might be better to call CFRunLoopRemoveSource than CFRunLoopSourceInvalidate.
		// He's right. There's no problem in re-enabling the callback after using CFRunLoopRemoveSource.
		// The source remains valid and can be added again to the run loop. Don't create it again.
		if(myRunLoopMode==NULL)myRunLoopMode=CFSTR("myMode");; // kCFRunLoopDefaultMode
		if(0 && optionsPrintCrashers)printf("%d: CFRunLoopRemoveSource\n",deviceIndex);
		CFRunLoopRemoveSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode);// kCFRunLoopDefaultMode
		if(0 && optionsPrintCrashers)printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex]
			   ,CFRunLoopSourceIsValid(source[deviceIndex])
			   ,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode));
		ready[deviceIndex]=0;
	}
	CheckRunLoopSource(deviceIndex,"ReceiveReportsStop",__LINE__);
	return 0;
}
/* PsychHIDReceiveReportsCleanup(void) -- Called at PsychHID shutdown time:

1. one must call CFRunLoopSourceInvalidate to kill the callback established by setInterruptReportHandlerCallback 
 before calling HIDReleaseDeviceList.

2. after calling setInterruptReportHandlerCallback to enable the callback and CFRunLoopSourceInvalidate to disable 
it, it is then impossible to re-enable the callback with that source. To later re-enable, simply remove the source, instead of
invalidating it. Once i've called CFRunLoopSourceInvalidate it appears that my only option is to release the interface by calling 
 HIDReleaseDeviceList and start over.

*/
PsychError PsychHIDReceiveReportsCleanup(void) 
{
	int deviceIndex;
	
	//printf("Clean up before PsychHID is flushed.\n");
	for(deviceIndex=0;deviceIndex<MAXDEVICEINDEXS;deviceIndex++) if(source[deviceIndex]!=NULL) {
        CheckRunLoopSource(deviceIndex,"PsychHIDReceiveReportsCleanup",__LINE__);
		CFRunLoopRemoveSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode);// kCFRunLoopDefaultMode
        if (optionsPrintCrashers) printf("%d: CFRunLoopSourceInvalidate\n",deviceIndex);
        CFRunLoopSourceInvalidate(source[deviceIndex]);
        if(optionsPrintCrashers) printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex]
                                           ,CFRunLoopSourceIsValid(source[deviceIndex])
                                           ,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode));
        ready[deviceIndex]=0;
        CheckRunLoopSource(deviceIndex,"PsychHIDReceiveReportsCleanup",__LINE__);
        source[deviceIndex]=NULL;
	}
    
    // Release all report linked lists, memory buffers etc.:
    PsychHIDReleaseAllReportMemory();

	return 0;
}
Example #6
0
SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnDatap) {
    struct __CFMessagePortMachMessage *sendmsg;
    CFRunLoopRef currentRL = CFRunLoopGetCurrent();
    CFRunLoopSourceRef source = NULL;
    CFDataRef reply = NULL;
    int64_t termTSR;
    uint32_t sendOpts = 0, sendTimeOut = 0;
    int32_t desiredReply;
    Boolean didRegister = false;
    kern_return_t ret;

//#warning CF: This should be an assert
    // if (!__CFMessagePortIsRemote(remote)) return -999;
    if (!__CFMessagePortIsValid(remote)) return kCFMessagePortIsInvalid;
    __CFMessagePortLock(remote);
    if (NULL == remote->_replyPort) {
	CFMachPortContext context;
	context.version = 0;
	context.info = remote;
	context.retain = (const void *(*)(const void *))CFRetain;
	context.release = (void (*)(const void *))CFRelease;
	context.copyDescription = (CFStringRef (*)(const void *))__CFMessagePortCopyDescription;
	remote->_replyPort = CFMachPortCreate(CFGetAllocator(remote), __CFMessagePortReplyCallBack, &context, NULL);
    }
    remote->_convCounter++;
    desiredReply = -remote->_convCounter;
    CFDictionarySetValue(remote->_replies, (void *)desiredReply, NULL);
    sendmsg = __CFMessagePortCreateMessage(CFGetAllocator(remote), false, CFMachPortGetPort(remote->_port), (replyMode != NULL ? CFMachPortGetPort(remote->_replyPort) : MACH_PORT_NULL), -desiredReply, msgid, (data ? CFDataGetBytePtr(data) : NULL), (data ? CFDataGetLength(data) : 0));
    __CFMessagePortUnlock(remote);
    if (replyMode != NULL) {
        source = CFMachPortCreateRunLoopSource(CFGetAllocator(remote), remote->_replyPort, -100);
        didRegister = !CFRunLoopContainsSource(currentRL, source, replyMode);
	if (didRegister) {
            CFRunLoopAddSource(currentRL, source, replyMode);
	}
    }
    if (sendTimeout < 10.0*86400) {
	// anything more than 10 days is no timeout!
	sendOpts = MACH_SEND_TIMEOUT;
	sendTimeout *= 1000.0;
	if (sendTimeout < 1.0) sendTimeout = 0.0;
	sendTimeOut = floor(sendTimeout);
    }
    ret = mach_msg((mach_msg_header_t *)sendmsg, MACH_SEND_MSG|sendOpts, sendmsg->head.msgh_size, 0, MACH_PORT_NULL, sendTimeOut, MACH_PORT_NULL);
    CFAllocatorDeallocate(CFGetAllocator(remote), sendmsg);
    if (KERN_SUCCESS != ret) {
	if (didRegister) {
	    CFRunLoopRemoveSource(currentRL, source, replyMode);
	    CFRelease(source);
	}
	if (MACH_SEND_TIMED_OUT == ret) return kCFMessagePortSendTimeout;
	return kCFMessagePortTransportError;
    }
    if (replyMode == NULL) {
	return kCFMessagePortSuccess;
    }
    CFRetain(remote); // retain during run loop to avoid invalidation causing freeing
    _CFMachPortInstallNotifyPort(currentRL, replyMode);
    termTSR = mach_absolute_time() + __CFTimeIntervalToTSR(rcvTimeout);
    for (;;) {
	CFRunLoopRunInMode(replyMode, __CFTSRToTimeInterval(termTSR - mach_absolute_time()), true);
	// warning: what, if anything, should be done if remote is now invalid?
	reply = CFDictionaryGetValue(remote->_replies, (void *)desiredReply);
	if (NULL != reply || termTSR < (int64_t)mach_absolute_time()) {
	    break;
	}
	if (!CFMessagePortIsValid(remote)) {
	    // no reason that reply port alone should go invalid so we don't check for that
	    break;
	}
    }
    // Should we uninstall the notify port?  A complex question...
    if (didRegister) {
        CFRunLoopRemoveSource(currentRL, source, replyMode);
	CFRelease(source);
    }
    if (NULL == reply) {
	CFDictionaryRemoveValue(remote->_replies, (void *)desiredReply);
	CFRelease(remote);
	return CFMessagePortIsValid(remote) ? kCFMessagePortReceiveTimeout : -5;
    }
    if (NULL != returnDatap) {
	*returnDatap = ((void *)0xffffffff == reply) ? NULL : reply;
    } else if ((void *)0xffffffff != reply) {
	CFRelease(reply);
    }
    CFDictionaryRemoveValue(remote->_replies, (void *)desiredReply);
    CFRelease(remote);
    return kCFMessagePortSuccess;
}
PsychError ReceiveReports(int deviceIndex)
{
	long error=0;
	pRecDevice device;
	IOHIDDeviceInterface122** interface=NULL;
	int reason; // kCFRunLoopRunFinished, kCFRunLoopRunStopped, kCFRunLoopRunTimedOut, kCFRunLoopRunHandledSource

	CountReports("ReceiveReports beginning.");
	if(freeReportsPtr==NULL)PrintfExit("No free reports.");

	PsychHIDVerifyInit();
	device=PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
	if(!HIDIsValidDevice(device))PrintfExit("PsychHID: Invalid device.\n");
	interface=device->interface;
	if(interface==NULL)PrintfExit("PsychHID: No interface for device.\n");
	if(deviceIndex<0 || deviceIndex>MAXDEVICEINDEXS-1)PrintfExit("Sorry. Can't cope with deviceNumber %d (more than %d). Please tell [email protected]",deviceIndex,(int)MAXDEVICEINDEXS-1);
	CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__);
	if(!ready[deviceIndex]){
		// setInterruptReportHandlerCallback
		static unsigned char buffer[MAXREPORTSIZE];
		psych_uint32 bufferSize=MAXREPORTSIZE;
		psych_bool createSource;

		createSource=(source[deviceIndex]==NULL);
		if(createSource){
			if(optionsPrintCrashers && createSource)printf("%d: createAsyncEventSource\n",deviceIndex);
			error=(*interface)->createAsyncEventSource(interface,&(source[deviceIndex]));
			if(error)PrintfExit("ReceiveReports - createAsyncEventSource error 0x%lx.",error);
			if(0 && optionsPrintCrashers && createSource)
				printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex]
					   ,CFRunLoopSourceIsValid(source[deviceIndex])
					   ,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode));
		}
		if(optionsPrintCrashers && createSource)printf("%d: getAsyncEventSource\n",deviceIndex);
		CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__);
		if(optionsPrintCrashers && createSource)printf("%d: CFRunLoopAddSource\n",deviceIndex);
		CFRunLoopAddSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode);
		if(0 && optionsPrintCrashers && createSource)printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex]
			   ,CFRunLoopSourceIsValid(source[deviceIndex])
			   ,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode));
		ready[deviceIndex]=1;
		CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__);
		if(optionsPrintCrashers && createSource)printf("%d: setInterruptReportHandlerCallback\n",deviceIndex);
		error=(*interface)->setInterruptReportHandlerCallback(interface,buffer,bufferSize,ReportCallback,buffer,(void *)deviceIndex);
		if(error)PrintfExit("ReceiveReports - setInterruptReportHandlerCallback error 0x%lx.",error);
		if(optionsPrintCrashers && createSource)printf("%d: CFRunLoopRunInMode.\n",deviceIndex);
	}
	//printf("%d: CFRunLoopRunInMode\n",deviceIndex);
	reason=CFRunLoopRunInMode(myRunLoopMode,optionsSecs,false);
	if(reason!=kCFRunLoopRunTimedOut && reason!=kCFRunLoopRunHandledSource){
		char *s;
		switch(reason){
			case kCFRunLoopRunFinished: s="kCFRunLoopRunFinished"; break;
			case kCFRunLoopRunStopped: s="kCFRunLoopRunStopped"; break;
			case kCFRunLoopRunTimedOut: s="kCFRunLoopRunTimedOut"; break;
			case kCFRunLoopRunHandledSource: s="kCFRunLoopRunHandledSource"; break;
			default: s="of unknown reason.";
		}
		printf("RunLoop ended at %.3f s because %s.\n",CFAbsoluteTimeGetCurrent()-AInScanStart,s);			
	}
	CountReports("ReceiveReports end.");
	return error;
}
Example #8
0
CF_EXPORT rwsched_CFRunLoopSourceRef
rwsched_tasklet_CFRunLoopRunTaskletBlock(rwsched_tasklet_ptr_t sched_tasklet,
        rwsched_CFRunLoopSourceRef blocking_source,
        CFTimeInterval secondsToWait)
{
    // Validate input paraemters
    RW_CF_TYPE_VALIDATE(sched_tasklet, rwsched_tasklet_ptr_t);
    rwsched_instance_ptr_t instance = sched_tasklet->instance;
    RW_CF_TYPE_VALIDATE(instance, rwsched_instance_ptr_t);

    SInt32 runloop_status;
    rwsched_CFRunLoopSourceRef return_source = NULL;
    //int i = 0;

    // Validate input parameters
    RW_CF_TYPE_VALIDATE(instance, rwsched_instance_ptr_t);

    // Make sure this tasklet is not already blocked
    RW_ASSERT(!sched_tasklet->blocking_mode.blocked);

    // Mark the tasklet as blocked
    RW_ZERO_VARIABLE(&sched_tasklet->blocking_mode);
    sched_tasklet->blocking_mode.blocked = TRUE;
    sched_tasklet->blocking_mode.cfsource = blocking_source;

    // Run the run loop in the default mode for up to the block interval specified
    // The run loop will be stopped if an event is avilable for the wakeupSource
    runloop_status = CFRunLoopRunInMode(instance->main_cfrunloop_mode, secondsToWait, false);

    // If the return value is kCFRunLoopRunTimedOut then the run loop timed out
    // If the return value is kCFRunLoopRunStopped then an event occured on the wakeupSource
    // If any other return value occurs, it is considered to be an error
    if (runloop_status == kCFRunLoopRunTimedOut) {
        CFRunLoopRef rl = CFRunLoopGetCurrent();
        return_source = blocking_source;
        if (CFRunLoopContainsSource(rl, blocking_source->cf_object, instance->main_cfrunloop_mode)) {
            return_source = NULL;
        }
    }
    else if (runloop_status == kCFRunLoopRunStopped || runloop_status == kCFRunLoopRunFinished) {
        return_source = blocking_source;
    }
    else {
        RW_CRASH();
    }

    g_rwresource_track_handle = sched_tasklet->rwresource_track_handle;
    g_tasklet_info = sched_tasklet;

    // relocate timers back to the main-mode
    rwsched_cfrunloop_relocate_timers_to_main_mode(sched_tasklet);

    g_rwresource_track_handle = sched_tasklet->rwresource_track_handle;
    g_tasklet_info = sched_tasklet;

    // relocate sources back to the main-mode
    rwsched_cfrunloop_relocate_sources_to_main_mode(sched_tasklet);

    //runloop_status = rwsched_instance_CFRunLoopRunInMode(instance, instance->deferred_cfrunloop_mode, 0.0, false);
    //RW_ASSERT(runloop_status == kCFRunLoopRunFinished || runloop_status == kCFRunLoopRunTimedOut);

    // Mark the tasklet as unblocked
    RW_ZERO_VARIABLE(&sched_tasklet->blocking_mode);

    g_rwresource_track_handle = sched_tasklet->rwresource_track_handle;
    g_tasklet_info = sched_tasklet;

    //Deliver any events on the dispatch sources
    rwsched_dispatch_unblock_sources(sched_tasklet);

    g_rwresource_track_handle = sched_tasklet->rwresource_track_handle;
    g_tasklet_info = sched_tasklet;

    // Return the runloop source that wokeup the blocking call, which is NULL if it timed out
    return return_source;
}
Example #9
0
/* CF_EXPORT */ void
CFNetServiceBrowserStopSearch(CFNetServiceBrowserRef b, CFStreamError* error) {

	__CFNetServiceBrowser* browser = (__CFNetServiceBrowser*)b;

	// By default, the error is marked as a cancel
	CFStreamError extra = {kCFStreamErrorDomainNetServices , kCFNetServicesErrorCancel};

	// Make sure error has a value.
	if (!error)
		error = &extra;

	// Lock down the browser
	__CFSpinLock(&(browser->_lock));

	// Make sure there is something to cancel.
	if (browser->_trigger) {

		CFRunLoopSourceContext ctxt = {
			0,									// version
			browser,							// info
			NULL,								// retain
			NULL,								// release
			NULL,								// copyDescription
			NULL,								// equal
			NULL,								// hash
			NULL,								// schedule
			NULL,								// cancel
			(void(*)(void*))(&_BrowserCancel)  // perform
		};

		// Remove the trigger from run loops and modes
		_CFTypeUnscheduleFromMultipleRunLoops(browser->_trigger, browser->_schedules);

		// Go ahead and invalidate the trigger
		_CFTypeInvalidate(browser->_trigger);

		// Release the trigger now.
		CFRelease(browser->_trigger);

		// Need to clean up the service discovery stuff if there is
		if (browser->_browse) {

			// Release the underlying service discovery reference
			DNSServiceRefDeallocate(browser->_browse);
			browser->_browse = NULL;

			// Dump all the lists of items.
			CFDictionaryRemoveAllValues(browser->_found);
			CFArrayRemoveAllValues(browser->_adds);
			CFArrayRemoveAllValues(browser->_removes);
		}

		// Copy the error into place
		memmove(&(browser->_error), error, sizeof(error[0]));

		// Create the cancel source
		browser->_trigger = CFRunLoopSourceCreate(CFGetAllocator(browser), 0, &ctxt);

		// If the cancel was created, need to schedule and signal it.
		if (browser->_trigger) {

			CFArrayRef schedules = browser->_schedules;
			CFIndex i, count = CFArrayGetCount(schedules);

			// Schedule the new trigger
			_CFTypeScheduleOnMultipleRunLoops(browser->_trigger, schedules);

			// Signal the cancel for immediate attention.
			CFRunLoopSourceSignal((CFRunLoopSourceRef)(browser->_trigger));

			// Make sure the signal can make it through
			for (i = 0; i < count; i += 2) {

				// Grab the run loop for checking
				CFRunLoopRef runloop = (CFRunLoopRef)CFArrayGetValueAtIndex(schedules, i);

				// If it's sleeping, need to further check it.
				if (CFRunLoopIsWaiting(runloop)) {

					// Grab the mode for further check
					CFStringRef mode = CFRunLoopCopyCurrentMode(runloop);

					if (mode) {

						// If the trigger is in the right mode, need to wake up the run loop.
						if (CFRunLoopContainsSource(runloop, (CFRunLoopSourceRef)(browser->_trigger), mode)) {
							CFRunLoopWakeUp(runloop);
						}

						// Don't need this anymore.
						CFRelease(mode);
					}
				}
			}
		}
	}

	// Unlock the browser
	__CFSpinUnlock(&(browser->_lock));
}
Example #10
0
//---------------------------------------------------------------------------
// wxJoystickThread::Entry
//
// Thread procedure
//
// Runs a CFRunLoop for polling. Basically, it sets the HID queue to
// call wxJoystickThread::HIDCallback in the context of this thread
// when something changes on the device. It polls as long as the user
// wants, or a certain amount if the user wants to "block". Note that
// we don't actually block here since this is in a secondary thread.
//---------------------------------------------------------------------------
void* wxJoystickThread::Entry()
{
    CFRunLoopSourceRef pRLSource = NULL;

    if ((*m_hid->GetQueue())->createAsyncEventSource(
                m_hid->GetQueue(), &pRLSource) != kIOReturnSuccess )
    {
        wxLogSysError(wxT("Couldn't create async event source"));
        return NULL;
    }

    wxASSERT(pRLSource != NULL);

    //attach runloop source to main run loop in thread
    CFRunLoopRef pRL = CFRunLoopGetCurrent();
    CFRunLoopAddSource(pRL, pRLSource, kCFRunLoopDefaultMode);
    wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) );


    if( (*m_hid->GetQueue())->setEventCallout(m_hid->GetQueue(),
            wxJoystickThread::HIDCallback, this, this) != kIOReturnSuccess )
    {
        wxLogSysError(wxT("Could not set event callout for queue"));
        return NULL;
    }

    if( (*m_hid->GetQueue())->start(m_hid->GetQueue()) != kIOReturnSuccess )
    {
        wxLogSysError(wxT("Could not start queue"));
        return NULL;
    }

    double dTime;

    while(true)
    {
        if (TestDestroy())
            break;

        if (m_polling)
            dTime = 0.0001 * m_polling;
        else
            dTime = 0.0001 * 10;  // check at least every 10 msec in "blocking" case

        //true just "handles and returns" - false forces it to stay the time
        //amount
#if 1
        CFRunLoopRunInMode(kCFRunLoopDefaultMode, dTime, true);
#else
        IOReturn ret = NULL;
        HIDCallback(this, ret, this, this);
        Sleep(3000);
#endif
    }

    wxASSERT( CFRunLoopContainsSource(pRL, pRLSource, kCFRunLoopDefaultMode) );

    CFRunLoopRemoveSource(pRL, pRLSource, kCFRunLoopDefaultMode);
    CFRelease(pRLSource);

    return NULL;
}