Bug 342311 - xpcom/proxy refactoring, in preparation for xptcall rework, r=darin
git-svn-id: svn://10.0.0.236/trunk@202029 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -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<nsProxyEvent> 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<nsIRunnable> 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<nsIRunnable> 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<nsIThreadInternal> 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<nsProxyThreadFilter> filter = new nsProxyThreadFilter();
|
||||
if (!filter)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
threadInt->PushEventQueue(filter);
|
||||
|
||||
proxyInfo->SetCallersTarget(thread);
|
||||
|
||||
// Dispatch can fail if the thread is shutting down
|
||||
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<nsProxyCallEvent> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<nsIEventTarget> mTarget; /* event target */
|
||||
|
||||
nsCOMPtr<nsISupports> 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<nsIEventTarget> mCallersTarget; /* this is the dispatch target that we must post a message back to
|
||||
when we are done invoking the method (only NS_PROXY_SYNC). */
|
||||
|
||||
nsRefPtr<nsProxyObject> mOwner; /* this is the strong referenced nsProxyObject */
|
||||
|
||||
void RefCountInInterfacePointers(PRBool addRef);
|
||||
void CopyStrings(PRBool copy);
|
||||
};
|
||||
|
||||
#endif // nsProxyEvent_h__
|
||||
@@ -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<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_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<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);
|
||||
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<nsIInterfaceInfo> 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<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);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Benjamin Smedberg <benjamin@smedbergs.us>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
@@ -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<nsISupports> rootObject = do_QueryInterface(mProxyObject->mRealObject);
|
||||
nsCOMPtr<nsISupports> 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<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_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<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(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<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(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<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(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<nsISupports> 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<nsProxyObjectCallInfo> 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<nsProxyObjectCallInfo> proxyInfo =
|
||||
new nsProxyObjectCallInfo(this, methodInfo, methodIndex,
|
||||
fullParam, paramCount);
|
||||
if (!proxyInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (! (GetProxyType() & NS_PROXY_SYNC)) {
|
||||
return GetTarget()->Dispatch(proxyInfo, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
// Post synchronously
|
||||
|
||||
nsIThread *thread = NS_GetCurrentThread();
|
||||
nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(thread);
|
||||
NS_ENSURE_STATE(threadInt);
|
||||
|
||||
// Install thread filter to limit event processing only to
|
||||
// nsProxyObjectCallInfo instances. XXX Add support for sequencing?
|
||||
nsRefPtr<nsProxyThreadFilter> filter = new nsProxyThreadFilter();
|
||||
if (!filter)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
threadInt->PushEventQueue(filter);
|
||||
|
||||
proxyInfo->SetCallersTarget(thread);
|
||||
|
||||
// Dispatch can fail if the thread is shutting down
|
||||
rv = GetTarget()->Dispatch(proxyInfo, NS_DISPATCH_NORMAL);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
while (!proxyInfo->GetCompleted()) {
|
||||
if (!NS_ProcessNextEvent(thread)) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("Failed to dispatch nsProxyCallEvent");
|
||||
}
|
||||
|
||||
threadInt->PopEventQueue();
|
||||
|
||||
PROXY_LOG(("PROXY(%p): PostAndWait exit [%p %x]\n", this, proxyInfo, rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -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<nsIInterfaceInfo> 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<nsIEventTarget> mTarget; /* event target */
|
||||
nsCOMPtr<nsISupports> mRealObject; /* the non-proxy object that this object is proxying
|
||||
This is a strong ref. */
|
||||
nsProxyEventObject *mFirst;
|
||||
|
||||
class nsProxyObjectDestructorEvent : public nsRunnable
|
||||
{
|
||||
nsProxyObjectDestructorEvent(nsProxyObject *doomed) :
|
||||
mDoomed(doomed)
|
||||
{}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
friend class nsProxyObject;
|
||||
private:
|
||||
nsProxyObject *mDoomed;
|
||||
};
|
||||
|
||||
friend 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<nsISomeInterface> mRealInterface;
|
||||
nsProxyEventClass *mClass;
|
||||
nsCOMPtr<nsProxyObject> mProxyObject;
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsProxyEventClass> mClass;
|
||||
nsRefPtr<nsProxyObject> 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<nsIEventTarget> mCallersTarget; /* this is the dispatch target that we must post a message back to
|
||||
when we are done invoking the method (only NS_PROXY_SYNC). */
|
||||
|
||||
nsRefPtr<nsProxyEventObject> mOwner; /* this is the strong referenced nsProxyObject */
|
||||
|
||||
void RefCountInInterfacePointers(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<nsIDHashKey, nsProxyEventClass> 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__
|
||||
|
||||
@@ -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<nsISupports> realObj = do_QueryInterface(aObj);
|
||||
|
||||
// Make sure the object passed in is not a proxy; if it is, be nice and
|
||||
// build the proxy for the real object.
|
||||
nsCOMPtr<nsProxyObject> po = do_QueryInterface(aObj);
|
||||
if (po) {
|
||||
realObj = po->GetRealObject();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> realEQ = do_QueryInterface(aTarget);
|
||||
|
||||
nsProxyEventKey rootKey(realObj, realEQ, proxyType);
|
||||
|
||||
// Enter the Grand Monitor here.
|
||||
nsAutoMonitor mon(mProxyCreationMonitor);
|
||||
|
||||
nsCOMPtr<nsProxyObject> 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<nsISupports> 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<nsIInterfaceInfo> 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user