int DeviceManagerThread::Run()
{
    ThreadCommand::PopBuffer command;

    SetThreadName("OVR::DeviceManagerThread");
    LogText("OVR::DeviceManagerThread - running (ThreadId=%p).\n", GetThreadId());
    

    while(!IsExiting())
    {
        // PopCommand will reset event on empty queue.
        if (PopCommand(&command))
        {
            command.Execute();
        }
        else
        {
            bool commands = 0;
            do
            {
                int n = poll(&PollFds[0], PollFds.GetSize(), -1);

                for (int i = 0; i < PollFds.GetSize(); i++)
                {
                    if (PollFds[i].revents & POLLERR)
                    {
                        OVR_DEBUG_LOG(("poll: error on [%d]: %d", i, PollFds[i].fd));
                    }
                    else if (PollFds[i].revents & POLLIN)
                    {
                        if (FdNotifiers[i])
                            FdNotifiers[i]->OnEvent(i, PollFds[i].fd);
                        else if (i == 0) // command
                        {
                            char dummy[128];                            
                            read(PollFds[i].fd, dummy, 128);
                            commands = 1;
                        }
                    }

                    if (PollFds[i].revents & POLLHUP)
                        PollFds[i].events = 0;

                    if (PollFds[i].revents != 0)
                    {
                        n--;
                        if (n == 0)
                            break;
                    }
                }                    
            } while (PollFds.GetSize() > 0 && !commands);
        }
    }

    LogText("OVR::DeviceManagerThread - exiting (ThreadId=%p).\n", GetThreadId());
    return 0;
}
int DeviceManagerThread::Run()
{
    ThreadCommand::PopBuffer command;

    SetThreadName("OVR::DeviceManagerThread");
    LogText("OVR::DeviceManagerThread - running (ThreadId=%p).\n", GetThreadId());
    
    // Signal to the parent thread that initialization has finished.
    StartupEvent.SetEvent();

    while(!IsExiting())
    {
        // PopCommand will reset event on empty queue.
        if (PopCommand(&command))
        {
            command.Execute();
        }
        else
        {
            bool commands = 0;
            do
            {
                int waitMs = -1;

                // If devices have time-dependent logic registered, get the longest wait
                // allowed based on current ticks.
                if (!TicksNotifiers.IsEmpty())
                {
                    UInt64 ticksMks = Timer::GetTicks();
                    int  waitAllowed;

                    for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
                    {
                        waitAllowed = (int)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
                        if (waitAllowed < waitMs)
                            waitMs = waitAllowed;
                    }
                }

                // wait until there is data available on one of the devices or the timeout expires
                int n = poll(&PollFds[0], PollFds.GetSize(), waitMs);

                if (n > 0)
                {
                    // Iterate backwards through the list so the ordering will not be
                    // affected if the called object gets removed during the callback
                    // Also, the HID data streams are located toward the back of the list
                    // and servicing them first will allow a disconnect to be handled
                    // and cleaned directly at the device first instead of the general HID monitor
                    for (int i=PollFds.GetSize()-1; i>=0; i--)
                    {
                        if (PollFds[i].revents & POLLERR)
                        {
                            OVR_DEBUG_LOG(("poll: error on [%d]: %d", i, PollFds[i].fd));
                        }
                        else if (PollFds[i].revents & POLLIN)
                        {
                            if (FdNotifiers[i])
                                FdNotifiers[i]->OnEvent(i, PollFds[i].fd);
                            else if (i == 0) // command
                            {
                                char dummy[128];
                                read(PollFds[i].fd, dummy, 128);
                                commands = 1;
                            }
                        }

                        if (PollFds[i].revents & POLLHUP)
                            PollFds[i].events = 0;

                        if (PollFds[i].revents != 0)
                        {
                            n--;
                            if (n == 0)
                                break;
                        }
                    }
                }
            } while (PollFds.GetSize() > 0 && !commands);
        }
    }

    LogText("OVR::DeviceManagerThread - exiting (ThreadId=%p).\n", GetThreadId());
    return 0;
}
int DeviceManagerThread::Run()
{

    SetThreadName("OVR::DeviceManagerThread");
    LogText("OVR::DeviceManagerThread - running (ThreadId=0x%p).\n", GetThreadId());

    // Store out the run loop ref.
    RunLoop = CFRunLoopGetCurrent();

    // Create a 'source' to enable us to signal the run loop to process the command queue.
    CFRunLoopSourceContext sourceContext;
    memset(&sourceContext, 0, sizeof(sourceContext));
    sourceContext.version = 0;
    sourceContext.info = this;
    sourceContext.perform = &staticCommandQueueSourceCallback;

    CommandQueueSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 , &sourceContext);

    CFRunLoopAddSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode);


    // Signal to the parent thread that initialization has finished.
    StartupEvent.SetEvent();


    ThreadCommand::PopBuffer command;
   
    while(!IsExiting())
    {
        // PopCommand will reset event on empty queue.
        if (PopCommand(&command))
        {
            command.Execute();
        }
        else
        {
            SInt32 exitReason = 0;
            do {

                UInt32 waitMs = INT_MAX;

                // If devices have time-dependent logic registered, get the longest wait
                // allowed based on current ticks.
                if (!TicksNotifiers.IsEmpty())
                {
                    UInt64 ticksMks = Timer::GetTicks();
                    UInt32  waitAllowed;

                    for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
                    {
                        waitAllowed = (UInt32)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
                        if (waitAllowed < waitMs)
                            waitMs = waitAllowed;
                    }
                }
                
                // Enter blocking run loop. We may continue until we timeout in which
                // case it's time to service the ticks. Or if commands arrive in the command
                // queue then the source callback will call 'CFRunLoopStop' causing this
                // to return.
                CFTimeInterval blockInterval = 0.001 * (double) waitMs;
                exitReason = CFRunLoopRunInMode(kCFRunLoopDefaultMode, blockInterval, false);

                if (exitReason == kCFRunLoopRunFinished)
                {
                    // Maybe this will occur during shutdown?
                    break;
                }
                else if (exitReason == kCFRunLoopRunStopped )
                {
                    // Commands need processing or we're being shutdown.
                    break;
                }
                else if (exitReason == kCFRunLoopRunTimedOut)
                {
                    // Timed out so that we can service our ticks callbacks.
                    continue;
                }
                else if (exitReason == kCFRunLoopRunHandledSource)
                {
                    // Should never occur since the last param when we call
                    // 'CFRunLoopRunInMode' is false.
                    OVR_ASSERT(false);
                    break;
                }
                else
                {
                    OVR_ASSERT_LOG(false, ("CFRunLoopRunInMode returned unexpected code"));
                    break;
                }
            }
            while(true);                    
        }
    }

                                   
    CFRunLoopRemoveSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode);
    CFRelease(CommandQueueSource);
    
    LogText("OVR::DeviceManagerThread - exiting (ThreadId=0x%p).\n", GetThreadId());

    return 0;
}