Skip to content

Commit

Permalink
Bug 1399707 - Make entries in TabChild::sActiveTabs and EventLoopActi…
Browse files Browse the repository at this point in the history
…vation::mEventGroups unique. r=billm

--HG--
extra : rebase_source : ffccc53b6b1055d7cfeb281ee145b897807a7810
  • Loading branch information
Bevis Tseng committed Sep 13, 2017
1 parent 9c73bf3 commit da72a54
Show file tree
Hide file tree
Showing 16 changed files with 152 additions and 46 deletions.
12 changes: 7 additions & 5 deletions dom/ipc/TabChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@
#include "nsIXULRuntime.h"
#include "nsPIDOMWindow.h"
#include "nsPIWindowRoot.h"
#include "nsPointerHashKeys.h"
#include "nsLayoutUtils.h"
#include "nsPrintfCString.h"
#include "nsTHashtable.h"
#include "nsThreadManager.h"
#include "nsThreadUtils.h"
#include "nsViewManager.h"
Expand Down Expand Up @@ -164,7 +166,7 @@ NS_IMPL_ISUPPORTS(TabChildSHistoryListener,

static const char BEFORE_FIRST_PAINT[] = "before-first-paint";

nsTArray<TabChild*>* TabChild::sActiveTabs;
nsTHashtable<nsPtrHashKey<TabChild>>* TabChild::sActiveTabs;

typedef nsDataHashtable<nsUint64HashKey, TabChild*> TabChildMap;
static TabChildMap* sTabChildren;
Expand Down Expand Up @@ -1120,7 +1122,7 @@ TabChild::ActorDestroy(ActorDestroyReason why)
TabChild::~TabChild()
{
if (sActiveTabs) {
sActiveTabs->RemoveElement(this);
sActiveTabs->RemoveEntry(this);
if (sActiveTabs->IsEmpty()) {
delete sActiveTabs;
sActiveTabs = nullptr;
Expand Down Expand Up @@ -2589,12 +2591,12 @@ TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)

if (aIsActive) {
if (!sActiveTabs) {
sActiveTabs = new nsTArray<TabChild*>();
sActiveTabs = new nsTHashtable<nsPtrHashKey<TabChild>>();
}
sActiveTabs->AppendElement(this);
sActiveTabs->PutEntry(this);
} else {
if (sActiveTabs) {
sActiveTabs->RemoveElement(this);
sActiveTabs->RemoveEntry(this);
// We don't delete sActiveTabs here when it's empty since that
// could cause a lot of churn. Instead, we wait until ~TabChild.
}
Expand Down
7 changes: 5 additions & 2 deletions dom/ipc/TabChild.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class nsIDOMWindowUtils;
class nsIHttpChannel;
class nsISerialEventTarget;

template<typename T> class nsTHashtable;
template<typename T> class nsPtrHashKey;

namespace mozilla {
class AbstractThread;
namespace layout {
Expand Down Expand Up @@ -762,7 +765,7 @@ class TabChild final : public TabChildBase,
// open. There can also be zero foreground TabChilds if the foreground tab is
// in a different content process. Note that this function should only be
// called if HasActiveTabs() returns true.
static const nsTArray<TabChild*>& GetActiveTabs()
static const nsTHashtable<nsPtrHashKey<TabChild>>& GetActiveTabs()
{
MOZ_ASSERT(HasActiveTabs());
return *sActiveTabs;
Expand Down Expand Up @@ -964,7 +967,7 @@ class TabChild final : public TabChildBase,
// the foreground). There may be more than one if there are multiple browser
// windows open. There may be none if this process does not host any
// foreground tabs.
static nsTArray<TabChild*>* sActiveTabs;
static nsTHashtable<nsPtrHashKey<TabChild>>* sActiveTabs;

DISALLOW_EVIL_CONSTRUCTORS(TabChild);
};
Expand Down
7 changes: 4 additions & 3 deletions ipc/glue/BackgroundChildImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,14 +628,15 @@ BackgroundChildImpl::RecvDispatchLocalStorageChange(
}

bool
BackgroundChildImpl::GetMessageSchedulerGroups(const Message& aMsg, nsTArray<RefPtr<SchedulerGroup>>& aGroups)
BackgroundChildImpl::GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups)
{
if (aMsg.type() == layout::PVsync::MessageType::Msg_Notify__ID) {
MOZ_ASSERT(NS_IsMainThread());
aGroups.Clear();
if (dom::TabChild::HasActiveTabs()) {
for (dom::TabChild* tabChild : dom::TabChild::GetActiveTabs()) {
aGroups.AppendElement(tabChild->TabGroup());
for (auto iter = dom::TabChild::GetActiveTabs().ConstIter();
!iter.Done(); iter.Next()) {
aGroups.Put(iter.Get()->GetKey()->TabGroup());
}
}
return true;
Expand Down
2 changes: 1 addition & 1 deletion ipc/glue/BackgroundChildImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class BackgroundChildImpl : public PBackgroundChild
const bool& aIsPrivate) override;

bool
GetMessageSchedulerGroups(const Message& aMsg, nsTArray<RefPtr<SchedulerGroup>>& aGroups) override;
GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups) override;
};

class BackgroundChildImpl::ThreadLocal final
Expand Down
2 changes: 1 addition & 1 deletion ipc/glue/MessageChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2002,7 +2002,7 @@ MessageChannel::MessageTask::GetPriority(uint32_t* aPriority)
}

bool
MessageChannel::MessageTask::GetAffectedSchedulerGroups(nsTArray<RefPtr<SchedulerGroup>>& aGroups)
MessageChannel::MessageTask::GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups)
{
if (!mChannel) {
return false;
Expand Down
2 changes: 1 addition & 1 deletion ipc/glue/MessageChannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver
Message& Msg() { return mMessage; }
const Message& Msg() const { return mMessage; }

bool GetAffectedSchedulerGroups(nsTArray<RefPtr<SchedulerGroup>>& aGroups) override;
bool GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups) override;

private:
MessageTask() = delete;
Expand Down
5 changes: 4 additions & 1 deletion ipc/glue/ProtocolUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "mozilla/NotNull.h"
#include "mozilla/UniquePtr.h"
#include "MainThreadUtils.h"
#include "nsILabelableRunnable.h"

#if defined(ANDROID) && defined(DEBUG)
#include <android/log.h>
Expand Down Expand Up @@ -268,6 +269,8 @@ class IToplevelProtocol : public IProtocol
~IToplevelProtocol();

public:
using SchedulerGroupSet = nsILabelableRunnable::SchedulerGroupSet;

void SetTransport(UniquePtr<Transport> aTrans)
{
mTrans = Move(aTrans);
Expand Down Expand Up @@ -388,7 +391,7 @@ class IToplevelProtocol : public IProtocol
// when it's difficult to determine an EventTarget ahead of time. See the
// comment in nsILabelableRunnable.h for more information.
virtual bool
GetMessageSchedulerGroups(const Message& aMsg, nsTArray<RefPtr<SchedulerGroup>>& aGroups)
GetMessageSchedulerGroups(const Message& aMsg, SchedulerGroupSet& aGroups)
{
return false;
}
Expand Down
18 changes: 4 additions & 14 deletions xpcom/threads/LabeledEventQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,7 @@ IsReadyToRun(nsIRunnable* aEvent, SchedulerGroup* aEventGroup)
return false;
}

AutoTArray<RefPtr<SchedulerGroup>, 1> groups;
bool labeled = labelable->GetAffectedSchedulerGroups(groups);
if (!labeled) {
return false;
}

for (SchedulerGroup* group : groups) {
if (group->IsRunning()) {
return false;
}
}
return true;
return labelable->IsReadyToRun();
}

void
Expand Down Expand Up @@ -181,8 +170,9 @@ LabeledEventQueue::GetEvent(EventPriority* aPriority,
// prevents us from preferentially processing events from active tabs twice in
// a row. This scheme is designed to prevent starvation.
if (TabChild::HasActiveTabs() && mAvoidActiveTabCount <= 0) {
for (TabChild* tabChild : TabChild::GetActiveTabs()) {
SchedulerGroup* group = tabChild->TabGroup();
for (auto iter = TabChild::GetActiveTabs().ConstIter();
!iter.Done(); iter.Next()) {
SchedulerGroup* group = iter.Get()->GetKey()->TabGroup();
if (!group->isInList() || group == sCurrentSchedulerGroup) {
continue;
}
Expand Down
12 changes: 2 additions & 10 deletions xpcom/threads/Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,11 +563,7 @@ SchedulerImpl::StartEvent(Scheduler::EventLoopActivation& aActivation)
MOZ_ASSERT(!sUnlabeledEventRunning);
if (aActivation.IsLabeled()) {
SchedulerGroup::SetValidatingAccess(SchedulerGroup::StartValidation);

for (SchedulerGroup* group : aActivation.EventGroupsAffected()) {
MOZ_ASSERT(!group->IsRunning());
group->SetIsRunning(true);
}
aActivation.EventGroupsAffected().SetIsRunning(true);
} else {
sUnlabeledEventRunning = true;
}
Expand All @@ -578,11 +574,7 @@ SchedulerImpl::StartEvent(Scheduler::EventLoopActivation& aActivation)
SchedulerImpl::FinishEvent(Scheduler::EventLoopActivation& aActivation)
{
if (aActivation.IsLabeled()) {
for (SchedulerGroup* group : aActivation.EventGroupsAffected()) {
MOZ_ASSERT(group->IsRunning());
group->SetIsRunning(false);
}

aActivation.EventGroupsAffected().SetIsRunning(false);
SchedulerGroup::SetValidatingAccess(SchedulerGroup::EndValidation);
} else {
MOZ_ASSERT(sUnlabeledEventRunning);
Expand Down
6 changes: 4 additions & 2 deletions xpcom/threads/Scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "mozilla/EventQueue.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsILabelableRunnable.h"

// Windows silliness. winbase.h defines an empty no-argument Yield macro.
#undef Yield
Expand Down Expand Up @@ -74,6 +75,7 @@ class Scheduler
class MOZ_RAII EventLoopActivation
{
public:
using EventGroups = nsILabelableRunnable::SchedulerGroupSet;
EventLoopActivation();
~EventLoopActivation();

Expand All @@ -85,13 +87,13 @@ class Scheduler

EventPriority Priority() const { return mPriority; }
bool IsLabeled() { return mIsLabeled; }
const nsTArray<RefPtr<SchedulerGroup>>& EventGroupsAffected() { return mEventGroups; }
EventGroups& EventGroupsAffected() { return mEventGroups; }

private:
EventLoopActivation* mPrev;
bool mProcessingEvent;
bool mIsLabeled;
nsTArray<RefPtr<SchedulerGroup>> mEventGroups;
EventGroups mEventGroups;
EventPriority mPriority;

static MOZ_THREAD_LOCAL(EventLoopActivation*) sTopActivation;
Expand Down
4 changes: 2 additions & 2 deletions xpcom/threads/SchedulerGroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,10 +359,10 @@ SchedulerGroup::Runnable::Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
}

bool
SchedulerGroup::Runnable::GetAffectedSchedulerGroups(nsTArray<RefPtr<SchedulerGroup>>& aGroups)
SchedulerGroup::Runnable::GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups)
{
aGroups.Clear();
aGroups.AppendElement(Group());
aGroups.Put(Group());
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion xpcom/threads/SchedulerGroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class SchedulerGroup : public LinkedListElement<SchedulerGroup>
Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
SchedulerGroup* aGroup);

bool GetAffectedSchedulerGroups(nsTArray<RefPtr<SchedulerGroup>>& aGroups) override;
bool GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups) override;

SchedulerGroup* Group() const { return mGroup; }

Expand Down
1 change: 1 addition & 0 deletions xpcom/threads/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ UNIFIED_SOURCES += [
'LazyIdleThread.cpp',
'MainThreadIdlePeriod.cpp',
'nsEnvironment.cpp',
'nsILabelableRunnable.cpp',
'nsMemoryPressure.cpp',
'nsProcessCommon.cpp',
'nsProxyRelease.cpp',
Expand Down
86 changes: 86 additions & 0 deletions xpcom/threads/nsILabelableRunnable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsILabelableRunnable.h"

#include "mozilla/Scheduler.h"
#include "mozilla/SchedulerGroup.h"

bool
nsILabelableRunnable::IsReadyToRun()
{
MOZ_ASSERT(mozilla::Scheduler::AnyEventRunning());
MOZ_ASSERT(!mozilla::Scheduler::UnlabeledEventRunning());
SchedulerGroupSet groups;
if (!GetAffectedSchedulerGroups(groups)) {
// it can not be labeled right now.
return false;
}

if (groups.mSingle) {
MOZ_ASSERT(groups.mMulti.isNothing());
return !groups.mSingle->IsRunning();
}

if (groups.mMulti.isSome()) {
MOZ_ASSERT(!groups.mSingle);
for (auto iter = groups.mMulti.ref().ConstIter(); !iter.Done(); iter.Next()) {
if (iter.Get()->GetKey()->IsRunning()) {
return false;
}
}
return true;
}

// No affected groups if we are here. Then, it's ready to run.
return true;
}

void
nsILabelableRunnable::SchedulerGroupSet::Put(mozilla::SchedulerGroup* aGroup)
{
if (mSingle) {
MOZ_ASSERT(mMulti.isNothing());
mMulti.emplace();
mMulti.ref().PutEntry(mSingle);
mSingle = nullptr;
return;
}

if (mMulti.isSome()) {
MOZ_ASSERT(!mSingle);
mMulti.ref().PutEntry(aGroup);
return;
}

mSingle = aGroup;
}

void
nsILabelableRunnable::SchedulerGroupSet::Clear()
{
mSingle = nullptr;
mMulti.reset();
}

void
nsILabelableRunnable::SchedulerGroupSet::SetIsRunning(bool aIsRunning)
{
if (mSingle) {
MOZ_ASSERT(mMulti.isNothing());
mSingle->SetIsRunning(aIsRunning);
return;
}

if (mMulti.isSome()) {
MOZ_ASSERT(!mSingle);
for (auto iter = mMulti.ref().ConstIter(); !iter.Done(); iter.Next()) {
MOZ_ASSERT(iter.Get()->GetKey()->IsRunning() != aIsRunning);
iter.Get()->GetKey()->SetIsRunning(aIsRunning);
}
return;
}
}
Loading

0 comments on commit da72a54

Please sign in to comment.