From d46694c91c2bec4eb1e282c0c0101e6dab26e082 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 3 Jul 2013 09:16:03 -0700 Subject: SDK 0.2.3 --- LibOVR/Src/OVR_DeviceImpl.cpp | 1574 +++++++++++++++++++++-------------------- 1 file changed, 790 insertions(+), 784 deletions(-) (limited to 'LibOVR/Src/OVR_DeviceImpl.cpp') diff --git a/LibOVR/Src/OVR_DeviceImpl.cpp b/LibOVR/Src/OVR_DeviceImpl.cpp index 97cc2d4..80dc7d2 100644 --- a/LibOVR/Src/OVR_DeviceImpl.cpp +++ b/LibOVR/Src/OVR_DeviceImpl.cpp @@ -1,784 +1,790 @@ -/************************************************************************************ - -Filename : OVR_DeviceImpl.h -Content : Partial back-end independent implementation of Device interfaces -Created : October 10, 2012 -Authors : Michael Antonov - -Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. - -Use of this software is subject to the terms of the Oculus license -agreement provided at the time of installation or download, or which -otherwise accompanies this software in either electronic or hard copy form. - -*************************************************************************************/ - -#include "OVR_DeviceImpl.h" -#include "Kernel/OVR_Atomic.h" -#include "Kernel/OVR_Log.h" -#include "Kernel/OVR_System.h" - -#include "OVR_DeviceImpl.h" -#include "OVR_SensorImpl.h" - -namespace OVR { - - -//------------------------------------------------------------------------------------- -// ***** SharedLock - -// This is a general purpose globally shared Lock implementation that should probably be -// moved to Kernel. -// May in theory busy spin-wait if we hit contention on first lock creation, -// but this shouldn't matter in practice since Lock* should be cached. - - -enum { LockInitMarker = 0xFFFFFFFF }; - -Lock* SharedLock::GetLockAddRef() -{ - int oldUseCount; - - do { - oldUseCount = UseCount; - if (oldUseCount == LockInitMarker) - continue; - - if (oldUseCount == 0) - { - // Initialize marker - if (AtomicOps::CompareAndSet_Sync(&UseCount, 0, LockInitMarker)) - { - Construct(Buffer); - do { } - while (!AtomicOps::CompareAndSet_Sync(&UseCount, LockInitMarker, 1)); - return toLock(); - } - continue; - } - - } while (!AtomicOps::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1)); - - return toLock(); -} - -void SharedLock::ReleaseLock(Lock* plock) -{ - OVR_UNUSED(plock); - OVR_ASSERT((plock = toLock()) != 0); - - int oldUseCount; - - do { - oldUseCount = UseCount; - OVR_ASSERT(oldUseCount != LockInitMarker); - - if (oldUseCount == 1) - { - // Initialize marker - if (AtomicOps::CompareAndSet_Sync(&UseCount, 1, LockInitMarker)) - { - Destruct(toLock()); - - do { } - while (!AtomicOps::CompareAndSet_Sync(&UseCount, LockInitMarker, 0)); - - return; - } - continue; - } - - } while (!AtomicOps::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1)); -} - - - -//------------------------------------------------------------------------------------- -// ***** MessageHandler - -// Threading notes: -// The OnMessage() handler and SetMessageHandler are currently synchronized -// through a separately stored shared Lock object to avoid calling the handler -// from background thread while it's being removed. - -static SharedLock MessageHandlerSharedLock; - - -class MessageHandlerImpl -{ -public: - MessageHandlerImpl() - : pLock(MessageHandlerSharedLock.GetLockAddRef()) - { - } - ~MessageHandlerImpl() - { - MessageHandlerSharedLock.ReleaseLock(pLock); - pLock = 0; - } - - static MessageHandlerImpl* FromHandler(MessageHandler* handler) - { return (MessageHandlerImpl*)&handler->Internal; } - static const MessageHandlerImpl* FromHandler(const MessageHandler* handler) - { return (const MessageHandlerImpl*)&handler->Internal; } - - // This lock is held while calling a handler and when we are applied/ - // removed from a device. - Lock* pLock; - // List of device we are applied to. - List UseList; -}; - - -MessageHandlerRef::MessageHandlerRef(DeviceBase* device) - : pLock(MessageHandlerSharedLock.GetLockAddRef()), pDevice(device), pHandler(0) -{ -} - -MessageHandlerRef::~MessageHandlerRef() -{ - { - Lock::Locker lockScope(pLock); - if (pHandler) - { - pHandler = 0; - RemoveNode(); - } - } - MessageHandlerSharedLock.ReleaseLock(pLock); - pLock = 0; -} - -void MessageHandlerRef::SetHandler(MessageHandler* handler) -{ - OVR_ASSERT(!handler || - MessageHandlerImpl::FromHandler(handler)->pLock == pLock); - Lock::Locker lockScope(pLock); - SetHandler_NTS(handler); -} - -void MessageHandlerRef::SetHandler_NTS(MessageHandler* handler) -{ - if (pHandler != handler) - { - if (pHandler) - RemoveNode(); - pHandler = handler; - - if (handler) - { - MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(handler); - handlerImpl->UseList.PushBack(this); - } - // TBD: Call notifier on device? - } -} - - -MessageHandler::MessageHandler() -{ - OVR_COMPILER_ASSERT(sizeof(Internal) > sizeof(MessageHandlerImpl)); - Construct(Internal); -} - -MessageHandler::~MessageHandler() -{ - MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); - { - Lock::Locker lockedScope(handlerImpl->pLock); - OVR_ASSERT_LOG(handlerImpl->UseList.IsEmpty(), - ("~MessageHandler %p - Handler still active; call RemoveHandlerFromDevices", this)); - } - - Destruct(handlerImpl); -} - -bool MessageHandler::IsHandlerInstalled() const -{ - const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); - Lock::Locker lockedScope(handlerImpl->pLock); - return handlerImpl->UseList.IsEmpty() != true; -} - - -void MessageHandler::RemoveHandlerFromDevices() -{ - MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); - Lock::Locker lockedScope(handlerImpl->pLock); - - while(!handlerImpl->UseList.IsEmpty()) - { - MessageHandlerRef* use = handlerImpl->UseList.GetFirst(); - use->SetHandler_NTS(0); - } -} - -Lock* MessageHandler::GetHandlerLock() const -{ - const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); - return handlerImpl->pLock; -} - - -//------------------------------------------------------------------------------------- -// ***** DeviceBase - - -// Delegate relevant implementation to DeviceRectord to avoid re-implementation in -// every derived Device. -void DeviceBase::AddRef() -{ - getDeviceCommon()->DeviceAddRef(); -} -void DeviceBase::Release() -{ - getDeviceCommon()->DeviceRelease(); -} -DeviceBase* DeviceBase::GetParent() const -{ - return getDeviceCommon()->pParent.GetPtr(); -} -DeviceManager* DeviceBase::GetManager() const -{ - return getDeviceCommon()->pCreateDesc->GetManagerImpl(); -} - -void DeviceBase::SetMessageHandler(MessageHandler* handler) -{ - getDeviceCommon()->HandlerRef.SetHandler(handler); -} -MessageHandler* DeviceBase::GetMessageHandler() const -{ - return getDeviceCommon()->HandlerRef.GetHandler(); -} - -DeviceType DeviceBase::GetType() const -{ - return getDeviceCommon()->pCreateDesc->Type; -} - -bool DeviceBase::GetDeviceInfo(DeviceInfo* info) const -{ - return getDeviceCommon()->pCreateDesc->GetDeviceInfo(info); - //info->Name[0] = 0; - //return false; -} - -// returns the MessageHandler's lock -Lock* DeviceBase::GetHandlerLock() const -{ - return getDeviceCommon()->HandlerRef.GetLock(); -} - -// Derive DeviceManagerCreateDesc to provide abstract function implementation. -class DeviceManagerCreateDesc : public DeviceCreateDesc -{ -public: - DeviceManagerCreateDesc(DeviceFactory* factory) - : DeviceCreateDesc(factory, Device_Manager) { } - - // We don't need there on Manager since it isn't assigned to DeviceHandle. - virtual DeviceCreateDesc* Clone() const { return 0; } - virtual MatchResult MatchDevice(const DeviceCreateDesc&, - DeviceCreateDesc**) const { return Match_None; } - virtual DeviceBase* NewDeviceInstance() { return 0; } - virtual bool GetDeviceInfo(DeviceInfo*) const { return false; } -}; - -//------------------------------------------------------------------------------------- -// ***** DeviceManagerImpl - -DeviceManagerImpl::DeviceManagerImpl() - : DeviceImpl(CreateManagerDesc(), 0) - //,DeviceCreateDescList(pCreateDesc ? pCreateDesc->pLock : 0) -{ - if (pCreateDesc) - { - pCreateDesc->pLock->pManager = this; - } -} - -DeviceManagerImpl::~DeviceManagerImpl() -{ - // Shutdown must've been called. - OVR_ASSERT(!pCreateDesc->pDevice); - - // Remove all factories - while(!Factories.IsEmpty()) - { - DeviceFactory* factory = Factories.GetFirst(); - factory->RemovedFromManager(); - factory->RemoveNode(); - } -} - -DeviceCreateDesc* DeviceManagerImpl::CreateManagerDesc() -{ - DeviceCreateDesc* managerDesc = new DeviceManagerCreateDesc(0); - if (managerDesc) - { - managerDesc->pLock = *new DeviceManagerLock; - } - return managerDesc; -} - -bool DeviceManagerImpl::Initialize(DeviceBase* parent) -{ - OVR_UNUSED(parent); - if (!pCreateDesc || !pCreateDesc->pLock) - return false; - return true; -} - -void DeviceManagerImpl::Shutdown() -{ - // Remove all device descriptors from list while the lock is held. - // Some descriptors may survive longer due to handles. - while(!Devices.IsEmpty()) - { - DeviceCreateDesc* devDesc = Devices.GetFirst(); - OVR_ASSERT(!devDesc->pDevice); // Manager shouldn't be dying while Device exists. - devDesc->Enumerated = false; - devDesc->RemoveNode(); - devDesc->pNext = devDesc->pPrev = 0; - - if (devDesc->HandleCount == 0) - { - delete devDesc; - } - } - Devices.Clear(); - - // These must've been cleared by caller. - OVR_ASSERT(pCreateDesc->pDevice == 0); - OVR_ASSERT(pCreateDesc->pLock->pManager == 0); -} - - -// Callbacks for DeviceCreation/Release -DeviceBase* DeviceManagerImpl::CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent) -{ - // Calls to DeviceManagerImpl::CreateDevice are enqueued with wait while holding pManager, - // so 'this' must remain valid. - OVR_ASSERT(createDesc->pLock->pManager); - - Lock::Locker devicesLock(GetLock()); - - // If device already exists, just AddRef to it. - if (createDesc->pDevice) - { - createDesc->pDevice->AddRef(); - return createDesc->pDevice; - } - - if (!parent) - parent = this; - - DeviceBase* device = createDesc->NewDeviceInstance(); - - if (device) - { - if (device->getDeviceCommon()->Initialize(parent)) - { - createDesc->pDevice = device; - } - else - { - // Don't go through Release() to avoid PushCall behaviour, - // as it is not needed here. - delete device; - device = 0; - } - } - - return device; -} - -Void DeviceManagerImpl::ReleaseDevice_MgrThread(DeviceBase* device) -{ - // descKeepAlive will keep ManagerLock object alive as well, - // allowing us to exit gracefully. - Ptr descKeepAlive; - Lock::Locker devicesLock(GetLock()); - DeviceCommon* devCommon = device->getDeviceCommon(); - - while(1) - { - UInt32 refCount = devCommon->RefCount; - - if (refCount > 1) - { - if (devCommon->RefCount.CompareAndSet_NoSync(refCount, refCount-1)) - { - // We decreented from initial count higher then 1; - // nothing else to do. - return 0; - } - } - else if (devCommon->RefCount.CompareAndSet_NoSync(1, 0)) - { - // { 1 -> 0 } decrement succeded. Destroy this device. - break; - } - } - - // At this point, may be releasing the device manager itself. - // This does not matter, however, since shutdown logic is the same - // in both cases. DeviceManager::Shutdown with begin shutdown process for - // the internal manager thread, which will eventually destroy itself. - // TBD: Clean thread shutdown. - descKeepAlive = devCommon->pCreateDesc; - descKeepAlive->pDevice = 0; - devCommon->Shutdown(); - delete device; - return 0; -} - - - -Void DeviceManagerImpl::EnumerateAllFactoryDevices() -{ - // 1. Mark matching devices as NOT enumerated. - // 2. Call factory to enumerate all HW devices, adding any device that - // was not matched. - // 3. Remove non-matching devices. - - Lock::Locker deviceLock(GetLock()); - - DeviceCreateDesc* devDesc, *nextdevDesc; - - // 1. - for(devDesc = Devices.GetFirst(); - !Devices.IsNull(devDesc); devDesc = devDesc->pNext) - { - //if (devDesc->pFactory == factory) - devDesc->Enumerated = false; - } - - // 2. - DeviceFactory* factory = Factories.GetFirst(); - while(!Factories.IsNull(factory)) - { - EnumerateFactoryDevices(factory); - factory = factory->pNext; - } - - - // 3. - for(devDesc = Devices.GetFirst(); - !Devices.IsNull(devDesc); devDesc = nextdevDesc) - { - // In case 'devDesc' gets removed. - nextdevDesc = devDesc->pNext; - - // Note, device might be not enumerated since it is opened and - // in use! Do NOT notify 'device removed' in this case (!AB) - if (!devDesc->Enumerated) - { - // This deletes the devDesc for HandleCount == 0 due to Release in DeviceHandle. - CallOnDeviceRemoved(devDesc); - - /* - if (devDesc->HandleCount == 0) - { - // Device must be dead if it ever existed, since it AddRefs to us. - // ~DeviceCreateDesc removes its node from list. - OVR_ASSERT(!devDesc->pDevice); - delete devDesc; - } - */ - } - } - - return 0; -} - -Ptr DeviceManagerImpl::AddDevice_NeedsLock( - const DeviceCreateDesc& createDesc) -{ - // If found, mark as enumerated and we are done. - DeviceCreateDesc* descCandidate = 0; - - for(DeviceCreateDesc* devDesc = Devices.GetFirst(); - !Devices.IsNull(devDesc); devDesc = devDesc->pNext) - { - DeviceCreateDesc::MatchResult mr = devDesc->MatchDevice(createDesc, &descCandidate); - if (mr == DeviceCreateDesc::Match_Found) - { - devDesc->Enumerated = true; - if (!devDesc->pDevice) - CallOnDeviceAdded(devDesc); - return devDesc; - } - } - - // Update candidate (this may involve writing fields to HMDDevice createDesc). - if (descCandidate) - { - bool newDevice = false; - if (descCandidate->UpdateMatchedCandidate(createDesc, &newDevice)) - { - descCandidate->Enumerated = true; - if (!descCandidate->pDevice || newDevice) - CallOnDeviceAdded(descCandidate); - return descCandidate; - } - } - - // If not found, add new device. - // - This stores a new descriptor with - // {pDevice = 0, HandleCount = 1, Enumerated = true} - DeviceCreateDesc* desc = createDesc.Clone(); - desc->pLock = pCreateDesc->pLock; - Devices.PushBack(desc); - desc->Enumerated = true; - - CallOnDeviceAdded(desc); - - return desc; -} - -Ptr DeviceManagerImpl::FindDevice( - const String& path, - DeviceType deviceType) -{ - Lock::Locker deviceLock(GetLock()); - DeviceCreateDesc* devDesc; - - for (devDesc = Devices.GetFirst(); - !Devices.IsNull(devDesc); devDesc = devDesc->pNext) - { - if ((deviceType == Device_None || deviceType == devDesc->Type) && - devDesc->MatchDevice(path)) - return devDesc; - } - return NULL; -} - -Ptr DeviceManagerImpl::FindHIDDevice(const HIDDeviceDesc& hidDevDesc) -{ - Lock::Locker deviceLock(GetLock()); - DeviceCreateDesc* devDesc; - - for (devDesc = Devices.GetFirst(); - !Devices.IsNull(devDesc); devDesc = devDesc->pNext) - { - if (devDesc->MatchHIDDevice(hidDevDesc)) - return devDesc; - } - return NULL; -} - -void DeviceManagerImpl::DetectHIDDevice(const HIDDeviceDesc& hidDevDesc) -{ - Lock::Locker deviceLock(GetLock()); - DeviceFactory* factory = Factories.GetFirst(); - while(!Factories.IsNull(factory)) - { - if (factory->DetectHIDDevice(this, hidDevDesc)) - break; - factory = factory->pNext; - } - -} - -// Enumerates devices for a particular factory. -Void DeviceManagerImpl::EnumerateFactoryDevices(DeviceFactory* factory) -{ - - class FactoryEnumerateVisitor : public DeviceFactory::EnumerateVisitor - { - DeviceManagerImpl* pManager; - DeviceFactory* pFactory; - public: - FactoryEnumerateVisitor(DeviceManagerImpl* manager, DeviceFactory* factory) - : pManager(manager), pFactory(factory) { } - - virtual void Visit(const DeviceCreateDesc& createDesc) - { - pManager->AddDevice_NeedsLock(createDesc); - } - }; - - FactoryEnumerateVisitor newDeviceVisitor(this, factory); - factory->EnumerateDevices(newDeviceVisitor); - - - return 0; -} - - -DeviceEnumerator<> DeviceManagerImpl::EnumerateDevicesEx(const DeviceEnumerationArgs& args) -{ - Lock::Locker deviceLock(GetLock()); - - if (Devices.IsEmpty()) - return DeviceEnumerator<>(); - - DeviceCreateDesc* firstDeviceDesc = Devices.GetFirst(); - DeviceEnumerator<> e = enumeratorFromHandle(DeviceHandle(firstDeviceDesc), args); - - if (!args.MatchRule(firstDeviceDesc->Type, firstDeviceDesc->Enumerated)) - { - e.Next(); - } - - return e; -} - -//------------------------------------------------------------------------------------- -// ***** DeviceCommon - -void DeviceCommon::DeviceAddRef() -{ - RefCount++; -} - -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; - } - } -} - - - -//------------------------------------------------------------------------------------- -// ***** DeviceCreateDesc - - -void DeviceCreateDesc::AddRef() -{ - // Technically, HandleCount { 0 -> 1 } transition can only happen during Lock, - // but we leave this to caller to worry about (happens during enumeration). - HandleCount++; -} - -void DeviceCreateDesc::Release() -{ - while(1) - { - UInt32 handleCount = HandleCount; - // HandleCount must obviously be >= 1, since we are releasing it. - OVR_ASSERT(handleCount > 0); - - // {1 -> 0} transition may cause us to be destroyed, so require a lock. - if (handleCount == 1) - { - Ptr lockKeepAlive; - Lock::Locker deviceLockScope(GetLock()); - - if (!HandleCount.CompareAndSet_NoSync(handleCount, 0)) - continue; - - OVR_ASSERT(pDevice == 0); - - // Destroy *this if the manager was destroyed already, or Enumerated - // is false (device no longer available). - if (!GetManagerImpl() || !Enumerated) - { - lockKeepAlive = pLock; - - // Remove from manager list (only matters for !Enumerated). - if (pNext) - { - RemoveNode(); - pNext = pPrev = 0; - } - - delete this; - } - - // Available DeviceCreateDesc may survive with { HandleCount == 0 }, - // in case it might be enumerated again later. - break; - } - else if (HandleCount.CompareAndSet_NoSync(handleCount, handleCount-1)) - { - break; - } - } -} - -HMDDevice* HMDDevice::Disconnect(SensorDevice* psensor) -{ - if (!psensor) - return NULL; - - OVR::DeviceManager* manager = GetManager(); - if (manager) - { - //DeviceManagerImpl* mgrImpl = static_cast(manager); - Ptr desc = getDeviceCommon()->pCreateDesc; - if (desc) - { - class Visitor : public DeviceFactory::EnumerateVisitor - { - Ptr Desc; - public: - Visitor(DeviceCreateDesc* desc) : Desc(desc) {} - virtual void Visit(const DeviceCreateDesc& createDesc) - { - Lock::Locker lock(Desc->GetLock()); - Desc->UpdateMatchedCandidate(createDesc); - } - } visitor(desc); - //SensorDeviceImpl* sImpl = static_cast(psensor); - - SensorDisplayInfoImpl displayInfo; - - if (psensor->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize)) - { - displayInfo.Unpack(); - - // If we got display info, try to match / create HMDDevice as well - // so that sensor settings give preference. - if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) - { - SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, visitor); - } - } - } - } - return this; -} - -bool HMDDevice::IsDisconnected() const -{ - OVR::HMDInfo info; - GetDeviceInfo(&info); - // if strlen(info.DisplayDeviceName) == 0 then - // this HMD is 'fake' (created using sensor). - return (strlen(info.DisplayDeviceName) == 0); -} - - -} // namespace OVR - +/************************************************************************************ + +Filename : OVR_DeviceImpl.h +Content : Partial back-end independent implementation of Device interfaces +Created : October 10, 2012 +Authors : Michael Antonov + +Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. + +Use of this software is subject to the terms of the Oculus license +agreement provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +*************************************************************************************/ + +#include "OVR_DeviceImpl.h" +#include "Kernel/OVR_Atomic.h" +#include "Kernel/OVR_Log.h" +#include "Kernel/OVR_System.h" + +#include "OVR_DeviceImpl.h" +#include "OVR_SensorImpl.h" +#include "OVR_Profile.h" + +namespace OVR { + + +//------------------------------------------------------------------------------------- +// ***** SharedLock + +// This is a general purpose globally shared Lock implementation that should probably be +// moved to Kernel. +// May in theory busy spin-wait if we hit contention on first lock creation, +// but this shouldn't matter in practice since Lock* should be cached. + + +enum { LockInitMarker = 0xFFFFFFFF }; + +Lock* SharedLock::GetLockAddRef() +{ + int oldUseCount; + + do { + oldUseCount = UseCount; + if (oldUseCount == LockInitMarker) + continue; + + if (oldUseCount == 0) + { + // Initialize marker + if (AtomicOps::CompareAndSet_Sync(&UseCount, 0, LockInitMarker)) + { + Construct(Buffer); + do { } + while (!AtomicOps::CompareAndSet_Sync(&UseCount, LockInitMarker, 1)); + return toLock(); + } + continue; + } + + } while (!AtomicOps::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1)); + + return toLock(); +} + +void SharedLock::ReleaseLock(Lock* plock) +{ + OVR_UNUSED(plock); + OVR_ASSERT(plock == toLock()); + + int oldUseCount; + + do { + oldUseCount = UseCount; + OVR_ASSERT(oldUseCount != LockInitMarker); + + if (oldUseCount == 1) + { + // Initialize marker + if (AtomicOps::CompareAndSet_Sync(&UseCount, 1, LockInitMarker)) + { + Destruct(toLock()); + + do { } + while (!AtomicOps::CompareAndSet_Sync(&UseCount, LockInitMarker, 0)); + + return; + } + continue; + } + + } while (!AtomicOps::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1)); +} + + + +//------------------------------------------------------------------------------------- +// ***** MessageHandler + +// Threading notes: +// The OnMessage() handler and SetMessageHandler are currently synchronized +// through a separately stored shared Lock object to avoid calling the handler +// from background thread while it's being removed. + +static SharedLock MessageHandlerSharedLock; + + +class MessageHandlerImpl +{ +public: + MessageHandlerImpl() + : pLock(MessageHandlerSharedLock.GetLockAddRef()) + { + } + ~MessageHandlerImpl() + { + MessageHandlerSharedLock.ReleaseLock(pLock); + pLock = 0; + } + + static MessageHandlerImpl* FromHandler(MessageHandler* handler) + { return (MessageHandlerImpl*)&handler->Internal; } + static const MessageHandlerImpl* FromHandler(const MessageHandler* handler) + { return (const MessageHandlerImpl*)&handler->Internal; } + + // This lock is held while calling a handler and when we are applied/ + // removed from a device. + Lock* pLock; + // List of device we are applied to. + List UseList; +}; + + +MessageHandlerRef::MessageHandlerRef(DeviceBase* device) + : pLock(MessageHandlerSharedLock.GetLockAddRef()), pDevice(device), pHandler(0) +{ +} + +MessageHandlerRef::~MessageHandlerRef() +{ + { + Lock::Locker lockScope(pLock); + if (pHandler) + { + pHandler = 0; + RemoveNode(); + } + } + MessageHandlerSharedLock.ReleaseLock(pLock); + pLock = 0; +} + +void MessageHandlerRef::SetHandler(MessageHandler* handler) +{ + OVR_ASSERT(!handler || + MessageHandlerImpl::FromHandler(handler)->pLock == pLock); + Lock::Locker lockScope(pLock); + SetHandler_NTS(handler); +} + +void MessageHandlerRef::SetHandler_NTS(MessageHandler* handler) +{ + if (pHandler != handler) + { + if (pHandler) + RemoveNode(); + pHandler = handler; + + if (handler) + { + MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(handler); + handlerImpl->UseList.PushBack(this); + } + // TBD: Call notifier on device? + } +} + + +MessageHandler::MessageHandler() +{ + OVR_COMPILER_ASSERT(sizeof(Internal) > sizeof(MessageHandlerImpl)); + Construct(Internal); +} + +MessageHandler::~MessageHandler() +{ + MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); + { + Lock::Locker lockedScope(handlerImpl->pLock); + OVR_ASSERT_LOG(handlerImpl->UseList.IsEmpty(), + ("~MessageHandler %p - Handler still active; call RemoveHandlerFromDevices", this)); + } + + Destruct(handlerImpl); +} + +bool MessageHandler::IsHandlerInstalled() const +{ + const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); + Lock::Locker lockedScope(handlerImpl->pLock); + return handlerImpl->UseList.IsEmpty() != true; +} + + +void MessageHandler::RemoveHandlerFromDevices() +{ + MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); + Lock::Locker lockedScope(handlerImpl->pLock); + + while(!handlerImpl->UseList.IsEmpty()) + { + MessageHandlerRef* use = handlerImpl->UseList.GetFirst(); + use->SetHandler_NTS(0); + } +} + +Lock* MessageHandler::GetHandlerLock() const +{ + const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); + return handlerImpl->pLock; +} + + +//------------------------------------------------------------------------------------- +// ***** DeviceBase + + +// Delegate relevant implementation to DeviceRectord to avoid re-implementation in +// every derived Device. +void DeviceBase::AddRef() +{ + getDeviceCommon()->DeviceAddRef(); +} +void DeviceBase::Release() +{ + getDeviceCommon()->DeviceRelease(); +} +DeviceBase* DeviceBase::GetParent() const +{ + return getDeviceCommon()->pParent.GetPtr(); +} +DeviceManager* DeviceBase::GetManager() const +{ + return getDeviceCommon()->pCreateDesc->GetManagerImpl(); +} + +void DeviceBase::SetMessageHandler(MessageHandler* handler) +{ + getDeviceCommon()->HandlerRef.SetHandler(handler); +} +MessageHandler* DeviceBase::GetMessageHandler() const +{ + return getDeviceCommon()->HandlerRef.GetHandler(); +} + +DeviceType DeviceBase::GetType() const +{ + return getDeviceCommon()->pCreateDesc->Type; +} + +bool DeviceBase::GetDeviceInfo(DeviceInfo* info) const +{ + return getDeviceCommon()->pCreateDesc->GetDeviceInfo(info); + //info->Name[0] = 0; + //return false; +} + +// returns the MessageHandler's lock +Lock* DeviceBase::GetHandlerLock() const +{ + return getDeviceCommon()->HandlerRef.GetLock(); +} + +// Derive DeviceManagerCreateDesc to provide abstract function implementation. +class DeviceManagerCreateDesc : public DeviceCreateDesc +{ +public: + DeviceManagerCreateDesc(DeviceFactory* factory) + : DeviceCreateDesc(factory, Device_Manager) { } + + // We don't need there on Manager since it isn't assigned to DeviceHandle. + virtual DeviceCreateDesc* Clone() const { return 0; } + virtual MatchResult MatchDevice(const DeviceCreateDesc&, + DeviceCreateDesc**) const { return Match_None; } + virtual DeviceBase* NewDeviceInstance() { return 0; } + virtual bool GetDeviceInfo(DeviceInfo*) const { return false; } +}; + +//------------------------------------------------------------------------------------- +// ***** DeviceManagerImpl + +DeviceManagerImpl::DeviceManagerImpl() + : DeviceImpl(CreateManagerDesc(), 0) + //,DeviceCreateDescList(pCreateDesc ? pCreateDesc->pLock : 0) +{ + if (pCreateDesc) + { + pCreateDesc->pLock->pManager = this; + } +} + +DeviceManagerImpl::~DeviceManagerImpl() +{ + // Shutdown must've been called. + OVR_ASSERT(!pCreateDesc->pDevice); + + // Remove all factories + while(!Factories.IsEmpty()) + { + DeviceFactory* factory = Factories.GetFirst(); + factory->RemovedFromManager(); + factory->RemoveNode(); + } +} + +DeviceCreateDesc* DeviceManagerImpl::CreateManagerDesc() +{ + DeviceCreateDesc* managerDesc = new DeviceManagerCreateDesc(0); + if (managerDesc) + { + managerDesc->pLock = *new DeviceManagerLock; + } + return managerDesc; +} + +bool DeviceManagerImpl::Initialize(DeviceBase* parent) +{ + OVR_UNUSED(parent); + if (!pCreateDesc || !pCreateDesc->pLock) + return false; + + pProfileManager = *ProfileManager::Create(); + + return true; +} + +void DeviceManagerImpl::Shutdown() +{ + // Remove all device descriptors from list while the lock is held. + // Some descriptors may survive longer due to handles. + while(!Devices.IsEmpty()) + { + DeviceCreateDesc* devDesc = Devices.GetFirst(); + OVR_ASSERT(!devDesc->pDevice); // Manager shouldn't be dying while Device exists. + devDesc->Enumerated = false; + devDesc->RemoveNode(); + devDesc->pNext = devDesc->pPrev = 0; + + if (devDesc->HandleCount == 0) + { + delete devDesc; + } + } + Devices.Clear(); + + // These must've been cleared by caller. + OVR_ASSERT(pCreateDesc->pDevice == 0); + OVR_ASSERT(pCreateDesc->pLock->pManager == 0); + + pProfileManager.Clear(); +} + + +// Callbacks for DeviceCreation/Release +DeviceBase* DeviceManagerImpl::CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent) +{ + // Calls to DeviceManagerImpl::CreateDevice are enqueued with wait while holding pManager, + // so 'this' must remain valid. + OVR_ASSERT(createDesc->pLock->pManager); + + Lock::Locker devicesLock(GetLock()); + + // If device already exists, just AddRef to it. + if (createDesc->pDevice) + { + createDesc->pDevice->AddRef(); + return createDesc->pDevice; + } + + if (!parent) + parent = this; + + DeviceBase* device = createDesc->NewDeviceInstance(); + + if (device) + { + if (device->getDeviceCommon()->Initialize(parent)) + { + createDesc->pDevice = device; + } + else + { + // Don't go through Release() to avoid PushCall behaviour, + // as it is not needed here. + delete device; + device = 0; + } + } + + return device; +} + +Void DeviceManagerImpl::ReleaseDevice_MgrThread(DeviceBase* device) +{ + // descKeepAlive will keep ManagerLock object alive as well, + // allowing us to exit gracefully. + Ptr descKeepAlive; + Lock::Locker devicesLock(GetLock()); + DeviceCommon* devCommon = device->getDeviceCommon(); + + while(1) + { + UInt32 refCount = devCommon->RefCount; + + if (refCount > 1) + { + if (devCommon->RefCount.CompareAndSet_NoSync(refCount, refCount-1)) + { + // We decreented from initial count higher then 1; + // nothing else to do. + return 0; + } + } + else if (devCommon->RefCount.CompareAndSet_NoSync(1, 0)) + { + // { 1 -> 0 } decrement succeded. Destroy this device. + break; + } + } + + // At this point, may be releasing the device manager itself. + // This does not matter, however, since shutdown logic is the same + // in both cases. DeviceManager::Shutdown with begin shutdown process for + // the internal manager thread, which will eventually destroy itself. + // TBD: Clean thread shutdown. + descKeepAlive = devCommon->pCreateDesc; + descKeepAlive->pDevice = 0; + devCommon->Shutdown(); + delete device; + return 0; +} + + + +Void DeviceManagerImpl::EnumerateAllFactoryDevices() +{ + // 1. Mark matching devices as NOT enumerated. + // 2. Call factory to enumerate all HW devices, adding any device that + // was not matched. + // 3. Remove non-matching devices. + + Lock::Locker deviceLock(GetLock()); + + DeviceCreateDesc* devDesc, *nextdevDesc; + + // 1. + for(devDesc = Devices.GetFirst(); + !Devices.IsNull(devDesc); devDesc = devDesc->pNext) + { + //if (devDesc->pFactory == factory) + devDesc->Enumerated = false; + } + + // 2. + DeviceFactory* factory = Factories.GetFirst(); + while(!Factories.IsNull(factory)) + { + EnumerateFactoryDevices(factory); + factory = factory->pNext; + } + + + // 3. + for(devDesc = Devices.GetFirst(); + !Devices.IsNull(devDesc); devDesc = nextdevDesc) + { + // In case 'devDesc' gets removed. + nextdevDesc = devDesc->pNext; + + // Note, device might be not enumerated since it is opened and + // in use! Do NOT notify 'device removed' in this case (!AB) + if (!devDesc->Enumerated) + { + // This deletes the devDesc for HandleCount == 0 due to Release in DeviceHandle. + CallOnDeviceRemoved(devDesc); + + /* + if (devDesc->HandleCount == 0) + { + // Device must be dead if it ever existed, since it AddRefs to us. + // ~DeviceCreateDesc removes its node from list. + OVR_ASSERT(!devDesc->pDevice); + delete devDesc; + } + */ + } + } + + return 0; +} + +Ptr DeviceManagerImpl::AddDevice_NeedsLock( + const DeviceCreateDesc& createDesc) +{ + // If found, mark as enumerated and we are done. + DeviceCreateDesc* descCandidate = 0; + + for(DeviceCreateDesc* devDesc = Devices.GetFirst(); + !Devices.IsNull(devDesc); devDesc = devDesc->pNext) + { + DeviceCreateDesc::MatchResult mr = devDesc->MatchDevice(createDesc, &descCandidate); + if (mr == DeviceCreateDesc::Match_Found) + { + devDesc->Enumerated = true; + if (!devDesc->pDevice) + CallOnDeviceAdded(devDesc); + return devDesc; + } + } + + // Update candidate (this may involve writing fields to HMDDevice createDesc). + if (descCandidate) + { + bool newDevice = false; + if (descCandidate->UpdateMatchedCandidate(createDesc, &newDevice)) + { + descCandidate->Enumerated = true; + if (!descCandidate->pDevice || newDevice) + CallOnDeviceAdded(descCandidate); + return descCandidate; + } + } + + // If not found, add new device. + // - This stores a new descriptor with + // {pDevice = 0, HandleCount = 1, Enumerated = true} + DeviceCreateDesc* desc = createDesc.Clone(); + desc->pLock = pCreateDesc->pLock; + Devices.PushBack(desc); + desc->Enumerated = true; + + CallOnDeviceAdded(desc); + + return desc; +} + +Ptr DeviceManagerImpl::FindDevice( + const String& path, + DeviceType deviceType) +{ + Lock::Locker deviceLock(GetLock()); + DeviceCreateDesc* devDesc; + + for (devDesc = Devices.GetFirst(); + !Devices.IsNull(devDesc); devDesc = devDesc->pNext) + { + if ((deviceType == Device_None || deviceType == devDesc->Type) && + devDesc->MatchDevice(path)) + return devDesc; + } + return NULL; +} + +Ptr DeviceManagerImpl::FindHIDDevice(const HIDDeviceDesc& hidDevDesc) +{ + Lock::Locker deviceLock(GetLock()); + DeviceCreateDesc* devDesc; + + for (devDesc = Devices.GetFirst(); + !Devices.IsNull(devDesc); devDesc = devDesc->pNext) + { + if (devDesc->MatchHIDDevice(hidDevDesc)) + return devDesc; + } + return NULL; +} + +void DeviceManagerImpl::DetectHIDDevice(const HIDDeviceDesc& hidDevDesc) +{ + Lock::Locker deviceLock(GetLock()); + DeviceFactory* factory = Factories.GetFirst(); + while(!Factories.IsNull(factory)) + { + if (factory->DetectHIDDevice(this, hidDevDesc)) + break; + factory = factory->pNext; + } + +} + +// Enumerates devices for a particular factory. +Void DeviceManagerImpl::EnumerateFactoryDevices(DeviceFactory* factory) +{ + + class FactoryEnumerateVisitor : public DeviceFactory::EnumerateVisitor + { + DeviceManagerImpl* pManager; + DeviceFactory* pFactory; + public: + FactoryEnumerateVisitor(DeviceManagerImpl* manager, DeviceFactory* factory) + : pManager(manager), pFactory(factory) { } + + virtual void Visit(const DeviceCreateDesc& createDesc) + { + pManager->AddDevice_NeedsLock(createDesc); + } + }; + + FactoryEnumerateVisitor newDeviceVisitor(this, factory); + factory->EnumerateDevices(newDeviceVisitor); + + + return 0; +} + + +DeviceEnumerator<> DeviceManagerImpl::EnumerateDevicesEx(const DeviceEnumerationArgs& args) +{ + Lock::Locker deviceLock(GetLock()); + + if (Devices.IsEmpty()) + return DeviceEnumerator<>(); + + DeviceCreateDesc* firstDeviceDesc = Devices.GetFirst(); + DeviceEnumerator<> e = enumeratorFromHandle(DeviceHandle(firstDeviceDesc), args); + + if (!args.MatchRule(firstDeviceDesc->Type, firstDeviceDesc->Enumerated)) + { + e.Next(); + } + + return e; +} + +//------------------------------------------------------------------------------------- +// ***** DeviceCommon + +void DeviceCommon::DeviceAddRef() +{ + RefCount++; +} + +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; + } + } +} + + + +//------------------------------------------------------------------------------------- +// ***** DeviceCreateDesc + + +void DeviceCreateDesc::AddRef() +{ + // Technically, HandleCount { 0 -> 1 } transition can only happen during Lock, + // but we leave this to caller to worry about (happens during enumeration). + HandleCount++; +} + +void DeviceCreateDesc::Release() +{ + while(1) + { + UInt32 handleCount = HandleCount; + // HandleCount must obviously be >= 1, since we are releasing it. + OVR_ASSERT(handleCount > 0); + + // {1 -> 0} transition may cause us to be destroyed, so require a lock. + if (handleCount == 1) + { + Ptr lockKeepAlive; + Lock::Locker deviceLockScope(GetLock()); + + if (!HandleCount.CompareAndSet_NoSync(handleCount, 0)) + continue; + + OVR_ASSERT(pDevice == 0); + + // Destroy *this if the manager was destroyed already, or Enumerated + // is false (device no longer available). + if (!GetManagerImpl() || !Enumerated) + { + lockKeepAlive = pLock; + + // Remove from manager list (only matters for !Enumerated). + if (pNext) + { + RemoveNode(); + pNext = pPrev = 0; + } + + delete this; + } + + // Available DeviceCreateDesc may survive with { HandleCount == 0 }, + // in case it might be enumerated again later. + break; + } + else if (HandleCount.CompareAndSet_NoSync(handleCount, handleCount-1)) + { + break; + } + } +} + +HMDDevice* HMDDevice::Disconnect(SensorDevice* psensor) +{ + if (!psensor) + return NULL; + + OVR::DeviceManager* manager = GetManager(); + if (manager) + { + //DeviceManagerImpl* mgrImpl = static_cast(manager); + Ptr desc = getDeviceCommon()->pCreateDesc; + if (desc) + { + class Visitor : public DeviceFactory::EnumerateVisitor + { + Ptr Desc; + public: + Visitor(DeviceCreateDesc* desc) : Desc(desc) {} + virtual void Visit(const DeviceCreateDesc& createDesc) + { + Lock::Locker lock(Desc->GetLock()); + Desc->UpdateMatchedCandidate(createDesc); + } + } visitor(desc); + //SensorDeviceImpl* sImpl = static_cast(psensor); + + SensorDisplayInfoImpl displayInfo; + + if (psensor->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize)) + { + displayInfo.Unpack(); + + // If we got display info, try to match / create HMDDevice as well + // so that sensor settings give preference. + if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) + { + SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, visitor); + } + } + } + } + return this; +} + +bool HMDDevice::IsDisconnected() const +{ + OVR::HMDInfo info; + GetDeviceInfo(&info); + // if strlen(info.DisplayDeviceName) == 0 then + // this HMD is 'fake' (created using sensor). + return (strlen(info.DisplayDeviceName) == 0); +} + + +} // namespace OVR + -- cgit v1.2.3