Bug 452317 - FeedConverter.js: QueryInterface should throw NS_ERROR_NO_INTERFACE...
[wine-gecko.git] / xpcom / proxy / src / nsProxyEvent.cpp
blobb6628c1efbdc567ed300f19197c0b667c89fdd62
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sw=4 sts=4 ci et: */
3 /*
5 * ***** BEGIN LICENSE BLOCK *****
6 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
8 * The contents of this file are subject to the Mozilla Public License Version
9 * 1.1 (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS" basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 * for the specific language governing rights and limitations under the
16 * License.
18 * The Original Code is mozilla.org code.
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
25 * Contributor(s):
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK *****
41 * This Original Code has been modified by IBM Corporation.
42 * Modifications made by IBM described herein are
43 * Copyright (c) International Business Machines
44 * Corporation, 2000
46 * Modifications to Mozilla code or documentation
47 * identified per MPL Section 3.3
49 * Date Modified by Description of modification
50 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
53 #include "nsProxyEventPrivate.h"
54 #include "nsProxyRelease.h"
55 #include "nsIProxyObjectManager.h"
56 #include "nsCRT.h"
58 #include "pratom.h"
59 #include "prmem.h"
60 #include "xptcall.h"
62 #include "nsAutoLock.h"
63 #include "nsXPCOMCID.h"
64 #include "nsServiceManagerUtils.h"
65 #include "nsIComponentManager.h"
66 #include "nsThreadUtils.h"
67 #include "nsEventQueue.h"
68 #include "nsMemory.h"
70 /**
71 * Map the nsAUTF8String, nsUTF8String classes to the nsACString and
72 * nsCString classes respectively for now. These defines need to be removed
73 * once Jag lands his nsUTF8String implementation.
75 #define nsAUTF8String nsACString
76 #define nsUTF8String nsCString
78 class nsProxyCallCompletedEvent : public nsRunnable
80 public:
81 nsProxyCallCompletedEvent(nsProxyObjectCallInfo *info)
82 : mInfo(info)
85 NS_DECL_NSIRUNNABLE
87 NS_IMETHOD QueryInterface(REFNSIID aIID, void **aResult);
89 private:
90 nsProxyObjectCallInfo *mInfo;
93 NS_IMETHODIMP
94 nsProxyCallCompletedEvent::Run()
96 NS_ASSERTION(mInfo, "no info");
97 mInfo->SetCompleted();
98 return NS_OK;
101 NS_DEFINE_IID(kFilterIID, NS_PROXYEVENT_FILTER_IID);
103 NS_IMETHODIMP
104 nsProxyCallCompletedEvent::QueryInterface(REFNSIID aIID, void **aResult)
106 // We are explicitly breaking XPCOM rules here by returning a different
107 // object from QueryInterface. We do this so that
108 // nsProxyThreadFilter::AcceptEvent can know whether we are an event that
109 // needs to be allowed through during a synchronous proxy call.
110 if (aIID.Equals(kFilterIID)) {
111 *aResult = mInfo;
112 mInfo->AddRef();
113 return NS_OK;
115 return nsRunnable::QueryInterface(aIID, aResult);
118 //-----------------------------------------------------------------------------
120 NS_IMETHODIMP
121 nsProxyObject::nsProxyObjectDestructorEvent::Run()
123 delete mDoomed;
124 return NS_OK;
127 //-----------------------------------------------------------------------------
129 nsProxyObjectCallInfo::nsProxyObjectCallInfo(nsProxyEventObject* owner,
130 const XPTMethodDescriptor *methodInfo,
131 PRUint32 methodIndex,
132 nsXPTCVariant* parameterList,
133 PRUint32 parameterCount) :
134 mResult(NS_ERROR_FAILURE),
135 mMethodInfo(methodInfo),
136 mMethodIndex(methodIndex),
137 mParameterList(parameterList),
138 mParameterCount(parameterCount),
139 mCompleted(0),
140 mOwner(owner)
142 NS_ASSERTION(owner, "No nsProxyObject!");
143 NS_ASSERTION(methodInfo, "No nsXPTMethodInfo!");
145 RefCountInInterfacePointers(PR_TRUE);
146 if (mOwner->GetProxyType() & NS_PROXY_ASYNC)
147 CopyStrings(PR_TRUE);
150 nsProxyObjectCallInfo::~nsProxyObjectCallInfo()
152 RefCountInInterfacePointers(PR_FALSE);
153 if (mOwner->GetProxyType() & NS_PROXY_ASYNC)
154 CopyStrings(PR_FALSE);
156 mOwner = nsnull;
158 if (mParameterList)
159 free(mParameterList);
162 NS_IMETHODIMP
163 nsProxyObjectCallInfo::QueryInterface(REFNSIID aIID, void **aResult)
165 if (aIID.Equals(kFilterIID)) {
166 *aResult = this;
167 AddRef();
168 return NS_OK;
170 return nsRunnable::QueryInterface(aIID, aResult);
173 NS_IMETHODIMP
174 nsProxyObjectCallInfo::Run()
176 PROXY_LOG(("PROXY(%p): Run\n", this));
178 mResult = NS_InvokeByIndex(mOwner->GetProxiedInterface(),
179 mMethodIndex,
180 mParameterCount,
181 mParameterList);
183 if (IsSync()) {
184 PostCompleted();
187 return NS_OK;
190 void
191 nsProxyObjectCallInfo::RefCountInInterfacePointers(PRBool addRef)
193 for (PRUint32 i = 0; i < mParameterCount; i++)
195 nsXPTParamInfo paramInfo = mMethodInfo->params[i];
197 if (paramInfo.GetType().IsInterfacePointer() )
199 nsISupports* anInterface = nsnull;
201 if (paramInfo.IsIn())
203 anInterface = ((nsISupports*)mParameterList[i].val.p);
205 if (anInterface)
207 if (addRef)
208 anInterface->AddRef();
209 else
210 anInterface->Release();
218 void
219 nsProxyObjectCallInfo::CopyStrings(PRBool copy)
221 for (PRUint32 i = 0; i < mParameterCount; i++)
223 const nsXPTParamInfo paramInfo = mMethodInfo->params[i];
225 if (paramInfo.IsIn())
227 const nsXPTType& type = paramInfo.GetType();
228 uint8 type_tag = type.TagPart();
229 void *ptr = mParameterList[i].val.p;
231 if (!ptr)
232 continue;
234 if (copy)
236 switch (type_tag)
238 case nsXPTType::T_CHAR_STR:
239 mParameterList[i].val.p =
240 PL_strdup((const char *)ptr);
241 break;
242 case nsXPTType::T_WCHAR_STR:
243 mParameterList[i].val.p =
244 nsCRT::strdup((const PRUnichar *)ptr);
245 break;
246 case nsXPTType::T_DOMSTRING:
247 case nsXPTType::T_ASTRING:
248 mParameterList[i].val.p =
249 new nsString(*((nsAString*) ptr));
250 break;
251 case nsXPTType::T_CSTRING:
252 mParameterList[i].val.p =
253 new nsCString(*((nsACString*) ptr));
254 break;
255 case nsXPTType::T_UTF8STRING:
256 mParameterList[i].val.p =
257 new nsUTF8String(*((nsAUTF8String*) ptr));
258 break;
259 default:
260 // Other types are ignored
261 break;
264 else
266 switch (type_tag)
268 case nsXPTType::T_CHAR_STR:
269 PL_strfree((char*) ptr);
270 break;
271 case nsXPTType::T_WCHAR_STR:
272 nsCRT::free((PRUnichar*)ptr);
273 break;
274 case nsXPTType::T_DOMSTRING:
275 case nsXPTType::T_ASTRING:
276 delete (nsString*) ptr;
277 break;
278 case nsXPTType::T_CSTRING:
279 delete (nsCString*) ptr;
280 break;
281 case nsXPTType::T_UTF8STRING:
282 delete (nsUTF8String*) ptr;
283 break;
284 default:
285 // Other types are ignored
286 break;
293 PRBool
294 nsProxyObjectCallInfo::GetCompleted()
296 return !!mCompleted;
299 void
300 nsProxyObjectCallInfo::SetCompleted()
302 PROXY_LOG(("PROXY(%p): SetCompleted\n", this));
303 PR_AtomicSet(&mCompleted, 1);
306 void
307 nsProxyObjectCallInfo::PostCompleted()
309 PROXY_LOG(("PROXY(%p): PostCompleted\n", this));
311 if (mCallersTarget) {
312 nsCOMPtr<nsIRunnable> event =
313 new nsProxyCallCompletedEvent(this);
314 if (event &&
315 NS_SUCCEEDED(mCallersTarget->Dispatch(event, NS_DISPATCH_NORMAL)))
316 return;
319 // OOM? caller does not have a target? This is an error!
320 NS_WARNING("Failed to dispatch nsProxyCallCompletedEvent");
321 SetCompleted();
324 nsIEventTarget*
325 nsProxyObjectCallInfo::GetCallersTarget()
327 return mCallersTarget;
330 void
331 nsProxyObjectCallInfo::SetCallersTarget(nsIEventTarget* target)
333 mCallersTarget = target;
336 nsProxyObject::nsProxyObject(nsIEventTarget *target, PRInt32 proxyType,
337 nsISupports *realObject) :
338 mProxyType(proxyType),
339 mTarget(target),
340 mRealObject(realObject),
341 mFirst(nsnull)
343 MOZ_COUNT_CTOR(nsProxyObject);
345 #ifdef DEBUG
346 nsCOMPtr<nsISupports> canonicalTarget = do_QueryInterface(target);
347 NS_ASSERTION(target == canonicalTarget,
348 "Non-canonical nsISupports passed to nsProxyObject constructor");
349 #endif
351 nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance();
352 NS_ASSERTION(pom, "Creating a proxy without a global proxy-object-manager.");
353 pom->AddRef();
356 nsProxyObject::~nsProxyObject()
358 // Proxy the release of mRealObject to protect against it being deleted on
359 // the wrong thread.
360 nsISupports *doomed = nsnull;
361 mRealObject.swap(doomed);
362 NS_ProxyRelease(mTarget, doomed);
364 MOZ_COUNT_DTOR(nsProxyObject);
367 NS_IMETHODIMP_(nsrefcnt)
368 nsProxyObject::AddRef()
370 nsAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
371 return LockedAddRef();
374 NS_IMETHODIMP_(nsrefcnt)
375 nsProxyObject::Release()
377 nsAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
378 return LockedRelease();
381 nsrefcnt
382 nsProxyObject::LockedAddRef()
384 ++mRefCnt;
385 NS_LOG_ADDREF(this, mRefCnt, "nsProxyObject", sizeof(nsProxyObject));
386 return mRefCnt;
389 nsrefcnt
390 nsProxyObject::LockedRelease()
392 NS_PRECONDITION(0 != mRefCnt, "dup release");
393 --mRefCnt;
394 NS_LOG_RELEASE(this, mRefCnt, "nsProxyObject");
395 if (mRefCnt)
396 return mRefCnt;
398 nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance();
399 pom->LockedRemove(this);
401 nsAutoUnlock unlock(pom->GetLock());
402 delete this;
403 pom->Release();
405 return 0;
408 NS_IMETHODIMP
409 nsProxyObject::QueryInterface(REFNSIID aIID, void **aResult)
411 if (aIID.Equals(GetIID())) {
412 *aResult = this;
413 AddRef();
414 return NS_OK;
417 if (aIID.Equals(NS_GET_IID(nsISupports))) {
418 *aResult = static_cast<nsISupports*>(this);
419 AddRef();
420 return NS_OK;
423 nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance();
424 NS_ASSERTION(pom, "Deleting a proxy without a global proxy-object-manager.");
426 nsAutoLock lock(pom->GetLock());
427 return LockedFind(aIID, aResult);
430 nsresult
431 nsProxyObject::LockedFind(REFNSIID aIID, void **aResult)
433 // This method is only called when the global lock is held.
434 // XXX assert this
436 nsProxyEventObject *peo;
438 for (peo = mFirst; peo; peo = peo->mNext) {
439 if (peo->GetClass()->GetProxiedIID().Equals(aIID)) {
440 *aResult = static_cast<nsISupports*>(peo->mXPTCStub);
441 peo->LockedAddRef();
442 return NS_OK;
446 nsProxyEventObject *newpeo;
448 // Both GetClass and QueryInterface call out to XPCOM, so we unlock for them
450 nsProxyObjectManager* pom = nsProxyObjectManager::GetInstance();
451 nsAutoUnlock unlock(pom->GetLock());
453 nsProxyEventClass *pec;
454 nsresult rv = pom->GetClass(aIID, &pec);
455 if (NS_FAILED(rv))
456 return rv;
458 nsISomeInterface* newInterface;
459 rv = mRealObject->QueryInterface(aIID, (void**) &newInterface);
460 if (NS_FAILED(rv))
461 return rv;
463 newpeo = new nsProxyEventObject(this, pec,
464 already_AddRefed<nsISomeInterface>(newInterface), &rv);
465 if (!newpeo) {
466 NS_RELEASE(newInterface);
467 return NS_ERROR_OUT_OF_MEMORY;
470 if (NS_FAILED(rv)) {
471 delete newpeo;
472 return rv;
476 // Now that we're locked again, check for races by repeating the
477 // linked-list check.
478 for (peo = mFirst; peo; peo = peo->mNext) {
479 if (peo->GetClass()->GetProxiedIID().Equals(aIID)) {
480 delete newpeo;
481 *aResult = static_cast<nsISupports*>(peo->mXPTCStub);
482 peo->LockedAddRef();
483 return NS_OK;
487 newpeo->mNext = mFirst;
488 mFirst = newpeo;
490 newpeo->LockedAddRef();
492 *aResult = static_cast<nsISupports*>(newpeo->mXPTCStub);
493 return NS_OK;
496 void
497 nsProxyObject::LockedRemove(nsProxyEventObject *peo)
499 nsProxyEventObject **i;
500 for (i = &mFirst; *i; i = &((*i)->mNext)) {
501 if (*i == peo) {
502 *i = peo->mNext;
503 return;
506 NS_ERROR("Didn't find nsProxyEventObject in nsProxyObject chain!");