mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Force child processes to close and wait for them on shutdown
This commit is contained in:
parent
6e6fa8eaec
commit
0f1d5c36a0
@ -21,6 +21,8 @@ child:
|
||||
|
||||
TestShell();
|
||||
~TestShell();
|
||||
|
||||
Quit();
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "base/task.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
@ -16,6 +19,7 @@ namespace dom {
|
||||
ContentProcessChild* ContentProcessChild::sSingleton;
|
||||
|
||||
ContentProcessChild::ContentProcessChild()
|
||||
: mQuit(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
@ -73,9 +77,29 @@ ContentProcessChild::TestShellDestructor(TestShellProtocolChild* shell)
|
||||
void
|
||||
ContentProcessChild::Quit()
|
||||
{
|
||||
NS_ASSERTION(mQuit, "Exiting uncleanly!");
|
||||
mIFrames.Clear();
|
||||
mTestShells.Clear();
|
||||
}
|
||||
|
||||
static void
|
||||
QuitIOLoop()
|
||||
{
|
||||
MessageLoop::current()->Quit();
|
||||
}
|
||||
|
||||
nsresult
|
||||
ContentProcessChild::RecvQuit()
|
||||
{
|
||||
mQuit = PR_TRUE;
|
||||
|
||||
Quit();
|
||||
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(&QuitIOLoop));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
virtual nsresult TestShellDestructor(TestShellProtocolChild*);
|
||||
|
||||
void Quit();
|
||||
virtual nsresult RecvQuit();
|
||||
|
||||
private:
|
||||
static ContentProcessChild* sSingleton;
|
||||
@ -40,6 +41,8 @@ private:
|
||||
nsTArray<nsAutoPtr<IFrameEmbeddingProtocolChild> > mIFrames;
|
||||
nsTArray<nsAutoPtr<TestShellProtocolChild> > mTestShells;
|
||||
|
||||
PRBool mQuit;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(ContentProcessChild);
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,19 @@
|
||||
#include "TabParent.h"
|
||||
#include "mozilla/ipc/TestShellParent.h"
|
||||
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using mozilla::MonitorAutoEnter;
|
||||
|
||||
namespace {
|
||||
PRBool gSingletonDied = PR_FALSE;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -15,10 +27,20 @@ ContentProcessParent* ContentProcessParent::gSingleton;
|
||||
ContentProcessParent*
|
||||
ContentProcessParent::GetSingleton()
|
||||
{
|
||||
if (!gSingleton)
|
||||
gSingleton = new ContentProcessParent();
|
||||
|
||||
return gSingleton;
|
||||
if (!gSingleton && !gSingletonDied) {
|
||||
nsRefPtr<ContentProcessParent> parent = new ContentProcessParent();
|
||||
if (parent) {
|
||||
nsCOMPtr<nsIObserverService> obs =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
if (obs) {
|
||||
if (NS_SUCCEEDED(obs->AddObserver(parent, "xpcom-shutdown",
|
||||
PR_FALSE))) {
|
||||
gSingleton = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return gSingleton;
|
||||
}
|
||||
|
||||
TabParent*
|
||||
@ -34,15 +56,50 @@ ContentProcessParent::CreateTestShell()
|
||||
}
|
||||
|
||||
ContentProcessParent::ContentProcessParent()
|
||||
: mSubprocess(GeckoProcessType_Content)
|
||||
: mMonitor("ContentProcessParent::mMonitor")
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
// TODO: async launching!
|
||||
mSubprocess.SyncLaunch();
|
||||
Open(mSubprocess.GetChannel());
|
||||
mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, this);
|
||||
mSubprocess->SyncLaunch();
|
||||
Open(mSubprocess->GetChannel());
|
||||
}
|
||||
|
||||
ContentProcessParent::~ContentProcessParent()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(gSingleton == this, "More than one singleton?!");
|
||||
gSingletonDied = PR_TRUE;
|
||||
gSingleton = nsnull;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(ContentProcessParent, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContentProcessParent::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const PRUnichar* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
|
||||
SendQuit();
|
||||
#ifdef OS_WIN
|
||||
MonitorAutoEnter mon(mMonitor);
|
||||
while (mSubprocess) {
|
||||
mon.Wait();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ContentProcessParent::OnWaitableEventSignaled(base::WaitableEvent *event)
|
||||
{
|
||||
// The child process has died! Sadly we're on the wrong thread to do much.
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
MonitorAutoEnter mon(mMonitor);
|
||||
mSubprocess = nsnull;
|
||||
mon.Notify();
|
||||
}
|
||||
|
||||
IFrameEmbeddingProtocolParent*
|
||||
|
@ -4,9 +4,14 @@
|
||||
#ifndef mozilla_dom_ContentProcessParent_h
|
||||
#define mozilla_dom_ContentProcessParent_h
|
||||
|
||||
#include "base/waitable_event_watcher.h"
|
||||
|
||||
#include "mozilla/dom/ContentProcessProtocolParent.h"
|
||||
#include "mozilla/ipc/GeckoChildProcessHost.h"
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class TestShellParent;
|
||||
@ -17,7 +22,9 @@ namespace dom {
|
||||
class TabParent;
|
||||
|
||||
class ContentProcessParent
|
||||
: private ContentProcessProtocolParent
|
||||
: private ContentProcessProtocolParent,
|
||||
public base::WaitableEventWatcher::Delegate,
|
||||
public nsIObserver
|
||||
{
|
||||
private:
|
||||
typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
|
||||
@ -30,6 +37,11 @@ public:
|
||||
static ContentProcessParent* FreeSingleton();
|
||||
#endif
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
virtual void OnWaitableEventSignaled(base::WaitableEvent *event);
|
||||
|
||||
TabParent* CreateTab(const MagicWindowHandle& hwnd);
|
||||
mozilla::ipc::TestShellParent* CreateTestShell();
|
||||
|
||||
@ -50,7 +62,9 @@ private:
|
||||
virtual TestShellProtocolParent* TestShellConstructor();
|
||||
virtual nsresult TestShellDestructor(TestShellProtocolParent* shell);
|
||||
|
||||
GeckoChildProcessHost mSubprocess;
|
||||
mozilla::Monitor mMonitor;
|
||||
|
||||
GeckoChildProcessHost* mSubprocess;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -51,6 +51,7 @@ PluginProcessParent::PluginProcessParent(const std::string& aPluginFilePath) :
|
||||
GeckoChildProcessHost(GeckoProcessType_Plugin),
|
||||
mPluginFilePath(aPluginFilePath)
|
||||
{
|
||||
// XXXbent Need to catch crashing plugins by watching the process event!
|
||||
}
|
||||
|
||||
PluginProcessParent::~PluginProcessParent()
|
||||
|
@ -97,8 +97,14 @@ class ChildProcessHost :
|
||||
// Sends the given notification to the notification service on the UI thread.
|
||||
void Notify(NotificationType type);
|
||||
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
protected:
|
||||
#endif
|
||||
// WaitableEventWatcher::Delegate implementation:
|
||||
virtual void OnWaitableEventSignaled(base::WaitableEvent *event);
|
||||
#ifdef CHROMIUM_MOZILLA_BUILD
|
||||
private:
|
||||
#endif
|
||||
|
||||
// By using an internal class as the IPC::Channel::Listener, we can intercept
|
||||
// OnMessageReceived/OnChannelConnected and do our own processing before
|
||||
|
@ -53,11 +53,13 @@ struct RunnableMethodTraits<GeckoChildProcessHost>
|
||||
static void ReleaseCallee(GeckoChildProcessHost* obj) { }
|
||||
};
|
||||
|
||||
GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType)
|
||||
GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
|
||||
base::WaitableEventWatcher::Delegate* aDelegate)
|
||||
: ChildProcessHost(RENDER_PROCESS), // FIXME/cjones: we should own this enum
|
||||
mProcessType(aProcessType),
|
||||
mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
|
||||
mLaunched(false)
|
||||
mLaunched(false),
|
||||
mDelegate(aDelegate)
|
||||
{
|
||||
}
|
||||
|
||||
@ -155,3 +157,12 @@ GeckoChildProcessHost::OnChannelError()
|
||||
{
|
||||
// XXXbent Notify that the child process is gone?
|
||||
}
|
||||
|
||||
void
|
||||
GeckoChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event)
|
||||
{
|
||||
if (mDelegate) {
|
||||
mDelegate->OnWaitableEventSignaled(event);
|
||||
}
|
||||
ChildProcessHost::OnWaitableEventSignaled(event);
|
||||
}
|
||||
|
@ -56,7 +56,8 @@ protected:
|
||||
typedef mozilla::Monitor Monitor;
|
||||
|
||||
public:
|
||||
GeckoChildProcessHost(GeckoProcessType aProcessType=GeckoProcessType_Default);
|
||||
GeckoChildProcessHost(GeckoProcessType aProcessType=GeckoProcessType_Default,
|
||||
base::WaitableEventWatcher::Delegate* aDelegate=nsnull);
|
||||
|
||||
bool SyncLaunch(std::vector<std::wstring> aExtraOpts=std::vector<std::wstring>());
|
||||
bool AsyncLaunch(std::vector<std::wstring> aExtraOpts=std::vector<std::wstring>());
|
||||
@ -67,6 +68,8 @@ public:
|
||||
|
||||
virtual bool CanShutdown() { return true; }
|
||||
|
||||
virtual void OnWaitableEventSignaled(base::WaitableEvent *event);
|
||||
|
||||
IPC::Channel* GetChannel() {
|
||||
return channelp();
|
||||
}
|
||||
@ -85,6 +88,8 @@ protected:
|
||||
base::file_handle_mapping_vector mFileMap;
|
||||
#endif
|
||||
|
||||
base::WaitableEventWatcher::Delegate* mDelegate;
|
||||
|
||||
private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost);
|
||||
};
|
||||
|
@ -85,6 +85,7 @@
|
||||
|
||||
using mozilla::ipc::GeckoChildProcessHost;
|
||||
using mozilla::ipc::GeckoThread;
|
||||
using mozilla::ipc::BrowserProcessSubThread;
|
||||
using mozilla::ipc::ScopedXREEmbed;
|
||||
|
||||
using mozilla::plugins::PluginThreadChild;
|
||||
@ -238,6 +239,8 @@ XRE_StringToChildProcessType(const char* aProcessTypeString)
|
||||
#ifdef MOZ_IPC
|
||||
static GeckoProcessType sChildProcessType = GeckoProcessType_Default;
|
||||
|
||||
static MessageLoop* sIOMessageLoop;
|
||||
|
||||
nsresult
|
||||
XRE_InitChildProcess(int aArgc,
|
||||
char* aArgv[],
|
||||
@ -288,7 +291,11 @@ XRE_InitChildProcess(int aArgc,
|
||||
ChildProcess process(mainThread);
|
||||
|
||||
// Do IPC event loop
|
||||
MessageLoop::current()->Run();
|
||||
sIOMessageLoop = MessageLoop::current();
|
||||
|
||||
sIOMessageLoop->Run();
|
||||
|
||||
sIOMessageLoop = nsnull;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -300,6 +307,16 @@ XRE_GetProcessType()
|
||||
return sChildProcessType;
|
||||
}
|
||||
|
||||
MessageLoop*
|
||||
XRE_GetIOMessageLoop()
|
||||
{
|
||||
if (sChildProcessType == GeckoProcessType_Default) {
|
||||
NS_ASSERTION(!sIOMessageLoop, "Shouldn't be set on parent process!");
|
||||
return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
|
||||
}
|
||||
return sIOMessageLoop;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class MainFunctionRunnable : public nsRunnable
|
||||
|
@ -477,6 +477,9 @@ class MessageLoop;
|
||||
XRE_API(void,
|
||||
XRE_ShutdownChildProcess, (MessageLoop* aUILoop))
|
||||
|
||||
XRE_API(MessageLoop*,
|
||||
XRE_GetIOMessageLoop, ())
|
||||
|
||||
struct JSContext;
|
||||
struct JSString;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user