Backed out changeset 5f819082a015 (bug 1936189) for causing reftest failures @ native...
[gecko.git] / gfx / vr / VRShMem.cpp
blob9295b5896616537d4dd44bf91f7807faaf1a22b0
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;
416 # if defined(XP_WIN)
417 WaitForMutex lock(mMutex);
418 status = lock.GetStatus();
419 # endif // defined(XP_WIN)
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;
427 #endif // defined(MOZ_WIDGET_ANDROID)
430 void VRShMem::PullBrowserState(mozilla::gfx::VRBrowserState& aState) {
431 if (!mExternalShmem) {
432 return;
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.
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)
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));
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();
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;
479 #endif // defined(MOZ_WIDGET_ANDROID)
482 void VRShMem::PushSystemState(const mozilla::gfx::VRSystemState& aState) {
483 if (!mExternalShmem) {
484 return;
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.
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");
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));
506 #else
507 bool lockState = true;
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();
516 # endif // defined(XP_WIN)
518 if (lockState) {
519 mExternalShmem->generationA = mExternalShmem->generationA + 1;
520 memcpy((void*)&mExternalShmem->state, &aState, sizeof(VRSystemState));
521 mExternalShmem->generationB = mExternalShmem->generationB + 1;
523 #endif // defined(MOZ_WIDGET_ANDROID)
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;
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;
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;
564 } // while (!done) {
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;
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;
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;
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;
613 # endif // defined(XP_WIN)
614 } // End: Scope for WaitForMutex
615 // Yield the thread while polling
616 YieldThread();
617 } // while (!true)
619 #endif // defined(MOZ_WIDGET_ANDROID)
621 void VRShMem::PushWindowState(VRWindowState& aState) {
622 #if defined(XP_WIN)
623 if (!mExternalShmem) {
624 return;
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));
634 #endif // defined(XP_WIN)
637 void VRShMem::PullWindowState(VRWindowState& aState) {
638 #if defined(XP_WIN)
639 if (!mExternalShmem) {
640 return;
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));
650 #endif // defined(XP_WIN)
653 void VRShMem::PushTelemetryState(VRTelemetryState& aState) {
654 #if defined(XP_WIN)
655 if (!mExternalShmem) {
656 return;
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));
666 #endif // defined(XP_WIN)
668 void VRShMem::PullTelemetryState(VRTelemetryState& aState) {
669 #if defined(XP_WIN)
670 if (!mExternalShmem) {
671 return;
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));
681 #endif // defined(XP_WIN)
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();
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
703 ::SetEvent(hSignal);
704 ::CloseHandle(hSignal);
705 #endif // defined(XP_WIN)
709 void VRShMem::SendIMEState(uint64_t aWindowID,
710 mozilla::gfx::VRFxEventState aEventState) {
711 SendEvent(aWindowID, mozilla::gfx::VRFxEventType::IME, aEventState);
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);
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());
725 mozilla::gfx::VRWindowState windowState = {0};
726 PullWindowState(windowState);
727 windowState.windowID = aWindowID;
728 windowState.eventType = mozilla::gfx::VRFxEventType::SHUTDOWN;
729 PushWindowState(windowState);
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
737 ::SetEvent(hSignal);
738 ::CloseHandle(hSignal);
739 #endif // defined(XP_WIN)