mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Rollup of bug 821192: Ensure that content processes don't see an inconsistent app dir. r=bent,dhylands
Bug 821192, part 1: Fix the watchdog timeout code. r=dhylands Bug 821192, part 2: Add an interface to join all live content processes. r=bent Bug 821192, part 3: Join all subprocesses before restarting the main process, when we're e.g. about to apply an update. r=dhylands
This commit is contained in:
parent
2abd0a40fb
commit
fb825fe86d
@ -163,6 +163,10 @@ nsDataHashtable<nsStringHashKey, ContentParent*>* ContentParent::gAppContentPare
|
||||
nsTArray<ContentParent*>* ContentParent::gNonAppContentParents;
|
||||
nsTArray<ContentParent*>* ContentParent::gPrivateContent;
|
||||
|
||||
// This is true when subprocess launching is enabled. This is the
|
||||
// case between StartUp() and ShutDown() or JoinAllSubprocesses().
|
||||
static bool sCanLaunchSubprocesses;
|
||||
|
||||
// The first content child has ID 1, so the chrome process can have ID 0.
|
||||
static uint64_t gContentChildID = 1;
|
||||
|
||||
@ -256,6 +260,8 @@ ContentParent::StartUp()
|
||||
// the main process goes idle before we preallocate a process
|
||||
MessageLoop::current()->PostIdleTask(FROM_HERE, NewRunnableFunction(FirstIdle));
|
||||
}
|
||||
|
||||
sCanLaunchSubprocesses = true;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
@ -263,6 +269,55 @@ ContentParent::ShutDown()
|
||||
{
|
||||
// No-op for now. We rely on normal process shutdown and
|
||||
// ClearOnShutdown() to clean up our state.
|
||||
sCanLaunchSubprocesses = false;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
ContentParent::JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
|
||||
Monitor* aMonitor, bool* aDone)
|
||||
{
|
||||
const nsTArray<ContentParent*>& processes = *aProcesses;
|
||||
for (uint32_t i = 0; i < processes.Length(); ++i) {
|
||||
if (GeckoChildProcessHost* process = processes[i]->mSubprocess) {
|
||||
process->Join();
|
||||
}
|
||||
}
|
||||
{
|
||||
MonitorAutoLock lock(*aMonitor);
|
||||
*aDone = true;
|
||||
lock.Notify();
|
||||
}
|
||||
// Don't touch any arguments to this function from now on.
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
ContentParent::JoinAllSubprocesses()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsAutoTArray<ContentParent*, 8> processes;
|
||||
GetAll(processes);
|
||||
if (processes.IsEmpty()) {
|
||||
printf_stderr("There are no live subprocesses.");
|
||||
return;
|
||||
}
|
||||
|
||||
printf_stderr("Subprocesses are still alive. Doing emergency join.\n");
|
||||
|
||||
bool done = false;
|
||||
Monitor monitor("mozilla.dom.ContentParent.JoinAllSubprocesses");
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(
|
||||
&ContentParent::JoinProcessesIOThread,
|
||||
&processes, &monitor, &done));
|
||||
{
|
||||
MonitorAutoLock lock(monitor);
|
||||
while (!done) {
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
sCanLaunchSubprocesses = false;
|
||||
}
|
||||
|
||||
/*static*/ ContentParent*
|
||||
@ -324,6 +379,10 @@ PrivilegesForApp(mozIApplication* aApp)
|
||||
/*static*/ TabParent*
|
||||
ContentParent::CreateBrowserOrApp(const TabContext& aContext)
|
||||
{
|
||||
if (!sCanLaunchSubprocesses) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
|
||||
if (ContentParent* cp = GetNewOrUsed(aContext.IsBrowserElement())) {
|
||||
nsRefPtr<TabParent> tp(new TabParent(aContext));
|
||||
|
@ -71,6 +71,13 @@ public:
|
||||
static void StartUp();
|
||||
/** Shut down the content-process machinery. */
|
||||
static void ShutDown();
|
||||
/**
|
||||
* Ensure that all subprocesses are terminated and their OS
|
||||
* resources have been reaped. This is synchronous and can be
|
||||
* very expensive in general. It also bypasses the normal
|
||||
* shutdown process.
|
||||
*/
|
||||
static void JoinAllSubprocesses();
|
||||
|
||||
static ContentParent* GetNewOrUsed(bool aForBrowserElement = false);
|
||||
|
||||
@ -136,6 +143,9 @@ private:
|
||||
static nsTArray<ContentParent*>* gNonAppContentParents;
|
||||
static nsTArray<ContentParent*>* gPrivateContent;
|
||||
|
||||
static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
|
||||
Monitor* aMonitor, bool* aDone);
|
||||
|
||||
static void PreallocateAppProcess();
|
||||
static void DelayedPreallocateAppProcess();
|
||||
static void ScheduleDelayedPreallocateAppProcess();
|
||||
|
@ -3,6 +3,7 @@
|
||||
* 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 "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/HalWakeLock.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
@ -139,6 +140,12 @@ PowerManagerService::Restart()
|
||||
// because it relies on the Gonk to initialize the Gecko processes to
|
||||
// restart B2G. It's better to do it here to have a real "restart".
|
||||
StartForceQuitWatchdog(eHalShutdownMode_Restart, mWatchdogTimeoutSecs);
|
||||
// Ensure all content processes are dead before we continue
|
||||
// restarting. This code is used to restart to apply updates, and
|
||||
// if we don't join all the subprocesses, race conditions can cause
|
||||
// them to see an inconsistent view of the application directory.
|
||||
ContentParent::JoinAllSubprocesses();
|
||||
|
||||
// To synchronize any unsaved user data before restarting.
|
||||
SyncProfile();
|
||||
#ifdef XP_UNIX
|
||||
|
@ -71,7 +71,16 @@ ForceQuitWatchdog(void* aParamPtr)
|
||||
if (paramPtr->timeoutSecs > 0 && paramPtr->timeoutSecs <= 30) {
|
||||
// If we shut down normally before the timeout, this thread will
|
||||
// be harmlessly reaped by the OS.
|
||||
sleep(paramPtr->timeoutSecs);
|
||||
TimeStamp deadline =
|
||||
(TimeStamp::Now() + TimeDuration::FromSeconds(paramPtr->timeoutSecs));
|
||||
while (true) {
|
||||
TimeDuration remaining = (deadline - TimeStamp::Now());
|
||||
int sleepSeconds = int(remaining.ToSeconds());
|
||||
if (sleepSeconds <= 0) {
|
||||
break;
|
||||
}
|
||||
sleep(sleepSeconds);
|
||||
}
|
||||
}
|
||||
hal::ShutdownMode mode = paramPtr->mode;
|
||||
delete paramPtr;
|
||||
|
@ -364,6 +364,20 @@ GeckoChildProcessHost::InitializeChannel()
|
||||
lock.Notify();
|
||||
}
|
||||
|
||||
void
|
||||
GeckoChildProcessHost::Join()
|
||||
{
|
||||
AssertIOThread();
|
||||
|
||||
if (!mChildProcessHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this fails, there's nothing we can do.
|
||||
base::KillProcess(mChildProcessHandle, 0, /*wait*/true);
|
||||
mChildProcessHandle = 0;
|
||||
}
|
||||
|
||||
int32_t GeckoChildProcessHost::mChildCounter = 0;
|
||||
|
||||
//
|
||||
|
@ -96,6 +96,11 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Must run on the IO thread. Cause the OS process to exit and
|
||||
* ensure its OS resources are cleaned up.
|
||||
*/
|
||||
void Join();
|
||||
|
||||
protected:
|
||||
GeckoProcessType mProcessType;
|
||||
|
Loading…
Reference in New Issue
Block a user