VirtualBox

Changeset 26554 in vbox


Ignore:
Timestamp:
Feb 15, 2010 6:13:54 PM (15 years ago)
Author:
vboxsync
Message:

XPCOM: fix IPC message processing in the situation where several threads call the same client which then crashes. Before only one thread got the client death message, and the others would hang forever. Essentially added code which keeps track of the client state.

Location:
trunk/src/libs/xpcom18a4/ipc/ipcd
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp

    r7049 r26554  
    4343#include "ipcLog.h"
    4444#include "ipcm.h"
     45#include "iprt/thread.h"
    4546
    4647#include "nsIFile.h"
     
    405406      break;
    406407    }
     408#ifdef VBOX
     409    else
     410    {
     411      /* Special client liveness check if there is no message to process.
     412       * This is necessary as there might be several threads waiting for
     413       * a message from a single client, and only one gets the DOWN msg. */
     414      PRBool alive = (aSelector)(aArg, td, NULL);
     415      if (!alive)
     416      {
     417        *aMsg = NULL;
     418        break;
     419      }
     420    }
     421#endif /* VBOX */
    407422
    408423    PRIntervalTime t = PR_IntervalNow();
     
    587602WaitIPCMResponseSelector(void *arg, ipcTargetData *td, const ipcMessage *msg)
    588603{
     604#ifdef VBOX
     605  if (!msg)
     606    return PR_TRUE;
     607#endif /* VBOX */
    589608  PRUint32 requestIndex = *(PRUint32 *) arg;
    590609  return IPCM_GetRequestIndex(msg) == requestIndex;
     
    914933{
    915934  WaitMessageSelectorData *data = (WaitMessageSelectorData *) arg;
     935#ifdef VBOX
     936  if (!msg)
     937  {
     938    /* Special NULL message which asks to check whether the client is
     939     * still alive. Called when there is nothing suitable in the queue. */
     940    ipcIMessageObserver *obs = data->observer;
     941    if (!obs)
     942      obs = td->observer;
     943    NS_ASSERTION(obs, "must at least have a default observer");
     944
     945    nsresult rv = obs->OnMessageAvailable(IPC_SENDER_ANY, nsID(), 0, 0);
     946    if (rv != IPC_WAIT_NEXT_MESSAGE)
     947    {
     948      data->senderDead = PR_TRUE;
     949      return PR_FALSE;
     950    }
     951    return PR_TRUE;
     952  }
     953#endif /* VBOX */
    916954
    917955  // process the specially forwarded client state message to see if the
     
    943981          {
    944982            // otherwise inform the observer about the client death using a special
    945             // null message with an emply target id, and fail IPC_WaitMessage call
     983            // null message with an empty target id, and fail IPC_WaitMessage call
    946984            // with NS_ERROR_xxx only if the observer accepts this message.
    947985
     
    959997          }
    960998        }
     999#ifdef VBOX
     1000        else if ((data->senderID == IPC_SENDER_ANY ||
     1001                  status->ClientID() == data->senderID) &&
     1002                 status->ClientState() == IPCM_CLIENT_STATE_UP)
     1003        {
     1004          LOG(("sender (%d) we're waiting a message from (%d) has come up\n",
     1005               status->ClientID(), data->senderID));
     1006          if (data->senderID == IPC_SENDER_ANY)
     1007          {
     1008            // inform the observer about the client appearance using a special
     1009            // null message with an empty target id, but a length of 1.
     1010
     1011            ipcIMessageObserver *obs = data->observer;
     1012            if (!obs)
     1013              obs = td->observer;
     1014            NS_ASSERTION(obs, "must at least have a default observer");
     1015
     1016            nsresult rv = obs->OnMessageAvailable(status->ClientID(), nsID(), 0, 1);
     1017            if (rv != IPC_WAIT_NEXT_MESSAGE)
     1018            {
     1019              /* It might sound a bit paradoxical to declare the sender as
     1020               * dead, but the fact that a client up message is received
     1021               * while waiting for a message from this client clearly
     1022               * indicates that this is no longer the client we were waiting
     1023               * for, but a new one got the same client ID (due to wraparound).
     1024               * Shouldn't happen in real life, but better be safe. */
     1025              data->senderDead = PR_TRUE;
     1026              return PR_TRUE; // consume the message
     1027            }
     1028          }
     1029        }
     1030#endif /* VBOX */
    9611031        break;
    9621032      }
  • trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp

    r24637 r26554  
    5151#include "nsDeque.h"
    5252#include "xptcall.h"
     53
     54#ifdef VBOX
     55#include <map>
     56#include <list>
     57#endif /* VBOX */
    5358
    5459#if defined(DCONNECT_MULTITHREADED)
     
    12551260//-----------------------------------------------------------------------------
    12561261
     1262#ifdef VBOX
     1263typedef struct ClientDownInfo
     1264{
     1265    ClientDownInfo(PRUint32 aClient)
     1266    {
     1267        uClient = aClient;
     1268        uTimestamp = PR_IntervalNow();
     1269    }
     1270
     1271    PRUint32 uClient;
     1272    PRIntervalTime uTimestamp;
     1273} ClientDownInfo;
     1274typedef std::map<PRUint32, ClientDownInfo *> ClientDownMap;
     1275typedef std::list<ClientDownInfo *> ClientDownList;
     1276
     1277#define MAX_CLIENT_DOWN_SIZE 10000
     1278
     1279/* Protected by the queue monitor. */
     1280static ClientDownMap g_ClientDownMap;
     1281static ClientDownList g_ClientDownList;
     1282
     1283#endif /* VBOX */
     1284
    12571285class DConnectMsgSelector : public ipcIMessageObserver
    12581286{
     
    12751303    // accept special "client dead" messages for a given peer
    12761304    // (empty target id, zero data and data length)
     1305#ifndef VBOX
    12771306    if (aSenderID == mPeer && aTarget.Equals(nsID()) && !aData && !aDataLen)
    12781307        return NS_OK;
     1308#else /* VBOX */
     1309    if (aSenderID != IPC_SENDER_ANY && aTarget.Equals(nsID()) && !aData && !aDataLen)
     1310    {
     1311        // Insert new client down information. Start by expiring outdated
     1312        // entries and free one element if there's still no space (if needed).
     1313        PRIntervalTime now = PR_IntervalNow();
     1314        do {
     1315            ClientDownInfo *cInfo = g_ClientDownList.back();
     1316            if (!cInfo)
     1317                break;
     1318            PRInt64 diff = (PRInt64)now - cInfo->uTimestamp;
     1319            if (diff < 0)
     1320                diff += (PRInt64)((PRIntervalTime)-1) + 1;
     1321            if (diff > PR_SecondsToInterval(15 * 60))
     1322            {
     1323                g_ClientDownMap.erase(cInfo->uClient);
     1324                g_ClientDownList.pop_back();
     1325                delete cInfo;
     1326            }
     1327            else
     1328                break;
     1329        } while (true);
     1330
     1331        ClientDownMap::iterator it = g_ClientDownMap.find(aSenderID);
     1332        if (it == g_ClientDownMap.end())
     1333        {
     1334            while (g_ClientDownList.size() >= MAX_CLIENT_DOWN_SIZE)
     1335            {
     1336                ClientDownInfo *cInfo = g_ClientDownList.back();
     1337                g_ClientDownMap.erase(cInfo->uClient);
     1338                g_ClientDownList.pop_back();
     1339                delete cInfo;
     1340            }
     1341
     1342            ClientDownInfo *cInfo = new ClientDownInfo(aSenderID);
     1343            g_ClientDownMap[aSenderID] = cInfo;
     1344            g_ClientDownList.push_front(cInfo);
     1345        }
     1346        return (aSenderID == mPeer) ? NS_OK : IPC_WAIT_NEXT_MESSAGE;
     1347    }
     1348    // accept special "client up" messages for a given peer
     1349    // (empty target id, zero data and data length=1)
     1350    if (aTarget.Equals(nsID()) && !aData && aDataLen == 1)
     1351    {
     1352        ClientDownMap::iterator it = g_ClientDownMap.find(aSenderID);
     1353        if (it != g_ClientDownMap.end())
     1354        {
     1355            ClientDownInfo *cInfo = it->second;
     1356            g_ClientDownMap.erase(it);
     1357            g_ClientDownList.remove(cInfo);
     1358            delete cInfo;
     1359        }
     1360        return (aSenderID == mPeer) ? NS_OK : IPC_WAIT_NEXT_MESSAGE;
     1361    }
     1362    // accept special "client check" messages for an anonymous sender
     1363    // (invalid sender id, empty target id, zero data and data length
     1364    if (aSenderID == IPC_SENDER_ANY && aTarget.Equals(nsID()) && !aData && !aDataLen)
     1365    {
     1366        LOG(("DConnectMsgSelector::OnMessageAvailable: poll liveness for mPeer=%d\n",
     1367             mPeer));
     1368        ClientDownMap::iterator it = g_ClientDownMap.find(mPeer);
     1369        return (it == g_ClientDownMap.end()) ? IPC_WAIT_NEXT_MESSAGE : NS_OK;
     1370    }
     1371#endif /* VBOX */
    12791372    const DConnectOp *op = (const DConnectOp *) aData;
    12801373    // accept only reply messages with the given peer/opcode/index
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette