зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1657404 - Back out changeset 6792f28b99bd keeping 349854c5ad56 r=handyman
Differential Revision: https://phabricator.services.mozilla.com/D100031
This commit is contained in:
Родитель
a70c653eb4
Коммит
c24dc89ea6
|
@ -11,7 +11,6 @@
|
|||
#include "mozilla/dom/GamepadTestChannelParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -25,8 +24,7 @@ namespace {
|
|||
|
||||
// This is the singleton instance of GamepadPlatformService, can be called
|
||||
// by both background and monitor thread.
|
||||
static StaticMutex gGamepadPlatformServiceSingletonMutex;
|
||||
static StaticRefPtr<GamepadPlatformService> gGamepadPlatformServiceSingleton;
|
||||
StaticRefPtr<GamepadPlatformService> gGamepadPlatformServiceSingleton;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -81,54 +79,44 @@ void GamepadMonitoringState::Set(bool aIsMonitoring) {
|
|||
}
|
||||
}
|
||||
|
||||
// This class is created to service one-or-more event channels
|
||||
// This implies an invariant - There is always at-least one event channel while
|
||||
// this class is alive. It should be created with a channel, and it should be
|
||||
// destroyed when the last channel is to be removed.
|
||||
GamepadPlatformService::GamepadPlatformService(
|
||||
RefPtr<GamepadEventChannelParent> aParent)
|
||||
GamepadPlatformService::GamepadPlatformService()
|
||||
: mNextGamepadHandleValue(1),
|
||||
mMutex("mozilla::dom::GamepadPlatformService") {
|
||||
AssertIsOnBackgroundThread();
|
||||
mChannelParents.AppendElement(std::move(aParent));
|
||||
MOZ_ASSERT(mChannelParents.Length() == 1);
|
||||
}
|
||||
mMutex("mozilla::dom::GamepadPlatformService") {}
|
||||
|
||||
GamepadPlatformService::~GamepadPlatformService() {
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mChannelParents.Length() == 1);
|
||||
}
|
||||
GamepadPlatformService::~GamepadPlatformService() { Cleanup(); }
|
||||
|
||||
// static
|
||||
already_AddRefed<GamepadPlatformService>
|
||||
GamepadPlatformService::GetParentService() {
|
||||
// GamepadPlatformService can only be accessed in parent process
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
// TODO - Remove this mutex once Bug 1682554 is fixed
|
||||
StaticMutexAutoLock lock(gGamepadPlatformServiceSingletonMutex);
|
||||
|
||||
// TODO - Turn this back into an assertion after Bug 1682554 is fixed
|
||||
if (!gGamepadPlatformServiceSingleton) {
|
||||
return nullptr;
|
||||
// Only Background Thread can create new GamepadPlatformService instance.
|
||||
if (IsOnBackgroundThread()) {
|
||||
gGamepadPlatformServiceSingleton = new GamepadPlatformService();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return RefPtr<GamepadPlatformService>(gGamepadPlatformServiceSingleton)
|
||||
.forget();
|
||||
RefPtr<GamepadPlatformService> service(gGamepadPlatformServiceSingleton);
|
||||
return service.forget();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void GamepadPlatformService::NotifyGamepadChange(
|
||||
GamepadHandle aHandle, const T& aInfo, const MutexAutoLock& aProofOfLock) {
|
||||
void GamepadPlatformService::NotifyGamepadChange(GamepadHandle aHandle,
|
||||
const T& aInfo) {
|
||||
// This method is called by monitor populated in
|
||||
// platform-dependent backends
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
aProofOfLock.AssertOwns(mMutex);
|
||||
|
||||
GamepadChangeEventBody body(aInfo);
|
||||
GamepadChangeEvent e(aHandle, body);
|
||||
|
||||
// mChannelParents may be accessed by background thread in the
|
||||
// same time, we use mutex to prevent possible race condtion
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
|
||||
for (uint32_t i = 0; i < mChannelParents.Length(); ++i) {
|
||||
mChannelParents[i]->DispatchUpdateEvent(e);
|
||||
}
|
||||
|
@ -136,7 +124,7 @@ void GamepadPlatformService::NotifyGamepadChange(
|
|||
|
||||
GamepadHandle GamepadPlatformService::AddGamepad(
|
||||
const char* aID, GamepadMappingType aMapping, GamepadHand aHand,
|
||||
uint32_t aNumButtons, uint32_t aNumAxes, uint32_t aNumHaptics,
|
||||
uint32_t aNumButtons, uint32_t aNumAxes, uint32_t aHaptics,
|
||||
uint32_t aNumLightIndicator, uint32_t aNumTouchEvents) {
|
||||
// This method is called by monitor thread populated in
|
||||
// platform-dependent backends
|
||||
|
@ -148,13 +136,11 @@ GamepadHandle GamepadPlatformService::AddGamepad(
|
|||
|
||||
// Only VR controllers has displayID, we give 0 to the general gamepads.
|
||||
GamepadAdded a(NS_ConvertUTF8toUTF16(nsDependentCString(aID)), aMapping,
|
||||
aHand, 0, aNumButtons, aNumAxes, aNumHaptics,
|
||||
aNumLightIndicator, aNumTouchEvents);
|
||||
aHand, 0, aNumButtons, aNumAxes, aHaptics, aNumLightIndicator,
|
||||
aNumTouchEvents);
|
||||
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
mGamepadAdded.emplace(gamepadHandle, a);
|
||||
NotifyGamepadChange<GamepadAdded>(gamepadHandle, a, autoLock);
|
||||
|
||||
NotifyGamepadChange<GamepadAdded>(gamepadHandle, a);
|
||||
return gamepadHandle;
|
||||
}
|
||||
|
||||
|
@ -164,9 +150,7 @@ void GamepadPlatformService::RemoveGamepad(GamepadHandle aHandle) {
|
|||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
GamepadRemoved a;
|
||||
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
NotifyGamepadChange<GamepadRemoved>(aHandle, a, autoLock);
|
||||
NotifyGamepadChange<GamepadRemoved>(aHandle, a);
|
||||
mGamepadAdded.erase(aHandle);
|
||||
}
|
||||
|
||||
|
@ -178,9 +162,7 @@ void GamepadPlatformService::NewButtonEvent(GamepadHandle aHandle,
|
|||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
GamepadButtonInformation a(aButton, aValue, aPressed, aTouched);
|
||||
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
NotifyGamepadChange<GamepadButtonInformation>(aHandle, a, autoLock);
|
||||
NotifyGamepadChange<GamepadButtonInformation>(aHandle, a);
|
||||
}
|
||||
|
||||
void GamepadPlatformService::NewButtonEvent(GamepadHandle aHandle,
|
||||
|
@ -222,9 +204,7 @@ void GamepadPlatformService::NewAxisMoveEvent(GamepadHandle aHandle,
|
|||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
GamepadAxisInformation a(aAxis, aValue);
|
||||
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
NotifyGamepadChange<GamepadAxisInformation>(aHandle, a, autoLock);
|
||||
NotifyGamepadChange<GamepadAxisInformation>(aHandle, a);
|
||||
}
|
||||
|
||||
void GamepadPlatformService::NewLightIndicatorTypeEvent(
|
||||
|
@ -234,10 +214,7 @@ void GamepadPlatformService::NewLightIndicatorTypeEvent(
|
|||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
GamepadLightIndicatorTypeInformation a(aLight, aType);
|
||||
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
NotifyGamepadChange<GamepadLightIndicatorTypeInformation>(aHandle, a,
|
||||
autoLock);
|
||||
NotifyGamepadChange<GamepadLightIndicatorTypeInformation>(aHandle, a);
|
||||
}
|
||||
|
||||
void GamepadPlatformService::NewPoseEvent(GamepadHandle aHandle,
|
||||
|
@ -247,9 +224,7 @@ void GamepadPlatformService::NewPoseEvent(GamepadHandle aHandle,
|
|||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
GamepadPoseInformation a(aState);
|
||||
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
NotifyGamepadChange<GamepadPoseInformation>(aHandle, a, autoLock);
|
||||
NotifyGamepadChange<GamepadPoseInformation>(aHandle, a);
|
||||
}
|
||||
|
||||
void GamepadPlatformService::NewMultiTouchEvent(
|
||||
|
@ -261,100 +236,101 @@ void GamepadPlatformService::NewMultiTouchEvent(
|
|||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
GamepadTouchInformation a(aTouchArrayIndex, aState);
|
||||
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
NotifyGamepadChange<GamepadTouchInformation>(aHandle, a, autoLock);
|
||||
NotifyGamepadChange<GamepadTouchInformation>(aHandle, a);
|
||||
}
|
||||
|
||||
void GamepadPlatformService::AddChannelParentInternal(
|
||||
const RefPtr<GamepadEventChannelParent>& aParent) {
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
|
||||
MOZ_RELEASE_ASSERT(!mChannelParents.Contains(aParent));
|
||||
mChannelParents.AppendElement(aParent);
|
||||
|
||||
// Inform the new channel of all the gamepads that have already been added
|
||||
for (const auto& evt : mGamepadAdded) {
|
||||
GamepadChangeEventBody body(evt.second);
|
||||
GamepadChangeEvent e(evt.first, body);
|
||||
aParent->DispatchUpdateEvent(e);
|
||||
}
|
||||
void GamepadPlatformService::ResetGamepadIndexes() {
|
||||
// This method is called by monitor thread populated in
|
||||
// platform-dependent backends
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
mNextGamepadHandleValue = 1;
|
||||
}
|
||||
|
||||
bool GamepadPlatformService::RemoveChannelParentInternal(
|
||||
GamepadEventChannelParent* aParent) {
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
|
||||
MOZ_RELEASE_ASSERT(mChannelParents.Contains(aParent));
|
||||
|
||||
// If there is only one channel left, we destroy the singleton instead of
|
||||
// unregistering the channel
|
||||
if (mChannelParents.Length() == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mChannelParents.RemoveElement(aParent);
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void GamepadPlatformService::AddChannelParent(
|
||||
const RefPtr<GamepadEventChannelParent>& aParent) {
|
||||
GamepadEventChannelParent* aParent) {
|
||||
// mChannelParents can only be modified once GamepadEventChannelParent
|
||||
// is created or removed in Background thread
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aParent);
|
||||
MOZ_ASSERT(!mChannelParents.Contains(aParent));
|
||||
|
||||
// We use mutex here to prevent race condition with monitor thread
|
||||
{
|
||||
StaticMutexAutoLock lock(gGamepadPlatformServiceSingletonMutex);
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
mChannelParents.AppendElement(aParent);
|
||||
|
||||
if (gGamepadPlatformServiceSingleton) {
|
||||
gGamepadPlatformServiceSingleton->AddChannelParentInternal(aParent);
|
||||
return;
|
||||
// For a new GamepadEventChannel, we have to send the exising GamepadAdded
|
||||
// to it to make it can have the same amount of gamepads with others.
|
||||
if (mChannelParents.Length() > 1) {
|
||||
for (const auto& evt : mGamepadAdded) {
|
||||
GamepadChangeEventBody body(evt.second);
|
||||
GamepadChangeEvent e(evt.first, body);
|
||||
aParent->DispatchUpdateEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
gGamepadPlatformServiceSingleton =
|
||||
RefPtr<GamepadPlatformService>(new GamepadPlatformService{aParent});
|
||||
}
|
||||
|
||||
StartGamepadMonitoring();
|
||||
|
||||
GamepadMonitoringState::GetSingleton().Set(true);
|
||||
}
|
||||
|
||||
// static
|
||||
void GamepadPlatformService::RemoveChannelParent(
|
||||
GamepadEventChannelParent* aParent) {
|
||||
// mChannelParents can only be modified once GamepadEventChannelParent
|
||||
// is created or removed in Background thread
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aParent);
|
||||
MOZ_ASSERT(mChannelParents.Contains(aParent));
|
||||
|
||||
// We use mutex here to prevent race condition with monitor thread
|
||||
{
|
||||
StaticMutexAutoLock lock(gGamepadPlatformServiceSingletonMutex);
|
||||
|
||||
MOZ_RELEASE_ASSERT(gGamepadPlatformServiceSingleton);
|
||||
|
||||
// RemoveChannelParentInternal will refuse to remove the last channel
|
||||
// In that case, we should destroy the singleton
|
||||
if (gGamepadPlatformServiceSingleton->RemoveChannelParentInternal(
|
||||
aParent)) {
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
mChannelParents.RemoveElement(aParent);
|
||||
if (!mChannelParents.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GamepadMonitoringState::GetSingleton().Set(false);
|
||||
|
||||
StopGamepadMonitoring();
|
||||
ResetGamepadIndexes();
|
||||
MaybeShutdown();
|
||||
}
|
||||
|
||||
StaticMutexAutoLock lock(gGamepadPlatformServiceSingletonMutex);
|
||||
void GamepadPlatformService::MaybeShutdown() {
|
||||
// This method is invoked in MaybeStopGamepadMonitoring when
|
||||
// an IPDL channel is going to be destroyed
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// We should never be destroying the singleton with event channels left in it
|
||||
MOZ_RELEASE_ASSERT(
|
||||
gGamepadPlatformServiceSingleton->mChannelParents.Length() == 1);
|
||||
// We have to release gGamepadPlatformServiceSingleton ouside
|
||||
// the mutex as well as making upcoming GetParentService() call
|
||||
// recreate new singleton, so we use this RefPtr to temporarily
|
||||
// hold the reference, postponing the release process until this
|
||||
// method ends.
|
||||
RefPtr<GamepadPlatformService> kungFuDeathGrip;
|
||||
|
||||
// The only reference to the singleton should be the global one
|
||||
MOZ_RELEASE_ASSERT(gGamepadPlatformServiceSingleton->mRefCnt.get() == 1);
|
||||
bool isChannelParentEmpty;
|
||||
{
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
isChannelParentEmpty = mChannelParents.IsEmpty();
|
||||
if (isChannelParentEmpty) {
|
||||
kungFuDeathGrip = gGamepadPlatformServiceSingleton;
|
||||
gGamepadPlatformServiceSingleton = nullptr;
|
||||
mGamepadAdded.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gGamepadPlatformServiceSingleton = nullptr;
|
||||
void GamepadPlatformService::Cleanup() {
|
||||
// This method is called when GamepadPlatformService is
|
||||
// successfully distructed in background thread
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
MutexAutoLock autoLock(mMutex);
|
||||
mChannelParents.Clear();
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
|
|
@ -111,38 +111,38 @@ class GamepadPlatformService final {
|
|||
void NewMultiTouchEvent(GamepadHandle aHandle, uint32_t aTouchArrayIndex,
|
||||
const GamepadTouchState& aState);
|
||||
|
||||
// When shutting down the platform communications for gamepad, also reset the
|
||||
// indexes.
|
||||
void ResetGamepadIndexes();
|
||||
|
||||
// Add IPDL parent instance
|
||||
static void AddChannelParent(
|
||||
const RefPtr<GamepadEventChannelParent>& aParent);
|
||||
void AddChannelParent(GamepadEventChannelParent* aParent);
|
||||
|
||||
// Remove IPDL parent instance
|
||||
static void RemoveChannelParent(GamepadEventChannelParent* aParent);
|
||||
void RemoveChannelParent(GamepadEventChannelParent* aParent);
|
||||
|
||||
void MaybeShutdown();
|
||||
|
||||
private:
|
||||
explicit GamepadPlatformService(RefPtr<GamepadEventChannelParent> aParent);
|
||||
GamepadPlatformService();
|
||||
~GamepadPlatformService();
|
||||
|
||||
void AddChannelParentInternal(
|
||||
const RefPtr<GamepadEventChannelParent>& aParent);
|
||||
bool RemoveChannelParentInternal(GamepadEventChannelParent* aParent);
|
||||
|
||||
template <class T>
|
||||
void NotifyGamepadChange(GamepadHandle aHandle, const T& aInfo,
|
||||
const MutexAutoLock& aProofOfLock);
|
||||
void NotifyGamepadChange(GamepadHandle aHandle, const T& aInfo);
|
||||
|
||||
void Cleanup();
|
||||
|
||||
// mNextGamepadHandleValue can only be accessed by monitor thread
|
||||
uint32_t mNextGamepadHandleValue;
|
||||
|
||||
// This mutex protects mChannelParents and mGamepadAdded from race condition
|
||||
// mChannelParents stores all the GamepadEventChannelParent instances
|
||||
// which may be accessed by both background thread and monitor thread
|
||||
// simultaneously, so we have a mutex to prevent race condition
|
||||
nsTArray<RefPtr<GamepadEventChannelParent>> mChannelParents;
|
||||
|
||||
// This mutex protects mChannelParents from race condition
|
||||
// between background and monitor thread
|
||||
Mutex mMutex;
|
||||
|
||||
// mChannelParents stores all the
|
||||
// GamepadEventChannelParent instances which may be
|
||||
// accessed by both background thread and monitor
|
||||
// thread simultaneously, so we have a mutex to
|
||||
// prevent race condition
|
||||
nsTArray<RefPtr<GamepadEventChannelParent>> mChannelParents;
|
||||
std::map<GamepadHandle, GamepadAdded> mGamepadAdded;
|
||||
};
|
||||
|
||||
|
|
|
@ -49,20 +49,20 @@ GamepadEventChannelParent::GamepadEventChannelParent() {
|
|||
|
||||
mBackgroundEventTarget = GetCurrentEventTarget();
|
||||
|
||||
GamepadPlatformService::AddChannelParent(
|
||||
RefPtr<GamepadEventChannelParent>(this));
|
||||
RefPtr<GamepadPlatformService> service =
|
||||
GamepadPlatformService::GetParentService();
|
||||
MOZ_ASSERT(service);
|
||||
|
||||
service->AddChannelParent(this);
|
||||
}
|
||||
|
||||
void GamepadEventChannelParent::ActorDestroy(ActorDestroyReason aWhy) {
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
// TODO - This is here because I suspect that IPDL is calling ActorDestroy
|
||||
// multiple times. If this fixes the random crashes in Bug 1681750, it might
|
||||
// be worth investigating further.
|
||||
if (!mShutdown) {
|
||||
GamepadPlatformService::RemoveChannelParent(this);
|
||||
mShutdown = true;
|
||||
}
|
||||
RefPtr<GamepadPlatformService> service =
|
||||
GamepadPlatformService::GetParentService();
|
||||
MOZ_ASSERT(service);
|
||||
service->RemoveChannelParent(this);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult GamepadEventChannelParent::RecvVibrateHaptic(
|
||||
|
|
|
@ -41,7 +41,6 @@ class GamepadEventChannelParent final : public PGamepadEventChannelParent {
|
|||
GamepadEventChannelParent();
|
||||
~GamepadEventChannelParent() = default;
|
||||
|
||||
bool mShutdown{false};
|
||||
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче