VRShMem.cpp (23206B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "VRShMem.h" 8 9 #ifdef MOZILLA_INTERNAL_API 10 # include "nsString.h" 11 # include "nsXULAppAPI.h" 12 #endif 13 14 #include "gfxVRMutex.h" 15 16 #if defined(XP_MACOSX) 17 # include <sys/mman.h> 18 # include <sys/stat.h> /* For mode constants */ 19 # include <fcntl.h> /* For O_* constants */ 20 #elif defined(MOZ_WIDGET_ANDROID) 21 # include "GeckoVRManager.h" 22 #endif 23 24 #if !defined(XP_WIN) 25 # include <unistd.h> // for ::sleep 26 #endif 27 28 using namespace mozilla::gfx; 29 30 #ifdef XP_WIN 31 static const char* kShmemName = "moz.gecko.vr_ext." SHMEM_VERSION; 32 static LPCTSTR kMutexName = TEXT("mozilla::vr::ShmemMutex" SHMEM_VERSION); 33 #elif defined(XP_MACOSX) 34 static const char* kShmemName = "/moz.gecko.vr_ext." SHMEM_VERSION; 35 #endif // XP_WIN 36 37 #if !defined(MOZ_WIDGET_ANDROID) 38 namespace { 39 void YieldThread() { 40 # if defined(XP_WIN) 41 ::Sleep(0); 42 # else 43 ::sleep(0); 44 # endif 45 } 46 } // anonymous namespace 47 #endif // !defined(MOZ_WIDGET_ANDROID) 48 49 VRShMem::VRShMem(volatile VRExternalShmem* aShmem, bool aRequiresMutex) 50 : mExternalShmem(aShmem), 51 mIsSharedExternalShmem(aShmem != nullptr) 52 #if defined(XP_WIN) 53 , 54 mRequiresMutex(aRequiresMutex) 55 #endif 56 #if defined(XP_MACOSX) 57 , 58 mShmemFD(0) 59 #elif defined(XP_WIN) 60 , 61 mShmemFile(nullptr), 62 mMutex(nullptr) 63 #endif 64 { 65 // Regarding input parameters, 66 // - aShmem is null for VRManager or for VRService in multi-proc 67 // - aShmem is !null for VRService in-proc (i.e., no VR proc) 68 } 69 70 // Note: This function should only be called for in-proc scenarios, where the 71 // shared memory is only shared within the same proc (rather than across 72 // processes). Also, this local heap memory's lifetime is tied to the class. 73 // Callers to this must ensure that its reference doesn't outlive the owning 74 // VRShMem instance. 75 volatile VRExternalShmem* VRShMem::GetExternalShmem() const { 76 #if defined(XP_MACOSX) 77 MOZ_ASSERT(mShmemFD == 0); 78 #elif defined(XP_WIN) 79 MOZ_ASSERT(mShmemFile == nullptr); 80 #endif 81 return mExternalShmem; 82 } 83 84 bool VRShMem::IsDisplayStateShutdown() const { 85 // adapted from VRService::Refresh 86 // Does this need the mutex for getting .shutdown? 87 return mExternalShmem != nullptr && 88 mExternalShmem->state.displayState.shutdown; 89 } 90 91 // This method returns true when there is a Shmem struct allocated and 92 // when there is a shmem handle from the OS. This implies that the struct 93 // is mapped to shared memory rather than being allocated on the heap by 94 // this process. 95 bool VRShMem::IsCreatedOnSharedMemory() const { 96 #if defined(XP_MACOSX) 97 return HasExternalShmem() && (mShmemFD != 0); 98 #elif defined(XP_WIN) 99 return HasExternalShmem() && (mShmemFile != nullptr); 100 #else 101 // VRShMem does not support system shared memory on remaining platformss 102 return false; 103 #endif 104 } 105 106 // CreateShMem allocates system shared memory for mExternalShmem and 107 // synchronization primitives to protect it. 108 // Callers/Processes to CreateShMem should followup with CloseShMem 109 void VRShMem::CreateShMem(bool aCreateOnSharedMemory) { 110 if (HasExternalShmem()) { 111 MOZ_ASSERT(mIsSharedExternalShmem && !IsCreatedOnSharedMemory()); 112 return; 113 } 114 #if defined(XP_WIN) 115 if (mMutex == nullptr) { 116 mMutex = CreateMutex(nullptr, // default security descriptor 117 false, // mutex not owned 118 kMutexName); // object name 119 if (mMutex == nullptr) { 120 # ifdef MOZILLA_INTERNAL_API 121 nsAutoCString msg; 122 msg.AppendPrintf("VRManager CreateMutex error \"%lu\".", GetLastError()); 123 NS_WARNING(msg.get()); 124 # endif 125 MOZ_ASSERT(false); 126 return; 127 } 128 // At xpcshell extension tests, it creates multiple VRManager 129 // instances in plug-contrainer.exe. It causes GetLastError() return 130 // `ERROR_ALREADY_EXISTS`. However, even though `ERROR_ALREADY_EXISTS`, it 131 // still returns the same mutex handle. 132 // 133 // https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-createmutexa 134 MOZ_ASSERT(GetLastError() == 0 || GetLastError() == ERROR_ALREADY_EXISTS); 135 } 136 #endif // XP_WIN 137 #if !defined(MOZ_WIDGET_ANDROID) 138 // The VR Service accesses all hardware from a separate process 139 // and replaces the other VRManager when enabled. 140 // If the VR process is not enabled, create an in-process VRService. 141 if (!aCreateOnSharedMemory) { 142 MOZ_ASSERT(mExternalShmem == nullptr); 143 // If the VR process is disabled, attempt to create a 144 // VR service within the current process on the heap 145 mExternalShmem = new VRExternalShmem(); 146 ClearShMem(); 147 return; 148 } 149 #endif 150 151 MOZ_ASSERT(aCreateOnSharedMemory); 152 153 #if defined(XP_MACOSX) 154 if (mShmemFD == 0) { 155 mShmemFD = 156 shm_open(kShmemName, O_RDWR, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH); 157 } 158 if (mShmemFD <= 0) { 159 mShmemFD = 0; 160 return; 161 } 162 163 struct stat sb; 164 fstat(mShmemFD, &sb); 165 off_t length = sb.st_size; 166 if (length < (off_t)sizeof(VRExternalShmem)) { 167 // TODO - Implement logging (Bug 1558912) 168 CloseShMem(); 169 return; 170 } 171 172 mExternalShmem = (VRExternalShmem*)mmap(NULL, length, PROT_READ | PROT_WRITE, 173 MAP_SHARED, mShmemFD, 0); 174 if (mExternalShmem == MAP_FAILED) { 175 // TODO - Implement logging (Bug 1558912) 176 mExternalShmem = NULL; 177 CloseShMem(); 178 return; 179 } 180 181 #elif defined(XP_WIN) 182 if (mShmemFile == nullptr) { 183 mShmemFile = 184 CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 185 sizeof(VRExternalShmem), kShmemName); 186 MOZ_ASSERT(GetLastError() == 0 || GetLastError() == ERROR_ALREADY_EXISTS); 187 MOZ_ASSERT(mShmemFile); 188 if (mShmemFile == nullptr) { 189 // TODO - Implement logging (Bug 1558912) 190 CloseShMem(); 191 return; 192 } 193 } 194 195 LARGE_INTEGER length; 196 length.QuadPart = sizeof(VRExternalShmem); 197 mExternalShmem = (VRExternalShmem*)MapViewOfFile( 198 mShmemFile, // handle to map object 199 FILE_MAP_ALL_ACCESS, // read/write permission 200 0, 0, length.QuadPart); 201 202 if (mExternalShmem == nullptr) { 203 // TODO - Implement logging (Bug 1558912) 204 CloseShMem(); 205 return; 206 } 207 #elif defined(MOZ_WIDGET_ANDROID) 208 MOZ_ASSERT(false, 209 "CreateShMem should not be called for Android. Use " 210 "CreateShMemForAndroid instead"); 211 #endif 212 } 213 214 // This function sets mExternalShmem in the Android/GeckoView 215 // scenarios where the host creates it in-memory and VRShMem 216 // accesses it via GeckVRManager. 217 void VRShMem::CreateShMemForAndroid() { 218 #if defined(MOZ_WIDGET_ANDROID) && defined(MOZILLA_INTERNAL_API) 219 mExternalShmem = 220 (VRExternalShmem*)mozilla::GeckoVRManager::GetExternalContext(); 221 if (!mExternalShmem) { 222 return; 223 } else { 224 mIsSharedExternalShmem = true; 225 } 226 227 int32_t version = -1; 228 int32_t size = 0; 229 if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 230 0) { 231 version = mExternalShmem->version; 232 size = mExternalShmem->size; 233 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex)); 234 } else { 235 return; 236 } 237 if (version != kVRExternalVersion) { 238 mExternalShmem = nullptr; 239 return; 240 } 241 if (size != sizeof(VRExternalShmem)) { 242 mExternalShmem = nullptr; 243 return; 244 } 245 #endif 246 } 247 248 void VRShMem::ClearShMem() { 249 if (mExternalShmem != nullptr) { 250 #ifdef MOZILLA_INTERNAL_API 251 // VRExternalShmem is asserted to be POD 252 mExternalShmem->Clear(); 253 #else 254 memset((void*)mExternalShmem, 0, sizeof(VRExternalShmem)); 255 #endif 256 } 257 } 258 259 // The cleanup corresponding to CreateShMem 260 void VRShMem::CloseShMem() { 261 #if !defined(MOZ_WIDGET_ANDROID) 262 if (!IsCreatedOnSharedMemory()) { 263 MOZ_ASSERT(!mIsSharedExternalShmem); 264 if (mExternalShmem) { 265 delete mExternalShmem; 266 mExternalShmem = nullptr; 267 } 268 return; 269 } 270 #endif 271 #if defined(XP_MACOSX) 272 if (mExternalShmem) { 273 munmap((void*)mExternalShmem, sizeof(VRExternalShmem)); 274 mExternalShmem = NULL; 275 } 276 if (mShmemFD) { 277 close(mShmemFD); 278 mShmemFD = 0; 279 } 280 #elif defined(XP_WIN) 281 if (mExternalShmem) { 282 UnmapViewOfFile((void*)mExternalShmem); 283 mExternalShmem = nullptr; 284 } 285 if (mShmemFile) { 286 CloseHandle(mShmemFile); 287 mShmemFile = nullptr; 288 } 289 #elif defined(MOZ_WIDGET_ANDROID) 290 mExternalShmem = NULL; 291 #endif 292 293 #if defined(XP_WIN) 294 if (mMutex) { 295 MOZ_ASSERT(mRequiresMutex); 296 CloseHandle(mMutex); 297 mMutex = nullptr; 298 } 299 #endif 300 } 301 302 // Called to use an existing shmem instance created by another process 303 // Callers to JoinShMem should call LeaveShMem for cleanup 304 bool VRShMem::JoinShMem() { 305 #if defined(XP_WIN) 306 if (!mMutex && mRequiresMutex) { 307 // Check that there are no errors before making system calls 308 MOZ_ASSERT(GetLastError() == 0); 309 310 mMutex = OpenMutex(MUTEX_ALL_ACCESS, // request full access 311 false, // handle not inheritable 312 kMutexName); // object name 313 314 if (mMutex == nullptr) { 315 # ifdef MOZILLA_INTERNAL_API 316 nsAutoCString msg; 317 msg.AppendPrintf("VRService OpenMutex error \"%lu\".", GetLastError()); 318 NS_WARNING(msg.get()); 319 # endif 320 return false; 321 } 322 MOZ_ASSERT(GetLastError() == 0); 323 } 324 #endif 325 326 if (HasExternalShmem()) { 327 // An ExternalShmem is already set. No need to override and rejoin 328 return true; 329 } 330 331 #if defined(XP_WIN) 332 // Opening a file-mapping object by name 333 base::ProcessHandle targetHandle = 334 OpenFileMappingA(FILE_MAP_ALL_ACCESS, // read/write access 335 FALSE, // do not inherit the name 336 kShmemName); // name of mapping object 337 338 MOZ_ASSERT(GetLastError() == 0); 339 340 LARGE_INTEGER length; 341 length.QuadPart = sizeof(VRExternalShmem); 342 mExternalShmem = (VRExternalShmem*)MapViewOfFile( 343 reinterpret_cast<base::ProcessHandle>( 344 targetHandle), // handle to map object 345 FILE_MAP_ALL_ACCESS, // read/write permission 346 0, 0, length.QuadPart); 347 MOZ_ASSERT(GetLastError() == 0); 348 349 // TODO - Implement logging (Bug 1558912) 350 mShmemFile = targetHandle; 351 if (!mExternalShmem) { 352 MOZ_ASSERT(mExternalShmem); 353 return false; 354 } 355 #else 356 // TODO: Implement shmem for other platforms. 357 // 358 // TODO: ** Does this mean that ShMem only works in Windows for now? If so, 359 // let's delete the code from other platforms (Bug 1563234) 360 MOZ_ASSERT(false, "JoinShMem not implemented"); 361 #endif 362 return true; 363 } 364 365 // The cleanup corresponding to JoinShMem 366 void VRShMem::LeaveShMem() { 367 #if defined(XP_WIN) 368 // Check that there are no errors before making system calls 369 MOZ_ASSERT(GetLastError() == 0); 370 371 if (mShmemFile) { 372 ::CloseHandle(mShmemFile); 373 mShmemFile = nullptr; 374 } 375 #endif 376 377 if (mExternalShmem != nullptr) { 378 #if defined(XP_WIN) 379 if (IsCreatedOnSharedMemory()) { 380 UnmapViewOfFile((void*)mExternalShmem); 381 MOZ_ASSERT(GetLastError() == 0); 382 } 383 // Otherwise, if not created on shared memory, simply null the shared 384 // reference to the heap object. The call to CloseShMem will appropriately 385 // free the allocation. 386 #endif 387 mExternalShmem = nullptr; 388 } 389 #if defined(XP_WIN) 390 if (mMutex) { 391 MOZ_ASSERT(mRequiresMutex); 392 CloseHandle(mMutex); 393 mMutex = nullptr; 394 } 395 #endif 396 } 397 398 void VRShMem::PushBrowserState(VRBrowserState& aBrowserState, 399 bool aNotifyCond) { 400 if (!mExternalShmem) { 401 return; 402 } 403 #if defined(MOZ_WIDGET_ANDROID) 404 if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->geckoMutex)) == 405 0) { 406 memcpy((void*)&(mExternalShmem->geckoState), (void*)&aBrowserState, 407 sizeof(VRBrowserState)); 408 if (aNotifyCond) { 409 pthread_cond_signal((pthread_cond_t*)&(mExternalShmem->geckoCond)); 410 } 411 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->geckoMutex)); 412 } 413 #else 414 bool status = true; 415 416 # if defined(XP_WIN) 417 WaitForMutex lock(mMutex); 418 status = lock.GetStatus(); 419 # endif // defined(XP_WIN) 420 421 if (status) { 422 mExternalShmem->geckoGenerationA = mExternalShmem->geckoGenerationA + 1; 423 memcpy((void*)&(mExternalShmem->geckoState), (void*)&aBrowserState, 424 sizeof(VRBrowserState)); 425 mExternalShmem->geckoGenerationB = mExternalShmem->geckoGenerationB + 1; 426 } 427 #endif // defined(MOZ_WIDGET_ANDROID) 428 } 429 430 void VRShMem::PullBrowserState(mozilla::gfx::VRBrowserState& aState) { 431 if (!mExternalShmem) { 432 return; 433 } 434 // Copying the browser state from the shmem is non-blocking 435 // on x86/x64 architectures. Arm requires a mutex that is 436 // locked for the duration of the memcpy to and from shmem on 437 // both sides. 438 // On x86/x64 It is fallable -- If a dirty copy is detected by 439 // a mismatch of geckoGenerationA and geckoGenerationB, 440 // the copy is discarded and will not replace the last known 441 // browser state. 442 443 #if defined(MOZ_WIDGET_ANDROID) 444 // TODO: This code is out-of-date and fails to compile, as 445 // VRService isn't compiled for Android (Bug 1563234) 446 /* 447 if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->geckoMutex)) == 448 0) { 449 memcpy(&aState, &tmp.geckoState, sizeof(VRBrowserState)); 450 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->geckoMutex)); 451 } 452 */ 453 MOZ_ASSERT(false, "PullBrowserState not implemented"); 454 #else 455 bool status = true; 456 # if defined(XP_WIN) 457 if (mRequiresMutex) { 458 // TODO: Is this scoped lock okay? Seems like it should allow some 459 // race condition (Bug 1563234) 460 WaitForMutex lock(mMutex); 461 status = lock.GetStatus(); 462 } 463 # endif // defined(XP_WIN) 464 if (status) { 465 VRExternalShmem tmp; 466 if (mExternalShmem->geckoGenerationA != mBrowserGeneration) { 467 // TODO - (void *) cast removes volatile semantics. 468 // The memcpy is not likely to be optimized out, but is theoretically 469 // possible. Suggest refactoring to either explicitly enforce memory 470 // order or to use locks. 471 memcpy(&tmp, (void*)mExternalShmem, sizeof(VRExternalShmem)); 472 if (tmp.geckoGenerationA == tmp.geckoGenerationB && 473 tmp.geckoGenerationA != 0) { 474 memcpy(&aState, &tmp.geckoState, sizeof(VRBrowserState)); 475 mBrowserGeneration = tmp.geckoGenerationA; 476 } 477 } 478 } 479 #endif // defined(MOZ_WIDGET_ANDROID) 480 } 481 482 void VRShMem::PushSystemState(const mozilla::gfx::VRSystemState& aState) { 483 if (!mExternalShmem) { 484 return; 485 } 486 // Copying the VR service state to the shmem is atomic, infallable, 487 // and non-blocking on x86/x64 architectures. Arm requires a mutex 488 // that is locked for the duration of the memcpy to and from shmem on 489 // both sides. 490 491 #if defined(MOZ_WIDGET_ANDROID) 492 // TODO: This code is out-of-date and fails to compile, as 493 // VRService isn't compiled for Android (Bug 1563234) 494 MOZ_ASSERT(false, "JoinShMem not implemented"); 495 /* 496 if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 497 0) { 498 // We are casting away the volatile keyword, which is not accepted by 499 // memcpy. It is possible (although very unlikely) that the compiler 500 // may optimize out the memcpy here as memcpy isn't explicitly safe for 501 // volatile memory in the C++ standard. 502 memcpy((void*)&mExternalShmem->state, &aState, sizeof(VRSystemState)); 503 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex)); 504 } 505 */ 506 #else 507 bool lockState = true; 508 509 # if defined(XP_WIN) 510 if (mRequiresMutex) { 511 // TODO: Is this scoped lock okay? Seems like it should allow some 512 // race condition (Bug 1563234) 513 WaitForMutex lock(mMutex); 514 lockState = lock.GetStatus(); 515 } 516 # endif // defined(XP_WIN) 517 518 if (lockState) { 519 mExternalShmem->generationA = mExternalShmem->generationA + 1; 520 memcpy((void*)&mExternalShmem->state, &aState, sizeof(VRSystemState)); 521 mExternalShmem->generationB = mExternalShmem->generationB + 1; 522 } 523 #endif // defined(MOZ_WIDGET_ANDROID) 524 } 525 526 #if defined(MOZ_WIDGET_ANDROID) 527 void VRShMem::PullSystemState( 528 VRDisplayState& aDisplayState, VRHMDSensorState& aSensorState, 529 std::array<VRControllerState, kVRControllerMaxCount>* const 530 aControllerState, 531 bool& aEnumerationCompleted, 532 const std::function<bool()>& aWaitCondition /* = nullptr */) { 533 if (!mExternalShmem) { 534 return; 535 } 536 bool done = false; 537 while (!done) { 538 if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) == 539 0) { 540 while (true) { 541 memcpy(&aDisplayState, (void*)&(mExternalShmem->state.displayState), 542 sizeof(VRDisplayState)); 543 memcpy(&aSensorState, (void*)&(mExternalShmem->state.sensorState), 544 sizeof(VRHMDSensorState)); 545 memcpy(aControllerState->data(), 546 (void*)&(mExternalShmem->state.controllerState), 547 sizeof(aControllerState->at(0)) * aControllerState->size()); 548 aEnumerationCompleted = mExternalShmem->state.enumerationCompleted; 549 if (!aWaitCondition || aWaitCondition()) { 550 done = true; 551 break; 552 } 553 // Block current thead using the condition variable until data 554 // changes 555 pthread_cond_wait((pthread_cond_t*)&mExternalShmem->systemCond, 556 (pthread_mutex_t*)&mExternalShmem->systemMutex); 557 } // while (true) 558 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex)); 559 } else if (!aWaitCondition) { 560 // pthread_mutex_lock failed and we are not waiting for a condition to 561 // exit from PullState call. 562 return; 563 } 564 } // while (!done) { 565 } 566 #else 567 void VRShMem::PullSystemState( 568 VRDisplayState& aDisplayState, VRHMDSensorState& aSensorState, 569 std::array<VRControllerState, kVRControllerMaxCount>* const 570 aControllerState, 571 bool& aEnumerationCompleted, 572 const std::function<bool()>& aWaitCondition /* = nullptr */) { 573 MOZ_ASSERT(mExternalShmem); 574 if (!mExternalShmem) { 575 return; 576 } 577 while (true) { 578 { // Scope for WaitForMutex 579 # if defined(XP_WIN) 580 bool status = true; 581 WaitForMutex lock(mMutex); 582 status = lock.GetStatus(); 583 if (status) { 584 # endif // defined(XP_WIN) 585 VRExternalShmem tmp; 586 memcpy(&tmp, (void*)mExternalShmem, sizeof(VRExternalShmem)); 587 bool isCleanCopy = 588 tmp.generationA == tmp.generationB && tmp.generationA != 0; 589 if (isCleanCopy) { 590 memcpy(&aDisplayState, &tmp.state.displayState, 591 sizeof(VRDisplayState)); 592 memcpy(&aSensorState, &tmp.state.sensorState, 593 sizeof(VRHMDSensorState)); 594 *aControllerState = tmp.state.controllerState; 595 aEnumerationCompleted = tmp.state.enumerationCompleted; 596 // Check for wait condition 597 if (!aWaitCondition || aWaitCondition()) { 598 return; 599 } 600 } else if (!aWaitCondition) { 601 // We did not get a clean copy, and we are not waiting for a condition 602 // to exit from PullState call. 603 return; 604 } 605 // Yield the thread while polling 606 YieldThread(); 607 # if defined(XP_WIN) 608 } else if (!aWaitCondition) { 609 // WaitForMutex failed and we are not waiting for a condition to 610 // exit from PullState call. 611 return; 612 } 613 # endif // defined(XP_WIN) 614 } // End: Scope for WaitForMutex 615 // Yield the thread while polling 616 YieldThread(); 617 } // while (!true) 618 } 619 #endif // defined(MOZ_WIDGET_ANDROID) 620 621 void VRShMem::PushWindowState(VRWindowState& aState) { 622 #if defined(XP_WIN) 623 if (!mExternalShmem) { 624 return; 625 } 626 627 bool status = true; 628 WaitForMutex lock(mMutex); 629 status = lock.GetStatus(); 630 if (status) { 631 memcpy((void*)&(mExternalShmem->windowState), (void*)&aState, 632 sizeof(VRWindowState)); 633 } 634 #endif // defined(XP_WIN) 635 } 636 637 void VRShMem::PullWindowState(VRWindowState& aState) { 638 #if defined(XP_WIN) 639 if (!mExternalShmem) { 640 return; 641 } 642 643 bool status = true; 644 WaitForMutex lock(mMutex); 645 status = lock.GetStatus(); 646 if (status) { 647 memcpy((void*)&aState, (void*)&(mExternalShmem->windowState), 648 sizeof(VRWindowState)); 649 } 650 #endif // defined(XP_WIN) 651 } 652 653 void VRShMem::PushTelemetryState(VRTelemetryState& aState) { 654 #if defined(XP_WIN) 655 if (!mExternalShmem) { 656 return; 657 } 658 659 bool status = true; 660 WaitForMutex lock(mMutex); 661 status = lock.GetStatus(); 662 if (status) { 663 memcpy((void*)&(mExternalShmem->telemetryState), (void*)&aState, 664 sizeof(VRTelemetryState)); 665 } 666 #endif // defined(XP_WIN) 667 } 668 void VRShMem::PullTelemetryState(VRTelemetryState& aState) { 669 #if defined(XP_WIN) 670 if (!mExternalShmem) { 671 return; 672 } 673 674 bool status = true; 675 WaitForMutex lock(mMutex); 676 status = lock.GetStatus(); 677 if (status) { 678 memcpy((void*)&aState, (void*)&(mExternalShmem->telemetryState), 679 sizeof(VRTelemetryState)); 680 } 681 #endif // defined(XP_WIN) 682 } 683 684 void VRShMem::SendEvent(uint64_t aWindowID, 685 mozilla::gfx::VRFxEventType aEventType, 686 mozilla::gfx::VRFxEventState aEventState) { 687 MOZ_ASSERT(!HasExternalShmem()); 688 if (JoinShMem()) { 689 mozilla::gfx::VRWindowState windowState = {0}; 690 PullWindowState(windowState); 691 windowState.windowID = aWindowID; 692 windowState.eventType = aEventType; 693 windowState.eventState = aEventState; 694 PushWindowState(windowState); 695 LeaveShMem(); 696 697 #if defined(XP_WIN) 698 // Notify the waiting host process that the data is now available 699 HANDLE hSignal = ::OpenEventA(EVENT_ALL_ACCESS, // dwDesiredAccess 700 FALSE, // bInheritHandle 701 windowState.signalName // lpName 702 ); 703 ::SetEvent(hSignal); 704 ::CloseHandle(hSignal); 705 #endif // defined(XP_WIN) 706 } 707 } 708 709 void VRShMem::SendIMEState(uint64_t aWindowID, 710 mozilla::gfx::VRFxEventState aEventState) { 711 SendEvent(aWindowID, mozilla::gfx::VRFxEventType::IME, aEventState); 712 } 713 714 void VRShMem::SendFullscreenState(uint64_t aWindowID, bool aFullscreen) { 715 SendEvent(aWindowID, mozilla::gfx::VRFxEventType::FULLSCREEN, 716 aFullscreen ? mozilla::gfx::VRFxEventState::FULLSCREEN_ENTER 717 : mozilla::gfx::VRFxEventState::FULLSCREEN_EXIT); 718 } 719 720 // Note: this should be called from the VRShMem instance that created 721 // the external shmem rather than joined it. 722 void VRShMem::SendShutdowmState(uint64_t aWindowID) { 723 MOZ_ASSERT(HasExternalShmem()); 724 725 mozilla::gfx::VRWindowState windowState = {0}; 726 PullWindowState(windowState); 727 windowState.windowID = aWindowID; 728 windowState.eventType = mozilla::gfx::VRFxEventType::SHUTDOWN; 729 PushWindowState(windowState); 730 731 #if defined(XP_WIN) 732 // Notify the waiting host process that the data is now available 733 HANDLE hSignal = ::OpenEventA(EVENT_ALL_ACCESS, // dwDesiredAccess 734 FALSE, // bInheritHandle 735 windowState.signalName // lpName 736 ); 737 ::SetEvent(hSignal); 738 ::CloseHandle(hSignal); 739 #endif // defined(XP_WIN) 740 }