Don't deadlock on a child process for a CPOW (bug 905896, r=cjones).

This commit is contained in:
David Anderson 2013-08-26 21:56:57 -07:00
parent 25c513e3f0
commit 86124d9cd4
8 changed files with 71 additions and 3 deletions

View File

@ -939,6 +939,10 @@ ContentParent::OnChannelConnected(int32_t pid)
} }
#endif #endif
} }
// Set a reply timeout. The only time the parent process will actually
// timeout is through urgent messages (which are used by CPOWs).
SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 3000));
} }
void void
@ -2797,5 +2801,14 @@ ContentParent::RecvKeywordToURI(const nsCString& aKeyword, OptionalInputStreamPa
return true; return true;
} }
bool
ContentParent::ShouldContinueFromReplyTimeout()
{
// The only time ContentParent sends blocking messages is for CPOWs, so
// timeouts should only ever occur in electrolysis-enabled sessions.
MOZ_ASSERT(Preferences::GetBool("browser.tabs.remote", false));
return false;
}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -180,6 +180,8 @@ protected:
void OnChannelConnected(int32_t pid) MOZ_OVERRIDE; void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why); virtual void ActorDestroy(ActorDestroyReason why);
bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
private: private:
static nsDataHashtable<nsStringHashKey, ContentParent*> *sAppContentParents; static nsDataHashtable<nsStringHashKey, ContentParent*> *sAppContentParents;
static nsTArray<ContentParent*>* sNonAppContentParents; static nsTArray<ContentParent*>* sNonAppContentParents;

View File

@ -322,6 +322,15 @@ SyncChannel::ShouldContinueFromTimeout()
cont = static_cast<SyncListener*>(mListener.get())->OnReplyTimeout(); cont = static_cast<SyncListener*>(mListener.get())->OnReplyTimeout();
} }
static enum { UNKNOWN, NOT_DEBUGGING, DEBUGGING } sDebuggingChildren = UNKNOWN;
if (sDebuggingChildren == UNKNOWN) {
sDebuggingChildren = getenv("MOZ_DEBUG_CHILD_PROCESS") ? DEBUGGING : NOT_DEBUGGING;
}
if (sDebuggingChildren == DEBUGGING) {
return true;
}
if (!cont) { if (!cont) {
// NB: there's a sublety here. If parents were allowed to // NB: there's a sublety here. If parents were allowed to
// send sync messages to children, then it would be possible // send sync messages to children, then it would be possible

View File

@ -1,6 +1,8 @@
include protocol PTestDataStructuresSub; include protocol PTestDataStructuresSub;
include PTestDataStructuresCommon; include PTestDataStructuresCommon;
include "mozilla/GfxMessageUtils.h";
namespace mozilla { namespace mozilla {
namespace _ipdltest { namespace _ipdltest {

View File

@ -9,12 +9,14 @@ parent:
sync Test3() returns (uint32_t result); sync Test3() returns (uint32_t result);
sync Test4_Begin(); sync Test4_Begin();
sync Test4_NestedSync(); sync Test4_NestedSync();
sync FinalTest_Begin();
child: child:
async Start(); async Start();
urgent Reply1() returns (uint32_t result); urgent Reply1() returns (uint32_t result);
urgent Reply2() returns (uint32_t result); urgent Reply2() returns (uint32_t result);
urgent Test4_Reenter(); urgent Test4_Reenter();
urgent FinalTest_Hang();
}; };
} // namespace _ipdltest } // namespace _ipdltest

View File

@ -3,6 +3,13 @@
#include "IPDLUnitTests.h" // fail etc. #include "IPDLUnitTests.h" // fail etc.
#include <unistd.h> #include <unistd.h>
template<>
struct RunnableMethodTraits<mozilla::_ipdltest::TestUrgencyParent>
{
static void RetainCallee(mozilla::_ipdltest::TestUrgencyParent* obj) { }
static void ReleaseCallee(mozilla::_ipdltest::TestUrgencyParent* obj) { }
};
namespace mozilla { namespace mozilla {
namespace _ipdltest { namespace _ipdltest {
@ -74,6 +81,21 @@ TestUrgencyParent::RecvTest4_NestedSync()
return false; return false;
} }
bool
TestUrgencyParent::RecvFinalTest_Begin()
{
SetReplyTimeoutMs(2000);
if (CallFinalTest_Hang())
fail("should have failed due to timeout");
if (!GetIPCChannel()->Unsound_IsClosed())
fail("channel should have closed");
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &TestUrgencyParent::Close));
return false;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// child // child
@ -115,6 +137,10 @@ TestUrgencyChild::RecvStart()
if (!SendTest4_Begin()) if (!SendTest4_Begin())
fail("calling SendTest4_Begin"); fail("calling SendTest4_Begin");
// This must be the last test, since the child process may die.
if (SendFinalTest_Begin())
fail("Final test should not have succeeded");
Close(); Close();
return true; return true;
@ -153,6 +179,13 @@ TestUrgencyChild::AnswerTest4_Reenter()
return true; return true;
} }
bool
TestUrgencyChild::AnswerFinalTest_Hang()
{
sleep(10);
return true;
}
TestUrgencyChild::TestUrgencyChild() TestUrgencyChild::TestUrgencyChild()
: test_(0) : test_(0)
{ {

View File

@ -27,14 +27,20 @@ public:
bool RecvTest3(uint32_t *value); bool RecvTest3(uint32_t *value);
bool RecvTest4_Begin(); bool RecvTest4_Begin();
bool RecvTest4_NestedSync(); bool RecvTest4_NestedSync();
bool RecvFinalTest_Begin();
bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE
{
return false;
}
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
{ {
if (NormalShutdown != why) if (AbnormalShutdown != why)
fail("unexpected destruction!"); fail("unexpected destruction!");
passed("ok"); passed("ok");
QuitParent(); QuitParent();
} }
private: private:
bool inreply_; bool inreply_;
}; };
@ -51,10 +57,11 @@ public:
bool AnswerReply1(uint32_t *reply); bool AnswerReply1(uint32_t *reply);
bool AnswerReply2(uint32_t *reply); bool AnswerReply2(uint32_t *reply);
bool AnswerTest4_Reenter(); bool AnswerTest4_Reenter();
bool AnswerFinalTest_Hang();
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
{ {
if (NormalShutdown != why) if (AbnormalShutdown != why)
fail("unexpected destruction!"); fail("unexpected destruction!");
QuitChild(); QuitChild();
} }

View File

@ -594,7 +594,7 @@ JavaScriptParent::unwrap(JSContext *cx, ObjectId objId)
bool bool
JavaScriptParent::ipcfail(JSContext *cx) JavaScriptParent::ipcfail(JSContext *cx)
{ {
JS_ReportError(cx, "catastrophic IPC failure"); JS_ReportError(cx, "child process crashed or timedout");
return false; return false;
} }