Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
ipcdclient.cpp File Reference
#include "ipcdclient.h"
#include "ipcConnection.h"
#include "ipcConfig.h"
#include "ipcMessageQ.h"
#include "ipcMessageUtils.h"
#include "ipcLog.h"
#include "ipcm.h"
#include "nsIFile.h"
#include "nsEventQueueUtils.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsRefPtrHashtable.h"
#include "nsAutoLock.h"
#include "nsProxyRelease.h"
#include "nsCOMArray.h"
#include "prio.h"
#include "prproces.h"
#include "pratom.h"

Go to the source code of this file.

Classes

class  ipcTargetData
class  ipcClientState
class  ipcEvent_ClientState
class  ipcEvent_ProcessPendingQ
struct  WaitMessageSelectorData

Defines

#define IPC_REQUEST_TIMEOUT   PR_SecondsToInterval(30)

Typedefs

typedef nsRefPtrHashtable
< nsIDHashKey, ipcTargetData
ipcTargetMap
typedef PRBool(* ipcMessageSelector )(void *arg, ipcTargetData *td, const ipcMessage *msg)

Functions

static PRBool GetTarget (const nsID &aTarget, ipcTargetData **td)
static PRBool PutTarget (const nsID &aTarget, ipcTargetData *td)
static void DelTarget (const nsID &aTarget)
static nsresult GetDaemonPath (nsCString &dpath)
static void ProcessPendingQ (const nsID &aTarget)
static PRBool DefaultSelector (void *arg, ipcTargetData *td, const ipcMessage *msg)
static nsresult WaitTarget (const nsID &aTarget, PRIntervalTime aTimeout, ipcMessage **aMsg, ipcMessageSelector aSelector=nsnull, void *aArg=nsnull)
static void PostEvent (nsIEventTarget *eventTarget, PLEvent *ev)
static void PostEventToMainThread (PLEvent *ev)
static void CallProcessPendingQ (const nsID &target, ipcTargetData *td)
static void DisableMessageObserver (const nsID &aTarget)
static void EnableMessageObserver (const nsID &aTarget)
static PRBool WaitIPCMResponseSelector (void *arg, ipcTargetData *td, const ipcMessage *msg)
static nsresult WaitIPCMResponse (PRUint32 requestIndex, ipcMessage **responseMsg=nsnull)
static nsresult MakeIPCMRequest (ipcMessage *msg, ipcMessage **responseMsg=nsnull)
static void RemoveTarget (const nsID &aTarget, PRBool aNotifyDaemon)
static nsresult DefineTarget (const nsID &aTarget, ipcIMessageObserver *aObserver, PRBool aOnCurrentThread, PRBool aNotifyDaemon, ipcTargetData **aResult)
static nsresult TryConnect ()
nsresult IPC_Init ()
 Connects this process to the IPC daemon and initializes it for use as a client of the IPC daemon.
nsresult IPC_Shutdown ()
 Disconnects this process from the IPC daemon.
nsresult IPC_DefineTarget (const nsID &aTarget, ipcIMessageObserver *aObserver, PRBool aOnCurrentThread)
 Call this method to define a message target.
nsresult IPC_DisableMessageObserver (const nsID &aTarget)
 Call this method to temporarily disable the message observer configured for a message target.
nsresult IPC_EnableMessageObserver (const nsID &aTarget)
 Call this method to re-enable the message observer configured for a message target.
nsresult IPC_SendMessage (PRUint32 aReceiverID, const nsID &aTarget, const PRUint8 *aData, PRUint32 aDataLen)
 This function sends a message to the IPC daemon asynchronously.
static PRBool WaitMessageSelector (void *arg, ipcTargetData *td, const ipcMessage *msg)
nsresult IPC_WaitMessage (PRUint32 aSenderID, const nsID &aTarget, ipcIMessageObserver *aObserver, PRIntervalTime aTimeout)
 This function blocks the calling thread until a message for the given target is received (optionally from the specified client).
nsresult IPC_GetID (PRUint32 *aClientID)
 Returns the "ClientID" of the current process.
