Bug 1434822 part 2: mscom: Add a function to disconnect all remote clients associated with a given target. r=aklotz

Because Interceptors disable COM garbage collection to improve performance, they never receive Release calls from remote clients.
If the object can be shut down while clients still hold a reference, this function can be used to force COM to disconnect all remote connections (using CoDisconnectObject) and thus release the associated references to the Interceptor, its target and any objects associated with the HandlerProvider.
A HandlerProvider::DisconnectHandlerRemotes method also had to be added to allow HandlerProviders to disconnect clients for their own objects.

MozReview-Commit-ID: JaxEkOtrP1M

--HG--
extra : rebase_source : 2262af8fc3cb1aec8d9c8fc2762f3d61e188cb37
This commit is contained in:
James Teh 2018-02-19 16:08:57 +10:00
parent 5f27445039
commit 6fc08ce5ed
5 changed files with 58 additions and 0 deletions

View File

@ -23,6 +23,7 @@ struct HandlerProvider
virtual STDMETHODIMP GetHandlerPayloadSize(NotNull<IInterceptor*> aInterceptor, NotNull<DWORD*> aOutPayloadSize) = 0;
virtual STDMETHODIMP WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor, NotNull<IStream*> aStream) = 0;
virtual STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) = 0;
virtual STDMETHODIMP DisconnectHandlerRemotes() = 0;
};
struct IHandlerProvider : public IUnknown

View File

@ -428,6 +428,7 @@ Interceptor::ReleaseMarshalData(IStream* pStm)
HRESULT
Interceptor::DisconnectObject(DWORD dwReserved)
{
mEventSink->DisconnectHandlerRemotes();
return mStdMarshal->DisconnectObject(dwReserved);
}
@ -830,5 +831,30 @@ Interceptor::Release()
return WeakReferenceSupport::Release();
}
/* static */ HRESULT
Interceptor::DisconnectRemotesForTarget(IUnknown* aTarget)
{
MOZ_ASSERT(aTarget);
detail::LiveSetAutoLock lock(GetLiveSet());
// It is not an error if the interceptor doesn't exist, so we return
// S_FALSE instead of an error in that case.
RefPtr<IWeakReference> existingWeak(Move(GetLiveSet().Get(aTarget)));
if (!existingWeak) {
return S_FALSE;
}
RefPtr<IWeakReferenceSource> existingStrong;
if (FAILED(existingWeak->ToStrongRef(getter_AddRefs(existingStrong)))) {
return S_FALSE;
}
// Since we now hold a strong ref on the interceptor, we may now release the
// lock.
lock.Unlock();
return ::CoDisconnectObject(existingStrong, 0);
}
} // namespace mscom
} // namespace mozilla

View File

@ -74,6 +74,26 @@ public:
static HRESULT Create(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink,
REFIID aInitialIid, void** aOutInterface);
/**
* Disconnect all remote clients for a given target.
* Because Interceptors disable COM garbage collection to improve
* performance, they never receive Release calls from remote clients. If
* the object can be shut down while clients still hold a reference, this
* function can be used to force COM to disconnect all remote connections
* (using CoDisconnectObject) and thus release the associated references to
* the Interceptor, its target and any objects associated with the
* HandlerProvider.
* Note that the specified target must be the same IUnknown pointer used to
* create the Interceptor. Where there is multiple inheritance, querying for
* IID_IUnknown and calling this function with that pointer alone will not
* disconnect remotes for all interfaces. If you expect that the same object
* may be fetched with different initial interfaces, you should call this
* function once for each possible IUnknown pointer.
* @return S_OK if there was an Interceptor for the given target,
* S_FALSE if there was not.
*/
static HRESULT DisconnectRemotesForTarget(IUnknown* aTarget);
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
STDMETHODIMP_(ULONG) AddRef() override;

View File

@ -589,6 +589,16 @@ MainThreadHandoff::MarshalAs(REFIID aIid)
return mHandlerProvider->MarshalAs(aIid);
}
HRESULT
MainThreadHandoff::DisconnectHandlerRemotes()
{
if (!mHandlerProvider) {
return E_NOTIMPL;
}
return mHandlerProvider->DisconnectHandlerRemotes();
}
HRESULT
MainThreadHandoff::OnWalkInterface(REFIID aIid, PVOID* aInterface,
BOOL aIsInParam, BOOL aIsOutParam)

View File

@ -66,6 +66,7 @@ public:
STDMETHODIMP WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor,
NotNull<IStream*> aStream) override;
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
STDMETHODIMP DisconnectHandlerRemotes() override;
// ICallFrameWalker
STDMETHODIMP OnWalkInterface(REFIID aIid, PVOID* aInterface, BOOL aIsInParam,