mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 06:45:42 +00:00
Bug 1446161 - Asynchronously launch preallocated content processes using MozPromise. r=mccr8
There are several layers to this patch: 1. GeckoChildProcessHost now exposes a promise that's resolved when the process handle is available (or rejected if launch failed), as a nonblocking alternative to LaunchAndWaitForProcessHandle. 2. ContentParent builds on this with the private method LaunchSubprocessAsync and the public method PreallocateProcessAsync; synchronous launch continues to exist for the regular on-demand launch path, for the time being. 3. PreallocatedProcessManager now uses async launch, and handles the new "launch in progress" state appropriately. Depends on D8942 Differential Revision: https://phabricator.services.mozilla.com/D8943 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
5379e8a375
commit
dececcae11
@ -622,7 +622,7 @@ bool ContentParent::sEarlySandboxInit = false;
|
||||
|
||||
// PreallocateProcess is called by the PreallocatedProcessManager.
|
||||
// ContentParent then takes this process back within GetNewOrUsedBrowserProcess.
|
||||
/*static*/ already_AddRefed<ContentParent>
|
||||
/*static*/ RefPtr<ContentParent::LaunchPromise>
|
||||
ContentParent::PreallocateProcess()
|
||||
{
|
||||
RefPtr<ContentParent> process =
|
||||
@ -631,11 +631,7 @@ ContentParent::PreallocateProcess()
|
||||
eNotRecordingOrReplaying,
|
||||
/* aRecordingFile = */ EmptyString());
|
||||
|
||||
if (!process->LaunchSubprocess(PROCESS_PRIORITY_PREALLOC)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return process.forget();
|
||||
return process->LaunchSubprocessAsync(PROCESS_PRIORITY_PREALLOC);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
@ -900,7 +896,7 @@ ContentParent::GetNewOrUsedBrowserProcess(Element* aFrameElement,
|
||||
// Create a new process from scratch.
|
||||
RefPtr<ContentParent> p = new ContentParent(aOpener, aRemoteType, recordReplayState, recordingFile);
|
||||
|
||||
if (!p->LaunchSubprocess(aPriority)) {
|
||||
if (!p->LaunchSubprocessSync(aPriority)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -933,7 +929,7 @@ ContentParent::GetNewOrUsedJSPluginProcess(uint32_t aPluginID,
|
||||
|
||||
p = new ContentParent(aPluginID);
|
||||
|
||||
if (!p->LaunchSubprocess(aPriority)) {
|
||||
if (!p->LaunchSubprocessSync(aPriority)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -2199,14 +2195,27 @@ ContentParent::AppendSandboxParams(std::vector<std::string>& aArgs)
|
||||
}
|
||||
#endif // XP_MACOSX && MOZ_CONTENT_SANDBOX
|
||||
|
||||
bool
|
||||
ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */)
|
||||
void
|
||||
ContentParent::LaunchSubprocessInternal(
|
||||
ProcessPriority aInitialPriority,
|
||||
mozilla::Variant<bool*, RefPtr<LaunchPromise>*>&& aRetval)
|
||||
{
|
||||
AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess", OTHER);
|
||||
const bool isSync = aRetval.is<bool*>();
|
||||
|
||||
auto earlyReject = [aRetval, isSync]() {
|
||||
if (isSync) {
|
||||
*aRetval.as<bool*>() = false;
|
||||
} else {
|
||||
*aRetval.as<RefPtr<LaunchPromise>*>() = LaunchPromise::CreateAndReject(
|
||||
GeckoChildProcessHost::LaunchError(), __func__);
|
||||
}
|
||||
};
|
||||
|
||||
if (!ContentProcessManager::GetSingleton()) {
|
||||
// Shutdown has begun, we shouldn't spawn any more child processes.
|
||||
return false;
|
||||
earlyReject();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> extraArgs;
|
||||
@ -2231,12 +2240,14 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
|
||||
if (!shm.Create(prefs.Length())) {
|
||||
NS_ERROR("failed to create shared memory in the parent");
|
||||
MarkAsDead();
|
||||
return false;
|
||||
earlyReject();
|
||||
return;
|
||||
}
|
||||
if (!shm.Map(prefs.Length())) {
|
||||
NS_ERROR("failed to map shared memory in the parent");
|
||||
MarkAsDead();
|
||||
return false;
|
||||
earlyReject();
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the serialized prefs into the shared memory.
|
||||
@ -2312,44 +2323,100 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
|
||||
extraArgs.push_back(NS_ConvertUTF16toUTF8(mRecordingFile).get());
|
||||
}
|
||||
|
||||
if (!mSubprocess->LaunchAndWaitForProcessHandle(extraArgs)) {
|
||||
RefPtr<ContentParent> self(this);
|
||||
|
||||
auto reject = [self, this](GeckoChildProcessHost::LaunchError err) {
|
||||
NS_ERROR("failed to launch child in the parent");
|
||||
MarkAsDead();
|
||||
return false;
|
||||
}
|
||||
return LaunchPromise::CreateAndReject(err, __func__);
|
||||
};
|
||||
|
||||
// See also ActorDestroy.
|
||||
mSelfRef = this;
|
||||
|
||||
base::ProcessId procId =
|
||||
base::GetProcId(mSubprocess->GetChildProcessHandle());
|
||||
Open(mSubprocess->GetChannel(), procId);
|
||||
// Lifetime note: the GeckoChildProcessHost holds a strong reference
|
||||
// to the launch promise, which takes ownership of these closures,
|
||||
// which hold strong references to this ContentParent; the
|
||||
// ContentParent then owns the GeckoChildProcessHost (and that
|
||||
// ownership is not exposed to the cycle collector). Therefore,
|
||||
// this all stays alive until the promise is resolved or rejected.
|
||||
|
||||
auto resolve = [self, this, aInitialPriority, isSync,
|
||||
// Transfer ownership of RAII file descriptor/handle
|
||||
// holders so that they won't be closed before the
|
||||
// child can inherit them.
|
||||
shm = std::move(shm),
|
||||
prefMapHandle = std::move(prefMapHandle)
|
||||
](base::ProcessHandle handle) {
|
||||
AUTO_PROFILER_LABEL("ContentParent::LaunchSubprocess::resolve", OTHER);
|
||||
|
||||
base::ProcessId procId = base::GetProcId(handle);
|
||||
Open(mSubprocess->GetChannel(), procId);
|
||||
#ifdef MOZ_CODE_COVERAGE
|
||||
Unused << SendShareCodeCoverageMutex(
|
||||
CodeCoverageHandler::Get()->GetMutexHandle(procId));
|
||||
Unused << SendShareCodeCoverageMutex(
|
||||
CodeCoverageHandler::Get()->GetMutexHandle(procId));
|
||||
#endif
|
||||
|
||||
InitInternal(aInitialPriority);
|
||||
mIsAlive = true;
|
||||
InitInternal(aInitialPriority);
|
||||
|
||||
ContentProcessManager::GetSingleton()->AddContentProcess(this);
|
||||
ContentProcessManager::GetSingleton()->AddContentProcess(this);
|
||||
|
||||
mHangMonitorActor = ProcessHangMonitor::AddProcess(this);
|
||||
mHangMonitorActor = ProcessHangMonitor::AddProcess(this);
|
||||
|
||||
// Set a reply timeout for CPOWs.
|
||||
SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 0));
|
||||
// Set a reply timeout for CPOWs.
|
||||
SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 0));
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
nsAutoString cpId;
|
||||
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
|
||||
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-initializing", cpId.get());
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
nsAutoString cpId;
|
||||
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
|
||||
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-initializing", cpId.get());
|
||||
}
|
||||
|
||||
Init();
|
||||
|
||||
// Launch time telemetry will return in a later patch (bug 1474991).
|
||||
Unused << isSync;
|
||||
|
||||
return LaunchPromise::CreateAndResolve(self, __func__);
|
||||
};
|
||||
|
||||
if (isSync) {
|
||||
bool ok = mSubprocess->LaunchAndWaitForProcessHandle(std::move(extraArgs));
|
||||
if (ok) {
|
||||
Unused << resolve(mSubprocess->GetChildProcessHandle());
|
||||
} else {
|
||||
Unused << reject(GeckoChildProcessHost::LaunchError{});
|
||||
}
|
||||
*aRetval.as<bool*>() = ok;
|
||||
} else {
|
||||
auto* retptr = aRetval.as<RefPtr<LaunchPromise>*>();
|
||||
if (mSubprocess->AsyncLaunch(std::move(extraArgs))) {
|
||||
RefPtr<GeckoChildProcessHost::HandlePromise> ready =
|
||||
mSubprocess->WhenProcessHandleReady();
|
||||
*retptr = ready->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
||||
std::move(resolve), std::move(reject));
|
||||
} else {
|
||||
*retptr = reject(GeckoChildProcessHost::LaunchError{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Init();
|
||||
/* static */ bool
|
||||
ContentParent::LaunchSubprocessSync(hal::ProcessPriority aInitialPriority)
|
||||
{
|
||||
bool retval;
|
||||
LaunchSubprocessInternal(aInitialPriority, mozilla::AsVariant(&retval));
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Launch time telemetry will return in a later patch (bug 1474991).
|
||||
|
||||
return true;
|
||||
/* static */ RefPtr<ContentParent::LaunchPromise>
|
||||
ContentParent::LaunchSubprocessAsync(hal::ProcessPriority aInitialPriority)
|
||||
{
|
||||
RefPtr<LaunchPromise> retval;
|
||||
LaunchSubprocessInternal(aInitialPriority, mozilla::AsVariant(&retval));
|
||||
return retval;
|
||||
}
|
||||
|
||||
ContentParent::ContentParent(ContentParent* aOpener,
|
||||
@ -2370,7 +2437,7 @@ ContentParent::ContentParent(ContentParent* aOpener,
|
||||
, mRemoteWorkerActors(0)
|
||||
, mNumDestroyingTabs(0)
|
||||
, mIsAvailable(true)
|
||||
, mIsAlive(true)
|
||||
, mIsAlive(false)
|
||||
, mIsForBrowser(!mRemoteType.IsEmpty())
|
||||
, mRecordReplayState(aRecordReplayState)
|
||||
, mRecordingFile(aRecordingFile)
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "mozilla/MemoryReportingProcess.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Variant.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "nsDataHashtable.h"
|
||||
@ -131,10 +132,13 @@ public:
|
||||
|
||||
virtual bool IsContentParent() const override { return true; }
|
||||
|
||||
using LaunchError = GeckoChildProcessHost::LaunchError;
|
||||
using LaunchPromise = GeckoChildProcessHost::LaunchPromise<RefPtr<ContentParent>>;
|
||||
|
||||
/**
|
||||
* Create a subprocess suitable for use later as a content process.
|
||||
*/
|
||||
static already_AddRefed<ContentParent> PreallocateProcess();
|
||||
static RefPtr<LaunchPromise> PreallocateProcess();
|
||||
|
||||
/**
|
||||
* Start up the content-process machinery. This might include
|
||||
@ -797,7 +801,20 @@ private:
|
||||
|
||||
// Launch the subprocess and associated initialization.
|
||||
// Returns false if the process fails to start.
|
||||
bool LaunchSubprocess(hal::ProcessPriority aInitialPriority = hal::PROCESS_PRIORITY_FOREGROUND);
|
||||
// Deprecated in favor of LaunchSubprocessAsync.
|
||||
bool LaunchSubprocessSync(hal::ProcessPriority aInitialPriority);
|
||||
|
||||
// Launch the subprocess and associated initialization;
|
||||
// returns a promise and signals failure by rejecting.
|
||||
// OS-level launching work is dispatched to another thread, but some
|
||||
// initialization (creating IPDL actors, etc.; see Init()) is run on
|
||||
// the main thread.
|
||||
RefPtr<LaunchPromise> LaunchSubprocessAsync(hal::ProcessPriority aInitialPriority);
|
||||
|
||||
// Common implementation of LaunchSubprocess{Sync,Async}.
|
||||
void LaunchSubprocessInternal(
|
||||
hal::ProcessPriority aInitialPriority,
|
||||
mozilla::Variant<bool*, RefPtr<LaunchPromise>*>&& aRetval);
|
||||
|
||||
// Common initialization after sub process launch.
|
||||
void InitInternal(ProcessPriority aPriority);
|
||||
|
@ -48,7 +48,7 @@ private:
|
||||
static mozilla::StaticRefPtr<PreallocatedProcessManagerImpl> sSingleton;
|
||||
|
||||
PreallocatedProcessManagerImpl();
|
||||
~PreallocatedProcessManagerImpl() {}
|
||||
~PreallocatedProcessManagerImpl();
|
||||
DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManagerImpl);
|
||||
|
||||
void Init();
|
||||
@ -67,8 +67,13 @@ private:
|
||||
|
||||
bool mEnabled;
|
||||
bool mShutdown;
|
||||
bool mLaunchInProgress;
|
||||
RefPtr<ContentParent> mPreallocatedProcess;
|
||||
nsTHashtable<nsUint64HashKey> mBlockers;
|
||||
|
||||
bool IsEmpty() const {
|
||||
return !mPreallocatedProcess && !mLaunchInProgress;
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ StaticRefPtr<PreallocatedProcessManagerImpl>
|
||||
@ -92,8 +97,16 @@ NS_IMPL_ISUPPORTS(PreallocatedProcessManagerImpl, nsIObserver)
|
||||
PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
|
||||
: mEnabled(false)
|
||||
, mShutdown(false)
|
||||
, mLaunchInProgress(false)
|
||||
{}
|
||||
|
||||
PreallocatedProcessManagerImpl::~PreallocatedProcessManagerImpl()
|
||||
{
|
||||
// This shouldn't happen, because the promise callbacks should
|
||||
// hold strong references, but let't make absolutely sure:
|
||||
MOZ_RELEASE_ASSERT(!mLaunchInProgress);
|
||||
}
|
||||
|
||||
void
|
||||
PreallocatedProcessManagerImpl::Init()
|
||||
{
|
||||
@ -179,6 +192,9 @@ PreallocatedProcessManagerImpl::Take()
|
||||
bool
|
||||
PreallocatedProcessManagerImpl::Provide(ContentParent* aParent)
|
||||
{
|
||||
// This will take the already-running process even if there's a
|
||||
// launch in progress; if that process hasn't been taken by the
|
||||
// time the launch completes, the new process will be shut down.
|
||||
if (mEnabled && !mShutdown && !mPreallocatedProcess) {
|
||||
mPreallocatedProcess = aParent;
|
||||
}
|
||||
@ -220,7 +236,7 @@ PreallocatedProcessManagerImpl::RemoveBlocker(ContentParent* aParent)
|
||||
// it's possible for a short-lived process to be recycled through
|
||||
// Provide() and Take() before reaching RecvFirstIdle.)
|
||||
mBlockers.RemoveEntry(childID);
|
||||
if (!mPreallocatedProcess && mBlockers.IsEmpty()) {
|
||||
if (IsEmpty() && mBlockers.IsEmpty()) {
|
||||
AllocateAfterDelay();
|
||||
}
|
||||
}
|
||||
@ -230,7 +246,7 @@ PreallocatedProcessManagerImpl::CanAllocate()
|
||||
{
|
||||
return mEnabled &&
|
||||
mBlockers.IsEmpty() &&
|
||||
!mPreallocatedProcess &&
|
||||
IsEmpty() &&
|
||||
!mShutdown &&
|
||||
!ContentParent::IsMaxProcessCountReached(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE));
|
||||
}
|
||||
@ -267,14 +283,31 @@ void
|
||||
PreallocatedProcessManagerImpl::AllocateNow()
|
||||
{
|
||||
if (!CanAllocate()) {
|
||||
if (mEnabled && !mShutdown && !mPreallocatedProcess && !mBlockers.IsEmpty()) {
|
||||
if (mEnabled && !mShutdown && IsEmpty() && !mBlockers.IsEmpty()) {
|
||||
// If it's too early to allocate a process let's retry later.
|
||||
AllocateAfterDelay();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mPreallocatedProcess = ContentParent::PreallocateProcess();
|
||||
RefPtr<PreallocatedProcessManagerImpl> self(this);
|
||||
mLaunchInProgress = true;
|
||||
|
||||
ContentParent::PreallocateProcess()
|
||||
->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
||||
|
||||
[self, this](const RefPtr<ContentParent>& process) {
|
||||
mLaunchInProgress = false;
|
||||
if (CanAllocate()) {
|
||||
mPreallocatedProcess = process;
|
||||
} else {
|
||||
process->ShutDownProcess(ContentParent::SEND_SHUTDOWN_MESSAGE);
|
||||
}
|
||||
},
|
||||
|
||||
[self, this](ContentParent::LaunchError err) {
|
||||
mLaunchInProgress = false;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -43,6 +43,9 @@ class SharedMemory {
|
||||
SetHandle(init_handle, read_only);
|
||||
}
|
||||
|
||||
// Move constructor; transfers ownership.
|
||||
SharedMemory(SharedMemory&& other);
|
||||
|
||||
// Destructor. Will close any open files.
|
||||
~SharedMemory();
|
||||
|
||||
|
@ -31,6 +31,20 @@ SharedMemory::SharedMemory()
|
||||
max_size_(0) {
|
||||
}
|
||||
|
||||
SharedMemory::SharedMemory(SharedMemory&& other) {
|
||||
if (this == &other) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapped_file_ = other.mapped_file_;
|
||||
memory_ = other.memory_;
|
||||
read_only_ = other.read_only_;
|
||||
max_size_ = other.max_size_;
|
||||
|
||||
other.mapped_file_ = -1;
|
||||
other.memory_ = nullptr;
|
||||
}
|
||||
|
||||
SharedMemory::~SharedMemory() {
|
||||
Close();
|
||||
}
|
||||
|
@ -64,6 +64,21 @@ SharedMemory::SharedMemory()
|
||||
max_size_(0) {
|
||||
}
|
||||
|
||||
SharedMemory::SharedMemory(SharedMemory&& other) {
|
||||
if (this == &other) {
|
||||
return;
|
||||
}
|
||||
|
||||
mapped_file_ = other.mapped_file_;
|
||||
memory_ = other.memory_;
|
||||
read_only_ = other.read_only_;
|
||||
max_size_ = other.max_size_;
|
||||
external_section_ = other.external_section_;
|
||||
|
||||
other.mapped_file_ = nullptr;
|
||||
other.memory_ = nullptr;
|
||||
}
|
||||
|
||||
SharedMemory::~SharedMemory() {
|
||||
external_section_ = true;
|
||||
Close();
|
||||
|
@ -346,6 +346,9 @@ GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
|
||||
|
||||
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
|
||||
|
||||
MOZ_ASSERT(mHandlePromise == nullptr);
|
||||
mHandlePromise = new HandlePromise::Private(__func__);
|
||||
|
||||
// Currently this can't fail (see the MOZ_ALWAYS_SUCCEEDS in
|
||||
// MessageLoop::PostTask_Helper), but in the future it possibly
|
||||
// could, in which case this method could return false.
|
||||
@ -494,6 +497,7 @@ GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector<std::string> aExtraOpts
|
||||
// If something failed let's set the error state and notify.
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mProcessState = PROCESS_ERROR;
|
||||
mHandlePromise->Reject(LaunchError{}, __func__);
|
||||
lock.Notify();
|
||||
CHROMIUM_LOG(ERROR) << "Failed to launch " <<
|
||||
XRE_ChildProcessTypeToString(mProcessType) << " subprocess";
|
||||
@ -1125,6 +1129,7 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
mProcessState = PROCESS_CREATED;
|
||||
mHandlePromise->Resolve(process, __func__);
|
||||
lock.Notify();
|
||||
|
||||
mLaunchOptions = nullptr;
|
||||
@ -1149,6 +1154,7 @@ GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid)
|
||||
MOZ_CRASH("can't open handle to child process");
|
||||
}
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mProcessState == PROCESS_CREATED);
|
||||
mProcessState = PROCESS_CONNECTED;
|
||||
lock.Notify();
|
||||
}
|
||||
@ -1170,12 +1176,20 @@ GeckoChildProcessHost::OnChannelError()
|
||||
// in the FIXME comment below.
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (mProcessState < PROCESS_CONNECTED) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mProcessState == PROCESS_CREATED);
|
||||
mProcessState = PROCESS_ERROR;
|
||||
lock.Notify();
|
||||
}
|
||||
// FIXME/bug 773925: save up this error for the next listener.
|
||||
}
|
||||
|
||||
RefPtr<GeckoChildProcessHost::HandlePromise>
|
||||
GeckoChildProcessHost::WhenProcessHandleReady()
|
||||
{
|
||||
MOZ_ASSERT(mHandlePromise != nullptr);
|
||||
return mHandlePromise;
|
||||
}
|
||||
|
||||
void
|
||||
GeckoChildProcessHost::GetQueuedMessages(std::queue<IPC::Message>& queue)
|
||||
{
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
@ -47,7 +48,8 @@ public:
|
||||
|
||||
// Does not block. The IPC channel may not be initialized yet, and
|
||||
// the child process may or may not have been created when this
|
||||
// method returns.
|
||||
// method returns. This GeckoChildProcessHost must not be destroyed
|
||||
// while the launch is in progress.
|
||||
bool AsyncLaunch(StringVector aExtraOpts=StringVector());
|
||||
|
||||
virtual bool WaitUntilConnected(int32_t aTimeoutMs = 0);
|
||||
@ -77,6 +79,15 @@ public:
|
||||
virtual void OnChannelError() override;
|
||||
virtual void GetQueuedMessages(std::queue<IPC::Message>& queue) override;
|
||||
|
||||
struct LaunchError {};
|
||||
template <typename T>
|
||||
using LaunchPromise = mozilla::MozPromise<T, LaunchError, /* excl: */ false>;
|
||||
using HandlePromise = LaunchPromise<base::ProcessHandle>;
|
||||
|
||||
// Resolves to the process handle when it's available (see
|
||||
// LaunchAndWaitForProcessHandle); use with AsyncLaunch.
|
||||
RefPtr<HandlePromise> WhenProcessHandleReady();
|
||||
|
||||
virtual void InitializeChannel();
|
||||
|
||||
virtual bool CanShutdown() override { return true; }
|
||||
@ -170,6 +181,7 @@ protected:
|
||||
#if defined(OS_MACOSX)
|
||||
task_t mChildTask;
|
||||
#endif
|
||||
RefPtr<HandlePromise::Private> mHandlePromise;
|
||||
|
||||
bool OpenPrivilegedHandle(base::ProcessId aPid);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user