Bug 828114: Set a timer to ensure content processes are killed if their tabs take a long time to shut down. r=jlebar a=blocking-basecamp

This commit is contained in:
Chris Jones 2013-01-09 19:04:54 +01:00
Родитель d555a604bd
Коммит dc502af4df
4 изменённых файлов: 57 добавлений и 0 удалений

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

@ -646,6 +646,11 @@ struct DelayedDeleteContentParentTask : public nsRunnable
void
ContentParent::ActorDestroy(ActorDestroyReason why)
{
if (mForceKillTask) {
mForceKillTask->Cancel();
mForceKillTask = nullptr;
}
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
if (ppm) {
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
@ -751,9 +756,35 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
}
void
ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
{
// There can be more than one PBrowser for a given app process
// because of popup windows. PBrowsers can also destroy
// concurrently. When all the PBrowsers are destroying, kick off
// another task to ensure the child process *really* shuts down,
// even if the PBrowsers themselves never finish destroying.
int32_t numLiveTabs = ManagedPBrowserParent().Length();
++mNumDestroyingTabs;
if (mNumDestroyingTabs != numLiveTabs) {
return;
}
MOZ_ASSERT(!mForceKillTask);
int32_t timeoutSecs =
Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
if (timeoutSecs > 0) {
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
mForceKillTask = NewRunnableMethod(this, &ContentParent::KillHard),
timeoutSecs * 1000);
}
}
void
ContentParent::NotifyTabDestroyed(PBrowserParent* aTab)
{
--mNumDestroyingTabs;
// There can be more than one PBrowser for a given app process
// because of popup windows. When the last one closes, shut
// us down.
@ -797,6 +828,8 @@ ContentParent::ContentParent(const nsAString& aAppManifestURL,
, mRunToCompletionDepth(0)
, mShouldCallUnblockChild(false)
, mAppManifestURL(aAppManifestURL)
, mForceKillTask(nullptr)
, mNumDestroyingTabs(0)
, mIsAlive(true)
, mIsDestroyed(false)
, mSendPermissionUpdates(false)
@ -855,6 +888,10 @@ ContentParent::ContentParent(const nsAString& aAppManifestURL,
ContentParent::~ContentParent()
{
if (mForceKillTask) {
mForceKillTask->Cancel();
}
if (OtherProcess())
base::CloseProcessHandle(OtherProcess());
@ -1442,6 +1479,7 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
void
ContentParent::KillHard()
{
mForceKillTask = nullptr;
// This ensures the process is eventually killed, but doesn't
// immediately KILLITWITHFIRE because we want to get a minidump if
// possible. After a timeout though, the process is forceably

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

@ -104,6 +104,8 @@ public:
virtual bool CheckPermission(const nsAString& aPermission);
virtual bool CheckManifestURL(const nsAString& aManifestURL);
/** Notify that a tab is beginning its destruction sequence. */
void NotifyTabDestroying(PBrowserParent* aTab);
/** Notify that a tab was destroyed during normal operation. */
void NotifyTabDestroyed(PBrowserParent* aTab);
@ -353,6 +355,15 @@ private:
const nsString mAppManifestURL;
nsRefPtr<nsFrameMessageManager> mMessageManager;
// After we initiate shutdown, we also start a timer to ensure
// that even content processes that are 100% blocked (say from
// SIGSTOP), are still killed eventually. This task enforces that
// timer.
CancelableTask* mForceKillTask;
// How many tabs we're waiting to finish their destruction
// sequence. Precisely, how many TabParents have called
// NotifyTabDestroying() but not called NotifyTabDestroyed().
int32_t mNumDestroyingTabs;
// True only while this is ready to be used to host remote tabs.
// This must not be used for new purposes after mIsAlive goes to
// false, but some previously scheduled IPC traffic may still pass

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

@ -124,6 +124,9 @@ TabParent::Destroy()
frame->Destroy();
}
mIsDestroyed = true;
ContentParent* cp = static_cast<ContentParent*>(Manager());
cp->NotifyTabDestroying(this);
}
bool

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

@ -1762,6 +1762,10 @@ pref("dom.ipc.plugins.hangUITimeoutSecs", 5);
// Minimum time that the plugin hang UI will be displayed
pref("dom.ipc.plugins.hangUIMinDisplaySecs", 10);
#endif
// How long a content process can take before closing its IPC channel
// after shutdown is initiated. If the process exceeds the timeout,
// we fear the worst and kill it.
pref("dom.ipc.tabs.shutdownTimeoutSecs", 5);
#else
// No timeout in DEBUG builds
pref("dom.ipc.plugins.timeoutSecs", 0);
@ -1771,6 +1775,7 @@ pref("dom.ipc.plugins.parentTimeoutSecs", 0);
pref("dom.ipc.plugins.hangUITimeoutSecs", 0);
pref("dom.ipc.plugins.hangUIMinDisplaySecs", 0);
#endif
pref("dom.ipc.tabs.shutdownTimeoutSecs", 0);
#endif
#ifdef XP_WIN