nsresult IPC_AddName (const char *aName)
 Adds a new name for the current process.
nsresult IPC_RemoveName (const char *aName)
 Removes a name associated with the current process.
nsresult IPC_AddClientObserver (ipcIClientObserver *aObserver)
 Adds client observer.
nsresult IPC_RemoveClientObserver (ipcIClientObserver *aObserver)
 Removes client observer.
nsresult IPC_ResolveClientName (const char *aName, PRUint32 *aClientID)
 Resolves the given client name to a client ID of a process connected to the IPC daemon.
nsresult IPC_ClientExists (PRUint32 aClientID, PRBool *aResult)
 Tests whether the client is connected to the IPC daemon.
nsresult IPC_SpawnDaemon (const char *path)
 IPC_SpawnDaemon.
 EnumerateTargetMapAndNotify (const nsID &aKey, ipcTargetData *aData, void *aClosure)
void IPC_OnConnectionEnd (nsresult error)
void IPC_OnMessageAvailable (ipcMessage *msg)

Variables

static ipcClientStategClientState

Class Documentation

struct WaitMessageSelectorData

Definition at line 824 of file ipcdclient.cpp.

Collaboration diagram for WaitMessageSelectorData:
Class Members
ipcIMessageObserver * observer
PRUint32 senderID

Define Documentation

#define IPC_REQUEST_TIMEOUT   PR_SecondsToInterval(30)

Definition at line 63 of file ipcdclient.cpp.


Typedef Documentation

Definition at line 284 of file ipcdclient.cpp.

Definition at line 140 of file ipcdclient.cpp.


Function Documentation

static void CallProcessPendingQ ( const nsID target,
ipcTargetData td 
) [static]

Definition at line 494 of file ipcdclient.cpp.

