From b9630144addee0006fadae3c44c8b78b4a88274a Mon Sep 17 00:00:00 2001 From: "darin%meer.net" Date: Sun, 9 Nov 2003 23:49:24 +0000 Subject: [PATCH] fixes bug 225016 "make IPC startup handshake (send CLIENT_HELLO, wait for CLIENT_ID) synchronous" r=timeless --- ipc/ipcd/client/src/ipcService.cpp | 153 ++++++--------- ipc/ipcd/client/src/ipcService.h | 22 +-- ipc/ipcd/client/src/ipcTransport.cpp | 266 ++++++++++++++------------- ipc/ipcd/client/src/ipcTransport.h | 132 ------------- 4 files changed, 192 insertions(+), 381 deletions(-) diff --git a/ipc/ipcd/client/src/ipcService.cpp b/ipc/ipcd/client/src/ipcService.cpp index 52141e67710..0ea7b5d8b9b 100644 --- a/ipc/ipcd/client/src/ipcService.cpp +++ b/ipc/ipcd/client/src/ipcService.cpp @@ -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 Fisher * * 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 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 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 observ( - do_GetService("@mozilla.org/observer-service;1")); - if (observ) - observ->NotifyObservers(NS_STATIC_CAST(ipcIService *, this), - IPC_SERVICE_SHUTDOWN_TOPIC, nsnull); + Shutdown(); } void diff --git a/ipc/ipcd/client/src/ipcService.h b/ipc/ipcd/client/src/ipcService.h index edb88893a15..c1e8e13b7a5 100644 --- a/ipc/ipcd/client/src/ipcService.h +++ b/ipc/ipcd/client/src/ipcService.h @@ -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 mTransport; + ipcClientQueryQ mQueryQ; + PRUint32 mClientID; }; #endif // !ipcService_h__ diff --git a/ipc/ipcd/client/src/ipcTransport.cpp b/ipc/ipcd/client/src/ipcTransport.cpp index 948ea53becb..b2cff08e87e 100644 --- a/ipc/ipcd/client/src/ipcTransport.cpp +++ b/ipc/ipcd/client/src/ipcTransport.cpp @@ -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 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 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); } diff --git a/ipc/ipcd/client/src/ipcTransport.h b/ipc/ipcd/client/src/ipcTransport.h index 8061dc852ce..e69de29bb2d 100644 --- a/ipc/ipcd/client/src/ipcTransport.h +++ b/ipc/ipcd/client/src/ipcTransport.h @@ -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 - * - * 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__