VirtualBox

Ignore:
Timestamp:
Nov 15, 2011 2:40:49 PM (13 years ago)
Author:
vboxsync
Message:

HostServices/GuestCtrl: Fixed cancellation of buffered (unassigned) host commands or assigned commands on client disconnect, logging adjustments.

File:
1 edited

Legend:

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

    r38133 r39312  
    2727 * - Client: A client (e.g. VBoxService) running inside the guest OS waiting for
    2828 *           new host commands to perform. There can be multiple clients connected
    29  *           to a service. A client is represented by its HGCM client ID.
     29 *           to this service. A client is represented by its unique HGCM client ID.
    3030 * - Context ID: An (almost) unique ID automatically generated on the host (Main API)
    3131 *               to not only distinguish clients but individual requests. Because
     
    285285    int clientConnect(uint32_t u32ClientID, void *pvClient);
    286286    int clientDisconnect(uint32_t u32ClientID, void *pvClient);
    287     int sendHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     287    int assignHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    288288    int retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     289    int cancelHostCmd(uint32_t u32ContextID);
    289290    int cancelPendingWaits(uint32_t u32ClientID);
    290291    int notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     
    492493int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient)
    493494{
    494     LogFlowFunc(("Client (%ld) disconnected\n", u32ClientID));
     495    LogFlowFunc(("Client (ID=%u, %u clients total) disconnected\n",
     496                 u32ClientID, mNumClients));
    495497    Assert(mNumClients > 0);
    496498    mNumClients--;
     499
     500    /* If this was the last connected (guest) client we need to
     501     * unblock all eventually queued up (waiting) host calls. */
     502    bool fAllClientsDisconnected = mNumClients == 0;
     503    if (fAllClientsDisconnected)
     504        LogFlowFunc(("No connected clients left, notifying all queued up callbacks\n"));
    497505
    498506    /*
     
    516524           && RT_SUCCESS(rc))
    517525    {
    518         if (it->mClientID == u32ClientID)
     526        /*
     527         * Unblock/call back all queued items of the specified client
     528         * or for all items in case there is no waiting client around
     529         * anymore.
     530         */
     531        if (   it->mClientID == u32ClientID
     532            || fAllClientsDisconnected)
    519533        {
    520534            std::list< uint32_t >::iterator itContext = it->mContextList.begin();
    521             while (   itContext != it->mContextList.end()
    522                    && RT_SUCCESS(rc))
     535            while (itContext != it->mContextList.end())
    523536            {
    524                 LogFlowFunc(("Notifying host context %u of disconnect ...\n", (*itContext)));
     537                uint32_t uContextID = (*itContext);
    525538
    526539                /*
     
    528541                 * around and need to be cleaned up (canceling waits etc).
    529542                 */
    530                 if (mpfnHostCallback)
     543                LogFlowFunc(("Notifying CID=%u of disconnect ...\n", uContextID));
     544                rc = cancelHostCmd(uContextID);
     545                if (RT_FAILURE(rc))
    531546                {
    532                     CALLBACKDATACLIENTDISCONNECTED data;
    533                     data.hdr.u32Magic = CALLBACKDATAMAGIC_CLIENT_DISCONNECTED;
    534                     data.hdr.u32ContextID = (*itContext);
    535                     rc = mpfnHostCallback(mpvHostData, GUEST_DISCONNECTED, (void *)(&data), sizeof(data));
    536                     if (RT_FAILURE(rc))
    537                         LogFlowFunc(("Notification of host context %u failed with %Rrc\n", rc));
     547                    LogFlowFunc(("Cancelling of CID=%u failed with rc=%Rrc\n",
     548                                 uContextID, rc));
     549                    /* Keep going. */
    538550                }
     551
    539552                itContext++;
    540553            }
     
    544557            it++;
    545558    }
     559
     560    if (fAllClientsDisconnected)
     561    {
     562        /*
     563         * If all clients disconnected we also need to make sure that all buffered
     564         * host commands need to be notified, because Main is waiting a notification
     565         * via a (multi stage) progress object.
     566         */
     567        HostCmdListIter it;
     568        for (it = mHostCmds.begin(); it != mHostCmds.end(); it++)
     569        {
     570            rc = cancelHostCmd(it->mContextID);
     571            if (RT_FAILURE(rc))
     572            {
     573                LogFlowFunc(("Cancelling of buffered CID=%u failed with rc=%Rrc\n",
     574                             it->mContextID, rc));
     575                /* Keep going. */
     576            }
     577
     578            paramBufferFree(&it->mParmBuf);
     579        }
     580
     581        mHostCmds.clear();
     582    }
     583
    546584    return rc;
    547585}
    548586
    549587/**
    550  * Sends a specified host command to a client.
     588 * Assigns a specified host command to a client.
    551589 *
    552590 * @return  IPRT status code.
     
    556594 * @param   paParms                 Array of parameters.
    557595 */
    558 int Service::sendHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    559 {
    560     AssertPtr(pCmd);
     596int Service::assignHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     597{
     598    AssertPtrReturn(pCmd, VERR_INVALID_POINTER);
    561599    int rc;
    562600
    563     /* Sufficient parameter space? */
     601    /* Does the current host command need more parameter space which
     602     * the client does not provide yet? */
    564603    if (pCmd->mParmBuf.uParmCount > cParms)
    565604    {
     
    578617        rc = paramBufferAssign(&pCmd->mParmBuf, cParms, paParms);
    579618    }
     619
     620    LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    580621    return rc;
    581622}
     
    632673         */
    633674         HostCmd curCmd = mHostCmds.front();
    634          rc = sendHostCmdToGuest(&curCmd, callHandle, cParms, paParms);
     675         rc = assignHostCmdToGuest(&curCmd, callHandle, cParms, paParms);
    635676         if (RT_SUCCESS(rc))
    636677         {
     
    658699         else
    659700         {
    660             /* Client did not understand the message or something else weird happened. Try again one
    661              * more time and drop it if it didn't get handled then. */
     701             /* Client did not understand the message or something else weird happened. Try again one
     702              * more time and drop it if it didn't get handled then. */
    662703             if (++curCmd.mTries > 1)
    663704             {
     
    668709    }
    669710    return rc;
     711}
     712
     713/**
     714 * Cancels a buffered host command to unblock waits on Main side
     715 * (via (multi stage) progress objects.
     716 *
     717 * @return  IPRT status code.
     718 * @param   u32ContextID                Context ID of host command to cancel.
     719 */
     720int Service::cancelHostCmd(uint32_t u32ContextID)
     721{
     722    AssertReturn(u32ContextID, VERR_INVALID_PARAMETER);
     723    Assert(mpfnHostCallback);
     724
     725    LogFlowFunc(("Cancelling CID=%u ...\n", u32ContextID));
     726
     727    CALLBACKDATACLIENTDISCONNECTED data;
     728    data.hdr.u32Magic = CALLBACKDATAMAGIC_CLIENT_DISCONNECTED;
     729    data.hdr.u32ContextID = u32ContextID;
     730
     731    AssertPtr(mpfnHostCallback);
     732    AssertPtr(mpvHostData);
     733
     734    return mpfnHostCallback(mpvHostData, GUEST_DISCONNECTED, (void *)(&data), sizeof(data));
    670735}
    671736
     
    789854    HostCmd newCmd;
    790855    int rc = paramBufferAllocate(&newCmd.mParmBuf, eFunction, cParms, paParms);
    791     if (RT_SUCCESS(rc) && cParms)
     856    if (   RT_SUCCESS(rc)
     857        && cParms) /* Make sure we at least get one parameter (that is, the context ID). */
    792858    {
    793859        /*
     
    798864        Assert(newCmd.mContextID > 0);
    799865    }
     866    else if (!cParms)
     867        rc = VERR_INVALID_PARAMETER;
    800868
    801869    if (RT_SUCCESS(rc))
    802870    {
     871        LogFlowFunc(("Handling host command CID = %u\n",
     872                     newCmd.mContextID));
     873
    803874        bool fProcessed = false;
    804875
     
    807878        {
    808879            ClientWaiter guest = mClientWaiterList.front();
    809             rc = sendHostCmdToGuest(&newCmd,
    810                                     guest.mHandle, guest.mNumParms, guest.mParms);
     880            rc = assignHostCmdToGuest(&newCmd,
     881                                      guest.mHandle, guest.mNumParms, guest.mParms);
    811882
    812883            /* In any case the client did something, so wake up and remove from list. */
     
    825896            else /* If command was understood by the client, free and remove from host commands list. */
    826897            {
     898                LogFlowFunc(("Host command CID = %u processed with rc=%Rrc\n",
     899                             newCmd.mContextID, rc));
     900
    827901                paramBufferFree(&newCmd.mParmBuf);
    828                 fProcessed = true;
    829902            }
    830903        }
    831904
    832         /* If not processed, buffer it ... */
    833905        if (!fProcessed)
    834906        {
     907            LogFlowFunc(("Buffering host command CID = %u (rc=%Rrc)\n",
     908                         newCmd.mContextID, rc));
     909
    835910            mHostCmds.push_back(newCmd);
    836 #if 0
    837             /* Limit list size by deleting oldest element. */
    838             if (mHostCmds.size() > 256) /** @todo Use a define! */
    839                 mHostCmds.pop_front();
    840 #endif
    841         }
    842     }
     911        }
     912    }
     913
     914    LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    843915    return rc;
    844916}
     
    858930{
    859931    int rc = VINF_SUCCESS;
    860     LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
     932    LogFlowFunc(("u32ClientID = %u, fn = %u, cParms = %u, paParms = 0x%p\n",
    861933                 u32ClientID, eFunction, cParms, paParms));
    862934    try
     
    913985{
    914986    int rc = VERR_NOT_SUPPORTED;
    915     LogFlowFunc(("fn = %d, cParms = %d, pparms = %d\n",
     987    LogFlowFunc(("fn = %u, cParms = %u, paParms = 0x%p\n",
    916988                 eFunction, cParms, paParms));
    917989    try
     
    9301002int Service::uninit()
    9311003{
    932     /* Free allocated buffered host commands. */
    933     HostCmdListIter it;
    934     for (it = mHostCmds.begin(); it != mHostCmds.end(); it++)
    935         paramBufferFree(&it->mParmBuf);
    936     mHostCmds.clear();
     1004    Assert(mHostCmds.empty());
    9371005
    9381006    return VINF_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.

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