VirtualBox

Changeset 28086 in vbox


Ignore:
Timestamp:
Apr 8, 2010 12:32:07 PM (15 years ago)
Author:
vboxsync
Message:

Guest Control: Update; now buffered and deferred commands work.

Location:
trunk/src/VBox
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp

    r28029 r28086  
    109109VBGLR3DECL(int) VbglR3GuestCtrlGetHostMsg(uint32_t u32ClientId, uint32_t *puMsg, uint32_t *puNumParms)
    110110{
     111    AssertPtr(puMsg);
     112    AssertPtr(puNumParms);
     113
    111114    VBoxGuestCtrlHGCMMsgType Msg;
    112115
     
    122125    if (RT_SUCCESS(rc))
    123126    {
    124         rc = Msg.hdr.result;
     127        rc = VbglHGCMParmUInt32Get(&Msg.msg, puMsg);
    125128        if (RT_SUCCESS(rc))
    126         {
    127             rc = VbglHGCMParmUInt32Get(&Msg.msg, puMsg);
     129            rc = VbglHGCMParmUInt32Get(&Msg.num_parms, puNumParms);
    128130            if (RT_SUCCESS(rc))
    129                 rc = VbglHGCMParmUInt32Get(&Msg.num_parms, puNumParms);
    130             /* Ok, so now we know what message type and how much parameters there are. */
    131         }
     131                rc = Msg.hdr.result;
     132                /* Ok, so now we know what message type and how much parameters there are. */
    132133    }
    133134    return rc;
     
    176177    Msg.hdr.result = VERR_WRONG_ORDER;
    177178    Msg.hdr.u32ClientID = u32ClientId;
    178     Msg.hdr.u32Function = GUEST_GET_HOST_MSG_DATA; /* Tell the host we want the actual data of a command. */
     179    Msg.hdr.u32Function = GUEST_GET_HOST_MSG;
    179180    Msg.hdr.cParms = uNumParms;
    180181
     
    196197    if (RT_SUCCESS(rc))
    197198    {
    198         rc = Msg.hdr.result;
    199 
    200         Msg.flags.GetUInt32(puFlags);
    201         Msg.num_args.GetUInt32(puNumArgs);
    202         Msg.num_env.GetUInt32(puNumEnvVars);
    203         Msg.cb_env.GetUInt32(pcbEnv);
    204         Msg.timeout.GetUInt32(puTimeLimit);       
     199        int rc2 = Msg.hdr.result;
     200        if (RT_FAILURE(rc2))
     201        {
     202            rc = rc2;
     203        }
     204        else
     205        {
     206            Msg.flags.GetUInt32(puFlags);
     207            Msg.num_args.GetUInt32(puNumArgs);
     208            Msg.num_env.GetUInt32(puNumEnvVars);
     209            Msg.cb_env.GetUInt32(pcbEnv);
     210            Msg.timeout.GetUInt32(puTimeLimit);
     211        }
    205212    }
    206213    return rc;
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp

    r28029 r28086  
    9696static int VBoxServiceControlHandleCmdExec(uint32_t u32ClientId, uint32_t uNumParms)
    9797{
    98     VBoxServiceVerbose(3, "VBoxServiceControlHandleCmdExec: Called uNumParms=%ld\n", uNumParms);
    99 
    10098    VBOXSERVICECTRLPROCDATA execData;
    10199    execData.cbEnv = sizeof(execData.szEnv);
     
    156154                /* Do the actual execution. */
    157155                rc = VBoxServiceControlExecProcess(&execData, ppaArg, ppaEnv);
     156                if (RT_FAILURE(rc))
     157                    VBoxServiceVerbose(3, "Control: Could not execute process \"%s\"! Error: %Rrc\n",
     158                                       execData.szCmd, rc);
    158159                /* Cleanup. */
    159160                if (execData.uNumEnvVars)
     
    193194        uint32_t uNumParms;
    194195        rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms);
     196        if (rc == VERR_TOO_MUCH_DATA)
     197        {
     198            VBoxServiceVerbose(3, "Control: Message requires %ld parameters, but only 2 supplied.\n", uNumParms);
     199            rc = VINF_SUCCESS;
     200        }
    195201        if (RT_SUCCESS(rc))
    196202        {
     
    202208
    203209                default:
    204                     VBoxServiceVerbose(3, "VBoxServiceControlWorker: Unsupported message from host! Msg=%ld\n", uMsg);
     210                    VBoxServiceVerbose(3, "Control: Unsupported message from host! Msg=%ld\n", uMsg);
    205211                    /* Don't terminate here; just wait for the next message. */
    206212                    break;
     
    221227        if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
    222228        {
    223             VBoxServiceError("VBoxServiceControlWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
     229            VBoxServiceError("Control: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
    224230            rc = rc2;
    225231            break;
  • trunk/src/VBox/HostServices/GuestControl/service.cpp

    r28013 r28086  
    5252namespace guestControl {
    5353
    54 struct Client
    55 {
     54/**
     55 * Structure for holding a buffered host command
     56 */
     57struct HostCmd
     58{
     59    /** Dynamic structure for holding the HGCM parms */
    5660    VBOXGUESTCTRPARAMBUFFER parmBuf;
    57     VBOXHGCMCALLHANDLE callHandle;
    58     uint32_t uClientID;
    5961};
    60 
    61 struct HostCmd
    62 {
    63     VBOXGUESTCTRPARAMBUFFER parmBuf;
    64     uint32_t uAssignedToClientID;
    65 };
    66 
    67 /** The client list list type */
    68 typedef std::list <Client> ClientList;
    6962/** The host cmd list type */
    7063typedef std::list <HostCmd> HostCmdList;
     64
     65/**
     66 * Structure for holding an uncompleted guest call
     67 */
     68struct GuestCall
     69{
     70    /** The call handle */
     71    VBOXHGCMCALLHANDLE mHandle;
     72    /** The function that was requested */
     73    uint32_t mFunction;
     74    /** The call parameters */
     75    VBOXHGCMSVCPARM *mParms;
     76    /** Number of parameters */
     77    uint32_t mNumParms;
     78    /** The default return value, used for passing warnings */
     79    int mRc;
     80
     81    /** The standard constructor */
     82    GuestCall() : mFunction(0) {}
     83    /** The normal contructor */
     84    GuestCall(VBOXHGCMCALLHANDLE aHandle, uint32_t aFunction,
     85              VBOXHGCMSVCPARM aParms[], int cParms, int aRc)
     86              : mHandle(aHandle), mFunction(aFunction), mParms(aParms),
     87                mNumParms(cParms), mRc(aRc) {}
     88};
     89/** The guest call list type */
     90typedef std::list <GuestCall> CallList;
    7191
    7292/**
     
    94114    /** User data pointer to be supplied to the host callback function */
    95115    void *mpvHostData;
    96     /** The client list */
    97     ClientList mClients;
     116    /** The deferred calls list */
     117    CallList mGuestWaiters;
    98118    /** The host command list */
    99119    HostCmdList mHostCmds;
     
    227247    int clientConnect(uint32_t u32ClientID, void *pvClient);
    228248    int clientDisconnect(uint32_t u32ClientID, void *pvClient);
     249    int guestGetHostMsg(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     250    int hostNotifyGuest(GuestCall *pCall, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     251    int hostProcessCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    229252    void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
    230253              void *pvClient, uint32_t eFunction, uint32_t cParms,
     
    381404int Service::clientConnect(uint32_t u32ClientID, void *pvClient)
    382405{
    383 ASMBreakpoint();
    384 
    385     bool bFound = false;
    386     for (ClientList::const_iterator it = mClients.begin();
    387          !bFound && it != mClients.end(); ++it)
    388     {
    389         if (it->uClientID == u32ClientID)
    390             bFound = true;
    391     }
    392 
    393     if (!bFound)
    394     {
    395         Client newClient;
    396 
    397         /** @todo Use a constructor here! */
    398         newClient.uClientID = u32ClientID;
    399         newClient.parmBuf.uParmCount = 0;
    400         newClient.parmBuf.pParms = NULL;
    401 
    402         mClients.push_back(newClient);
    403         LogFlowFunc(("New client = %ld connected\n", u32ClientID));
    404     }
    405     else
    406     {
    407         LogFlowFunc(("Exising client (%ld) connected another instance\n", u32ClientID));
    408     }
     406    LogFlowFunc(("New client (%ld) connected\n", u32ClientID));
    409407    return VINF_SUCCESS;
    410408}
     
    412410int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient)
    413411{
    414 ASMBreakpoint();
    415 
    416     bool bFound = false;
    417     for (ClientList::iterator it = mClients.begin();
    418          !bFound && it != mClients.end(); ++it)
    419     {
    420         if (it->uClientID == u32ClientID)
    421         {
    422             mClients.erase(it);
    423             bFound = true;
    424         }
    425     }
    426     Assert(bFound);
    427 
    428412    LogFlowFunc(("Client (%ld) disconnected\n", u32ClientID));
    429413    return VINF_SUCCESS;
     414}
     415
     416/*
     417 * Either fills in parameters from a pending host command into our guest context or
     418 * defer the guest call until we have something from the host.
     419 */
     420int Service::guestGetHostMsg(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     421{
     422    int rc = VINF_SUCCESS;
     423
     424    /** @todo !!!!! LOCKING !!!!!!!!! */
     425
     426    if (cParms < 2)
     427    {
     428        LogFlowFunc(("Parameter buffer is too small!\n"));
     429        rc = VERR_INVALID_PARAMETER;
     430    }
     431    else
     432    {     
     433        /*
     434         * If host command list is empty (nothing to do right now) just
     435         * defer the call until we got something to do (makes the client
     436         * wait, depending on the flags set).
     437         */
     438        if (mHostCmds.empty()) /* Command list is empty, defer ... */
     439            rc = VINF_HGCM_ASYNC_EXECUTE;
     440
     441        if (rc != VINF_HGCM_ASYNC_EXECUTE)
     442        {
     443            /*
     444             * Get the next unassigned host command in the list.
     445             */
     446             HostCmd curCmd = mHostCmds.front();
     447             uint32_t uParmCount = curCmd.parmBuf.uParmCount;
     448
     449             /* Sufficient parameter space? */
     450             if (uParmCount > cParms)
     451             {
     452                uint32_t uCmd = 0;
     453                if (uParmCount)
     454                    curCmd.parmBuf.pParms[0].getUInt32(&uCmd);
     455
     456                 paParms[0].setUInt32(/*uCmd*/ 1); /* Message ID */
     457                 paParms[1].setUInt32(uParmCount); /* Required parameters for message */
     458
     459                 /*
     460                  * So this call apparently failed because the guest wanted to peek
     461                  * how much parameters it has to supply in order to successfully retrieve
     462                  * this command. Let's tell him so!
     463                  */
     464                 rc = VERR_TOO_MUCH_DATA;
     465             }
     466             else
     467             {
     468                 rc = execBufferAssign(&curCmd.parmBuf, cParms, paParms);                 
     469                 if (RT_SUCCESS(rc))
     470                     mHostCmds.pop_front();
     471             }
     472        }
     473        else
     474        {
     475            /* Call is deferred because of reasons above. */
     476            mGuestWaiters.push_back(GuestCall(callHandle, GUEST_GET_HOST_MSG,
     477                                              paParms, cParms, rc));
     478        }
     479    }
     480    return rc;
     481}
     482
     483/*
     484 * Sends a command notification to the first waiting (deferred) client/guest in line in
     485 * order to wake up and do some work.
     486 */
     487int Service::hostNotifyGuest(GuestCall *pCall, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     488{
     489    /** @todo !!!!! LOCKING !!!!!!!!! */
     490
     491    AssertPtr(pCall);
     492    int rc = VINF_SUCCESS;   
     493
     494    int rc2 = guestGetHostMsg(pCall->mHandle, pCall->mNumParms, pCall->mParms);
     495    if (RT_SUCCESS(rc2))
     496        rc2 = pCall->mRc;
     497    AssertPtr(mpHelpers);
     498    mpHelpers->pfnCallComplete(pCall->mHandle, rc2);
     499    return rc;
     500}
     501
     502int Service::hostProcessCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     503{
     504    /** @todo !!!!! LOCKING !!!!!!!!! */
     505
     506    int rc = VINF_SUCCESS;
     507
     508    HostCmd newCmd;
     509    execBufferAllocate(&newCmd.parmBuf, cParms, paParms);
     510    mHostCmds.push_back(newCmd);
     511
     512    /* Limit list size by deleting oldest element. */
     513    if (mHostCmds.size() > 256) /** @todo Use a define! */
     514        mHostCmds.pop_front();
     515
     516    /* Some lazy guests to wake up? */
     517    if (!mGuestWaiters.empty())
     518    {
     519        GuestCall curCall = mGuestWaiters.front();
     520        rc = hostNotifyGuest(&curCall, eFunction, cParms, paParms);
     521        mGuestWaiters.pop_front();
     522    }
     523    return rc;
    430524}
    431525
     
    456550            case GUEST_GET_HOST_MSG:
    457551                LogFlowFunc(("GUEST_GET_HOST_MSG\n"));               
    458 
    459 /** @todo !!!!! LOCKING !!!!!!!!! */
    460 
    461                 if (cParms < 2)
    462                 {
    463                     LogFlowFunc(("Parameter buffer is too small!\n"));
    464                     rc = VERR_INVALID_PARAMETER;
    465                 }
    466                 else
    467                 {     
    468                     /*
    469                      * If host command list is empty (nothing to do right now) just
    470                      * defer the call until we got something to do (makes the client
    471                      * wait, depending on the flags set).
    472                      */
    473                     if (mHostCmds.empty())
    474                         rc = VINF_HGCM_ASYNC_EXECUTE;
    475    
    476                     if (   RT_SUCCESS(rc)
    477                         && rc != VINF_HGCM_ASYNC_EXECUTE)
    478                     {
    479                         /*
    480                          * Get the next unassigned host command in the list.
    481                          */
    482                         bool bFound = false;
    483                         HostCmdList::iterator it;
    484                         for (it = mHostCmds.begin();
    485                              !bFound && it != mHostCmds.end(); ++it)
    486                         {
    487                             if (it->uAssignedToClientID == 0)
    488                             {
    489                                 bFound = true;
    490                                 break;
    491                             }
    492                         }
    493                         if (!bFound) /* No new command found, defer ... */
    494                             rc = VINF_HGCM_ASYNC_EXECUTE;
    495 
    496                         /*
    497                          * Okay we got a host command which is unassigned at the moment.                   
    498                          */
    499                         if (   RT_SUCCESS(rc)
    500                             && rc != VINF_HGCM_ASYNC_EXECUTE)
    501                         {
    502                             /*
    503                              * Do *not* remove the command from host cmds list here yet, because
    504                              * the client could fail in retrieving the GUEST_GET_HOST_MSG_DATA message
    505                              * below. Then we just could repeat this one here.
    506                              */
    507                             uint32_t uCmd = 1; /** @todo HARDCODED FOR EXEC! */
    508                             uint32_t uParmCount = it->parmBuf.uParmCount;
    509                             if (uParmCount)
    510                                 it->parmBuf.pParms[0].getUInt32(&uCmd);
    511                             paParms[0].setUInt32(uCmd); /* msg id */
    512                             paParms[1].setUInt32(uParmCount); /* parms count */
    513    
    514                             /* Assign this command to the specific client ID. */
    515                             it->uAssignedToClientID = u32ClientID;
    516                         }
    517                     }
    518                 }
    519                 break;
    520 
    521             case GUEST_GET_HOST_MSG_DATA:
    522                 {
    523                     LogFlowFunc(("GUEST_GET_HOST_MSG_DATA\n"));
    524 
    525 /** @todo !!!!! LOCKING !!!!!!!!! */
    526 
    527                     /*
    528                      * Get host command assigned to incoming client ID.                           
    529                      */
    530                     bool bFound = false;
    531                     HostCmdList::iterator it;
    532                     for (it = mHostCmds.begin();
    533                          !bFound && it != mHostCmds.end(); ++it)
    534                     {
    535                         if (it->uAssignedToClientID == u32ClientID)   
    536                         {
    537                             bFound = true;
    538                             break;
    539                         }
    540                     }
    541                     Assert(bFound);
    542 
    543                     /*
    544                      * Assign buffered data to client HGCM parms.
    545                      */
    546                     rc = execBufferAssign(&it->parmBuf, cParms, paParms);
    547        
    548                     /*
    549                      * Finally remove the command from the list.
    550                      */
    551                     execBufferFree(&it->parmBuf);
    552                     mHostCmds.erase(it);
    553                 }
     552                rc = guestGetHostMsg(callHandle, cParms, paParms);
    554553                break;
    555554
     
    572571                rc = VERR_NOT_IMPLEMENTED;
    573572        }
     573        /*
     574         * If current call is not deferred, call the completion function.
     575         */
     576        if (rc != VINF_HGCM_ASYNC_EXECUTE)
     577        {
     578            mpHelpers->pfnCallComplete(callHandle, rc);
     579        }
    574580    }
    575581    catch (std::bad_alloc)
     
    578584    }
    579585    LogFlowFunc(("rc = %Rrc\n", rc));
    580     if (rc != VINF_HGCM_ASYNC_EXECUTE)
    581     {
    582         mpHelpers->pfnCallComplete(callHandle, rc);
    583     }
    584586}
    585587
     
    604606            case HOST_EXEC_CMD:
    605607                LogFlowFunc(("HOST_EXEC_CMD\n"));
    606 
    607 /** @todo !!!!! LOCKING !!!!!!!!! */
    608 
    609                 HostCmd newCmd;
    610                 execBufferAllocate(&newCmd.parmBuf, cParms, paParms);
    611                 newCmd.uAssignedToClientID = 0;
    612                 mHostCmds.push_back(newCmd);
     608                rc = hostProcessCmd(eFunction, cParms, paParms);
    613609                break;
    614610
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