VirtualBox

Changeset 45415 in vbox for trunk/src/VBox/HostServices


Ignore:
Timestamp:
Apr 8, 2013 9:40:42 PM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
84843
Message:

GuestCtrl: Implemented using (public) VirtualBox events instead of own callback mechanisms. Bugfixes for testcases (still work in progress).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostServices/GuestControl/service.cpp

    r45010 r45415  
    5959*   Header Files                                                               *
    6060*******************************************************************************/
    61 #define LOG_GROUP LOG_GROUP_HGCM
     61#ifdef LOG_GROUP
     62 #undef LOG_GROUP
     63#endif
     64#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
    6265#include <VBox/HostServices/GuestControlSvc.h>
    6366
     
    8487
    8588/** Flag for indicating that the client only is interested in
    86  *  messages for specific contexts. */
     89 *  messages of specific context IDs. */
    8790#define CLIENTSTATE_FLAG_CONTEXTFILTER      RT_BIT(0)
    8891
     
    113116    uint32_t AddRef(void)
    114117    {
     118#ifdef DEBUG_andy
     119        LogFlowFunc(("Adding reference pHostCmd=%p, CID=%RU32, new refCount=%RU32\n",
     120                     this, mContextID, mRefCount + 1));
     121#endif
    115122        return ++mRefCount;
    116123    }
     
    118125    uint32_t Release(void)
    119126    {
    120         LogFlowFunc(("Releasing CID=%RU32, refCount=%RU32\n",
    121                      mContextID, mRefCount));
    122 
     127#ifdef DEBUG_andy
     128        LogFlowFunc(("Releasing reference pHostCmd=%p, CID=%RU32, new refCount=%RU32\n",
     129                     this, mContextID, mRefCount - 1));
     130#endif
    123131        /* Release reference for current command. */
    124132        Assert(mRefCount);
     
    139147    int Allocate(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    140148    {
    141         LogFlowFunc(("Allocating uMsg=%RU32, cParms=%RU32, paParms=%p\n",
    142                      uMsg, cParms, paParms));
     149        LogFlowFunc(("Allocating pHostCmd=%p, uMsg=%RU32, cParms=%RU32, paParms=%p\n",
     150                     this, uMsg, cParms, paParms));
    143151
    144152        if (!cParms) /* At least one parameter (context ID) must be present. */
     
    219227             */
    220228            rc = mpParms[0].getUInt32(&mContextID);
     229
     230            /* Set timestamp so that clients can distinguish between already
     231             * processed commands and new ones. */
     232            mTimestamp = RTTimeNanoTS();
    221233        }
    222234
     
    232244    void Free(void)
    233245    {
    234         AssertMsg(mRefCount == 0, ("Command CID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n",
    235                                    mContextID, mRefCount));
    236 
    237         LogFlowFunc(("Freeing host command CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
    238                      mContextID, mMsgType, mParmCount, mpParms));
     246        AssertMsg(mRefCount == 0, ("pHostCmd=%p, CID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n",
     247                                   this, mContextID, mRefCount));
     248
     249        LogFlowFunc(("Freeing host command pHostCmd=%p, CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
     250                     this, mContextID, mMsgType, mParmCount, mpParms));
    239251
    240252        for (uint32_t i = 0; i < mParmCount; i++)
     
    260272        mParmCount = 0;
    261273
    262        /* Removes the command from its list */
    263        RTListNodeRemove(&Node);
     274        /* Removes the command from its list */
     275        RTListNodeRemove(&Node);
    264276    }
    265277
     
    274286    int CopyTo(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms) const
    275287    {
     288        LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mContextID=%RU32\n",
     289                     this, mMsgType, mParmCount, mContextID));
     290
    276291        int rc = VINF_SUCCESS;
    277292        if (cDstParms != mParmCount)
     
    294309                else
    295310                {
    296 #ifdef DEBUG_andy
    297                     LogFlowFunc(("\tmpParms[%RU32] type = %RU32\n",
    298                                  i, mpParms[i].type));
    299 #endif
    300311                    switch (mpParms[i].type)
    301312                    {
     
    362373        int rc;
    363374
    364         LogFlowFunc(("mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
    365                      mMsgType, mParmCount, mpParms));
     375        LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
     376                     this, mMsgType, mParmCount, mpParms));
    366377
    367378        /* Does the current host command need more parameter space which
     
    392403        }
    393404
    394         LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    395405        return rc;
    396406    }
     
    400410        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    401411
    402         LogFlowFunc(("mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
    403                      mMsgType, mParmCount, mpParms));
    404         LogFlowFunc(("Telling client the next upcoming message type=%RU32, count=%RU32\n",
    405                      mMsgType, mParmCount));
     412        LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
     413                     this, mMsgType, mParmCount, mpParms));
    406414
    407415        if (pConnection->mNumParms >= 2)
     
    431439    /** Dynamic structure for holding the HGCM parms */
    432440    uint32_t mMsgType;
     441    /** Number of HGCM parameters. */
    433442    uint32_t mParmCount;
     443    /** Array of HGCM parameters. */
    434444    PVBOXHGCMSVCPARM mpParms;
     445    /** Incoming timestamp (us). */
     446    uint64_t mTimestamp;
    435447} HostCommand;
     448typedef std::list< HostCommand *> HostCmdList;
     449typedef std::list< HostCommand *>::iterator HostCmdListIter;
     450typedef std::list< HostCommand *>::const_iterator HostCmdListIterConst;
    436451
    437452/**
     
    459474{
    460475    ClientState(void)
    461         : mSvcHelpers(NULL),
     476        : mID(0),
     477          mSvcHelpers(NULL),
    462478          mFlags(0), mContextFilter(0),
    463           mpHostCmd(NULL), mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),
    464           mIsPending(false) {}
    465 
    466     ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers)
    467         : mSvcHelpers(pSvcHelpers),
     479          mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),
     480          mHostCmdTS(0),
     481          mIsPending(false) { }
     482
     483    ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t uClientID)
     484        : mID(uClientID),
     485          mSvcHelpers(pSvcHelpers),
    468486          mFlags(0), mContextFilter(0),
    469           mpHostCmd(NULL), mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),
    470           mIsPending(false) {}
     487          mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),
     488          mHostCmdTS(0),
     489          mIsPending(false) { }
     490
     491    void DequeueAll(void)
     492    {
     493        HostCmdListIter curItem = mHostCmdList.begin();
     494        while (curItem != mHostCmdList.end())
     495            Dequeue(curItem++);
     496    }
     497
     498    void DequeueCurrent(void)
     499    {
     500        HostCmdListIter curCmd = mHostCmdList.begin();
     501        if (curCmd != mHostCmdList.end())
     502            Dequeue(curCmd);
     503    }
     504
     505    void Dequeue(HostCommand *pHostCmd)
     506    {
     507        AssertPtrReturnVoid(pHostCmd);
     508
     509        HostCmdListIter curItem = mHostCmdList.begin();
     510        while (curItem != mHostCmdList.end())
     511        {
     512            if ((*curItem) == pHostCmd)
     513            {
     514                Dequeue(curItem);
     515                break;
     516            }
     517
     518            curItem++;
     519        }
     520    }
     521
     522    void Dequeue(HostCmdListIter &curItem)
     523    {
     524        HostCommand *pHostCmd = (*curItem);
     525        AssertPtr(pHostCmd);
     526
     527        if (pHostCmd->Release() == 0)
     528        {
     529            LogFlowFunc(("[Client %RU32] Destroying pHostCmd=%p\n",
     530                         mID, (*curItem)));
     531
     532            delete pHostCmd;
     533            pHostCmd = NULL;
     534        }
     535
     536        mHostCmdList.erase(curItem);
     537
     538        /* Reset everything else. */
     539        mHostCmdRc    = VINF_SUCCESS;
     540        mHostCmdTries = 0;
     541    }
     542
     543    int EnqueueCommand(HostCommand *pHostCmd)
     544    {
     545        AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
     546
     547        int rc = VINF_SUCCESS;
     548
     549        try
     550        {
     551            mHostCmdList.push_back(pHostCmd);
     552            pHostCmd->AddRef();
     553        }
     554        catch (std::bad_alloc)
     555        {
     556            rc = VERR_NO_MEMORY;
     557        }
     558
     559        return rc;
     560    }
    471561
    472562    bool WantsHostCommand(const HostCommand *pHostCmd) const
     
    475565
    476566#ifdef DEBUG_andy
    477             LogFlowFunc(("mFlags=%x, mContextID=%RU32, mContextFilter=%x, filterRes=%x\n",
    478                          mFlags, pHostCmd->mContextID, mContextFilter, pHostCmd->mContextID & mContextFilter));
     567        LogFlowFunc(("mHostCmdTS=%RU64, pHostCmdTS=%RU64\n",
     568                     mHostCmdTS, pHostCmd->mTimestamp));
     569#endif
     570
     571        /* Only process newer commands. */
     572        if (pHostCmd->mTimestamp <= mHostCmdTS)
     573            return false;
     574
     575#ifdef DEBUG_andy
     576            LogFlowFunc(("[Client %RU32] mFlags=%x, mContextID=%RU32, mContextFilter=%x, filterRes=%x, sessionID=%RU32\n",
     577                         mID, mFlags, pHostCmd->mContextID, mContextFilter,
     578                         pHostCmd->mContextID & mContextFilter, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->mContextID)));
    479579#endif
    480580        /*
    481581         * If a sesseion filter is set, only obey those sessions we're interested in.
    482582         */
     583        bool fWant = false;
    483584        if (mFlags & CLIENTSTATE_FLAG_CONTEXTFILTER)
    484585        {
    485586            if ((pHostCmd->mContextID & mContextFilter) == mContextFilter)
    486                 return true;
     587                fWant = true;
    487588        }
    488589        else /* Client is interested in all commands. */
    489             return true;
    490 
    491         return false;
     590            fWant = true;
     591
     592        return fWant;
    492593    }
    493594
     
    496597        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    497598
    498         LogFlowFunc(("mIsPending=%RTbool, mpHostCmd=%p, CID=%RU32, type=%RU32\n",
    499                      mIsPending, mpHostCmd,
    500                      mpHostCmd ? mpHostCmd->mContextID : 0,
    501                      mpHostCmd ? mpHostCmd->mMsgType : 0));
    502 
    503599        if (mIsPending)
    504600        {
    505             LogFlowFunc(("Client already is in pending mode\n"));
     601            LogFlowFunc(("[Client %RU32] Already is in pending mode\n", mID));
    506602
    507603            /*
     
    511607        }
    512608
    513         if (mpHostCmd == NULL)
     609        if (mHostCmdList.empty())
    514610        {
    515611            AssertMsg(mIsPending == false,
    516                       ("Client %p already is pending but tried to receive a new host command\n", this));
    517 
    518             mPending.mHandle   = pConnection->mHandle;
    519             mPending.mNumParms = pConnection->mNumParms;
    520             mPending.mParms    = pConnection->mParms;
     612                      ("Client ID=%RU32 already is pending but tried to receive a new host command\n", mID));
     613
     614            mPendingCon.mHandle   = pConnection->mHandle;
     615            mPendingCon.mNumParms = pConnection->mNumParms;
     616            mPendingCon.mParms    = pConnection->mParms;
    521617
    522618            mIsPending = true;
    523619
    524             LogFlowFunc(("Client now is in pending mode\n"));
     620            LogFlowFunc(("[Client %RU32] Is now in pending mode\n", mID));
    525621
    526622            /*
     
    538634    }
    539635
    540     int SetNextCommand(HostCommand *pHostCmd)
    541     {
     636    int Run(const ClientConnection *pConnection,
     637                  HostCommand      *pHostCmd)
     638    {
     639        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    542640        AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
    543641
    544         mpHostCmd = pHostCmd;
    545         AssertPtr(mpHostCmd);
    546         mpHostCmd->AddRef();
    547 
    548         /* Create a command context to keep track of client-specific
    549          * information about a certain command. */
    550         Assert(mContextMap.find(mpHostCmd->mContextID) == mContextMap.end());
    551         mContextMap[mpHostCmd->mContextID] = ClientContext(mpHostCmd);
    552         /** @todo Exception handling! */
    553 
    554         LogFlowFunc(("Assigning next host comamnd CID=%RU32, cmdType=%RU32, cmdParms=%RU32, new refCount=%RU32\n",
    555                      mpHostCmd->mContextID, mpHostCmd->mMsgType, mpHostCmd->mParmCount, mpHostCmd->mRefCount));
    556 
    557         return VINF_SUCCESS;
    558     }
    559 
    560     int Run(const ClientConnection *pConnection,
    561             const RTLISTANCHOR     *pHostCmdList)
    562     {
    563642        int rc = VINF_SUCCESS;
    564643
    565         LogFlowFunc(("Client pConnection=%p, pHostCmdList=%p\n",
    566                       pConnection, pHostCmdList));
    567         LogFlowFunc(("Client hostCmd=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n",
    568                       mpHostCmd, mHostCmdRc, mHostCmdTries));
    569 
    570         /* No current command? Try getting a new one to process now. */
    571         if (mpHostCmd == NULL)
    572         {
    573             /* Get the next host command the clienet is interested in. */
    574             bool fFoundCmd = false;
    575             HostCommand *pCurCmd;
    576             RTListForEach(pHostCmdList, pCurCmd, HostCommand, Node)
     644        LogFlowFunc(("[Client %RU32] pConnection=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n",
     645                      mID, pConnection, mHostCmdRc, mHostCmdTries));
     646
     647        mHostCmdRc = SendReply(pConnection, pHostCmd);
     648        LogFlowFunc(("[Client %RU32] Processing pHostCmd=%p ended with rc=%Rrc\n",
     649                     mID, pHostCmd, mHostCmdRc));
     650
     651        bool fRemove = false;
     652        if (RT_FAILURE(mHostCmdRc))
     653        {
     654            mHostCmdTries++;
     655
     656            /*
     657             * If the client understood the message but supplied too little buffer space
     658             * don't send this message again and drop it after 3 unsuccessful attempts.
     659             * The host then should take care of next actions (maybe retry it with a smaller buffer).
     660             */
     661            if (mHostCmdRc == VERR_TOO_MUCH_DATA)
    577662            {
    578                 fFoundCmd = WantsHostCommand(pCurCmd);
    579                 if (fFoundCmd)
    580                 {
    581                     int rc2 = SetNextCommand(pCurCmd);
    582                     if (RT_SUCCESS(rc2))
    583                         break;
    584                 }
    585             }
    586 
    587             LogFlowFunc(("Client %s new command\n",
    588                          fFoundCmd ? "found" : "did not find a"));
    589 
    590             /* If no new command was found, set client into pending state. */
    591             if (!fFoundCmd)
    592                 rc = SetPending(pConnection);
    593         }
    594 
    595         if (mpHostCmd)
    596         {
    597             AssertPtr(mpHostCmd);
    598             mHostCmdRc = SendReply(pConnection, mpHostCmd);
    599             LogFlowFunc(("Processing command CID=%RU32 ended with rc=%Rrc\n",
    600                          mpHostCmd->mContextID, mHostCmdRc));
    601 
    602             bool fRemove = false;
    603             if (RT_FAILURE(mHostCmdRc))
    604             {
    605                 mHostCmdTries++;
    606 
    607                 /*
    608                  * If the client understood the message but supplied too little buffer space
    609                  * don't send this message again and drop it after 3 unsuccessful attempts.
    610                  * The host then should take care of next actions (maybe retry it with a smaller buffer).
    611                  */
    612                 if (   mHostCmdRc    == VERR_TOO_MUCH_DATA
    613                     && mHostCmdTries >= 3)
    614                 {
    615                     fRemove = true;
    616                 }
    617                 /* Client did not understand the message or something else weird happened. Try again one
    618                  * more time and drop it if it didn't get handled then. */
    619                 else if (mHostCmdTries > 1)
     663                if (mHostCmdTries >= 3)
    620664                    fRemove = true;
    621665            }
     666            /* Client did not understand the message or something else weird happened. Try again one
     667             * more time and drop it if it didn't get handled then. */
     668            else if (mHostCmdTries > 1)
     669                fRemove = true;
     670        }
     671        else
     672            fRemove = true; /* Everything went fine, remove it. */
     673
     674        LogFlowFunc(("[Client %RU32] Tried pHostCmd=%p for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n",
     675                     mID, pHostCmd, mHostCmdTries, mHostCmdRc, fRemove));
     676
     677        if (RT_SUCCESS(rc))
     678            rc = mHostCmdRc;
     679
     680        if (fRemove)
     681            Dequeue(pHostCmd);
     682
     683        LogFlowFunc(("[Client %RU32] Returned with rc=%Rrc\n", mID, rc));
     684        return rc;
     685    }
     686
     687    int RunCurrent(const ClientConnection *pConnection)
     688    {
     689        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
     690
     691        int rc;
     692        if (mHostCmdList.empty())
     693        {
     694            rc = SetPending(pConnection);
     695        }
     696        else
     697        {
     698            AssertMsgReturn(!mIsPending,
     699                            ("Client ID=%RU32 still is in pending mode; can't use another connection\n", mID), VERR_INVALID_PARAMETER);
     700
     701            HostCmdListIter curCmd = mHostCmdList.begin();
     702            Assert(curCmd != mHostCmdList.end());
     703            HostCommand *pHostCmd = (*curCmd);
     704            AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
     705
     706            rc = Run(pConnection, pHostCmd);
     707        }
     708
     709        return rc;
     710    }
     711
     712    int Wakeup(void)
     713    {
     714        int rc = VINF_NO_CHANGE;
     715
     716        if (mIsPending)
     717        {
     718            LogFlowFunc(("[Client %RU32] Waking up ...\n", mID));
     719
     720            rc = VINF_SUCCESS;
     721
     722            HostCmdListIter curCmd = mHostCmdList.begin();
     723            if (curCmd != mHostCmdList.end())
     724            {
     725                HostCommand *pHostCmd = (*curCmd);
     726                AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
     727
     728                LogFlowFunc(("[Client %RU32] Current host command is pHostCmd=%p, CID=%RU32, cmdType=%RU32, cmdParms=%RU32, refCount=%RU32\n",
     729                             mID, pHostCmd, pHostCmd->mContextID, pHostCmd->mMsgType, pHostCmd->mParmCount, pHostCmd->mRefCount));
     730
     731                rc = Run(&mPendingCon, pHostCmd);
     732            }
    622733            else
    623                 fRemove = true; /* Everything went fine, remove it. */
    624 
    625             LogFlowFunc(("Client tried CID=%RU32 for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n",
    626                          mpHostCmd->mContextID, mHostCmdTries, mHostCmdRc, fRemove));
    627 
    628             if (fRemove)
    629             {
    630                 /* Try fetching next command. */
    631                 HostCommand *pCmdNext = RTListGetNext(pHostCmdList, mpHostCmd, HostCommand, Node);
    632 
    633                 LogFlowFunc(("Client removes itself from command CID=%RU32 (next command: %p, CID=%RU32)\n",
    634                               mpHostCmd->mContextID, pCmdNext, pCmdNext ? pCmdNext->mContextID : 0));
    635 
    636                 /* Remove command from context map. */
    637                 /** @todo Exception handling! */
    638                 mContextMap.erase(mpHostCmd->mContextID);
    639 
    640                 /* Release reference for current command. */
    641                 if (mpHostCmd->Release() == 0)
    642                 {
    643                     LogFlowFunc(("Destroying command CID=%RU32\n",
    644                                  mpHostCmd->mContextID));
    645 
    646                     RTMemFree(mpHostCmd);
    647                 }
    648 
    649                 /* Assign next command (if any) to this client. */
    650                 if (pCmdNext)
    651                 {
    652                     rc = SetNextCommand(pCmdNext);
    653                 }
    654                 else
    655                     mpHostCmd = NULL;
    656 
    657                 /* Reset everything else. */
    658                 mHostCmdRc    = VINF_SUCCESS;
    659                 mHostCmdTries = 0;
    660             }
    661 
    662             if (RT_SUCCESS(rc))
    663                 rc = mHostCmdRc;
    664         }
    665 
    666         LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    667         return rc;
    668     }
    669 
    670     int RunNow(const ClientConnection *pConnection,
    671                const PRTLISTANCHOR     pHostCmdList)
    672     {
    673         AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    674         AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER);
    675 
    676         AssertMsgReturn(!mIsPending, ("Can't use another connection when client still is in pending mode\n"),
    677                         VERR_INVALID_PARAMETER);
    678 
    679         int rc = Run(pConnection, pHostCmdList);
    680 
    681         LogFlowFunc(("Returned with rc=%Rrc\n"));
    682         return rc;
    683     }
    684 
    685     int Wakeup(const PRTLISTANCHOR pHostCmdList)
    686     {
    687         AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER);
    688         AssertMsgReturn(mIsPending, ("Cannot wake up a client which is not in pending mode\n"),
    689                         VERR_INVALID_PARAMETER);
    690 
    691         int rc = Run(&mPending, pHostCmdList);
    692 
    693         /* Reset pending state. */
    694         mIsPending = false;
    695 
    696         LogFlowFunc(("Returned with rc=%Rrc\n"));
    697         return rc;
     734                AssertMsgFailed(("Waking up client ID=%RU32 with no host command in queue is a bad idea\n", mID));
     735
     736            return rc;
     737        }
     738
     739        return VINF_NO_CHANGE;
    698740    }
    699741
    700742    int CancelWaiting(int rcPending)
    701743    {
    702         LogFlowFunc(("Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n",
    703                      rcPending, mIsPending, mPending.mNumParms, mFlags));
     744        LogFlowFunc(("[Client %RU32] Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n",
     745                     mID, rcPending, mIsPending, mPendingCon.mNumParms, mFlags));
    704746
    705747        if (   mIsPending
    706             && mPending.mNumParms >= 2)
    707         {
    708             mPending.mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */
    709             mPending.mParms[1].setUInt32(0);                         /* Required parameters for message. */
     748            && mPendingCon.mNumParms >= 2)
     749        {
     750            mPendingCon.mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */
     751            mPendingCon.mParms[1].setUInt32(0);                         /* Required parameters for message. */
    710752
    711753            AssertPtr(mSvcHelpers);
    712             mSvcHelpers->pfnCallComplete(mPending.mHandle, rcPending);
     754            mSvcHelpers->pfnCallComplete(mPendingCon.mHandle, rcPending);
    713755
    714756            mIsPending = false;
     
    740782        }
    741783
     784        /* Reset pending status. */
     785        mIsPending = false;
     786
    742787        /* In any case the client did something, so complete
    743788         * the pending call with the result we just got. */
     
    745790        mSvcHelpers->pfnCallComplete(pConnection->mHandle, rc);
    746791
    747         LogFlowFunc(("pConnection=%p, pHostCmd=%p, rc=%Rrc\n",
    748                      pConnection, pHostCmd, rc));
     792        LogFlowFunc(("[Client %RU32] pConnection=%p, pHostCmd=%p, replyRc=%Rrc\n",
     793                     mID, pConnection, pHostCmd, rc));
    749794        return rc;
    750795    }
    751796
    752797    PVBOXHGCMSVCHELPERS mSvcHelpers;
     798    /** The client's ID. */
     799    uint32_t mID;
    753800    /** Client flags. @sa CLIENTSTATE_FLAG_ flags. */
    754801    uint32_t mFlags;
    755802    /** The context ID filter, based on the flags set. */
    756803    uint32_t mContextFilter;
    757     /** Pointer to current host command to process. */
    758     HostCommand *mpHostCmd;
     804    /** Host command list to process. */
     805    HostCmdList mHostCmdList;
    759806    /** Last (most recent) rc after handling the
    760807     *  host command. */
     
    763810     *  command to the according client. */
    764811    uint32_t mHostCmdTries;
    765     /** Map containing all context IDs a client is assigned to. */
    766     ClientContextMap mContextMap;
     812    /** Timestamp (us) of last host command processed. */
     813    uint64_t mHostCmdTS;
    767814    /** Flag indicating whether the client currently is pending. */
    768815    bool mIsPending;
    769816    /** The client's pending connection. */
    770     ClientConnection mPending;
     817    ClientConnection mPendingCon;
    771818} ClientState;
    772819typedef std::map< uint32_t, ClientState > ClientStateMap;
     
    831878    {
    832879        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    833         LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
    834880        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     881        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    835882        return pSelf->clientConnect(u32ClientID, pvClient);
    836883    }
     
    845892    {
    846893        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    847         LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
    848894        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     895        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    849896        return pSelf->clientDisconnect(u32ClientID, pvClient);
    850897    }
     
    863910    {
    864911        AssertLogRelReturnVoid(VALID_PTR(pvService));
    865         LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n",
    866                       pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
    867912        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     913        AssertPtrReturnVoid(pSelf);
    868914        pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
    869915    }
     
    879925    {
    880926        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    881         LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
    882927        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     928        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    883929        return pSelf->hostCall(u32Function, cParms, paParms);
    884930    }
     
    894940        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    895941        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     942        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    896943        pSelf->mpfnHostCallback = pfnExtension;
    897944        pSelf->mpvHostData = pvExtension;
     
    906953    int clientGetCommand(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    907954    int clientSetMsgFilter(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     955    int clientSkipMsg(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    908956    int cancelHostCmd(uint32_t u32ContextID);
    909957    int cancelPendingWaits(uint32_t u32ClientID, int rcPending);
     
    924972int Service::clientConnect(uint32_t u32ClientID, void *pvClient)
    925973{
    926     LogFlowFunc(("New client with ID=%RU32 connected\n", u32ClientID));
     974    LogFlowFunc(("[Client %RU32] Connected\n", u32ClientID));
    927975#ifdef VBOX_STRICT
    928976    ClientStateMapIterConst it = mClientStateMap.find(u32ClientID);
     
    934982    }
    935983#endif
    936     ClientState cs(mpHelpers);
    937     mClientStateMap[u32ClientID] = cs;
     984    ClientState clientState(mpHelpers, u32ClientID);
     985    mClientStateMap[u32ClientID] = clientState;
    938986    /** @todo Exception handling! */
    939987    return VINF_SUCCESS;
     
    951999int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient)
    9521000{
    953     LogFlowFunc(("Client with ID=%RU32 (%zu clients total) disconnected\n",
     1001    LogFlowFunc(("[Client %RU32] Disonnected (%zu clients total)\n",
    9541002                 u32ClientID, mClientStateMap.size()));
    9551003
    956     /* If this was the last connected (guest) client we need to
    957      * unblock all eventually queued up (waiting) host calls. */
     1004    AssertMsg(mClientStateMap.size(),
     1005              ("No clients in list anymore when there should (client ID=%RU32)\n", u32ClientID));
     1006
     1007    int rc = VINF_SUCCESS;
     1008
     1009    ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID);
     1010    AssertMsg(itClientState != mClientStateMap.end(),
     1011              ("Clients ID=%RU32 not found in client list when it should be there\n", u32ClientID));
     1012
     1013    if (itClientState != mClientStateMap.end())
     1014    {
     1015        itClientState->second.DequeueAll();
     1016
     1017        mClientStateMap.erase(itClientState);
     1018    }
     1019
    9581020    bool fAllClientsDisconnected = mClientStateMap.size() == 0;
    9591021    if (fAllClientsDisconnected)
    960         LogFlowFunc(("No connected clients left, notifying all queued up host callbacks\n"));
    961 
    962     /*
    963      * Throw out all stale clients.
    964      */
    965     int rc = VINF_SUCCESS;
    966 
    967     ClientStateMapIter itClientState = mClientStateMap.begin();
    968     while (   itClientState != mClientStateMap.end()
    969            && RT_SUCCESS(rc))
    970     {
    971         /*
    972          * Unblock/call back all queued items of the specified client
    973          * or for all items in case there is no waiting client around
    974          * anymore.
    975          */
    976         if (   itClientState->first == u32ClientID
    977             || fAllClientsDisconnected)
    978         {
    979             LogFlowFunc(("Cancelling %RU32 context(s) of client ID=%RU32\n",
    980                          itClientState->second.mContextMap.size(), u32ClientID));
    981 
    982             ClientContextMapIter itContext = itClientState->second.mContextMap.begin();
    983             while (itContext != itClientState->second.mContextMap.end())
    984             {
    985                 uint32_t uContextID = itContext->first;
    986 
    987                 /*
    988                  * Notify the host that clients with u32ClientID are no longer
    989                  * around and need to be cleaned up (canceling waits etc).
    990                  */
    991                 LogFlowFunc(("Notifying CID=%RU32 of disconnect ...\n", uContextID));
    992                 int rc2 = cancelHostCmd(uContextID);
    993                 if (RT_FAILURE(rc2))
    994                 {
    995                     LogFlowFunc(("Cancelling host command with CID=%RU32 failed with rc=%Rrc\n",
    996                                  uContextID, rc2));
    997                     /* Keep going. */
    998                 }
    999 
    1000                 AssertPtr(itContext->second.mpHostCmd);
    1001                 itContext->second.mpHostCmd->Release();
    1002 
    1003                 itContext++;
    1004             }
    1005 
    1006             itClientState->second.mContextMap.clear();
    1007 
    1008             /** @todo Exception handling! */
    1009             mClientStateMap.erase(itClientState++);
    1010         }
    1011         else
    1012             itClientState++;
    1013     }
    1014 
    1015     if (fAllClientsDisconnected)
    1016     {
     1022    {
     1023        LogFlowFunc(("All clients disconnected, cancelling all host commands ...\n"));
     1024
    10171025        /*
    10181026         * If all clients disconnected we also need to make sure that all buffered
     
    10341042            }
    10351043
    1036             pCurCmd->Free();
    1037 
    1038             RTListNodeRemove(&pCurCmd->Node);
    1039             RTMemFree(pCurCmd);
     1044            while (pCurCmd->Release());
     1045
     1046            delete pCurCmd;
     1047            pCurCmd = NULL;
    10401048
    10411049            if (fLast)
     
    10821090    thisCon.mParms    = paParms;
    10831091
    1084     /*
    1085      * If host command list is empty (nothing to do right now) just
    1086      * defer the call until we got something to do (makes the client
    1087      * wait).
    1088      */
    1089     int rc;
    1090     if (RTListIsEmpty(&mHostCmdList))
    1091     {
    1092         rc = clientState.SetPending(&thisCon);
    1093     }
    1094     else
    1095     {
    1096         rc = clientState.RunNow(&thisCon, &mHostCmdList);
    1097     }
    1098 
    1099     LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    1100     return rc;
     1092    return clientState.RunCurrent(&thisCon);
    11011093}
    11021094
     
    11231115    if (RT_SUCCESS(rc))
    11241116    {
    1125         /* paParms[1] unused yet. */
    1126 
    11271117        ClientState &clientState = itClientState->second;
    11281118
     
    11381128    }
    11391129
    1140     LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    11411130    return rc;
     1131}
     1132
     1133int Service::clientSkipMsg(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle,
     1134                           uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     1135{
     1136    /*
     1137     * Lookup client in our list so that we can assign the context ID of
     1138     * a command to that client.
     1139     */
     1140    ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID);
     1141    AssertMsg(itClientState != mClientStateMap.end(), ("Client ID=%RU32 not found when it should be present\n",
     1142                                                       u32ClientID));
     1143    if (itClientState == mClientStateMap.end())
     1144        return VERR_NOT_FOUND; /* Should never happen. */
     1145
     1146    if (cParms != 0)
     1147        return VERR_INVALID_PARAMETER;
     1148
     1149    LogFlowFunc(("Client ID=%RU32 skipping message ...\n", u32ClientID));
     1150
     1151    itClientState->second.DequeueCurrent();
     1152
     1153    return VINF_SUCCESS;
    11421154}
    11431155
     
    12281240
    12291241    int rc;
    1230     HostCommand *pHostCmd = (HostCommand*)RTMemAllocZ(sizeof(HostCommand));
    1231     if (pHostCmd)
    1232     {
     1242
     1243    HostCommand *pHostCmd = NULL;
     1244    try
     1245    {
     1246        pHostCmd = new HostCommand();
    12331247        rc = pHostCmd->Allocate(eFunction, cParms, paParms);
    12341248        if (RT_SUCCESS(rc))
    1235             RTListAppend(&mHostCmdList, &pHostCmd->Node);
    1236     }
    1237     else
     1249            /* rc = */ RTListAppend(&mHostCmdList, &pHostCmd->Node);
     1250    }
     1251    catch (std::bad_alloc)
     1252    {
    12381253        rc = VERR_NO_MEMORY;
     1254    }
    12391255
    12401256    if (RT_SUCCESS(rc))
    12411257    {
    1242         LogFlowFunc(("Handling host command CID=%RU32, numClients=%zu\n",
    1243                      pHostCmd->mContextID, mClientStateMap.size()));
     1258        LogFlowFunc(("Handling host command CID=%RU32, eFunction=%RU32, cParms=%RU32, paParms=%p, numClients=%zu\n",
     1259                     pHostCmd->mContextID, eFunction, cParms, paParms, mClientStateMap.size()));
    12441260
    12451261        /*
     
    12501266        uint32_t uClientsWokenUp = 0;
    12511267#endif
    1252 
    12531268        ClientStateMapIter itClientState = mClientStateMap.begin();
    12541269        AssertMsg(itClientState != mClientStateMap.end(), ("Client state map is empty when it should not\n"));
    12551270        while (itClientState != mClientStateMap.end())
    12561271        {
    1257             if (itClientState->second.mIsPending) /* Only wake up pending clients. */
     1272            ClientState &clientState = itClientState->second;
     1273
     1274            /* If a client indicates that it it wants the new host command,
     1275             * add a reference to not delete it.*/
     1276            if (clientState.WantsHostCommand(pHostCmd))
    12581277            {
    1259                 LogFlowFunc(("Waking up client ID=%RU32 (isPending=%RTbool) ...\n",
    1260                              itClientState->first, itClientState->second.mIsPending));
    1261 
    1262                 ClientState &clientState = itClientState->second;
    1263                 int rc2 = clientState.Wakeup(&mHostCmdList);
    1264                 LogFlowFunc(("Client ID=%RU32 wakeup ended with rc=%Rrc\n",
    1265                              itClientState->first, rc2));
    1266 #ifdef DEBUG
     1278                clientState.EnqueueCommand(pHostCmd);
     1279
     1280                int rc2 = clientState.Wakeup();
     1281                if (RT_FAILURE(rc2))
     1282                    LogFlowFunc(("Waking up client ID=%RU32 failed with rc=%Rrc\n",
     1283                                 itClientState->first, rc2));
     1284#ifdef DEBUG_andy
    12671285                uClientsWokenUp++;
    12681286#endif
    12691287            }
    1270             else
    1271                 LogFlowFunc(("Client ID=%RU32 is not in pending state\n",
    1272                              itClientState->first));
    12731288
    12741289            itClientState++;
    12751290        }
    12761291
    1277 #ifdef DEBUG
    1278         LogFlowFunc(("%RU32 clients have been succcessfully woken up\n",
    1279                       uClientsWokenUp));
     1292#ifdef DEBUG_andy
     1293        LogFlowFunc(("%RU32 clients have been woken up\n", uClientsWokenUp));
    12801294#endif
    12811295    }
    12821296
    1283     LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    12841297    return rc;
    12851298}
     
    12991312{
    13001313    int rc = VINF_SUCCESS;
    1301     LogFlowFunc(("u32ClientID=%RU32, fn=%RU32, cParms=%RU32, paParms=0x%p\n",
     1314    LogFlowFunc(("[Client %RU32] eFunction=%RU32, cParms=%RU32, paParms=0x%p\n",
    13021315                 u32ClientID, eFunction, cParms, paParms));
    13031316    try
     
    13081321        if (eFunction == GUEST_MSG_WAIT)
    13091322        {
    1310             LogFlowFunc(("GUEST_MSG_GET\n"));
     1323            LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", u32ClientID));
    13111324            rc = clientGetCommand(u32ClientID, callHandle, cParms, paParms);
    13121325        }
     
    13211334                 */
    13221335                case GUEST_CANCEL_PENDING_WAITS:
    1323                     LogFlowFunc(("GUEST_CANCEL_PENDING_WAITS\n"));
     1336                    LogFlowFunc(("[Client %RU32] GUEST_CANCEL_PENDING_WAITS\n", u32ClientID));
    13241337                    rc = cancelPendingWaits(u32ClientID, VINF_SUCCESS /* Pending result */);
    13251338                    break;
     
    13301343                 */
    13311344                case GUEST_MSG_FILTER:
    1332                     LogFlowFunc(("GUEST_MSG_FILTER\n"));
     1345                    LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER\n", u32ClientID));
    13331346                    rc = clientSetMsgFilter(u32ClientID, callHandle, cParms, paParms);
     1347                    break;
     1348
     1349                /*
     1350                 * The guest only wants skip the currently assigned messages.
     1351                 * Since VBox 4.3+.
     1352                 */
     1353                case GUEST_MSG_SKIP:
     1354                    LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", u32ClientID));
     1355                    rc = clientSkipMsg(u32ClientID, callHandle, cParms, paParms);
    13341356                    break;
    13351357
     
    14161438 * @copydoc VBOXHGCMSVCLOAD
    14171439 */
    1418 extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable)
     1440extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
    14191441{
    14201442    int rc = VINF_SUCCESS;
    14211443
    1422     LogFlowFunc(("ptable = %p\n", ptable));
    1423 
    1424     if (!VALID_PTR(ptable))
     1444    LogFlowFunc(("pTable=%p\n", pTable));
     1445
     1446    if (!VALID_PTR(pTable))
    14251447    {
    14261448        rc = VERR_INVALID_PARAMETER;
     
    14281450    else
    14291451    {
    1430         LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
    1431 
    1432         if (   ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
    1433             || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
     1452        LogFlowFunc(("pTable->cbSize=%d, pTable->u32Version=0x%08X\n", pTable->cbSize, pTable->u32Version));
     1453
     1454        if (   pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
     1455            || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
    14341456        {
    14351457            rc = VERR_VERSION_MISMATCH;
     
    14401462            /* No exceptions may propagate outside. */
    14411463            try {
    1442                 apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
     1464                apService = std::auto_ptr<Service>(new Service(pTable->pHelpers));
    14431465            } catch (int rcThrown) {
    14441466                rc = rcThrown;
     
    14531475                 * because we're a class which can have members for that :-).
    14541476                 */
    1455                 ptable->cbClient = 0;
     1477                pTable->cbClient = 0;
    14561478
    14571479                /* Register functions. */
    1458                 ptable->pfnUnload             = Service::svcUnload;
    1459                 ptable->pfnConnect            = Service::svcConnect;
    1460                 ptable->pfnDisconnect         = Service::svcDisconnect;
    1461                 ptable->pfnCall               = Service::svcCall;
    1462                 ptable->pfnHostCall           = Service::svcHostCall;
    1463                 ptable->pfnSaveState          = NULL;  /* The service is stateless, so the normal */
    1464                 ptable->pfnLoadState          = NULL;  /* construction done before restoring suffices */
    1465                 ptable->pfnRegisterExtension  = Service::svcRegisterExtension;
     1480                pTable->pfnUnload             = Service::svcUnload;
     1481                pTable->pfnConnect            = Service::svcConnect;
     1482                pTable->pfnDisconnect         = Service::svcDisconnect;
     1483                pTable->pfnCall               = Service::svcCall;
     1484                pTable->pfnHostCall           = Service::svcHostCall;
     1485                pTable->pfnSaveState          = NULL;  /* The service is stateless, so the normal */
     1486                pTable->pfnLoadState          = NULL;  /* construction done before restoring suffices */
     1487                pTable->pfnRegisterExtension  = Service::svcRegisterExtension;
    14661488
    14671489                /* Service specific initialization. */
    1468                 ptable->pvService = apService.release();
     1490                pTable->pvService = apService.release();
    14691491            }
    14701492        }
    14711493    }
    14721494
    1473     LogFlowFunc(("returning %Rrc\n", rc));
     1495    LogFlowFunc(("Returning %Rrc\n", rc));
    14741496    return rc;
    14751497}
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