ovr_sdk

annotate LibOVR/Src/Kernel/OVR_SharedMemory.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
rev   line source
nuclear@0 1 /************************************************************************************
nuclear@0 2
nuclear@0 3 Filename : OVR_SharedMemory.cpp
nuclear@0 4 Content : Inter-process shared memory subsystem
nuclear@0 5 Created : June 1, 2014
nuclear@0 6 Notes :
nuclear@0 7
nuclear@0 8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 9
nuclear@0 10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 11 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 12 which is provided at the time of installation or download, or which
nuclear@0 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 14
nuclear@0 15 You may obtain a copy of the License at
nuclear@0 16
nuclear@0 17 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 18
nuclear@0 19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 20 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 22 See the License for the specific language governing permissions and
nuclear@0 23 limitations under the License.
nuclear@0 24
nuclear@0 25 ************************************************************************************/
nuclear@0 26
nuclear@0 27 #include "OVR_SharedMemory.h"
nuclear@0 28 #include "OVR_Atomic.h"
nuclear@0 29 #include "OVR_Log.h"
nuclear@0 30 #include "OVR_String.h"
nuclear@0 31 #include "OVR_Array.h"
nuclear@0 32
nuclear@0 33 #if defined(OVR_OS_WIN32) && !defined(OVR_FAKE_SHAREDMEMORY)
nuclear@0 34 #include <Sddl.h> // ConvertStringSecurityDescriptorToSecurityDescriptor
nuclear@0 35 #endif // OVR_OS_WIN32
nuclear@0 36
nuclear@0 37 #if (defined(OVR_OS_LINUX) || defined(OVR_OS_MAC)) && !defined(OVR_FAKE_SHAREDMEMORY)
nuclear@0 38 #include <sys/mman.h> // shm_open(), mmap()
nuclear@0 39 #include <errno.h> // error results for mmap
nuclear@0 40 #include <sys/stat.h> // mode constants
nuclear@0 41 #include <fcntl.h> // O_ constants
nuclear@0 42 #include <unistd.h> // close()
nuclear@0 43 #endif // OVR_OS_LINUX
nuclear@0 44
nuclear@0 45 OVR_DEFINE_SINGLETON(OVR::SharedMemoryFactory);
nuclear@0 46
nuclear@0 47 namespace OVR {
nuclear@0 48
nuclear@0 49
nuclear@0 50 //// Fake version
nuclear@0 51
nuclear@0 52 #if defined(OVR_FAKE_SHAREDMEMORY)
nuclear@0 53
nuclear@0 54 class FakeMemoryBlock : public RefCountBase<FakeMemoryBlock>
nuclear@0 55 {
nuclear@0 56 String Name;
nuclear@0 57 char* Data;
nuclear@0 58 int SizeBytes;
nuclear@0 59 int References;
nuclear@0 60
nuclear@0 61 public:
nuclear@0 62 FakeMemoryBlock(const String& name, int size) :
nuclear@0 63 Name(name),
nuclear@0 64 Data(NULL),
nuclear@0 65 SizeBytes(size),
nuclear@0 66 References(1)
nuclear@0 67 {
nuclear@0 68 Data = new char[SizeBytes];
nuclear@0 69 }
nuclear@0 70 ~FakeMemoryBlock()
nuclear@0 71 {
nuclear@0 72 delete[] Data;
nuclear@0 73 }
nuclear@0 74
nuclear@0 75 bool IsNamed(const String& name)
nuclear@0 76 {
nuclear@0 77 return Name.CompareNoCase(name) == 0;
nuclear@0 78 }
nuclear@0 79 void* GetData()
nuclear@0 80 {
nuclear@0 81 return Data;
nuclear@0 82 }
nuclear@0 83 int GetSizeI()
nuclear@0 84 {
nuclear@0 85 return SizeBytes;
nuclear@0 86 }
nuclear@0 87 void IncrementReferences()
nuclear@0 88 {
nuclear@0 89 ++References;
nuclear@0 90 }
nuclear@0 91 bool DecrementReferences()
nuclear@0 92 {
nuclear@0 93 return --References <= 0;
nuclear@0 94 }
nuclear@0 95 };
nuclear@0 96
nuclear@0 97 class SharedMemoryInternal : public NewOverrideBase
nuclear@0 98 {
nuclear@0 99 public:
nuclear@0 100 void* FileView;
nuclear@0 101 Ptr<FakeMemoryBlock> Block;
nuclear@0 102
nuclear@0 103 void Close();
nuclear@0 104
nuclear@0 105 SharedMemoryInternal(FakeMemoryBlock* block) :
nuclear@0 106 Block(block)
nuclear@0 107 {
nuclear@0 108 FileView = Block->GetData();
nuclear@0 109 }
nuclear@0 110 ~SharedMemoryInternal()
nuclear@0 111 {
nuclear@0 112 Close();
nuclear@0 113 }
nuclear@0 114
nuclear@0 115 static SharedMemoryInternal* CreateSharedMemory(const SharedMemory::OpenParameters& params);
nuclear@0 116 };
nuclear@0 117
nuclear@0 118
nuclear@0 119 //// FakeMemoryManager
nuclear@0 120
nuclear@0 121 class FakeMemoryManager : public NewOverrideBase, public SystemSingletonBase<FakeMemoryManager>
nuclear@0 122 {
nuclear@0 123 OVR_DECLARE_SINGLETON(FakeMemoryManager);
nuclear@0 124
nuclear@0 125 Lock FakeLock;
nuclear@0 126 Array< Ptr<FakeMemoryBlock> > FakeArray;
nuclear@0 127
nuclear@0 128 public:
nuclear@0 129 SharedMemoryInternal* Open(const char *name, int bytes, bool openOnly)
nuclear@0 130 {
nuclear@0 131 Lock::Locker locker(&FakeLock);
nuclear@0 132
nuclear@0 133 const int count = FakeArray.GetSizeI();
nuclear@0 134 for (int ii = 0; ii < count; ++ii)
nuclear@0 135 {
nuclear@0 136 if (FakeArray[ii]->IsNamed(name))
nuclear@0 137 {
nuclear@0 138 FakeArray[ii]->IncrementReferences();
nuclear@0 139 return new SharedMemoryInternal(FakeArray[ii]);
nuclear@0 140 }
nuclear@0 141 }
nuclear@0 142
nuclear@0 143 if (openOnly)
nuclear@0 144 {
nuclear@0 145 return NULL;
nuclear@0 146 }
nuclear@0 147
nuclear@0 148 Ptr<FakeMemoryBlock> data = *new FakeMemoryBlock(name, bytes);
nuclear@0 149 FakeArray.PushBack(data);
nuclear@0 150 return new SharedMemoryInternal(data);
nuclear@0 151 }
nuclear@0 152
nuclear@0 153 void Free(FakeMemoryBlock* block)
nuclear@0 154 {
nuclear@0 155 Lock::Locker locker(&FakeLock);
nuclear@0 156
nuclear@0 157 const int count = FakeArray.GetSizeI();
nuclear@0 158 for (int ii = 0; ii < count; ++ii)
nuclear@0 159 {
nuclear@0 160 if (FakeArray[ii].GetPtr() == block)
nuclear@0 161 {
nuclear@0 162 // If the reference count hit zero,
nuclear@0 163 if (FakeArray[ii]->DecrementReferences())
nuclear@0 164 {
nuclear@0 165 // Toast
nuclear@0 166 FakeArray.RemoveAtUnordered(ii);
nuclear@0 167 }
nuclear@0 168 break;
nuclear@0 169 }
nuclear@0 170 }
nuclear@0 171 }
nuclear@0 172 };
nuclear@0 173
nuclear@0 174 FakeMemoryManager::FakeMemoryManager()
nuclear@0 175 {
nuclear@0 176 PushDestroyCallbacks();
nuclear@0 177 }
nuclear@0 178
nuclear@0 179 FakeMemoryManager::~FakeMemoryManager()
nuclear@0 180 {
nuclear@0 181 OVR_ASSERT(FakeArray.GetSizeI() == 0);
nuclear@0 182 }
nuclear@0 183
nuclear@0 184 void FakeMemoryManager::OnSystemDestroy()
nuclear@0 185 {
nuclear@0 186 delete this;
nuclear@0 187 }
nuclear@0 188
nuclear@0 189
nuclear@0 190 } // namespace OVR
nuclear@0 191
nuclear@0 192 OVR_DEFINE_SINGLETON(FakeMemoryManager);
nuclear@0 193
nuclear@0 194 namespace OVR {
nuclear@0 195
nuclear@0 196
nuclear@0 197 void SharedMemoryInternal::Close()
nuclear@0 198 {
nuclear@0 199 FakeMemoryManager::GetInstance()->Free(Block);
nuclear@0 200 Block.Clear();
nuclear@0 201 }
nuclear@0 202
nuclear@0 203 SharedMemoryInternal* SharedMemoryInternal::CreateSharedMemory(const SharedMemory::OpenParameters& params)
nuclear@0 204 {
nuclear@0 205 return FakeMemoryManager::GetInstance()->Open(params.globalName, params.minSizeBytes, params.openMode == SharedMemory::OpenMode_OpenOnly);
nuclear@0 206 }
nuclear@0 207
nuclear@0 208 #endif
nuclear@0 209
nuclear@0 210
nuclear@0 211 //// Windows version
nuclear@0 212
nuclear@0 213 #if defined(OVR_OS_WIN32) && !defined(OVR_FAKE_SHAREDMEMORY)
nuclear@0 214
nuclear@0 215 #pragma comment(lib, "advapi32.lib")
nuclear@0 216
nuclear@0 217 // Hidden implementation class for OS-specific behavior
nuclear@0 218 class SharedMemoryInternal : public NewOverrideBase
nuclear@0 219 {
nuclear@0 220 public:
nuclear@0 221 HANDLE FileMapping;
nuclear@0 222 void* FileView;
nuclear@0 223
nuclear@0 224 SharedMemoryInternal(HANDLE fileMapping, void* fileView) :
nuclear@0 225 FileMapping(fileMapping),
nuclear@0 226 FileView(fileView)
nuclear@0 227 {
nuclear@0 228 }
nuclear@0 229
nuclear@0 230 ~SharedMemoryInternal()
nuclear@0 231 {
nuclear@0 232 // If file view is set,
nuclear@0 233 if (FileView)
nuclear@0 234 {
nuclear@0 235 UnmapViewOfFile(FileView);
nuclear@0 236 FileView = NULL;
nuclear@0 237 }
nuclear@0 238
nuclear@0 239 // If file mapping is set,
nuclear@0 240 if (FileMapping != NULL)
nuclear@0 241 {
nuclear@0 242 CloseHandle(FileMapping);
nuclear@0 243 FileMapping = NULL;
nuclear@0 244 }
nuclear@0 245 }
nuclear@0 246
nuclear@0 247 static SharedMemoryInternal* DoFileMap(HANDLE hFileMapping, const char* fileName, bool openReadOnly, int minSize);
nuclear@0 248 static SharedMemoryInternal* AttemptOpenSharedMemory(const char* fileName, int minSize, bool openReadOnly);
nuclear@0 249 static SharedMemoryInternal* AttemptCreateSharedMemory(const char* fileName, int minSize, bool openReadOnly, bool allowRemoteWrite);
nuclear@0 250 static SharedMemoryInternal* CreateSharedMemory(const SharedMemory::OpenParameters& params);
nuclear@0 251 };
nuclear@0 252
nuclear@0 253 SharedMemoryInternal* SharedMemoryInternal::DoFileMap(HANDLE hFileMapping, const char* fileName, bool openReadOnly, int minSize)
nuclear@0 254 {
nuclear@0 255 // Interpret the access mode as a map desired access code
nuclear@0 256 DWORD mapDesiredAccess = openReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE;
nuclear@0 257
nuclear@0 258 // Map view of the file to this process
nuclear@0 259 void* pFileView = MapViewOfFile(hFileMapping, mapDesiredAccess, 0, 0, minSize);
nuclear@0 260
nuclear@0 261 // If mapping could not be created,
nuclear@0 262 if (!pFileView)
nuclear@0 263 {
nuclear@0 264 CloseHandle(hFileMapping);
nuclear@0 265
nuclear@0 266 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to map view of file for %s error code = %d", fileName, GetLastError()));
nuclear@0 267 OVR_UNUSED(fileName);
nuclear@0 268 return NULL;
nuclear@0 269 }
nuclear@0 270
nuclear@0 271 // Create internal representation
nuclear@0 272 SharedMemoryInternal* pimple = new SharedMemoryInternal(hFileMapping, pFileView);
nuclear@0 273
nuclear@0 274 // If memory allocation fails,
nuclear@0 275 if (!pimple)
nuclear@0 276 {
nuclear@0 277 UnmapViewOfFile(pFileView);
nuclear@0 278 CloseHandle(hFileMapping);
nuclear@0 279
nuclear@0 280 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Out of memory"));
nuclear@0 281 return NULL;
nuclear@0 282 }
nuclear@0 283
nuclear@0 284 return pimple;
nuclear@0 285 }
nuclear@0 286
nuclear@0 287 SharedMemoryInternal* SharedMemoryInternal::AttemptOpenSharedMemory(const char* fileName, int minSize, bool openReadOnly)
nuclear@0 288 {
nuclear@0 289 // Interpret the access mode as a map desired access code
nuclear@0 290 DWORD mapDesiredAccess = openReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE;
nuclear@0 291
nuclear@0 292 // Open file mapping
nuclear@0 293 HANDLE hFileMapping = OpenFileMappingA(mapDesiredAccess, TRUE, fileName);
nuclear@0 294
nuclear@0 295 // If file was mapped unsuccessfully,
nuclear@0 296 if (NULL == hFileMapping)
nuclear@0 297 {
nuclear@0 298 OVR_DEBUG_LOG(("[SharedMemory] WARNING: Unable to open file mapping for %s error code = %d (not necessarily bad)", fileName, GetLastError()));
nuclear@0 299 return NULL;
nuclear@0 300 }
nuclear@0 301
nuclear@0 302 // Map the file
nuclear@0 303 return DoFileMap(hFileMapping, fileName, openReadOnly, minSize);
nuclear@0 304 }
nuclear@0 305
nuclear@0 306 SharedMemoryInternal* SharedMemoryInternal::AttemptCreateSharedMemory(const char* fileName, int minSize, bool openReadOnly, bool allowRemoteWrite)
nuclear@0 307 {
nuclear@0 308 // Prepare a SECURITY_ATTRIBUTES object
nuclear@0 309 SECURITY_ATTRIBUTES security;
nuclear@0 310 ZeroMemory(&security, sizeof(security));
nuclear@0 311 security.nLength = sizeof(security);
nuclear@0 312
nuclear@0 313 // Security descriptor by DACL strings:
nuclear@0 314 // ACE strings grant Allow(A), Object/Contains Inheritance (OICI) of:
nuclear@0 315 // + Grant All (GA) to System (SY)
nuclear@0 316 // + Grant All (GA) to Built-in Administrators (BA)
nuclear@0 317 // + Grant Read-Only (GR) or Read-Write (GWGR) to Interactive Users (IU) - ie. games
nuclear@0 318 static const char* DACLString_ReadOnly = "D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GR;;;IU)";
nuclear@0 319 static const char* DACLString_ReadWrite = "D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWGR;;;IU)";
nuclear@0 320
nuclear@0 321 // Select the remote process access mode
nuclear@0 322 const char* remoteAccessString =
nuclear@0 323 allowRemoteWrite ? DACLString_ReadWrite : DACLString_ReadOnly;
nuclear@0 324
nuclear@0 325 // Attempt to convert access string to security attributes
nuclear@0 326 // Note: This will allocate the security descriptor with LocalAlloc() and must be freed later
nuclear@0 327 BOOL bConvertOkay = ConvertStringSecurityDescriptorToSecurityDescriptorA(
nuclear@0 328 remoteAccessString, SDDL_REVISION_1, &security.lpSecurityDescriptor, NULL);
nuclear@0 329
nuclear@0 330 // If conversion fails,
nuclear@0 331 if (!bConvertOkay)
nuclear@0 332 {
nuclear@0 333 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to convert access string, error code = %d", GetLastError()));
nuclear@0 334 return NULL;
nuclear@0 335 }
nuclear@0 336
nuclear@0 337 // Interpret the access mode as a page protection code
nuclear@0 338 int pageProtectCode = openReadOnly ? PAGE_READONLY : PAGE_READWRITE;
nuclear@0 339
nuclear@0 340 // Attempt to create a file mapping
nuclear@0 341 HANDLE hFileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE, // From page file
nuclear@0 342 &security, // Security attributes
nuclear@0 343 pageProtectCode, // Read-only?
nuclear@0 344 0, // High word for size = 0
nuclear@0 345 minSize, // Low word for size
nuclear@0 346 fileName); // Name of global shared memory file
nuclear@0 347
nuclear@0 348 // Free the security descriptor buffer
nuclear@0 349 LocalFree(security.lpSecurityDescriptor);
nuclear@0 350
nuclear@0 351 // If mapping could not be created,
nuclear@0 352 if (NULL == hFileMapping)
nuclear@0 353 {
nuclear@0 354 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to create file mapping for %s error code = %d", fileName, GetLastError()));
nuclear@0 355 return NULL;
nuclear@0 356 }
nuclear@0 357
nuclear@0 358 #ifndef OVR_ALLOW_CREATE_FILE_MAPPING_IF_EXISTS
nuclear@0 359 // If the file mapping already exists,
nuclear@0 360 if (GetLastError() == ERROR_ALREADY_EXISTS)
nuclear@0 361 {
nuclear@0 362 CloseHandle(hFileMapping);
nuclear@0 363
nuclear@0 364 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: File mapping at %s already exists", fileName));
nuclear@0 365 return NULL;
nuclear@0 366 }
nuclear@0 367 #endif
nuclear@0 368
nuclear@0 369 // Map the file
nuclear@0 370 return DoFileMap(hFileMapping, fileName, openReadOnly, minSize);
nuclear@0 371 }
nuclear@0 372
nuclear@0 373 SharedMemoryInternal* SharedMemoryInternal::CreateSharedMemory(const SharedMemory::OpenParameters& params)
nuclear@0 374 {
nuclear@0 375 SharedMemoryInternal* retval = NULL;
nuclear@0 376
nuclear@0 377 // Construct the file mapping name in a Windows-specific way
nuclear@0 378 OVR::String fileMappingName = params.globalName;
nuclear@0 379 const char *fileName = fileMappingName.ToCStr();
nuclear@0 380
nuclear@0 381 // Is being opened read-only?
nuclear@0 382 const bool openReadOnly = (params.accessMode == SharedMemory::AccessMode_ReadOnly);
nuclear@0 383
nuclear@0 384 // Try up to 3 times to reduce low-probability failures:
nuclear@0 385 static const int ATTEMPTS_MAX = 3;
nuclear@0 386 for (int attempts = 0; attempts < ATTEMPTS_MAX; ++attempts)
nuclear@0 387 {
nuclear@0 388 // If opening should be attempted first,
nuclear@0 389 if (params.openMode != SharedMemory::OpenMode_CreateOnly)
nuclear@0 390 {
nuclear@0 391 // Attempt to open a shared memory map
nuclear@0 392 retval = AttemptOpenSharedMemory(fileName, params.minSizeBytes, openReadOnly);
nuclear@0 393
nuclear@0 394 // If successful,
nuclear@0 395 if (retval)
nuclear@0 396 {
nuclear@0 397 // Done!
nuclear@0 398 break;
nuclear@0 399 }
nuclear@0 400 }
nuclear@0 401
nuclear@0 402 // If creating the shared memory is also acceptable,
nuclear@0 403 if (params.openMode != SharedMemory::OpenMode_OpenOnly)
nuclear@0 404 {
nuclear@0 405 // Interpret create mode
nuclear@0 406 const bool allowRemoteWrite = (params.remoteMode == SharedMemory::RemoteMode_ReadWrite);
nuclear@0 407
nuclear@0 408 // Attempt to create a shared memory map
nuclear@0 409 retval = AttemptCreateSharedMemory(fileName, params.minSizeBytes, openReadOnly, allowRemoteWrite);
nuclear@0 410
nuclear@0 411 // If successful,
nuclear@0 412 if (retval)
nuclear@0 413 {
nuclear@0 414 // Done!
nuclear@0 415 break;
nuclear@0 416 }
nuclear@0 417 }
nuclear@0 418 } // Re-attempt create/open
nuclear@0 419
nuclear@0 420 // Note: On Windows the initial contents of the region are guaranteed to be zero.
nuclear@0 421 return retval;
nuclear@0 422 }
nuclear@0 423
nuclear@0 424 #endif // OVR_OS_WIN32
nuclear@0 425
nuclear@0 426
nuclear@0 427 #if (defined(OVR_OS_LINUX) || defined(OVR_OS_MAC)) && !defined(OVR_FAKE_SHAREDMEMORY)
nuclear@0 428
nuclear@0 429 // Hidden implementation class for OS-specific behavior
nuclear@0 430 class SharedMemoryInternal
nuclear@0 431 {
nuclear@0 432 public:
nuclear@0 433 int FileMapping;
nuclear@0 434 void* FileView;
nuclear@0 435 int FileSize;
nuclear@0 436
nuclear@0 437 SharedMemoryInternal(int fileMapping, void* fileView, int fileSize) :
nuclear@0 438 FileMapping(fileMapping),
nuclear@0 439 FileView(fileView),
nuclear@0 440 FileSize(fileSize)
nuclear@0 441 {
nuclear@0 442 }
nuclear@0 443
nuclear@0 444 ~SharedMemoryInternal()
nuclear@0 445 {
nuclear@0 446 // If file view is set,
nuclear@0 447 if (FileView)
nuclear@0 448 {
nuclear@0 449 munmap(FileView, FileSize);
nuclear@0 450 FileView = MAP_FAILED;
nuclear@0 451 }
nuclear@0 452
nuclear@0 453 // If file mapping is set,
nuclear@0 454 if (FileMapping >= 0)
nuclear@0 455 {
nuclear@0 456 close(FileMapping);
nuclear@0 457 FileMapping = -1;
nuclear@0 458 }
nuclear@0 459 }
nuclear@0 460
nuclear@0 461 static SharedMemoryInternal* DoFileMap(int hFileMapping, const char* fileName, bool openReadOnly, int minSize);
nuclear@0 462 static SharedMemoryInternal* AttemptOpenSharedMemory(const char* fileName, int minSize, bool openReadOnly);
nuclear@0 463 static SharedMemoryInternal* AttemptCreateSharedMemory(const char* fileName, int minSize, bool openReadOnly, bool allowRemoteWrite);
nuclear@0 464 static SharedMemoryInternal* CreateSharedMemory(const SharedMemory::OpenParameters& params);
nuclear@0 465 };
nuclear@0 466
nuclear@0 467 SharedMemoryInternal* SharedMemoryInternal::DoFileMap(int hFileMapping, const char* fileName, bool openReadOnly, int minSize)
nuclear@0 468 {
nuclear@0 469 // Calculate the required flags based on read/write mode
nuclear@0 470 int prot = openReadOnly ? PROT_READ : (PROT_READ|PROT_WRITE);
nuclear@0 471
nuclear@0 472 // Map the file view
nuclear@0 473 void* pFileView = mmap(NULL, minSize, prot, MAP_SHARED, hFileMapping, 0);
nuclear@0 474
nuclear@0 475 if (pFileView == MAP_FAILED)
nuclear@0 476 {
nuclear@0 477 close(hFileMapping);
nuclear@0 478
nuclear@0 479 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to map view of file for %s error code = %d", fileName, errno));
nuclear@0 480 OVR_UNUSED(fileName);
nuclear@0 481 return NULL;
nuclear@0 482 }
nuclear@0 483
nuclear@0 484 // Create internal representation
nuclear@0 485 SharedMemoryInternal* pimple = new SharedMemoryInternal(hFileMapping, pFileView, minSize);
nuclear@0 486
nuclear@0 487 // If memory allocation fails,
nuclear@0 488 if (!pimple)
nuclear@0 489 {
nuclear@0 490 munmap(pFileView, minSize);
nuclear@0 491 close(hFileMapping);
nuclear@0 492
nuclear@0 493 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Out of memory"));
nuclear@0 494 return NULL;
nuclear@0 495 }
nuclear@0 496
nuclear@0 497 return pimple;
nuclear@0 498 }
nuclear@0 499
nuclear@0 500 SharedMemoryInternal* SharedMemoryInternal::AttemptOpenSharedMemory(const char* fileName, int minSize, bool openReadOnly)
nuclear@0 501 {
nuclear@0 502 // Calculate permissions and flags based on read/write mode
nuclear@0 503 int flags = openReadOnly ? O_RDONLY : O_RDWR;
nuclear@0 504 int perms = openReadOnly ? S_IRUSR : (S_IRUSR | S_IWUSR);
nuclear@0 505
nuclear@0 506 // Attempt to open the shared memory file
nuclear@0 507 int hFileMapping = shm_open(fileName, flags, perms);
nuclear@0 508
nuclear@0 509 // If file was not opened successfully,
nuclear@0 510 if (hFileMapping < 0)
nuclear@0 511 {
nuclear@0 512 OVR_DEBUG_LOG(("[SharedMemory] WARNING: Unable to open file mapping for %s error code = %d (not necessarily bad)", fileName, errno));
nuclear@0 513 return NULL;
nuclear@0 514 }
nuclear@0 515
nuclear@0 516 // Map the file
nuclear@0 517 return DoFileMap(hFileMapping, fileName, openReadOnly, minSize);
nuclear@0 518 }
nuclear@0 519
nuclear@0 520 SharedMemoryInternal* SharedMemoryInternal::AttemptCreateSharedMemory(const char* fileName, int minSize, bool openReadOnly, bool allowRemoteWrite)
nuclear@0 521 {
nuclear@0 522 // Create mode
nuclear@0 523 // Note: Cannot create the shared memory file read-only because then ftruncate() will fail.
nuclear@0 524 int flags = O_CREAT | O_RDWR;
nuclear@0 525
nuclear@0 526 #ifndef OVR_ALLOW_CREATE_FILE_MAPPING_IF_EXISTS
nuclear@0 527 // Require exclusive access when creating (seems like a good idea without trying it yet..)
nuclear@0 528 if (shm_unlink(fileName) < 0)
nuclear@0 529 {
nuclear@0 530 OVR_DEBUG_LOG(("[SharedMemory] WARNING: Unable to unlink shared memory file %s error code = %d", fileName, errno));
nuclear@0 531 }
nuclear@0 532 flags |= O_EXCL;
nuclear@0 533 #endif
nuclear@0 534
nuclear@0 535 // Set own read/write permissions
nuclear@0 536 int perms = openReadOnly ? S_IRUSR : (S_IRUSR|S_IWUSR);
nuclear@0 537
nuclear@0 538 // Allow other users to read/write the shared memory file
nuclear@0 539 perms |= allowRemoteWrite ? (S_IWGRP|S_IWOTH|S_IRGRP|S_IROTH) : (S_IRGRP|S_IROTH);
nuclear@0 540
nuclear@0 541 // Attempt to open the shared memory file
nuclear@0 542 int hFileMapping = shm_open(fileName, flags, perms);
nuclear@0 543
nuclear@0 544 // If file was not opened successfully,
nuclear@0 545 if (hFileMapping < 0)
nuclear@0 546 {
nuclear@0 547 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to create file mapping for %s error code = %d", fileName, errno));
nuclear@0 548 return NULL;
nuclear@0 549 }
nuclear@0 550
nuclear@0 551 int truncRes = ftruncate(hFileMapping, minSize);
nuclear@0 552
nuclear@0 553 // If file was not opened successfully,
nuclear@0 554 if (truncRes < 0)
nuclear@0 555 {
nuclear@0 556 close(hFileMapping);
nuclear@0 557 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to truncate file for %s to %d error code = %d", fileName, minSize, errno));
nuclear@0 558 return NULL;
nuclear@0 559 }
nuclear@0 560
nuclear@0 561 // Map the file
nuclear@0 562 return DoFileMap(hFileMapping, fileName, openReadOnly, minSize);
nuclear@0 563 }
nuclear@0 564
nuclear@0 565 SharedMemoryInternal* SharedMemoryInternal::CreateSharedMemory(const SharedMemory::OpenParameters& params)
nuclear@0 566 {
nuclear@0 567 SharedMemoryInternal* retval = NULL;
nuclear@0 568
nuclear@0 569 // Construct the file mapping name in a Linux-specific way
nuclear@0 570 OVR::String fileMappingName = "/";
nuclear@0 571 fileMappingName += params.globalName;
nuclear@0 572 const char *fileName = fileMappingName.ToCStr();
nuclear@0 573
nuclear@0 574 // Is being opened read-only?
nuclear@0 575 const bool openReadOnly = (params.accessMode == SharedMemory::AccessMode_ReadOnly);
nuclear@0 576
nuclear@0 577 // Try up to 3 times to reduce low-probability failures:
nuclear@0 578 static const int ATTEMPTS_MAX = 3;
nuclear@0 579 for (int attempts = 0; attempts < ATTEMPTS_MAX; ++attempts)
nuclear@0 580 {
nuclear@0 581 // If opening should be attempted first,
nuclear@0 582 if (params.openMode != SharedMemory::OpenMode_CreateOnly)
nuclear@0 583 {
nuclear@0 584 // Attempt to open a shared memory map
nuclear@0 585 retval = AttemptOpenSharedMemory(fileName, params.minSizeBytes, openReadOnly);
nuclear@0 586
nuclear@0 587 // If successful,
nuclear@0 588 if (retval)
nuclear@0 589 {
nuclear@0 590 // Done!
nuclear@0 591 break;
nuclear@0 592 }
nuclear@0 593 }
nuclear@0 594
nuclear@0 595 // If creating the shared memory is also acceptable,
nuclear@0 596 if (params.openMode != SharedMemory::OpenMode_OpenOnly)
nuclear@0 597 {
nuclear@0 598 // Interpret create mode
nuclear@0 599 const bool allowRemoteWrite = (params.remoteMode == SharedMemory::RemoteMode_ReadWrite);
nuclear@0 600
nuclear@0 601 // Attempt to create a shared memory map
nuclear@0 602 retval = AttemptCreateSharedMemory(fileName, params.minSizeBytes, openReadOnly, allowRemoteWrite);
nuclear@0 603
nuclear@0 604 // If successful,
nuclear@0 605 if (retval)
nuclear@0 606 {
nuclear@0 607 // Done!
nuclear@0 608 break;
nuclear@0 609 }
nuclear@0 610 }
nuclear@0 611 } // Re-attempt create/open
nuclear@0 612
nuclear@0 613 // Note: On Windows the initial contents of the region are guaranteed to be zero.
nuclear@0 614 return retval;
nuclear@0 615 }
nuclear@0 616
nuclear@0 617 #endif // OVR_OS_LINUX
nuclear@0 618
nuclear@0 619
nuclear@0 620 //// SharedMemory
nuclear@0 621
nuclear@0 622 SharedMemory::SharedMemory(int size, void* data, SharedMemoryInternal* pInternal) :
nuclear@0 623 Size(size),
nuclear@0 624 Data(data),
nuclear@0 625 Internal(pInternal)
nuclear@0 626 {
nuclear@0 627 }
nuclear@0 628 // Call close when it goes out of scope
nuclear@0 629 SharedMemory::~SharedMemory()
nuclear@0 630 {
nuclear@0 631 Close();
nuclear@0 632 delete Internal;
nuclear@0 633 }
nuclear@0 634
nuclear@0 635 void SharedMemory::Close()
nuclear@0 636 {
nuclear@0 637 if (Internal)
nuclear@0 638 {
nuclear@0 639 delete Internal;
nuclear@0 640 Internal = NULL;
nuclear@0 641 }
nuclear@0 642 }
nuclear@0 643
nuclear@0 644
nuclear@0 645 //// SharedMemoryFactory
nuclear@0 646
nuclear@0 647 Ptr<SharedMemory> SharedMemoryFactory::Open(const SharedMemory::OpenParameters& params)
nuclear@0 648 {
nuclear@0 649 Ptr<SharedMemory> retval;
nuclear@0 650
nuclear@0 651 // If no name specified or no size requested,
nuclear@0 652 if (!params.globalName || (params.minSizeBytes <= 0))
nuclear@0 653 {
nuclear@0 654 OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Invalid parameters to Create()"));
nuclear@0 655 return NULL;
nuclear@0 656 }
nuclear@0 657
nuclear@0 658 OVR_DEBUG_LOG(("[SharedMemory] Creating shared memory region: %s > %d bytes",
nuclear@0 659 params.globalName, params.minSizeBytes));
nuclear@0 660
nuclear@0 661 // Attempt to create a shared memory region from the parameters
nuclear@0 662 SharedMemoryInternal* pInternal = SharedMemoryInternal::CreateSharedMemory(params);
nuclear@0 663
nuclear@0 664 if (pInternal)
nuclear@0 665 {
nuclear@0 666 // Create the wrapper object
nuclear@0 667 retval = *new SharedMemory(params.minSizeBytes, pInternal->FileView, pInternal);
nuclear@0 668 }
nuclear@0 669
nuclear@0 670 return retval;
nuclear@0 671 }
nuclear@0 672
nuclear@0 673 SharedMemoryFactory::SharedMemoryFactory()
nuclear@0 674 {
nuclear@0 675 OVR_DEBUG_LOG(("[SharedMemory] Creating factory"));
nuclear@0 676
nuclear@0 677 PushDestroyCallbacks();
nuclear@0 678 }
nuclear@0 679
nuclear@0 680 SharedMemoryFactory::~SharedMemoryFactory()
nuclear@0 681 {
nuclear@0 682 OVR_DEBUG_LOG(("[SharedMemory] Destroying factory"));
nuclear@0 683 }
nuclear@0 684
nuclear@0 685 void SharedMemoryFactory::OnSystemDestroy()
nuclear@0 686 {
nuclear@0 687 delete this;
nuclear@0 688 }
nuclear@0 689
nuclear@0 690
nuclear@0 691 } // namespace OVR