Bug 1699062 - Flatten toolkit/themes/*/global/alerts/. r=desktop-theme-reviewers,dao
[gecko.git] / gfx / vr / VRShMem.cpp
blob778a27e54cf01c41812165a23d96527f54c885d7
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/. */
7 #include "VRShMem.h"
9 #ifdef MOZILLA_INTERNAL_API
10 # include "nsString.h"
11 # include "nsXULAppAPI.h"
12 #endif
14 #include "gfxVRMutex.h"
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
24 #if !defined(XP_WIN)
25 # include <unistd.h> // for ::sleep
26 #endif
28 using namespace mozilla::gfx;
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
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
46 } // anonymous namespace
47 #endif // !defined(MOZ_WIDGET_ANDROID)
49 VRShMem::VRShMem(volatile VRExternalShmem* aShmem, bool aRequiresMutex)
50 : mExternalShmem(aShmem),
51 mIsSharedExternalShmem(aShmem != nullptr)
52 #if defined(XP_WIN)
54 mRequiresMutex(aRequiresMutex)
55 #endif
56 #if defined(XP_MACOSX)
58 mShmemFD(0)
59 #elif defined(XP_WIN)
61 mShmemFile(nullptr),
62 mMutex(nullptr)
63 #endif
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)
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;
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;
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
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;
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;
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.
133 // https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-createmutexa
134 MOZ_ASSERT(GetLastError() == 0 || GetLastError() == ERROR_ALREADY_EXISTS);
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;
149 #endif
151 MOZ_ASSERT(aCreateOnSharedMemory);
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);
158 if (mShmemFD <= 0) {
159 mShmemFD = 0;
160 return;
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;
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;
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;
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);
202 if (mExternalShmem == nullptr) {
203 // TODO - Implement logging (Bug 1558912)
204 CloseShMem();
205 return;
207 #elif defined(MOZ_WIDGET_ANDROID)
208 MOZ_ASSERT(false,
209 "CreateShMem should not be called for Android. Use "
210 "CreateShMemForAndroid instead");
211 #endif
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;
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;
237 if (version != kVRExternalVersion) {
238 mExternalShmem = nullptr;
239 return;
241 if (size != sizeof(VRExternalShmem)) {
242 mExternalShmem = nullptr;
243 return;
245 #endif
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
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;
268 return;
270 #endif
271 #if defined(XP_MACOSX)
272 if (mExternalShmem) {
273 munmap((void*)mExternalShmem, sizeof(VRExternalShmem));
274 mExternalShmem = NULL;
276 if (mShmemFD) {
277 close(mShmemFD);
278 mShmemFD = 0;
280 #elif defined(XP_WIN)
281 if (mExternalShmem) {
282 UnmapViewOfFile((void*)mExternalShmem);
283 mExternalShmem = nullptr;
285 if (mShmemFile) {
286 CloseHandle(mShmemFile);
287 mShmemFile = nullptr;
289 #elif defined(MOZ_WIDGET_ANDROID)
290 mExternalShmem = NULL;
291 #endif
293 #if defined(XP_WIN)
294 if (mMutex) {
295 MOZ_ASSERT(mRequiresMutex);
296 CloseHandle(mMutex);
297 mMutex = nullptr;
299 #endif
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);
310 mMutex = OpenMutex(MUTEX_ALL_ACCESS, // request full access
311 false, // handle not inheritable
312 kMutexName); // object name
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;
322 MOZ_ASSERT(GetLastError() == 0);
324 #endif
326 if (HasExternalShmem()) {
327 // An ExternalShmem is already set. No need to override and rejoin
328 return true;
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
338 MOZ_ASSERT(GetLastError() == 0);
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);
349 // TODO - Implement logging (Bug 1558912)
350 mShmemFile = targetHandle;
351 if (!mExternalShmem) {
352 MOZ_ASSERT(mExternalShmem);
353 return false;
355 #else
356 // TODO: Implement shmem for other platforms.
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;
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);
371 if (mShmemFile) {
372 ::CloseHandle(mShmemFile);
373 mShmemFile = nullptr;
375 #endif
377 if (mExternalShmem != nullptr) {
378 #if defined(XP_WIN)
379 if (IsCreatedOnSharedMemory()) {
380 UnmapViewOfFile((void*)mExternalShmem);
381 MOZ_ASSERT(GetLastError() == 0);
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;
389 #if defined(XP_WIN)
390 if (mMutex) {
391 MOZ_ASSERT(mRequiresMutex);
392 CloseHandle(mMutex);
393 mMutex = nullptr;
395 #endif
398 void VRShMem::PushBrowserState(VRBrowserState& aBrowserState,
399 bool aNotifyCond) {
400 if (!mExternalShmem) {
401 return;
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));
411 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->geckoMutex));
413 #else
414 bool status = true;
415 # if defined(XP_WIN)
416 WaitForMutex lock(mMutex);
417 status = lock.GetStatus();
418 # endif // defined(XP_WIN)
419 if (status) {
420 mExternalShmem->geckoGenerationA++;
421 memcpy((void*)&(mExternalShmem->geckoState), (void*)&aBrowserState,
422 sizeof(VRBrowserState));
423 mExternalShmem->geckoGenerationB++;
425 #endif // defined(MOZ_WIDGET_ANDROID)
428 void VRShMem::PullBrowserState(mozilla::gfx::VRBrowserState& aState) {
429 if (!mExternalShmem) {
430 return;
432 // Copying the browser state from the shmem is non-blocking
433 // on x86/x64 architectures. Arm requires a mutex that is
434 // locked for the duration of the memcpy to and from shmem on
435 // both sides.
436 // On x86/x64 It is fallable -- If a dirty copy is detected by
437 // a mismatch of geckoGenerationA and geckoGenerationB,
438 // the copy is discarded and will not replace the last known
439 // browser state.
441 #if defined(MOZ_WIDGET_ANDROID)
442 // TODO: This code is out-of-date and fails to compile, as
443 // VRService isn't compiled for Android (Bug 1563234)
445 if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->geckoMutex)) ==
446 0) {
447 memcpy(&aState, &tmp.geckoState, sizeof(VRBrowserState));
448 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->geckoMutex));
451 MOZ_ASSERT(false, "PullBrowserState not implemented");
452 #else
453 bool status = true;
454 # if defined(XP_WIN)
455 if (mRequiresMutex) {
456 // TODO: Is this scoped lock okay? Seems like it should allow some
457 // race condition (Bug 1563234)
458 WaitForMutex lock(mMutex);
459 status = lock.GetStatus();
461 # endif // defined(XP_WIN)
462 if (status) {
463 VRExternalShmem tmp;
464 if (mExternalShmem->geckoGenerationA != mBrowserGeneration) {
465 // TODO - (void *) cast removes volatile semantics.
466 // The memcpy is not likely to be optimized out, but is theoretically
467 // possible. Suggest refactoring to either explicitly enforce memory
468 // order or to use locks.
469 memcpy(&tmp, (void*)mExternalShmem, sizeof(VRExternalShmem));
470 if (tmp.geckoGenerationA == tmp.geckoGenerationB &&
471 tmp.geckoGenerationA != 0) {
472 memcpy(&aState, &tmp.geckoState, sizeof(VRBrowserState));
473 mBrowserGeneration = tmp.geckoGenerationA;
477 #endif // defined(MOZ_WIDGET_ANDROID)
480 void VRShMem::PushSystemState(const mozilla::gfx::VRSystemState& aState) {
481 if (!mExternalShmem) {
482 return;
484 // Copying the VR service state to the shmem is atomic, infallable,
485 // and non-blocking on x86/x64 architectures. Arm requires a mutex
486 // that is locked for the duration of the memcpy to and from shmem on
487 // both sides.
489 #if defined(MOZ_WIDGET_ANDROID)
490 // TODO: This code is out-of-date and fails to compile, as
491 // VRService isn't compiled for Android (Bug 1563234)
492 MOZ_ASSERT(false, "JoinShMem not implemented");
494 if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) ==
495 0) {
496 // We are casting away the volatile keyword, which is not accepted by
497 // memcpy. It is possible (although very unlikely) that the compiler
498 // may optimize out the memcpy here as memcpy isn't explicitly safe for
499 // volatile memory in the C++ standard.
500 memcpy((void*)&mExternalShmem->state, &aState, sizeof(VRSystemState));
501 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
504 #else
505 bool lockState = true;
506 # if defined(XP_WIN)
507 if (mRequiresMutex) {
508 // TODO: Is this scoped lock okay? Seems like it should allow some
509 // race condition (Bug 1563234)
510 WaitForMutex lock(mMutex);
511 lockState = lock.GetStatus();
513 # endif // defined(XP_WIN)
514 if (lockState) {
515 mExternalShmem->generationA++;
516 memcpy((void*)&mExternalShmem->state, &aState, sizeof(VRSystemState));
517 mExternalShmem->generationB++;
519 #endif // defined(MOZ_WIDGET_ANDROID)
522 #if defined(MOZ_WIDGET_ANDROID)
523 void VRShMem::PullSystemState(
524 VRDisplayState& aDisplayState, VRHMDSensorState& aSensorState,
525 VRControllerState (&aControllerState)[kVRControllerMaxCount],
526 bool& aEnumerationCompleted,
527 const std::function<bool()>& aWaitCondition /* = nullptr */) {
528 if (!mExternalShmem) {
529 return;
531 bool done = false;
532 while (!done) {
533 if (pthread_mutex_lock((pthread_mutex_t*)&(mExternalShmem->systemMutex)) ==
534 0) {
535 while (true) {
536 memcpy(&aDisplayState, (void*)&(mExternalShmem->state.displayState),
537 sizeof(VRDisplayState));
538 memcpy(&aSensorState, (void*)&(mExternalShmem->state.sensorState),
539 sizeof(VRHMDSensorState));
540 memcpy(aControllerState,
541 (void*)&(mExternalShmem->state.controllerState),
542 sizeof(VRControllerState) * kVRControllerMaxCount);
543 aEnumerationCompleted = mExternalShmem->state.enumerationCompleted;
544 if (!aWaitCondition || aWaitCondition()) {
545 done = true;
546 break;
548 // Block current thead using the condition variable until data
549 // changes
550 pthread_cond_wait((pthread_cond_t*)&mExternalShmem->systemCond,
551 (pthread_mutex_t*)&mExternalShmem->systemMutex);
552 } // while (true)
553 pthread_mutex_unlock((pthread_mutex_t*)&(mExternalShmem->systemMutex));
554 } else if (!aWaitCondition) {
555 // pthread_mutex_lock failed and we are not waiting for a condition to
556 // exit from PullState call.
557 return;
559 } // while (!done) {
561 #else
562 void VRShMem::PullSystemState(
563 VRDisplayState& aDisplayState, VRHMDSensorState& aSensorState,
564 VRControllerState (&aControllerState)[kVRControllerMaxCount],
565 bool& aEnumerationCompleted,
566 const std::function<bool()>& aWaitCondition /* = nullptr */) {
567 MOZ_ASSERT(mExternalShmem);
568 if (!mExternalShmem) {
569 return;
571 while (true) {
572 { // Scope for WaitForMutex
573 # if defined(XP_WIN)
574 bool status = true;
575 WaitForMutex lock(mMutex);
576 status = lock.GetStatus();
577 if (status) {
578 # endif // defined(XP_WIN)
579 VRExternalShmem tmp;
580 memcpy(&tmp, (void*)mExternalShmem, sizeof(VRExternalShmem));
581 bool isCleanCopy =
582 tmp.generationA == tmp.generationB && tmp.generationA != 0;
583 if (isCleanCopy) {
584 memcpy(&aDisplayState, &tmp.state.displayState,
585 sizeof(VRDisplayState));
586 memcpy(&aSensorState, &tmp.state.sensorState,
587 sizeof(VRHMDSensorState));
588 memcpy(aControllerState,
589 (void*)&(mExternalShmem->state.controllerState),
590 sizeof(VRControllerState) * kVRControllerMaxCount);
591 aEnumerationCompleted = mExternalShmem->state.enumerationCompleted;
592 // Check for wait condition
593 if (!aWaitCondition || aWaitCondition()) {
594 return;
596 } else if (!aWaitCondition) {
597 // We did not get a clean copy, and we are not waiting for a condition
598 // to exit from PullState call.
599 return;
601 // Yield the thread while polling
602 YieldThread();
603 # if defined(XP_WIN)
604 } else if (!aWaitCondition) {
605 // WaitForMutex failed and we are not waiting for a condition to
606 // exit from PullState call.
607 return;
609 # endif // defined(XP_WIN)
610 } // End: Scope for WaitForMutex
611 // Yield the thread while polling
612 YieldThread();
613 } // while (!true)
615 #endif // defined(MOZ_WIDGET_ANDROID)
617 void VRShMem::PushWindowState(VRWindowState& aState) {
618 #if defined(XP_WIN)
619 if (!mExternalShmem) {
620 return;
623 bool status = true;
624 WaitForMutex lock(mMutex);
625 status = lock.GetStatus();
626 if (status) {
627 memcpy((void*)&(mExternalShmem->windowState), (void*)&aState,
628 sizeof(VRWindowState));
630 #endif // defined(XP_WIN)
633 void VRShMem::PullWindowState(VRWindowState& aState) {
634 #if defined(XP_WIN)
635 if (!mExternalShmem) {
636 return;
639 bool status = true;
640 WaitForMutex lock(mMutex);
641 status = lock.GetStatus();
642 if (status) {
643 memcpy((void*)&aState, (void*)&(mExternalShmem->windowState),
644 sizeof(VRWindowState));
646 #endif // defined(XP_WIN)
649 void VRShMem::PushTelemetryState(VRTelemetryState& aState) {
650 #if defined(XP_WIN)
651 if (!mExternalShmem) {
652 return;
655 bool status = true;
656 WaitForMutex lock(mMutex);
657 status = lock.GetStatus();
658 if (status) {
659 memcpy((void*)&(mExternalShmem->telemetryState), (void*)&aState,
660 sizeof(VRTelemetryState));
662 #endif // defined(XP_WIN)
664 void VRShMem::PullTelemetryState(VRTelemetryState& aState) {
665 #if defined(XP_WIN)
666 if (!mExternalShmem) {
667 return;
670 bool status = true;
671 WaitForMutex lock(mMutex);
672 status = lock.GetStatus();
673 if (status) {
674 memcpy((void*)&aState, (void*)&(mExternalShmem->telemetryState),
675 sizeof(VRTelemetryState));
677 #endif // defined(XP_WIN)
680 void VRShMem::SendEvent(uint64_t aWindowID,
681 mozilla::gfx::VRFxEventType aEventType,
682 mozilla::gfx::VRFxEventState aEventState) {
683 MOZ_ASSERT(!HasExternalShmem());
684 if (JoinShMem()) {
685 mozilla::gfx::VRWindowState windowState = {0};
686 PullWindowState(windowState);
687 windowState.windowID = aWindowID;
688 windowState.eventType = aEventType;
689 windowState.eventState = aEventState;
690 PushWindowState(windowState);
691 LeaveShMem();
693 #if defined(XP_WIN)
694 // Notify the waiting host process that the data is now available
695 HANDLE hSignal = ::OpenEventA(EVENT_ALL_ACCESS, // dwDesiredAccess
696 FALSE, // bInheritHandle
697 windowState.signalName // lpName
699 ::SetEvent(hSignal);
700 ::CloseHandle(hSignal);
701 #endif // defined(XP_WIN)
705 void VRShMem::SendIMEState(uint64_t aWindowID,
706 mozilla::gfx::VRFxEventState aEventState) {
707 SendEvent(aWindowID, mozilla::gfx::VRFxEventType::IME, aEventState);
710 void VRShMem::SendFullscreenState(uint64_t aWindowID, bool aFullscreen) {
711 SendEvent(aWindowID, mozilla::gfx::VRFxEventType::FULLSCREEN,
712 aFullscreen ? mozilla::gfx::VRFxEventState::FULLSCREEN_ENTER
713 : mozilla::gfx::VRFxEventState::FULLSCREEN_EXIT);
716 // Note: this should be called from the VRShMem instance that created
717 // the external shmem rather than joined it.
718 void VRShMem::SendShutdowmState(uint64_t aWindowID) {
719 MOZ_ASSERT(HasExternalShmem());
721 mozilla::gfx::VRWindowState windowState = {0};
722 PullWindowState(windowState);
723 windowState.windowID = aWindowID;
724 windowState.eventType = mozilla::gfx::VRFxEventType::SHUTDOWN;
725 PushWindowState(windowState);
727 #if defined(XP_WIN)
728 // Notify the waiting host process that the data is now available
729 HANDLE hSignal = ::OpenEventA(EVENT_ALL_ACCESS, // dwDesiredAccess
730 FALSE, // bInheritHandle
731 windowState.signalName // lpName
733 ::SetEvent(hSignal);
734 ::CloseHandle(hSignal);
735 #endif // defined(XP_WIN)