mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-27 07:34:20 +00:00
Bug 675221 part B - remove the implementation of XPCOM proxies, sr=dougt
This commit is contained in:
parent
51e3a00405
commit
00e37f7b43
@ -56,7 +56,6 @@ DIRS = \
|
||||
components \
|
||||
threads \
|
||||
reflect \
|
||||
proxy \
|
||||
system \
|
||||
../chrome \
|
||||
build \
|
||||
@ -73,7 +72,7 @@ TOOL_DIRS += \
|
||||
tests \
|
||||
sample \
|
||||
typelib/xpt/tests \
|
||||
proxy/tests
|
||||
$(NULL)
|
||||
|
||||
# Can't build internal xptcall tests that use symbols which are not exported.
|
||||
#TOOL_DIRS += \
|
||||
|
@ -24,8 +24,6 @@
|
||||
COMPONENT(ATOMSERVICE, nsAtomServiceConstructor)
|
||||
COMPONENT(OBSERVERSERVICE, nsObserverService::Create)
|
||||
|
||||
COMPONENT(XPCOMPROXY, nsProxyObjectManager::Create)
|
||||
|
||||
COMPONENT(TIMER, nsTimerImplConstructor)
|
||||
|
||||
#define COMPONENT_SUPPORTS(TYPE, Type) \
|
||||
|
@ -78,9 +78,6 @@
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsThreadPool.h"
|
||||
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsProxyEventPrivate.h" // access to the impl of nsProxyObjectManager for the generic factory registration.
|
||||
|
||||
#include "xptinfo.h"
|
||||
#include "nsIInterfaceInfoManager.h"
|
||||
#include "xptiprivate.h"
|
||||
@ -273,7 +270,6 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsChromeRegistry,
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsChromeProtocolHandler)
|
||||
|
||||
#define NS_PERSISTENTPROPERTIES_CID NS_IPERSISTENTPROPERTIES_CID /* sigh */
|
||||
#define NS_XPCOMPROXY_CID NS_PROXYEVENT_MANAGER_CID
|
||||
|
||||
static already_AddRefed<nsIFactory>
|
||||
CreateINIParserFactory(const mozilla::Module& module,
|
||||
@ -665,8 +661,6 @@ ShutdownXPCOM(nsIServiceManager* servMgr)
|
||||
nsComponentManagerImpl::gComponentManager->FreeServices();
|
||||
}
|
||||
|
||||
nsProxyObjectManager::Shutdown();
|
||||
|
||||
// Release the directory service
|
||||
NS_IF_RELEASE(nsDirectoryService::gService);
|
||||
|
||||
|
@ -1,49 +0,0 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = xpcom
|
||||
DIRS = public src
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -1,57 +0,0 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = xpcom
|
||||
XPIDL_MODULE = proxyObject
|
||||
|
||||
EXPORTS = \
|
||||
nsProxiedService.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIProxyObjectManager.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -1,144 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Doug Turner <dougt@netscape.com> (Original Author)
|
||||
* Dan Mosedale <dmose@netscape.com>
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIEventTarget;
|
||||
|
||||
/**
|
||||
* An interface for the proxy object manager.
|
||||
*
|
||||
* See http://www.mozilla.org/projects/xpcom/Proxies.html
|
||||
*/
|
||||
[scriptable, uuid(ee8ce1e3-0319-4bd9-8f70-7258b21c7733)]
|
||||
interface nsIProxyObjectManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Construct a proxy object that invokes methods on the real object
|
||||
* synchronously (i.e., the calling thread is blocked until the real method
|
||||
* call returns). This flag causes methods invoked on the proxy object to
|
||||
* emmulate a real method call.
|
||||
*
|
||||
* For C++ callers, NS_PROXY_SYNC is a synonym for this flag.
|
||||
*/
|
||||
const long INVOKE_SYNC = 0x0001;
|
||||
|
||||
/**
|
||||
* Construct a proxy object that invokes methods on the real object
|
||||
* asynchronously (i.e., the calling thread does not wait for the real
|
||||
* method call to occur).
|
||||
*
|
||||
* WARNING: do not pass pointers into the stack when using this flag.
|
||||
*
|
||||
* For C++ callers, NS_PROXY_ASYNC is a synonym for this flag.
|
||||
*/
|
||||
const long INVOKE_ASYNC = 0x0002;
|
||||
|
||||
/**
|
||||
* Always create the proxy object even if for same thread as current thread.
|
||||
*
|
||||
* For C++ callers, NS_PROXY_ALWAYS is a synonym for this flag.
|
||||
*/
|
||||
const long FORCE_PROXY_CREATION = 0x0004;
|
||||
|
||||
/**
|
||||
* Create a proxy for the given object. The proxy implements the specified
|
||||
* interface, but when its methods are invoked, it causes the corresponding
|
||||
* method on the actual object to be called via the designated event
|
||||
* target. Typically, the event target identifies a thread where the
|
||||
* method call should occur.
|
||||
*
|
||||
* @param target
|
||||
* If target is null, then the current thread is used as the target.
|
||||
* Otherwise, target identifies the nsIEventTarget from which proxy
|
||||
* method calls should be executed.
|
||||
* @param iid
|
||||
* Identifies the interface being proxied. The given object must QI to
|
||||
* this type.
|
||||
* @param object
|
||||
* The object being proxied.
|
||||
* @param proxyType
|
||||
* Specifies the type of proxy to construct. Either INVOKE_SYNC or
|
||||
* INVOKE_ASYNC must be specified. FORCE_PROXY_CREATION may be bit-wise
|
||||
* OR'd with either of those flags.
|
||||
* @param result
|
||||
* This param holds the resulting proxy object upon successful return.
|
||||
*/
|
||||
void getProxyForObject(in nsIEventTarget target,
|
||||
in nsIIDRef iid,
|
||||
in nsISupports object,
|
||||
in PRInt32 proxyType,
|
||||
[iid_is(iid),retval] out nsQIResult result);
|
||||
};
|
||||
|
||||
|
||||
%{C++
|
||||
/**
|
||||
* convenience macros
|
||||
*/
|
||||
#define NS_PROXY_SYNC nsIProxyObjectManager::INVOKE_SYNC
|
||||
#define NS_PROXY_ASYNC nsIProxyObjectManager::INVOKE_ASYNC
|
||||
#define NS_PROXY_ALWAYS nsIProxyObjectManager::FORCE_PROXY_CREATION
|
||||
|
||||
/**
|
||||
* Pass this value as the target to {NS_}GetProxyForObject to specify the current
|
||||
* thread as the target for the proxy object.
|
||||
*/
|
||||
#define NS_PROXY_TO_CURRENT_THREAD ((nsIEventTarget *) 0)
|
||||
|
||||
/**
|
||||
* Pass this value as the target to NS_GetProxyForObject to specify the main
|
||||
* thread as the target for the proxy object.
|
||||
*/
|
||||
#define NS_PROXY_TO_MAIN_THREAD ((nsIEventTarget *) 1)
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
/**
|
||||
* Helper function for code that already has a link-time dependency on the
|
||||
* internal API (MOZILLA_INTERNAL_API) and needs to get proxies in a bunch of
|
||||
* different places. This way, the caller isn't forced to get the proxy object
|
||||
* manager themselves every single time, thus making the calling code more
|
||||
* readable. The parameters are the same as for GetProxyForObject.
|
||||
*/
|
||||
extern nsresult
|
||||
NS_GetProxyForObject(nsIEventTarget *target, REFNSIID iid, nsISupports* object,
|
||||
PRInt32 proxyType, void** result);
|
||||
#endif
|
||||
%}
|
@ -1,143 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsProxiedService_h__
|
||||
#define nsProxiedService_h__
|
||||
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NS_WITH_PROXIED_SERVICE: macro to make using services that need to be proxied
|
||||
// before using them easier.
|
||||
// Now you can replace this:
|
||||
// {
|
||||
// nsresult rv;
|
||||
// nsCOMPtr<nsIMyService> pIMyService =
|
||||
// do_GetService(kMyServiceCID, &rv);
|
||||
// if(NS_FAILED(rv))
|
||||
// return;
|
||||
// nsCOMPtr<nsIProxyObjectManager> pIProxyObjectManager =
|
||||
// do_GetService(kProxyObjectManagerCID, &rv);
|
||||
// if(NS_FAILED(rv))
|
||||
// return;
|
||||
// nsIMyService pIProxiedObject = NULL;
|
||||
// rv = pIProxyObjectManager->GetProxyForObject(pIDispatchTarget,
|
||||
// NS_GET_IID(nsIMyService),
|
||||
// pIMyService, NS_PROXY_SYNC,
|
||||
// (void**)&pIProxiedObject);
|
||||
// pIProxiedObject->DoIt(...); // Executed on same thread as pIProxyQueue
|
||||
// ...
|
||||
// pIProxiedObject->Release(); // Must be done as not managed for you.
|
||||
// }
|
||||
// with this:
|
||||
// {
|
||||
// nsresult rv;
|
||||
// NS_WITH_PROXIED_SERVICE(nsIMyService, pIMyService, kMyServiceCID,
|
||||
// pIDispatchTarget, &rv);
|
||||
// if(NS_FAILED(rv))
|
||||
// return;
|
||||
// pIMyService->DoIt(...); // Executed on the same thread as pIProxyQueue
|
||||
// }
|
||||
// and the automatic destructor will take care of releasing the service and
|
||||
// the proxied object for you.
|
||||
//
|
||||
// Note that this macro requires you to link with the xpcom DLL to pick up the
|
||||
// static member functions from nsServiceManager.
|
||||
|
||||
#define NS_WITH_PROXIED_SERVICE(T, var, cid, Q, rvAddr) \
|
||||
nsProxiedService _serv##var(cid, NS_GET_IID(T), Q, false, rvAddr); \
|
||||
T* var = (T*)(nsISupports*)_serv##var;
|
||||
|
||||
#define NS_WITH_ALWAYS_PROXIED_SERVICE(T, var, cid, Q, rvAddr) \
|
||||
nsProxiedService _serv##var(cid, NS_GET_IID(T), Q, true, rvAddr); \
|
||||
T* var = (T*)(nsISupports*)_serv##var;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsProxiedService
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class NS_STACK_CLASS nsProxiedService
|
||||
{
|
||||
public:
|
||||
nsProxiedService(const nsCID &aClass, const nsIID &aIID,
|
||||
nsIEventTarget* aTarget, bool always, nsresult* rv)
|
||||
{
|
||||
nsCOMPtr<nsISupports> svc = do_GetService(aClass, rv);
|
||||
if (NS_SUCCEEDED(*rv))
|
||||
InitProxy(svc, aIID, aTarget, always, rv);
|
||||
}
|
||||
|
||||
nsProxiedService(const char* aContractID, const nsIID &aIID,
|
||||
nsIEventTarget* aTarget, bool always, nsresult* rv)
|
||||
{
|
||||
nsCOMPtr<nsISupports> svc = do_GetService(aContractID, rv);
|
||||
if (NS_SUCCEEDED(*rv))
|
||||
InitProxy(svc, aIID, aTarget, always, rv);
|
||||
}
|
||||
|
||||
operator nsISupports*() const
|
||||
{
|
||||
return mProxiedService;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void InitProxy(nsISupports *aObj, const nsIID &aIID,
|
||||
nsIEventTarget* aTarget, bool always, nsresult*rv)
|
||||
{
|
||||
PRInt32 proxyType = NS_PROXY_SYNC;
|
||||
if (always)
|
||||
proxyType |= NS_PROXY_ALWAYS;
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> proxyObjMgr = do_GetService(NS_XPCOMPROXY_CONTRACTID, rv);
|
||||
if (NS_FAILED(*rv))
|
||||
return;
|
||||
|
||||
*rv = proxyObjMgr->GetProxyForObject(aTarget,
|
||||
aIID,
|
||||
aObj,
|
||||
proxyType,
|
||||
getter_AddRefs(mProxiedService));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> mProxiedService;
|
||||
};
|
||||
|
||||
#endif // nsProxiedService_h__
|
@ -1,66 +0,0 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = xpcom
|
||||
LIBRARY_NAME = xpcomproxy_s
|
||||
MOZILLA_INTERNAL_API = 1
|
||||
|
||||
|
||||
CPPSRCS = \
|
||||
nsProxyEvent.cpp \
|
||||
nsProxyEventClass.cpp \
|
||||
nsProxyEventObject.cpp \
|
||||
nsProxyObjectManager.cpp \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -D_IMPL_NS_COM -DEXPORT_XPTC_API
|
||||
LOCAL_INCLUDES += -I$(top_srcdir)/xpcom/threads/
|
||||
|
||||
# No shared lib; Force creation of static lib
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
LOCAL_INCLUDES += -I$(srcdir)/../../reflect/xptinfo/src
|
@ -1,513 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 ci et: */
|
||||
/*
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK *****
|
||||
*
|
||||
* This Original Code has been modified by IBM Corporation.
|
||||
* Modifications made by IBM described herein are
|
||||
* Copyright (c) International Business Machines
|
||||
* Corporation, 2000
|
||||
*
|
||||
* Modifications to Mozilla code or documentation
|
||||
* identified per MPL Section 3.3
|
||||
*
|
||||
* Date Modified by Description of modification
|
||||
* 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
|
||||
*/
|
||||
|
||||
#include "nsProxyEventPrivate.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#include "pratom.h"
|
||||
#include "prmem.h"
|
||||
#include "xptcall.h"
|
||||
|
||||
#include "nsXPCOMCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsEventQueue.h"
|
||||
#include "nsMemory.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/**
|
||||
* Map the nsAUTF8String, nsUTF8String classes to the nsACString and
|
||||
* nsCString classes respectively for now. These defines need to be removed
|
||||
* once Jag lands his nsUTF8String implementation.
|
||||
*/
|
||||
#define nsAUTF8String nsACString
|
||||
#define nsUTF8String nsCString
|
||||
|
||||
class nsProxyCallCompletedEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsProxyCallCompletedEvent(nsProxyObjectCallInfo *info)
|
||||
: mInfo(info)
|
||||
{}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void **aResult);
|
||||
|
||||
private:
|
||||
nsProxyObjectCallInfo *mInfo;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyCallCompletedEvent::Run()
|
||||
{
|
||||
NS_ASSERTION(mInfo, "no info");
|
||||
mInfo->SetCompleted();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DEFINE_IID(kFilterIID, NS_PROXYEVENT_FILTER_IID);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyCallCompletedEvent::QueryInterface(REFNSIID aIID, void **aResult)
|
||||
{
|
||||
// We are explicitly breaking XPCOM rules here by returning a different
|
||||
// object from QueryInterface. We do this so that
|
||||
// nsProxyThreadFilter::AcceptEvent can know whether we are an event that
|
||||
// needs to be allowed through during a synchronous proxy call.
|
||||
if (aIID.Equals(kFilterIID)) {
|
||||
*aResult = mInfo;
|
||||
mInfo->AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return nsRunnable::QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyObject::nsProxyObjectDestructorEvent::Run()
|
||||
{
|
||||
delete mDoomed;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsProxyObjectCallInfo::nsProxyObjectCallInfo(nsProxyEventObject* owner,
|
||||
const XPTMethodDescriptor *methodInfo,
|
||||
PRUint32 methodIndex,
|
||||
nsXPTCVariant* parameterList,
|
||||
PRUint32 parameterCount) :
|
||||
mResult(NS_ERROR_FAILURE),
|
||||
mMethodInfo(methodInfo),
|
||||
mMethodIndex(methodIndex),
|
||||
mParameterList(parameterList),
|
||||
mParameterCount(parameterCount),
|
||||
mCompleted(0),
|
||||
mOwner(owner)
|
||||
{
|
||||
NS_ASSERTION(owner, "No nsProxyObject!");
|
||||
NS_ASSERTION(methodInfo, "No nsXPTMethodInfo!");
|
||||
|
||||
RefCountInInterfacePointers(true);
|
||||
if (mOwner->GetProxyType() & NS_PROXY_ASYNC)
|
||||
CopyStrings(true);
|
||||
}
|
||||
|
||||
nsProxyObjectCallInfo::~nsProxyObjectCallInfo()
|
||||
{
|
||||
RefCountInInterfacePointers(false);
|
||||
if (mOwner->GetProxyType() & NS_PROXY_ASYNC)
|
||||
CopyStrings(false);
|
||||
|
||||
mOwner = nsnull;
|
||||
|
||||
if (mParameterList)
|
||||
free(mParameterList);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyObjectCallInfo::QueryInterface(REFNSIID aIID, void **aResult)
|
||||
{
|
||||
if (aIID.Equals(kFilterIID)) {
|
||||
*aResult = this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return nsRunnable::QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyObjectCallInfo::Run()
|
||||
{
|
||||
PROXY_LOG(("PROXY(%p): Run\n", this));
|
||||
|
||||
mResult = NS_InvokeByIndex(mOwner->GetProxiedInterface(),
|
||||
mMethodIndex,
|
||||
mParameterCount,
|
||||
mParameterList);
|
||||
|
||||
if (IsSync()) {
|
||||
PostCompleted();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObjectCallInfo::RefCountInInterfacePointers(bool addRef)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mParameterCount; i++)
|
||||
{
|
||||
nsXPTParamInfo paramInfo = mMethodInfo->params[i];
|
||||
|
||||
if (paramInfo.GetType().IsInterfacePointer() )
|
||||
{
|
||||
nsISupports* anInterface = nsnull;
|
||||
|
||||
if (paramInfo.IsIn())
|
||||
{
|
||||
anInterface = ((nsISupports*)mParameterList[i].val.p);
|
||||
|
||||
if (anInterface)
|
||||
{
|
||||
if (addRef)
|
||||
anInterface->AddRef();
|
||||
else
|
||||
anInterface->Release();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObjectCallInfo::CopyStrings(bool copy)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mParameterCount; i++)
|
||||
{
|
||||
const nsXPTParamInfo paramInfo = mMethodInfo->params[i];
|
||||
|
||||
if (paramInfo.IsIn())
|
||||
{
|
||||
const nsXPTType& type = paramInfo.GetType();
|
||||
uint8 type_tag = type.TagPart();
|
||||
void *ptr = mParameterList[i].val.p;
|
||||
|
||||
if (!ptr)
|
||||
continue;
|
||||
|
||||
if (copy)
|
||||
{
|
||||
switch (type_tag)
|
||||
{
|
||||
case nsXPTType::T_CHAR_STR:
|
||||
mParameterList[i].val.p =
|
||||
PL_strdup((const char *)ptr);
|
||||
break;
|
||||
case nsXPTType::T_WCHAR_STR:
|
||||
mParameterList[i].val.p =
|
||||
nsCRT::strdup((const PRUnichar *)ptr);
|
||||
break;
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
case nsXPTType::T_ASTRING:
|
||||
mParameterList[i].val.p =
|
||||
new nsString(*((nsAString*) ptr));
|
||||
break;
|
||||
case nsXPTType::T_CSTRING:
|
||||
mParameterList[i].val.p =
|
||||
new nsCString(*((nsACString*) ptr));
|
||||
break;
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
mParameterList[i].val.p =
|
||||
new nsUTF8String(*((nsAUTF8String*) ptr));
|
||||
break;
|
||||
default:
|
||||
// Other types are ignored
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (type_tag)
|
||||
{
|
||||
case nsXPTType::T_CHAR_STR:
|
||||
PL_strfree((char*) ptr);
|
||||
break;
|
||||
case nsXPTType::T_WCHAR_STR:
|
||||
nsCRT::free((PRUnichar*)ptr);
|
||||
break;
|
||||
case nsXPTType::T_DOMSTRING:
|
||||
case nsXPTType::T_ASTRING:
|
||||
delete (nsString*) ptr;
|
||||
break;
|
||||
case nsXPTType::T_CSTRING:
|
||||
delete (nsCString*) ptr;
|
||||
break;
|
||||
case nsXPTType::T_UTF8STRING:
|
||||
delete (nsUTF8String*) ptr;
|
||||
break;
|
||||
default:
|
||||
// Other types are ignored
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsProxyObjectCallInfo::GetCompleted()
|
||||
{
|
||||
return !!mCompleted;
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObjectCallInfo::SetCompleted()
|
||||
{
|
||||
PROXY_LOG(("PROXY(%p): SetCompleted\n", this));
|
||||
PR_ATOMIC_SET(&mCompleted, 1);
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObjectCallInfo::PostCompleted()
|
||||
{
|
||||
PROXY_LOG(("PROXY(%p): PostCompleted\n", this));
|
||||
|
||||
if (mCallersTarget) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new nsProxyCallCompletedEvent(this);
|
||||
if (event &&
|
||||
NS_SUCCEEDED(mCallersTarget->Dispatch(event, NS_DISPATCH_NORMAL)))
|
||||
return;
|
||||
}
|
||||
|
||||
// OOM? caller does not have a target? This is an error!
|
||||
NS_WARNING("Failed to dispatch nsProxyCallCompletedEvent");
|
||||
SetCompleted();
|
||||
}
|
||||
|
||||
nsIEventTarget*
|
||||
nsProxyObjectCallInfo::GetCallersTarget()
|
||||
{
|
||||
return mCallersTarget;
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObjectCallInfo::SetCallersTarget(nsIEventTarget* target)
|
||||
{
|
||||
mCallersTarget = target;
|
||||
}
|
||||
|
||||
nsProxyObject::nsProxyObject(nsIEventTarget *target, PRInt32 proxyType,
|
||||
nsISupports *realObject) :
|
||||
mProxyType(proxyType),
|
||||
mTarget(target),
|
||||
mRealObject(realObject),
|
||||
mFirst(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsProxyObject);
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsISupports> canonicalTarget = do_QueryInterface(target);
|
||||
NS_ASSERTION(target == canonicalTarget,
|
||||
"Non-canonical nsISupports passed to nsProxyObject constructor");
|
||||
#endif
|
||||
}
|
||||
|
||||
nsProxyObject::~nsProxyObject()
|
||||
{
|
||||
// Proxy the release of mRealObject to protect against it being deleted on
|
||||
// the wrong thread.
|
||||
nsISupports *doomed = nsnull;
|
||||
mRealObject.swap(doomed);
|
||||
NS_ProxyRelease(mTarget, doomed);
|
||||
|
||||
MOZ_COUNT_DTOR(nsProxyObject);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsProxyObject::AddRef()
|
||||
{
|
||||
MutexAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
|
||||
return LockedAddRef();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsProxyObject::Release()
|
||||
{
|
||||
MutexAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
|
||||
return LockedRelease();
|
||||
}
|
||||
|
||||
nsrefcnt
|
||||
nsProxyObject::LockedAddRef()
|
||||
{
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "nsProxyObject", sizeof(nsProxyObject));
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
nsrefcnt
|
||||
nsProxyObject::LockedRelease()
|
||||
{
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsProxyObject");
|
||||
if (mRefCnt)
|
||||
return mRefCnt;
|
||||
|
||||
nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance();
|
||||
pom->LockedRemove(this);
|
||||
|
||||
MutexAutoUnlock unlock(pom->GetLock());
|
||||
delete this;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyObject::QueryInterface(REFNSIID aIID, void **aResult)
|
||||
{
|
||||
if (aIID.Equals(GetIID())) {
|
||||
*aResult = this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsISupports))) {
|
||||
*aResult = static_cast<nsISupports*>(this);
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance();
|
||||
NS_ASSERTION(pom, "Deleting a proxy without a global proxy-object-manager.");
|
||||
|
||||
MutexAutoLock lock(pom->GetLock());
|
||||
return LockedFind(aIID, aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsProxyObject::LockedFind(REFNSIID aIID, void **aResult)
|
||||
{
|
||||
// This method is only called when the global lock is held.
|
||||
#ifdef DEBUG
|
||||
nsProxyObjectManager::GetInstance()->GetLock().AssertCurrentThreadOwns();
|
||||
#endif
|
||||
|
||||
nsProxyEventObject *peo;
|
||||
|
||||
for (peo = mFirst; peo; peo = peo->mNext) {
|
||||
if (peo->GetClass()->GetProxiedIID().Equals(aIID)) {
|
||||
*aResult = static_cast<nsISupports*>(peo->mXPTCStub);
|
||||
peo->LockedAddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsProxyEventObject *newpeo;
|
||||
|
||||
// Both GetClass and QueryInterface call out to XPCOM, so we unlock for them
|
||||
nsProxyObjectManager* pom = nsProxyObjectManager::GetInstance();
|
||||
{
|
||||
MutexAutoUnlock unlock(pom->GetLock());
|
||||
|
||||
nsProxyEventClass *pec;
|
||||
nsresult rv = pom->GetClass(aIID, &pec);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsISomeInterface* newInterface;
|
||||
rv = mRealObject->QueryInterface(aIID, (void**) &newInterface);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
newpeo = new nsProxyEventObject(this, pec,
|
||||
already_AddRefed<nsISomeInterface>(newInterface), &rv);
|
||||
if (!newpeo) {
|
||||
NS_RELEASE(newInterface);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
delete newpeo;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we're locked again, check for races by repeating the
|
||||
// linked-list check.
|
||||
for (peo = mFirst; peo; peo = peo->mNext) {
|
||||
if (peo->GetClass()->GetProxiedIID().Equals(aIID)) {
|
||||
// Best to AddRef for our caller before unlocking.
|
||||
peo->LockedAddRef();
|
||||
|
||||
{
|
||||
// Deleting an nsProxyEventObject can call Release on an
|
||||
// nsProxyObject, which can only happen when not holding
|
||||
// the lock.
|
||||
MutexAutoUnlock unlock(pom->GetLock());
|
||||
delete newpeo;
|
||||
}
|
||||
*aResult = static_cast<nsISupports*>(peo->mXPTCStub);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
newpeo->mNext = mFirst;
|
||||
mFirst = newpeo;
|
||||
|
||||
newpeo->LockedAddRef();
|
||||
|
||||
*aResult = static_cast<nsISupports*>(newpeo->mXPTCStub);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObject::LockedRemove(nsProxyEventObject *peo)
|
||||
{
|
||||
nsProxyEventObject **i;
|
||||
for (i = &mFirst; *i; i = &((*i)->mNext)) {
|
||||
if (*i == peo) {
|
||||
*i = peo->mNext;
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_ERROR("Didn't find nsProxyEventObject in nsProxyObject chain!");
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 ci et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsProxyEventPrivate.h"
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsMemory.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
#include "xptcall.h"
|
||||
|
||||
// LIFETIME_CACHE will cache class for the entire cyle of the application.
|
||||
#define LIFETIME_CACHE
|
||||
|
||||
static uint32 zero_methods_descriptor;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// nsProxyEventClass
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo)
|
||||
: mIID(aIID),
|
||||
mInfo(aInfo),
|
||||
mDescriptors(NULL)
|
||||
{
|
||||
uint16 methodCount;
|
||||
if(NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount)))
|
||||
{
|
||||
if(methodCount)
|
||||
{
|
||||
int wordCount = (methodCount/32)+1;
|
||||
if(NULL != (mDescriptors = new uint32[wordCount]))
|
||||
{
|
||||
memset(mDescriptors, 0, wordCount * sizeof(uint32));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mDescriptors = &zero_methods_descriptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsProxyEventClass::~nsProxyEventClass()
|
||||
{
|
||||
if (mDescriptors && mDescriptors != &zero_methods_descriptor)
|
||||
delete [] mDescriptors;
|
||||
}
|
@ -1,274 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Benjamin Smedberg <benjamin@smedbergs.us>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "prprf.h"
|
||||
#include "prmem.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsProxyEventPrivate.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "nsHashtable.h"
|
||||
|
||||
#include "nsIInterfaceInfoManager.h"
|
||||
#include "xptcall.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsProxyEventObject::nsProxyEventObject(nsProxyObject *aParent,
|
||||
nsProxyEventClass* aClass,
|
||||
already_AddRefed<nsISomeInterface> aRealInterface,
|
||||
nsresult *rv)
|
||||
: mClass(aClass),
|
||||
mProxyObject(aParent),
|
||||
mRealInterface(aRealInterface),
|
||||
mNext(nsnull)
|
||||
{
|
||||
*rv = InitStub(aClass->GetProxiedIID());
|
||||
}
|
||||
|
||||
nsProxyEventObject::~nsProxyEventObject()
|
||||
{
|
||||
// This destructor must *not* be called within the POM lock
|
||||
// XXX assert this!
|
||||
|
||||
// mRealInterface must be released before mProxyObject so that the last
|
||||
// release of the proxied object is proxied to the correct thread.
|
||||
// See bug 337492.
|
||||
mRealInterface = nsnull;
|
||||
}
|
||||
|
||||
//
|
||||
// nsISupports implementation...
|
||||
//
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsProxyEventObject::AddRef()
|
||||
{
|
||||
MutexAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
|
||||
return LockedAddRef();
|
||||
}
|
||||
|
||||
nsrefcnt
|
||||
nsProxyEventObject::LockedAddRef()
|
||||
{
|
||||
++mRefCnt;
|
||||
NS_LOG_ADDREF(this, mRefCnt, "nsProxyEventObject", sizeof(nsProxyEventObject));
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsProxyEventObject::Release(void)
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(nsProxyObjectManager::GetInstance()->GetLock());
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
|
||||
--mRefCnt;
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsProxyEventObject");
|
||||
|
||||
if (mRefCnt)
|
||||
return mRefCnt;
|
||||
|
||||
mProxyObject->LockedRemove(this);
|
||||
}
|
||||
|
||||
// call the destructor outside of the lock so that we aren't holding the
|
||||
// lock when we release the object
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyEventObject::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
if( aIID.Equals(GetClass()->GetProxiedIID()) )
|
||||
{
|
||||
*aInstancePtr = static_cast<nsISupports*>(mXPTCStub);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mProxyObject->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
//
|
||||
// nsXPTCStubBase implementation...
|
||||
//
|
||||
|
||||
nsresult
|
||||
nsProxyEventObject::convertMiniVariantToVariant(const XPTMethodDescriptor *methodInfo,
|
||||
nsXPTCMiniVariant * params,
|
||||
nsXPTCVariant **fullParam,
|
||||
uint8 *outParamCount)
|
||||
{
|
||||
uint8 paramCount = methodInfo->num_args;
|
||||
*outParamCount = paramCount;
|
||||
*fullParam = nsnull;
|
||||
|
||||
if (!paramCount) return NS_OK;
|
||||
|
||||
*fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount);
|
||||
|
||||
if (*fullParam == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
{
|
||||
const nsXPTParamInfo& paramInfo = methodInfo->params[i];
|
||||
if ((GetProxyType() & NS_PROXY_ASYNC) &&
|
||||
(paramInfo.IsOut() || paramInfo.IsDipper()))
|
||||
{
|
||||
NS_WARNING("Async proxying of out parameters is not supported");
|
||||
free(*fullParam);
|
||||
return NS_ERROR_PROXY_INVALID_OUT_PARAMETER;
|
||||
}
|
||||
uint8 flags = paramInfo.IsOut() ? nsXPTCVariant::PTR_IS_DATA : 0;
|
||||
(*fullParam)[i].Init(params[i], paramInfo.GetType(), flags);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class nsProxyThreadFilter : public nsIThreadEventFilter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITHREADEVENTFILTER
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyThreadFilter, nsIThreadEventFilter)
|
||||
|
||||
NS_DEFINE_IID(kFilterIID, NS_PROXYEVENT_FILTER_IID);
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
nsProxyThreadFilter::AcceptEvent(nsIRunnable *event)
|
||||
{
|
||||
PROXY_LOG(("PROXY(%p): filter event [%p]\n", this, event));
|
||||
|
||||
// If we encounter one of our proxy events that is for a synchronous method
|
||||
// call, then we want to put it in our event queue for processing. Else,
|
||||
// we want to allow the event to be dispatched to the thread's event queue
|
||||
// for processing later once we complete the current sync method call.
|
||||
|
||||
nsRefPtr<nsProxyObjectCallInfo> poci;
|
||||
event->QueryInterface(kFilterIID, getter_AddRefs(poci));
|
||||
return poci && poci->IsSync();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyEventObject::CallMethod(PRUint16 methodIndex,
|
||||
const XPTMethodDescriptor* methodInfo,
|
||||
nsXPTCMiniVariant * params)
|
||||
{
|
||||
NS_ASSERTION(methodIndex > 2,
|
||||
"Calling QI/AddRef/Release through CallMethod");
|
||||
nsresult rv;
|
||||
|
||||
if (XPT_MD_IS_NOTXPCOM(methodInfo->flags))
|
||||
return NS_ERROR_PROXY_INVALID_IN_PARAMETER;
|
||||
|
||||
nsXPTCVariant *fullParam;
|
||||
uint8 paramCount;
|
||||
rv = convertMiniVariantToVariant(methodInfo, params,
|
||||
&fullParam, ¶mCount);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
bool callDirectly = false;
|
||||
if (GetProxyType() & NS_PROXY_SYNC &&
|
||||
NS_SUCCEEDED(GetTarget()->IsOnCurrentThread(&callDirectly)) &&
|
||||
callDirectly) {
|
||||
|
||||
// invoke directly using xptc
|
||||
rv = NS_InvokeByIndex(mRealInterface, methodIndex,
|
||||
paramCount, fullParam);
|
||||
|
||||
if (fullParam)
|
||||
free(fullParam);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsRefPtr<nsProxyObjectCallInfo> proxyInfo =
|
||||
new nsProxyObjectCallInfo(this, methodInfo, methodIndex,
|
||||
fullParam, paramCount);
|
||||
if (!proxyInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (! (GetProxyType() & NS_PROXY_SYNC)) {
|
||||
return GetTarget()->Dispatch(proxyInfo, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
// Post synchronously
|
||||
|
||||
nsIThread *thread = NS_GetCurrentThread();
|
||||
nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(thread);
|
||||
NS_ENSURE_STATE(threadInt);
|
||||
|
||||
// Install thread filter to limit event processing only to
|
||||
// nsProxyObjectCallInfo instances. XXX Add support for sequencing?
|
||||
nsRefPtr<nsProxyThreadFilter> filter = new nsProxyThreadFilter();
|
||||
if (!filter)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
threadInt->PushEventQueue(filter);
|
||||
|
||||
proxyInfo->SetCallersTarget(thread);
|
||||
|
||||
// Dispatch can fail if the thread is shutting down
|
||||
rv = GetTarget()->Dispatch(proxyInfo, NS_DISPATCH_NORMAL);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
while (!proxyInfo->GetCompleted()) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rv = proxyInfo->GetResult();
|
||||
} else {
|
||||
NS_WARNING("Failed to dispatch nsProxyCallEvent");
|
||||
}
|
||||
|
||||
threadInt->PopEventQueue();
|
||||
|
||||
PROXY_LOG(("PROXY(%p): PostAndWait exit [%p %x]\n", this, proxyInfo.get(), rv));
|
||||
return rv;
|
||||
}
|
@ -1,320 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsProxyEventPrivate_h__
|
||||
#define nsProxyEventPrivate_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIInterfaceInfo.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
|
||||
#include "nsXPTCUtils.h"
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
#include "prlog.h"
|
||||
|
||||
class nsProxyEventObject;
|
||||
|
||||
/**
|
||||
* To make types clearer, we distinguish between a canonical nsISupports* and
|
||||
* a proxied interface pointer which represents an arbitrary interface known
|
||||
* at runtime.
|
||||
*/
|
||||
typedef nsISupports nsISomeInterface;
|
||||
|
||||
#define NS_PROXYOBJECT_CLASS_IID \
|
||||
{ 0xeea90d45, 0xb059, 0x11d2, \
|
||||
{ 0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33 } }
|
||||
|
||||
// This IID is used to filter runnables during synchronous event handling.
|
||||
// The returned pointer is type nsProxyObjectCallInfo
|
||||
|
||||
#define NS_PROXYEVENT_FILTER_IID \
|
||||
{ 0xec373590, 0x9164, 0x11d3, \
|
||||
{0x8c, 0x73, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74} }
|
||||
|
||||
/**
|
||||
* An object representing an IID and its associated interfaceinfo. Instances
|
||||
* of this class are obtained via nsProxyObjectManager::GetClass.
|
||||
*/
|
||||
class nsProxyEventClass
|
||||
{
|
||||
public:
|
||||
nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo;}
|
||||
const nsIID& GetProxiedIID() const {return mIID; }
|
||||
|
||||
nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo);
|
||||
~nsProxyEventClass();
|
||||
|
||||
nsIID mIID;
|
||||
nsCOMPtr<nsIInterfaceInfo> mInfo;
|
||||
uint32* mDescriptors;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class which provides the XPCOM identity for a proxied object.
|
||||
* Instances of this class are obtained from the POM, and are uniquely
|
||||
* hashed on a proxytype/eventtarget/realobject key.
|
||||
*/
|
||||
class nsProxyObject : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYOBJECT_CLASS_IID)
|
||||
|
||||
nsProxyObject(nsIEventTarget *destQueue, PRInt32 proxyType,
|
||||
nsISupports *realObject);
|
||||
|
||||
nsISupports* GetRealObject() const { return mRealObject; }
|
||||
nsIEventTarget* GetTarget() const { return mTarget; }
|
||||
PRInt32 GetProxyType() const { return mProxyType; }
|
||||
|
||||
// these are the equivalents of AddRef/Release, but must be called
|
||||
// while holding the global POM lock
|
||||
nsrefcnt LockedAddRef();
|
||||
nsrefcnt LockedRelease();
|
||||
|
||||
// LockedFind should be called holding the POM lock. It will
|
||||
// temporarily unlock the lock during execution.
|
||||
nsresult LockedFind(REFNSIID iid, void **aResult);
|
||||
|
||||
void LockedRemove(nsProxyEventObject* aObject);
|
||||
|
||||
friend class nsProxyObjectManager;
|
||||
private:
|
||||
~nsProxyObject();
|
||||
|
||||
PRInt32 mProxyType;
|
||||
nsCOMPtr<nsIEventTarget> mTarget; /* event target */
|
||||
nsCOMPtr<nsISupports> mRealObject; /* the non-proxy object that this object is proxying
|
||||
This is a strong ref. */
|
||||
nsProxyEventObject *mFirst;
|
||||
|
||||
class nsProxyObjectDestructorEvent : public nsRunnable
|
||||
{
|
||||
nsProxyObjectDestructorEvent(nsProxyObject *doomed) :
|
||||
mDoomed(doomed)
|
||||
{}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
friend class nsProxyObject;
|
||||
private:
|
||||
nsProxyObject *mDoomed;
|
||||
};
|
||||
|
||||
friend class nsProxyObjectDestructorEvent;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyObject, NS_PROXYOBJECT_CLASS_IID)
|
||||
|
||||
/**
|
||||
* Object representing a single interface implemented on a proxied object.
|
||||
* This object is maintained in a singly-linked list from the associated
|
||||
* "parent" nsProxyObject.
|
||||
*/
|
||||
class nsProxyEventObject : protected nsAutoXPTCStub
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// call this method and return result
|
||||
NS_IMETHOD CallMethod(PRUint16 methodIndex,
|
||||
const XPTMethodDescriptor* info,
|
||||
nsXPTCMiniVariant* params);
|
||||
|
||||
nsProxyEventClass* GetClass() const { return mClass; }
|
||||
nsISomeInterface* GetProxiedInterface() const { return mRealInterface; }
|
||||
nsIEventTarget* GetTarget() const { return mProxyObject->GetTarget(); }
|
||||
PRInt32 GetProxyType() const { return mProxyObject->GetProxyType(); }
|
||||
|
||||
nsresult convertMiniVariantToVariant(const XPTMethodDescriptor *methodInfo,
|
||||
nsXPTCMiniVariant *params,
|
||||
nsXPTCVariant **fullParam,
|
||||
uint8 *outParamCount);
|
||||
|
||||
nsProxyEventObject(nsProxyObject *aParent,
|
||||
nsProxyEventClass *aClass,
|
||||
already_AddRefed<nsISomeInterface> aRealInterface,
|
||||
nsresult *rv);
|
||||
|
||||
// AddRef, but you must be holding the global POM lock
|
||||
nsrefcnt LockedAddRef();
|
||||
friend class nsProxyObject;
|
||||
|
||||
private:
|
||||
~nsProxyEventObject();
|
||||
|
||||
// Member ordering is important: See note in the destructor.
|
||||
nsProxyEventClass *mClass;
|
||||
nsCOMPtr<nsProxyObject> mProxyObject;
|
||||
nsCOMPtr<nsISomeInterface> mRealInterface;
|
||||
|
||||
// Weak reference, maintained by the parent nsProxyObject
|
||||
nsProxyEventObject *mNext;
|
||||
};
|
||||
|
||||
#define NS_PROXYEVENT_IID \
|
||||
{ /* 9a24dc5e-2b42-4a5a-aeca-37b8c8fd8ccd */ \
|
||||
0x9a24dc5e, \
|
||||
0x2b42, \
|
||||
0x4a5a, \
|
||||
{0xae, 0xca, 0x37, 0xb8, 0xc8, 0xfd, 0x8c, 0xcd} \
|
||||
}
|
||||
|
||||
/**
|
||||
* A class representing a particular proxied method call.
|
||||
*/
|
||||
class nsProxyObjectCallInfo : public nsRunnable
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void **aResult);
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IID)
|
||||
|
||||
nsProxyObjectCallInfo(nsProxyEventObject* owner,
|
||||
const XPTMethodDescriptor *methodInfo,
|
||||
PRUint32 methodIndex,
|
||||
nsXPTCVariant* parameterList,
|
||||
PRUint32 parameterCount);
|
||||
|
||||
~nsProxyObjectCallInfo();
|
||||
|
||||
PRUint32 GetMethodIndex() const { return mMethodIndex; }
|
||||
nsXPTCVariant* GetParameterList() const { return mParameterList; }
|
||||
PRUint32 GetParameterCount() const { return mParameterCount; }
|
||||
nsresult GetResult() const { return mResult; }
|
||||
|
||||
bool GetCompleted();
|
||||
void SetCompleted();
|
||||
void PostCompleted();
|
||||
|
||||
void SetResult(nsresult rv) { mResult = rv; }
|
||||
|
||||
nsIEventTarget* GetCallersTarget();
|
||||
void SetCallersTarget(nsIEventTarget* target);
|
||||
bool IsSync() const
|
||||
{
|
||||
return !!(mOwner->GetProxyType() & NS_PROXY_SYNC);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
nsresult mResult; /* this is the return result of the called function */
|
||||
const XPTMethodDescriptor *mMethodInfo;
|
||||
PRUint32 mMethodIndex; /* which method to be called? */
|
||||
nsXPTCVariant *mParameterList; /* marshalled in parameter buffer */
|
||||
PRUint32 mParameterCount; /* number of params */
|
||||
PRInt32 mCompleted; /* is true when the method has been called. */
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mCallersTarget; /* this is the dispatch target that we must post a message back to
|
||||
when we are done invoking the method (only NS_PROXY_SYNC). */
|
||||
|
||||
nsRefPtr<nsProxyEventObject> mOwner; /* this is the strong referenced nsProxyObject */
|
||||
|
||||
void RefCountInInterfacePointers(bool addRef);
|
||||
void CopyStrings(bool copy);
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyObjectCallInfo, NS_PROXYEVENT_IID)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsProxyObjectManager
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsProxyObjectManager: public nsIProxyObjectManager
|
||||
{
|
||||
typedef mozilla::Mutex Mutex;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPROXYOBJECTMANAGER
|
||||
|
||||
static nsresult Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
|
||||
|
||||
nsProxyObjectManager();
|
||||
|
||||
static nsProxyObjectManager *GetInstance();
|
||||
static bool IsManagerShutdown();
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
nsresult GetClass(REFNSIID aIID, nsProxyEventClass **aResult);
|
||||
|
||||
void LockedRemove(nsProxyObject* aProxy);
|
||||
|
||||
Mutex& GetLock() { return mProxyCreationLock; }
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *sLog;
|
||||
#endif
|
||||
|
||||
private:
|
||||
~nsProxyObjectManager();
|
||||
|
||||
static nsProxyObjectManager* gInstance;
|
||||
nsHashtable mProxyObjectMap;
|
||||
nsClassHashtable<nsIDHashKey, nsProxyEventClass> mProxyClassMap;
|
||||
Mutex mProxyCreationLock;
|
||||
};
|
||||
|
||||
#define NS_XPCOMPROXY_CLASSNAME "nsProxyObjectManager"
|
||||
#define NS_PROXYEVENT_MANAGER_CID \
|
||||
{ 0xeea90d41, \
|
||||
0xb059, \
|
||||
0x11d2, \
|
||||
{0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33} \
|
||||
}
|
||||
|
||||
#define PROXY_LOG(args) PR_LOG(nsProxyObjectManager::sLog, PR_LOG_DEBUG, args)
|
||||
|
||||
#endif // nsProxyEventPrivate_h__
|
@ -1,351 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Doug Turner <dougt@netscape.com> (Original Author)
|
||||
* Judson Valeski <valeski@netscape.com>
|
||||
* Dan Matejka <danm@netscape.com>
|
||||
* Scott Collins <scc@netscape.com>
|
||||
* Heikki Toivonen <heiki@citec.fi>
|
||||
* Patrick Beard <beard@netscape.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Warren Harris <warren@netscape.com>
|
||||
* Chris Seawood <cls@seawood.org>
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Dan Mosedale <dmose@netscape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsProxyEventPrivate.h"
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIThread.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "xptiprivate.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo *nsProxyObjectManager::sLog = PR_NewLogModule("xpcomproxy");
|
||||
#endif
|
||||
|
||||
class nsProxyEventKey : public nsHashKey
|
||||
{
|
||||
public:
|
||||
nsProxyEventKey(void* rootObjectKey, void* targetKey, PRInt32 proxyType)
|
||||
: mRootObjectKey(rootObjectKey), mTargetKey(targetKey), mProxyType(proxyType) {
|
||||
}
|
||||
|
||||
PRUint32 HashCode(void) const {
|
||||
return NS_PTR_TO_INT32(mRootObjectKey) ^
|
||||
NS_PTR_TO_INT32(mTargetKey) ^ mProxyType;
|
||||
}
|
||||
|
||||
bool Equals(const nsHashKey *aKey) const {
|
||||
const nsProxyEventKey* other = (const nsProxyEventKey*)aKey;
|
||||
return mRootObjectKey == other->mRootObjectKey
|
||||
&& mTargetKey == other->mTargetKey
|
||||
&& mProxyType == other->mProxyType;
|
||||
}
|
||||
|
||||
nsHashKey *Clone() const {
|
||||
return new nsProxyEventKey(mRootObjectKey, mTargetKey, mProxyType);
|
||||
}
|
||||
|
||||
protected:
|
||||
void* mRootObjectKey;
|
||||
void* mTargetKey;
|
||||
PRInt32 mProxyType;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// nsProxyObjectManager
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsProxyObjectManager* nsProxyObjectManager::gInstance = nsnull;
|
||||
|
||||
NS_IMPL_QUERY_INTERFACE1(nsProxyObjectManager, nsIProxyObjectManager)
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsProxyObjectManager::AddRef()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsProxyObjectManager::Release()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
nsProxyObjectManager::nsProxyObjectManager()
|
||||
: mProxyObjectMap(256, false)
|
||||
, mProxyCreationLock("nsProxyObjectManager.mProxyCreationLock")
|
||||
{
|
||||
mProxyClassMap.Init(256);
|
||||
}
|
||||
|
||||
nsProxyObjectManager::~nsProxyObjectManager()
|
||||
{
|
||||
mProxyClassMap.Clear();
|
||||
|
||||
nsProxyObjectManager::gInstance = nsnull;
|
||||
}
|
||||
|
||||
bool
|
||||
nsProxyObjectManager::IsManagerShutdown()
|
||||
{
|
||||
return gInstance == nsnull;
|
||||
}
|
||||
|
||||
nsProxyObjectManager *
|
||||
nsProxyObjectManager::GetInstance()
|
||||
{
|
||||
if (!gInstance)
|
||||
gInstance = new nsProxyObjectManager();
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObjectManager::Shutdown()
|
||||
{
|
||||
delete gInstance;
|
||||
NS_ASSERTION(!gInstance, "Destructor didn't null gInstance?");
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsProxyObjectManager::Create(nsISupports* outer, const nsIID& aIID,
|
||||
void* *aInstancePtr)
|
||||
{
|
||||
nsProxyObjectManager *proxyObjectManager = GetInstance();
|
||||
if (!proxyObjectManager)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return proxyObjectManager->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
class nsProxyLockedRefPtr
|
||||
{
|
||||
public:
|
||||
nsProxyLockedRefPtr(nsProxyObject* aPtr) :
|
||||
mProxyObject(aPtr)
|
||||
{
|
||||
if (mProxyObject)
|
||||
mProxyObject->LockedAddRef();
|
||||
}
|
||||
|
||||
~nsProxyLockedRefPtr()
|
||||
{
|
||||
if (mProxyObject)
|
||||
mProxyObject->LockedRelease();
|
||||
}
|
||||
|
||||
operator nsProxyObject*() const
|
||||
{
|
||||
return mProxyObject;
|
||||
}
|
||||
|
||||
nsProxyObject* operator->() const
|
||||
{
|
||||
return mProxyObject;
|
||||
}
|
||||
|
||||
private:
|
||||
nsProxyObject *mProxyObject;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProxyObjectManager::GetProxyForObject(nsIEventTarget* aTarget,
|
||||
REFNSIID aIID,
|
||||
nsISupports* aObj,
|
||||
PRInt32 proxyType,
|
||||
void** aProxyObject)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aObj);
|
||||
|
||||
*aProxyObject = nsnull;
|
||||
|
||||
// handle special values
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
if (aTarget == NS_PROXY_TO_CURRENT_THREAD) {
|
||||
aTarget = NS_GetCurrentThread();
|
||||
} else if (aTarget == NS_PROXY_TO_MAIN_THREAD) {
|
||||
thread = do_GetMainThread();
|
||||
aTarget = thread.get();
|
||||
}
|
||||
|
||||
// check to see if the target is on our thread. If so, just return the
|
||||
// real object.
|
||||
|
||||
if (!(proxyType & NS_PROXY_ASYNC) && !(proxyType & NS_PROXY_ALWAYS))
|
||||
{
|
||||
bool result;
|
||||
aTarget->IsOnCurrentThread(&result);
|
||||
|
||||
if (result)
|
||||
return aObj->QueryInterface(aIID, aProxyObject);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> realObj = do_QueryInterface(aObj);
|
||||
|
||||
// Make sure the object passed in is not a proxy; if it is, be nice and
|
||||
// build the proxy for the real object.
|
||||
nsCOMPtr<nsProxyObject> po = do_QueryInterface(aObj);
|
||||
if (po) {
|
||||
realObj = po->GetRealObject();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> realEQ = do_QueryInterface(aTarget);
|
||||
|
||||
nsProxyEventKey rootKey(realObj, realEQ, proxyType);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mProxyCreationLock);
|
||||
nsProxyLockedRefPtr root =
|
||||
(nsProxyObject*) mProxyObjectMap.Get(&rootKey);
|
||||
if (root)
|
||||
return root->LockedFind(aIID, aProxyObject);
|
||||
}
|
||||
|
||||
// don't lock while creating the nsProxyObject
|
||||
nsProxyObject *newRoot = new nsProxyObject(aTarget, proxyType, realObj);
|
||||
if (!newRoot)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// lock again, and check for a race putting into mProxyObjectMap
|
||||
{
|
||||
MutexAutoLock lock(mProxyCreationLock);
|
||||
nsProxyLockedRefPtr root =
|
||||
(nsProxyObject*) mProxyObjectMap.Get(&rootKey);
|
||||
if (root) {
|
||||
delete newRoot;
|
||||
return root->LockedFind(aIID, aProxyObject);
|
||||
}
|
||||
|
||||
mProxyObjectMap.Put(&rootKey, newRoot);
|
||||
|
||||
nsProxyLockedRefPtr kungFuDeathGrip(newRoot);
|
||||
return newRoot->LockedFind(aIID, aProxyObject);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsProxyObjectManager::LockedRemove(nsProxyObject *aProxy)
|
||||
{
|
||||
nsCOMPtr<nsISupports> realEQ = do_QueryInterface(aProxy->GetTarget());
|
||||
|
||||
nsProxyEventKey rootKey(aProxy->GetRealObject(), realEQ, aProxy->GetProxyType());
|
||||
|
||||
if (!mProxyObjectMap.Remove(&rootKey)) {
|
||||
NS_ERROR("nsProxyObject not found in global hash.");
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsProxyObjectManager::GetClass(REFNSIID aIID, nsProxyEventClass **aResult)
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(mProxyCreationLock);
|
||||
if (mProxyClassMap.Get(aIID, aResult)) {
|
||||
NS_ASSERTION(*aResult, "Null data in mProxyClassMap");
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsIInterfaceInfoManager *iim =
|
||||
xptiInterfaceInfoManager::GetSingleton();
|
||||
if (!iim)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIInterfaceInfo> ii;
|
||||
nsresult rv = iim->GetInfoForIID(&aIID, getter_AddRefs(ii));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsProxyEventClass *pec = new nsProxyEventClass(aIID, ii);
|
||||
if (!pec)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Re-lock to put this class into our map. Before putting, check to see
|
||||
// if another thread raced to put before us
|
||||
MutexAutoLock lock(mProxyCreationLock);
|
||||
|
||||
if (mProxyClassMap.Get(aIID, aResult)) {
|
||||
NS_ASSERTION(*aResult, "Null data in mProxyClassMap");
|
||||
delete pec;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mProxyClassMap.Put(aIID, pec)) {
|
||||
delete pec;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
*aResult = pec;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for code that already has a link-time dependency on
|
||||
* libxpcom and needs to get proxies in a bunch of different places.
|
||||
* This way, the caller isn't forced to get the proxy object manager
|
||||
* themselves every single time, thus making the calling code more
|
||||
* readable.
|
||||
*/
|
||||
nsresult
|
||||
NS_GetProxyForObject(nsIEventTarget *target,
|
||||
REFNSIID aIID,
|
||||
nsISupports* aObj,
|
||||
PRInt32 proxyType,
|
||||
void** aProxyObject)
|
||||
{
|
||||
static NS_DEFINE_CID(proxyObjMgrCID, NS_PROXYEVENT_MANAGER_CID);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// get the proxy object manager
|
||||
//
|
||||
nsCOMPtr<nsIProxyObjectManager> proxyObjMgr =
|
||||
do_GetService(proxyObjMgrCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// and try to get the proxy object
|
||||
//
|
||||
return proxyObjMgr->GetProxyForObject(target, aIID, aObj,
|
||||
proxyType, aProxyObject);
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = xpcom_tests
|
||||
XPIDL_MODULE = proxytest
|
||||
|
||||
CPPSRCS = proxytests.cpp \
|
||||
proxy-create-threadsafety.cpp \
|
||||
$(NULL)
|
||||
XPIDLSRCS = nsITestProxy.idl
|
||||
|
||||
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
|
||||
|
||||
LIBS = \
|
||||
$(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \
|
||||
$(XPCOM_LIBS) \
|
||||
$(NSPR_LIBS) \
|
||||
$(MOZ_JS_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
@ -1,9 +0,0 @@
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[uuid(1979e980-1cfd-11d3-915e-0000863011c4)]
|
||||
interface nsITestProxy : nsISupports
|
||||
{
|
||||
long Test(in long p1, in long p2);
|
||||
void Test2();
|
||||
void Test3(in nsISupports p1, out nsISupports p2);
|
||||
};
|
@ -1,255 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mark 'Mook' Yen <mook@songbirdnest.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIComponentRegistrar.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nspr.h"
|
||||
|
||||
#include "nsITestProxy.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/*
|
||||
|
||||
A quick diagram of how this test works:
|
||||
|
||||
This tests for bug 400450, where the creation of a proxy event object
|
||||
causes a deadlock. We use a counter and a monitor to make things
|
||||
be more deterministic.
|
||||
|
||||
The leftmost column marks the thread that is running.
|
||||
|
||||
M Create two threads
|
||||
1 Get a proxy
|
||||
1 proxy event object created
|
||||
1 (Proxy object QIs the target)
|
||||
1 Lock [*]
|
||||
2 Get a proxy
|
||||
2 proxy event object created
|
||||
2 (Proxy object calls QI)
|
||||
2 Unlock [*]
|
||||
2 proxy event object stored
|
||||
2 proxy obtained
|
||||
1 proxy event object released
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
/* ProxyTest */
|
||||
/***************************************************************************/
|
||||
|
||||
class ProxyTest : public nsIRunnable,
|
||||
public nsITestProxy,
|
||||
public nsISupportsPrimitive
|
||||
{
|
||||
public:
|
||||
ProxyTest()
|
||||
: mCounterLock("ProxyTest.mCounterLock")
|
||||
, mEvilReentrantMonitor("ProxyTest.mEvilReentrantMonitor")
|
||||
, mCounter(0)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIProxyObjectManager> pom =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISupportsPrimitive> prim;
|
||||
rv = pom->GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
|
||||
NS_GET_IID(nsISupportsPrimitive),
|
||||
NS_ISUPPORTS_CAST(nsIRunnable*, this),
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(prim));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
/* we don't actually need to use the proxied object */
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32 *_retval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!NS_IsMainThread())
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
/* note that we don't have an event queue... */
|
||||
|
||||
rv = NS_NewThread(getter_AddRefs(mThreadOne),
|
||||
static_cast<nsIRunnable*>(this));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = NS_NewThread(getter_AddRefs(mThreadTwo),
|
||||
static_cast<nsIRunnable*>(this));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mThreadOne->Shutdown();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mThreadTwo->Shutdown();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Test2(void)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetType(PRUint16 *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
NS_ASSERTION(aInstancePtr,
|
||||
"QueryInterface requires a non-NULL destination!");
|
||||
nsISupports* foundInterface;
|
||||
if ( aIID.Equals(NS_GET_IID(nsIRunnable)) ) {
|
||||
foundInterface = static_cast<nsIRunnable*>(this);
|
||||
} else if ( aIID.Equals(NS_GET_IID(nsITestProxy)) ) {
|
||||
foundInterface = static_cast<nsITestProxy*>(this);
|
||||
} else if ( aIID.Equals(NS_GET_IID(nsISupports)) ) {
|
||||
foundInterface = NS_ISUPPORTS_CAST(nsIRunnable*, this);
|
||||
} else if ( aIID.Equals(NS_GET_IID(nsISupportsPrimitive)) ) {
|
||||
{
|
||||
MutexAutoLock counterLock(mCounterLock);
|
||||
switch(mCounter) {
|
||||
case 0:
|
||||
++mCounter;
|
||||
{
|
||||
/* be evil here and hang */
|
||||
MutexAutoUnlock counterUnlock(mCounterLock);
|
||||
ReentrantMonitorAutoEnter evilReentrantMonitor(mEvilReentrantMonitor);
|
||||
nsresult rv = evilReentrantMonitor.Wait();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
++mCounter;
|
||||
{
|
||||
/* okay, we had our fun, un-hang */
|
||||
MutexAutoUnlock counterUnlock(mCounterLock);
|
||||
ReentrantMonitorAutoEnter evilReentrantMonitor(mEvilReentrantMonitor);
|
||||
nsresult rv = evilReentrantMonitor.Notify();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* nothing special here */
|
||||
++mCounter;
|
||||
}
|
||||
}
|
||||
++mCounter;
|
||||
}
|
||||
// remeber to admit to supporting this interface
|
||||
foundInterface = static_cast<nsISupportsPrimitive*>(this);
|
||||
} else {
|
||||
foundInterface = nsnull;
|
||||
}
|
||||
nsresult status;
|
||||
if (!foundInterface) {
|
||||
status = NS_ERROR_NO_INTERFACE;
|
||||
} else {
|
||||
NS_ADDREF(foundInterface);
|
||||
status = NS_OK;
|
||||
}
|
||||
*aInstancePtr = foundInterface;
|
||||
return status;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(nsrefcnt) AddRef(void);
|
||||
NS_IMETHOD_(nsrefcnt) Release(void);
|
||||
|
||||
protected:
|
||||
nsAutoRefCnt mRefCnt;
|
||||
NS_DECL_OWNINGTHREAD
|
||||
|
||||
private:
|
||||
Mutex mCounterLock;
|
||||
ReentrantMonitor mEvilReentrantMonitor;
|
||||
PRInt32 mCounter;
|
||||
nsCOMPtr<nsIThread> mThreadOne;
|
||||
nsCOMPtr<nsIThread> mThreadTwo;
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(ProxyTest)
|
||||
NS_IMPL_THREADSAFE_RELEASE(ProxyTest)
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
NS_InitXPCOM2(nsnull, nsnull, nsnull);
|
||||
|
||||
// Scope code so everything is destroyed before we run call NS_ShutdownXPCOM
|
||||
{
|
||||
nsCOMPtr<nsITestProxy> tester = new ProxyTest();
|
||||
tester->Test(0, 0, nsnull);
|
||||
}
|
||||
|
||||
NS_ShutdownXPCOM(nsnull);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,554 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIComponentRegistrar.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nspr.h"
|
||||
#include "prmon.h"
|
||||
|
||||
#include "nsITestProxy.h"
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsIThreadPool.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *sLog = PR_NewLogModule("Test");
|
||||
#define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
|
||||
#else
|
||||
#define LOG(args) printf args
|
||||
#endif
|
||||
|
||||
namespace proxytests {
|
||||
|
||||
static nsresult
|
||||
GetThreadFromPRThread(PRThread *prthread, nsIThread **result)
|
||||
{
|
||||
LOG(("TEST: GetThreadFromPRThread [%p]\n", prthread));
|
||||
|
||||
nsCOMPtr<nsIThreadManager> tm = do_GetService(NS_THREADMANAGER_CONTRACTID);
|
||||
NS_ENSURE_STATE(tm);
|
||||
return tm->GetThreadFromPRThread(prthread, result);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* nsTestXPCFoo */
|
||||
/***************************************************************************/
|
||||
class nsTestXPCFoo : public nsITestProxy
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32* retval);
|
||||
NS_IMETHOD Test2();
|
||||
NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2);
|
||||
|
||||
nsTestXPCFoo();
|
||||
};
|
||||
|
||||
nsTestXPCFoo::nsTestXPCFoo()
|
||||
{
|
||||
NS_ADDREF_THIS();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsTestXPCFoo, nsITestProxy)
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo::Test(PRInt32 p1, PRInt32 p2, PRInt32* retval)
|
||||
{
|
||||
LOG(("TEST: Thread (%d) Test Called successfully! Party on...\n", p1));
|
||||
*retval = p1+p2;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo::Test2()
|
||||
{
|
||||
LOG(("TEST: The quick brown netscape jumped over the old lazy ie..\n"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo::Test3(nsISupports *p1, nsISupports **p2)
|
||||
{
|
||||
if (p1 != nsnull)
|
||||
{
|
||||
nsITestProxy *test;
|
||||
|
||||
p1->QueryInterface(NS_GET_IID(nsITestProxy), (void**)&test);
|
||||
|
||||
test->Test2();
|
||||
PRInt32 a;
|
||||
test->Test( 1, 2, &a);
|
||||
LOG(("TEST: \n1+2=%d\n",a));
|
||||
}
|
||||
|
||||
|
||||
*p2 = new nsTestXPCFoo();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* nsTestXPCFoo2 */
|
||||
/***************************************************************************/
|
||||
class nsTestXPCFoo2 : public nsITestProxy
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32* retval);
|
||||
NS_IMETHOD Test2();
|
||||
NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2);
|
||||
|
||||
nsTestXPCFoo2();
|
||||
};
|
||||
|
||||
nsTestXPCFoo2::nsTestXPCFoo2()
|
||||
{
|
||||
NS_ADDREF_THIS();
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsTestXPCFoo2, nsITestProxy)
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo2::Test(PRInt32 p1, PRInt32 p2, PRInt32* retval)
|
||||
{
|
||||
LOG(("TEST: calling back to caller!\n"));
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
LOG(("TEST: ProxyObjectManager: %p \n", (void *) manager.get()));
|
||||
|
||||
PR_ASSERT(manager);
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
GetThreadFromPRThread((PRThread *) p1, getter_AddRefs(thread));
|
||||
NS_ENSURE_STATE(thread);
|
||||
|
||||
nsCOMPtr<nsITestProxy> proxyObject;
|
||||
manager->GetProxyForObject(thread, NS_GET_IID(nsITestProxy), this, NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
proxyObject->Test3(nsnull, nsnull);
|
||||
|
||||
LOG(("TEST: Deleting Proxy Object\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo2::Test2()
|
||||
{
|
||||
LOG(("TEST: nsTestXPCFoo2::Test2() called\n"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo2::Test3(nsISupports *p1, nsISupports **p2)
|
||||
{
|
||||
LOG(("TEST: Got called"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
struct ArgsStruct {
|
||||
nsIThread* thread;
|
||||
PRInt32 threadNumber;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// This will create two objects both descendants of a single IID.
|
||||
void TestCase_TwoClassesOneInterface(void *arg)
|
||||
{
|
||||
ArgsStruct *argsStruct = (ArgsStruct*) arg;
|
||||
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
printf("ProxyObjectManager: %p \n", (void *) manager.get());
|
||||
|
||||
PR_ASSERT(manager);
|
||||
|
||||
nsITestProxy *proxyObject;
|
||||
nsITestProxy *proxyObject2;
|
||||
|
||||
nsTestXPCFoo* foo = new nsTestXPCFoo();
|
||||
nsTestXPCFoo2* foo2 = new nsTestXPCFoo2();
|
||||
|
||||
PR_ASSERT(foo);
|
||||
PR_ASSERT(foo2);
|
||||
|
||||
|
||||
manager->GetProxyForObject(argsStruct->thread, NS_GET_IID(nsITestProxy), foo, NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
|
||||
manager->GetProxyForObject(argsStruct->thread, NS_GET_IID(nsITestProxy), foo2, NS_PROXY_SYNC, (void**)&proxyObject2);
|
||||
|
||||
|
||||
|
||||
if (proxyObject && proxyObject2)
|
||||
{
|
||||
// release ownership of the real object.
|
||||
|
||||
PRInt32 a;
|
||||
nsresult rv;
|
||||
PRInt32 threadNumber = argsStruct->threadNumber;
|
||||
|
||||
printf("Deleting real Object (%d)\n", threadNumber);
|
||||
NS_RELEASE(foo);
|
||||
|
||||
printf("Deleting real Object 2 (%d)\n", threadNumber);
|
||||
NS_RELEASE(foo2);
|
||||
|
||||
|
||||
printf("Thread (%d) Prior to calling proxyObject->Test.\n", threadNumber);
|
||||
rv = proxyObject->Test(threadNumber, 0, &a);
|
||||
printf("Thread (%d) error: %d.\n", threadNumber, rv);
|
||||
|
||||
|
||||
printf("Thread (%d) Prior to calling proxyObject->Test2.\n", threadNumber);
|
||||
rv = proxyObject->Test2();
|
||||
printf("Thread (%d) error: %d.\n", threadNumber, rv);
|
||||
|
||||
printf("Thread (%d) Prior to calling proxyObject2->Test2.\n", threadNumber);
|
||||
rv = proxyObject2->Test2();
|
||||
printf("Thread (%d) proxyObject2 error: %d.\n", threadNumber, rv);
|
||||
|
||||
printf("Deleting Proxy Object (%d)\n", threadNumber );
|
||||
NS_RELEASE(proxyObject);
|
||||
|
||||
printf("Deleting Proxy Object 2 (%d)\n", threadNumber );
|
||||
NS_RELEASE(proxyObject2);
|
||||
}
|
||||
|
||||
PR_Sleep( PR_MillisecondsToInterval(1000) ); // If your thread goes away, your stack goes away. Only use ASYNC on calls that do not have out parameters
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void TestCase_NestedLoop(nsIThread *thread, PRInt32 index)
|
||||
{
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
LOG(("TEST: ProxyObjectManager: %p\n", (void *) manager.get()));
|
||||
|
||||
PR_ASSERT(manager);
|
||||
|
||||
nsITestProxy *proxyObject;
|
||||
nsTestXPCFoo2* foo = new nsTestXPCFoo2();
|
||||
|
||||
PR_ASSERT(foo);
|
||||
|
||||
|
||||
manager->GetProxyForObject(thread, NS_GET_IID(nsITestProxy), foo, NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
|
||||
if (proxyObject)
|
||||
{
|
||||
// release ownership of the real object.
|
||||
|
||||
nsresult rv;
|
||||
|
||||
LOG(("TEST: Deleting real Object (%d)\n", index));
|
||||
NS_RELEASE(foo);
|
||||
|
||||
PRInt32 retval;
|
||||
|
||||
LOG(("TEST: Getting EventThread...\n"));
|
||||
|
||||
//nsCOMPtr<nsIThread> curThread = do_GetCurrentThread();
|
||||
PRThread *curThread = PR_GetCurrentThread();
|
||||
if (curThread)
|
||||
{
|
||||
LOG(("TEST: Thread (%d) Prior to calling proxyObject->Test.\n", index));
|
||||
rv = proxyObject->Test(NS_PTR_TO_INT32((void*)curThread), 0, &retval); // XXX broken on 64-bit arch
|
||||
LOG(("TEST: Thread (%d) proxyObject error: %x.\n", index, rv));
|
||||
|
||||
LOG(("TEST: Deleting Proxy Object (%d)\n", index));
|
||||
NS_RELEASE(proxyObject);
|
||||
}
|
||||
|
||||
PR_Sleep( PR_MillisecondsToInterval(1000) ); // If your thread goes away, your stack goes away. Only use ASYNC on calls that do not have out parameters
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void TestCase_nsISupports(void *arg)
|
||||
{
|
||||
|
||||
ArgsStruct *argsStruct = (ArgsStruct*) arg;
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
PR_ASSERT(manager);
|
||||
|
||||
nsITestProxy *proxyObject;
|
||||
nsTestXPCFoo* foo = new nsTestXPCFoo();
|
||||
|
||||
PR_ASSERT(foo);
|
||||
|
||||
manager->GetProxyForObject(argsStruct->thread, NS_GET_IID(nsITestProxy), foo, NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
|
||||
if (proxyObject != nsnull)
|
||||
{
|
||||
nsISupports *bISupports = nsnull, *cISupports = nsnull;
|
||||
|
||||
proxyObject->Test3(foo, &bISupports);
|
||||
proxyObject->Test3(bISupports, &cISupports);
|
||||
|
||||
nsITestProxy *test;
|
||||
bISupports->QueryInterface(NS_GET_IID(nsITestProxy), (void**)&test);
|
||||
|
||||
test->Test2();
|
||||
|
||||
NS_RELEASE(foo);
|
||||
NS_RELEASE(proxyObject);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
/* ProxyTest */
|
||||
/***************************************************************************/
|
||||
|
||||
class ProxyTest : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
ProxyTest(PRThread *eventLoopThread, PRInt32 index)
|
||||
: mEventLoopThread(eventLoopThread)
|
||||
, mIndex(index)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
//TestCase_TwoClassesOneInterface(arg);
|
||||
//TestCase_nsISupports(arg);
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
GetThreadFromPRThread(mEventLoopThread, getter_AddRefs(thread));
|
||||
TestCase_NestedLoop(thread, mIndex);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
PRThread *mEventLoopThread;
|
||||
PRInt32 mIndex;
|
||||
};
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(ProxyTest, nsIRunnable)
|
||||
|
||||
class TestSyncProxyToSelf : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
LOG(("TEST: Verifing calling Proxy on eventQ thread.\n"));
|
||||
|
||||
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
|
||||
|
||||
nsITestProxy *proxyObject;
|
||||
nsTestXPCFoo *foo = new nsTestXPCFoo();
|
||||
NS_ENSURE_STATE(foo);
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
manager->GetProxyForObject(thread,
|
||||
NS_GET_IID(nsITestProxy), foo,
|
||||
NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
|
||||
PRInt32 a;
|
||||
proxyObject->Test(1, 2, &a);
|
||||
proxyObject->Test2();
|
||||
|
||||
NS_RELEASE(proxyObject);
|
||||
delete foo;
|
||||
|
||||
LOG(("TEST: End of Verification calling Proxy on eventQ thread.\n"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(TestSyncProxyToSelf, nsIRunnable)
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Test to make sure we can call methods on a "main thread only" object from
|
||||
// a background thread.
|
||||
|
||||
class MainThreadOnly : public nsIRunnable {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD Run() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "method called on wrong thread");
|
||||
*mNumRuns -= 1;
|
||||
return NS_OK;
|
||||
}
|
||||
MainThreadOnly(PRUint32 *numRuns) : mNumRuns(numRuns) {}
|
||||
~MainThreadOnly() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "method called on wrong thread");
|
||||
}
|
||||
bool IsDone() { return mNumRuns == 0; }
|
||||
private:
|
||||
PRUint32 *mNumRuns;
|
||||
};
|
||||
NS_IMPL_ISUPPORTS1(MainThreadOnly, nsIRunnable) // not threadsafe!
|
||||
|
||||
static nsresult
|
||||
RunApartmentTest()
|
||||
{
|
||||
LOG(("RunApartmentTest: start\n"));
|
||||
|
||||
const PRUint32 numDispatched = 160;
|
||||
|
||||
PRUint32 numCompleted = 0;
|
||||
nsCOMPtr<nsIRunnable> obj = new MainThreadOnly(&numCompleted);
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
nsCOMPtr<nsIRunnable> objProxy;
|
||||
manager->GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
||||
NS_GET_IID(nsIRunnable),
|
||||
obj,
|
||||
NS_PROXY_ASYNC,
|
||||
getter_AddRefs(objProxy));
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
NS_NewThread(getter_AddRefs(thread));
|
||||
|
||||
obj = nsnull;
|
||||
|
||||
nsCOMPtr<nsIThreadPool> pool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
|
||||
|
||||
pool->SetThreadLimit(8);
|
||||
for (PRUint32 i = 0; i < numDispatched; ++i)
|
||||
pool->Dispatch(objProxy, NS_DISPATCH_NORMAL);
|
||||
|
||||
objProxy = nsnull;
|
||||
|
||||
nsCOMPtr<nsIThread> curThread = do_GetCurrentThread();
|
||||
while (numCompleted < numDispatched) {
|
||||
NS_ProcessNextEvent(curThread);
|
||||
}
|
||||
|
||||
pool->Shutdown();
|
||||
|
||||
LOG(("RunApartmentTest: end\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace proxytests;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int numberOfThreads = 1;
|
||||
|
||||
if (argc > 1)
|
||||
numberOfThreads = atoi(argv[1]);
|
||||
|
||||
NS_InitXPCOM2(nsnull, nsnull, nsnull);
|
||||
|
||||
// Scope code so everything is destroyed before we run call NS_ShutdownXPCOM
|
||||
{
|
||||
RunApartmentTest();
|
||||
|
||||
nsCOMPtr<nsIThread> eventLoopThread;
|
||||
NS_NewThread(getter_AddRefs(eventLoopThread));
|
||||
|
||||
nsCOMPtr<nsIRunnable> test = new TestSyncProxyToSelf();
|
||||
eventLoopThread->Dispatch(test, NS_DISPATCH_NORMAL);
|
||||
|
||||
PRThread *eventLoopPRThread;
|
||||
eventLoopThread->GetPRThread(&eventLoopPRThread);
|
||||
PR_ASSERT(eventLoopPRThread);
|
||||
|
||||
LOG(("TEST: Spawn Threads:\n"));
|
||||
nsCOMArray<nsIThread> threads;
|
||||
for (PRInt32 spawn = 0; spawn < numberOfThreads; spawn++)
|
||||
{
|
||||
test = new ProxyTest(eventLoopPRThread, spawn);
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
NS_NewThread(getter_AddRefs(thread), test);
|
||||
|
||||
threads.AppendObject(thread);
|
||||
|
||||
LOG(("TEST: \tThread (%d) spawned\n", spawn));
|
||||
|
||||
PR_Sleep( PR_MillisecondsToInterval(250) );
|
||||
}
|
||||
|
||||
LOG(("TEST: All Threads Spawned.\n"));
|
||||
|
||||
LOG(("TEST: Wait for threads.\n"));
|
||||
for (PRInt32 i = 0; i < numberOfThreads; i++)
|
||||
{
|
||||
LOG(("TEST: Thread (%d) Join...\n", i));
|
||||
nsresult rv = threads[i]->Shutdown();
|
||||
LOG(("TEST: Thread (%d) Joined. (error: %x).\n", i, rv));
|
||||
}
|
||||
|
||||
LOG(("TEST: Shutting down event loop thread\n"));
|
||||
eventLoopThread->Shutdown();
|
||||
}
|
||||
|
||||
LOG(("TEST: Calling Cleanup.\n"));
|
||||
NS_ShutdownXPCOM(nsnull);
|
||||
|
||||
LOG(("TEST: Return zero.\n"));
|
||||
return 0;
|
||||
}
|
@ -114,7 +114,6 @@ endif
|
||||
# TestExpirationTracker.cpp \
|
||||
# TestPipes.cpp \
|
||||
# TestPriorityQueue.cpp \
|
||||
# TestProxies.cpp \
|
||||
# TestStorageStream.cpp \
|
||||
# TestStrings.cpp \
|
||||
# TestSynchronization.cpp \
|
||||
|
@ -1,798 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Proxy Test Code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ben Turner <bent.mozilla@gmail.com>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "TestHarness.h"
|
||||
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIThreadPool.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
using namespace mozilla;
|
||||
|
||||
typedef nsresult(*TestFuncPtr)();
|
||||
|
||||
#define TEST_NAME "TestProxies"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo* sLog = PR_NewLogModule(TEST_NAME);
|
||||
#endif
|
||||
#define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
|
||||
|
||||
static nsIThread* gMainThread = nsnull;
|
||||
static nsIThread* gTestThread = nsnull;
|
||||
|
||||
static nsresult
|
||||
GetProxyForObject(nsIEventTarget* aTarget,
|
||||
REFNSIID aIID,
|
||||
nsISupports* aObj,
|
||||
PRInt32 aProxyType,
|
||||
void** aProxyObject)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIProxyObjectManager> proxyObjMgr =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return proxyObjMgr->GetProxyForObject(aTarget, aIID, aObj, aProxyType,
|
||||
aProxyObject);
|
||||
}
|
||||
|
||||
class nsAutoTestThread
|
||||
{
|
||||
public:
|
||||
nsAutoTestThread(nsIThread** aGlobal = nsnull)
|
||||
: mGlobal(aGlobal)
|
||||
{
|
||||
nsCOMPtr<nsIThread> newThread;
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(newThread));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
rv = newThread->GetPRThread(&mNativeThread);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
LOG(("Created test thread [0x%p]", static_cast<void*>(mNativeThread)));
|
||||
|
||||
newThread.swap(mThread);
|
||||
|
||||
if (mGlobal)
|
||||
*mGlobal = mThread;
|
||||
}
|
||||
|
||||
~nsAutoTestThread()
|
||||
{
|
||||
if (mGlobal)
|
||||
*mGlobal = nsnull;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
void* nativeThread = static_cast<void*>(mNativeThread);
|
||||
#endif
|
||||
|
||||
LOG(("Shutting down test thread [0x%p]", nativeThread));
|
||||
mThread->Shutdown();
|
||||
LOG(("Test thread successfully shut down [0x%p]", nativeThread));
|
||||
}
|
||||
|
||||
operator nsIThread*() const
|
||||
{
|
||||
return mThread;
|
||||
}
|
||||
|
||||
nsIThread* operator->() const
|
||||
{
|
||||
return mThread;
|
||||
}
|
||||
|
||||
private:
|
||||
nsIThread** mGlobal;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
PRThread* mNativeThread;
|
||||
};
|
||||
|
||||
class SimpleRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SimpleRunnable(const char* aType = "SimpleRunnable")
|
||||
: mType(aType)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
LOG(("%s::Run() [0x%p]", mType,
|
||||
static_cast<void*>(static_cast<nsISupports*>(this))));
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
const char* mType;
|
||||
};
|
||||
|
||||
class TestTargetThreadRunnable : public SimpleRunnable
|
||||
{
|
||||
public:
|
||||
TestTargetThreadRunnable(nsIThread* aTarget)
|
||||
: SimpleRunnable("TestTargetThreadRunnable"),
|
||||
mTarget(aTarget)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsresult rv = SimpleRunnable::Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIThread> currentThread(do_GetCurrentThread());
|
||||
if (currentThread != mTarget) {
|
||||
NS_ERROR("Proxy sent call to wrong thread!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIThread> mTarget;
|
||||
};
|
||||
|
||||
class ChainedProxyRunnable : public SimpleRunnable
|
||||
{
|
||||
public:
|
||||
ChainedProxyRunnable(nsIThread* aSecondTarget,
|
||||
nsIThread* aThirdTarget = nsnull)
|
||||
: SimpleRunnable("ChainedProxyRunnable"), mSecondTarget(aSecondTarget),
|
||||
mThirdTarget(aThirdTarget)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsresult rv = SimpleRunnable::Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRefPtr<SimpleRunnable> runnable = mThirdTarget ?
|
||||
new ChainedProxyRunnable(mThirdTarget) :
|
||||
new SimpleRunnable();
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy;
|
||||
rv = GetProxyForObject(mSecondTarget, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIThread> mSecondTarget;
|
||||
nsCOMPtr<nsIThread> mThirdTarget;
|
||||
};
|
||||
|
||||
class IncrementingRunnable : public SimpleRunnable
|
||||
{
|
||||
public:
|
||||
IncrementingRunnable(PRUint32* aCounter, Mutex* aLock = nsnull)
|
||||
: SimpleRunnable("IncrementingRunnable"), mCounter(aCounter), mLock(aLock)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsresult rv = SimpleRunnable::Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mLock)
|
||||
mLock->Lock();
|
||||
|
||||
(*mCounter)++;
|
||||
|
||||
if (mLock)
|
||||
mLock->Unlock();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
PRUint32* mCounter;
|
||||
Mutex* mLock;
|
||||
};
|
||||
|
||||
class NonThreadsafeRunnable : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NonThreadsafeRunnable(PRUint32* aCounter,
|
||||
const char* aType = "NonThreadsafeRunnable")
|
||||
: mCounter(aCounter),
|
||||
mType(aType)
|
||||
{ }
|
||||
|
||||
virtual ~NonThreadsafeRunnable()
|
||||
{ };
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
LOG(("%s::Run() [0x%p]", mType,
|
||||
static_cast<void*>(static_cast<nsISupports*>(this))));
|
||||
|
||||
(*mCounter)++;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
PRUint32* mCounter;
|
||||
const char* mType;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(NonThreadsafeRunnable, nsIRunnable)
|
||||
|
||||
class MainThreadRunnable : public NonThreadsafeRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
MainThreadRunnable(PRUint32* aCounter)
|
||||
: NonThreadsafeRunnable(aCounter, "MainThreadRunnable")
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_ERROR("Not running on the main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~MainThreadRunnable()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_ERROR("Not running on the main thread!");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_ERROR("Not running on the main thread!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = NonThreadsafeRunnable::Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(MainThreadRunnable, NonThreadsafeRunnable)
|
||||
|
||||
class ProxyGetter : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ProxyGetter(nsIRunnable* aRunnable, nsIRunnable** retval)
|
||||
: mRunnable(aRunnable), _retval(retval)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
*_retval = nsnull;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
NS_ERROR("Shouldn't be running on the main thread!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy;
|
||||
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
||||
mRunnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
proxy.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsIRunnable* mRunnable;
|
||||
nsIRunnable** _retval;
|
||||
};
|
||||
|
||||
class RunnableGetter : public nsRunnable
|
||||
{
|
||||
public:
|
||||
RunnableGetter(PRUint32* aCounter, nsIRunnable** retval)
|
||||
: mCounter(aCounter), _retval(retval)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
*_retval = nsnull;
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
NS_ERROR("Shouldn't be running on the main thread!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new NonThreadsafeRunnable(mCounter);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
runnable.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
PRUint32* mCounter;
|
||||
nsIRunnable** _retval;
|
||||
};
|
||||
|
||||
nsresult
|
||||
TestTargetThread()
|
||||
{
|
||||
LOG(("--- Running TestTargetThread ---"));
|
||||
|
||||
nsRefPtr<TestTargetThreadRunnable> runnable =
|
||||
new TestTargetThreadRunnable(gMainThread);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy;
|
||||
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
||||
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable = new TestTargetThreadRunnable(gTestThread);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS, getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestNonThreadsafeProxy()
|
||||
{
|
||||
LOG(("--- Running TestNonThreadsafeProxy 1 ---"));
|
||||
|
||||
// Make sure a non-threadsafe object and proxy to it (both created on the same
|
||||
// thread) can be used on the same thread.
|
||||
|
||||
PRUint32 counter = 0;
|
||||
nsCOMPtr<nsIRunnable> runnable(new MainThreadRunnable(&counter));
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy;
|
||||
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
||||
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (PRUint32 otherCounter = 0; otherCounter < 5;) {
|
||||
rv = gTestThread->Dispatch(proxy, NS_DISPATCH_SYNC);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// Make sure a non-threadsafe object and proxy to it (both created on the same
|
||||
// thread) can be used on a different thread.
|
||||
|
||||
LOG(("--- Running TestNonThreadsafeProxy 2 ---"));
|
||||
|
||||
counter = 0;
|
||||
runnable = new NonThreadsafeRunnable(&counter);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable),
|
||||
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable = nsnull;
|
||||
|
||||
for (PRUint32 otherCounter = 0; otherCounter < 5;) {
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(counter == 5, NS_ERROR_FAILURE);
|
||||
|
||||
// Make sure a non-threadsafe object and proxy to it (created on different
|
||||
// threads) can be used by any thread.
|
||||
|
||||
LOG(("--- Running TestNonThreadsafeProxy 3 ---"));
|
||||
|
||||
counter = 0;
|
||||
proxy = nsnull;
|
||||
|
||||
runnable = new MainThreadRunnable(&counter);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxyGetter =
|
||||
new ProxyGetter(runnable, getter_AddRefs(proxy));
|
||||
NS_ENSURE_TRUE(proxyGetter, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = gTestThread->Dispatch(proxyGetter, NS_DISPATCH_SYNC);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(proxy, NS_ERROR_FAILURE);
|
||||
|
||||
for (PRUint32 otherCounter = 0; otherCounter < 5;) {
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// Make sure a non-threadsafe object (created on thread 1) and proxy to it
|
||||
// (created on thread 2) can be used by thread 3.
|
||||
|
||||
LOG(("--- Running TestNonThreadsafeProxy 4 ---"));
|
||||
|
||||
counter = 0;
|
||||
proxy = nsnull;
|
||||
runnable = nsnull;
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnableGetter =
|
||||
new RunnableGetter(&counter, getter_AddRefs(runnable));
|
||||
NS_ENSURE_TRUE(runnableGetter, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = gTestThread->Dispatch(runnableGetter, NS_DISPATCH_SYNC);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE);
|
||||
|
||||
proxyGetter = new ProxyGetter(runnable, getter_AddRefs(proxy));
|
||||
NS_ENSURE_TRUE(proxyGetter, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsAutoTestThread otherTestThread;
|
||||
NS_ENSURE_TRUE(otherTestThread, NS_ERROR_FAILURE);
|
||||
|
||||
rv = otherTestThread->Dispatch(proxyGetter, NS_DISPATCH_SYNC);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(proxy, NS_ERROR_FAILURE);
|
||||
|
||||
for (PRUint32 otherCounter = 0; otherCounter < 5;) {
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestChainedProxy()
|
||||
{
|
||||
LOG(("--- Running TestChainedProxy ---"));
|
||||
|
||||
nsRefPtr<ChainedProxyRunnable> runnable =
|
||||
new ChainedProxyRunnable(gMainThread);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy;
|
||||
nsresult rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable),
|
||||
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This will do a test->main call
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable = new ChainedProxyRunnable(gTestThread);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This will do a main->test call
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable = new ChainedProxyRunnable(gMainThread);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This will do a main->main call
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable = new ChainedProxyRunnable(gTestThread);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This will do a test->test call
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable = new ChainedProxyRunnable(gMainThread, gTestThread);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This will do a test->main->test call
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestReleaseOfRealObjects()
|
||||
{
|
||||
LOG(("--- Running TestReleaseOfRealObjects ---"));
|
||||
|
||||
PRUint32 counter = 0, otherCounter = 0;
|
||||
|
||||
nsRefPtr<IncrementingRunnable> runnable(new IncrementingRunnable(&counter));
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy1;
|
||||
nsresult rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable),
|
||||
runnable, NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy1));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy2;
|
||||
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy2));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy3;
|
||||
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy3));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ENSURE_FALSE(proxy1 == proxy2, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(proxy2 == proxy3, NS_ERROR_FAILURE);
|
||||
proxy3 = nsnull;
|
||||
|
||||
rv = proxy1->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
|
||||
rv = proxy2->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
|
||||
runnable = nsnull;
|
||||
|
||||
rv = proxy1->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
|
||||
rv = proxy2->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
|
||||
proxy1 = nsnull;
|
||||
|
||||
rv = proxy2->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestCurrentThreadProxy()
|
||||
{
|
||||
LOG(("--- Running TestCurrentThreadProxy ---"));
|
||||
|
||||
PRUint32 counter = 0, otherCounter = 0;
|
||||
nsRefPtr<IncrementingRunnable> runnable(new IncrementingRunnable(&counter));
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy1;
|
||||
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
||||
runnable, NS_PROXY_SYNC,
|
||||
getter_AddRefs(proxy1));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy2;
|
||||
rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
||||
getter_AddRefs(proxy2));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ENSURE_FALSE(proxy1 == proxy2, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIRunnable> realRunnable(do_QueryInterface(runnable));
|
||||
NS_ENSURE_TRUE(realRunnable, NS_ERROR_FAILURE);
|
||||
|
||||
NS_ENSURE_TRUE(static_cast<void*>(realRunnable) == static_cast<void*>(runnable),
|
||||
NS_ERROR_FAILURE);
|
||||
|
||||
rv = proxy1->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
|
||||
rv = proxy2->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(counter == ++otherCounter, NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestAsyncProxy()
|
||||
{
|
||||
LOG(("--- Running TestAsyncProxy ---"));
|
||||
|
||||
// Test async proxies to the current thread.
|
||||
|
||||
PRUint32 counter = 0;
|
||||
nsRefPtr<SimpleRunnable> runnable(new IncrementingRunnable(&counter));
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIRunnable> proxy;
|
||||
nsresult rv = GetProxyForObject(gMainThread, NS_GET_IID(nsIRunnable),
|
||||
runnable, NS_PROXY_ASYNC,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
runnable = nsnull;
|
||||
|
||||
for (PRUint32 i = 0; i < 5; i++) {
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
while (counter < 5) {
|
||||
rv = NS_ProcessPendingEvents(gMainThread, PR_SecondsToInterval(1));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Now test async proxies to another thread.
|
||||
|
||||
Mutex* counterLock = new Mutex("counterLock");
|
||||
NS_ENSURE_TRUE(counterLock, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
counter = 0;
|
||||
runnable = new IncrementingRunnable(&counter, counterLock);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable), runnable,
|
||||
NS_PROXY_ASYNC, getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (PRUint32 i = 0; i < 5; i++) {
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
PRUint32 safeCounter = 0;
|
||||
while (safeCounter < 5) {
|
||||
rv = NS_ProcessPendingEvents(gMainThread, PR_SecondsToInterval(1));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MutexAutoLock lock(*counterLock);
|
||||
safeCounter = counter;
|
||||
}
|
||||
|
||||
delete counterLock;
|
||||
|
||||
// Now test async proxies to another thread that create sync proxies to this
|
||||
// thread.
|
||||
|
||||
runnable = new ChainedProxyRunnable(gMainThread);
|
||||
NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = GetProxyForObject(gTestThread, NS_GET_IID(nsIRunnable),
|
||||
runnable, NS_PROXY_ASYNC,
|
||||
getter_AddRefs(proxy));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = proxy->Run();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// That was async, so make sure to wait for all the events on the test thread
|
||||
// to be processed before we return. This is easy to do with an empty sync
|
||||
// event.
|
||||
nsCOMPtr<nsIRunnable> flusher = new nsRunnable();
|
||||
NS_ENSURE_TRUE(flusher, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
LOG(("Flushing events on test thread"));
|
||||
|
||||
rv = gTestThread->Dispatch(flusher, NS_DISPATCH_SYNC);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
LOG(("Flushing events completed"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
ScopedXPCOM xpcom(TEST_NAME);
|
||||
NS_ENSURE_FALSE(xpcom.failed(), 1);
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
|
||||
NS_ENSURE_TRUE(mainThread, 1);
|
||||
|
||||
LOG(("Got main thread"));
|
||||
gMainThread = mainThread;
|
||||
|
||||
nsAutoTestThread testThread(&gTestThread);
|
||||
NS_ENSURE_TRUE(testThread, 1);
|
||||
|
||||
static TestFuncPtr testsToRun[] = {
|
||||
TestTargetThread,
|
||||
// TestNonThreadsafeProxy, /* Not currently supported! */
|
||||
TestChainedProxy,
|
||||
TestReleaseOfRealObjects,
|
||||
TestCurrentThreadProxy,
|
||||
TestAsyncProxy
|
||||
};
|
||||
static PRUint32 testCount = sizeof(testsToRun) / sizeof(testsToRun[0]);
|
||||
|
||||
for (PRUint32 i = 0; i < testCount; i++) {
|
||||
nsresult rv = testsToRun[i]();
|
||||
NS_ENSURE_SUCCESS(rv, 1);
|
||||
}
|
||||
|
||||
LOG(("--- Finished all tests ---"));
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user