DeviceBase* DeviceHandle::CreateDevice() { if (!pImpl) return 0; DeviceBase* device = 0; Ptr<DeviceManagerImpl> manager= 0; // Since both manager and device pointers can only be destroyed during a lock, // hold it while checking for availability. // AddRef to manager so that it doesn't get released on us. { Lock::Locker deviceLockScope(pImpl->GetLock()); if (pImpl->pDevice) { pImpl->pDevice->AddRef(); return device; } manager = pImpl->GetManagerImpl(); } if (manager) { // Queue up a CreateDevice request. This fills in '&device' with AddRefed value, // or keep it at null. manager->GetThreadQueue()->PushCallAndWaitResult( manager.GetPtr(), &DeviceManagerImpl::CreateDevice_MgrThread, &device, pImpl, (DeviceBase*)0); } return device; }
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<DeviceManagerLock> 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; } } }