Changeset 3821 in vbox for trunk/src/libs/xpcom18a4/ipc/ipcd/extensions
- Timestamp:
- Jul 25, 2007 9:01:48 AM (17 years ago)
- 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 955 955 , mInstance(aInstance) 956 956 , mPeerID(aPeerID) 957 , m ISupportsInstance(0)957 , mCachedISupports(0) 958 958 , mRefCntLevels(0) 959 959 {} … … 988 988 PRUint32 mPeerID; 989 989 990 // cached nsISupports instancefor this object991 DCon Addr mISupportsInstance;990 // cached nsISupports stub for this object 991 DConnectStub *mCachedISupports; 992 992 993 993 // stack of reference counter values returned by AddRef made in CreateStub … … 1004 1004 // object in order to balance AddRef() the peer does on DConnectInstance every 1005 1005 // 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; 1006 1011 1007 nsAutoLock stubLock ( ipcDConnectService::GetInstance()->StubLock());1012 nsAutoLock stubLock (dConnect->StubLock()); 1008 1013 1009 1014 nsrefcnt count = AddRef(); … … 1630 1635 dConnect->DeleteStub(this); 1631 1636 } 1637 1638 // release the cached nsISupports instance if it's not the same object 1639 if (mCachedISupports != 0 && mCachedISupports != this) 1640 NS_RELEASE(mCachedISupports); 1632 1641 } 1633 1642 … … 1706 1715 } 1707 1716 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 } 1709 1789 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 1739 1791 1740 1792 #ifdef IPC_LOGGING 1741 1793 { 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)); 1757 1803 } 1758 1804 #endif … … 1763 1809 msg.instance = mInstance; 1764 1810 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 1774 1827 return rv; 1775 1828 } … … 2271 2324 , mDisconnected(PR_TRUE) 2272 2325 , mStubLock(NULL) 2326 , mStubQILock(NULL) 2273 2327 { 2274 2328 } … … 2300 2354 2301 2355 mInstance = nsnull; 2356 PR_DestroyLock(mStubQILock); 2302 2357 PR_DestroyLock(mStubLock); 2303 2358 PR_DestroyLock(mLock); … … 2337 2392 mStubLock = PR_NewLock(); 2338 2393 if (!mStubLock) 2394 return NS_ERROR_OUT_OF_MEMORY; 2395 2396 mStubQILock = PR_NewLock(); 2397 if (!mStubQILock) 2339 2398 return NS_ERROR_OUT_OF_MEMORY; 2340 2399 -
trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h
r2499 r3821 238 238 239 239 PRLock *StubLock() { return mStubLock; } 240 PRLock *StubQILock() { return mStubQILock; } 240 241 241 242 static nsRefPtr <ipcDConnectService> GetInstance() { … … 289 290 // global lock to protect access to DConnectStub internal data 290 291 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; 291 297 292 298 #if defined(DCONNECT_MULTITHREADED)
Note:
See TracChangeset
for help on using the changeset viewer.