VirtualBox

Ignore:
Timestamp:
Sep 17, 2007 6:05:36 PM (17 years ago)
Author:
vboxsync
Message:

XPCOM/IPC/DConnect: Lock the whole Release() method of stub objects to provide atomicity of releasing the last stub reference and removing this stub from the set of existing stubs (to avoid misuse of stubs by other threads just before they are deleted which may happen on SMP machines).

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

    r3821 r4863  
    991991  DConnectStub *mCachedISupports;
    992992 
    993   // stack of reference counter values returned by AddRef made in CreateStub
    994   // (access must be protected using the ipcDConnectService::stubLock())
     993  // stack of reference counter values (protected by
     994  // ipcDConnectService::StubLock())
    995995  nsDeque mRefCntLevels;
    996996};
     
    10051005  // time it passes an object over IPC.
    10061006
     1007  // NOTE: this function is to be called from DConnectInstance::CreateStub only!
     1008
    10071009  nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
    10081010  NS_ASSERTION(dConnect, "no ipcDConnectService (uninitialized?)");
    10091011  if (!dConnect)
    10101012    return 0;
    1011  
    1012   nsAutoLock stubLock (dConnect->StubLock());
    1013  
     1013
     1014  // dConnect->StubLock() must be already locked here by
     1015  // DConnectInstance::CreateStub
     1016
    10141017  nsrefcnt count = AddRef();
    10151018  mRefCntLevels.Push((void *) count);
     
    10311034
    10321035  if (mDisconnected)
    1033       return NS_ERROR_NOT_INITIALIZED;
     1036    return NS_ERROR_NOT_INITIALIZED;
     1037
     1038  // we also need the stub lock which protects DConnectStub::mRefCntLevels and
     1039  // ipcDConnectService::mStubs
     1040  nsAutoLock stubLock (mStubLock);
    10341041
    10351042  DConnectStub *stub = nsnull;
     
    16241631#endif   
    16251632   
    1626   nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
    1627   if (dConnect)
    1628   {
    1629 #ifdef NS_DEBUG
    1630     {
    1631       nsAutoLock stubLock (dConnect->StubLock());
    1632       NS_ASSERTION(mRefCntLevels.GetSize() == 0, "refcnt levels are still left");
    1633     }
    1634 #endif   
    1635     dConnect->DeleteStub(this);
    1636   }
    1637 
    16381633  // release the cached nsISupports instance if it's not the same object
    16391634  if (mCachedISupports != 0 && mCachedISupports != this)
     
    16531648DConnectStub::Release()
    16541649{
    1655   nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
    1656   NS_LOG_RELEASE(this, count, "DConnectStub");
     1650  nsrefcnt count;
    16571651
    16581652  nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance());
    16591653  if (dConnect)
    16601654  {
     1655    // lock the stub lock on every release to make sure that once the counter
     1656    // drops to zero, we delete the stub from the set of stubs before a new
     1657    // request to create a stub on other thread tries to find the existing
     1658    // stub in the set (wchich could otherwise AddRef the object after it had
     1659    // Released to zero and pass it to the client right before its
     1660    // destruction).
    16611661    nsAutoLock stubLock (dConnect->StubLock());
    1662      
     1662
     1663    count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
     1664    NS_LOG_RELEASE(this, count, "DConnectStub");
     1665
    16631666    // mRefCntLevels may already be empty here (due to the "stabilize" trick below)
    16641667    if (mRefCntLevels.GetSize() > 0)
     
    16751678        mRefCntLevels.Pop();
    16761679
     1680        if (0 == count)
     1681        {
     1682          // this is the last reference, remove from the set before we leave
     1683          // the lock, to provide atomicity of these two operations
     1684          dConnect->DeleteStub (this);
     1685
     1686          NS_ASSERTION(mRefCntLevels.GetSize() == 0, "refcnt levels are still left");
     1687        }
     1688
     1689        // leave the lock before sending a message
    16771690        stubLock.unlock();
    16781691     
     
    16921705      }
    16931706    }
     1707  }
     1708  else
     1709  {
     1710    count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
     1711    NS_LOG_RELEASE(this, count, "DConnectStub");
    16941712  }
    16951713 
     
    23222340ipcDConnectService::ipcDConnectService()
    23232341 : mLock(NULL)
     2342 , mStubLock(NULL)
    23242343 , mDisconnected(PR_TRUE)
    2325  , mStubLock(NULL)
    23262344 , mStubQILock(NULL)
    23272345{
     
    23832401    return NS_ERROR_OUT_OF_MEMORY;
    23842402
     2403  mStubLock = PR_NewLock();
     2404  if (!mStubLock)
     2405    return NS_ERROR_OUT_OF_MEMORY;
     2406
    23852407  if (!mStubs.Init())
    23862408    return NS_ERROR_OUT_OF_MEMORY;
     
    23892411  if (NS_FAILED(rv))
    23902412    return rv;
    2391 
    2392   mStubLock = PR_NewLock();
    2393   if (!mStubLock)
    2394     return NS_ERROR_OUT_OF_MEMORY;
    23952413
    23962414  mStubQILock = PR_NewLock();
     
    26212639#endif
    26222640
    2623   nsAutoLock lock (mLock);
    2624 
    2625   // this method is intended to be called only from DConnectStub destructor.
     2641  // this method is intended to be called only from DConnectStub::Release().
    26262642  // the stub object is not deleted when removed from the table, because
    26272643  // DConnectStub pointers are not owned by mStubs.
     
    26292645}
    26302646
     2647// not currently used
     2648#if 0
    26312649PRBool
    26322650ipcDConnectService::FindStubAndAddRef(PRUint32 peer, const DConAddr instance,
    26332651                                      DConnectStub **stub)
    26342652{
    2635   nsAutoLock lock (mLock);
     2653  nsAutoLock stubLock (mStubLock);
    26362654
    26372655  PRBool result = mStubs.Get(DConnectStubKey::Key(peer, instance), stub);
     
    26402658  return result;
    26412659}
     2660#endif
    26422661
    26432662NS_IMPL_THREADSAFE_ISUPPORTS3(ipcDConnectService, ipcIDConnectService,
  • trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h

    r3821 r4863  
    228228
    229229  NS_HIDDEN_(nsresult) CreateStub(const nsID &, PRUint32, DConAddr, DConnectStub **);
     230#if 0
    230231  NS_HIDDEN_(PRBool)   FindStubAndAddRef(PRUint32, const DConAddr, DConnectStub **);
     232#endif
    231233  // public only for DConnectStub::~DConnectStub()
    232234  NS_HIDDEN_(void)     DeleteStub(DConnectStub *);
     
    269271  nsCOMPtr<nsIInterfaceInfoManager> mIIM;
    270272
    271   // lock to protect access to instance and stub sets and the disconnected flag
     273  // lock to protect access to instance sets and the disconnected flag
    272274  PRLock *mLock;
    273275
     
    279281  DConnectInstanceSet mInstanceSet;
    280282
     283  // lock to protect access to mStubs and DConnectStub::mRefCntLevels
     284  // (also guards every DConnectStub::Release call to provide atomicity)
     285  PRLock *mStubLock;
     286
    281287  // table of remote object stubs allocated to communicate with peer's instances
    282288  DConnectStubMap mStubs;
     
    288294  PRUint32 mSelfID;
    289295 
    290   // global lock to protect access to DConnectStub internal data
    291   PRLock *mStubLock;
    292 
    293296  // global lock to protect access to protect DConnectStub::QueryInterface()
    294297  // (we cannot use mStubLock because it isn't supposed to be held long,
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