VirtualBox

Changeset 30607 in vbox


Ignore:
Timestamp:
Jul 5, 2010 12:29:12 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
63333
Message:

webservice: optimizations second try: avoid calling QueryInterface? for every object lookup when interface UUIDs can be more easily compared (this avoids constantly creating and deleting temporary stubs in XPCOM; avoid excessive string copying when returning MORs

Location:
trunk/src/VBox/Main/webservice
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/webservice/vboxweb.cpp

    r30584 r30607  
    107107bool                    g_fDaemonize = false;           // run in background.
    108108#endif
     109
     110const WSDLT_ID          g_EmptyWSDLID;                  // for NULL MORs
    109111
    110112/****************************************************************************
     
    11681170            }
    11691171
    1170             _pISession = new ManagedObjectRef(*this, g_pcszISession, session);
     1172            ComPtr<IUnknown> p2 = session;
     1173            _pISession = new ManagedObjectRef(*this,
     1174                                              p2,                               // IUnknown *pobjUnknown
     1175                                              session,                          // void *pobjInterface
     1176                                              com::Guid(COM_IIDOF(ISession)),
     1177                                              g_pcszISession);
    11711178
    11721179            if (g_fVerbose)
    11731180            {
    11741181                ISession *p = session;
    1175                 std::string strMOR = _pISession->toWSDL();
    1176                 WEBDEBUG(("   * %s: created session object with comptr 0x%lX, MOR = %s\n", __FUNCTION__, p, strMOR.c_str()));
     1182                WEBDEBUG(("   * %s: created session object with comptr 0x%lX, MOR = %s\n", __FUNCTION__, p, _pISession->getWSDLID().c_str()));
    11771183            }
    11781184        } while (0);
     
    11971203 * @return The existing ManagedObjectRef that represents the COM object, or NULL if there's none yet.
    11981204 */
    1199 ManagedObjectRef* WebServiceSession::findRefFromPtr(const ComPtr<IUnknown> &pcu)
     1205ManagedObjectRef* WebServiceSession::findRefFromPtr(const IUnknown *pObject)
    12001206{
    12011207    Assert(g_pSessionsLockHandle->isWriteLockOnCurrentThread());
    12021208
    1203     IUnknown *p = pcu;
    1204     uintptr_t ulp = (uintptr_t)p;
    1205     ManagedObjectRef *pRef;
     1209    uintptr_t ulp = (uintptr_t)pObject;
    12061210    // WEBDEBUG(("   %s: looking up 0x%lX\n", __FUNCTION__, ulp));
    12071211    ManagedObjectsMapByPtr::iterator it = _pp->_mapManagedObjectsByPtr.find(ulp);
    12081212    if (it != _pp->_mapManagedObjectsByPtr.end())
    12091213    {
    1210         pRef = it->second;
    1211         WSDLT_ID id = pRef->toWSDL();
    1212         WEBDEBUG(("   %s: found existing ref %s (%s) for COM obj 0x%lX\n", __FUNCTION__, id.c_str(), pRef->getInterfaceName(), ulp));
    1213     }
    1214     else
    1215         pRef = NULL;
    1216     return pRef;
     1214        ManagedObjectRef *pRef = it->second;
     1215        WEBDEBUG(("   %s: found existing ref %s (%s) for COM obj 0x%lX\n", __FUNCTION__, pRef->getWSDLID().c_str(), pRef->getInterfaceName(), ulp));
     1216        return pRef;
     1217    }
     1218
     1219    return NULL;
    12171220}
    12181221
     
    12471250 *
    12481251 */
    1249 WSDLT_ID WebServiceSession::getSessionObject() const
    1250 {
    1251     return _pISession->toWSDL();
     1252const WSDLT_ID& WebServiceSession::getSessionWSDLID() const
     1253{
     1254    return _pISession->getWSDLID();
    12521255}
    12531256
     
    12661269}
    12671270
    1268 /**
    1269  *
    1270  */
    1271 void WebServiceSession::DumpRefs()
    1272 {
    1273     WEBDEBUG(("   dumping object refs:\n"));
    1274     ManagedObjectsIteratorById
    1275         iter = _pp->_mapManagedObjectsById.begin(),
    1276         end = _pp->_mapManagedObjectsById.end();
    1277     for (;
    1278         iter != end;
    1279         ++iter)
    1280     {
    1281         ManagedObjectRef *pRef = iter->second;
    1282         uint64_t id = pRef->getID();
    1283         void *p = pRef->getComPtr();
    1284         WEBDEBUG(("     objid %llX: comptr 0x%lX\n", id, p));
    1285     }
    1286 }
    12871271
    12881272/****************************************************************************
     
    13091293 *      instance already exists for a given COM pointer.
    13101294 *
     1295 *  This constructor calls AddRef() on the given COM object, and
     1296 *  the destructor will call Release(). We require two input pointers
     1297 *  for that COM object, one generic IUnknown* pointer which is used
     1298 *  as the map key, and a specific interface pointer (e.g. IMachine*)
     1299 *  which must support the interface given in guidInterface. All
     1300 *  three values are returned by getPtr(), which gives future callers
     1301 *  a chance to reuse the specific interface pointer without having
     1302 *  to call QueryInterface, which can be expensive.
     1303 *
    13111304 *  This does _not_ check whether another instance already
    13121305 *  exists in the hash. This gets called only from the
    1313  *  createRefFromObject() template function in vboxweb.h, which
     1306 *  createOrFindRefFromComPtr() template function in vboxweb.h, which
    13141307 *  does perform that check.
    13151308 *
    13161309 * Preconditions: Caller must have locked g_pSessionsLockHandle.
    13171310 *
    1318  * @param pObj
     1311 * @param session Session to which the MOR will be added.
     1312 * @param pobjUnknown Pointer to IUnknown* interface for the COM object; this will be used in the hashes.
     1313 * @param pobjInterface Pointer to a specific interface for the COM object, described by guidInterface.
     1314 * @param guidInterface Interface which pobjInterface points to.
     1315 * @param pcszInterface String representation of that interface (e.g. "IMachine") for readability and logging.
    13191316 */
    13201317ManagedObjectRef::ManagedObjectRef(WebServiceSession &session,
    1321                                    const char *pcszInterface,
    1322                                    const ComPtr<IUnknown> &pc)
     1318                                   IUnknown *pobjUnknown,
     1319                                   void *pobjInterface,
     1320                                   const com::Guid &guidInterface,
     1321                                   const char *pcszInterface)
    13231322    : _session(session),
    1324       _pObj(pc),
     1323      _pobjUnknown(pobjUnknown),
     1324      _pobjInterface(pobjInterface),
     1325      _guidInterface(guidInterface),
    13251326      _pcszInterface(pcszInterface)
    13261327{
    1327     ComPtr<IUnknown> pcUnknown(pc);
    1328     _ulp = (uintptr_t)(IUnknown*)pcUnknown;
     1328    Assert(pobjUnknown);
     1329    Assert(pobjInterface);
     1330
     1331    // keep both stubs alive while this MOR exists (matching Release() calls are in destructor)
     1332    uint32_t cRefs1 = pobjUnknown->AddRef();
     1333    uint32_t cRefs2 = ((IUnknown*)pobjInterface)->AddRef();
     1334    _ulp = (uintptr_t)pobjUnknown;
    13291335
    13301336    Assert(g_pSessionsLockHandle->isWriteLockOnCurrentThread());
     
    13421348    session.touch();
    13431349
    1344     WEBDEBUG(("   * %s: MOR created for ulp 0x%lX (%s), new ID is %llX; now %lld objects total\n", __FUNCTION__, _ulp, pcszInterface, _id, cTotal));
     1350    WEBDEBUG(("   * %s: MOR created for %s*=0x%lX (IUnknown*=0x%lX; COM refcount now %RI32/%RI32), new ID is %llX; now %lld objects total\n",
     1351              __FUNCTION__,
     1352              pcszInterface,
     1353              pobjInterface,
     1354              pobjUnknown,
     1355              cRefs1,
     1356              cRefs2,
     1357              _id,
     1358              cTotal));
    13451359}
    13461360
    13471361/**
    13481362 * Destructor; removes the instance from the global hash of
    1349  * managed objects.
     1363 * managed objects. Calls Release() on the contained COM object.
    13501364 *
    13511365 * Preconditions: Caller must have locked g_pSessionsLockHandle.
     
    13561370    ULONG64 cTotal = --g_cManagedObjects;
    13571371
    1358     WEBDEBUG(("   * %s: deleting MOR for ID %llX (%s); now %lld objects total\n", __FUNCTION__, _id, _pcszInterface, cTotal));
     1372    Assert(_pobjUnknown);
     1373    Assert(_pobjInterface);
     1374
     1375    // we called AddRef() on both interfaces, so call Release() on
     1376    // both as well, but in reverse order
     1377    uint32_t cRefs2 = ((IUnknown*)_pobjInterface)->Release();
     1378    uint32_t cRefs1 = _pobjUnknown->Release();
     1379    WEBDEBUG(("   * %s: deleting MOR for ID %llX (%s; COM refcount now %RI32/%RI32); now %lld objects total\n", __FUNCTION__, _id, _pcszInterface, cRefs1, cRefs2, cTotal));
    13591380
    13601381    // if we're being destroyed from the session's destructor,
     
    13681389            WEBDEBUG(("   WARNING: could not find %llX in _mapManagedObjectsByPtr\n", _ulp));
    13691390    }
    1370 }
    1371 
    1372 /**
    1373  * Converts the ID of this managed object reference to string
    1374  * form, for returning with SOAP data or similar.
    1375  *
    1376  * @return The ID in string form.
    1377  */
    1378 WSDLT_ID ManagedObjectRef::toWSDL() const
    1379 {
    1380     return _strID;
    13811391}
    13821392
     
    14241434        }
    14251435
    1426         WEBDEBUG(("   %s(): sessid %llX, objid %llX\n", __FUNCTION__, sessid, objid));
    14271436        SessionsMapIterator it = g_mapSessions.find(sessid);
    14281437        if (it == g_mapSessions.end())
     
    15971606            // that it will be implicitly be included in all future requests of this
    15981607            // webservice client
    1599             ManagedObjectRef *pRef = new ManagedObjectRef(*pSession, g_pcszIVirtualBox, g_pVirtualBox);
    1600             resp->returnval = pRef->toWSDL();
     1608            ComPtr<IUnknown> p2 = g_pVirtualBox;
     1609            ManagedObjectRef *pRef = new ManagedObjectRef(*pSession,
     1610                                                          p2,                       // IUnknown *pobjUnknown
     1611                                                          g_pVirtualBox,            // void *pobjInterface
     1612                                                          COM_IIDOF(IVirtualBox),
     1613                                                          g_pcszIVirtualBox);
     1614            resp->returnval = pRef->getWSDLID();
    16011615            WEBDEBUG(("VirtualBox object ref is %s\n", resp->returnval.c_str()));
    16021616        }
     
    16271641        WebServiceSession* pSession;
    16281642        if ((pSession = WebServiceSession::findSessionFromRef(req->refIVirtualBox)))
    1629             resp->returnval = pSession->getSessionObject();
     1643            resp->returnval = pSession->getSessionWSDLID();
    16301644
    16311645    } while (0);
     
    16721686    return SOAP_OK;
    16731687}
     1688
  • trunk/src/VBox/Main/webservice/vboxweb.h

    r30584 r30607  
    4141/****************************************************************************
    4242 *
    43  * global variables
    44  *
    45  ****************************************************************************/
    46 
    47 extern ComPtr<IVirtualBox> g_pVirtualBox;
    48 extern bool g_fVerbose;
    49 
    50 extern PRTSTREAM g_pstrLog;
    51 
    52 extern util::WriteLockHandle  *g_pAuthLibLockHandle;
    53 extern util::WriteLockHandle  *g_pSessionsLockHandle;
    54 
    55 /****************************************************************************
    56  *
    5743 * typedefs
    5844 *
     
    6248typedef std::string WSDLT_ID;               // combined managed object ref (session ID plus object ID)
    6349typedef std::string vbox__uuid;
     50
     51/****************************************************************************
     52 *
     53 * global variables
     54 *
     55 ****************************************************************************/
     56
     57extern ComPtr<IVirtualBox> g_pVirtualBox;
     58extern bool g_fVerbose;
     59
     60extern PRTSTREAM g_pstrLog;
     61
     62extern util::WriteLockHandle  *g_pAuthLibLockHandle;
     63extern util::WriteLockHandle  *g_pSessionsLockHandle;
     64
     65extern const WSDLT_ID          g_EmptyWSDLID;
    6466
    6567/****************************************************************************
     
    121123                         const char *pcszPassword);
    122124
    123         ManagedObjectRef* findRefFromPtr(const ComPtr<IUnknown> &pcu);
     125        ManagedObjectRef* findRefFromPtr(const IUnknown *pObject);
    124126
    125127        uint64_t getID() const
     
    128130        }
    129131
    130         WSDLT_ID getSessionObject() const;
     132        const WSDLT_ID& getSessionWSDLID() const;
    131133
    132134        void touch();
     
    157159        WebServiceSession           &_session;
    158160
    159         // value:
    160         ComPtr<IUnknown>            _pObj;
    161         const char                  *_pcszInterface;
     161
     162        IUnknown                    *_pobjUnknown;          // pointer to IUnknown interface for this MOR
     163
     164        void                        *_pobjInterface;        // pointer to COM interface represented by _guidInterface, for which this MOR
     165                                                            // was created; this may be an IUnknown or something more specific
     166        com::Guid                   _guidInterface;         // the interface which _pvObj represents
     167
     168        const char                  *_pcszInterface;        // string representation of that interface (e.g. "IMachine")
    162169
    163170        // keys:
     
    170177    public:
    171178        ManagedObjectRef(WebServiceSession &session,
    172                          const char *pcszInterface,
    173                          const ComPtr<IUnknown> &obj);
     179                         IUnknown *pobjUnknown,
     180                         void *pobjInterface,
     181                         const com::Guid &guidInterface,
     182                         const char *pcszInterface);
    174183        ~ManagedObjectRef();
    175184
     
    179188        }
    180189
    181         ComPtr<IUnknown> getComPtr()
    182         {
    183             return _pObj;
    184         }
    185 
    186         WSDLT_ID toWSDL() const;
     190        /**
     191         * Returns the contained COM pointer and the UUID of the COM interface
     192         * which it supports.
     193         * @param
     194         * @return
     195         */
     196        const com::Guid& getPtr(void **ppobjInterface,
     197                                IUnknown **ppobjUnknown)
     198        {
     199            *ppobjInterface = _pobjInterface;
     200            *ppobjUnknown = _pobjUnknown;
     201            return _guidInterface;
     202        }
     203
     204        /**
     205         * Returns the ID of this managed object reference to string
     206         * form, for returning with SOAP data or similar.
     207         *
     208         * @return The ID in string form.
     209         */
     210        const WSDLT_ID& getWSDLID() const
     211        {
     212            return _strID;
     213        }
     214
    187215        const char* getInterfaceName() const
    188216        {
     
    202230/**
    203231 * Template function that resolves a managed object reference to a COM pointer
    204  * of the template class T. Gets called from tons of generated code in
    205  * methodmaps.cpp.
     232 * of the template class T.
     233 *
     234 * This gets called only from tons of generated code in methodmaps.cpp to
     235 * resolve objects in *input* parameters to COM methods (i.e. translate
     236 * MOR strings to COM objects which should exist already).
    206237 *
    207238 * This is a template function so that we can support ComPtr's for arbitrary
    208239 * interfaces and automatically verify that the managed object reference on
    209  * the internal stack actually is of the expected interface.
     240 * the internal stack actually is of the expected interface. We also now avoid
     241 * calling QueryInterface for the case that the interface desired by the caller
     242 * is the same as the interface for which the MOR was originally created. In
     243 * that case, the lookup is very fast.
    210244 *
    211245 * @param soap
     
    231265    ManagedObjectRef *pRef;
    232266    if ((rc = ManagedObjectRef::findRefFromId(id, &pRef, fNullAllowed)))
     267        // error:
    233268        RaiseSoapInvalidObjectFault(soap, id);
    234269    else
     
    236271        if (fNullAllowed && pRef == NULL)
    237272        {
     273            WEBDEBUG(("   %s(): returning NULL object as permitted\n", __FUNCTION__));
    238274            pComPtr.setNull();
    239275            return 0;
    240276        }
    241277
    242         // pRef->getComPtr returns a ComPtr<IUnknown>; by casting it to
    243         // ComPtr<T>, we implicitly do a COM queryInterface() call
    244         if (pComPtr = pRef->getComPtr())
     278        const com::Guid &guidCaller = COM_IIDOF(T);
     279
     280        // pRef->getPtr returns both a void* for its specific interface pointer as well as a generic IUnknown*
     281        void *pobjInterface;
     282        IUnknown *pobjUnknown;
     283        const com::Guid &guidInterface = pRef->getPtr(&pobjInterface, &pobjUnknown);
     284
     285        if (guidInterface == guidCaller)
     286        {
     287            // same interface: then no QueryInterface needed
     288            WEBDEBUG(("   %s(): returning original %s*=0x%lX (IUnknown*=0x%lX)\n", __FUNCTION__, pRef->getInterfaceName(), pobjInterface, pobjUnknown));
     289            pComPtr = (T*)pobjInterface;        // this calls AddRef() once
    245290            return 0;
     291        }
     292
     293        // QueryInterface tests whether p actually supports the templated T interface desired by caller
     294        T *pT;
     295        pobjUnknown->QueryInterface(guidCaller, (void**)&pT);      // this adds a reference count
     296        if (pT)
     297        {
     298            // assign to caller's ComPtr<T>; use asOutParam() to avoid adding another reference, QueryInterface() already added one
     299            WEBDEBUG(("   %s(): returning pointer 0x%lX for queried interface %RTuuid (IUnknown*=0x%lX)\n", __FUNCTION__, pT, guidCaller.raw(), pobjUnknown));
     300            *(pComPtr.asOutParam()) = pT;
     301            return 0;
     302        }
    246303
    247304        WEBDEBUG(("    Interface not supported for object reference %s, which is of class %s\n", id.c_str(), pRef->getInterfaceName()));
     
    254311
    255312/**
    256  * Template function that creates a new managed object for the given COM
    257  * pointer of the template class T. If a reference already exists for the
    258  * given pointer, then that reference's ID is returned instead.
     313 * Creates a new managed object for the given COM pointer. If a reference already exists
     314 * for the given pointer, then that reference's ID is returned instead.
     315 *
     316 * This gets called from tons of generated code in methodmaps.cpp to
     317 * resolve objects *returned* from COM methods (i.e. create MOR strings from COM objects
     318 * which might have been newly created).
    259319 *
    260320 * @param idParent managed object reference of calling object; used to extract session ID
     
    263323 */
    264324template <class T>
    265 WSDLT_ID createOrFindRefFromComPtr(const WSDLT_ID &idParent,
    266                                    const char *pcszInterface,
    267                                    const ComPtr<T> &pc)
     325const WSDLT_ID& createOrFindRefFromComPtr(const WSDLT_ID &idParent,
     326                                          const char *pcszInterface,
     327                                         ComPtr<T> &pc)
    268328{
    269329    // NULL comptr should return NULL MOR
    270330    if (pc.isNull())
    271331    {
    272         WEBDEBUG(("   createOrFindRefFromComPtr(): returning empty MOR for NULL %s pointer\n", pcszInterface));
    273         return "";
     332        WEBDEBUG(("   createOrFindRefFromComPtr(): returning empty MOR for NULL COM pointer\n"));
     333        return g_EmptyWSDLID;
    274334    }
    275335
     
    278338    if ((pSession = WebServiceSession::findSessionFromRef(idParent)))
    279339    {
    280         // WEBDEBUG(("\n-- found session for %s\n", idParent.c_str()));
    281340        ManagedObjectRef *pRef;
    282         if (    ((pRef = pSession->findRefFromPtr(pc)))
    283              || ((pRef = new ManagedObjectRef(*pSession, pcszInterface, pc)))
     341
     342        // we need an IUnknown pointer for the MOR
     343        ComPtr<IUnknown> pobjUnknown = pc;
     344
     345        if (    ((pRef = pSession->findRefFromPtr(pobjUnknown)))
     346             || ((pRef = new ManagedObjectRef(*pSession,
     347                                              pobjUnknown,          // IUnknown *pobjUnknown
     348                                              pc,                   // void *pobjInterface
     349                                              COM_IIDOF(T),
     350                                              pcszInterface)))
    284351           )
    285             return pRef->toWSDL();
     352            return pRef->getWSDLID();
    286353    }
    287354
    288355    // session has expired, return an empty MOR instead of allocating a
    289356    // new reference which couldn't be used anyway.
    290     return "";
     357    return g_EmptyWSDLID;
    291358}
    292 
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette