diff --git a/mozilla/xpcom/proxy/src/nsProxyEvent.cpp b/mozilla/xpcom/proxy/src/nsProxyEvent.cpp index 96720ab5b03..047bb22641d 100644 --- a/mozilla/xpcom/proxy/src/nsProxyEvent.cpp +++ b/mozilla/xpcom/proxy/src/nsProxyEvent.cpp @@ -50,7 +50,6 @@ * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 */ -#include "nsProxyEvent.h" #include "nsProxyEventPrivate.h" #include "nsProxyRelease.h" #include "nsIProxyObjectManager.h" @@ -60,20 +59,14 @@ #include "prmem.h" #include "xptcall.h" +#include "nsAutoLock.h" #include "nsXPCOMCID.h" #include "nsServiceManagerUtils.h" #include "nsIComponentManager.h" -#include "nsIThreadInternal.h" #include "nsThreadUtils.h" #include "nsEventQueue.h" #include "nsMemory.h" -#include "prlog.h" -#ifdef PR_LOGGING -static PRLogModuleInfo *sLog = PR_NewLogModule("xpcomproxy"); -#endif -#define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args) - /** * Map the nsAUTF8String, nsUTF8String classes to the nsACString and * nsCString classes respectively for now. These defines need to be removed @@ -82,177 +75,78 @@ static PRLogModuleInfo *sLog = PR_NewLogModule("xpcomproxy"); #define nsAUTF8String nsACString #define nsUTF8String nsCString -//----------------------------------------------------------------------------- - -#define NS_PROXYEVENT_IID \ -{ /* 9a24dc5e-2b42-4a5a-aeca-37b8c8fd8ccd */ \ - 0x9a24dc5e, \ - 0x2b42, \ - 0x4a5a, \ - {0xae, 0xca, 0x37, 0xb8, 0xc8, 0xfd, 0x8c, 0xcd} \ -} - -class nsProxyEvent : public nsIRunnable -{ -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IID) - NS_DECL_ISUPPORTS - - nsProxyEvent(nsProxyObjectCallInfo *info = nsnull) - : mInfo(info) - {} - - void SetInfo(nsProxyObjectCallInfo *info) - { - NS_ASSERTION(info, "null info"); - NS_ASSERTION(!mInfo, "unexpected change to mInfo"); - mInfo = info; - } - - PRBool IsSyncProxyEvent() - { - return mInfo->GetProxyObject()->GetProxyType() & NS_PROXY_SYNC; - } - -protected: - nsProxyObjectCallInfo *mInfo; -}; -NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyEvent, NS_PROXYEVENT_IID) -NS_IMPL_THREADSAFE_ISUPPORTS2(nsProxyEvent, nsProxyEvent, nsIRunnable) - -//----------------------------------------------------------------------------- - -class nsProxyThreadFilter : public nsIThreadEventFilter -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSITHREADEVENTFILTER -}; - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyThreadFilter, nsIThreadEventFilter) - -NS_IMETHODIMP_(PRBool) -nsProxyThreadFilter::AcceptEvent(nsIRunnable *event) -{ - LOG(("PROXY(%p): filter event [%p]\n", this, event)); - - // If we encounter one of our proxy events that is for a synchronous method - // call, then we want to put it in our event queue for processing. Else, - // we want to allow the event to be dispatched to the thread's event queue - // for processing later once we complete the current sync method call. - - nsCOMPtr pe = do_QueryInterface(event); - return pe && pe->IsSyncProxyEvent(); -} - -//----------------------------------------------------------------------------- - -class nsProxyCallEvent : public nsProxyEvent -{ -public: - nsProxyCallEvent() - : nsProxyEvent() - {} - - NS_IMETHOD Run() - { - NS_ASSERTION(mInfo, "no info"); - Invoke(); - if (IsSyncProxyEvent()) { - mInfo->PostCompleted(); - } else { - delete mInfo; - mInfo = nsnull; - } - return NS_OK; - } - - void Invoke() - { - LOG(("PROXY(%p): Invoke\n", this)); - - nsProxyObject *proxyObject = mInfo->GetProxyObject(); - if (proxyObject) - { - // invoke the magic of xptc... - nsresult rv = XPTC_InvokeByIndex(proxyObject->GetRealObject(), - mInfo->GetMethodIndex(), - mInfo->GetParameterCount(), - mInfo->GetParameterList()); - mInfo->SetResult(rv); - } - else - { - mInfo->SetResult(NS_ERROR_OUT_OF_MEMORY); - } - } -}; - -//----------------------------------------------------------------------------- - -class nsProxyCallCompletedEvent : public nsProxyEvent +class nsProxyCallCompletedEvent : public nsRunnable { public: nsProxyCallCompletedEvent(nsProxyObjectCallInfo *info) - : nsProxyEvent(info) + : mInfo(info) {} - NS_IMETHOD Run() - { - NS_ASSERTION(mInfo, "no info"); - mInfo->SetCompleted(); - return NS_OK; - } -}; + NS_DECL_NSIRUNNABLE -//----------------------------------------------------------------------------- - -class nsProxyDestructorEvent : public nsRunnable -{ -public: - nsProxyDestructorEvent(nsProxyObject *doomed) - : mDoomed(doomed) - {} - - NS_IMETHOD Run() - { - delete mDoomed; - return NS_OK; - } + NS_IMETHOD QueryInterface(REFNSIID aIID, void **aResult); private: - nsProxyObject *mDoomed; + nsProxyObjectCallInfo *mInfo; }; +NS_IMETHODIMP +nsProxyCallCompletedEvent::Run() +{ + NS_ASSERTION(mInfo, "no info"); + mInfo->SetCompleted(); + return NS_OK; +} + +NS_DEFINE_IID(kFilterIID, NS_PROXYEVENT_FILTER_IID); + +NS_IMETHODIMP +nsProxyCallCompletedEvent::QueryInterface(REFNSIID aIID, void **aResult) +{ + // We are explicitly breaking XPCOM rules here by returning a different + // object from QueryInterface. We do this so that + // nsProxyThreadFilter::AcceptEvent can know whether we are an event that + // needs to be allowed through during a synchronous proxy call. + if (aIID.Equals(kFilterIID)) { + *aResult = mInfo; + mInfo->AddRef(); + return NS_OK; + } + return nsRunnable::QueryInterface(aIID, aResult); +} + //----------------------------------------------------------------------------- -nsProxyObjectCallInfo::nsProxyObjectCallInfo(nsProxyObject* owner, - nsXPTMethodInfo *methodInfo, +NS_IMETHODIMP +nsProxyObject::nsProxyObjectDestructorEvent::Run() +{ + delete mDoomed; + return NS_OK; +} + +//----------------------------------------------------------------------------- + +nsProxyObjectCallInfo::nsProxyObjectCallInfo(nsProxyEventObject* owner, + const nsXPTMethodInfo *methodInfo, PRUint32 methodIndex, nsXPTCVariant* parameterList, - PRUint32 parameterCount, - nsIRunnable *event) + PRUint32 parameterCount) : + mResult(NS_ERROR_FAILURE), + mMethodInfo(methodInfo), + mMethodIndex(methodIndex), + mParameterList(parameterList), + mParameterCount(parameterCount), + mCompleted(0), + mOwner(owner) { NS_ASSERTION(owner, "No nsProxyObject!"); NS_ASSERTION(methodInfo, "No nsXPTMethodInfo!"); - NS_ASSERTION(event, "No PLEvent!"); - - mCompleted = 0; - mMethodIndex = methodIndex; - mParameterList = parameterList; - mParameterCount = parameterCount; - mEvent = event; // XXX strong or weak ref? - mMethodInfo = methodInfo; - mCallersTarget = nsnull; - mOwner = owner; - RefCountInInterfacePointers(PR_TRUE); if (mOwner->GetProxyType() & NS_PROXY_ASYNC) CopyStrings(PR_TRUE); } - nsProxyObjectCallInfo::~nsProxyObjectCallInfo() { RefCountInInterfacePointers(PR_FALSE); @@ -262,7 +156,35 @@ nsProxyObjectCallInfo::~nsProxyObjectCallInfo() mOwner = nsnull; if (mParameterList) - free((void*) mParameterList); + free(mParameterList); +} + +NS_IMETHODIMP +nsProxyObjectCallInfo::QueryInterface(REFNSIID aIID, void **aResult) +{ + if (aIID.Equals(kFilterIID)) { + *aResult = this; + AddRef(); + return NS_OK; + } + return nsRunnable::QueryInterface(aIID, aResult); +} + +NS_IMETHODIMP +nsProxyObjectCallInfo::Run() +{ + PROXY_LOG(("PROXY(%p): Run\n", this)); + + mResult = XPTC_InvokeByIndex(mOwner->GetProxiedInterface(), + mMethodIndex, + mParameterCount, + mParameterList); + + if (IsSync()) { + PostCompleted(); + } + + return NS_OK; } void @@ -375,14 +297,14 @@ nsProxyObjectCallInfo::GetCompleted() void nsProxyObjectCallInfo::SetCompleted() { - LOG(("PROXY(%p): SetCompleted\n", this)); + PROXY_LOG(("PROXY(%p): SetCompleted\n", this)); PR_AtomicSet(&mCompleted, 1); } void nsProxyObjectCallInfo::PostCompleted() { - LOG(("PROXY(%p): PostCompleted\n", this)); + PROXY_LOG(("PROXY(%p): PostCompleted\n", this)); if (mCallersTarget) { nsCOMPtr event = @@ -410,13 +332,15 @@ nsProxyObjectCallInfo::SetCallersTarget(nsIEventTarget* target) } nsProxyObject::nsProxyObject(nsIEventTarget *target, PRInt32 proxyType, - nsISupports *realObject, - nsISupports *rootObject) + nsISupports *realObject) : + mProxyType(proxyType), + mTarget(target), + mRealObject(realObject), + mFirst(nsnull) { - mRealObject = realObject; - mRootObject = rootObject; - mTarget = target; - mProxyType = proxyType; + nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance(); + NS_ASSERTION(pom, "Creating a proxy without a global proxy-object-manager."); + pom->AddRef(); } nsProxyObject::~nsProxyObject() @@ -428,208 +352,98 @@ nsProxyObject::~nsProxyObject() NS_ProxyRelease(mTarget, doomed); } -void -nsProxyObject::AddRef() +NS_IMPL_THREADSAFE_ADDREF(nsProxyObject) + +NS_IMETHODIMP_(nsrefcnt) +nsProxyObject::Release() { - PR_AtomicIncrement((PRInt32 *)&mRefCnt); - NS_LOG_ADDREF(this, mRefCnt, "nsProxyObject", sizeof(*this)); + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + count = PR_AtomicDecrement((PRInt32*) &mRefCnt); + NS_LOG_RELEASE(this, count, "nsProxyRelease"); + if (count) + return count; + + nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance(); + NS_ASSERTION(pom, "Deleting a proxy without a global proxy-object-manager."); + + pom->Remove(this); + pom->Release(); + + return 0; } -void -nsProxyObject::Release(void) +NS_IMETHODIMP +nsProxyObject::QueryInterface(REFNSIID aIID, void **aResult) { - 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; - mTarget->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.. - - nsCOMPtr event = new nsProxyDestructorEvent(this); - if (event == nsnull) - { - NS_NOTREACHED("Leaking nsProxyObject!"); - return; // if this happens we are going to leak. - } - - if (NS_FAILED(mTarget->Dispatch(event, NS_DISPATCH_NORMAL))) - NS_WARNING("Failed to dispatch nsProxyDestructorEvent"); - } -} - - -nsresult -nsProxyObject::PostAndWait(nsProxyObjectCallInfo *proxyInfo) -{ - LOG(("PROXY(%p): PostAndWait enter [%p]\n", this, proxyInfo)); - - NS_ENSURE_ARG_POINTER(proxyInfo); - - nsIRunnable* event = proxyInfo->GetEvent(); - if (!event) - return NS_ERROR_NULL_POINTER; - - nsIThread *thread = NS_GetCurrentThread(); - nsCOMPtr threadInt = do_QueryInterface(thread); - NS_ENSURE_STATE(threadInt); - - // Install thread filter to limit event processing only to subclasses of - // nsProxyEvent. XXX Add support for sequencing? - nsRefPtr filter = new nsProxyThreadFilter(); - if (!filter) - return NS_ERROR_OUT_OF_MEMORY; - threadInt->PushEventQueue(filter); - - proxyInfo->SetCallersTarget(thread); - - // Dispatch can fail if the thread is shutting down - nsresult rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL); - if (NS_SUCCEEDED(rv)) { - while (!proxyInfo->GetCompleted()) { - if (!NS_ProcessNextEvent(thread)) { - rv = NS_ERROR_UNEXPECTED; - break; - } - } - } else { - NS_WARNING("Failed to dispatch nsProxyCallEvent"); + if (aIID.Equals(GetIID())) { + *aResult = this; + AddRef(); + return NS_OK; } - threadInt->PopEventQueue(); - - LOG(("PROXY(%p): PostAndWait exit [%p %x]\n", this, proxyInfo, rv)); - 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; - - *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount); - - if (*fullParam == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - - for (int i = 0; i < paramCount; i++) - { - const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i); - if ((mProxyType & NS_PROXY_ASYNC) && paramInfo.IsDipper()) - { - NS_WARNING("Async proxying of out parameters is not supported"); - free(*fullParam); - return NS_ERROR_PROXY_INVALID_OUT_PARAMETER; - } - uint8 flags = paramInfo.IsOut() ? nsXPTCVariant::PTR_IS_DATA : 0; - (*fullParam)[i].Init(params[i], paramInfo.GetType(), flags); + if (aIID.Equals(NS_GET_IID(nsISupports))) { + *aResult = NS_STATIC_CAST(nsISupports*, this); + AddRef(); + return NS_OK; } - - return NS_OK; + + nsProxyObjectManager *pom = nsProxyObjectManager::GetInstance(); + NS_ASSERTION(pom, "Deleting a proxy without a global proxy-object-manager."); + + nsAutoMonitor mon(pom->GetMonitor()); + + return LockedFind(aIID, aResult); } - + nsresult -nsProxyObject::Post( PRUint32 methodIndex, - nsXPTMethodInfo *methodInfo, - nsXPTCMiniVariant * params, - nsIInterfaceInfo *interfaceInfo) +nsProxyObject::LockedFind(REFNSIID aIID, void **aResult) { - nsresult rv = NS_OK; + // This method is only called when the global monitor is held. + // XXX assert this - if (! mTarget || ! mRealObject) - return NS_ERROR_OUT_OF_MEMORY; + nsProxyEventObject *peo; - if (methodInfo->IsNotXPCOM()) - return NS_ERROR_PROXY_INVALID_IN_PARAMETER; - - nsXPTCVariant *fullParam; - uint8 paramCount; - rv = convertMiniVariantToVariant(methodInfo, params, &fullParam, ¶mCount); - + for (peo = mFirst; peo; peo = peo->mNext) { + if (peo->GetClass()->GetProxiedIID().Equals(aIID)) { + *aResult = NS_STATIC_CAST(nsISupports*, peo); + peo->AddRef(); + return NS_OK; + } + } + + nsProxyEventClass *pec; + nsresult rv = nsProxyObjectManager::GetInstance()->GetClass(aIID, &pec); 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 dispatch target. - if ( (methodIndex == 0) || - (mProxyType & NS_PROXY_SYNC && - NS_SUCCEEDED(mTarget->IsOnCurrentThread(&callDirectly)) && - callDirectly)) - { - - // invoke the magic of xptc... - nsresult rv = XPTC_InvokeByIndex( mRealObject, - methodIndex, - paramCount, - fullParam); - - if (fullParam) - free(fullParam); + nsISomeInterface* newInterface; + rv = mRealObject->QueryInterface(aIID, (void**) &newInterface); + if (NS_FAILED(rv)) return rv; - } - nsRefPtr event = new nsProxyCallEvent(); - if (!event) { - if (fullParam) - free(fullParam); - 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) { - if (fullParam) - free(fullParam); - return NS_ERROR_OUT_OF_MEMORY; - } + peo = new nsProxyEventObject(this, pec, newInterface); + if (!peo) + return NS_ERROR_OUT_OF_MEMORY; - event->SetInfo(proxyInfo); + peo->mNext = mFirst; + mFirst = peo; - if (mProxyType & NS_PROXY_SYNC) - { - rv = PostAndWait(proxyInfo); - - if (NS_SUCCEEDED(rv)) - rv = proxyInfo->GetResult(); - delete proxyInfo; - return rv; - } - - if (mProxyType & NS_PROXY_ASYNC) - { - mTarget->Dispatch(event, NS_DISPATCH_NORMAL); - return NS_OK; - } - return NS_ERROR_UNEXPECTED; + NS_ADDREF(peo); + + *aResult = (nsISupports*) peo; + return NS_OK; } + +void +nsProxyObject::LockedRemove(nsProxyEventObject *peo) +{ + nsProxyEventObject **i; + for (i = &mFirst; *i; i = &((*i)->mNext)) { + if (*i == peo) { + *i = peo->mNext; + break; + } + } +} + diff --git a/mozilla/xpcom/proxy/src/nsProxyEvent.h b/mozilla/xpcom/proxy/src/nsProxyEvent.h deleted file mode 100644 index 92af56ab679..00000000000 --- a/mozilla/xpcom/proxy/src/nsProxyEvent.h +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * 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 "nsIEventTarget.h" - -#include "prtypes.h" -#include "xptcall.h" -#include "xptinfo.h" - -class nsProxyObjectCallInfo; -class nsIRunnable; - -//#define AUTOPROXIFICATION - -// WARNING about NS_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(nsIEventTarget *destQueue, PRInt32 proxyType, - nsISupports *realObject, nsISupports *rootObject); - - void AddRef(); - void Release(); - - ~nsProxyObject(); - - nsresult Post( PRUint32 methodIndex, - nsXPTMethodInfo * info, - nsXPTCMiniVariant * params, - nsIInterfaceInfo * interfaceInfo); - - nsresult PostAndWait(nsProxyObjectCallInfo *proxyInfo); - nsISupports* GetRealObject() const { return mRealObject; } - nsIEventTarget* GetTarget() const { return mTarget; } - PRInt32 GetProxyType() const { return mProxyType; } - - friend class nsProxyEventObject; -private: - - nsAutoRefCnt mRefCnt; - - PRInt32 mProxyType; - - nsCOMPtr mTarget; /* event target */ - - nsCOMPtr mRealObject; /* the non-proxy object that this event is referring to. - This is a strong ref. */ - nsISupports *mRootObject; /* weak pointer to identity object */ - - nsresult convertMiniVariantToVariant(nsXPTMethodInfo * methodInfo, - nsXPTCMiniVariant * params, - nsXPTCVariant **fullParam, - uint8 *paramCount); -}; - - -class nsProxyObjectCallInfo -{ -public: - - nsProxyObjectCallInfo(nsProxyObject* owner, - nsXPTMethodInfo *methodInfo, - PRUint32 methodIndex, - nsXPTCVariant* parameterList, - PRUint32 parameterCount, - nsIRunnable *event); - - ~nsProxyObjectCallInfo(); - - PRUint32 GetMethodIndex() const { return mMethodIndex; } - nsXPTCVariant* GetParameterList() const { return mParameterList; } - PRUint32 GetParameterCount() const { return mParameterCount; } - nsIRunnable* GetEvent() 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; } - - nsIEventTarget* GetCallersTarget(); - void SetCallersTarget(nsIEventTarget* target); - -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 */ - nsIRunnable *mEvent; /* the current runnable */ - PRInt32 mCompleted; /* is true when the method has been called. */ - - nsCOMPtr mCallersTarget; /* this is the dispatch target that we must post a message back to - when we are done invoking the method (only NS_PROXY_SYNC). */ - - nsRefPtr mOwner; /* this is the strong referenced nsProxyObject */ - - void RefCountInInterfacePointers(PRBool addRef); - void CopyStrings(PRBool copy); -}; - -#endif // nsProxyEvent_h__ diff --git a/mozilla/xpcom/proxy/src/nsProxyEventClass.cpp b/mozilla/xpcom/proxy/src/nsProxyEventClass.cpp index c690ead7c92..adea1594a99 100644 --- a/mozilla/xpcom/proxy/src/nsProxyEventClass.cpp +++ b/mozilla/xpcom/proxy/src/nsProxyEventClass.cpp @@ -37,9 +37,6 @@ * * ***** END LICENSE BLOCK ***** */ - -#include "nsProxyEvent.h" -#include "nsIProxyObjectManager.h" #include "nsProxyEventPrivate.h" #include "nsIComponentManager.h" @@ -50,7 +47,6 @@ #include "nsHashtable.h" #include "nsAutoLock.h" -#include "xptiprivate.h" #include "xptcall.h" // LIFETIME_CACHE will cache class for the entire cyle of the application. @@ -59,138 +55,15 @@ 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; - - // don't 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); - PR_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); - PR_Free(iidStr); -#endif - } - else - { - nsIInterfaceInfoManager* iimgr = - xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); - - if(iimgr) - { - nsCOMPtr info; - if(NS_SUCCEEDED(iimgr->GetInfoForIID(&aIID, getter_AddRefs(info)))) - { - /* - Check to see if isISupportsDescendent - */ - nsCOMPtr oldest = info; - nsCOMPtr 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_NOTREACHED("This constructor should never be called"); -} nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo) : mIID(aIID), + mInfo(aInfo), mDescriptors(NULL) { - NS_ADDREF_THIS(); - - mInfo = aInfo; - - /* add use to the used classes */ - nsIDKey key(aIID); - - nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); - if (manager == nsnull) - return; - // don't 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); - PR_Free(iidStr); -#endif - } - uint16 methodCount; if(NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) { @@ -213,163 +86,4 @@ nsProxyEventClass::~nsProxyEventClass() { if (mDescriptors && mDescriptors != &zero_methods_descriptor) delete [] mDescriptors; - - if (nsProxyObjectManager::IsManagerShutdown()) - return; - -#ifndef LIFETIME_CACHE - nsIDKey key(mIID); - - nsCOMPtr 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); - PR_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 interfaceInfo; - const nsXPTMethodInfo *mi; - - nsIInterfaceInfoManager* iim = - xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); - - 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->GetTarget(), - 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_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IDENTITY_CLASS_IID) - - static void* GetSingleton() - { - static ProxyEventClassIdentity* singleton = NULL; - if(!singleton) - singleton = new ProxyEventClassIdentity(); - return singleton; - } -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(ProxyEventClassIdentity, - NS_PROXYEVENT_IDENTITY_CLASS_IID) - -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 current = GetInterfaceInfo(); - nsCOMPtr 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/mozilla/xpcom/proxy/src/nsProxyEventObject.cpp b/mozilla/xpcom/proxy/src/nsProxyEventObject.cpp index 9ce507aa102..8ea694f7bfa 100644 --- a/mozilla/xpcom/proxy/src/nsProxyEventObject.cpp +++ b/mozilla/xpcom/proxy/src/nsProxyEventObject.cpp @@ -21,6 +21,7 @@ * * Contributor(s): * Pierre Phaneuf + * Benjamin Smedberg * * 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"), @@ -40,9 +41,8 @@ #include "prmem.h" #include "nscore.h" -#include "nsProxyEvent.h" -#include "nsIProxyObjectManager.h" #include "nsProxyEventPrivate.h" +#include "nsIThreadInternal.h" #include "nsServiceManagerUtils.h" @@ -53,423 +53,22 @@ #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* targetKey, PRInt32 proxyType) - : mRootObjectKey(rootObjectKey), mTargetKey(targetKey), mProxyType(proxyType) { - } - - PRUint32 HashCode(void) const { - return NS_PTR_TO_INT32(mRootObjectKey) ^ - NS_PTR_TO_INT32(mTargetKey) ^ mProxyType; - } - - PRBool Equals(const nsHashKey *aKey) const { - const nsProxyEventKey* other = (const nsProxyEventKey*)aKey; - return mRootObjectKey == other->mRootObjectKey - && mTargetKey == other->mTargetKey - && mProxyType == other->mProxyType; - } - - nsHashKey *Clone() const { - return new nsProxyEventKey(mRootObjectKey, mTargetKey, mProxyType); - } - -protected: - void* mRootObjectKey; - void* mTargetKey; - PRInt32 mProxyType; -}; - -//////////////////////////////////////////////////////////////////////////////// - -#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 rootObject = do_QueryInterface(mProxyObject->mRealObject); - nsCOMPtr rootQueue = do_QueryInterface(mProxyObject->mTarget); - 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(nsIEventTarget *target, - 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 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_WARNING("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 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 destQRoot = do_QueryInterface(target, &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 rootProxy; - nsCOMPtr 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 rootClazz; - - rootClazz = dont_AddRef(nsProxyEventClass::GetNewOrUsedClass( - NS_GET_IID(nsISupports))); - if (!rootClazz) { - return nsnull; - } - - peo = new nsProxyEventObject(target, - proxyType, - rootObject, - 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 proxyClazz; - - proxyClazz = dont_AddRef(nsProxyEventClass::GetNewOrUsedClass(aIID)); - if(!proxyClazz) { - return nsnull; - } - - // Get the raw interface for this IID - nsCOMPtr 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(target, - proxyType, - rawInterface, - rootObject, - 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(nsIEventTarget *target, - PRInt32 proxyType, - nsISupports* aObj, - nsISupports* aRootObj, +nsProxyEventObject::nsProxyEventObject(nsProxyObject *aParent, nsProxyEventClass* aClass, - nsProxyEventObject* root) - : mClass(aClass), - mRoot(root), + nsISomeInterface* aRealInterface) + : mRealInterface(aRealInterface), + mClass(aClass), + mProxyObject(aParent), mNext(nsnull) { - NS_IF_ADDREF(mRoot); - - // XXX protect against OOM errors - mProxyObject = new nsProxyObject(target, proxyType, aObj, aRootObj); - -#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(); + // This destructor is always called within the POM monitor. + // XXX assert this! - NS_ASSERTION(!mNext, "There are still proxies in the chain!"); - - if (realToProxyMap != nsnull) { - nsCOMPtr rootTarget = - do_QueryInterface(mProxyObject->mTarget); - nsProxyEventKey key(mProxyObject->mRootObject, rootTarget, - 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); + mProxyObject->LockedRemove(this); } // @@ -481,13 +80,7 @@ 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); + nsAutoMonitor mon(nsProxyObjectManager::GetInstance()->GetMonitor()); nsrefcnt count; NS_PRECONDITION(0 != mRefCnt, "dup release"); @@ -511,14 +104,14 @@ nsProxyEventObject::Release(void) NS_IMETHODIMP nsProxyEventObject::QueryInterface(REFNSIID aIID, void** aInstancePtr) { - if( aIID.Equals(GetIID()) ) + if( aIID.Equals(GetClass()->GetProxiedIID()) ) { *aInstancePtr = NS_STATIC_CAST(nsISupports*, this); NS_ADDREF_THIS(); return NS_OK; } - return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr); + return mProxyObject->QueryInterface(aIID, aInstancePtr); } // @@ -528,34 +121,146 @@ nsProxyEventObject::QueryInterface(REFNSIID aIID, void** aInstancePtr) 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; } +nsresult +nsProxyEventObject::convertMiniVariantToVariant(const nsXPTMethodInfo *methodInfo, + nsXPTCMiniVariant * params, + nsXPTCVariant **fullParam, + uint8 *outParamCount) +{ + uint8 paramCount = methodInfo->GetParamCount(); + *outParamCount = paramCount; + *fullParam = nsnull; + + if (!paramCount) return NS_OK; + + *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount); + + if (*fullParam == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + for (int i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i); + if ((GetProxyType() & NS_PROXY_ASYNC) && paramInfo.IsDipper()) + { + NS_WARNING("Async proxying of out parameters is not supported"); + free(*fullParam); + return NS_ERROR_PROXY_INVALID_OUT_PARAMETER; + } + uint8 flags = paramInfo.IsOut() ? nsXPTCVariant::PTR_IS_DATA : 0; + (*fullParam)[i].Init(params[i], paramInfo.GetType(), flags); + } + + return NS_OK; +} + +class nsProxyThreadFilter : public nsIThreadEventFilter +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSITHREADEVENTFILTER +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyThreadFilter, nsIThreadEventFilter) + +NS_DEFINE_IID(kFilterIID, NS_PROXYEVENT_FILTER_IID); + +NS_IMETHODIMP_(PRBool) +nsProxyThreadFilter::AcceptEvent(nsIRunnable *event) +{ + PROXY_LOG(("PROXY(%p): filter event [%p]\n", this, event)); + + // If we encounter one of our proxy events that is for a synchronous method + // call, then we want to put it in our event queue for processing. Else, + // we want to allow the event to be dispatched to the thread's event queue + // for processing later once we complete the current sync method call. + + nsRefPtr poci; + event->QueryInterface(kFilterIID, getter_AddRefs(poci)); + return poci && poci->IsSync(); +} + NS_IMETHODIMP nsProxyEventObject::CallMethod(PRUint16 methodIndex, - const nsXPTMethodInfo* info, + const nsXPTMethodInfo* methodInfo, nsXPTCMiniVariant * params) { + NS_ASSERTION(methodIndex > 2, + "Calling QI/AddRef/Release through CallMethod"); nsresult rv; - if (mProxyObject) { - rv = mProxyObject->Post(methodIndex, - (nsXPTMethodInfo*)info, - params, - mClass->GetInterfaceInfo()); - } else { - rv = NS_ERROR_NULL_POINTER; + 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 = PR_FALSE; + if (GetProxyType() & NS_PROXY_SYNC && + NS_SUCCEEDED(GetTarget()->IsOnCurrentThread(&callDirectly)) && + callDirectly) { + + // invoke directly using xptc + rv = XPTC_InvokeByIndex(mRealInterface, methodIndex, + paramCount, fullParam); + + if (fullParam) + free(fullParam); + + return rv; } + nsRefPtr proxyInfo = + new nsProxyObjectCallInfo(this, methodInfo, methodIndex, + fullParam, paramCount); + if (!proxyInfo) + return NS_ERROR_OUT_OF_MEMORY; + + if (! (GetProxyType() & NS_PROXY_SYNC)) { + return GetTarget()->Dispatch(proxyInfo, NS_DISPATCH_NORMAL); + } + + // Post synchronously + + nsIThread *thread = NS_GetCurrentThread(); + nsCOMPtr threadInt = do_QueryInterface(thread); + NS_ENSURE_STATE(threadInt); + + // Install thread filter to limit event processing only to + // nsProxyObjectCallInfo instances. XXX Add support for sequencing? + nsRefPtr filter = new nsProxyThreadFilter(); + if (!filter) + return NS_ERROR_OUT_OF_MEMORY; + threadInt->PushEventQueue(filter); + + proxyInfo->SetCallersTarget(thread); + + // Dispatch can fail if the thread is shutting down + rv = GetTarget()->Dispatch(proxyInfo, NS_DISPATCH_NORMAL); + if (NS_SUCCEEDED(rv)) { + while (!proxyInfo->GetCompleted()) { + if (!NS_ProcessNextEvent(thread)) { + rv = NS_ERROR_UNEXPECTED; + break; + } + } + } else { + NS_WARNING("Failed to dispatch nsProxyCallEvent"); + } + + threadInt->PopEventQueue(); + + PROXY_LOG(("PROXY(%p): PostAndWait exit [%p %x]\n", this, proxyInfo, rv)); return rv; } diff --git a/mozilla/xpcom/proxy/src/nsProxyEventPrivate.h b/mozilla/xpcom/proxy/src/nsProxyEventPrivate.h index 15a4218dd15..9424207567f 100644 --- a/mozilla/xpcom/proxy/src/nsProxyEventPrivate.h +++ b/mozilla/xpcom/proxy/src/nsProxyEventPrivate.h @@ -39,128 +39,221 @@ #ifndef nsProxyEventPrivate_h__ #define nsProxyEventPrivate_h__ -#include "nscore.h" #include "nsISupports.h" #include "nsIFactory.h" -#include "nsHashtable.h" +#include "nsIEventTarget.h" +#include "nsIInterfaceInfo.h" +#include "nsIProxyObjectManager.h" #include "xptcall.h" // defines nsXPTCVariant -#include "nsProxyEvent.h" -#include "nsIProxyObjectManager.h" +#include "nsAutoPtr.h" +#include "nsCOMPtr.h" +#include "nsThreadUtils.h" + +#include "nsClassHashtable.h" +#include "nsHashtable.h" + #include "prmon.h" +#include "prlog.h" class nsProxyEventObject; -class nsProxyEventClass; -#define NS_PROXYEVENT_CLASS_IID \ -{ 0xeea90d42, \ - 0xb059, \ - 0x11d2, \ - {0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33}\ -} +/** + * To make types clearer, we distinguish between a canonical nsISupports* and + * a proxied interface pointer which represents an arbitrary interface known + * at runtime. + */ +typedef nsISupports nsISomeInterface; -#define NS_PROXYEVENT_IDENTITY_CLASS_IID \ +#define NS_PROXYOBJECT_CLASS_IID \ { 0xeea90d45, 0xb059, 0x11d2, \ { 0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33 } } +// This IID is used to filter runnables during synchronous event handling. +// The returned pointer is type nsProxyObjectCallInfo -#define NS_PROXYEVENT_OBJECT_IID \ +#define NS_PROXYEVENT_FILTER_IID \ { 0xec373590, 0x9164, 0x11d3, \ {0x8c, 0x73, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74} } - -class nsProxyEventClass : public nsISupports +/** + * An object representing an IID and its associated interfaceinfo. Instances + * of this class are obtained via nsProxyObjectManager::GetClass. + */ +class nsProxyEventClass { public: - NS_DECL_ISUPPORTS - - NS_DECLARE_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 mInfo; uint32* mDescriptors; - - nsresult CallQueryInterfaceOnProxy(nsProxyEventObject* self, - REFNSIID aIID, - nsProxyEventObject** aInstancePtr); }; -NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyEventClass, NS_PROXYEVENT_CLASS_IID) +/** + * A class which provides the XPCOM identity for a proxied object. + * Instances of this class are obtained from the POM, and are uniquely + * hashed on a proxytype/eventtarget/realobject key. + */ +class nsProxyObject : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYOBJECT_CLASS_IID) + nsProxyObject(nsIEventTarget *destQueue, PRInt32 proxyType, + nsISupports *realObject); + + nsISupports* GetRealObject() const { return mRealObject; } + nsIEventTarget* GetTarget() const { return mTarget; } + PRInt32 GetProxyType() const { return mProxyType; } + + nsresult LockedFind(REFNSIID iid, void **aResult); + void LockedRemove(nsProxyEventObject* aObject); + + friend class nsProxyObjectManager; +private: + ~nsProxyObject(); + + PRInt32 mProxyType; + nsCOMPtr mTarget; /* event target */ + nsCOMPtr mRealObject; /* the non-proxy object that this object is proxying + This is a strong ref. */ + nsProxyEventObject *mFirst; + + class nsProxyObjectDestructorEvent : public nsRunnable + { + nsProxyObjectDestructorEvent(nsProxyObject *doomed) : + mDoomed(doomed) + {} + + NS_DECL_NSIRUNNABLE + + friend class nsProxyObject; + private: + nsProxyObject *mDoomed; + }; + + friend nsProxyObjectDestructorEvent; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyObject, NS_PROXYOBJECT_CLASS_IID) + +/** + * Object representing a single interface implemented on a proxied object. + * This object is maintained in a singly-linked list from the associated + * "parent" nsProxyObject. + */ class nsProxyEventObject : public nsXPTCStubBase { public: NS_DECL_ISUPPORTS - NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_OBJECT_IID) - - static nsProxyEventObject* GetNewOrUsedProxy(nsIEventTarget *target, - 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; } + nsISomeInterface* GetProxiedInterface() const { return mRealInterface; } + nsIEventTarget* GetTarget() const { return mProxyObject->GetTarget(); } + PRInt32 GetProxyType() const { return mProxyObject->GetProxyType(); } - nsProxyEventClass* GetClass() const { return mClass; } - nsIEventTarget* GetTarget() const { return (mProxyObject ? mProxyObject->GetTarget() : nsnull);} - nsISupports* GetRealObject() const { return (mProxyObject ? mProxyObject->GetRealObject(): nsnull);} - PRInt32 GetProxyType() const { return (mProxyObject ? mProxyObject->GetProxyType() : nsnull);} + nsresult convertMiniVariantToVariant(const nsXPTMethodInfo *methodInfo, + nsXPTCMiniVariant *params, + nsXPTCVariant **fullParam, + uint8 *outParamCount); - nsProxyEventObject(); - nsProxyEventObject(nsIEventTarget *target, - PRInt32 proxyType, - nsISupports* aObj, - nsISupports* aRootObj, // result of QI(nsISupports) - nsProxyEventClass* aClass, - nsProxyEventObject* root); - - nsProxyEventObject* LockedFind(REFNSIID aIID); + nsProxyEventObject(nsProxyObject *aParent, + nsProxyEventClass *aClass, + nsISomeInterface *aRealInterface); -#ifdef DEBUG_xpcom_proxy - void DebugDump(const char * message, PRUint32 hashKey); -#endif + friend class nsProxyObject; private: ~nsProxyEventObject(); -protected: - void LockedRemoveProxy(); + nsCOMPtr mRealInterface; + nsProxyEventClass *mClass; + nsCOMPtr mProxyObject; -protected: - nsCOMPtr mClass; - nsRefPtr mProxyObject; - - // Owning reference... - nsProxyEventObject *mRoot; - - // Weak reference... - nsProxyEventObject *mNext; + // Weak reference, maintained by the parent nsProxyObject + nsProxyEventObject *mNext; }; -NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyEventObject, NS_PROXYEVENT_OBJECT_IID) +#define NS_PROXYEVENT_IID \ +{ /* 9a24dc5e-2b42-4a5a-aeca-37b8c8fd8ccd */ \ + 0x9a24dc5e, \ + 0x2b42, \ + 0x4a5a, \ + {0xae, 0xca, 0x37, 0xb8, 0xc8, 0xfd, 0x8c, 0xcd} \ +} + +/** + * A class representing a particular proxied method call. + */ +class nsProxyObjectCallInfo : public nsRunnable +{ +public: + + NS_DECL_NSIRUNNABLE + + NS_IMETHOD QueryInterface(REFNSIID aIID, void **aResult); + + NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IID) + + nsProxyObjectCallInfo(nsProxyEventObject* owner, + const nsXPTMethodInfo *methodInfo, + PRUint32 methodIndex, + nsXPTCVariant* parameterList, + PRUint32 parameterCount); + + ~nsProxyObjectCallInfo(); + + PRUint32 GetMethodIndex() const { return mMethodIndex; } + nsXPTCVariant* GetParameterList() const { return mParameterList; } + PRUint32 GetParameterCount() const { return mParameterCount; } + nsresult GetResult() const { return mResult; } + + PRBool GetCompleted(); + void SetCompleted(); + void PostCompleted(); + + void SetResult(nsresult rv) { mResult = rv; } + + nsIEventTarget* GetCallersTarget(); + void SetCallersTarget(nsIEventTarget* target); + PRBool IsSync() const + { + return mOwner->GetProxyType() & NS_PROXY_SYNC; + } + +private: + + nsresult mResult; /* this is the return result of the called function */ + const nsXPTMethodInfo *mMethodInfo; + PRUint32 mMethodIndex; /* which method to be called? */ + nsXPTCVariant *mParameterList; /* marshalled in parameter buffer */ + PRUint32 mParameterCount; /* number of params */ + PRInt32 mCompleted; /* is true when the method has been called. */ + + nsCOMPtr mCallersTarget; /* this is the dispatch target that we must post a message back to + when we are done invoking the method (only NS_PROXY_SYNC). */ + + nsRefPtr mOwner; /* this is the strong referenced nsProxyObject */ + + void RefCountInInterfacePointers(PRBool addRef); + void CopyStrings(PRBool copy); +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsProxyObjectCallInfo, NS_PROXYEVENT_IID) //////////////////////////////////////////////////////////////////////////////// // nsProxyObjectManager @@ -180,18 +273,23 @@ public: static PRBool IsManagerShutdown(); static void Shutdown(); - - nsHashtable* GetRealObjectToProxyObjectMap() { return &mProxyObjectMap;} - nsHashtable* GetIIDToProxyClassMap() { return &mProxyClassMap; } + + nsresult GetClass(REFNSIID aIID, nsProxyEventClass **aResult); + + void Remove(nsProxyObject* aProxy); PRMonitor* GetMonitor() const { return mProxyCreationMonitor; } - + +#ifdef PR_LOGGING + static PRLogModuleInfo *sLog; +#endif + private: ~nsProxyObjectManager(); static nsProxyObjectManager* mInstance; nsHashtable mProxyObjectMap; - nsHashtable mProxyClassMap; + nsClassHashtable mProxyClassMap; PRMonitor *mProxyCreationMonitor; }; @@ -203,4 +301,6 @@ private: {0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33} \ } +#define PROXY_LOG(args) PR_LOG(nsProxyObjectManager::sLog, PR_LOG_DEBUG, args) + #endif // nsProxyEventPrivate_h__ diff --git a/mozilla/xpcom/proxy/src/nsProxyObjectManager.cpp b/mozilla/xpcom/proxy/src/nsProxyObjectManager.cpp index afac93313ed..0ff8e12501f 100644 --- a/mozilla/xpcom/proxy/src/nsProxyObjectManager.cpp +++ b/mozilla/xpcom/proxy/src/nsProxyObjectManager.cpp @@ -46,18 +46,51 @@ * * ***** END LICENSE BLOCK ***** */ - -#include "nsProxyEvent.h" -#include "nsIProxyObjectManager.h" #include "nsProxyEventPrivate.h" -#include "nsThreadUtils.h" #include "nsIComponentManager.h" +#include "nsIProxyObjectManager.h" #include "nsIServiceManager.h" -#include "nsCOMPtr.h" - #include "nsIThread.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsThreadUtils.h" +#include "xptiprivate.h" + + +#ifdef PR_LOGGING +PRLogModuleInfo *nsProxyObjectManager::sLog = PR_NewLogModule("xpcomproxy"); +#endif + +class nsProxyEventKey : public nsHashKey +{ +public: + nsProxyEventKey(void* rootObjectKey, void* targetKey, PRInt32 proxyType) + : mRootObjectKey(rootObjectKey), mTargetKey(targetKey), mProxyType(proxyType) { + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mRootObjectKey) ^ + NS_PTR_TO_INT32(mTargetKey) ^ mProxyType; + } + + PRBool Equals(const nsHashKey *aKey) const { + const nsProxyEventKey* other = (const nsProxyEventKey*)aKey; + return mRootObjectKey == other->mRootObjectKey + && mTargetKey == other->mTargetKey + && mProxyType == other->mProxyType; + } + + nsHashKey *Clone() const { + return new nsProxyEventKey(mRootObjectKey, mTargetKey, mProxyType); + } + +protected: + void* mRootObjectKey; + void* mTargetKey; + PRInt32 mProxyType; +}; ///////////////////////////////////////////////////////////////////////// // nsProxyObjectManager @@ -68,23 +101,15 @@ nsProxyObjectManager* nsProxyObjectManager::mInstance = nsnull; NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyObjectManager, nsIProxyObjectManager) nsProxyObjectManager::nsProxyObjectManager() - : mProxyObjectMap(256, PR_TRUE), - mProxyClassMap(256, PR_TRUE) + : mProxyObjectMap(256, PR_FALSE) { mProxyCreationMonitor = PR_NewMonitor(); -} - -static PRIntn -PurgeProxyClasses(nsHashKey *aKey, void *aData, void* closure) -{ - nsProxyEventClass* ptr = NS_STATIC_CAST(nsProxyEventClass*, aData); - NS_RELEASE(ptr); - return kHashEnumerateNext; + mProxyClassMap.Init(256); } nsProxyObjectManager::~nsProxyObjectManager() { - mProxyClassMap.Reset(PurgeProxyClasses, nsnull); + mProxyClassMap.Clear(); if (mProxyCreationMonitor) PR_DestroyMonitor(mProxyCreationMonitor); @@ -155,12 +180,76 @@ nsProxyObjectManager::GetProxyForObject(nsIEventTarget* aTarget, return aObj->QueryInterface(aIID, aProxyObject); } - // check to see if proxy is there or not. - *aProxyObject = nsProxyEventObject::GetNewOrUsedProxy(aTarget, proxyType, - aObj, aIID); - if (!*aProxyObject) - return NS_ERROR_UNEXPECTED; - + nsCOMPtr realObj = do_QueryInterface(aObj); + + // Make sure the object passed in is not a proxy; if it is, be nice and + // build the proxy for the real object. + nsCOMPtr po = do_QueryInterface(aObj); + if (po) { + realObj = po->GetRealObject(); + } + + nsCOMPtr realEQ = do_QueryInterface(aTarget); + + nsProxyEventKey rootKey(realObj, realEQ, proxyType); + + // Enter the Grand Monitor here. + nsAutoMonitor mon(mProxyCreationMonitor); + + nsCOMPtr root = (nsProxyObject*) mProxyObjectMap.Get(&rootKey); + if (!root) { + root = new nsProxyObject(aTarget, proxyType, realObj); + if (!root) + return NS_ERROR_OUT_OF_MEMORY; + + mProxyObjectMap.Put(&rootKey, root); + } + return root->LockedFind(aIID, aProxyObject); +} + +void +nsProxyObjectManager::Remove(nsProxyObject *aProxy) +{ + nsCOMPtr realEQ = do_QueryInterface(aProxy->GetTarget()); + + nsProxyEventKey rootKey(aProxy->GetRealObject(), realEQ, aProxy->GetProxyType()); + + nsAutoMonitor mon(mProxyCreationMonitor); + + if (!mProxyObjectMap.Remove(&rootKey)) { + NS_ERROR("nsProxyObject not found in global hash."); + } +} + +nsresult +nsProxyObjectManager::GetClass(REFNSIID aIID, nsProxyEventClass **aResult) +{ + nsAutoMonitor mon(mProxyCreationMonitor); + + nsProxyEventClass *pec; + mProxyClassMap.Get(aIID, &pec); + if (!pec) { + nsIInterfaceInfoManager *iim = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + if (!iim) + return NS_ERROR_FAILURE; + + nsCOMPtr ii; + nsresult rv = iim->GetInfoForIID(&aIID, getter_AddRefs(ii)); + if (NS_FAILED(rv)) + return rv; + + pec = new nsProxyEventClass(aIID, ii); + if (!pec) + return NS_ERROR_OUT_OF_MEMORY; + + if (!mProxyClassMap.Put(aIID, pec)) { + delete pec; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + *aResult = pec; return NS_OK; }