VirtualBox

Changeset 26582 in vbox


Ignore:
Timestamp:
Feb 16, 2010 3:01:50 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. r57733 was too paranoid, and failed more or less frequently when VBoxSVC was autostarted.

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

Legend:

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

    r26566 r26582  
    405405      break;
    406406    }
     407#ifdef VBOX
     408    else
     409    {
     410      /* Special client liveness check if there is no message to process.
     411       * This is necessary as there might be several threads waiting for
     412       * a message from a single client, and only one gets the DOWN msg. */
     413      PRBool alive = (aSelector)(aArg, td, NULL);
     414      if (!alive)
     415      {
     416        *aMsg = NULL;
     417        break;
     418      }
     419    }
     420#endif /* VBOX */
    407421
    408422    PRIntervalTime t = PR_IntervalNow();
     
    587601WaitIPCMResponseSelector(void *arg, ipcTargetData *td, const ipcMessage *msg)
    588602{
     603#ifdef VBOX
     604  if (!msg)
     605    return PR_TRUE;
     606#endif /* VBOX */
    589607  PRUint32 requestIndex = *(PRUint32 *) arg;
    590608  return IPCM_GetRequestIndex(msg) == requestIndex;
     
    914932{
    915933  WaitMessageSelectorData *data = (WaitMessageSelectorData *) arg;
     934#ifdef VBOX
     935  if (!msg)
     936  {
     937    /* Special NULL message which asks to check whether the client is
     938     * still alive. Called when there is nothing suitable in the queue. */
     939    ipcIMessageObserver *obs = data->observer;
     940    if (!obs)
     941      obs = td->observer;
     942    NS_ASSERTION(obs, "must at least have a default observer");
     943
     944    nsresult rv = obs->OnMessageAvailable(IPC_SENDER_ANY, nsID(), 0, 0);
     945    if (rv != IPC_WAIT_NEXT_MESSAGE)
     946    {
     947      data->senderDead = PR_TRUE;
     948      return PR_FALSE;
     949    }
     950    return PR_TRUE;
     951  }
     952#endif /* VBOX */
    916953
    917954  // process the specially forwarded client state message to see if the
     
    943980          {
    944981            // otherwise inform the observer about the client death using a special
    945             // null message with an emply target id, and fail IPC_WaitMessage call
     982            // null message with an empty target id, and fail IPC_WaitMessage call
    946983            // with NS_ERROR_xxx only if the observer accepts this message.
    947984
     
    959996          }
    960997        }
     998#ifdef VBOX
     999        else if ((data->senderID == IPC_SENDER_ANY ||
     1000                  status->ClientID() == data->senderID) &&
     1001                 status->ClientState() == IPCM_CLIENT_STATE_UP)
     1002        {
     1003          LOG(("sender (%d) we're waiting a message from (%d) has come up\n",
     1004               status->ClientID(), data->senderID));
     1005          if (data->senderID == IPC_SENDER_ANY)
     1006          {
     1007            // inform the observer about the client appearance using a special
     1008            // null message with an empty target id, but a length of 1.
     1009
     1010            ipcIMessageObserver *obs = data->observer;
     1011            if (!obs)
     1012              obs = td->observer;
     1013            NS_ASSERTION(obs, "must at least have a default observer");
     1014
     1015            nsresult rv = obs->OnMessageAvailable(status->ClientID(), nsID(), 0, 1);
     1016            /* VBoxSVC/VBoxXPCOMIPCD auto-start can cause that a client up
     1017             * message arrives while we're already waiting for a response
     1018             * from this client. Don't declare the connection as dead in
     1019             * this case. A client ID wraparound can't falsely trigger
     1020             * this, since the waiting thread would have hit the liveness
     1021             * check in the mean time. Also, DO NOT consume the message,
     1022             * otherwise it gets passed to the DConnect message handling
     1023             * without any further checks. IPCM messages are automatically
     1024             * discarded if they are left unclaimed. */
     1025          }
     1026        }
     1027#endif /* VBOX */
    9611028        break;
    9621029      }
  • trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp

    r26566 r26582  
    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