зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
5f27445039
Коммит
6fc08ce5ed
|
@ -23,6 +23,7 @@ struct HandlerProvider
|
||||||
virtual STDMETHODIMP GetHandlerPayloadSize(NotNull<IInterceptor*> aInterceptor, NotNull<DWORD*> aOutPayloadSize) = 0;
|
virtual STDMETHODIMP GetHandlerPayloadSize(NotNull<IInterceptor*> aInterceptor, NotNull<DWORD*> aOutPayloadSize) = 0;
|
||||||
virtual STDMETHODIMP WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor, NotNull<IStream*> aStream) = 0;
|
virtual STDMETHODIMP WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor, NotNull<IStream*> aStream) = 0;
|
||||||
virtual STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) = 0;
|
virtual STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) = 0;
|
||||||
|
virtual STDMETHODIMP DisconnectHandlerRemotes() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IHandlerProvider : public IUnknown
|
struct IHandlerProvider : public IUnknown
|
||||||
|
|
|
@ -428,6 +428,7 @@ Interceptor::ReleaseMarshalData(IStream* pStm)
|
||||||
HRESULT
|
HRESULT
|
||||||
Interceptor::DisconnectObject(DWORD dwReserved)
|
Interceptor::DisconnectObject(DWORD dwReserved)
|
||||||
{
|
{
|
||||||
|
mEventSink->DisconnectHandlerRemotes();
|
||||||
return mStdMarshal->DisconnectObject(dwReserved);
|
return mStdMarshal->DisconnectObject(dwReserved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,5 +831,30 @@ Interceptor::Release()
|
||||||
return WeakReferenceSupport::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 mscom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -74,6 +74,26 @@ public:
|
||||||
static HRESULT Create(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink,
|
static HRESULT Create(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink,
|
||||||
REFIID aInitialIid, void** aOutInterface);
|
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
|
// IUnknown
|
||||||
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
|
||||||
STDMETHODIMP_(ULONG) AddRef() override;
|
STDMETHODIMP_(ULONG) AddRef() override;
|
||||||
|
|
|
@ -589,6 +589,16 @@ MainThreadHandoff::MarshalAs(REFIID aIid)
|
||||||
return mHandlerProvider->MarshalAs(aIid);
|
return mHandlerProvider->MarshalAs(aIid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT
|
||||||
|
MainThreadHandoff::DisconnectHandlerRemotes()
|
||||||
|
{
|
||||||
|
if (!mHandlerProvider) {
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mHandlerProvider->DisconnectHandlerRemotes();
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT
|
HRESULT
|
||||||
MainThreadHandoff::OnWalkInterface(REFIID aIid, PVOID* aInterface,
|
MainThreadHandoff::OnWalkInterface(REFIID aIid, PVOID* aInterface,
|
||||||
BOOL aIsInParam, BOOL aIsOutParam)
|
BOOL aIsInParam, BOOL aIsOutParam)
|
||||||
|
|
|
@ -66,6 +66,7 @@ public:
|
||||||
STDMETHODIMP WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor,
|
STDMETHODIMP WriteHandlerPayload(NotNull<IInterceptor*> aInterceptor,
|
||||||
NotNull<IStream*> aStream) override;
|
NotNull<IStream*> aStream) override;
|
||||||
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
|
STDMETHODIMP_(REFIID) MarshalAs(REFIID aIid) override;
|
||||||
|
STDMETHODIMP DisconnectHandlerRemotes() override;
|
||||||
|
|
||||||
// ICallFrameWalker
|
// ICallFrameWalker
|
||||||
STDMETHODIMP OnWalkInterface(REFIID aIid, PVOID* aInterface, BOOL aIsInParam,
|
STDMETHODIMP OnWalkInterface(REFIID aIid, PVOID* aInterface, BOOL aIsInParam,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче