VirtualBox

Ignore:
Timestamp:
Jul 25, 2007 9:01:48 AM (17 years ago)
Author:
vboxsync
Message:

XPCOM/IPC/DConnect: Fixed one IUnknown Identity aspect indirectly broken in r14191 which also superceded incorrect IUnknown caching introduced in r14229; Implemented thread safety for QueryInterface() for stubs representing inter-process objects.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp

    r3276 r3821  
    955955    , mInstance(aInstance)
    956956    , mPeerID(aPeerID)
    957     , mISupportsInstance(0)
     957    , mCachedISupports(0)
    958958    , mRefCntLevels(0)
    959959    {}
     
    988988  PRUint32 mPeerID;
    989989 
    990   // cached nsISupports instance for this object
    991   DConAddr mISupportsInstance;
     990  // cached nsISupports stub for this object
     991  DConnectStub *mCachedISupports;
    992992 
    993993  // stack of reference counter values returned by AddRef made in CreateStub
     
    10041004  // object in order to balance AddRef() the peer does on DConnectInstance every
    10051005  // time it passes an object over IPC.
     1006
     1007  nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
     1008  NS_ASSERTION(dConnect, "no ipcDConnectService (uninitialized?)");
     1009  if (!dConnect)
     1010    return 0;
    10061011 
    1007   nsAutoLock stubLock (ipcDConnectService::GetInstance()->StubLock());
     1012  nsAutoLock stubLock (dConnect->StubLock());
    10081013 
    10091014  nsrefcnt count = AddRef();
     
    16301635    dConnect->DeleteStub(this);
    16311636  }
     1637
     1638  // release the cached nsISupports instance if it's not the same object
     1639  if (mCachedISupports != 0 && mCachedISupports != this)
     1640    NS_RELEASE(mCachedISupports);
    16321641}
    16331642
     
    17061715  }
    17071716
    1708   PRBool isISupports = aIID.Equals(NS_GET_IID(nsISupports));
     1717  // In order to truely support the COM Identity Rule across processes,
     1718  // we need to make the following code work:
     1719  //
     1720  //   IFoo *foo = ...
     1721  //   nsISupports unk;
     1722  //   foo->QueryInterface(NS_GET_IID(nsISupports), (void **) &unk);
     1723  //   unk->Release();
     1724  //   nsISupports unk2;
     1725  //   foo->QueryInterface(NS_GET_IID(nsISupports), (void **) &unk2);
     1726  //   Assert (unk == unk2);
     1727  //
     1728  // I.e. querying nsISupports on the same object must always return the same
     1729  // pointer, even if the nsISupports object returned for the first time is
     1730  // released before it is requested for the second time, as long as the
     1731  // original object is kept alive (referenced by the client) between these
     1732  // two queries.
     1733  //
     1734  // This is done by remembering the nsISupports stub returned by the peer
     1735  // when nsISupports is queried for the first time. The remembered stub, when
     1736  // it is not the same as this object, is strongly referenced in order to
     1737  // keep it alive (and therefore have the same pointer value) as long as this
     1738  // object is alive.
     1739  //
     1740  // Besides supporting the Identity Rule, this also reduces the number of IPC
     1741  // calls, since an IPC call requesting nsISupports will be done only once
     1742  // per every stub object.
     1743
     1744  nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
     1745  NS_ASSERTION(dConnect, "no ipcDConnectService (uninitialized?)");
     1746  if (!dConnect)
     1747    return NS_ERROR_NOT_INITIALIZED;
     1748
     1749  nsresult rv;
     1750  PRBool needISupports = aIID.Equals(NS_GET_IID(nsISupports));
     1751
     1752  if (needISupports)
     1753  {
     1754    // XXX it would be sufficient to use cmpxchg here to protect access to
     1755    // mCachedISupports, but NSPR doesn't provide cross-platform cmpxchg
     1756    // functionality, so we have to use a shared lock instead...
     1757    PR_Lock(dConnect->StubQILock());
     1758
     1759    // check if we have already got a nsISupports stub for this object
     1760    if (mCachedISupports != 0)
     1761    {
     1762      *aInstancePtr = mCachedISupports;
     1763      NS_ADDREF(mCachedISupports);
     1764
     1765      PR_Unlock(dConnect->StubQILock());
     1766      return NS_OK;
     1767    }
     1768
     1769    // check if this object is nsISupports itself
     1770    nsIID *iid = 0;
     1771    rv = mIInfo->GetInterfaceIID(&iid);
     1772    NS_ASSERTION(NS_SUCCEEDED(rv) && iid,
     1773                 "nsIInterfaceInfo::GetInterfaceIID failed");
     1774    if (NS_SUCCEEDED(rv) && iid &&
     1775        iid->Equals(NS_GET_IID(nsISupports)))
     1776    {
     1777      // nsISupports is queried on nsISupports, return ourselves
     1778      *aInstancePtr = this;
     1779      NS_ADDREF_THIS();
     1780      // cache ourselves weakly
     1781      mCachedISupports = this;
     1782
     1783      PR_Unlock(dConnect->StubQILock());
     1784      return NS_OK;
     1785    }
     1786
     1787    // stub lock remains held until we've queried the peer
     1788  }
    17091789 
    1710   // see if we have a nsISupports stub for this object
    1711   if (isISupports)
    1712   {
    1713     // according to the COM Identity Rule, an object should always return the
    1714     // same nsISupports pointer on every QueryInterface call. Based on this,
    1715     // we cache the nsISupports instance for this stub's object in order to
    1716     // reduce the number of IPC calls.
    1717 
    1718     if (mISupportsInstance != 0)
    1719     {
    1720       // check that the instance is still valid by searching for a stub for it
    1721       nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
    1722       if (dConnect)
    1723       {
    1724         DConnectStub *stub = nsnull;
    1725         if (dConnect->FindStubAndAddRef(mPeerID, mISupportsInstance, &stub))
    1726         {
    1727             LOG(("using cached nsISupports stub for peer object\n"));
    1728             *aInstancePtr = stub;
    1729             return NS_OK;
    1730         }
    1731       }
    1732      
    1733       // the stub for the instance has already been deleted
    1734       mISupportsInstance = 0;
    1735     }
    1736   }
    1737  
    1738   // else, we need to query the peer object
     1790  // else, we need to query the peer object by making an IPC call
    17391791
    17401792#ifdef IPC_LOGGING
    17411793  {
    1742     nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
    1743     if (dConnect)
    1744     {
    1745       const char *name;
    1746       nsCOMPtr <nsIInterfaceInfo> iinfo;
    1747       GetInterfaceInfo(getter_AddRefs(iinfo));
    1748       iinfo->GetNameShared(&name);
    1749       const char *nameQ;
    1750       nsCOMPtr <nsIInterfaceInfo> iinfoQ;
    1751       dConnect->GetInterfaceInfo(aIID, getter_AddRefs(iinfoQ));
    1752       iinfoQ->GetNameShared(&nameQ);
    1753       LOG(("calling QueryInterface {%s} on peer object "
    1754            "(stub=%p, instance=%p {%s})\n",
    1755            nameQ, this, mInstance, name));
    1756     }
     1794    const char *name;
     1795    mIInfo->GetNameShared(&name);
     1796    const char *nameQ;
     1797    nsCOMPtr <nsIInterfaceInfo> iinfoQ;
     1798    dConnect->GetInterfaceInfo(aIID, getter_AddRefs(iinfoQ));
     1799    iinfoQ->GetNameShared(&nameQ);
     1800    LOG(("calling QueryInterface {%s} on peer object "
     1801         "(stub=%p, instance=%p {%s})\n",
     1802         nameQ, this, mInstance, name));
    17571803  }
    17581804#endif
     
    17631809  msg.instance = mInstance;
    17641810
    1765   nsresult rv = SetupPeerInstance(mPeerID, &msg, sizeof(msg), aInstancePtr);
    1766  
    1767   if (isISupports && NS_SUCCEEDED(rv))
    1768   {
    1769     // cache the nsISupports instance (SetupPeerInstance returns DConnectStub)
    1770     DConnectStub *stub = (DConnectStub *) *aInstancePtr;
    1771     mISupportsInstance = stub->mInstance;
    1772   }
    1773  
     1811  rv = SetupPeerInstance(mPeerID, &msg, sizeof(msg), aInstancePtr);
     1812
     1813  if (needISupports)
     1814  {
     1815    if (NS_SUCCEEDED(rv))
     1816    {
     1817      // cache the nsISupports object (SetupPeerInstance returns DConnectStub)
     1818      mCachedISupports = (DConnectStub *) *aInstancePtr;
     1819      // use a weak reference if nsISupports is the same object as us
     1820      if (this != mCachedISupports)
     1821        NS_ADDREF(mCachedISupports);
     1822    }
     1823
     1824    PR_Unlock(dConnect->StubQILock());
     1825  }
     1826
    17741827  return rv;
    17751828}
     
    22712324 , mDisconnected(PR_TRUE)
    22722325 , mStubLock(NULL)
     2326 , mStubQILock(NULL)
    22732327{
    22742328}
     
    23002354
    23012355  mInstance = nsnull;
     2356  PR_DestroyLock(mStubQILock);
    23022357  PR_DestroyLock(mStubLock);
    23032358  PR_DestroyLock(mLock);
     
    23372392  mStubLock = PR_NewLock();
    23382393  if (!mStubLock)
     2394    return NS_ERROR_OUT_OF_MEMORY;
     2395
     2396  mStubQILock = PR_NewLock();
     2397  if (!mStubQILock)
    23392398    return NS_ERROR_OUT_OF_MEMORY;
    23402399
  • trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h

    r2499 r3821  
    238238
    239239  PRLock *StubLock() { return mStubLock; }
     240  PRLock *StubQILock() { return mStubQILock; }
    240241 
    241242  static nsRefPtr <ipcDConnectService> GetInstance() {
     
    289290  // global lock to protect access to DConnectStub internal data
    290291  PRLock *mStubLock;
     292
     293  // global lock to protect access to protect DConnectStub::QueryInterface()
     294  // (we cannot use mStubLock because it isn't supposed to be held long,
     295  // like in case of an IPC call and such)
     296  PRLock *mStubQILock;
    291297
    292298#if defined(DCONNECT_MULTITHREADED)
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