Back to index

lightning-sunbird  0.9+nobinonly
nsProxyEvent.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK *****
00038  *
00039  * This Original Code has been modified by IBM Corporation.
00040  * Modifications made by IBM described herein are
00041  * Copyright (c) International Business Machines
00042  * Corporation, 2000
00043  *
00044  * Modifications to Mozilla code or documentation
00045  * identified per MPL Section 3.3
00046  *
00047  * Date             Modified by     Description of modification
00048  * 04/20/2000       IBM Corp.      Added PR_CALLBACK for Optlink use in OS2
00049  */
00050 
00051 #include "nsProxyEvent.h"
00052 #include "nsProxyEventPrivate.h"
00053 #include "nsIProxyObjectManager.h"
00054 #include "nsCRT.h"
00055 
00056 #include "pratom.h"
00057 #include "prmem.h"
00058 #include "xptcall.h"
00059 
00060 #include "nsIComponentManager.h"
00061 #include "nsMemory.h"
00062 #include "nsIEventQueueService.h"
00063 #include "nsIThread.h"
00064 
00065 #include "nsIAtom.h"  //hack!  Need a way to define a component as threadsafe (ie. sta).
00066 
00072 #define nsAUTF8String nsACString
00073 #define nsUTF8String nsCString
00074 
00075 static void* PR_CALLBACK EventHandler(PLEvent *self);
00076 static void  PR_CALLBACK DestroyHandler(PLEvent *self);
00077 static void* PR_CALLBACK CompletedEventHandler(PLEvent *self);
00078 static void PR_CALLBACK CompletedDestroyHandler(PLEvent *self) ;
00079 static void* PR_CALLBACK ProxyDestructorEventHandler(PLEvent *self);
00080 static void PR_CALLBACK ProxyDestructorDestroyHandler(PLEvent *self) ;
00081 
00082 nsProxyObjectCallInfo::nsProxyObjectCallInfo( nsProxyObject* owner,
00083                                               nsXPTMethodInfo *methodInfo,
00084                                               PRUint32 methodIndex, 
00085                                               nsXPTCVariant* parameterList, 
00086                                               PRUint32 parameterCount, 
00087                                               PLEvent *event)
00088 {
00089     NS_ASSERTION(owner, "No nsProxyObject!");
00090     NS_ASSERTION(methodInfo, "No nsXPTMethodInfo!");
00091     NS_ASSERTION(event, "No PLEvent!");
00092     
00093     mCompleted        = 0;
00094     mMethodIndex      = methodIndex;
00095     mParameterList    = parameterList;
00096     mParameterCount   = parameterCount;
00097     mEvent            = event;
00098     mMethodInfo       = methodInfo;
00099     mCallersEventQ    = nsnull;
00100 
00101     mOwner            = owner;
00102     
00103     RefCountInInterfacePointers(PR_TRUE);
00104     if (mOwner->GetProxyType() & PROXY_ASYNC)
00105         CopyStrings(PR_TRUE);
00106 }
00107 
00108 
00109 nsProxyObjectCallInfo::~nsProxyObjectCallInfo()
00110 {
00111     RefCountInInterfacePointers(PR_FALSE);
00112     if (mOwner->GetProxyType() & PROXY_ASYNC)
00113         CopyStrings(PR_FALSE);
00114 
00115     mOwner = nsnull;
00116     
00117     PR_FREEIF(mEvent);
00118     
00119     if (mParameterList)  
00120         free( (void*) mParameterList);
00121 }
00122 
00123 void
00124 nsProxyObjectCallInfo::RefCountInInterfacePointers(PRBool addRef)
00125 {
00126     for (PRUint32 i = 0; i < mParameterCount; i++)
00127     {
00128         nsXPTParamInfo paramInfo = mMethodInfo->GetParam(i);
00129 
00130         if (paramInfo.GetType().IsInterfacePointer() )
00131         {
00132             nsISupports* anInterface = nsnull;
00133 
00134             if (paramInfo.IsIn())
00135             {
00136                 anInterface = ((nsISupports*)mParameterList[i].val.p);
00137                 
00138                 if (anInterface)
00139                 {
00140                     if(addRef)
00141                         anInterface->AddRef();
00142                     else
00143                         anInterface->Release();
00144             
00145                 }
00146             }
00147         }
00148     }
00149 }
00150 
00151 void
00152 nsProxyObjectCallInfo::CopyStrings(PRBool copy)
00153 {
00154     for (PRUint32 i = 0; i < mParameterCount; i++)
00155     {
00156         const nsXPTParamInfo paramInfo = mMethodInfo->GetParam(i);
00157 
00158         if(paramInfo.IsIn())
00159         {
00160             const nsXPTType& type = paramInfo.GetType();
00161             uint8 type_tag = type.TagPart();
00162             void *ptr = mParameterList[i].val.p;
00163 
00164             if (!ptr)
00165                 continue;
00166 
00167             if (copy)
00168             {                
00169                 switch (type_tag) 
00170                 {
00171                     case nsXPTType::T_CHAR_STR:                                
00172                         mParameterList[i].val.p =
00173                             PL_strdup((const char *)ptr);
00174                         break;
00175                     case nsXPTType::T_WCHAR_STR:
00176                         mParameterList[i].val.p =
00177                             nsCRT::strdup((const PRUnichar *)ptr);
00178                         break;
00179                     case nsXPTType::T_DOMSTRING:
00180                     case nsXPTType::T_ASTRING:
00181                         mParameterList[i].val.p = 
00182                             new nsString(*((nsAString*) ptr));
00183                         break;
00184                     case nsXPTType::T_CSTRING:
00185                         mParameterList[i].val.p = 
00186                             new nsCString(*((nsACString*) ptr));
00187                         break;
00188                     case nsXPTType::T_UTF8STRING:                        
00189                         mParameterList[i].val.p = 
00190                             new nsUTF8String(*((nsAUTF8String*) ptr));
00191                         break;
00192                     default:
00193                         // Other types are ignored
00194                         break;                    
00195                 }
00196             }
00197             else
00198             {
00199                 switch (type_tag) 
00200                 {
00201                     case nsXPTType::T_CHAR_STR:
00202                     case nsXPTType::T_WCHAR_STR:
00203                         PL_strfree((char*) ptr);
00204                         break;
00205                     case nsXPTType::T_DOMSTRING:
00206                     case nsXPTType::T_ASTRING:
00207                         delete (nsString*) ptr;
00208                         break;
00209                     case nsXPTType::T_CSTRING:
00210                         delete (nsCString*) ptr;
00211                         break;
00212                     case nsXPTType::T_UTF8STRING:
00213                         delete (nsUTF8String*) ptr;
00214                         break;
00215                     default:
00216                         // Other types are ignored
00217                         break;
00218                 }
00219             }
00220         }
00221     }
00222 }
00223 
00224 PRBool                
00225 nsProxyObjectCallInfo::GetCompleted()
00226 {
00227     return (PRBool)mCompleted;
00228 }
00229 
00230 void
00231 nsProxyObjectCallInfo::SetCompleted()
00232 {
00233     PR_AtomicSet(&mCompleted, 1);
00234 }
00235 
00236 void                
00237 nsProxyObjectCallInfo::PostCompleted()
00238 {
00239     if (mCallersEventQ)
00240     {
00241         PLEvent *event = PR_NEW(PLEvent);
00242     
00243         PL_InitEvent(event, 
00244                      this,
00245                      CompletedEventHandler,
00246                      CompletedDestroyHandler);
00247    
00248         mCallersEventQ->PostSynchronousEvent(event, nsnull);
00249         PR_FREEIF(event);
00250     }
00251     else
00252     {
00253         // caller does not have an eventQ? This is an error!
00254         SetCompleted();
00255     }
00256 }
00257   
00258 nsIEventQueue*      
00259 nsProxyObjectCallInfo::GetCallersQueue() 
00260 { 
00261     return mCallersEventQ;
00262 }   
00263 void
00264 nsProxyObjectCallInfo::SetCallersQueue(nsIEventQueue* queue)
00265 {
00266     mCallersEventQ = queue;
00267 }   
00268 
00269 
00270 nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject,
00271        nsIEventQueueService* eventQService)
00272 {
00273     mEventQService = eventQService;
00274 
00275     mRealObject      = realObject;
00276     mDestQueue       = do_QueryInterface(destQueue);
00277     mProxyType       = proxyType;
00278 }
00279 
00280 
00281 nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32  proxyType, const nsCID &aClass,  
00282        nsISupports *aDelegate,  const nsIID &aIID, nsIEventQueueService* eventQService)
00283 {
00284     mEventQService = eventQService;
00285 
00286     nsCOMPtr<nsIComponentManager> compMgr;
00287     NS_GetComponentManager(getter_AddRefs(compMgr));
00288     compMgr->CreateInstance(aClass, 
00289                             aDelegate,
00290                             aIID,
00291                             getter_AddRefs(mRealObject));
00292 
00293     mDestQueue       = do_QueryInterface(destQueue);
00294     mProxyType       = proxyType;
00295 }
00296 
00297 nsProxyObject::~nsProxyObject()
00298 {   
00299     // I am worried about order of destruction here.  
00300     // do not remove assignments.
00301     
00302     mRealObject = 0;
00303     mDestQueue  = 0;
00304 }
00305 
00306 
00307 void
00308 nsProxyObject::AddRef()
00309 {
00310   PR_AtomicIncrement((PRInt32 *)&mRefCnt);
00311   NS_LOG_ADDREF(this, mRefCnt, "nsProxyObject", sizeof(*this));
00312 }
00313 
00314 void
00315 nsProxyObject::Release(void)
00316 {
00317   NS_PRECONDITION(0 != mRefCnt, "dup release");             
00318 
00319   nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
00320   NS_LOG_RELEASE(this, count, "nsProxyObject");
00321 
00322   if (count == 0)
00323   {
00324        mRefCnt = 1; /* stabilize */
00325 
00326        PRBool callDirectly;
00327        mDestQueue->IsOnCurrentThread(&callDirectly);
00328 
00329        if (callDirectly)
00330        {
00331            delete this;
00332            return;
00333        }
00334 
00335       // need to do something special here so that
00336       // the real object will always be deleted on
00337       // the correct thread..
00338 
00339        PLEvent *event = PR_NEW(PLEvent);
00340        if (event == nsnull)
00341        {
00342            NS_ASSERTION(0, "Could not create a plevent. Leaking nsProxyObject!");
00343            return;  // if this happens we are going to leak.
00344        }
00345        
00346        PL_InitEvent(event, 
00347                     this,
00348                     ProxyDestructorEventHandler,
00349                     ProxyDestructorDestroyHandler);  
00350 
00351        mDestQueue->PostEvent(event);
00352   }                          
00353 }                
00354 
00355 
00356 nsresult
00357 nsProxyObject::PostAndWait(nsProxyObjectCallInfo *proxyInfo)
00358 {
00359     if (proxyInfo == nsnull || mEventQService == nsnull) 
00360         return NS_ERROR_NULL_POINTER;
00361     
00362     PRBool eventLoopCreated = PR_FALSE;
00363     nsresult rv; 
00364 
00365     nsCOMPtr<nsIEventQueue> eventQ;
00366     rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ));
00367     if (NS_FAILED(rv))
00368     {
00369         rv = mEventQService->CreateMonitoredThreadEventQueue();
00370         eventLoopCreated = PR_TRUE;
00371         if (NS_FAILED(rv))
00372             return rv;
00373         
00374         rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ));
00375     }
00376 
00377     if (NS_FAILED(rv))
00378         return rv;
00379     
00380     proxyInfo->SetCallersQueue(eventQ);
00381 
00382     PLEvent* event = proxyInfo->GetPLEvent();
00383     if (!event)
00384         return NS_ERROR_NULL_POINTER;
00385     
00386     mDestQueue->PostEvent(event);
00387 
00388     while (! proxyInfo->GetCompleted())
00389     {
00390         PLEvent *nextEvent;
00391         rv = eventQ->WaitForEvent(&nextEvent);
00392         if (NS_FAILED(rv)) break;
00393                 
00394         eventQ->HandleEvent(nextEvent);
00395     }  
00396 
00397     if (eventLoopCreated)
00398     {
00399          mEventQService->DestroyThreadEventQueue();
00400          eventQ = 0;
00401     }
00402     
00403     return rv;
00404 }
00405         
00406         
00407 nsresult
00408 nsProxyObject::convertMiniVariantToVariant(nsXPTMethodInfo *methodInfo, 
00409                                            nsXPTCMiniVariant * params, 
00410                                            nsXPTCVariant **fullParam, 
00411                                            uint8 *outParamCount)
00412 {
00413     uint8 paramCount = methodInfo->GetParamCount();
00414     *outParamCount = paramCount;
00415     *fullParam = nsnull;
00416 
00417     if (!paramCount) return NS_OK;
00418         
00419     *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount);
00420     
00421     if (*fullParam == nsnull)
00422         return NS_ERROR_OUT_OF_MEMORY;
00423     
00424     for (int i = 0; i < paramCount; i++)
00425     {
00426         const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i);
00427         if ((mProxyType & PROXY_ASYNC) && paramInfo.IsDipper())
00428         {
00429             NS_WARNING("Async proxying of out parameters is not supported"); 
00430             return NS_ERROR_PROXY_INVALID_OUT_PARAMETER;
00431         }
00432         uint8 flags = paramInfo.IsOut() ? nsXPTCVariant::PTR_IS_DATA : 0;
00433         (*fullParam)[i].Init(params[i], paramInfo.GetType(), flags);
00434     }
00435     
00436     return NS_OK;
00437 }
00438         
00439 nsresult
00440 nsProxyObject::Post( PRUint32 methodIndex, 
00441                      nsXPTMethodInfo *methodInfo, 
00442                      nsXPTCMiniVariant * params, 
00443                      nsIInterfaceInfo *interfaceInfo)            
00444 {
00445     nsresult rv = NS_OK; 
00446 
00447     if (! mDestQueue  || ! mRealObject)
00448         return NS_ERROR_OUT_OF_MEMORY;
00449 
00450     if (methodInfo->IsNotXPCOM())
00451         return NS_ERROR_PROXY_INVALID_IN_PARAMETER;
00452     
00453     nsXPTCVariant *fullParam;
00454     uint8 paramCount; 
00455     rv = convertMiniVariantToVariant(methodInfo, params, &fullParam, &paramCount);
00456     
00457     if (NS_FAILED(rv))
00458         return rv;
00459 
00460     PRBool callDirectly;
00461 
00462     // see if we should call into the method directly. Either it is a QI function call
00463     // (methodIndex == 0), or it is a sync proxy and this code is running on the same thread
00464     // as the destination event queue. 
00465     if ( (methodIndex == 0) ||
00466          (mProxyType & PROXY_SYNC && 
00467           NS_SUCCEEDED(mDestQueue->IsOnCurrentThread(&callDirectly)) &&
00468           callDirectly))
00469     {
00470 
00471         // invoke the magic of xptc...
00472         nsresult rv = XPTC_InvokeByIndex( mRealObject, 
00473                                           methodIndex,
00474                                           paramCount, 
00475                                           fullParam);
00476         
00477         if (fullParam) 
00478             free(fullParam);
00479         return rv;
00480     }
00481 
00482     PLEvent *event = PR_NEW(PLEvent);
00483     
00484     if (event == nsnull) {
00485         if (fullParam) 
00486             free(fullParam);
00487         return NS_ERROR_OUT_OF_MEMORY;   
00488     }
00489 
00490     nsProxyObjectCallInfo *proxyInfo = new nsProxyObjectCallInfo(this, 
00491                                                                  methodInfo, 
00492                                                                  methodIndex, 
00493                                                                  fullParam,   // will be deleted by ~()
00494                                                                  paramCount, 
00495                                                                  event);      // will be deleted by ~()
00496     
00497     if (proxyInfo == nsnull) {
00498         PR_DELETE(event);
00499         if (fullParam)
00500             free(fullParam);
00501         return NS_ERROR_OUT_OF_MEMORY;  
00502     }
00503 
00504     PL_InitEvent(event, 
00505                  proxyInfo,
00506                  EventHandler,
00507                  DestroyHandler);
00508    
00509     if (mProxyType & PROXY_SYNC)
00510     {
00511         rv = PostAndWait(proxyInfo);
00512         
00513         if (NS_SUCCEEDED(rv))
00514             rv = proxyInfo->GetResult();
00515         delete proxyInfo;
00516         return rv;
00517     }
00518     
00519     if (mProxyType & PROXY_ASYNC)
00520     {
00521         mDestQueue->PostEvent(event);
00522         return NS_OK;
00523     }
00524     return NS_ERROR_UNEXPECTED;
00525 }
00526 
00527 
00528 
00529 static void DestroyHandler(PLEvent *self) 
00530 {
00531     nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self);
00532     nsProxyObject* proxyObject = owner->GetProxyObject();
00533     
00534     if (proxyObject == nsnull)
00535         return;
00536  
00537     if (proxyObject->GetProxyType() & PROXY_ASYNC)
00538     {        
00539         delete owner;
00540     }
00541     else
00542     {
00543         owner->PostCompleted();
00544     }
00545 
00546 }
00547 
00548 static void* EventHandler(PLEvent *self) 
00549 {
00550     nsProxyObjectCallInfo *info = (nsProxyObjectCallInfo*)PL_GetEventOwner(self);
00551     NS_ASSERTION(info, "No nsProxyObjectCallInfo!");
00552     
00553     nsProxyObject *proxyObject = info->GetProxyObject();
00554         
00555     if (proxyObject)
00556     {
00557         // invoke the magic of xptc...
00558         nsresult rv = XPTC_InvokeByIndex( proxyObject->GetRealObject(), 
00559                                           info->GetMethodIndex(),
00560                                           info->GetParameterCount(), 
00561                                           info->GetParameterList());
00562         info->SetResult(rv);
00563     }
00564     else
00565     {
00566         info->SetResult(NS_ERROR_OUT_OF_MEMORY);
00567     }
00568     return NULL;
00569 }
00570 
00571 static void CompletedDestroyHandler(PLEvent *self) 
00572 {
00573 }
00574 
00575 static void* CompletedEventHandler(PLEvent *self) 
00576 {
00577     nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self);
00578     owner->SetCompleted();
00579     return nsnull;
00580 }
00581 
00582 static void* ProxyDestructorEventHandler(PLEvent *self)
00583 {              
00584     nsProxyObject* owner = (nsProxyObject*) PL_GetEventOwner(self);
00585     NS_DELETEXPCOM(owner);
00586     return nsnull;                                            
00587 }
00588 
00589 static void ProxyDestructorDestroyHandler(PLEvent *self)
00590 {
00591     PR_DELETE(self);
00592 }
00593