зеркало из https://github.com/mozilla/pjs.git
fixes bug 225016 "make IPC startup handshake (send CLIENT_HELLO, wait for CLIENT_ID) synchronous" r=timeless
This commit is contained in:
Родитель
672c056aa6
Коммит
b9630144ad
|
@ -1,3 +1,4 @@
|
|||
/* vim:set ts=4 sw=4 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -19,7 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@netscape.com>
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -164,24 +165,59 @@ ipcService::~ipcService()
|
|||
nsresult
|
||||
ipcService::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIObserverService> observ(do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (observ) {
|
||||
if (observ)
|
||||
observ->AddObserver(this, "xpcom-shutdown", PR_FALSE);
|
||||
observ->AddObserver(this, "profile-change-net-teardown", PR_FALSE);
|
||||
observ->AddObserver(this, "profile-change-net-restore", PR_FALSE);
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
mTransport = new ipcTransport();
|
||||
if (!mTransport)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(mTransport);
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else {
|
||||
rv = mTransport->Init(this, &mClientID);
|
||||
if (NS_FAILED(rv))
|
||||
mTransport = nsnull;
|
||||
else {
|
||||
//
|
||||
// broadcast IPC startup...
|
||||
//
|
||||
NS_CreateServicesFromCategory(IPC_SERVICE_STARTUP_CATEGORY,
|
||||
NS_STATIC_CAST(ipcIService *, this),
|
||||
IPC_SERVICE_STARTUP_TOPIC);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mTransport->Init(this);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
void
|
||||
ipcService::Shutdown()
|
||||
{
|
||||
//
|
||||
// broadcast IPC shutdown...
|
||||
//
|
||||
nsCOMPtr<nsIObserverService> observ(
|
||||
do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (observ)
|
||||
observ->NotifyObservers(NS_STATIC_CAST(ipcIService *, this),
|
||||
IPC_SERVICE_SHUTDOWN_TOPIC, nsnull);
|
||||
|
||||
return NS_OK;
|
||||
// error out any pending queries
|
||||
while (mQueryQ.First()) {
|
||||
ipcClientQuery *query = mQueryQ.First();
|
||||
query->OnQueryComplete(NS_ERROR_ABORT, NULL);
|
||||
mQueryQ.DeleteFirst();
|
||||
}
|
||||
|
||||
// disconnect any message observers
|
||||
mObserverDB.Reset(ipcReleaseMessageObserver, nsnull);
|
||||
|
||||
// drop daemon connection
|
||||
if (mTransport) {
|
||||
mTransport->Shutdown();
|
||||
mTransport = nsnull;
|
||||
}
|
||||
|
||||
mClientID = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -245,44 +281,6 @@ ipcService::OnIPCMError(const ipcmMessageError *msg)
|
|||
mQueryQ.DeleteFirst();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ipcService::
|
||||
ProcessDelayedMsgQ_Event::ProcessDelayedMsgQ_Event(ipcService *serv,
|
||||
ipcMessageQ *msgQ)
|
||||
{
|
||||
NS_ADDREF(mServ = serv);
|
||||
mMsgQ = msgQ;
|
||||
}
|
||||
|
||||
ipcService::
|
||||
ProcessDelayedMsgQ_Event::~ProcessDelayedMsgQ_Event()
|
||||
{
|
||||
NS_RELEASE(mServ);
|
||||
}
|
||||
|
||||
void * PR_CALLBACK
|
||||
ipcService::ProcessDelayedMsgQ_EventHandler(PLEvent *plevent)
|
||||
{
|
||||
LOG(("ipcService::ProcessDelayedMsgQ_EventHandler\n"));
|
||||
|
||||
ProcessDelayedMsgQ_Event *ev = (ProcessDelayedMsgQ_Event *) plevent;
|
||||
|
||||
while (!ev->mMsgQ->IsEmpty()) {
|
||||
ipcMessage *msg = ev->mMsgQ->First();
|
||||
ev->mMsgQ->RemoveFirst();
|
||||
ev->mServ->OnMessageAvailable(msg);
|
||||
delete msg;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void PR_CALLBACK
|
||||
ipcService::ProcessDelayedMsgQ_EventCleanup(PLEvent *plevent)
|
||||
{
|
||||
delete (ProcessDelayedMsgQ_Event *) plevent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// interface impl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -292,8 +290,7 @@ NS_IMPL_ISUPPORTS2(ipcService, ipcIService, nsIObserver)
|
|||
NS_IMETHODIMP
|
||||
ipcService::GetClientID(PRUint32 *clientID)
|
||||
{
|
||||
if (mClientID == 0)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
NS_ENSURE_TRUE(mClientID != 0, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
*clientID = mClientID;
|
||||
return NS_OK;
|
||||
|
@ -464,21 +461,8 @@ ipcService::SendMessage(PRUint32 clientID,
|
|||
NS_IMETHODIMP
|
||||
ipcService::Observe(nsISupports *subject, const char *topic, const PRUnichar *data)
|
||||
{
|
||||
if (strcmp(topic, "xpcom-shutdown") == 0 ||
|
||||
strcmp(topic, "profile-change-net-teardown") == 0) {
|
||||
// disconnect any message observers
|
||||
mObserverDB.Reset(ipcReleaseMessageObserver, nsnull);
|
||||
|
||||
// drop daemon connection
|
||||
if (mTransport) {
|
||||
mTransport->Shutdown();
|
||||
NS_RELEASE(mTransport);
|
||||
}
|
||||
}
|
||||
else if (strcmp(topic, "profile-change-net-restore") == 0) {
|
||||
if (mTransport)
|
||||
mTransport->Init(this);
|
||||
}
|
||||
if (strcmp(topic, "xpcom-shutdown") == 0)
|
||||
Shutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -486,43 +470,10 @@ ipcService::Observe(nsISupports *subject, const char *topic, const PRUnichar *da
|
|||
// ipcTransportObserver impl
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
ipcService::OnConnectionEstablished(PRUint32 clientID)
|
||||
{
|
||||
LOG(("ipcService::OnConnectionEstablished [cid=%u]\n", clientID));
|
||||
|
||||
mClientID = clientID;
|
||||
|
||||
//
|
||||
// enumerate ipc startup category...
|
||||
//
|
||||
NS_CreateServicesFromCategory(IPC_SERVICE_STARTUP_CATEGORY,
|
||||
NS_STATIC_CAST(ipcIService *, this),
|
||||
IPC_SERVICE_STARTUP_TOPIC);
|
||||
}
|
||||
|
||||
void
|
||||
ipcService::OnConnectionLost()
|
||||
{
|
||||
mClientID = 0;
|
||||
|
||||
//
|
||||
// error out any pending queries
|
||||
//
|
||||
while (mQueryQ.First()) {
|
||||
ipcClientQuery *query = mQueryQ.First();
|
||||
query->OnQueryComplete(NS_ERROR_ABORT, NULL);
|
||||
mQueryQ.DeleteFirst();
|
||||
}
|
||||
|
||||
//
|
||||
// broadcast ipc shutdown...
|
||||
//
|
||||
nsCOMPtr<nsIObserverService> observ(
|
||||
do_GetService("@mozilla.org/observer-service;1"));
|
||||
if (observ)
|
||||
observ->NotifyObservers(NS_STATIC_CAST(ipcIService *, this),
|
||||
IPC_SERVICE_SHUTDOWN_TOPIC, nsnull);
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
#ifndef ipcService_h__
|
||||
#define ipcService_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "plevent.h"
|
||||
|
||||
#include "ipcIService.h"
|
||||
|
@ -68,9 +68,9 @@ public:
|
|||
virtual ~ipcService();
|
||||
|
||||
nsresult Init();
|
||||
void Shutdown();
|
||||
|
||||
// ipcTransportObserver:
|
||||
void OnConnectionEstablished(PRUint32 clientID);
|
||||
void OnConnectionLost();
|
||||
void OnMessageAvailable(const ipcMessage *);
|
||||
|
||||
|
@ -80,20 +80,10 @@ private:
|
|||
void OnIPCMClientInfo(const ipcmMessageClientInfo *);
|
||||
void OnIPCMError(const ipcmMessageError *);
|
||||
|
||||
struct ProcessDelayedMsgQ_Event : PLEvent {
|
||||
ProcessDelayedMsgQ_Event(ipcService *, ipcMessageQ *);
|
||||
~ProcessDelayedMsgQ_Event();
|
||||
ipcService *mServ;
|
||||
ipcMessageQ *mMsgQ;
|
||||
};
|
||||
PR_STATIC_CALLBACK(void*) ProcessDelayedMsgQ_EventHandler(PLEvent *);
|
||||
PR_STATIC_CALLBACK(void) ProcessDelayedMsgQ_EventCleanup(PLEvent *);
|
||||
|
||||
nsHashtable mObserverDB;
|
||||
ipcTransport *mTransport;
|
||||
PRUint32 mClientID;
|
||||
|
||||
ipcClientQueryQ mQueryQ;
|
||||
nsHashtable mObserverDB;
|
||||
nsRefPtr<ipcTransport> mTransport;
|
||||
ipcClientQueryQ mQueryQ;
|
||||
PRUint32 mClientID;
|
||||
};
|
||||
|
||||
#endif // !ipcService_h__
|
||||
|
|
|
@ -89,51 +89,51 @@ IPC_OnMessageAvailable(ipcMessage *msg)
|
|||
nsresult
|
||||
IPC_SpawnDaemon(const char *path)
|
||||
{
|
||||
PRFileDesc *readable = NULL, *writable = NULL;
|
||||
PRProcessAttr *attr = NULL;
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
char *const argv[] = { (char *const) path, NULL };
|
||||
char c;
|
||||
PRFileDesc *readable = NULL, *writable = NULL;
|
||||
PRProcessAttr *attr = NULL;
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
char *const argv[] = { (char *const) path, NULL };
|
||||
char c;
|
||||
|
||||
// setup an anonymous pipe that we can use to determine when the daemon
|
||||
// process has started up. the daemon will write a char to the pipe, and
|
||||
// when we read it, we'll know to proceed with trying to connect to the
|
||||
// daemon's socket port.
|
||||
// setup an anonymous pipe that we can use to determine when the daemon
|
||||
// process has started up. the daemon will write a char to the pipe, and
|
||||
// when we read it, we'll know to proceed with trying to connect to the
|
||||
// daemon's socket port.
|
||||
|
||||
if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
|
||||
goto end;
|
||||
PR_SetFDInheritable(writable, PR_TRUE);
|
||||
if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
|
||||
goto end;
|
||||
PR_SetFDInheritable(writable, PR_TRUE);
|
||||
|
||||
attr = PR_NewProcessAttr();
|
||||
if (!attr)
|
||||
goto end;
|
||||
attr = PR_NewProcessAttr();
|
||||
if (!attr)
|
||||
goto end;
|
||||
|
||||
if (PR_ProcessAttrSetInheritableFD(attr, writable, IPC_STARTUP_PIPE_NAME) != PR_SUCCESS)
|
||||
goto end;
|
||||
if (PR_ProcessAttrSetInheritableFD(attr, writable, IPC_STARTUP_PIPE_NAME) != PR_SUCCESS)
|
||||
goto end;
|
||||
|
||||
if (PR_CreateProcessDetached(path, argv, NULL, attr) != PR_SUCCESS)
|
||||
goto end;
|
||||
if (PR_CreateProcessDetached(path, argv, NULL, attr) != PR_SUCCESS)
|
||||
goto end;
|
||||
|
||||
if ((PR_Read(readable, &c, 1) != 1) && (c != IPC_STARTUP_PIPE_MAGIC))
|
||||
goto end;
|
||||
if ((PR_Read(readable, &c, 1) != 1) && (c != IPC_STARTUP_PIPE_MAGIC))
|
||||
goto end;
|
||||
|
||||
rv = NS_OK;
|
||||
rv = NS_OK;
|
||||
end:
|
||||
if (readable)
|
||||
PR_Close(readable);
|
||||
if (writable)
|
||||
PR_Close(writable);
|
||||
if (attr)
|
||||
PR_DestroyProcessAttr(attr);
|
||||
return rv;
|
||||
}
|
||||
if (readable)
|
||||
PR_Close(readable);
|
||||
if (writable)
|
||||
PR_Close(writable);
|
||||
if (attr)
|
||||
PR_DestroyProcessAttr(attr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcTransport
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
ipcTransport::Init(ipcTransportObserver *obs)
|
||||
ipcTransport::Init(ipcTransportObserver *obs, PRUint32 *clientID)
|
||||
{
|
||||
LOG(("ipcTransport::Init\n"));
|
||||
|
||||
|
@ -142,25 +142,53 @@ ipcTransport::Init(ipcTransportObserver *obs)
|
|||
nsCAutoString path;
|
||||
|
||||
rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = file->AppendNative(NS_LITERAL_CSTRING(IPC_DAEMON_APP_NAME));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = file->GetNativePath(path);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// stash reference to self so we can handle the callbacks.
|
||||
NS_ADDREF(gTransport = this);
|
||||
|
||||
rv = IPC_Connect(path.get());
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = IPC_SendMsg(new ipcmMessageClientHello());
|
||||
// if we failed to connect or failed to send the client HELLO
|
||||
// message, then bail.
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mObserver = obs;
|
||||
else
|
||||
NS_RELEASE(gTransport);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// okay, send the CLIENT_HELLO message, and wait for the CLIENT_ID
|
||||
// response message from the IPC daemon.
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
mHaveConnection = PR_TRUE;
|
||||
|
||||
ipcMessage *reply = nsnull;
|
||||
rv = SendMsg_Locked(new ipcmMessageClientHello(), PR_TRUE, &reply);
|
||||
if (NS_SUCCEEDED(rv) && reply &&
|
||||
reply->Target().Equals(IPCM_TARGET) &&
|
||||
IPCM_GetMsgType(reply) == IPCM_MSG_TYPE_CLIENT_ID) {
|
||||
// remember our client ID
|
||||
ipcMessageCast<ipcmMessageClientID> msg(reply);
|
||||
|
||||
*clientID = msg->ClientID();
|
||||
mHaveConnection = PR_TRUE;
|
||||
mObserver = obs;
|
||||
|
||||
LOG(("connected w/ client ID = %u\n", *clientID));
|
||||
return rv; // return with success!
|
||||
}
|
||||
|
||||
mHaveConnection = PR_FALSE;
|
||||
}
|
||||
// otherwise, we need to tear down the connection, and cleanup.
|
||||
IPC_Disconnect();
|
||||
}
|
||||
|
||||
// cleanup before exiting
|
||||
NS_RELEASE(gTransport);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -169,7 +197,6 @@ ipcTransport::Shutdown()
|
|||
{
|
||||
LOG(("ipcTransport::Shutdown\n"));
|
||||
|
||||
mObserver = 0;
|
||||
return IPC_Disconnect();
|
||||
}
|
||||
|
||||
|
@ -181,48 +208,53 @@ ipcTransport::SendMsg(ipcMessage *msg, PRBool sync)
|
|||
|
||||
LOG(("ipcTransport::SendMsg [msg=%p dataLen=%u]\n", msg, msg->DataLen()));
|
||||
|
||||
nsresult rv;
|
||||
ipcMessage *syncReply = nsnull;
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
nsresult rv;
|
||||
NS_ENSURE_TRUE(mHaveConnection, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (sync) {
|
||||
msg->SetFlag(IPC_MSG_FLAG_SYNC_QUERY);
|
||||
// flag before sending to avoid race with background thread.
|
||||
mSyncWaiting = PR_TRUE;
|
||||
}
|
||||
|
||||
if (mHaveConnection) {
|
||||
rv = IPC_SendMsg(msg);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
else {
|
||||
LOG((" delaying message until connected\n"));
|
||||
mDelayedQ.Append(msg);
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
// XXX we need to break out of this loop if the connection is lost.
|
||||
while (!mSyncReplyMsg && mHaveConnection) {
|
||||
LOG((" waiting for response...\n"));
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
if (!mHaveConnection) {
|
||||
LOG(("connection lost while waiting for sync response\n"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
syncReply = mSyncReplyMsg;
|
||||
mSyncReplyMsg = nsnull;
|
||||
}
|
||||
rv = SendMsg_Locked(msg, sync, &syncReply);
|
||||
}
|
||||
if (syncReply) {
|
||||
// NOTE: may re-enter SendMsg
|
||||
mObserver->OnMessageAvailable(syncReply);
|
||||
delete syncReply;
|
||||
}
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ipcTransport::SendMsg_Locked(ipcMessage *msg, PRBool sync, ipcMessage **syncReply)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (sync) {
|
||||
msg->SetFlag(IPC_MSG_FLAG_SYNC_QUERY);
|
||||
// flag before sending to avoid race with background thread.
|
||||
mSyncWaiting = PR_TRUE;
|
||||
}
|
||||
|
||||
rv = IPC_SendMsg(msg);
|
||||
|
||||
if (sync && NS_SUCCEEDED(rv)) {
|
||||
LOG((" waiting for synchronous response...\n"));
|
||||
|
||||
// break out of this loop if we receive a the response to the sync msg
|
||||
// or if the connection is lost...
|
||||
while (mSyncWaiting && mHaveConnection)
|
||||
PR_Wait(mMonitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
|
||||
// if the connection is lost, then we will not have a sync reply.
|
||||
if (!mHaveConnection) {
|
||||
LOG((" connection lost while waiting for sync response\n"));
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
*syncReply = mSyncReplyMsg;
|
||||
mSyncReplyMsg = nsnull;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -250,7 +282,7 @@ ipcTransport::ProcessIncomingMsgQ()
|
|||
}
|
||||
}
|
||||
|
||||
void *
|
||||
void * PR_CALLBACK
|
||||
ipcTransport::ProcessIncomingMsgQ_EventHandler(PLEvent *ev)
|
||||
{
|
||||
ipcTransport *self = (ipcTransport *) PL_GetEventOwner(ev);
|
||||
|
@ -258,25 +290,18 @@ ipcTransport::ProcessIncomingMsgQ_EventHandler(PLEvent *ev)
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
void *
|
||||
ipcTransport::ConnectionEstablished_EventHandler(PLEvent *ev)
|
||||
{
|
||||
ipcTransport *self = (ipcTransport *) PL_GetEventOwner(ev);
|
||||
if (self->mObserver)
|
||||
self->mObserver->OnConnectionEstablished(self->mClientID);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void *
|
||||
void * PR_CALLBACK
|
||||
ipcTransport::ConnectionLost_EventHandler(PLEvent *ev)
|
||||
{
|
||||
ipcTransport *self = (ipcTransport *) PL_GetEventOwner(ev);
|
||||
if (self->mObserver)
|
||||
if (self->mObserver) {
|
||||
self->mObserver->OnConnectionLost();
|
||||
self->mObserver = nsnull;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
void PR_CALLBACK
|
||||
ipcTransport::Generic_EventCleanup(PLEvent *ev)
|
||||
{
|
||||
ipcTransport *self = (ipcTransport *) PL_GetEventOwner(ev);
|
||||
|
@ -302,59 +327,36 @@ ipcTransport::OnMessageAvailable(ipcMessage *rawMsg)
|
|||
//
|
||||
|
||||
PRBool dispatchEvent = PR_FALSE;
|
||||
PRBool connectEvent = PR_FALSE;
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
if (!mHaveConnection) {
|
||||
if (rawMsg->Target().Equals(IPCM_TARGET) &&
|
||||
IPCM_GetMsgType(rawMsg) == IPCM_MSG_TYPE_CLIENT_ID) {
|
||||
LOG((" connection established!\n"));
|
||||
mHaveConnection = PR_TRUE;
|
||||
LOG((" mSyncWaiting=%u MSG_FLAG_SYNC_REPLY=%u\n",
|
||||
mSyncWaiting, rawMsg->TestFlag(IPC_MSG_FLAG_SYNC_REPLY) != 0));
|
||||
|
||||
// remember our client ID
|
||||
ipcMessageCast<ipcmMessageClientID> msg(rawMsg);
|
||||
mClientID = msg->ClientID();
|
||||
connectEvent = PR_TRUE;
|
||||
|
||||
// move messages off the delayed message queue
|
||||
while (!mDelayedQ.IsEmpty()) {
|
||||
ipcMessage *msg = mDelayedQ.First();
|
||||
mDelayedQ.RemoveFirst();
|
||||
IPC_SendMsg(msg);
|
||||
}
|
||||
rawMsg = nsnull;
|
||||
if (mSyncWaiting && rawMsg->TestFlag(IPC_MSG_FLAG_SYNC_REPLY)) {
|
||||
mSyncReplyMsg = rawMsg;
|
||||
mSyncWaiting = PR_FALSE;
|
||||
mon.Notify();
|
||||
}
|
||||
else {
|
||||
// we batch up all incoming event processing. this is done to
|
||||
// avoid crushing the main thread's event queue with a bunch of
|
||||
// IPC events. of course, this could also cause us to process
|
||||
// too many events synchronously on the main thread. that could
|
||||
// be a different kind of performance issue ;-)
|
||||
if (!mIncomingMsgQ) {
|
||||
mIncomingMsgQ = new ipcMessageQ();
|
||||
if (!mIncomingMsgQ)
|
||||
return;
|
||||
dispatchEvent = PR_TRUE;
|
||||
}
|
||||
else
|
||||
LOG((" received unexpected first message!\n"));
|
||||
mIncomingMsgQ->Append(rawMsg);
|
||||
}
|
||||
|
||||
if (rawMsg) {
|
||||
LOG((" mSyncWaiting=%u MSG_FLAG_SYNC_REPLY=%u\n",
|
||||
mSyncWaiting, rawMsg->TestFlag(IPC_MSG_FLAG_SYNC_REPLY) != 0));
|
||||
|
||||
if (mSyncWaiting && rawMsg->TestFlag(IPC_MSG_FLAG_SYNC_REPLY)) {
|
||||
mSyncReplyMsg = rawMsg;
|
||||
mSyncWaiting = PR_FALSE;
|
||||
mon.Notify();
|
||||
}
|
||||
else {
|
||||
if (!mIncomingMsgQ) {
|
||||
mIncomingMsgQ = new ipcMessageQ();
|
||||
if (!mIncomingMsgQ)
|
||||
return;
|
||||
dispatchEvent = PR_TRUE;
|
||||
}
|
||||
mIncomingMsgQ->Append(rawMsg);
|
||||
}
|
||||
}
|
||||
|
||||
LOG((" connectEvent=%u dispatchEvent=%u mSyncReplyMsg=%p mIncomingMsgQ=%p\n",
|
||||
connectEvent, dispatchEvent, mSyncReplyMsg, mIncomingMsgQ));
|
||||
LOG((" dispatchEvent=%u mSyncReplyMsg=%p mIncomingMsgQ=%p\n",
|
||||
dispatchEvent, mSyncReplyMsg, mIncomingMsgQ));
|
||||
}
|
||||
|
||||
if (connectEvent)
|
||||
ProxyToMainThread(ConnectionEstablished_EventHandler);
|
||||
if (dispatchEvent)
|
||||
ProxyToMainThread(ProcessIncomingMsgQ_EventHandler);
|
||||
}
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla IPC.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef ipcTransport_h__
|
||||
#define ipcTransport_h__
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "prmon.h"
|
||||
|
||||
#include "ipcMessage.h"
|
||||
#include "ipcMessageQ.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ipcTransportObserver interface
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class ipcTransportObserver
|
||||
{
|
||||
public:
|
||||
virtual void OnConnectionEstablished(PRUint32 clientID) = 0;
|
||||
virtual void OnConnectionLost() = 0;
|
||||
virtual void OnMessageAvailable(const ipcMessage *) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ipcTransport
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ipcTransport : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
ipcTransport()
|
||||
: mMonitor(PR_NewMonitor())
|
||||
, mObserver(nsnull)
|
||||
, mIncomingMsgQ(nsnull)
|
||||
, mSyncReplyMsg(nsnull)
|
||||
, mSyncWaiting(nsnull)
|
||||
, mSentHello(PR_FALSE)
|
||||
, mHaveConnection(PR_FALSE)
|
||||
, mSpawnedDaemon(PR_FALSE)
|
||||
, mConnectionAttemptCount(0)
|
||||
, mClientID(0)
|
||||
{}
|
||||
|
||||
virtual ~ipcTransport()
|
||||
{
|
||||
PR_DestroyMonitor(mMonitor);
|
||||
}
|
||||
|
||||
nsresult Init(ipcTransportObserver *observer);
|
||||
nsresult Shutdown();
|
||||
|
||||
// takes ownership of |msg|
|
||||
nsresult SendMsg(ipcMessage *msg, PRBool sync = PR_FALSE);
|
||||
|
||||
public:
|
||||
//
|
||||
// internal to implementation
|
||||
//
|
||||
void OnMessageAvailable(ipcMessage *); // takes ownership
|
||||
|
||||
private:
|
||||
friend void IPC_OnMessageAvailable(ipcMessage *);
|
||||
friend void IPC_OnConnectionEnd(nsresult);
|
||||
|
||||
//
|
||||
// helpers
|
||||
//
|
||||
void ProxyToMainThread(PLHandleEventProc);
|
||||
void ProcessIncomingMsgQ();
|
||||
|
||||
PR_STATIC_CALLBACK(void *) ProcessIncomingMsgQ_EventHandler(PLEvent *);
|
||||
PR_STATIC_CALLBACK(void *) ConnectionEstablished_EventHandler(PLEvent *);
|
||||
PR_STATIC_CALLBACK(void *) ConnectionLost_EventHandler(PLEvent *);
|
||||
PR_STATIC_CALLBACK(void) Generic_EventCleanup(PLEvent *);
|
||||
|
||||
//
|
||||
// data
|
||||
//
|
||||
PRMonitor *mMonitor;
|
||||
ipcTransportObserver *mObserver; // weak reference
|
||||
ipcMessageQ mDelayedQ;
|
||||
ipcMessageQ *mIncomingMsgQ;
|
||||
ipcMessage *mSyncReplyMsg;
|
||||
PRPackedBool mSyncWaiting;
|
||||
PRPackedBool mSentHello;
|
||||
PRPackedBool mHaveConnection;
|
||||
PRPackedBool mSpawnedDaemon;
|
||||
PRUint32 mConnectionAttemptCount;
|
||||
PRUint32 mClientID;
|
||||
};
|
||||
|
||||
#endif // !ipcTransport_h__
|
Загрузка…
Ссылка в новой задаче