mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-05-13 08:57:27 +00:00
b=47143, r=valeski. Puts the real object release on the proper thread.
This commit is contained in:
parent
03c675c33c
commit
6502c4d736
@ -37,7 +37,7 @@
|
||||
|
||||
class nsProxyObjectCallInfo;
|
||||
|
||||
#define PROXY_SYNC 0x0001 // act just like a function call.
|
||||
#define PROXY_SYNC 0x0001 // acts just like a function call.
|
||||
#define PROXY_ASYNC 0x0002 // fire and forget. This will return immediately and you will lose all return information.
|
||||
#define PROXY_ALWAYS 0x0004 // ignore check to see if the eventQ is on the same thread as the caller, and alway return a proxied object.
|
||||
|
||||
@ -113,19 +113,6 @@ private:
|
||||
nsXPTCVariant **fullParam,
|
||||
uint8 *paramCount);
|
||||
|
||||
#ifdef AUTOPROXIFICATION
|
||||
typedef enum
|
||||
{
|
||||
convertOutParameters = 1,
|
||||
convertInParameters,
|
||||
convertAllParameters
|
||||
|
||||
} AutoProxyConvertTypes;
|
||||
|
||||
|
||||
nsresult AutoProxyParameterList(PRUint32 methodIndex, nsXPTMethodInfo *methodInfo, nsXPTCMiniVariant * params,
|
||||
nsIInterfaceInfo *interfaceInfo, AutoProxyConvertTypes convertType);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -49,14 +49,14 @@
|
||||
|
||||
#include "nsIAtom.h" //hack! Need a way to define a component as threadsafe (ie. sta).
|
||||
|
||||
//#define NESTED_Q
|
||||
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
static void* PR_CALLBACK EventHandler(PLEvent *self);
|
||||
static void PR_CALLBACK DestroyHandler(PLEvent *self);
|
||||
static void* PR_CALLBACK CompletedEventHandler(PLEvent *self);
|
||||
static void PR_CALLBACK CompletedDestroyHandler(PLEvent *self) ;
|
||||
static void* PR_CALLBACK ProxyDestructorEventHandler(PLEvent *self);
|
||||
static void PR_CALLBACK ProxyDestructorDestroyHandler(PLEvent *self) ;
|
||||
|
||||
nsProxyObjectCallInfo::nsProxyObjectCallInfo( nsProxyObject* owner,
|
||||
nsXPTMethodInfo *methodInfo,
|
||||
@ -215,8 +215,7 @@ nsProxyObjectCallInfo::SetCallersQueue(nsIEventQueue* queue)
|
||||
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsProxyObject)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsProxyObject)
|
||||
NS_IMPL_QUERY_INTERFACE0(nsProxyObject)
|
||||
NS_IMPL_THREADSAFE_QUERY_INTERFACE0(nsProxyObject)
|
||||
|
||||
nsProxyObject::nsProxyObject()
|
||||
{
|
||||
@ -258,6 +257,55 @@ nsProxyObject::~nsProxyObject()
|
||||
mDestQueue = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt)
|
||||
nsProxyObject::Release(void)
|
||||
{
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
|
||||
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
NS_LOG_RELEASE(this, mRefCnt, "nsProxyObject");
|
||||
mRefCnt = 1; /* stabilize */
|
||||
|
||||
PRBool callDirectly;
|
||||
mDestQueue->IsQueueOnCurrentThread(&callDirectly);
|
||||
|
||||
if (callDirectly)
|
||||
{
|
||||
NS_DELETEXPCOM(this);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// need to do something special here so that
|
||||
// the real object will always be deleted on
|
||||
// the correct thread..
|
||||
|
||||
PLEvent *event = PR_NEW(PLEvent);
|
||||
if (event == nsnull)
|
||||
{
|
||||
NS_ASSERTION(0, "Could not create a plevent. Leaking nsProxyObject!");
|
||||
return 0; // if this happens we are going to leak.
|
||||
}
|
||||
|
||||
PL_InitEvent(event,
|
||||
this,
|
||||
ProxyDestructorEventHandler,
|
||||
ProxyDestructorDestroyHandler);
|
||||
|
||||
// fire it off.
|
||||
mDestQueue->PostSynchronousEvent(event, nsnull);
|
||||
|
||||
delete event;
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
|
||||
// GetRealObject
|
||||
// This function must return the real pointer to the object to be proxied.
|
||||
// It must not be a comptr or be addreffed.
|
||||
@ -286,23 +334,16 @@ nsProxyObject::PostAndWait(nsProxyObjectCallInfo *proxyInfo)
|
||||
rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ));
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
rv = mEventQService->CreateThreadEventQueue();
|
||||
rv = mEventQService->CreateMonitoredThreadEventQueue();
|
||||
eventLoopCreated = PR_TRUE;
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ));
|
||||
}
|
||||
#ifdef NESTED_Q
|
||||
else
|
||||
{
|
||||
rv = mEventQService->PushThreadEventQueue(getter_AddRefs(eventQ));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
//---------------------
|
||||
|
||||
proxyInfo->SetCallersQueue(eventQ);
|
||||
|
||||
@ -326,16 +367,6 @@ nsProxyObject::PostAndWait(nsProxyObjectCallInfo *proxyInfo)
|
||||
mEventQService->DestroyThreadEventQueue();
|
||||
eventQ = 0;
|
||||
}
|
||||
#ifdef NESTED_Q
|
||||
else
|
||||
{
|
||||
nsIEventQueue *dumbAddref = eventQ;
|
||||
NS_ADDREF(dumbAddref); // PopThreadEventQueue released the nsCOMPtr,
|
||||
// then we crash while leaving this functions.
|
||||
mEventQService->PopThreadEventQueue(dumbAddref); // this is totally evil
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -372,22 +403,12 @@ nsProxyObject::Post( PRUint32 methodIndex, nsXPTMethodInfo *methodInfo, nsXPTCMi
|
||||
if (methodInfo->IsNotXPCOM())
|
||||
return NS_ERROR_PROXY_INVALID_IN_PARAMETER;
|
||||
|
||||
|
||||
PLEvent *event = PR_NEW(PLEvent);
|
||||
|
||||
if (event == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
#ifdef AUTOPROXIFICATION
|
||||
// this should move into the nsProxyObjectCallInfo.
|
||||
rv = AutoProxyParameterList(methodIndex, methodInfo, params, interfaceInfo, convertInParameters);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
delete event;
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
nsXPTCVariant *fullParam;
|
||||
uint8 paramCount;
|
||||
rv = convertMiniVariantToVariant(methodInfo, params, &fullParam, ¶mCount);
|
||||
@ -439,10 +460,6 @@ nsProxyObject::Post( PRUint32 methodIndex, nsXPTMethodInfo *methodInfo, nsXPTCMi
|
||||
|
||||
rv = proxyInfo->GetResult();
|
||||
delete proxyInfo;
|
||||
|
||||
#ifdef AUTOPROXIFICATION
|
||||
rv = AutoProxyParameterList(methodIndex, methodInfo, params, interfaceInfo, convertOutParameters);
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -463,7 +480,7 @@ static void DestroyHandler(PLEvent *self)
|
||||
|
||||
if (proxyObject == nsnull)
|
||||
return;
|
||||
|
||||
|
||||
if (proxyObject->GetProxyType() & PROXY_ASYNC)
|
||||
{
|
||||
delete owner;
|
||||
@ -509,225 +526,14 @@ static void* CompletedEventHandler(PLEvent *self)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
#ifdef AUTOPROXIFICATION
|
||||
/* 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);
|
||||
|
||||
nsresult
|
||||
AutoProxyParameterList(PRUint32 methodIndex, nsXPTMethodInfo *methodInfo, nsXPTCMiniVariant * params,
|
||||
nsIInterfaceInfo *interfaceInfo, AutoProxyConvertTypes convertType)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
uint8 paramCount = methodInfo->GetParamCount();
|
||||
|
||||
for (PRUint32 i = 0; i < paramCount; i++)
|
||||
{
|
||||
nsXPTParamInfo paramInfo = methodInfo->GetParam(i);
|
||||
|
||||
if (! paramInfo.GetType().IsInterfacePointer() )
|
||||
continue;
|
||||
|
||||
if ( (convertType == convertOutParameters && paramInfo.IsOut()) ||
|
||||
(convertType == convertInParameters && paramInfo.IsIn()) )
|
||||
{
|
||||
// We found an out parameter which is a interface, check for proxy
|
||||
if (params[i].val.p == nsnull)
|
||||
continue;
|
||||
|
||||
nsISupports* anInterface = nsnull;
|
||||
|
||||
if (paramInfo.IsOut())
|
||||
anInterface = *((nsISupports**)params[i].val.p);
|
||||
else
|
||||
anInterface = ((nsISupports*)params[i].val.p);
|
||||
|
||||
|
||||
if (anInterface == nsnull)
|
||||
continue;
|
||||
|
||||
nsISupports *aProxyObject;
|
||||
nsISupports *aIdentificationObject;
|
||||
|
||||
rv = anInterface->QueryInterface(kProxyObject_Identity_Class_IID, (void**)&aIdentificationObject);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
// create a proxy
|
||||
nsIProxyObjectManager* manager;
|
||||
|
||||
rv = nsServiceManager::GetService( NS_XPCOMPROXY_PROGID,
|
||||
NS_GET_IID(nsIProxyObjectManager),
|
||||
(nsISupports **)&manager);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
const nsXPTType& type = paramInfo.GetType();
|
||||
nsIID* iid = nsnull;
|
||||
if(type.TagPart() == nsXPTType::T_INTERFACE_IS)
|
||||
{
|
||||
uint8 arg_num;
|
||||
|
||||
rv = interfaceInfo->GetInterfaceIsArgNumberForParam(methodIndex, ¶mInfo, &arg_num);
|
||||
if(NS_FAILED(rv))
|
||||
{
|
||||
// This is really bad that we are here.
|
||||
rv = NS_ERROR_PROXY_INVALID_IN_PARAMETER;
|
||||
continue;
|
||||
}
|
||||
|
||||
const nsXPTParamInfo& param = methodInfo->GetParam(arg_num);
|
||||
const nsXPTType& currentType = param.GetType();
|
||||
|
||||
if( !currentType.IsPointer() ||
|
||||
currentType.TagPart() != nsXPTType::T_IID ||
|
||||
!(iid = (nsIID*) nsMemory::Clone(params[arg_num].val.p, sizeof(nsIID))))
|
||||
{
|
||||
// This is really bad that we are here.
|
||||
rv = NS_ERROR_PROXY_INVALID_IN_PARAMETER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
interfaceInfo->GetIIDForParam((PRUint16)methodIndex, ¶mInfo, &iid);
|
||||
}
|
||||
|
||||
if (iid == nsnull)
|
||||
{
|
||||
// could not get a IID for the parameter that is in question!
|
||||
|
||||
#ifdef DEBUG
|
||||
char* interfaceName;
|
||||
|
||||
interfaceInfo->GetName(&interfaceName);
|
||||
|
||||
printf("**************************************************\n");
|
||||
printf("xpcom-proxy: could not invoke method: %s::%s().\n", interfaceName, methodInfo->GetName());
|
||||
printf(" could not find an IID for a parameter: %d\n", (i) );
|
||||
printf("**************************************************\n");
|
||||
|
||||
nsMemory::Free((void*)interfaceName);
|
||||
#endif /* DEBUG */
|
||||
|
||||
|
||||
rv = NS_ERROR_PROXY_INVALID_IN_PARAMETER; //TODO: Change error code
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
nsCOMPtr<nsIEventQueue> eventQ;
|
||||
/*
|
||||
if the parameter is coming |in|, it should only be called on the callers thread.
|
||||
else, if the parameter is an |out| thread, it should only be called on the proxy
|
||||
objects thread
|
||||
*/
|
||||
|
||||
if (paramInfo.IsOut())
|
||||
{
|
||||
eventQ = GetQueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mEventQService == nsnull) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ);
|
||||
if ( NS_FAILED( rv ) )
|
||||
{
|
||||
// the caller does not have an eventQ of their own. bad.
|
||||
eventQ = GetQueue();
|
||||
rv = NS_OK; // todo: remove!
|
||||
#ifdef DEBUG
|
||||
printf("**************************************************\n");
|
||||
printf("xpcom-proxy: Caller does not have an EventQ\n");
|
||||
printf("**************************************************\n");
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
}
|
||||
|
||||
/* This is a hack until we can do some lookup
|
||||
in the register to find the threading model
|
||||
of an object. right now, nsIAtom should be
|
||||
treated as a free threaded object since layout
|
||||
does evil things like compare pointer for direct
|
||||
equality. Again, this will go away when we can
|
||||
use co-classes to find the ClassID. Then look in
|
||||
the register for the thread model
|
||||
*/
|
||||
|
||||
if (NS_SUCCEEDED( rv ) && iid && iid->Equals(NS_GET_IID(nsIAtom)))
|
||||
{
|
||||
nsMemory::Free((void*)iid);
|
||||
NS_RELEASE(manager);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ( NS_SUCCEEDED( rv ) )
|
||||
{
|
||||
rv = manager->GetProxyForObject(eventQ,
|
||||
*iid,
|
||||
anInterface,
|
||||
GetProxyType(),
|
||||
(void **) &aProxyObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nsMemory::Free((void*)iid);
|
||||
NS_RELEASE(manager);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// stuff the new proxies into the val.p. If it is an OUT parameter, release once
|
||||
// the real object to force the proxy to be the owner.
|
||||
if (paramInfo.IsOut())
|
||||
{
|
||||
anInterface->Release();
|
||||
*((void**)params[i].val.p) = ((void*)aProxyObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
(params[i].val.p) = ((void*)aProxyObject);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could not get nsIProxyObjectManager
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// It already is a proxy!
|
||||
}
|
||||
}
|
||||
else if ( (convertType == convertOutParameters) && paramInfo.IsIn() )
|
||||
{
|
||||
// we need to Release() any |in| parameters that we created proxies for
|
||||
// and replace the proxied object with the real object on the stack.
|
||||
nsProxyEventObject* replaceInterface = ((nsProxyEventObject*)params[i].val.p);
|
||||
if (replaceInterface)
|
||||
{
|
||||
/* ssc@netscape.com wishes he could get rid of this
|
||||
* instance of |NS_DEFINE_IID|, but
|
||||
* |ProxyEventClassIdentity| is not visible from here
|
||||
*/
|
||||
nsISupports *aIdentificationObject;
|
||||
rv = replaceInterface->QueryInterface(kProxyObject_Identity_Class_IID, (void**)&aIdentificationObject);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsISupports* realObject = replaceInterface->GetRealObject();
|
||||
replaceInterface->Release();
|
||||
(params[i].val.p) = ((void*)realObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
static void* ProxyDestructorEventHandler(PLEvent *self)
|
||||
{
|
||||
nsProxyObject* owner = (nsProxyObject*) PL_GetEventOwner(self);
|
||||
NS_DELETEXPCOM(owner);
|
||||
return nsnull;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ProxyDestructorDestroyHandler(PLEvent *self)
|
||||
{
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user