{
  // we assume that we are inside td's monitor 

  PLEvent *ev = new ipcEvent_ProcessPendingQ(target);
  if (!ev)
    return;

  nsresult rv;

  if (td->eventQ)
    rv = td->eventQ->PostEvent(ev);
  else
    rv = IPC_DoCallback((ipcCallbackFunc) PL_HandleEvent, ev);

  if (NS_FAILED(rv))
    PL_DestroyEvent(ev);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool DefaultSelector ( void arg,
ipcTargetData td,
const ipcMessage msg 
) [static]

Definition at line 292 of file ipcdclient.cpp.

{
  return PR_TRUE;
}

Here is the caller graph for this function:

static nsresult DefineTarget ( const nsID aTarget,
ipcIMessageObserver aObserver,
PRBool  aOnCurrentThread,
PRBool  aNotifyDaemon,
ipcTargetData **  aResult 
) [static]

Definition at line 620 of file ipcdclient.cpp.

{
  nsresult rv;

  nsRefPtr<ipcTargetData> td( ipcTargetData::Create() );
  if (!td)
    return NS_ERROR_OUT_OF_MEMORY;
  td->SetObserver(aObserver, aOnCurrentThread);

  if (!PutTarget(aTarget, td))
    return NS_ERROR_OUT_OF_MEMORY;

  if (aNotifyDaemon)
  {
    rv = MakeIPCMRequest(new ipcmMessageClientAddTarget(aTarget));
    if (NS_FAILED(rv))
    {
      LOG(("failed to add target: rv=%x\n", rv));
      RemoveTarget(aTarget, PR_FALSE);
      return rv;
    }
  }

  if (aResult)
    NS_ADDREF(*aResult = td);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void DelTarget ( const nsID aTarget) [static]

Definition at line 214 of file ipcdclient.cpp.

{
  nsAutoMonitor mon(gClientState->monitor);
  gClientState->targetMap.Remove(nsIDHashKey(&aTarget).GetKey());
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 516 of file ipcdclient.cpp.

{
  nsRefPtr<ipcTargetData> td;
  if (GetTarget(aTarget, getter_AddRefs(td)))
  {
    nsAutoMonitor mon(td->monitor);
    ++td->observerDisabled;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 527 of file ipcdclient.cpp.

{
  nsRefPtr<ipcTargetData> td;
  if (GetTarget(aTarget, getter_AddRefs(td)))
  {
    nsAutoMonitor mon(td->monitor);
    if (td->observerDisabled > 0 && --td->observerDisabled == 0)
      if (!td->pendingQ.IsEmpty())
        CallProcessPendingQ(aTarget, td);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

EnumerateTargetMapAndNotify ( const nsID aKey,
ipcTargetData aData,
void aClosure 
)

Definition at line 1021 of file ipcdclient.cpp.

{
  nsAutoMonitor mon(aData->monitor);

  // wake up anyone waiting on this target.
  mon.NotifyAll();

  return PL_DHASH_NEXT;
}

Here is the caller graph for this function:

static nsresult GetDaemonPath ( nsCString dpath) [static]

Definition at line 223 of file ipcdclient.cpp.

{
  nsCOMPtr<nsIFile> file;

  nsresult rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
                                       getter_AddRefs(file));
  if (NS_SUCCEEDED(rv))
  {
    rv = file->AppendNative(NS_LITERAL_CSTRING(IPC_DAEMON_APP_NAME));
    if (NS_SUCCEEDED(rv))
      rv = file->GetNativePath(dpath);
  }

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool GetTarget ( const nsID aTarget,
ipcTargetData **  td 
) [static]

Definition at line 200 of file ipcdclient.cpp.

{
  nsAutoMonitor mon(gClientState->monitor);
  return gClientState->targetMap.Get(nsIDHashKey(&aTarget).GetKey(), td);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Adds client observer.

Will be called on the main thread.

Definition at line 906 of file ipcdclient.cpp.

Here is the call graph for this function:

nsresult IPC_AddName ( const char *  aName)

Adds a new name for the current process.

The IPC daemon is notified of this change, which allows other processes to discover this process by the given name.

Definition at line 888 of file ipcdclient.cpp.

Here is the call graph for this function:

nsresult IPC_ClientExists ( PRUint32  aClientID,
PRBool aResult 
)

Tests whether the client is connected to the IPC daemon.

Definition at line 957 of file ipcdclient.cpp.

{
  // this is a bit of a hack.  we forward a PING to the specified client.
  // the assumption is that the forwarding will only succeed if the client
  // exists, so we wait for the RESULT message corresponding to the FORWARD
  // request.  if that gives a successful status, then we know that the
  // client exists.

  ipcmMessagePing ping;

  return MakeIPCMRequest(new ipcmMessageForward(IPCM_MSG_REQ_FORWARD,
                                                aClientID,
                                                IPCM_TARGET,
                                                ping.Data(),
                                                ping.DataLen()));
}

Here is the call graph for this function:

nsresult IPC_DefineTarget ( const nsID aTarget,
ipcIMessageObserver aObserver,
PRBool  aOnCurrentThread = PR_TRUE 
)

Call this method to define a message target.

A message target is defined by a UUID and a message observer. This observer is notified asynchronously whenever a message is sent to this target in this process.

This function has three main effects: o If the message target is already defined, then this function simply resets its message observer. o If the message target is not already defined, then the message target is defined and the IPC daemon is notified of the existance of this message target. o If null is passed for the message observer, then the message target is removed, and the daemon is notified of the removal of this message target.

If aOnCurrentThread is true, then notifications to the observer will occur on the current thread. This means that there must be a nsIEventTarget associated with the calling thread. If aOnCurrentThread is false, then notifications to the observer will occur on a background thread. In which case, the observer must be threadsafe.

Definition at line 727 of file ipcdclient.cpp.

{
  NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);

  // do not permit the re-definition of the IPCM protocol's target.
  if (aTarget.Equals(IPCM_TARGET))
    return NS_ERROR_INVALID_ARG;

  nsresult rv;

  nsRefPtr<ipcTargetData> td;
  if (GetTarget(aTarget, getter_AddRefs(td)))
  {
    // clear out observer before removing target since we want to ensure that
    // the observer is released on the main thread.
    {
      nsAutoMonitor mon(td->monitor);
      td->SetObserver(aObserver, aOnCurrentThread);
    }

    // remove target outside of td's monitor to avoid holding the monitor
    // while entering the client state's monitor.
    if (!aObserver)
      RemoveTarget(aTarget, PR_TRUE);

    rv = NS_OK;
  }
  else
  {
    if (aObserver)
      rv = DefineTarget(aTarget, aObserver, aOnCurrentThread, PR_TRUE, nsnull);
    else
      rv = NS_ERROR_INVALID_ARG; // unknown target
  }

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Call this method to temporarily disable the message observer configured for a message target.

Definition at line 768 of file ipcdclient.cpp.

{
  NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);

  // do not permit modifications to the IPCM protocol's target.
  if (aTarget.Equals(IPCM_TARGET))
    return NS_ERROR_INVALID_ARG;

  DisableMessageObserver(aTarget);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Call this method to re-enable the message observer configured for a message target.

Definition at line 781 of file ipcdclient.cpp.

{
  NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);

  // do not permit modifications to the IPCM protocol's target.
  if (aTarget.Equals(IPCM_TARGET))
    return NS_ERROR_INVALID_ARG;

  EnableMessageObserver(aTarget);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult IPC_GetID ( PRUint32 aClientID)

Returns the "ClientID" of the current process.

Definition at line 879 of file ipcdclient.cpp.

Connects this process to the IPC daemon and initializes it for use as a client of the IPC daemon.

This function must be called once before any other methods defined in this file can be used.

Returns:
NS_ERROR_ALREADY_INITIALIZED if IPC_Shutdown was not called since the last time IPC_Init was called.

Definition at line 693 of file ipcdclient.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1035 of file ipcdclient.cpp.

{
  // now, go through the target map, and tickle each monitor.  that should
  // unblock any calls to WaitTarget.

  nsAutoMonitor mon(gClientState->monitor);
  gClientState->connected = PR_FALSE;
  gClientState->targetMap.EnumerateRead(EnumerateTargetMapAndNotify, nsnull);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1054 of file ipcdclient.cpp.

{
#ifdef IPC_LOGGING
  if (LOG_ENABLED())
  {
    char *targetStr = msg->Target().ToString();
    LOG(("got message for target: %s\n", targetStr));
    nsMemory::Free(targetStr);

    IPC_LogBinary((const PRUint8 *) msg->Data(), msg->DataLen());
  }
#endif

  if (msg->Target().Equals(IPCM_TARGET))
  {
    switch (IPCM_GetType(msg))
    {
      // if this is a forwarded message, then post the inner message instead.
      case IPCM_MSG_PSH_FORWARD:
      {
        ipcMessageCast<ipcmMessageForward> fwd(msg);
        ipcMessage *innerMsg = new ipcMessage(fwd->InnerTarget(),
                                              fwd->InnerData(),
                                              fwd->InnerDataLen());
        // store the sender's client id in the meta-data field of the message.
        innerMsg->mMetaData = fwd->ClientID();

        delete msg;

        // recurse so we can handle forwarded IPCM messages
        IPC_OnMessageAvailable(innerMsg);
        return;
      }
      case IPCM_MSG_PSH_CLIENT_STATE:
      {
        ipcMessageCast<ipcmMessageClientState> status(msg);
        PostEventToMainThread(new ipcEvent_ClientState(status->ClientID(),
                                                       status->ClientState()));
        return;
      }
    }
  }

  nsRefPtr<ipcTargetData> td;
  if (GetTarget(msg->Target(), getter_AddRefs(td)))
  {
    nsAutoMonitor mon(td->monitor);

    // we only want to dispatch a 'ProcessPendingQ' event if we have not
    // already done so.
    PRBool dispatchEvent = td->pendingQ.IsEmpty();

    // put this message on our pending queue
    td->pendingQ.Append(msg);

    // make copy of target since |msg| may end up pointing to free'd memory
    // once we notify the monitor.
    const nsID target = msg->Target();

    LOG(("placed message on pending queue for target and notifying all...\n"));

    // wake up anyone waiting on this queue
    mon.NotifyAll();

    // proxy call to target's message procedure
    if (dispatchEvent)
      CallProcessPendingQ(target, td);
  }
  else
  {
    NS_WARNING("message target is undefined");
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Removes client observer.

Definition at line 915 of file ipcdclient.cpp.

Here is the call graph for this function:

nsresult IPC_RemoveName ( const char *  aName)

Removes a name associated with the current process.

Definition at line 896 of file ipcdclient.cpp.

Here is the call graph for this function:

nsresult IPC_ResolveClientName ( const char *  aName,
PRUint32 aClientID 
)

Resolves the given client name to a client ID of a process connected to the IPC daemon.

Definition at line 932 of file ipcdclient.cpp.

{
  NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);

  ipcMessage *msg;

  nsresult rv = MakeIPCMRequest(new ipcmMessageQueryClientByName(aName), &msg);
  if (NS_FAILED(rv))
    return rv;

  if (IPCM_GetType(msg) == IPCM_MSG_ACK_CLIENT_ID)
    *aClientID = ipcMessageCast<ipcmMessageClientID>(msg)->ClientID();
  else
  {
    LOG(("unexpected IPCM response: type=%x\n", IPCM_GetType(msg)));
    rv = NS_ERROR_UNEXPECTED;
  }
    
  delete msg;
  return rv;
}

Here is the call graph for this function:

nsresult IPC_SendMessage ( PRUint32  aReceiverID,
const nsID aTarget,
const PRUint8 aData,
PRUint32  aDataLen 
)

This function sends a message to the IPC daemon asynchronously.

If aReceiverID is non-zero, then the message is forwarded to the client corresponding to that identifier.

If there is no client corresponding to aRecieverID, then the IPC daemon will simply drop the message.

Definition at line 794 of file ipcdclient.cpp.

{
  NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);

  // do not permit sending IPCM messages
  if (aTarget.Equals(IPCM_TARGET))
    return NS_ERROR_INVALID_ARG;

  nsresult rv;
  if (aReceiverID == 0)
  {
    ipcMessage *msg = new ipcMessage(aTarget, (const char *) aData, aDataLen);
    if (!msg)
      return NS_ERROR_OUT_OF_MEMORY;

    rv = IPC_SendMsg(msg);
  }
  else
    rv = MakeIPCMRequest(new ipcmMessageForward(IPCM_MSG_REQ_FORWARD,
                                                aReceiverID,
                                                aTarget,
                                                (const char *) aData,
                                                aDataLen));

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Disconnects this process from the IPC daemon.

After this function is called, no other methods in this file except for IPC_Init may be called.

Returns:
NS_ERROR_NOT_INITIALIZED if IPC_Init has not been called or if IPC_Init did not return a success code.

Definition at line 711 of file ipcdclient.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult IPC_SpawnDaemon ( const char *  daemonPath)

IPC_SpawnDaemon.

This function launches the IPC daemon process. It is called by the platform specific IPC_Connect implementation. It should not return until the daemon process is ready to receive a client connection or an error occurs.

Parameters:
daemonPathSpecifies the path to the IPC daemon executable.

Definition at line 977 of file ipcdclient.cpp.

{
  PRFileDesc *readable = nsnull, *writable = nsnull;
  PRProcessAttr *attr = nsnull;
  nsresult rv = NS_ERROR_FAILURE;
  char *const argv[] = { (char *const) path, nsnull };
  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.

  if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
    goto end;
  PR_SetFDInheritable(writable, PR_TRUE);

  attr = PR_NewProcessAttr();
  if (!attr)
    goto end;

  if (PR_ProcessAttrSetInheritableFD(attr, writable, IPC_STARTUP_PIPE_NAME) != PR_SUCCESS)
    goto end;

  if (PR_CreateProcessDetached(path, argv, nsnull, attr) != PR_SUCCESS)
    goto end;

  if ((PR_Read(readable, &c, 1) != 1) && (c != IPC_STARTUP_PIPE_MAGIC))
    goto end;

  rv = NS_OK;
end:
  if (readable)
    PR_Close(readable);
  if (writable)
    PR_Close(writable);
  if (attr)
    PR_DestroyProcessAttr(attr);
  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult IPC_WaitMessage ( PRUint32  aSenderID,
const nsID aTarget,
ipcIMessageObserver aObserver = nsnull,
PRIntervalTime  aTimeout = PR_INTERVAL_NO_TIMEOUT 
)

This function blocks the calling thread until a message for the given target is received (optionally from the specified client).

The aSenderID parameter is interpreted as follows: o If aSenderID is 0, then this function waits for a message to be sent by the IPC daemon. o If aSenderID is IPC_SENDER_ANY, then this function waits for a message to be sent from any source. o Otherwise, this function waits for a message to be sent by the client with ID given by aSenderID. If aSenderID does not identify a valid client, then this function will return an error.

The aObserver parameter is interpreted as follows: o If aObserver is null, then the default message observer for the target is invoked when the next message is received. o Otherwise, aObserver will be inovked when the next message is received.

The aTimeout parameter is interpreted as follows: o If aTimeout is PR_INTERVAL_NO_TIMEOUT, then this function will block until a matching message is received. o If aTimeout is PR_INTERVAL_NO_WAIT, then this function will only inspect the current queue of messages. If no matching message is found, then IPC_ERROR_WOULD_BLOCK is returned. o Otherwise, aTimeout specifies the maximum amount of time to wait for a matching message to be received. If no matching message is found after the timeout expires, then IPC_ERROR_WOULD_BLOCK is returned.

If aObserver's OnMessageAvailable function returns IPC_WAIT_NEXT_MESSAGE, then the function will continue blocking until the next matching message is received. Bypassed messages will be dispatched to the default message observer when the event queue, associated with the thread that called IPC_DefineTarget, is processed.

This function runs the risk of hanging the calling thread indefinitely if no matching message is ever received.

Definition at line 854 of file ipcdclient.cpp.

{
  NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED);

  // do not permit waiting for IPCM messages
  if (aTarget.Equals(IPCM_TARGET))
    return NS_ERROR_INVALID_ARG;

  WaitMessageSelectorData data = { aSenderID, aObserver };

  ipcMessage *msg;
  nsresult rv = WaitTarget(aTarget, aTimeout, &msg, WaitMessageSelector, &data);
  if (NS_FAILED(rv))
    return rv;
  delete msg;

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult MakeIPCMRequest ( ipcMessage msg,
ipcMessage **  responseMsg = nsnull 
) [static]

Definition at line 582 of file ipcdclient.cpp.

{
  if (!msg)
    return NS_ERROR_OUT_OF_MEMORY;

  PRUint32 requestIndex = IPCM_GetRequestIndex(msg);

  // suppress 'ProcessPendingQ' for IPCM messages until we receive the
  // response to this IPCM request.  if we did not do this then there
  // would be a race condition leading to the possible removal of our
  // response from the pendingQ between sending the request and waiting
  // for the response.
  DisableMessageObserver(IPCM_TARGET);

  nsresult rv = IPC_SendMsg(msg);
  if (NS_SUCCEEDED(rv))
    rv = WaitIPCMResponse(requestIndex, responseMsg);

  EnableMessageObserver(IPCM_TARGET);
  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PostEvent ( nsIEventTarget eventTarget,
PLEvent ev 
) [static]

Definition at line 404 of file ipcdclient.cpp.

{
  if (!ev)
    return;

  nsresult rv = eventTarget->PostEvent(ev);
  if (NS_FAILED(rv))
  {
    NS_WARNING("PostEvent failed");
    PL_DestroyEvent(ev);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PostEventToMainThread ( PLEvent ev) [static]

Definition at line 418 of file ipcdclient.cpp.

{
  nsCOMPtr<nsIEventQueue> eventQ;
  NS_GetMainEventQ(getter_AddRefs(eventQ));
  if (!eventQ)
  {
    NS_WARNING("unable to get reference to main event queue");
    PL_DestroyEvent(ev);
    return;
  }
  PostEvent(eventQ, ev);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ProcessPendingQ ( const nsID aTarget) [static]

Definition at line 242 of file ipcdclient.cpp.

{
  ipcMessageQ tempQ;

  nsRefPtr<ipcTargetData> td;
  if (GetTarget(aTarget, getter_AddRefs(td)))
  {
    nsAutoMonitor mon(td->monitor);

    // if the observer for this target has been temporarily disabled, then
    // we must not processing any pending messages at this time.

    if (!td->observerDisabled)
      td->pendingQ.MoveTo(tempQ);
  }

  // process pending queue outside monitor
  while (!tempQ.IsEmpty())
  {
    ipcMessage *msg = tempQ.First();

    if (td->observer)
      td->observer->OnMessageAvailable(msg->mMetaData,
                                       msg->Target(),
                                       (const PRUint8 *) msg->Data(),
                                       msg->DataLen());
    else
    {
      // the IPCM target does not have an observer, and therefore any IPCM
      // messages that make it here will simply be dropped.
      NS_ASSERTION(aTarget.Equals(IPCM_TARGET), "unexpected target");
      LOG(("dropping IPCM message: type=%x\n", IPCM_GetType(msg)));
    }
    tempQ.DeleteFirst();
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool PutTarget ( const nsID aTarget,
ipcTargetData td 
) [static]

Definition at line 207 of file ipcdclient.cpp.

{
  nsAutoMonitor mon(gClientState->monitor);
  return gClientState->targetMap.Put(nsIDHashKey(&aTarget).GetKey(), td);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void RemoveTarget ( const nsID aTarget,
PRBool  aNotifyDaemon 
) [static]

Definition at line 607 of file ipcdclient.cpp.

{
  DelTarget(aTarget);

  if (aNotifyDaemon)
  {
    nsresult rv = MakeIPCMRequest(new ipcmMessageClientDelTarget(aTarget));
    if (NS_FAILED(rv))
      LOG(("failed to delete target: rv=%x\n", rv));
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult TryConnect ( ) [static]

Definition at line 655 of file ipcdclient.cpp.

{
  nsCAutoString dpath;
  nsresult rv = GetDaemonPath(dpath);
  if (NS_FAILED(rv))
    return rv;
  
  rv = IPC_Connect(dpath.get());
  if (NS_FAILED(rv))
    return rv;

  gClientState->connected = PR_TRUE;

  rv = DefineTarget(IPCM_TARGET, nsnull, PR_FALSE, PR_FALSE, nsnull);
  if (NS_FAILED(rv))
    return rv;

  ipcMessage *msg;

  // send CLIENT_HELLO and wait for CLIENT_ID response...
  rv = MakeIPCMRequest(new ipcmMessageClientHello(), &msg);
  if (NS_FAILED(rv))
    return rv;

  if (IPCM_GetType(msg) == IPCM_MSG_ACK_CLIENT_ID)
    gClientState->selfID = ipcMessageCast<ipcmMessageClientID>(msg)->ClientID();
  else
  {
    LOG(("unexpected response from CLIENT_HELLO message: type=%x!\n",
        IPCM_GetType(msg)));
    rv = NS_ERROR_UNEXPECTED;
  }

  delete msg;
  return rv;
}

Here is the call graph for this function:

static nsresult WaitIPCMResponse ( PRUint32  requestIndex,
ipcMessage **  responseMsg = nsnull 
) [static]

Definition at line 554 of file ipcdclient.cpp.

{
  ipcMessage *msg;

  nsresult rv = WaitTarget(IPCM_TARGET, IPC_REQUEST_TIMEOUT, &msg,
                           WaitIPCMResponseSelector, &requestIndex);
  if (NS_FAILED(rv))
    return rv;

  if (IPCM_GetType(msg) == IPCM_MSG_ACK_RESULT)
  {
    ipcMessageCast<ipcmMessageResult> result(msg);
    if (result->Status() < 0)
      rv = NS_ERROR_FAILURE; // XXX nsresult_from_ipcm_result()
    else
      rv = NS_OK;
  }

  if (responseMsg)
    *responseMsg = msg;
  else
    delete msg;

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool WaitIPCMResponseSelector ( void arg,
ipcTargetData td,
const ipcMessage msg 
) [static]

Definition at line 543 of file ipcdclient.cpp.

{
  PRUint32 requestIndex = *(PRUint32 *) arg;
  return IPCM_GetRequestIndex(msg) == requestIndex;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool WaitMessageSelector ( void arg,
ipcTargetData td,
const ipcMessage msg 
) [static]

Definition at line 830 of file ipcdclient.cpp.

{
  WaitMessageSelectorData *data = (WaitMessageSelectorData *) arg;

  nsresult rv = IPC_WAIT_NEXT_MESSAGE;

  if (msg->mMetaData == data->senderID)
  {
    ipcIMessageObserver *obs = data->observer;
    if (!obs)
      obs = td->observer;
    NS_ASSERTION(obs, "must at least have a default observer");

    rv = obs->OnMessageAvailable(msg->mMetaData,
                                 msg->Target(),
                                 (const PRUint8 *) msg->Data(),
                                 msg->DataLen());
  }

  // stop iterating if we got a match that the observer accepted.
  return rv != IPC_WAIT_NEXT_MESSAGE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult WaitTarget ( const nsID aTarget,
PRIntervalTime  aTimeout,
ipcMessage **  aMsg,
ipcMessageSelector  aSelector = nsnull,
void aArg = nsnull 
) [static]

Definition at line 298 of file ipcdclient.cpp.

{
  *aMsg = nsnull;

  if (!aSelector)
    aSelector = DefaultSelector;

  nsRefPtr<ipcTargetData> td;
  if (!GetTarget(aTarget, getter_AddRefs(td)))
    return NS_ERROR_INVALID_ARG; // bad aTarget

  PRIntervalTime timeStart = PR_IntervalNow();
  PRIntervalTime timeEnd;
  if (aTimeout == PR_INTERVAL_NO_TIMEOUT)
    timeEnd = aTimeout;
  else if (aTimeout == PR_INTERVAL_NO_WAIT)
    timeEnd = timeStart;
  else
  {
    timeEnd = timeStart + aTimeout;

    // if overflowed, then set to max value
    if (timeEnd < timeStart)
      timeEnd = PR_INTERVAL_NO_TIMEOUT;
  }

  ipcMessage *lastChecked = nsnull, *beforeLastChecked = nsnull;
  nsresult rv = NS_ERROR_FAILURE;

  nsAutoMonitor mon(td->monitor);

  while (gClientState->connected)
  {
    NS_ASSERTION(!lastChecked, "oops");

    //
    // NOTE:
    //
    // we must start at the top of the pending queue, possibly revisiting
    // messages that our selector has already rejected.  this is necessary
    // because the queue may have been modified while we were waiting on
    // the monitor.  the impact of this on performance remains to be seen.
    //
    // one cheap solution is to keep a counter that is incremented each
    // time a message is removed from the pending queue.  that way we can
    // avoid revisiting all messages sometimes.
    //

    lastChecked = td->pendingQ.First();
    beforeLastChecked = nsnull;

    // loop over pending queue until we find a message that our selector likes.
    while (lastChecked)
    {
      if ((aSelector)(aArg, td, lastChecked))
      {
        // remove from pending queue
        if (beforeLastChecked)
          td->pendingQ.RemoveAfter(beforeLastChecked);
        else
          td->pendingQ.RemoveFirst();
        lastChecked->mNext = nsnull;

        *aMsg = lastChecked;
        break;
      }

      beforeLastChecked = lastChecked;
      lastChecked = lastChecked->mNext;
    }
      
    if (*aMsg)
    {
      rv = NS_OK;
      break;
    }

    // make sure we are still connected before waiting...
    if (!gClientState->connected)
    {
      rv = NS_ERROR_ABORT;
      break;
    }

    PRIntervalTime t = PR_IntervalNow();
    if (t > timeEnd) // check if timeout has expired
    {
      rv = IPC_ERROR_WOULD_BLOCK;
      break;
    }
    mon.Wait(timeEnd - t);

    LOG(("woke up from sleep [pendingQempty=%d connected=%d]\n",
          td->pendingQ.IsEmpty(), gClientState->connected));
  }

  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 197 of file ipcdclient.cpp.