Changeset 3276 in vbox
- Timestamp:
- Jun 25, 2007 2:36:15 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp
r3058 r3276 234 234 count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); 235 235 if (0 == count) { 236 NS_PRECONDITION(PRInt32(mRefCntIPC) == 0, "non-zero IPC refcnt"); 236 237 mRefCnt = 1; /* stabilize */ 238 delete this; 239 return 0; 240 } 241 return count; 242 } 243 244 // this gets called after calling AddRef() on an instance passed to the 245 // client over IPC in order to have a count of IPC client-related references 246 // separately from the overall reference count 247 NS_IMETHODIMP_(nsrefcnt) AddRefIPC(void) 248 { 249 NS_PRECONDITION(PRInt32(mRefCntIPC) >= 0, "illegal refcnt"); 250 nsrefcnt count = PR_AtomicIncrement((PRInt32*)&mRefCntIPC); 251 return count; 252 } 253 254 // this gets called before calling Release() when DCON_OP_RELEASE is 255 // received from the IPC client and in other cases to balance AddRefIPC() 256 NS_IMETHODIMP_(nsrefcnt) ReleaseIPC(PRBool locked = PR_FALSE) 257 { 258 NS_PRECONDITION(0 != mRefCntIPC, "dup release"); 259 nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCntIPC); 260 if (0 == count) { 261 // If the last IPC reference is releaed, remove this instance from the map. 237 262 // ipcDConnectService is guaranteed to still exist here 238 263 // (DConnectInstance lifetime is bound to ipcDConnectService) 239 264 nsRefPtr <ipcDConnectService> dConnect (ipcDConnectService::GetInstance()); 240 265 if (dConnect) 241 dConnect->DeleteInstance(this );266 dConnect->DeleteInstance(this, locked); 242 267 else 243 268 NS_NOTREACHED("ipcDConnectService has gone before DConnectInstance"); 244 delete this;245 return 0;246 269 } 247 270 return count; … … 250 273 private: 251 274 nsAutoRefCnt mRefCnt; 275 nsAutoRefCnt mRefCntIPC; 252 276 PRUint32 mPeer; // peer process "owning" this instance 253 277 nsCOMPtr<nsIInterfaceInfo> mIInfo; … … 259 283 { 260 284 for (PRInt32 i=0; i<wrappers.Count(); ++i) 285 { 286 ((DConnectInstance *) wrappers[i])->ReleaseIPC(); 261 287 ((DConnectInstance *) wrappers[i])->Release(); 288 } 262 289 } 263 290 … … 1098 1125 wrapper->AddRef(); 1099 1126 } 1127 1128 // increase the second, IPC-only, reference counter (mandatory before 1129 // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove 1130 // the wrapper from the instance map on failure) 1131 wrapper->AddRefIPC(); 1100 1132 1101 1133 if (!wrappers.AppendElement(wrapper)) 1102 1134 { 1135 wrapper->ReleaseIPC(); 1103 1136 wrapper->Release(); 1104 1137 return NS_ERROR_OUT_OF_MEMORY; … … 1365 1398 wrapper->AddRef(); 1366 1399 } 1400 1401 // increase the second, IPC-only, reference counter (mandatory before 1402 // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove 1403 // the wrapper from the instance map on failure) 1404 wrapper->AddRefIPC(); 1367 1405 1368 1406 if (!wrappers.AppendElement(wrapper)) 1369 1407 { 1408 wrapper->ReleaseIPC(); 1370 1409 wrapper->Release(); 1371 1410 return NS_ERROR_OUT_OF_MEMORY; … … 1374 1413 // wrapper remains referenced when passing it to the client 1375 1414 // (will be released upon DCON_OP_RELEASE) 1376 1415 1377 1416 // send address of the instance wrapper, and set the low bit 1378 1417 // to indicate that this is an instance wrapper. … … 1646 1685 } 1647 1686 1648 if (0 == count) { 1687 if (0 == count) 1688 { 1649 1689 mRefCnt = 1; /* stabilize */ 1650 1690 delete this; … … 1697 1737 1698 1738 // else, we need to query the peer object 1699 LOG(("calling QueryInterface on peer object\n")); 1739 1740 #ifdef IPC_LOGGING 1741 { 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 } 1757 } 1758 #endif 1700 1759 1701 1760 DConnectSetupQueryInterface msg; … … 2674 2733 if (args && args->clientID == aData->Peer()) 2675 2734 { 2676 // ignore the reference counter: the client is officially dead 2677 args->that->DeleteInstance(aData, PR_TRUE /* locked */); 2678 // collect the instance for future destruction 2735 nsrefcnt countIPC = aData->ReleaseIPC(PR_TRUE /* locked */); 2736 2737 LOG(("ipcDConnectService::PruneInstanceMapForPeer: " 2738 "instance=%p: %d IPC refs to release\n", 2739 aData, countIPC + 1)); 2740 2741 // release all IPC instances of the "officially dead" client (see 2742 // #OnRelease() to understand why it must be done under the lock). Note 2743 // that due to true multithreading, late OnRelease() requests may still 2744 // happen on other worker threads *after* OnClientStateChange() has been 2745 // called, but it's OK because the instance will be removed from the map 2746 // by the below code alreay and won't be deleted for the second time. 2747 while (countIPC) 2748 { 2749 countIPC = aData->ReleaseIPC(PR_TRUE /* locked */); 2750 aData->Release(); 2751 } 2752 2753 // collect the instance for the last release 2754 // (we'll do it later outside the lock) 2679 2755 if (!args->wrappers.AppendElement(aData)) 2680 2756 { 2681 2757 NS_NOTREACHED("Not enough memory"); 2682 2758 // bad but what to do 2683 delete aData;2759 aData->Release(); 2684 2760 } 2685 2761 } … … 2717 2793 } 2718 2794 2719 // destruct all instances outside the lock because it will release 2720 // the real objects which may need to make asynchronous use our service 2795 LOG(("ipcDConnectService::OnClientStateChange: " 2796 "%d lost instances\n", wrappers.Count())); 2797 2798 // release all pending references left after PruneInstanceMapForPeer(). 2799 // this may call wrapper destructors so it's important to do that 2800 // outside the lock because destructors will release the real objects 2801 // which may need to make asynchronous use our service 2721 2802 for (PRInt32 i = 0; i < wrappers.Count(); ++i) 2722 delete ((DConnectInstance *) wrappers[i]);2803 ((DConnectInstance *) wrappers[i])->Release(); 2723 2804 } 2724 2805 } … … 2865 2946 // reference the newly created wrapper 2866 2947 wrapper->AddRef(); 2867 2868 if (!wrappers.AppendElement(wrapper))2869 {2870 NS_RELEASE(wrapper);2871 rv = NS_ERROR_OUT_OF_MEMORY;2872 }2873 2948 } 2949 } 2950 } 2951 2952 if (wrapper) 2953 { 2954 // increase the second, IPC-only, reference counter (mandatory before 2955 // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove 2956 // the wrapper from the instance map on failure) 2957 wrapper->AddRefIPC(); 2958 2959 if (!wrappers.AppendElement(wrapper)) 2960 { 2961 wrapper->ReleaseIPC(); 2962 wrapper->Release(); 2963 rv = NS_ERROR_OUT_OF_MEMORY; 2874 2964 } 2875 2965 } … … 2947 3037 if (mInstanceSet.Contains(wrapper)) 2948 3038 { 2949 nsrefcnt count = wrapper->AddRef(); 2950 count = wrapper->Release(); 2951 if (count == 1) 2952 { 2953 // we are the last one who holds a (fake) reference, remove the 2954 // instace from instance maps while still under the lock 2955 DeleteInstance(wrapper, PR_TRUE /* locked */); 2956 // leave the lock before calling the destructor because it will release 2957 // the real object which may need to make asynchronous use our service 2958 lock.unlock(); 2959 delete wrapper; 2960 } 3039 // release the IPC reference from under the lock to ensure atomicity of 3040 // the "check + possible delete" sequence ("delete" is remove this wrapper 3041 // from the instance map when the IPC reference counter drops to zero) 3042 wrapper->ReleaseIPC(PR_TRUE /* locked */); 3043 // leave the lock before Release() because it may call the destructor 3044 // which will release the real object which may need to make asynchronous 3045 // use our service 3046 lock.unlock(); 3047 wrapper->Release(); 2961 3048 } 2962 3049 else 2963 3050 { 2964 3051 // it is possible that the client disconnection event handler has released 2965 // all client instances before the RELEASE message sent by the client gets 2966 // processed here. Just give a warning 2967 LOG(("ipcDConnectService::OnRelease: WARNING: instance wrapper not found")); 3052 // all client instances before the DCON_OP_RELEASE message sent by the 3053 // client gets processed here (because of true multithreading). Just log 3054 // a debug warning 3055 LOG(("ipcDConnectService::OnRelease: WARNING: " 3056 "instance wrapper %p not found", wrapper)); 2968 3057 } 2969 3058 }
Note:
See TracChangeset
for help on using the changeset viewer.