Bug 1467936 [wpt PR 11436] - Split up editing/run/* with `variant`, a=testonly
[gecko.git] / ipc / mscom / Interceptor.h
blobc5dc1d50e60f6cf18495e5ce32ae5b9ffc7fbf0b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_mscom_Interceptor_h
8 #define mozilla_mscom_Interceptor_h
10 #include "mozilla/Move.h"
11 #include "mozilla/Mutex.h"
12 #include "nsTArray.h"
13 #include "mozilla/mscom/IHandlerProvider.h"
14 #include "mozilla/mscom/Ptr.h"
15 #include "mozilla/mscom/WeakRef.h"
16 #include "mozilla/RefPtr.h"
18 #include <objidl.h>
19 #include <callobj.h>
21 namespace mozilla {
22 namespace mscom {
23 namespace detail {
25 class LiveSetAutoLock;
27 } // namespace detail
29 // {8831EB53-A937-42BC-9921-B3E1121FDF86}
30 DEFINE_GUID(IID_IInterceptorSink,
31 0x8831eb53, 0xa937, 0x42bc, 0x99, 0x21, 0xb3, 0xe1, 0x12, 0x1f, 0xdf, 0x86);
33 struct IInterceptorSink : public ICallFrameEvents
34 , public HandlerProvider
36 virtual STDMETHODIMP SetInterceptor(IWeakReference* aInterceptor) = 0;
39 // {3710799B-ECA2-4165-B9B0-3FA1E4A9B230}
40 DEFINE_GUID(IID_IInterceptor,
41 0x3710799b, 0xeca2, 0x4165, 0xb9, 0xb0, 0x3f, 0xa1, 0xe4, 0xa9, 0xb2, 0x30);
43 struct IInterceptor : public IUnknown
45 virtual STDMETHODIMP GetTargetForIID(REFIID aIid,
46 InterceptorTargetPtr<IUnknown>& aTarget) = 0;
47 virtual STDMETHODIMP GetInterceptorForIID(REFIID aIid,
48 void** aOutInterceptor) = 0;
51 /**
52 * The COM interceptor is the core functionality in mscom that allows us to
53 * redirect method calls to different threads. It emulates the vtable of a
54 * target interface. When a call is made on this emulated vtable, the call is
55 * packaged up into an instance of the ICallFrame interface which may be passed
56 * to other contexts for execution.
58 * In order to accomplish this, COM itself provides the CoGetInterceptor
59 * function, which instantiates an ICallInterceptor. Note, however, that
60 * ICallInterceptor only works on a single interface; we need to be able to
61 * interpose QueryInterface calls so that we can instantiate a new
62 * ICallInterceptor for each new interface that is requested.
64 * We accomplish this by using COM aggregation, which means that the
65 * ICallInterceptor delegates its IUnknown implementation to its outer object
66 * (the mscom::Interceptor we implement and control).
68 class Interceptor final : public WeakReferenceSupport
69 , public IStdMarshalInfo
70 , public IMarshal
71 , public IInterceptor
73 public:
74 static HRESULT Create(STAUniquePtr<IUnknown> aTarget, IInterceptorSink* aSink,
75 REFIID aInitialIid, void** aOutInterface);
77 /**
78 * Disconnect all remote clients for a given target.
79 * Because Interceptors disable COM garbage collection to improve
80 * performance, they never receive Release calls from remote clients. If
81 * the object can be shut down while clients still hold a reference, this
82 * function can be used to force COM to disconnect all remote connections
83 * (using CoDisconnectObject) and thus release the associated references to
84 * the Interceptor, its target and any objects associated with the
85 * HandlerProvider.
86 * Note that the specified target must be the same IUnknown pointer used to
87 * create the Interceptor. Where there is multiple inheritance, querying for
88 * IID_IUnknown and calling this function with that pointer alone will not
89 * disconnect remotes for all interfaces. If you expect that the same object
90 * may be fetched with different initial interfaces, you should call this
91 * function once for each possible IUnknown pointer.
92 * @return S_OK if there was an Interceptor for the given target,
93 * S_FALSE if there was not.
95 static HRESULT DisconnectRemotesForTarget(IUnknown* aTarget);
97 // IUnknown
98 STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
99 STDMETHODIMP_(ULONG) AddRef() override;
100 STDMETHODIMP_(ULONG) Release() override;
102 // IStdMarshalInfo
103 STDMETHODIMP GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
104 CLSID* aHandlerClsid) override;
106 // IMarshal
107 STDMETHODIMP GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext,
108 void* pvDestContext, DWORD mshlflags,
109 CLSID* pCid) override;
110 STDMETHODIMP GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
111 void* pvDestContext, DWORD mshlflags,
112 DWORD* pSize) override;
113 STDMETHODIMP MarshalInterface(IStream* pStm, REFIID riid, void* pv,
114 DWORD dwDestContext, void* pvDestContext,
115 DWORD mshlflags) override;
116 STDMETHODIMP UnmarshalInterface(IStream* pStm, REFIID riid,
117 void** ppv) override;
118 STDMETHODIMP ReleaseMarshalData(IStream* pStm) override;
119 STDMETHODIMP DisconnectObject(DWORD dwReserved) override;
121 // IInterceptor
122 STDMETHODIMP GetTargetForIID(REFIID aIid,
123 InterceptorTargetPtr<IUnknown>& aTarget) override;
124 STDMETHODIMP GetInterceptorForIID(REFIID aIid, void** aOutInterceptor) override;
126 private:
127 struct MapEntry
129 MapEntry(REFIID aIid, IUnknown* aInterceptor, IUnknown* aTargetInterface)
130 : mIID(aIid)
131 , mInterceptor(aInterceptor)
132 , mTargetInterface(aTargetInterface)
135 IID mIID;
136 RefPtr<IUnknown> mInterceptor;
137 IUnknown* mTargetInterface;
140 private:
141 explicit Interceptor(IInterceptorSink* aSink);
142 ~Interceptor();
143 HRESULT GetInitialInterceptorForIID(detail::LiveSetAutoLock& aLiveSetLock,
144 REFIID aTargetIid,
145 STAUniquePtr<IUnknown> aTarget,
146 void** aOutInterface);
147 HRESULT GetInterceptorForIID(REFIID aIid, void** aOutInterceptor,
148 MutexAutoLock* aAlreadyLocked);
149 MapEntry* Lookup(REFIID aIid);
150 HRESULT QueryInterfaceTarget(REFIID aIid, void** aOutput,
151 TimeDuration* aOutDuration = nullptr);
152 HRESULT WeakRefQueryInterface(REFIID aIid,
153 IUnknown** aOutInterface) override;
154 HRESULT CreateInterceptor(REFIID aIid, IUnknown* aOuter, IUnknown** aOutput);
155 REFIID MarshalAs(REFIID aIid) const;
156 HRESULT PublishTarget(detail::LiveSetAutoLock& aLiveSetLock,
157 RefPtr<IUnknown> aInterceptor,
158 REFIID aTargetIid,
159 STAUniquePtr<IUnknown> aTarget);
161 private:
162 InterceptorTargetPtr<IUnknown> mTarget;
163 RefPtr<IInterceptorSink> mEventSink;
164 mozilla::Mutex mInterceptorMapMutex; // Guards mInterceptorMap
165 // Using a nsTArray since the # of interfaces is not going to be very high
166 nsTArray<MapEntry> mInterceptorMap;
167 mozilla::Mutex mStdMarshalMutex; // Guards mStdMarshalUnk and mStdMarshal
168 RefPtr<IUnknown> mStdMarshalUnk;
169 IMarshal* mStdMarshal; // WEAK
170 static MOZ_THREAD_LOCAL(bool) tlsCreatingStdMarshal;
173 template <typename InterfaceT>
174 inline HRESULT
175 CreateInterceptor(STAUniquePtr<InterfaceT> aTargetInterface,
176 IInterceptorSink* aEventSink,
177 InterfaceT** aOutInterface)
179 if (!aTargetInterface || !aEventSink) {
180 return E_INVALIDARG;
183 REFIID iidTarget = __uuidof(InterfaceT);
185 STAUniquePtr<IUnknown> targetUnknown(aTargetInterface.release());
186 return Interceptor::Create(std::move(targetUnknown), aEventSink, iidTarget,
187 (void**)aOutInterface);
190 } // namespace mscom
191 } // namespace mozilla
193 #endif // mozilla_mscom_Interceptor_h