diff options
Diffstat (limited to 'src/libs/xpcom18a4/xpcom/proxy')
22 files changed, 3557 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/proxy/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/Makefile.in new file mode 100644 index 00000000..c30f214f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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 + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in new file mode 100644 index 00000000..d6950b9a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in @@ -0,0 +1,63 @@ +# +# ***** 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 +ifeq ($(OS_ARCH),WINNT) +XPIDL_MODULE = proxyObject +else +XPIDL_MODULE = proxyObjInst +endif + +EXPORTS = \ + nsProxyEvent.h \ + nsProxyRelease.h \ + nsProxiedService.h \ + $(NULL) + +XPIDLSRCS = nsIProxyCreateInstance.idl \ + nsIProxyObjectManager.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl new file mode 100644 index 00000000..cd576f7b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl @@ -0,0 +1,53 @@ +/* -*- 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): + * + * 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" + +[scriptable, uuid(948c2080-0398-11d3-915e-0000863011c4)] +interface nsIProxyCreateInstance : nsISupports +{ + [noscript] void CreateInstanceByIID(in nsIIDRef cid, + in nsISupports aOuter, + in nsIIDRef iid, + out voidPtr result); + + [noscript] void CreateInstanceByContractID(in string aContractID, + in nsISupports aOuter, + in nsIIDRef iid, + out voidPtr result); +}; + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl new file mode 100644 index 00000000..5b2cfd4d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl @@ -0,0 +1,87 @@ +/* -*- 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> + * + * 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 nsIEventQueue; + +[scriptable, uuid(eea90d43-b059-11d2-915e-c12b696c9333)] +interface nsIProxyObjectManager : nsISupports +{ + void getProxyForObject(in nsIEventQueue destQueue, + in nsIIDRef iid, + in nsISupports object, + in PRInt32 proxyType, + [iid_is(iid),retval] out nsQIResult result); + + void getProxy(in nsIEventQueue destQueue, + in nsIIDRef cid, + in nsISupports aOuter, + in nsIIDRef iid, + in PRInt32 proxyType, + [iid_is(iid),retval] out nsQIResult result); + +}; + + +%{C++ +#include "nsProxyEvent.h" + +#define NS_XPCOMPROXY_CONTRACTID "@mozilla.org/xpcomproxy;1" +#define NS_XPCOMPROXY_CLASSNAME "XPCom Proxy" + +#define NS_PROXYEVENT_MANAGER_CID \ +{ 0xeea90d41, \ + 0xb059, \ + 0x11d2, \ + {0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33}\ +} + +/** + * 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. + */ +extern NS_COM nsresult +NS_GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject); +%} diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h new file mode 100644 index 00000000..3a39ade1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h @@ -0,0 +1,164 @@ +/* -*- 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 __nsProxiedServiceManager_h_ +#define __nsProxiedServiceManager_h_ + +#include "nsIServiceManager.h" +#include "nsIProxyObjectManager.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(pIProxyQueue, +// NS_GET_IID(nsIMyService), +// pIMyService, 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, +// pIProxyQueue, &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, PR_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, PR_TRUE, rvAddr); \ + T* var = (T*)(nsISupports*)_serv##var; + +//////////////////////////////////////////////////////////////////////////////// +// nsProxiedService +//////////////////////////////////////////////////////////////////////////////// + +class nsProxiedService +{ + public: + + nsProxiedService(const nsCID &aClass, const nsIID &aIID, + nsIEventQueue* pIProxyQueue, PRBool always, nsresult*rv) + { + *rv = nsServiceManager::GetService(aClass, + aIID, + getter_AddRefs(mService)); + if (NS_FAILED(*rv)) return; + InitProxy(aIID, pIProxyQueue, always, rv); + } + + nsProxiedService(const char* aContractID, const nsIID &aIID, + nsIEventQueue* pIProxyQueue, PRBool always, nsresult*rv) + { + *rv = nsServiceManager::GetService(aContractID, + aIID, + getter_AddRefs(mService)); + if (NS_FAILED(*rv)) return; + InitProxy(aIID, pIProxyQueue, always, rv); + } + + void InitProxy(const nsIID &aIID, nsIEventQueue* pIProxyQueue, + PRBool always, nsresult*rv) + { + static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); + + nsCOMPtr<nsIProxyObjectManager> pIProxyObjectManager = + do_GetService(kProxyObjectManagerCID, rv); + if (NS_FAILED(*rv)) return; + + PRInt32 proxyType = PROXY_SYNC; + if (always) proxyType |= PROXY_ALWAYS; + *rv = pIProxyObjectManager->GetProxyForObject(pIProxyQueue, + aIID, + mService, + proxyType, + getter_AddRefs(mProxiedService)); + } + + ~nsProxiedService() + { + } + + nsISupports* operator->() const + { + NS_PRECONDITION(mProxiedService != 0, "Your code should test the error result from the constructor."); + return mProxiedService; + } + + PRBool operator==(const nsISupports* other) + { + return ((mProxiedService == other) || (mService == other)); + } + + operator nsISupports*() const + { + return mProxiedService; + } + + protected: + nsCOMPtr<nsISupports> mProxiedService; + nsCOMPtr<nsISupports> mService; + + }; + + +#endif //__nsProxiedServiceManager_h_ diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h new file mode 100644 index 00000000..c718bbdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h @@ -0,0 +1,183 @@ +/* -*- 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): + * + * 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 __nsProxyEvent_h_ +#define __nsProxyEvent_h_ + +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "nscore.h" +#include "nsISupports.h" +#include "nsIFactory.h" + +#include "nsIEventQueueService.h" +#include "nsIEventQueue.h" +#include "plevent.h" +#include "prtypes.h" +#include "xptcall.h" +#include "xptinfo.h" + +class nsProxyObjectCallInfo; + +#define PROXY_SYNC 0x0001 // acts just like a function call. +#define PROXY_ASYNC 0x0002 // fire and forget. This will return immediately and you will lose all return information. +#define PROXY_ALWAYS 0x0004 // ignore check to see if the eventQ is on the same thread as the caller, and alway return a proxied object. + +//#define AUTOPROXIFICATION + +// WARNING about PROXY_ASYNC: +// +// If the calling thread goes away, any function which accesses the calling stack +// will blow up. +// +// example: +// +// myFoo->bar(&x) +// +// ... thread goes away ... +// +// bar(PRInt32 *x) +// { +// *x = 0; <----- You will blow up here. +// +// +// So what gets saved? +// +// You can safely pass base types by value. You can also pass interface pointers. +// I will make sure that the interface pointers are addrefed while they are being +// proxied. You can also pass string and wstring. These I will copy and free. +// +// I do **NOT** copy arrays or strings with size. If you are using these either +// change your interface, or contact me about this feature request. + + + + +class nsProxyObject +{ +public: + nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject); + nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID); + + void AddRef(); + void Release(); + + ~nsProxyObject(); + + nsresult Post( PRUint32 methodIndex, + nsXPTMethodInfo * info, + nsXPTCMiniVariant * params, + nsIInterfaceInfo * interfaceInfo); + + nsresult PostAndWait(nsProxyObjectCallInfo *proxyInfo); + nsISupports* GetRealObject() const { return mRealObject; } + nsIEventQueue* GetQueue() const { return mDestQueue; } + PRInt32 GetProxyType() const { return mProxyType; } + + friend class nsProxyEventObject; +private: + + nsAutoRefCnt mRefCnt; + + PRInt32 mProxyType; + + nsCOMPtr<nsIEventQueue> mDestQueue; /* destination queue */ + + nsCOMPtr<nsISupports> mRealObject; /* the non-proxy object that this event is referring to. + This is a strong ref. */ + nsCOMPtr<nsIEventQueueService> mEventQService; + + nsresult convertMiniVariantToVariant(nsXPTMethodInfo * methodInfo, + nsXPTCMiniVariant * params, + nsXPTCVariant **fullParam, + uint8 *paramCount); + +}; + + +class nsProxyObjectCallInfo +{ +public: + + nsProxyObjectCallInfo(nsProxyObject* owner, + nsXPTMethodInfo *methodInfo, + PRUint32 methodIndex, + nsXPTCVariant* parameterList, + PRUint32 parameterCount, + PLEvent *event); + + ~nsProxyObjectCallInfo(); + + PRUint32 GetMethodIndex() const { return mMethodIndex; } + nsXPTCVariant* GetParameterList() const { return mParameterList; } + PRUint32 GetParameterCount() const { return mParameterCount; } + PLEvent* GetPLEvent() const { return mEvent; } + nsresult GetResult() const { return mResult; } + nsProxyObject* GetProxyObject() const { return mOwner; } + + PRBool GetCompleted(); + void SetCompleted(); + void PostCompleted(); + + void SetResult(nsresult rv) {mResult = rv; } + + nsIEventQueue* GetCallersQueue(); + void SetCallersQueue(nsIEventQueue* queue); + +private: + + nsresult mResult; /* this is the return result of the called function */ + nsXPTMethodInfo *mMethodInfo; + PRUint32 mMethodIndex; /* which method to be called? */ + nsXPTCVariant *mParameterList; /* marshalled in parameter buffer */ + PRUint32 mParameterCount; /* number of params */ + PLEvent *mEvent; /* the current plevent */ + PRInt32 mCompleted; /* is true when the method has been called. */ + + nsCOMPtr<nsIEventQueue> mCallersEventQ; /* this is the eventQ that we must post a message back to + when we are done invoking the method (only PROXY_SYNC). + */ + + nsRefPtr<nsProxyObject> mOwner; /* this is the strong referenced nsProxyObject */ + + void RefCountInInterfacePointers(PRBool addRef); + void CopyStrings(PRBool copy); + +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h new file mode 100644 index 00000000..413a3d0e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */ +/* ***** 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 ***** */ + +#ifndef nsProxyRelease_h__ +#define nsProxyRelease_h__ + +#include "nsIEventQueueService.h" +#include "pratom.h" +#include "prmem.h" + +/** + * Ensures that the delete of a nsISupports object occurs on the target thread. + * + * @param target + * the target thread where the doomed object should be released. + * @param doomed + * the doomed object; the object to be released on the target thread. + * @param alwaysProxy + * normally, if NS_ProxyRelease is called on the target thread, then the + * doomed object will released directly. however, if this parameter is + * true, then a PLEvent will always be posted to the target thread and + * the release will happen when that PLEvent is handled. + */ +NS_COM nsresult NS_ProxyRelease + (nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy=PR_FALSE); + + +#define NS_IMPL_PROXY_RELEASE(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + NS_PRECONDITION(0 != mRefCnt, "dup release"); \ + nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); \ + NS_LOG_RELEASE(this, count, #_class); \ + \ + if (count == 0) \ + { \ + mRefCnt = 1; /* stabilize */ \ + PRBool callDirectly = PR_TRUE; \ + static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); \ + nsCOMPtr<nsIEventQueueService> eventQService \ + = do_GetService(kEventQueueServiceCID); \ + NS_ASSERTION(eventQService, "event queue service is unavailable"); \ + \ + nsCOMPtr<nsIEventQueue> eventQ; \ + if (eventQService) { \ + eventQService->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eventQ)); \ + if (eventQ) \ + eventQ->IsOnCurrentThread(&callDirectly); \ + } \ + \ + if (callDirectly) \ + { \ + NS_RELEASE(this); \ + return 0; \ + } \ + PLEvent *event = new PLEvent; \ + if (event == nsnull) \ + { \ + NS_ASSERTION(0, "Could not create a plevent. Deleting on wrong thread!"); \ + NS_DELETEXPCOM(this); \ + return 0; \ + } \ + \ + PL_InitEvent(event, \ + NS_STATIC_CAST(nsISupports*, this), \ + ReleaseDestructorEventHandler, \ + ReleaseDestructorDestroyHandler); \ + \ + eventQ->PostEvent(event); \ + return 0; \ + } \ + return count; \ +} \ + + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in new file mode 100644 index 00000000..3d46f60b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in @@ -0,0 +1,67 @@ +# +# ***** 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 +REQUIRES = string \ + $(NULL) + + +CPPSRCS = \ + nsProxyEvent.cpp \ + nsProxyEventClass.cpp \ + nsProxyEventObject.cpp \ + nsProxyObjectManager.cpp \ + nsProxyRelease.cpp \ + $(NULL) + +DEFINES += -D_IMPL_NS_COM -DEXPORT_XPTC_API -DEXPORT_XPTI_API + +# No shared lib; Force creation of static lib +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h b/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h new file mode 100644 index 00000000..13755d74 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h @@ -0,0 +1,39 @@ +/* + * DO NOT EDIT. THIS FILE IS GENERATED FROM nsIProxyCreateInstance.idl + */ + +#ifndef __gen_nsIProxyCreateInstance_h__ +#define __gen_nsIProxyCreateInstance_h__ + +#include "nsISupports.h" /* interface nsISupports */ +#include "nsrootidl.h" /* interface nsrootidl */ + +#ifdef XPIDL_JS_STUBS +#include "jsapi.h" +#endif + +/* starting interface: nsIProxyCreateInstance */ + +/* {948c2080-0398-11d3-915e-0000863011c4} */ +#define NS_IPROXYCREATEINSTANCE_IID_STR "948c2080-0398-11d3-915e-0000863011c4" +#define NS_IPROXYCREATEINSTANCE_IID \ + {0x948c2080, 0x0398, 0x11d3, \ + { 0x91, 0x5e, 0x00, 0x00, 0x86, 0x30, 0x11, 0xc4 }} + +class nsIProxyCreateInstance : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPROXYCREATEINSTANCE_IID) + + /* void CreateInstanceByIID (in nsIIDRef cid, in nsISupports aOuter, in nsIIDRef iid, out voidStar result); */ + NS_IMETHOD CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result) = 0; + + /* void CreateInstanceByContractID (in string aContractID, in nsISupports aOuter, in nsIIDRef iid, out voidStar result); */ + NS_IMETHOD CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result) = 0; + +#ifdef XPIDL_JS_STUBS + static NS_EXPORT_(JSObject *) InitJSClass(JSContext *cx); + static NS_EXPORT_(JSObject *) GetJSObject(JSContext *cx, nsIProxyCreateInstance *priv); +#endif +}; + +#endif /* __gen_nsIProxyCreateInstance_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp new file mode 100644 index 00000000..561c2fdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp @@ -0,0 +1,613 @@ +/* -*- 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): + * + * 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 "nsProxyEvent.h" +#include "nsProxyEventPrivate.h" +#include "nsIProxyObjectManager.h" +#include "nsCRT.h" + +#include "pratom.h" +#include "prmem.h" +#include "xptcall.h" + +#include "nsIComponentManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsIEventQueueService.h" +#include "nsIThread.h" + +#include "nsIAtom.h" //hack! Need a way to define a component as threadsafe (ie. sta). + +/** + * 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 + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +static void* PR_CALLBACK EventHandler(PLEvent *self); +static void PR_CALLBACK DestroyHandler(PLEvent *self); +static void* PR_CALLBACK CompletedEventHandler(PLEvent *self); +static void PR_CALLBACK CompletedDestroyHandler(PLEvent *self) ; +static void* PR_CALLBACK ProxyDestructorEventHandler(PLEvent *self); +static void PR_CALLBACK ProxyDestructorDestroyHandler(PLEvent *self) ; + +nsProxyObjectCallInfo::nsProxyObjectCallInfo( nsProxyObject* owner, + nsXPTMethodInfo *methodInfo, + PRUint32 methodIndex, + nsXPTCVariant* parameterList, + PRUint32 parameterCount, + PLEvent *event) +{ + NS_ASSERTION(owner, "No nsProxyObject!"); + NS_ASSERTION(methodInfo, "No nsXPTMethodInfo!"); + NS_ASSERTION(event, "No PLEvent!"); + + mCompleted = 0; + mMethodIndex = methodIndex; + mParameterList = parameterList; + mParameterCount = parameterCount; + mEvent = event; + mMethodInfo = methodInfo; + mCallersEventQ = nsnull; + + mOwner = owner; + + RefCountInInterfacePointers(PR_TRUE); + if (mOwner->GetProxyType() & PROXY_ASYNC) + CopyStrings(PR_TRUE); +} + + +nsProxyObjectCallInfo::~nsProxyObjectCallInfo() +{ + RefCountInInterfacePointers(PR_FALSE); + if (mOwner->GetProxyType() & PROXY_ASYNC) + CopyStrings(PR_FALSE); + + mOwner = nsnull; + + PR_FREEIF(mEvent); + + if (mParameterList) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free((void*) mParameterList); +#else + free( (void*) mParameterList); +#endif +} + +void +nsProxyObjectCallInfo::RefCountInInterfacePointers(PRBool addRef) +{ + for (PRUint32 i = 0; i < mParameterCount; i++) + { + nsXPTParamInfo paramInfo = mMethodInfo->GetParam(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(PRBool copy) +{ + for (PRUint32 i = 0; i < mParameterCount; i++) + { + const nsXPTParamInfo paramInfo = mMethodInfo->GetParam(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: + case nsXPTType::T_WCHAR_STR: + PL_strfree((char*) 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; + } + } + } + } +} + +PRBool +nsProxyObjectCallInfo::GetCompleted() +{ + return (PRBool)mCompleted; +} + +void +nsProxyObjectCallInfo::SetCompleted() +{ + PR_AtomicSet(&mCompleted, 1); +} + +void +nsProxyObjectCallInfo::PostCompleted() +{ + if (mCallersEventQ) + { + PLEvent *event = PR_NEW(PLEvent); + + PL_InitEvent(event, + this, + CompletedEventHandler, + CompletedDestroyHandler); + + mCallersEventQ->PostSynchronousEvent(event, nsnull); + PR_FREEIF(event); + } + else + { + // caller does not have an eventQ? This is an error! + SetCompleted(); + } +} + +nsIEventQueue* +nsProxyObjectCallInfo::GetCallersQueue() +{ + return mCallersEventQ; +} +void +nsProxyObjectCallInfo::SetCallersQueue(nsIEventQueue* queue) +{ + mCallersEventQ = queue; +} + + +nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject) +{ + mEventQService = do_GetService(kEventQueueServiceCID); + + mRealObject = realObject; + mDestQueue = do_QueryInterface(destQueue); + mProxyType = proxyType; +} + + +nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID) +{ + mEventQService = do_GetService(kEventQueueServiceCID); + + nsComponentManager::CreateInstance(aClass, + aDelegate, + aIID, + getter_AddRefs(mRealObject)); + + mDestQueue = do_QueryInterface(destQueue); + mProxyType = proxyType; +} + +nsProxyObject::~nsProxyObject() +{ + // I am worried about order of destruction here. + // do not remove assignments. + + mRealObject = 0; + mDestQueue = 0; +} + + +void +nsProxyObject::AddRef() +{ + PR_AtomicIncrement((PRInt32 *)&mRefCnt); + NS_LOG_ADDREF(this, mRefCnt, "nsProxyObject", sizeof(*this)); +} + +void +nsProxyObject::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + + nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "nsProxyObject"); + + if (count == 0) + { + mRefCnt = 1; /* stabilize */ + + PRBool callDirectly; + mDestQueue->IsOnCurrentThread(&callDirectly); + + if (callDirectly) + { + delete this; + return; + } + + // need to do something special here so that + // the real object will always be deleted on + // the correct thread.. + + PLEvent *event = PR_NEW(PLEvent); + if (event == nsnull) + { + NS_ASSERTION(0, "Could not create a plevent. Leaking nsProxyObject!"); + return; // if this happens we are going to leak. + } + + PL_InitEvent(event, + this, + ProxyDestructorEventHandler, + ProxyDestructorDestroyHandler); + + mDestQueue->PostEvent(event); + } +} + + +nsresult +nsProxyObject::PostAndWait(nsProxyObjectCallInfo *proxyInfo) +{ + if (proxyInfo == nsnull || mEventQService == nsnull) + return NS_ERROR_NULL_POINTER; + + PRBool eventLoopCreated = PR_FALSE; + nsresult rv; + + nsCOMPtr<nsIEventQueue> eventQ; + rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) + { + rv = mEventQService->CreateMonitoredThreadEventQueue(); + eventLoopCreated = PR_TRUE; + if (NS_FAILED(rv)) + return rv; + + rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ)); + } + + if (NS_FAILED(rv)) + return rv; + + proxyInfo->SetCallersQueue(eventQ); + + PLEvent* event = proxyInfo->GetPLEvent(); + if (!event) + return NS_ERROR_NULL_POINTER; + + mDestQueue->PostEvent(event); + + while (! proxyInfo->GetCompleted()) + { + PLEvent *nextEvent; + rv = eventQ->WaitForEvent(&nextEvent); + if (NS_FAILED(rv)) break; + + eventQ->HandleEvent(nextEvent); + } + + if (eventLoopCreated) + { + mEventQService->DestroyThreadEventQueue(); + eventQ = 0; + } + + return rv; +} + + +nsresult +nsProxyObject::convertMiniVariantToVariant(nsXPTMethodInfo *methodInfo, + nsXPTCMiniVariant * params, + nsXPTCVariant **fullParam, + uint8 *outParamCount) +{ + uint8 paramCount = methodInfo->GetParamCount(); + *outParamCount = paramCount; + *fullParam = nsnull; + + if (!paramCount) return NS_OK; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + *fullParam = (nsXPTCVariant*)nsMemory::Alloc(sizeof(nsXPTCVariant) * paramCount); +#else + *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount); +#endif + + if (*fullParam == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + for (int i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i); + if ((mProxyType & PROXY_ASYNC) && paramInfo.IsDipper()) + { + NS_WARNING("Async proxying of out parameters is not supported"); + 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; +} + +nsresult +nsProxyObject::Post( PRUint32 methodIndex, + nsXPTMethodInfo *methodInfo, + nsXPTCMiniVariant * params, + nsIInterfaceInfo *interfaceInfo) +{ + nsresult rv = NS_OK; + + if (! mDestQueue || ! mRealObject) + return NS_ERROR_OUT_OF_MEMORY; + + if (methodInfo->IsNotXPCOM()) + return NS_ERROR_PROXY_INVALID_IN_PARAMETER; + + nsXPTCVariant *fullParam; + uint8 paramCount; + rv = convertMiniVariantToVariant(methodInfo, params, &fullParam, ¶mCount); + + if (NS_FAILED(rv)) + return rv; + + PRBool callDirectly; + + // see if we should call into the method directly. Either it is a QI function call + // (methodIndex == 0), or it is a sync proxy and this code is running on the same thread + // as the destination event queue. + if ( (methodIndex == 0) || + (mProxyType & PROXY_SYNC && + NS_SUCCEEDED(mDestQueue->IsOnCurrentThread(&callDirectly)) && + callDirectly)) + { + + // invoke the magic of xptc... + nsresult rv = XPTC_InvokeByIndex( mRealObject, + methodIndex, + paramCount, + fullParam); + + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return rv; + } + + PLEvent *event = PR_NEW(PLEvent); + + if (event == nsnull) { + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return NS_ERROR_OUT_OF_MEMORY; + } + + nsProxyObjectCallInfo *proxyInfo = new nsProxyObjectCallInfo(this, + methodInfo, + methodIndex, + fullParam, // will be deleted by ~() + paramCount, + event); // will be deleted by ~() + + if (proxyInfo == nsnull) { + PR_DELETE(event); + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return NS_ERROR_OUT_OF_MEMORY; + } + + PL_InitEvent(event, + proxyInfo, + EventHandler, + DestroyHandler); + + if (mProxyType & PROXY_SYNC) + { + rv = PostAndWait(proxyInfo); + + if (NS_SUCCEEDED(rv)) + rv = proxyInfo->GetResult(); + delete proxyInfo; + return rv; + } + + if (mProxyType & PROXY_ASYNC) + { + mDestQueue->PostEvent(event); + return NS_OK; + } + return NS_ERROR_UNEXPECTED; +} + + + +static void DestroyHandler(PLEvent *self) +{ + nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + nsProxyObject* proxyObject = owner->GetProxyObject(); + + if (proxyObject == nsnull) + return; + + if (proxyObject->GetProxyType() & PROXY_ASYNC) + { + delete owner; + } + else + { + owner->PostCompleted(); + } + +} + +static void* EventHandler(PLEvent *self) +{ + nsProxyObjectCallInfo *info = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + NS_ASSERTION(info, "No nsProxyObjectCallInfo!"); + + nsProxyObject *proxyObject = info->GetProxyObject(); + + if (proxyObject) + { + // invoke the magic of xptc... + nsresult rv = XPTC_InvokeByIndex( proxyObject->GetRealObject(), + info->GetMethodIndex(), + info->GetParameterCount(), + info->GetParameterList()); + info->SetResult(rv); + } + else + { + info->SetResult(NS_ERROR_OUT_OF_MEMORY); + } + return NULL; +} + +static void CompletedDestroyHandler(PLEvent *self) +{ +} + +static void* CompletedEventHandler(PLEvent *self) +{ + nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + owner->SetCompleted(); + return nsnull; +} + +static void* ProxyDestructorEventHandler(PLEvent *self) +{ + nsProxyObject* owner = (nsProxyObject*) PL_GetEventOwner(self); + NS_DELETEXPCOM(owner); + return nsnull; +} + +static void ProxyDestructorDestroyHandler(PLEvent *self) +{ + PR_DELETE(self); +} + diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp new file mode 100644 index 00000000..8e221afa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp @@ -0,0 +1,367 @@ +/* -*- 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 ***** */ + + +#include "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" + +#include "nsMemory.h" +#include "nsHashtable.h" + +#include "nsAutoLock.h" +#include "nsIInterfaceInfoManager.h" +#include "xptcall.h" + +// LIFETIME_CACHE will cache class for the entire cyle of the application. +#define LIFETIME_CACHE + +static uint32 zero_methods_descriptor; + + +/* ssc@netscape.com wishes he could get rid of this instance of + * |NS_DEFINE_IID|, but |ProxyEventClassIdentity| is not visible from + * here. + */ +static NS_DEFINE_IID(kProxyObject_Identity_Class_IID, NS_PROXYEVENT_IDENTITY_CLASS_IID); + +////////////////////////////////////////////////////////////////////////////////////////////////// +// nsProxyEventClass +////////////////////////////////////////////////////////////////////////////////////////////////// +NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyEventClass, nsProxyEventClass) + +// static +nsProxyEventClass* +nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID) +{ + /* find in our hash table */ + + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) return nsnull; + + // dont need to lock the map, because this is only called + // by nsProxyEventClass::GetNewOrUsed which locks it for us. + + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap == nsnull) + { + return nsnull; + } + + nsProxyEventClass* clazz = nsnull; + nsIDKey key(aIID); + +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s\n", iidStr); + nsCRT::free(iidStr); +#endif + + clazz = (nsProxyEventClass*) iidToClassMap->Get(&key); + if(clazz) + { + NS_ADDREF(clazz); +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s hit\n", iidStr); + nsCRT::free(iidStr); +#endif + } + else + { + nsCOMPtr<nsIInterfaceInfoManager> iimgr = getter_AddRefs(XPTI_GetInterfaceInfoManager()); + if(iimgr) + { + nsCOMPtr<nsIInterfaceInfo> info; + if(NS_SUCCEEDED(iimgr->GetInfoForIID(&aIID, getter_AddRefs(info)))) + { + /* + Check to see if isISupportsDescendent + */ + nsCOMPtr<nsIInterfaceInfo> oldest = info; + nsCOMPtr<nsIInterfaceInfo> parent; + + while(NS_SUCCEEDED(oldest->GetParent(getter_AddRefs(parent)))&& + parent) + { + oldest = parent; + } + + PRBool isISupportsDescendent = PR_FALSE; + nsID* iid; + if(NS_SUCCEEDED(oldest->GetInterfaceIID(&iid))) + { + isISupportsDescendent = iid->Equals(NS_GET_IID(nsISupports)); + nsMemory::Free(iid); + } + + NS_ASSERTION(isISupportsDescendent, "!isISupportsDescendent"); + + if (isISupportsDescendent) + { + clazz = new nsProxyEventClass(aIID, info); + if(!clazz->mDescriptors) + NS_RELEASE(clazz); // sets clazz to NULL + } + } + } + } + return clazz; +} + +nsProxyEventClass::nsProxyEventClass() +{ + NS_WARNING("This constructor should never be called"); +} + +nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo) +: mIID(aIID), + mDescriptors(NULL) +{ + NS_ADDREF_THIS(); + + mInfo = aInfo; + + /* add use to the used classes */ + nsIDKey key(aIID); + + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) return; + // dont need to lock the map, because this is only called + // by GetNewOrUsed which locks it for us. + + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap != nsnull) + { + iidToClassMap->Put(&key, this); +#ifdef LIFETIME_CACHE + // extra addref to hold it in the cache + NS_ADDREF_THIS(); +#endif +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s put\n", iidStr); + nsCRT::free(iidStr); +#endif + } + + 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; + + if (nsProxyObjectManager::IsManagerShutdown()) + return; + +#ifndef LIFETIME_CACHE + nsIDKey key(mIID); + + nsCOMPtr<nsProxyObjectManager> manager = getter_AddRefs(nsProxyObjectManager::GetInstance()); + if (manager == nsnull) return; + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap != nsnull) + { + iidToClassMap->Remove(&key); +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = mIID.ToString(); + printf("GetNewOrUsedClass %s remove\n", iidStr); + nsCRT::free(iidStr); +#endif + } +#endif +} + +nsresult +nsProxyEventClass::CallQueryInterfaceOnProxy(nsProxyEventObject* self, REFNSIID aIID, nsProxyEventObject** aInstancePtr) +{ + NS_PRECONDITION(aInstancePtr, "Requires non-null result"); + + nsresult rv; + + *aInstancePtr = nsnull; // in case of error. + + + // The functions we will call: QueryInterface(REFNSIID aIID, void** aInstancePtr) + + nsXPTCMiniVariant var[2]; + + var[0].val.p = (void*)&aIID; + var[1].val.p = (void*)aInstancePtr; + + nsCOMPtr<nsIInterfaceInfo> interfaceInfo; + const nsXPTMethodInfo *mi; + + nsCOMPtr<nsIInterfaceInfoManager> iim = getter_AddRefs(XPTI_GetInterfaceInfoManager()); + + if (!iim) return NS_NOINTERFACE; + iim->GetInfoForName("nsISupports", getter_AddRefs(interfaceInfo)); + interfaceInfo->GetMethodInfo(0, &mi); // 0 is QueryInterface + + rv = self->CallMethod(0, mi, var); + + if (NS_SUCCEEDED(rv)) + { + nsISupports *aIdentificationObject; + + rv = (*aInstancePtr)->QueryInterface(kProxyObject_Identity_Class_IID, (void**)&aIdentificationObject); + + if (NS_FAILED(rv)) + { + // okay, aInstancePtr was not a proxy. Lets create one. + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) + { + NS_IF_RELEASE((*aInstancePtr)); + return NS_ERROR_FAILURE; + } + + rv = manager->GetProxyForObject(self->GetQueue(), + aIID, + self->GetRealObject(), + self->GetProxyType(), + (void**) &aIdentificationObject); + } + + NS_IF_RELEASE((*aInstancePtr)); + (*aInstancePtr) = NS_STATIC_CAST(nsProxyEventObject*, aIdentificationObject); + } + return rv; +} + + +/***************************************************************************/ +// This 'ProxyEventClassIdentity' class and singleton allow us to figure out if +// any given nsISupports* is implemented by a nsProxy object. This is done +// using a QueryInterface call on the interface pointer with our ID. If +// that call returns NS_OK and the pointer is to a nsProxyEventObject. It must +// be released when done. + +// NS_PROXYEVENT_IDENTITY_CLASS_IID defined in nsProxyEventPrivate.h +class ProxyEventClassIdentity +{ + // no instance methods... +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IDENTITY_CLASS_IID) + + static void* GetSingleton() + { + static ProxyEventClassIdentity* singleton = NULL; + if(!singleton) + singleton = new ProxyEventClassIdentity(); + return (void*) singleton; + } +}; + +NS_IMETHODIMP +nsProxyEventClass::DelegatedQueryInterface(nsProxyEventObject* self, + REFNSIID aIID, + void** aInstancePtr) +{ + + if(aIID.Equals(NS_GET_IID(ProxyEventClassIdentity))) + { + *aInstancePtr = NS_STATIC_CAST(void*, self); + NS_ADDREF(self); + return NS_OK; + } + + nsProxyEventObject* sibling; + { + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsAutoMonitor mon(manager->GetMonitor()); + + // This includes checking for nsISupports and the iid of self. + // And it also checks for other wrappers that have been constructed + // for this object. + if(nsnull != (sibling = self->LockedFind(aIID))) + { + NS_ADDREF(sibling); + *aInstancePtr = (void*) sibling; + return NS_OK; + } + + // check if asking for an interface that we inherit from + nsCOMPtr<nsIInterfaceInfo> current = GetInterfaceInfo(); + nsCOMPtr<nsIInterfaceInfo> parent; + + while(NS_SUCCEEDED(current->GetParent(getter_AddRefs(parent))) && parent) + { + current = parent; + + nsIID* iid; + if(NS_SUCCEEDED(current->GetInterfaceIID(&iid)) && iid) + { + PRBool found = aIID.Equals(*iid); + nsMemory::Free(iid); + if(found) + { + *aInstancePtr = (void*) self; + NS_ADDREF(self); + return NS_OK; + } + } + } + } + + return CallQueryInterfaceOnProxy(self, aIID, (nsProxyEventObject**)aInstancePtr); +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp new file mode 100644 index 00000000..d529fc05 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp @@ -0,0 +1,555 @@ +/* -*- 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 ***** */ + +#include "prprf.h" +#include "prmem.h" + +#include "nscore.h" +#include "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsHashtable.h" + +#include "nsIInterfaceInfoManager.h" +#include "xptcall.h" + +#include "nsAutoLock.h" + +static NS_DEFINE_IID(kProxyObject_Identity_Class_IID, NS_PROXYEVENT_IDENTITY_CLASS_IID); + + +//////////////////////////////////////////////////////////////////////////////// + +class nsProxyEventKey : public nsHashKey +{ +public: + nsProxyEventKey(void* rootObjectKey, void* destQueueKey, PRInt32 proxyType) + : mRootObjectKey(rootObjectKey), mDestQueueKey(destQueueKey), mProxyType(proxyType) { + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mRootObjectKey) ^ + NS_PTR_TO_INT32(mDestQueueKey) ^ mProxyType; + } + + PRBool Equals(const nsHashKey *aKey) const { + const nsProxyEventKey* other = (const nsProxyEventKey*)aKey; + return mRootObjectKey == other->mRootObjectKey + && mDestQueueKey == other->mDestQueueKey + && mProxyType == other->mProxyType; + } + + nsHashKey *Clone() const { + return new nsProxyEventKey(mRootObjectKey, mDestQueueKey, mProxyType); + } + +protected: + void* mRootObjectKey; + void* mDestQueueKey; + PRInt32 mProxyType; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef DEBUG_xpcom_proxy +static PRMonitor* mon = nsnull; +static PRUint32 totalProxyObjects = 0; +static PRUint32 outstandingProxyObjects = 0; + +void +nsProxyEventObject::DebugDump(const char * message, PRUint32 hashKey) +{ + + if (mon == nsnull) + { + mon = PR_NewMonitor(); + } + + PR_EnterMonitor(mon); + + if (message) + { + printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-\n"); + printf("%s\n", message); + + if(strcmp(message, "Create") == 0) + { + totalProxyObjects++; + outstandingProxyObjects++; + } + else if(strcmp(message, "Delete") == 0) + { + outstandingProxyObjects--; + } + } + printf("nsProxyEventObject @ %x with mRefCnt = %d\n", this, mRefCnt); + + PRBool isRoot = mRoot == nsnull; + printf("%s wrapper around @ %x\n", isRoot ? "ROOT":"non-root\n", GetRealObject()); + + nsCOMPtr<nsISupports> rootObject = do_QueryInterface(mProxyObject->mRealObject); + nsCOMPtr<nsISupports> rootQueue = do_QueryInterface(mProxyObject->mDestQueue); + nsProxyEventKey key(rootObject, rootQueue, mProxyObject->mProxyType); + printf("Hashkey: %d\n", key.HashCode()); + + char* name; + GetClass()->GetInterfaceInfo()->GetName(&name); + printf("interface name is %s\n", name); + if(name) + nsMemory::Free(name); + char * iid = GetClass()->GetProxiedIID().ToString(); + printf("IID number is %s\n", iid); + delete iid; + printf("nsProxyEventClass @ %x\n", mClass); + + if(mNext) + { + if(isRoot) + { + printf("Additional wrappers for this object...\n"); + } + mNext->DebugDump(nsnull, 0); + } + + printf("[proxyobjects] %d total used in system, %d outstading\n", totalProxyObjects, outstandingProxyObjects); + + if (message) + printf("-=-=-=-=-=-=-=-=-=-=-=-=-\n"); + + PR_ExitMonitor(mon); +} +#endif + + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// +// nsProxyEventObject +// +////////////////////////////////////////////////////////////////////////////////////////////////// +nsProxyEventObject* +nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports *aObj, + REFNSIID aIID) +{ + nsresult rv; + + if (!aObj) + return nsnull; + + nsISupports* rawObject = aObj; + + // + // make sure that the object pass in is not a proxy... + // if the object *is* a proxy, then be nice and build the proxy + // for the real object... + // + nsCOMPtr<nsProxyEventObject> identificationObject; + + rv = rawObject->QueryInterface(kProxyObject_Identity_Class_IID, + getter_AddRefs(identificationObject)); + if (NS_SUCCEEDED(rv)) { + // + // ATTENTION!!!! + // + // If you are hitting any of the assertions in this block of code, + // please contact dougt@netscape.com. + // + + // if you hit this assertion, you might want to check out how + // you are using proxies. You shouldn't need to be creating + // a proxy from a proxy. -- dougt@netscape.com + NS_ASSERTION(0, "Someone is building a proxy from a proxy"); + + NS_ASSERTION(identificationObject, "where did my identification object go!"); + if (!identificationObject) { + return nsnull; + } + + // someone is asking us to create a proxy for a proxy. Lets get + // the real object and build aproxy for that! + rawObject = identificationObject->GetRealObject(); + + NS_ASSERTION(rawObject, "where did my real object go!"); + if (!rawObject) { + return nsnull; + } + } + + // + // Get the root nsISupports of the |real| object. + // + nsCOMPtr<nsISupports> rootObject; + + rootObject = do_QueryInterface(rawObject, &rv); + if (NS_FAILED(rv) || !rootObject) { + NS_ASSERTION(NS_FAILED(rv), "where did my root object go!"); + return nsnull; + } + + // Get the root nsISupports of the event queue... This is used later, + // as part of the hashtable key... + nsCOMPtr<nsISupports> destQRoot = do_QueryInterface(destQueue, &rv); + if (NS_FAILED(rv) || !destQRoot) { + return nsnull; + } + + // + // Enter the proxy object creation lock. + // + // This lock protects thev linked list which chains proxies together + // (ie. mRoot and mNext) and ensures that there is no hashtable contention + // between the time that a proxy is looked up (and not found) in the + // hashtable and then added... + // + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (!manager) { + return nsnull; + } + + nsAutoMonitor mon(manager->GetMonitor()); + + // Get the hash table containing root proxy objects... + nsHashtable *realToProxyMap = manager->GetRealObjectToProxyObjectMap(); + if (!realToProxyMap) { + return nsnull; + } + + // Now, lookup the root nsISupports of the raw object in the hashtable + // The key consists of 3 pieces of information: + // - root nsISupports of the raw object + // - event queue of the current thread + // - type of proxy being constructed... + // + nsProxyEventKey rootkey(rootObject.get(), destQRoot.get(), proxyType); + + nsCOMPtr<nsProxyEventObject> rootProxy; + nsCOMPtr<nsProxyEventObject> proxy; + nsProxyEventObject* peo; + + // find in our hash table + rootProxy = (nsProxyEventObject*) realToProxyMap->Get(&rootkey); + + if(rootProxy) { + // + // At least one proxy has already been created for this raw object... + // + // Look for the specific interface proxy in the list off of + // the root proxy... + // + peo = rootProxy->LockedFind(aIID); + + if(peo) { + // An existing proxy is available... So use it. + NS_ADDREF(peo); + return peo; + } + } + else { + // build the root proxy + nsCOMPtr<nsProxyEventClass> rootClazz; + + rootClazz = dont_AddRef(nsProxyEventClass::GetNewOrUsedClass( + NS_GET_IID(nsISupports))); + if (!rootClazz) { + return nsnull; + } + + peo = new nsProxyEventObject(destQueue, + proxyType, + rootObject, + rootClazz, + nsnull); + if(!peo) { + // Ouch... Out of memory! + return nsnull; + } + + // Add this root proxy into the hash table... + realToProxyMap->Put(&rootkey, peo); + + if(aIID.Equals(NS_GET_IID(nsISupports))) { + // + // Since the requested proxy is for the nsISupports interface of + // the raw object, use the new root proxy as the specific proxy + // too... + // + NS_ADDREF(peo); + return peo; + } + + // This assignment is an owning reference to the new ProxyEventObject. + // So, it will automatically get deleted if any subsequent early + // returns are taken... + rootProxy = do_QueryInterface(peo); + } + + // + // at this point we have a proxy for the root nsISupports (ie. rootProxy) + // but we need to build the specific proxy for this interface... + // + NS_ASSERTION(rootProxy, "What happened to the root proxy!"); + + // Get a class for this IID. + nsCOMPtr<nsProxyEventClass> proxyClazz; + + proxyClazz = dont_AddRef(nsProxyEventClass::GetNewOrUsedClass(aIID)); + if(!proxyClazz) { + return nsnull; + } + + // Get the raw interface for this IID + nsCOMPtr<nsISupports> rawInterface; + + rv = rawObject->QueryInterface(aIID, getter_AddRefs(rawInterface)); + if (NS_FAILED(rv) || !rawInterface) { + NS_ASSERTION(NS_FAILED(rv), "where did my rawInterface object go!"); + return nsnull; + } + + peo = new nsProxyEventObject(destQueue, + proxyType, + rawInterface, + proxyClazz, + rootProxy); + if (!peo) { + // Ouch... Out of memory! + return nsnull; + } + + // + // Add the new specific proxy to the head of the list of proxies hanging + // off of the rootProxy... + // + peo->mNext = rootProxy->mNext; + rootProxy->mNext = peo; + + NS_ADDREF(peo); + return peo; + +} + +nsProxyEventObject* nsProxyEventObject::LockedFind(REFNSIID aIID) +{ + if(aIID.Equals(mClass->GetProxiedIID())) { + return this; + } + + if(aIID.Equals(NS_GET_IID(nsISupports))) { + return this; + } + + nsProxyEventObject* cur = (mRoot ? mRoot : mNext); + while(cur) { + if(aIID.Equals(cur->GetClass()->GetProxiedIID())) { + return cur; + } + cur = cur->mNext; + } + + return nsnull; +} + +nsProxyEventObject::nsProxyEventObject() +: mNext(nsnull) +{ + NS_WARNING("This constructor should never be called"); +} + +nsProxyEventObject::nsProxyEventObject(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports* aObj, + nsProxyEventClass* aClass, + nsProxyEventObject* root) + : mClass(aClass), + mRoot(root), + mNext(nsnull) +{ + NS_IF_ADDREF(mRoot); + + mProxyObject = new nsProxyObject(destQueue, proxyType, aObj); + +#ifdef DEBUG_xpcom_proxy + DebugDump("Create", 0); +#endif +} + +nsProxyEventObject::~nsProxyEventObject() +{ +#ifdef DEBUG_xpcom_proxy + DebugDump("Delete", 0); +#endif + if (mRoot) { + // + // This proxy is not the root interface so it must be removed + // from the chain of proxies... + // + nsProxyEventObject* cur = mRoot; + while(cur) { + if(cur->mNext == this) { + cur->mNext = mNext; + mNext = nsnull; + break; + } + cur = cur->mNext; + } + NS_ASSERTION(cur, "failed to find wrapper in its own chain"); + } + else { + // + // This proxy is for the root interface. Each proxy in the chain + // has a strong reference to the root... So, when its refcount goes + // to zero, it safe to remove it because no proxies are in its chain. + // + if (! nsProxyObjectManager::IsManagerShutdown()) { + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsHashtable *realToProxyMap = manager->GetRealObjectToProxyObjectMap(); + + NS_ASSERTION(!mNext, "There are still proxies in the chain!"); + + if (realToProxyMap != nsnull) { + nsCOMPtr<nsISupports> rootObject = do_QueryInterface(mProxyObject->mRealObject); + nsCOMPtr<nsISupports> rootQueue = do_QueryInterface(mProxyObject->mDestQueue); + nsProxyEventKey key(rootObject, rootQueue, mProxyObject->mProxyType); +#ifdef DEBUG_dougt + void* value = +#endif + realToProxyMap->Remove(&key); +#ifdef DEBUG_dougt + NS_ASSERTION(value, "failed to remove from realToProxyMap"); +#endif + } + } + } + + // I am worried about ordering. + // do not remove assignments. + mProxyObject = nsnull; + mClass = nsnull; + NS_IF_RELEASE(mRoot); +} + +// +// nsISupports implementation... +// + +NS_IMPL_THREADSAFE_ADDREF(nsProxyEventObject) + +NS_IMETHODIMP_(nsrefcnt) +nsProxyEventObject::Release(void) +{ + // + // Be pessimistic about whether the manager or even the monitor exist... + // This is to protect against shutdown issues where a proxy object could + // be destroyed after (or while) the Proxy Manager is being destroyed... + // + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsAutoMonitor mon(manager ? manager->GetMonitor() : nsnull); + + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + // Decrement atomically - in case the Proxy Object Manager has already + // been deleted and the monitor is unavailable... + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "nsProxyEventObject"); + if (0 == count) { + mRefCnt = 1; /* stabilize */ + // + // Remove the proxy from the hashtable (if necessary) or its + // proxy chain. This must be done inside of the proxy lock to + // prevent GetNewOrUsedProxy(...) from ressurecting it... + // + NS_DELETEXPCOM(this); + return 0; + } + return count; +} + +NS_IMETHODIMP +nsProxyEventObject::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if( aIID.Equals(GetIID()) ) + { + *aInstancePtr = NS_STATIC_CAST(nsISupports*, this); + NS_ADDREF_THIS(); + return NS_OK; + } + + return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr); +} + +// +// nsXPTCStubBase implementation... +// + +NS_IMETHODIMP +nsProxyEventObject::GetInterfaceInfo(nsIInterfaceInfo** info) +{ + NS_ENSURE_ARG_POINTER(info); + + *info = mClass->GetInterfaceInfo(); + + NS_ASSERTION(*info, "proxy class without interface"); + if (!*info) { + return NS_ERROR_UNEXPECTED; + } + + NS_ADDREF(*info); + return NS_OK; +} + +NS_IMETHODIMP +nsProxyEventObject::CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant * params) +{ + nsresult rv; + + if (mProxyObject) { + rv = mProxyObject->Post(methodIndex, + (nsXPTMethodInfo*)info, + params, + mClass->GetInterfaceInfo()); + } else { + rv = NS_ERROR_NULL_POINTER; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h new file mode 100644 index 00000000..ee34927e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h @@ -0,0 +1,201 @@ +/* -*- 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 "nscore.h" +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsHashtable.h" + +#include "plevent.h" +#include "xptcall.h" // defines nsXPTCVariant +#include "nsIEventQueue.h" + +#include "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" + +class nsProxyEventObject; +class nsProxyEventClass; + +#define NS_PROXYEVENT_CLASS_IID \ +{ 0xeea90d42, \ + 0xb059, \ + 0x11d2, \ + {0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33}\ +} + +#define NS_PROXYEVENT_IDENTITY_CLASS_IID \ +{ 0xeea90d45, 0xb059, 0x11d2, \ + { 0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33 } } + + +#define NS_PROXYEVENT_OBJECT_IID \ +{ 0xec373590, 0x9164, 0x11d3, \ +{0x8c, 0x73, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74} } + + +class nsProxyEventClass : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_CLASS_IID) + static nsProxyEventClass* GetNewOrUsedClass(REFNSIID aIID); + + NS_IMETHOD DelegatedQueryInterface( nsProxyEventObject* self, + REFNSIID aIID, + void** aInstancePtr); + + + nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo;} + const nsIID& GetProxiedIID() const {return mIID; } +protected: + nsProxyEventClass(); + nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo); + +private: + ~nsProxyEventClass(); + + nsIID mIID; + nsCOMPtr<nsIInterfaceInfo> mInfo; + uint32* mDescriptors; + + nsresult CallQueryInterfaceOnProxy(nsProxyEventObject* self, + REFNSIID aIID, + nsProxyEventObject** aInstancePtr); +}; + + + +class nsProxyEventObject : public nsXPTCStubBase +{ +public: + + NS_DECL_ISUPPORTS + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_OBJECT_IID) + + static nsProxyEventObject* GetNewOrUsedProxy(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports *aObj, + REFNSIID aIID); + + + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info); + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, const nsXPTMethodInfo* info, nsXPTCMiniVariant* params); + + + nsProxyEventClass* GetClass() const { return mClass; } + nsIEventQueue* GetQueue() const { return (mProxyObject ? mProxyObject->GetQueue() : nsnull);} + nsISupports* GetRealObject() const { return (mProxyObject ? mProxyObject->GetRealObject(): nsnull);} + PRInt32 GetProxyType() const { return (mProxyObject ? mProxyObject->GetProxyType() : nsnull);} + + nsProxyEventObject(); + nsProxyEventObject(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports* aObj, + nsProxyEventClass* aClass, + nsProxyEventObject* root); + + nsProxyEventObject* LockedFind(REFNSIID aIID); + +#ifdef DEBUG_xpcom_proxy + void DebugDump(const char * message, PRUint32 hashKey); +#endif + +private: + ~nsProxyEventObject(); + +protected: + void LockedRemoveProxy(); + +protected: + nsCOMPtr<nsProxyEventClass> mClass; + nsRefPtr<nsProxyObject> mProxyObject; + + // Owning reference... + nsProxyEventObject *mRoot; + + // Weak reference... + nsProxyEventObject *mNext; +}; + + + + +//////////////////////////////////////////////////////////////////////////////// +// nsProxyObjectManager +//////////////////////////////////////////////////////////////////////////////// + +class nsProxyObjectManager: public nsIProxyObjectManager +{ +public: + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROXYOBJECTMANAGER + + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + nsProxyObjectManager(); + + static nsProxyObjectManager *GetInstance(); + static PRBool IsManagerShutdown(); + + static void Shutdown(); + + nsHashtable* GetRealObjectToProxyObjectMap() { return &mProxyObjectMap;} + nsHashtable* GetIIDToProxyClassMap() { return &mProxyClassMap; } + + PRMonitor* GetMonitor() const { return mProxyCreationMonitor; } + +private: + ~nsProxyObjectManager(); + + static nsProxyObjectManager* mInstance; + nsHashtable mProxyObjectMap; + nsHashtable mProxyClassMap; + PRMonitor *mProxyCreationMonitor; +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp new file mode 100644 index 00000000..0602bcd7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp @@ -0,0 +1,322 @@ +/* -*- 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 "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsIProxyCreateInstance.h" + +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsCOMPtr.h" + +#include "nsIEventQueueService.h" +#include "nsIThread.h" + + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +/***************************************************************************/ +/* nsProxyCreateInstance */ +/* This private class will allow us to create Instances on another thread */ +/***************************************************************************/ +class nsProxyCreateInstance : public nsIProxyCreateInstance +{ + NS_DECL_ISUPPORTS + NS_IMETHOD CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result); + NS_IMETHOD CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result); + + nsProxyCreateInstance() {} + +private: + ~nsProxyCreateInstance() {} +}; + +NS_IMPL_ISUPPORTS1(nsProxyCreateInstance, nsIProxyCreateInstance) + +NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result) +{ + return nsComponentManager::CreateInstance( cid, + aOuter, + iid, + result); +} + + +NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result) +{ + return nsComponentManager::CreateInstance( aContractID, + aOuter, + iid, + result); +} + +///////////////////////////////////////////////////////////////////////// +// nsProxyObjectManager +///////////////////////////////////////////////////////////////////////// + +nsProxyObjectManager* nsProxyObjectManager::mInstance = nsnull; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyObjectManager, nsIProxyObjectManager) + +nsProxyObjectManager::nsProxyObjectManager() + : mProxyObjectMap(256, PR_TRUE), + mProxyClassMap(256, PR_TRUE) +{ + mProxyCreationMonitor = PR_NewMonitor(); +} + +static PRBool PurgeProxyClasses(nsHashKey *aKey, void *aData, void* closure) +{ + nsProxyEventClass* ptr = NS_REINTERPRET_CAST(nsProxyEventClass*, aData); + NS_RELEASE(ptr); + return PR_TRUE; +} + +nsProxyObjectManager::~nsProxyObjectManager() +{ + mProxyClassMap.Reset((nsHashtableEnumFunc)PurgeProxyClasses, nsnull); + + if (mProxyCreationMonitor) { + PR_DestroyMonitor(mProxyCreationMonitor); + } + + nsProxyObjectManager::mInstance = nsnull; +} + +PRBool +nsProxyObjectManager::IsManagerShutdown() +{ + if (mInstance) + return PR_FALSE; + return PR_TRUE; +} + +nsProxyObjectManager * +nsProxyObjectManager::GetInstance() +{ + if (! mInstance) + { + mInstance = new nsProxyObjectManager(); + } + return mInstance; +} + + +void +nsProxyObjectManager::Shutdown() +{ + mInstance = nsnull; +} + + +// Helpers +NS_IMETHODIMP +nsProxyObjectManager::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + nsProxyObjectManager *proxyObjectManager = GetInstance(); + + if (proxyObjectManager == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + return proxyObjectManager->QueryInterface(aIID, aInstancePtr); +} + + +NS_IMETHODIMP +nsProxyObjectManager::GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject) +{ + if (!aObj) return NS_ERROR_NULL_POINTER; + if (!aProxyObject) return NS_ERROR_NULL_POINTER; + + nsresult rv; + nsCOMPtr<nsIEventQueue> postQ; + + + *aProxyObject = nsnull; + + // check to see if the destination Q is a special case. + + nsCOMPtr<nsIEventQueueService> eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = eventQService->ResolveEventQueue(destQueue, getter_AddRefs(postQ)); + if (NS_FAILED(rv)) + return rv; + + // check to see if the eventQ is on our thread. If so, just return the real object. + + if (postQ && !(proxyType & PROXY_ASYNC) && !(proxyType & PROXY_ALWAYS)) + { + PRBool aResult; + postQ->IsOnCurrentThread(&aResult); + + if (aResult) + { + return aObj->QueryInterface(aIID, aProxyObject); + } + } + + // check to see if proxy is there or not. + *aProxyObject = nsProxyEventObject::GetNewOrUsedProxy(postQ, proxyType, aObj, aIID); + + if (*aProxyObject == nsnull) + return NS_ERROR_NO_INTERFACE; //fix error code? + + return NS_OK; +} + + +NS_IMETHODIMP +nsProxyObjectManager::GetProxy( nsIEventQueue *destQueue, + const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + PRInt32 proxyType, + void** aProxyObject) +{ + if (!aProxyObject) return NS_ERROR_NULL_POINTER; + *aProxyObject = nsnull; + + // 1. Create a proxy for creating an instance on another thread. + + nsIProxyCreateInstance* ciProxy = nsnull; + + nsProxyCreateInstance* ciObject = new nsProxyCreateInstance(); + + if (ciObject == nsnull) + return NS_ERROR_NULL_POINTER; + + NS_ADDREF(ciObject); + + nsresult rv = GetProxyForObject(destQueue, + NS_GET_IID(nsIProxyCreateInstance), + ciObject, + PROXY_SYNC, + (void**)&ciProxy); + + if (NS_FAILED(rv)) + { + NS_RELEASE(ciObject); + return rv; + } + + // 2. now create a new instance of the request object via our proxy. + + nsISupports* aObj; + + rv = ciProxy->CreateInstanceByIID(aClass, + aDelegate, + aIID, + (void**)&aObj); + + + // 3. Delete the create instance proxy and its real object. + + NS_RELEASE(ciProxy); + NS_RELEASE(ciObject); + + // 4. Check to see if creating the requested instance failed. + if ( NS_FAILED(rv)) + { + return rv; + } + + // 5. Now create a proxy object for the requested object. + + rv = GetProxyForObject(destQueue, aIID, aObj, proxyType, aProxyObject); + + // 6. release ownership of aObj so that aProxyObject owns it. + + NS_RELEASE(aObj); + + // 7. return the error returned from GetProxyForObject. Either way, we our out of here. + + return rv; +} + +/** + * 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. + */ +NS_COM nsresult +NS_GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject) +{ + static NS_DEFINE_CID(proxyObjMgrCID, NS_PROXYEVENT_MANAGER_CID); + + nsresult rv; // temp for return value + + // get the proxy object manager + // + nsCOMPtr<nsIProxyObjectManager> proxyObjMgr = + do_GetService(proxyObjMgrCID, &rv); + + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + // and try to get the proxy object + // + return proxyObjMgr->GetProxyForObject(destQueue, aIID, aObj, + proxyType, aProxyObject); +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp new file mode 100644 index 00000000..3ceeb667 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp @@ -0,0 +1,55 @@ +#include "nsProxyRelease.h" + +PR_STATIC_CALLBACK(void*) +HandleProxyReleaseEvent(PLEvent *self) +{ + nsISupports* owner = (nsISupports*) self->owner; + NS_RELEASE(owner); + return nsnull; +} + +PR_STATIC_CALLBACK(void) +DestroyProxyReleaseEvent(PLEvent *self) +{ + delete self; +} + +NS_COM nsresult +NS_ProxyRelease(nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy) +{ + nsresult rv; + + if (!target) { + NS_RELEASE(doomed); + return NS_OK; + } + + if (!alwaysProxy) { + PRBool onCurrentThread = PR_FALSE; + rv = target->IsOnCurrentThread(&onCurrentThread); + if (NS_SUCCEEDED(rv) && onCurrentThread) { + NS_RELEASE(doomed); + return NS_OK; + } + } + + PLEvent *ev = new PLEvent; + if (!ev) { + // we do not release doomed here since it may cause a delete on the + // wrong thread. better to leak than crash. + return NS_ERROR_OUT_OF_MEMORY; + } + + PL_InitEvent(ev, doomed, + HandleProxyReleaseEvent, + DestroyProxyReleaseEvent); + + rv = target->PostEvent(ev); + if (NS_FAILED(rv)) { + NS_WARNING("failed to post proxy release event"); + PL_DestroyEvent(ev); + // again, it is better to leak the doomed object than risk crashing as + // a result of deleting it on the wrong thread. + } + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore new file mode 100644 index 00000000..b7457ff6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile +proxytests diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in new file mode 100644 index 00000000..e5e908f1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** 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 = proxytest +REQUIRES = $(NULL) + +CPPSRCS = proxytests.cpp +XPIDLSRCS = nsITestProxy.idl + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl b/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl new file mode 100644 index 00000000..98cb3f94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl @@ -0,0 +1,9 @@ +#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); +}; diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp b/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp new file mode 100644 index 00000000..20693463 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp @@ -0,0 +1,553 @@ +/* -*- 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 "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" + +#include "nscore.h" +#include "nspr.h" +#include "prmon.h" + +#include "nsITestProxy.h" + +#include "nsIProxyObjectManager.h" +#include "nsIEventQueueService.h" + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +/***************************************************************************/ +/* 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) +{ + printf("Thread (%d) Test Called successfully! Party on...\n", p1); + *retval = p1+p2; + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo::Test2() +{ + printf("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); + printf("\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) +{ +printf("calling back to caller!\n\n"); + + nsIProxyObjectManager* manager; + nsITestProxy * proxyObject; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + manager->GetProxyForObject((nsIEventQueue*)p1, NS_GET_IID(nsITestProxy), this, PROXY_SYNC, (void**)&proxyObject); + proxyObject->Test3(nsnull, nsnull); + + printf("Deleting Proxy Object\n"); + NS_RELEASE(proxyObject); + + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo2::Test2() +{ + printf("nsTestXPCFoo2::Test2() called\n"); + + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo2::Test3(nsISupports *p1, nsISupports **p2) +{ + printf("Got called"); + return NS_OK; +} + + + +typedef struct _ArgsStruct +{ + nsIEventQueue* queue; + PRInt32 threadNumber; +}ArgsStruct; + + + +// This will create two objects both descendants of a single IID. +void TestCase_TwoClassesOneInterface(void *arg) +{ + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsITestProxy *proxyObject2; + + nsTestXPCFoo* foo = new nsTestXPCFoo(); + nsTestXPCFoo2* foo2 = new nsTestXPCFoo2(); + + PR_ASSERT(foo); + PR_ASSERT(foo2); + + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo2, 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 +} + + + +void TestCase_NestedLoop(void *arg) +{ + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo2* foo = new nsTestXPCFoo2(); + + PR_ASSERT(foo); + + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + if (proxyObject) + { + // release ownership of the real object. + + nsresult rv; + PRInt32 threadNumber = argsStruct->threadNumber; + + printf("Deleting real Object (%d)\n", threadNumber); + NS_RELEASE(foo); + + PRInt32 retval; + + printf("Getting EventQueue...\n"); + + nsIEventQueue* eventQ; + nsCOMPtr<nsIEventQueueService> eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_SUCCEEDED(rv)) + { + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + if (NS_FAILED(rv)) + rv = eventQService->CreateThreadEventQueue(); + if (NS_FAILED(rv)) + return; + else + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + + printf("Thread (%d) Prior to calling proxyObject->Test.\n", threadNumber); + rv = proxyObject->Test(NS_PTR_TO_INT32(eventQ), 0, &retval); + printf("Thread (%d) proxyObject error: %d.\n", threadNumber, rv); + + printf("Deleting Proxy Object (%d)\n", threadNumber ); + 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 + } +} + + + +void TestCase_2(void *arg) +{ + + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + + manager->GetProxy(argsStruct->queue, + NS_GET_IID(nsITestProxy), // should be CID! + nsnull, + NS_GET_IID(nsITestProxy), + PROXY_SYNC, + (void**)&proxyObject); + + if (proxyObject != nsnull) + { + NS_RELEASE(proxyObject); + } +} + + + +void TestCase_nsISupports(void *arg) +{ + + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo* foo = new nsTestXPCFoo(); + + PR_ASSERT(foo); + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, 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); + } +} + + + + + +/***************************************************************************/ +/* ProxyTest */ +/***************************************************************************/ + +static void PR_CALLBACK ProxyTest( void *arg ) +{ + //TestCase_TwoClassesOneInterface(arg); + // TestCase_2(arg); + //TestCase_nsISupports(arg); + TestCase_NestedLoop(arg); + + NS_RELEASE( ((ArgsStruct*) arg)->queue); + free((void*) arg); +} + +nsIEventQueue *gEventQueue = nsnull; + +static void PR_CALLBACK EventLoop( void *arg ) +{ + nsresult rv; + printf("Creating EventQueue...\n"); + + nsIEventQueue* eventQ; + nsCOMPtr<nsIEventQueueService> eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_SUCCEEDED(rv)) { + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + if (NS_FAILED(rv)) + rv = eventQService->CreateThreadEventQueue(); + if (NS_FAILED(rv)) + return; + else + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + } + if (NS_FAILED(rv)) return; + + rv = eventQ->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&gEventQueue); + if (NS_FAILED(rv)) return; + + + printf("Verifing calling Proxy on eventQ thread.\n"); + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo* foo = new nsTestXPCFoo(); + + PR_ASSERT(foo); + + manager->GetProxyForObject(gEventQueue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + PRInt32 a; + proxyObject->Test(1, 2, &a); + proxyObject->Test2(); + + + NS_RELEASE(proxyObject); + delete foo; + + printf("End of Verification calling Proxy on eventQ thread.\n"); + + + printf("Looping for events.\n"); + + PLEvent* event = nsnull; + + while ( PR_SUCCESS == PR_Sleep( PR_MillisecondsToInterval(1)) ) + { + rv = gEventQueue->GetEvent(&event); + if (NS_FAILED(rv)) + return; + gEventQueue->HandleEvent(event); + } + + gEventQueue->ProcessPendingEvents(); + + printf("Closing down Event Queue.\n"); + delete gEventQueue; + gEventQueue = nsnull; + + printf("End looping for events.\n\n"); +} + +int +main(int argc, char **argv) +{ + int numberOfThreads = 1; + + if (argc > 1) + numberOfThreads = atoi(argv[1]); + + nsCOMPtr<nsIServiceManager> servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + + static PRThread** threads = (PRThread**) calloc(sizeof(PRThread*), numberOfThreads); + static PRThread* aEventThread; + + aEventThread = PR_CreateThread(PR_USER_THREAD, + EventLoop, + NULL, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + + + PR_Sleep(PR_MillisecondsToInterval(1000)); + + NS_ASSERTION(gEventQueue, "no main event queue"); // BAD BAD BAD. EVENT THREAD DID NOT CREATE QUEUE. This may be a timing issue, set the + // sleep about longer, and try again. + + printf("Spawn Threads:\n"); + for (PRInt32 spawn = 0; spawn < numberOfThreads; spawn++) + { + + ArgsStruct *args = (ArgsStruct *) malloc (sizeof(ArgsStruct)); + + args->queue = gEventQueue; + NS_ADDREF(args->queue); + args->threadNumber = spawn; + + threads[spawn] = PR_CreateThread(PR_USER_THREAD, + ProxyTest, + args, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + + printf("\tThread (%d) spawned\n", spawn); + + PR_Sleep( PR_MillisecondsToInterval(250) ); + } + + printf("All Threads Spawned.\n\n"); + + + + printf("Wait for threads.\n"); + for (PRInt32 i = 0; i < numberOfThreads; i++) + { + PRStatus rv; + printf("Thread (%d) Join...\n", i); + rv = PR_JoinThread(threads[i]); + printf("Thread (%d) Joined. (error: %d).\n", i, rv); + } + + PR_Interrupt(aEventThread); + PR_JoinThread(aEventThread); + + + printf("Calling Cleanup.\n"); + PR_Cleanup(); + + printf("Return zero.\n"); + return 0; +} |