nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: PublicHeader: OVR nuclear@0: Filename : OVR_SharedMemory.h nuclear@0: Content : Inter-process shared memory subsystem nuclear@0: Created : June 1, 2014 nuclear@0: Notes : nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #ifndef OVR_SharedMemory_h nuclear@0: #define OVR_SharedMemory_h nuclear@0: nuclear@0: #include "OVR_Types.h" nuclear@0: #include "OVR_RefCount.h" nuclear@0: #include "OVR_Allocator.h" nuclear@0: #include "OVR_System.h" nuclear@0: nuclear@0: #ifdef OVR_SINGLE_PROCESS /* Everything running in one process usually for debugging */ nuclear@0: #define OVR_FAKE_SHAREDMEMORY /* Single-process version to avoid admin privs */ nuclear@0: #endif nuclear@0: nuclear@0: namespace OVR { nuclear@0: nuclear@0: class SharedMemoryInternal; // Opaque nuclear@0: nuclear@0: nuclear@0: // SharedMemory nuclear@0: // Note: Safe when used between 32-bit and 64-bit processes nuclear@0: class SharedMemory : public RefCountBase nuclear@0: { nuclear@0: friend class SharedMemoryFactory; nuclear@0: nuclear@0: OVR_NON_COPYABLE(SharedMemory); nuclear@0: nuclear@0: public: nuclear@0: // Only constructed by the SharedMemory Factory nuclear@0: SharedMemory(int size, void* data, SharedMemoryInternal* pInternal); nuclear@0: // Call close when it goes out of scope nuclear@0: ~SharedMemory(); nuclear@0: nuclear@0: // Modes for opening a new shared memory region nuclear@0: enum OpenMode nuclear@0: { nuclear@0: // Note: On Windows, Create* requires Administrator priviledges or running as a Service. nuclear@0: OpenMode_CreateOnly, // Must not already exist nuclear@0: OpenMode_OpenOnly, // Must already exist nuclear@0: OpenMode_CreateOrOpen // May exist or not nuclear@0: }; nuclear@0: nuclear@0: // Local access restrictions nuclear@0: enum AccessMode nuclear@0: { nuclear@0: AccessMode_ReadOnly, // Acquire read-only access nuclear@0: AccessMode_ReadWrite, // Acquire read or write access nuclear@0: }; nuclear@0: nuclear@0: // Remote access restrictions nuclear@0: enum RemoteMode nuclear@0: { nuclear@0: RemoteMode_ReadOnly, // Other processes will need to open in read-only mode nuclear@0: RemoteMode_ReadWrite // Other processes can open in read-write mode nuclear@0: }; nuclear@0: nuclear@0: // Modes for opening a new shared memory region nuclear@0: struct OpenParameters nuclear@0: { nuclear@0: OpenParameters() : nuclear@0: globalName(NULL), nuclear@0: minSizeBytes(0), nuclear@0: openMode(SharedMemory::OpenMode_CreateOrOpen), nuclear@0: remoteMode(SharedMemory::RemoteMode_ReadWrite), nuclear@0: accessMode(SharedMemory::AccessMode_ReadWrite) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: // Creation parameters nuclear@0: const char* globalName; // Name of the shared memory region nuclear@0: int minSizeBytes; // Minimum number of bytes to request nuclear@0: SharedMemory::OpenMode openMode; // Creating the file or opening the file? nuclear@0: SharedMemory::RemoteMode remoteMode; // When creating, what access should other processes get? nuclear@0: SharedMemory::AccessMode accessMode; // When opening/creating, what access should this process get? nuclear@0: }; nuclear@0: nuclear@0: public: nuclear@0: // Returns the size of the shared memory region nuclear@0: int GetSizeI() const nuclear@0: { nuclear@0: return Size; nuclear@0: } nuclear@0: nuclear@0: // Returns the process-local pointer to the shared memory region nuclear@0: // Note: This may be different on different processes nuclear@0: void* GetData() const nuclear@0: { nuclear@0: return Data; nuclear@0: } nuclear@0: nuclear@0: protected: nuclear@0: int Size; // How many shared bytes are shared at the pointer address? nuclear@0: void* Data; // Pointer to the shared memory region. nuclear@0: nuclear@0: // Hidden implementation class for OS-specific behavior nuclear@0: SharedMemoryInternal* Internal; nuclear@0: nuclear@0: // Close and cleanup the shared memory region nuclear@0: // Note: This is called on destruction nuclear@0: void Close(); nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // SharedMemoryFactory nuclear@0: class SharedMemoryFactory : public NewOverrideBase, public SystemSingletonBase nuclear@0: { nuclear@0: OVR_DECLARE_SINGLETON(SharedMemoryFactory); nuclear@0: nuclear@0: public: nuclear@0: // Construct a SharedMemory object. nuclear@0: // Note: The new object is reference-counted so it should be stored with Ptr<>. Initial reference count is 1. nuclear@0: Ptr Open(const SharedMemory::OpenParameters&); nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: // A shared object nuclear@0: // Its constructor will be called when creating a writer nuclear@0: // Its destructor will not be called nuclear@0: template nuclear@0: class ISharedObject : public NewOverrideBase nuclear@0: { nuclear@0: public: nuclear@0: static const int RegionSize = (int)sizeof(SharedType); nuclear@0: nuclear@0: protected: nuclear@0: Ptr pSharedMemory; nuclear@0: nuclear@0: bool Open(const char* name, bool readOnly) nuclear@0: { nuclear@0: // Configure open parameters based on read-only mode nuclear@0: SharedMemory::OpenParameters params; nuclear@0: nuclear@0: // FIXME: This is a hack. We currently need to allow clients to open this for read-write even nuclear@0: // though they only need read-only access. This is because in the first 0.4 release the nuclear@0: // LocklessUpdater class technically writes to it (increments by 0) to read from the space. nuclear@0: // This was quickly corrected in 0.4.1 and we are waiting for the right time to disallow write nuclear@0: // access when everyone upgrades to 0.4.1+. nuclear@0: //params.remoteMode = SharedMemory::RemoteMode_ReadOnly; nuclear@0: params.remoteMode = SharedMemory::RemoteMode_ReadWrite; nuclear@0: nuclear@0: params.globalName = name; nuclear@0: params.accessMode = readOnly ? SharedMemory::AccessMode_ReadOnly : SharedMemory::AccessMode_ReadWrite; nuclear@0: params.minSizeBytes = RegionSize; nuclear@0: params.openMode = readOnly ? SharedMemory::OpenMode_OpenOnly : SharedMemory::OpenMode_CreateOrOpen; nuclear@0: nuclear@0: // Attempt to open the shared memory file nuclear@0: pSharedMemory = SharedMemoryFactory::GetInstance()->Open(params); nuclear@0: nuclear@0: // If it was not able to be opened, nuclear@0: if (pSharedMemory && pSharedMemory->GetSizeI() >= RegionSize && pSharedMemory->GetData()) nuclear@0: { nuclear@0: // If writing, nuclear@0: if (!readOnly) nuclear@0: { nuclear@0: // Construct the object also nuclear@0: Construct(pSharedMemory->GetData()); nuclear@0: } nuclear@0: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: SharedType* Get() const nuclear@0: { nuclear@0: if (!pSharedMemory) nuclear@0: { nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: void* data = pSharedMemory->GetData(); nuclear@0: if (!data) nuclear@0: { nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: return reinterpret_cast(data); nuclear@0: } nuclear@0: }; nuclear@0: nuclear@0: // Writer specialized shared object: Ctor will be called on Open() nuclear@0: template nuclear@0: class SharedObjectWriter : public ISharedObject nuclear@0: { nuclear@0: public: nuclear@0: OVR_FORCE_INLINE bool Open(const char* name) nuclear@0: { nuclear@0: return ISharedObject::Open(name, false); nuclear@0: } nuclear@0: OVR_FORCE_INLINE SharedType* Get() nuclear@0: { nuclear@0: return ISharedObject::Get(); nuclear@0: } nuclear@0: }; nuclear@0: nuclear@0: // Reader specialized shared object: Ctor will not be called nuclear@0: template nuclear@0: class SharedObjectReader : public ISharedObject nuclear@0: { nuclear@0: public: nuclear@0: OVR_FORCE_INLINE bool Open(const char* name) nuclear@0: { nuclear@0: return ISharedObject::Open(name, true); nuclear@0: } nuclear@0: OVR_FORCE_INLINE const SharedType* Get() const nuclear@0: { nuclear@0: return ISharedObject::Get(); nuclear@0: } nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: } // namespace OVR nuclear@0: nuclear@0: #endif // OVR_SharedMemory_h