Bug 1657404 - Back out changeset 6792f28b99bd keeping 349854c5ad56 r=handyman

Differential Revision: https://phabricator.services.mozilla.com/D100031
This commit is contained in:
Chris Martin 2020-12-17 18:21:06 +00:00
Родитель a70c653eb4
Коммит c24dc89ea6
4 изменённых файлов: 112 добавлений и 137 удалений

Просмотреть файл

@ -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;
};