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: */
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
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.
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
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"
62 #include "nsAutoLock.h"
63 #include "nsXPCOMCID.h"
64 #include "nsServiceManagerUtils.h"
65 #include "nsIComponentManager.h"
66 #include "nsThreadUtils.h"
67 #include "nsEventQueue.h"
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
81 nsProxyCallCompletedEvent(nsProxyObjectCallInfo
*info
)
87 NS_IMETHOD
QueryInterface(REFNSIID aIID
, void **aResult
);
90 nsProxyObjectCallInfo
*mInfo
;
94 nsProxyCallCompletedEvent::Run()
96 NS_ASSERTION(mInfo
, "no info");
97 mInfo
->SetCompleted();
101 NS_DEFINE_IID(kFilterIID
, NS_PROXYEVENT_FILTER_IID
);
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
)) {
115 return nsRunnable::QueryInterface(aIID
, aResult
);
118 //-----------------------------------------------------------------------------
121 nsProxyObject::nsProxyObjectDestructorEvent::Run()
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
),
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
);
159 free(mParameterList
);
163 nsProxyObjectCallInfo::QueryInterface(REFNSIID aIID
, void **aResult
)
165 if (aIID
.Equals(kFilterIID
)) {
170 return nsRunnable::QueryInterface(aIID
, aResult
);
174 nsProxyObjectCallInfo::Run()
176 PROXY_LOG(("PROXY(%p): Run\n", this));
178 mResult
= NS_InvokeByIndex(mOwner
->GetProxiedInterface(),
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
);
208 anInterface
->AddRef();
210 anInterface
->Release();
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
;
238 case nsXPTType::T_CHAR_STR
:
239 mParameterList
[i
].val
.p
=
240 PL_strdup((const char *)ptr
);
242 case nsXPTType::T_WCHAR_STR
:
243 mParameterList
[i
].val
.p
=
244 nsCRT::strdup((const PRUnichar
*)ptr
);
246 case nsXPTType::T_DOMSTRING
:
247 case nsXPTType::T_ASTRING
:
248 mParameterList
[i
].val
.p
=
249 new nsString(*((nsAString
*) ptr
));
251 case nsXPTType::T_CSTRING
:
252 mParameterList
[i
].val
.p
=
253 new nsCString(*((nsACString
*) ptr
));
255 case nsXPTType::T_UTF8STRING
:
256 mParameterList
[i
].val
.p
=
257 new nsUTF8String(*((nsAUTF8String
*) ptr
));
260 // Other types are ignored
268 case nsXPTType::T_CHAR_STR
:
269 PL_strfree((char*) ptr
);
271 case nsXPTType::T_WCHAR_STR
:
272 nsCRT::free((PRUnichar
*)ptr
);
274 case nsXPTType::T_DOMSTRING
:
275 case nsXPTType::T_ASTRING
:
276 delete (nsString
*) ptr
;
278 case nsXPTType::T_CSTRING
:
279 delete (nsCString
*) ptr
;
281 case nsXPTType::T_UTF8STRING
:
282 delete (nsUTF8String
*) ptr
;
285 // Other types are ignored
294 nsProxyObjectCallInfo::GetCompleted()
300 nsProxyObjectCallInfo::SetCompleted()
302 PROXY_LOG(("PROXY(%p): SetCompleted\n", this));
303 PR_AtomicSet(&mCompleted
, 1);
307 nsProxyObjectCallInfo::PostCompleted()
309 PROXY_LOG(("PROXY(%p): PostCompleted\n", this));
311 if (mCallersTarget
) {
312 nsCOMPtr
<nsIRunnable
> event
=
313 new nsProxyCallCompletedEvent(this);
315 NS_SUCCEEDED(mCallersTarget
->Dispatch(event
, NS_DISPATCH_NORMAL
)))
319 // OOM? caller does not have a target? This is an error!
320 NS_WARNING("Failed to dispatch nsProxyCallCompletedEvent");
325 nsProxyObjectCallInfo::GetCallersTarget()
327 return mCallersTarget
;
331 nsProxyObjectCallInfo::SetCallersTarget(nsIEventTarget
* target
)
333 mCallersTarget
= target
;
336 nsProxyObject::nsProxyObject(nsIEventTarget
*target
, PRInt32 proxyType
,
337 nsISupports
*realObject
) :
338 mProxyType(proxyType
),
340 mRealObject(realObject
),
343 MOZ_COUNT_CTOR(nsProxyObject
);
346 nsCOMPtr
<nsISupports
> canonicalTarget
= do_QueryInterface(target
);
347 NS_ASSERTION(target
== canonicalTarget
,
348 "Non-canonical nsISupports passed to nsProxyObject constructor");
351 nsProxyObjectManager
*pom
= nsProxyObjectManager::GetInstance();
352 NS_ASSERTION(pom
, "Creating a proxy without a global proxy-object-manager.");
356 nsProxyObject::~nsProxyObject()
358 // Proxy the release of mRealObject to protect against it being deleted on
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();
382 nsProxyObject::LockedAddRef()
385 NS_LOG_ADDREF(this, mRefCnt
, "nsProxyObject", sizeof(nsProxyObject
));
390 nsProxyObject::LockedRelease()
392 NS_PRECONDITION(0 != mRefCnt
, "dup release");
394 NS_LOG_RELEASE(this, mRefCnt
, "nsProxyObject");
398 nsProxyObjectManager
*pom
= nsProxyObjectManager::GetInstance();
399 pom
->LockedRemove(this);
401 nsAutoUnlock
unlock(pom
->GetLock());
409 nsProxyObject::QueryInterface(REFNSIID aIID
, void **aResult
)
411 if (aIID
.Equals(GetIID())) {
417 if (aIID
.Equals(NS_GET_IID(nsISupports
))) {
418 *aResult
= static_cast<nsISupports
*>(this);
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
);
431 nsProxyObject::LockedFind(REFNSIID aIID
, void **aResult
)
433 // This method is only called when the global lock is held.
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
);
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
);
458 nsISomeInterface
* newInterface
;
459 rv
= mRealObject
->QueryInterface(aIID
, (void**) &newInterface
);
463 newpeo
= new nsProxyEventObject(this, pec
,
464 already_AddRefed
<nsISomeInterface
>(newInterface
), &rv
);
466 NS_RELEASE(newInterface
);
467 return NS_ERROR_OUT_OF_MEMORY
;
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
)) {
481 *aResult
= static_cast<nsISupports
*>(peo
->mXPTCStub
);
487 newpeo
->mNext
= mFirst
;
490 newpeo
->LockedAddRef();
492 *aResult
= static_cast<nsISupports
*>(newpeo
->mXPTCStub
);
497 nsProxyObject::LockedRemove(nsProxyEventObject
*peo
)
499 nsProxyEventObject
**i
;
500 for (i
= &mFirst
; *i
; i
= &((*i
)->mNext
)) {
506 NS_ERROR("Didn't find nsProxyEventObject in nsProxyObject chain!");