Bug 452317 - FeedConverter.js: QueryInterface should throw NS_ERROR_NO_INTERFACE...
[wine-gecko.git] / xpcom / proxy / src / nsProxyEventObject.cpp
blob7dab1773c802401fa0aff37f198d564361661165
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Pierre Phaneuf <pp@ludusdesign.com>
24 * Benjamin Smedberg <benjamin@smedbergs.us>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "prprf.h"
41 #include "prmem.h"
43 #include "nscore.h"
44 #include "nsProxyEventPrivate.h"
45 #include "nsIThreadInternal.h"
47 #include "nsServiceManagerUtils.h"
49 #include "nsHashtable.h"
51 #include "nsIInterfaceInfoManager.h"
52 #include "xptcall.h"
54 #include "nsAutoLock.h"
56 nsProxyEventObject::nsProxyEventObject(nsProxyObject *aParent,
57 nsProxyEventClass* aClass,
58 already_AddRefed<nsISomeInterface> aRealInterface,
59 nsresult *rv)
60 : mClass(aClass),
61 mProxyObject(aParent),
62 mRealInterface(aRealInterface),
63 mNext(nsnull)
65 *rv = InitStub(aClass->GetProxiedIID());
68 nsProxyEventObject::~nsProxyEventObject()
70 // This destructor must *not* be called within the POM lock
71 // XXX assert this!
73 // mRealInterface must be released before mProxyObject so that the last
74 // release of the proxied object is proxied to the correct thread.
75 // See bug 337492.
76 mRealInterface = nsnull;
80 // nsISupports implementation...
83 NS_IMETHODIMP_(nsrefcnt)
84 nsProxyEventObject::AddRef()
86 nsAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
87 return LockedAddRef();
90 nsrefcnt
91 nsProxyEventObject::LockedAddRef()
93 ++mRefCnt;
94 NS_LOG_ADDREF(this, mRefCnt, "nsProxyEventObject", sizeof(nsProxyEventObject));
95 return mRefCnt;
98 NS_IMETHODIMP_(nsrefcnt)
99 nsProxyEventObject::Release(void)
102 nsAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
103 NS_PRECONDITION(0 != mRefCnt, "dup release");
105 --mRefCnt;
106 NS_LOG_RELEASE(this, mRefCnt, "nsProxyEventObject");
108 if (mRefCnt)
109 return mRefCnt;
111 mProxyObject->LockedRemove(this);
114 // call the destructor outside of the lock so that we aren't holding the
115 // lock when we release the object
116 NS_DELETEXPCOM(this);
117 return 0;
120 NS_IMETHODIMP
121 nsProxyEventObject::QueryInterface(REFNSIID aIID, void** aInstancePtr)
123 if( aIID.Equals(GetClass()->GetProxiedIID()) )
125 *aInstancePtr = static_cast<nsISupports*>(mXPTCStub);
126 NS_ADDREF_THIS();
127 return NS_OK;
130 return mProxyObject->QueryInterface(aIID, aInstancePtr);
134 // nsXPTCStubBase implementation...
137 nsresult
138 nsProxyEventObject::convertMiniVariantToVariant(const XPTMethodDescriptor *methodInfo,
139 nsXPTCMiniVariant * params,
140 nsXPTCVariant **fullParam,
141 uint8 *outParamCount)
143 uint8 paramCount = methodInfo->num_args;
144 *outParamCount = paramCount;
145 *fullParam = nsnull;
147 if (!paramCount) return NS_OK;
149 *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount);
151 if (*fullParam == nsnull)
152 return NS_ERROR_OUT_OF_MEMORY;
154 for (int i = 0; i < paramCount; i++)
156 const nsXPTParamInfo& paramInfo = methodInfo->params[i];
157 if ((GetProxyType() & NS_PROXY_ASYNC) &&
158 (paramInfo.IsOut() || paramInfo.IsDipper()))
160 NS_WARNING("Async proxying of out parameters is not supported");
161 free(*fullParam);
162 return NS_ERROR_PROXY_INVALID_OUT_PARAMETER;
164 uint8 flags = paramInfo.IsOut() ? nsXPTCVariant::PTR_IS_DATA : 0;
165 (*fullParam)[i].Init(params[i], paramInfo.GetType(), flags);
168 return NS_OK;
171 class nsProxyThreadFilter : public nsIThreadEventFilter
173 public:
174 NS_DECL_ISUPPORTS
175 NS_DECL_NSITHREADEVENTFILTER
178 NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyThreadFilter, nsIThreadEventFilter)
180 NS_DEFINE_IID(kFilterIID, NS_PROXYEVENT_FILTER_IID);
182 NS_IMETHODIMP_(PRBool)
183 nsProxyThreadFilter::AcceptEvent(nsIRunnable *event)
185 PROXY_LOG(("PROXY(%p): filter event [%p]\n", this, event));
187 // If we encounter one of our proxy events that is for a synchronous method
188 // call, then we want to put it in our event queue for processing. Else,
189 // we want to allow the event to be dispatched to the thread's event queue
190 // for processing later once we complete the current sync method call.
192 nsRefPtr<nsProxyObjectCallInfo> poci;
193 event->QueryInterface(kFilterIID, getter_AddRefs(poci));
194 return poci && poci->IsSync();
197 NS_IMETHODIMP
198 nsProxyEventObject::CallMethod(PRUint16 methodIndex,
199 const XPTMethodDescriptor* methodInfo,
200 nsXPTCMiniVariant * params)
202 NS_ASSERTION(methodIndex > 2,
203 "Calling QI/AddRef/Release through CallMethod");
204 nsresult rv;
206 if (XPT_MD_IS_NOTXPCOM(methodInfo->flags))
207 return NS_ERROR_PROXY_INVALID_IN_PARAMETER;
209 nsXPTCVariant *fullParam;
210 uint8 paramCount;
211 rv = convertMiniVariantToVariant(methodInfo, params,
212 &fullParam, &paramCount);
213 if (NS_FAILED(rv))
214 return rv;
216 PRBool callDirectly = PR_FALSE;
217 if (GetProxyType() & NS_PROXY_SYNC &&
218 NS_SUCCEEDED(GetTarget()->IsOnCurrentThread(&callDirectly)) &&
219 callDirectly) {
221 // invoke directly using xptc
222 rv = NS_InvokeByIndex(mRealInterface, methodIndex,
223 paramCount, fullParam);
225 if (fullParam)
226 free(fullParam);
228 return rv;
231 nsRefPtr<nsProxyObjectCallInfo> proxyInfo =
232 new nsProxyObjectCallInfo(this, methodInfo, methodIndex,
233 fullParam, paramCount);
234 if (!proxyInfo)
235 return NS_ERROR_OUT_OF_MEMORY;
237 if (! (GetProxyType() & NS_PROXY_SYNC)) {
238 return GetTarget()->Dispatch(proxyInfo, NS_DISPATCH_NORMAL);
241 // Post synchronously
243 nsIThread *thread = NS_GetCurrentThread();
244 nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(thread);
245 NS_ENSURE_STATE(threadInt);
247 // Install thread filter to limit event processing only to
248 // nsProxyObjectCallInfo instances. XXX Add support for sequencing?
249 nsRefPtr<nsProxyThreadFilter> filter = new nsProxyThreadFilter();
250 if (!filter)
251 return NS_ERROR_OUT_OF_MEMORY;
252 threadInt->PushEventQueue(filter);
254 proxyInfo->SetCallersTarget(thread);
256 // Dispatch can fail if the thread is shutting down
257 rv = GetTarget()->Dispatch(proxyInfo, NS_DISPATCH_NORMAL);
258 if (NS_SUCCEEDED(rv)) {
259 while (!proxyInfo->GetCompleted()) {
260 if (!NS_ProcessNextEvent(thread)) {
261 rv = NS_ERROR_UNEXPECTED;
262 break;
265 rv = proxyInfo->GetResult();
266 } else {
267 NS_WARNING("Failed to dispatch nsProxyCallEvent");
270 threadInt->PopEventQueue();
272 PROXY_LOG(("PROXY(%p): PostAndWait exit [%p %x]\n", this, proxyInfo.get(), rv));
273 return rv;