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
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.
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 ***** */
44 #include "nsProxyEventPrivate.h"
45 #include "nsIThreadInternal.h"
47 #include "nsServiceManagerUtils.h"
49 #include "nsHashtable.h"
51 #include "nsIInterfaceInfoManager.h"
54 #include "nsAutoLock.h"
56 nsProxyEventObject::nsProxyEventObject(nsProxyObject
*aParent
,
57 nsProxyEventClass
* aClass
,
58 already_AddRefed
<nsISomeInterface
> aRealInterface
,
61 mProxyObject(aParent
),
62 mRealInterface(aRealInterface
),
65 *rv
= InitStub(aClass
->GetProxiedIID());
68 nsProxyEventObject::~nsProxyEventObject()
70 // This destructor must *not* be called within the POM lock
73 // mRealInterface must be released before mProxyObject so that the last
74 // release of the proxied object is proxied to the correct thread.
76 mRealInterface
= nsnull
;
80 // nsISupports implementation...
83 NS_IMETHODIMP_(nsrefcnt
)
84 nsProxyEventObject::AddRef()
86 nsAutoLock
lock(nsProxyObjectManager::GetInstance()->GetLock());
87 return LockedAddRef();
91 nsProxyEventObject::LockedAddRef()
94 NS_LOG_ADDREF(this, mRefCnt
, "nsProxyEventObject", sizeof(nsProxyEventObject
));
98 NS_IMETHODIMP_(nsrefcnt
)
99 nsProxyEventObject::Release(void)
102 nsAutoLock
lock(nsProxyObjectManager::GetInstance()->GetLock());
103 NS_PRECONDITION(0 != mRefCnt
, "dup release");
106 NS_LOG_RELEASE(this, mRefCnt
, "nsProxyEventObject");
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);
121 nsProxyEventObject::QueryInterface(REFNSIID aIID
, void** aInstancePtr
)
123 if( aIID
.Equals(GetClass()->GetProxiedIID()) )
125 *aInstancePtr
= static_cast<nsISupports
*>(mXPTCStub
);
130 return mProxyObject
->QueryInterface(aIID
, aInstancePtr
);
134 // nsXPTCStubBase implementation...
138 nsProxyEventObject::convertMiniVariantToVariant(const XPTMethodDescriptor
*methodInfo
,
139 nsXPTCMiniVariant
* params
,
140 nsXPTCVariant
**fullParam
,
141 uint8
*outParamCount
)
143 uint8 paramCount
= methodInfo
->num_args
;
144 *outParamCount
= paramCount
;
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");
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
);
171 class nsProxyThreadFilter
: public nsIThreadEventFilter
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();
198 nsProxyEventObject::CallMethod(PRUint16 methodIndex
,
199 const XPTMethodDescriptor
* methodInfo
,
200 nsXPTCMiniVariant
* params
)
202 NS_ASSERTION(methodIndex
> 2,
203 "Calling QI/AddRef/Release through CallMethod");
206 if (XPT_MD_IS_NOTXPCOM(methodInfo
->flags
))
207 return NS_ERROR_PROXY_INVALID_IN_PARAMETER
;
209 nsXPTCVariant
*fullParam
;
211 rv
= convertMiniVariantToVariant(methodInfo
, params
,
212 &fullParam
, ¶mCount
);
216 PRBool callDirectly
= PR_FALSE
;
217 if (GetProxyType() & NS_PROXY_SYNC
&&
218 NS_SUCCEEDED(GetTarget()->IsOnCurrentThread(&callDirectly
)) &&
221 // invoke directly using xptc
222 rv
= NS_InvokeByIndex(mRealInterface
, methodIndex
,
223 paramCount
, fullParam
);
231 nsRefPtr
<nsProxyObjectCallInfo
> proxyInfo
=
232 new nsProxyObjectCallInfo(this, methodInfo
, methodIndex
,
233 fullParam
, paramCount
);
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();
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
;
265 rv
= proxyInfo
->GetResult();
267 NS_WARNING("Failed to dispatch nsProxyCallEvent");
270 threadInt
->PopEventQueue();
272 PROXY_LOG(("PROXY(%p): PostAndWait exit [%p %x]\n", this, proxyInfo
.get(), rv
));