bool LatencyTestDeviceImpl::SetConfiguration(const OVR::LatencyTestConfiguration& configuration, bool waitFlag)
{  
    bool                result = false;
    ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();

    if (GetManagerImpl()->GetThreadId() != OVR::GetCurrentThreadId())
    {
        if (!waitFlag)
        {
            return queue->PushCall(this, &LatencyTestDeviceImpl::setConfiguration, configuration);
        }

        if (!queue->PushCallAndWaitResult(  this, 
            &LatencyTestDeviceImpl::setConfiguration,
            &result, 
            configuration))
        {
            return false;
        }
    }
    else
        return setConfiguration(configuration);

    return result;
}
void DeviceCommon::DeviceRelease()
{
    while(1)
    {
        UInt32 refCount = RefCount;
        OVR_ASSERT(refCount > 0);
        
        if (refCount == 1)
        {
            DeviceManagerImpl*  manager = pCreateDesc->GetManagerImpl();
            ThreadCommandQueue* queue   = manager->GetThreadQueue();

            // Enqueue ReleaseDevice for {1 -> 0} transition with no wait.
            // We pass our reference ownership into the queue to destroy.
            // It's in theory possible for another thread to re-steal our device reference,
            // but that is checked for atomically in DeviceManagerImpl::ReleaseDevice.
            if (!queue->PushCall(manager, &DeviceManagerImpl::ReleaseDevice_MgrThread,
                                          pCreateDesc->pDevice))
            {
                // PushCall shouldn't fail because background thread runs while manager is
                // alive and we are holding Manager alive through pParent chain.
                OVR_ASSERT(false);
            }

            // Warning! At his point everything, including manager, may be dead.
            break;
        }
        else if (RefCount.CompareAndSet_NoSync(refCount, refCount-1))
        {
            break;
        }
    }
}
bool LatencyTestDeviceImpl::GetConfiguration(OVR::LatencyTestConfiguration* configuration)
{  
    bool result = false;

	ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
    if (!pQueue->PushCallAndWaitResult(this, &LatencyTestDeviceImpl::getConfiguration, &result, configuration))
        return false;

    return result;
}
bool LatencyTestDeviceImpl::SetDisplay(const OVR::LatencyTestDisplay& display, bool waitFlag)
{
    bool                 result = false;
    ThreadCommandQueue * queue = GetManagerImpl()->GetThreadQueue();

    if (!waitFlag)
    {
        return queue->PushCall(this, &LatencyTestDeviceImpl::setDisplay, display);
    }

    if (!queue->PushCallAndWaitResult(  this, 
                                        &LatencyTestDeviceImpl::setDisplay,
                                        &result, 
                                        display))
    {
        return false;
    }

    return result;
}
bool LatencyTestDeviceImpl::SetStartTest(const Color& targetColor, bool waitFlag)
{
    bool                result = false;
    ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();

    if (!waitFlag)
    {
        return queue->PushCall(this, &LatencyTestDeviceImpl::setStartTest, targetColor);
    }

    if (!queue->PushCallAndWaitResult(  this, 
                                        &LatencyTestDeviceImpl::setStartTest,
                                        &result, 
                                        targetColor))
    {
        return false;
    }

    return result;
}
bool ThreadCommandQueueImpl::PushCommand(const ThreadCommand& command)
{
    ThreadCommand::NotifyEvent* completeEvent = 0;
    ThreadCommand::NotifyEvent* queueAvailableEvent = 0;

    // Repeat  writing command into buffer until it is available.    
    do {

        { // Lock Scope
            Lock::Locker lock(&QueueLock);

            if (queueAvailableEvent)
            {
                FreeNotifyEvent_NTS(queueAvailableEvent);
                queueAvailableEvent = 0;
            }

            // Don't allow any commands after PushExitCommand() is called.
            if (ExitEnqueued && !command.ExitFlag)
                return false;


            bool   bufferWasEmpty = CommandBuffer.IsEmpty();
            UByte* buffer = CommandBuffer.Write(command.GetSize());
            if  (buffer)
            {
                ThreadCommand* c = command.CopyConstruct(buffer);
                if (c->NeedsWait())
                    completeEvent = c->pEvent = AllocNotifyEvent_NTS();
                // Signal-waker consumer when we add data to buffer.
                if (bufferWasEmpty)
                    pQueue->OnPushNonEmpty_Locked();
                break;
            }

            queueAvailableEvent = AllocNotifyEvent_NTS();
            BlockedProducers.PushBack(queueAvailableEvent);
        } // Lock Scope

        queueAvailableEvent->Wait();

    } while(1);

    // Command was enqueued, wait if necessary.
    if (completeEvent)
    {
        completeEvent->Wait();
        Lock::Locker lock(&QueueLock);
        FreeNotifyEvent_NTS(completeEvent);
    }

    return true;
}
// Pops the next command from the thread queue, if any is available.
bool ThreadCommandQueueImpl::PopCommand(ThreadCommand::PopBuffer* popBuffer)
{    
    Lock::Locker lock(&QueueLock);

    UByte* buffer = CommandBuffer.ReadBegin();
    if (!buffer)
    {
        // Notify thread while in lock scope, enabling initialization of wait.
        pQueue->OnPopEmpty_Locked();
        return false;
    }

    popBuffer->InitFromBuffer(buffer);
    CommandBuffer.ReadEnd(popBuffer->GetSize());

    if (!BlockedProducers.IsEmpty())
    {
        ThreadCommand::NotifyEvent* queueAvailableEvent = BlockedProducers.GetFirst();
        queueAvailableEvent->RemoveNode();
        queueAvailableEvent->PulseEvent();
        // Event is freed later by waiter.
    }    
    return true;
}