author | Chih-Yi Leu <cleu@mozilla.com> |
Tue, 28 Jun 2016 00:27:00 +0200 | |
changeset 302842 | 8f8875dbdc71478aaf172c2a5c146443f171496d |
parent 302841 | 050df9c81c1e80c03e75905716ec95343d83bf0f |
child 302843 | c79d6cf318c472b95996577b827d28c8bff61a34 |
push id | 30376 |
push user | cbook@mozilla.com |
push date | Tue, 28 Jun 2016 14:09:36 +0000 |
treeherder | mozilla-central@e45890951ce7 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | baku |
bugs | 1221730 |
milestone | 50.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/gamepad/GamepadMonitoring.cpp +++ b/dom/gamepad/GamepadMonitoring.cpp @@ -12,17 +12,17 @@ using namespace mozilla::ipc; namespace mozilla { namespace dom { void MaybeStopGamepadMonitoring() { AssertIsOnBackgroundThread(); - GamepadPlatformService* service = + RefPtr<GamepadPlatformService> service = GamepadPlatformService::GetParentService(); MOZ_ASSERT(service); if(service->HasGamepadListeners()) { return; } StopGamepadMonitoring(); service->ResetGamepadIndexes(); service->MaybeShutdown();
--- a/dom/gamepad/GamepadPlatformService.cpp +++ b/dom/gamepad/GamepadPlatformService.cpp @@ -19,40 +19,46 @@ using namespace mozilla::ipc; namespace mozilla { namespace dom { namespace { // This is the singleton instance of GamepadPlatformService, can be called // by both background and monitor thread. -StaticAutoPtr<GamepadPlatformService> gGamepadPlatformServiceSingleton; +StaticRefPtr<GamepadPlatformService> gGamepadPlatformServiceSingleton; } //namepsace GamepadPlatformService::GamepadPlatformService() : mGamepadIndex(0), mMutex("mozilla::dom::GamepadPlatformService") {} GamepadPlatformService::~GamepadPlatformService() { Cleanup(); } // static -GamepadPlatformService* +already_AddRefed<GamepadPlatformService> GamepadPlatformService::GetParentService() { //GamepadPlatformService can only be accessed in parent process MOZ_ASSERT(XRE_IsParentProcess()); - if(!gGamepadPlatformServiceSingleton) { - gGamepadPlatformServiceSingleton = new GamepadPlatformService(); + if (!gGamepadPlatformServiceSingleton) { + // Only Background Thread can create new GamepadPlatformService instance. + if (IsOnBackgroundThread()) { + gGamepadPlatformServiceSingleton = new GamepadPlatformService(); + } else { + return nullptr; + } } - return gGamepadPlatformServiceSingleton; + RefPtr<GamepadPlatformService> service(gGamepadPlatformServiceSingleton); + return service.forget(); } template<class T> void GamepadPlatformService::NotifyGamepadChange(const T& aInfo) { // This method is called by monitor populated in // platform-dependent backends @@ -190,23 +196,31 @@ GamepadPlatformService::HasGamepadListen void GamepadPlatformService::MaybeShutdown() { // This method is invoked in MaybeStopGamepadMonitoring when // an IPDL channel is going to be destroyed AssertIsOnBackgroundThread(); + // 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; + bool isChannelParentEmpty; { MutexAutoLock autoLock(mMutex); isChannelParentEmpty = mChannelParents.IsEmpty(); - } - if(isChannelParentEmpty) { - gGamepadPlatformServiceSingleton = nullptr; + if(isChannelParentEmpty) { + kungFuDeathGrip = gGamepadPlatformServiceSingleton; + gGamepadPlatformServiceSingleton = nullptr; + } } } void GamepadPlatformService::Cleanup() { // This method is called when GamepadPlatformService is // successfully distructed in background thread
--- a/dom/gamepad/GamepadPlatformService.h +++ b/dom/gamepad/GamepadPlatformService.h @@ -26,20 +26,20 @@ class GamepadEventChannelParent; // This thread takes charge of IPDL communications // between here and DOM side // // 2. Monitor Thread: // This thread is populated in platform-dependent backends, which // is in charge of processing gamepad hardware events from OS class GamepadPlatformService final { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GamepadPlatformService) public: - ~GamepadPlatformService(); //Get the singleton service - static GamepadPlatformService* GetParentService(); + static already_AddRefed<GamepadPlatformService> GetParentService(); // Add a gamepad to the list of known gamepads, and return its index. uint32_t AddGamepad(const char* aID, GamepadMappingType aMapping, uint32_t aNumButtons, uint32_t aNumAxes); // Remove the gamepad at |aIndex| from the list of known gamepads. void RemoveGamepad(uint32_t aIndex); // Update the state of |aButton| for the gamepad at |aIndex| for all @@ -67,16 +67,17 @@ class GamepadPlatformService final void RemoveChannelParent(GamepadEventChannelParent* aParent); bool HasGamepadListeners(); void MaybeShutdown(); private: GamepadPlatformService(); + ~GamepadPlatformService(); template<class T> void NotifyGamepadChange(const T& aInfo); void Cleanup(); // mGamepadIndex can only be accessed by monitor thread uint32_t mGamepadIndex; // mChannelParents stores all the GamepadEventChannelParent instances // which may be accessed by both background thread and monitor thread
--- a/dom/gamepad/cocoa/CocoaGamepad.cpp +++ b/dom/gamepad/cocoa/CocoaGamepad.cpp @@ -242,16 +242,22 @@ class DarwinGamepadServiceStartupRunnabl mService->StartupInternal(); return NS_OK; } }; void DarwinGamepadService::DeviceAdded(IOHIDDeviceRef device) { + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (!service) { + return; + } + size_t slot = size_t(-1); for (size_t i = 0; i < mGamepads.size(); i++) { if (mGamepads[i] == device) return; if (slot == size_t(-1) && mGamepads[i].empty()) slot = i; } @@ -271,32 +277,31 @@ DarwinGamepadService::DeviceAdded(IOHIDD int vendorId, productId; CFNumberGetValue(vendorIdRef, kCFNumberIntType, &vendorId); CFNumberGetValue(productIdRef, kCFNumberIntType, &productId); char product_name[128]; CFStringGetCString(productRef, product_name, sizeof(product_name), kCFStringEncodingASCII); char buffer[256]; sprintf(buffer, "%x-%x-%s", vendorId, productId, product_name); - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); uint32_t index = service->AddGamepad(buffer, mozilla::dom::GamepadMappingType::_empty, (int)mGamepads[slot].numButtons(), (int)mGamepads[slot].numAxes()); mGamepads[slot].mSuperIndex = index; } void DarwinGamepadService::DeviceRemoved(IOHIDDeviceRef device) { - GamepadPlatformService* service = + RefPtr<GamepadPlatformService> service = GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); + if (!service) { + return; + } for (size_t i = 0; i < mGamepads.size(); i++) { if (mGamepads[i] == device) { service->RemoveGamepad(mGamepads[i].mSuperIndex); mGamepads[i].clear(); return; } } } @@ -338,27 +343,31 @@ UnpackDpad(int dpad_value, int min, int if (value > 0 && value < 4) { buttons[kRight] = true; } } void DarwinGamepadService::InputValueChanged(IOHIDValueRef value) { + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (!service) { + return; + } + uint32_t value_length = IOHIDValueGetLength(value); if (value_length > 4) { // Workaround for bizarre issue with PS3 controllers that try to return // massive (30+ byte) values and crash IOHIDValueGetIntegerValue return; } IOHIDElementRef element = IOHIDValueGetElement(value); IOHIDDeviceRef device = IOHIDElementGetDevice(element); - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); + for (unsigned i = 0; i < mGamepads.size(); i++) { Gamepad &gamepad = mGamepads[i]; if (gamepad == device) { if (gamepad.isDpad(element)) { const dpad_buttons& oldState = gamepad.getDpadState(); dpad_buttons newState = { false, false, false, false }; UnpackDpad(IOHIDValueGetIntegerValue(value), IOHIDElementGetLogicalMin(element),
--- a/dom/gamepad/ipc/GamepadEventChannelParent.cpp +++ b/dom/gamepad/ipc/GamepadEventChannelParent.cpp @@ -37,17 +37,17 @@ class SendGamepadUpdateRunnable final : } }; } // namespace GamepadEventChannelParent::GamepadEventChannelParent() : mHasGamepadListener(false) { - GamepadPlatformService* service = + RefPtr<GamepadPlatformService> service = GamepadPlatformService::GetParentService(); MOZ_ASSERT(service); service->AddChannelParent(this); mBackgroundThread = NS_GetCurrentThread(); } bool GamepadEventChannelParent::RecvGamepadListenerAdded() @@ -60,34 +60,34 @@ GamepadEventChannelParent::RecvGamepadLi } bool GamepadEventChannelParent::RecvGamepadListenerRemoved() { AssertIsOnBackgroundThread(); MOZ_ASSERT(mHasGamepadListener); mHasGamepadListener = false; - GamepadPlatformService* service = + RefPtr<GamepadPlatformService> service = GamepadPlatformService::GetParentService(); MOZ_ASSERT(service); service->RemoveChannelParent(this); Unused << Send__delete__(this); return true; } void GamepadEventChannelParent::ActorDestroy(ActorDestroyReason aWhy) { AssertIsOnBackgroundThread(); // It may be called because IPDL child side crashed, we'll // not receive RecvGamepadListenerRemoved in that case if (mHasGamepadListener) { mHasGamepadListener = false; - GamepadPlatformService* service = + RefPtr<GamepadPlatformService> service = GamepadPlatformService::GetParentService(); MOZ_ASSERT(service); service->RemoveChannelParent(this); } MaybeStopGamepadMonitoring(); } void
--- a/dom/gamepad/ipc/GamepadTestChannelParent.cpp +++ b/dom/gamepad/ipc/GamepadTestChannelParent.cpp @@ -10,17 +10,17 @@ namespace mozilla { namespace dom { bool GamepadTestChannelParent::RecvGamepadTestEvent(const uint32_t& aID, const GamepadChangeEvent& aEvent) { mozilla::ipc::AssertIsOnBackgroundThread(); - GamepadPlatformService* service = + RefPtr<GamepadPlatformService> service = GamepadPlatformService::GetParentService(); MOZ_ASSERT(service); if (aEvent.type() == GamepadChangeEvent::TGamepadAdded) { const GamepadAdded& a = aEvent.get_GamepadAdded(); nsCString gamepadID; LossyCopyUTF16toASCII(a.id(), gamepadID); uint32_t index = service->AddGamepad(gamepadID.get(), (GamepadMappingType)a.mapping(),
--- a/dom/gamepad/linux/LinuxGamepad.cpp +++ b/dom/gamepad/linux/LinuxGamepad.cpp @@ -81,16 +81,22 @@ private: }; // singleton instance LinuxGamepadService* gService = nullptr; void LinuxGamepadService::AddDevice(struct udev_device* dev) { + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (!service) { + return; + } + const char* devpath = mUdev.udev_device_get_devnode(dev); if (!devpath) { return; } // Ensure that this device hasn't already been added. for (unsigned int i = 0; i < mGamepads.Length(); i++) { if (strcmp(mGamepads[i].devpath, devpath) == 0) { @@ -129,19 +135,16 @@ LinuxGamepadService::AddDevice(struct ud } snprintf(gamepad.idstring, sizeof(gamepad.idstring), "%s-%s-%s", vendor_id ? vendor_id : "unknown", model_id ? model_id : "unknown", name); char numAxes = 0, numButtons = 0; - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); ioctl(fd, JSIOCGAXES, &numAxes); gamepad.numAxes = numAxes; ioctl(fd, JSIOCGBUTTONS, &numButtons); gamepad.numButtons = numButtons; gamepad.index = service->AddGamepad(gamepad.idstring, mozilla::dom::GamepadMappingType::_empty, gamepad.numButtons, @@ -155,23 +158,27 @@ LinuxGamepadService::AddDevice(struct ud g_io_channel_unref(channel); mGamepads.AppendElement(gamepad); } void LinuxGamepadService::RemoveDevice(struct udev_device* dev) { + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (!service) { + return; + } + const char* devpath = mUdev.udev_device_get_devnode(dev); if (!devpath) { return; } - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); + for (unsigned int i = 0; i < mGamepads.Length(); i++) { if (strcmp(mGamepads[i].devpath, devpath) == 0) { g_source_remove(mGamepads[i].source_id); service->RemoveGamepad(mGamepads[i].index); mGamepads.RemoveElementAt(i); break; } } @@ -295,20 +302,22 @@ LinuxGamepadService::ReadUdevChange() } // static gboolean LinuxGamepadService::OnGamepadData(GIOChannel* source, GIOCondition condition, gpointer data) { + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (!service) { + return TRUE; + } int index = GPOINTER_TO_INT(data); - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); //TODO: remove gamepad? if (condition & G_IO_ERR || condition & G_IO_HUP) return FALSE; while (true) { struct js_event event; gsize count; GError* err = nullptr;
--- a/dom/gamepad/windows/WindowsGamepad.cpp +++ b/dom/gamepad/windows/WindowsGamepad.cpp @@ -426,31 +426,34 @@ WindowsGamepadService::HaveXInputGamepad } bool WindowsGamepadService::ScanForXInputDevices() { MOZ_ASSERT(mXInput, "XInput should be present!"); bool found = false; + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (!service) { + return found; + } + for (int i = 0; i < XUSER_MAX_COUNT; i++) { XINPUT_STATE state = {}; if (mXInput.mXInputGetState(i, &state) != ERROR_SUCCESS) { continue; } found = true; // See if this device is already present in our list. if (HaveXInputGamepad(i)) { continue; } // Not already present, add it. - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); Gamepad gamepad = {}; gamepad.type = kXInputGamepad; gamepad.present = true; gamepad.state = state; gamepad.userIndex = i; gamepad.numButtons = kStandardGamepadButtons; gamepad.numAxes = kStandardGamepadAxes; gamepad.id = service->AddGamepad("xinput", @@ -461,16 +464,22 @@ WindowsGamepadService::ScanForXInputDevi } return found; } void WindowsGamepadService::ScanForDevices() { + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (!service) { + return; + } + for (int i = mGamepads.Length() - 1; i >= 0; i--) { mGamepads[i].present = false; } if (mHID) { ScanForRawInputDevices(); } if (mXInput) { @@ -481,19 +490,16 @@ WindowsGamepadService::ScanForDevices() kXInputPollInterval, nsITimer::TYPE_ONE_SHOT); } else { mIsXInputMonitoring = false; } } // Look for devices that are no longer present and remove them. - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); for (int i = mGamepads.Length() - 1; i >= 0; i--) { if (!mGamepads[i].present) { service->RemoveGamepad(mGamepads[i].id); mGamepads.RemoveElementAt(i); } } } @@ -511,19 +517,21 @@ WindowsGamepadService::PollXInput() && state.dwPacketNumber != mGamepads[i].state.dwPacketNumber) { CheckXInputChanges(mGamepads[i], state); } } } void WindowsGamepadService::CheckXInputChanges(Gamepad& gamepad, XINPUT_STATE& state) { - GamepadPlatformService* service = + RefPtr<GamepadPlatformService> service = GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); + if (!service) { + return; + } // Handle digital buttons first for (size_t b = 0; b < kNumMappings; b++) { if (state.Gamepad.wButtons & kXIButtonMap[b].button && !(gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button)) { // Button pressed service->NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, true); } else if (!(state.Gamepad.wButtons & kXIButtonMap[b].button) && gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button) { @@ -581,16 +589,22 @@ public: } return c1.UsagePage < c2.UsagePage; } }; bool WindowsGamepadService::GetRawGamepad(HANDLE handle) { + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (!service) { + return true; + } + if (!mHID) { return false; } for (unsigned i = 0; i < mGamepads.Length(); i++) { if (mGamepads[i].type == kRawInputGamepad && mGamepads[i].handle == handle) { mGamepads[i].present = true; return true; @@ -717,35 +731,37 @@ WindowsGamepadService::GetRawGamepad(HAN if (i >= kMaxAxes) { break; } gamepad.axes[i].caps = axes[i]; } gamepad.type = kRawInputGamepad; gamepad.handle = handle; gamepad.present = true; - - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); gamepad.id = service->AddGamepad(gamepad_id, GamepadMappingType::_empty, gamepad.numButtons, gamepad.numAxes); mGamepads.AppendElement(gamepad); return true; } bool WindowsGamepadService::HandleRawInput(HRAWINPUT handle) { if (!mHID) { return false; } + RefPtr<GamepadPlatformService> service = + GamepadPlatformService::GetParentService(); + if (service) { + return true; + } + // First, get data from the handle UINT size; GetRawInputData(handle, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER)); nsTArray<uint8_t> data(size); data.SetLength(size); if (GetRawInputData(handle, RID_INPUT, data.Elements(), &size, sizeof(RAWINPUTHEADER)) == kRawInputError) { return false; @@ -768,19 +784,16 @@ WindowsGamepadService::HandleRawInput(HR nsTArray<uint8_t> parsedbytes; if (!GetPreparsedData(raw->header.hDevice, parsedbytes)) { return false; } PHIDP_PREPARSED_DATA parsed = reinterpret_cast<PHIDP_PREPARSED_DATA>(parsedbytes.Elements()); // Get all the pressed buttons. - GamepadPlatformService* service = - GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); nsTArray<USAGE> usages(gamepad->numButtons); usages.SetLength(gamepad->numButtons); ULONG usageLength = gamepad->numButtons; if (mHID.mHidP_GetUsages(HidP_Input, kButtonUsagePage, 0, usages.Elements(), &usageLength, parsed, (PCHAR)raw->data.hid.bRawData, raw->data.hid.dwSizeHid) != HIDP_STATUS_SUCCESS) { return false; }
--- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -929,19 +929,21 @@ nsAppShell::LegacyGeckoEvent::Run() } else { Telemetry::Accumulate(NS_ConvertUTF16toUTF8(curEvent->Characters()).get(), curEvent->Count()); } break; case AndroidGeckoEvent::GAMEPAD_ADDREMOVE: { #ifdef MOZ_GAMEPAD - GamepadPlatformService* service; + RefPtr<GamepadPlatformService> service; service = GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); + if (!service) { + break; + } if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_ADDED) { int svc_id = service->AddGamepad("android", dom::GamepadMappingType::Standard, dom::kStandardGamepadButtons, dom::kStandardGamepadAxes); widget::GeckoAppShell::GamepadAdded(curEvent->ID(), svc_id); } else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_REMOVED) { @@ -949,19 +951,21 @@ nsAppShell::LegacyGeckoEvent::Run() } #endif break; } case AndroidGeckoEvent::GAMEPAD_DATA: { #ifdef MOZ_GAMEPAD int id = curEvent->ID(); - GamepadPlatformService* service; + RefPtr<GamepadPlatformService> service; service = GamepadPlatformService::GetParentService(); - MOZ_ASSERT(service); + if (!service) { + break; + } if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_BUTTON) { service->NewButtonEvent(id, curEvent->GamepadButton(), curEvent->GamepadButtonPressed(), curEvent->GamepadButtonValue()); } else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_AXES) { int valid = curEvent->Flags(); const nsTArray<float>& values = curEvent->GamepadValues(); for (unsigned i = 0; i < values.Length(); i++) {