VirtualBox

Changeset 29438 in vbox


Ignore:
Timestamp:
May 12, 2010 9:50:16 PM (15 years ago)
Author:
vboxsync
Message:

Guest Control/VBoxService: Added support for cancel pending (blocking) calls; added support for properly stopping + shutting down main thread.

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/HostServices/GuestControlSvc.h

    r28887 r29438  
    136136     * or starting a program.
    137137     */
    138     HOST_EXEC_CMD = 1,
     138    HOST_EXEC_CMD = 100,
    139139    /**
    140140     * Sends input data for stdin to a running process executed by HOST_EXEC_CMD.
    141141     */
    142     HOST_EXEC_SET_INPUT = 2,
     142    HOST_EXEC_SET_INPUT = 101,
    143143    /**
    144144     * Gets the current status of a running process, e.g.
    145145     * new data on stdout/stderr, process terminated etc.
    146146     */
    147     HOST_EXEC_GET_OUTPUT = 3
     147    HOST_EXEC_GET_OUTPUT = 102
    148148};
    149149
     
    155155{
    156156    /**
     157     * Guest waits for a new message the host wants to process on the guest side.
     158     * This is a blocking call and can be deferred.
     159     */
     160    GUEST_GET_HOST_MSG = 1,
     161    /**
     162     * Guest asks the host to cancel all pending waits the guest waits on.
     163     * This becomes necessary when the guest wants to quit but still waits for
     164     * commands from the host.
     165     */
     166    GUEST_CANCEL_PENDING_WAITS = 2,
     167    /**
    157168     * TODO
    158169     */
    159     GUEST_GET_HOST_MSG = 1,
     170    GUEST_EXEC_SEND_OUTPUT = 100,
    160171    /**
    161172     * TODO
    162173     */
    163     GUEST_EXEC_SEND_OUTPUT = 2,
    164     /**
    165      * TODO
    166      */
    167     GUEST_EXEC_SEND_STATUS = 3
     174    GUEST_EXEC_SEND_STATUS = 101
    168175};
    169176
     
    175182{
    176183    /**
     184     * Hosts wants the guest to stop waiting for new messages.
     185     */
     186    GETHOSTMSG_EXEC_HOST_CANCEL_WAIT = 0,
     187    /**
    177188     * The host wants to execute something in the guest. This can be a command line
    178189     * or starting a program.
    179190     */
    180     GETHOSTMSG_EXEC_START_PROCESS = 1,
     191    GETHOSTMSG_EXEC_START_PROCESS = 100,
    181192    /**
    182193     * Sends input data for stdin to a running process executed by HOST_EXEC_CMD.
    183194     */
    184     GETHOSTMSG_EXEC_SEND_INPUT = 2,
     195    GETHOSTMSG_EXEC_SEND_INPUT = 101,
    185196    /**
    186197     * Host requests the so far collected stdout/stderr output
    187198     * from a running process executed by HOST_EXEC_CMD.
    188199     */
    189     GETHOSTMSG_EXEC_GET_OUTPUT = 3
     200    GETHOSTMSG_EXEC_GET_OUTPUT = 102
    190201};
    191202
     
    200211    /**
    201212     * The returned command the host wants to
    202      * execute on the guest.
     213     * run on the guest.
    203214     */
    204215    HGCMFunctionParameter msg;       /* OUT uint32_t */
    205 
     216    /** Number of parameters the message needs. */
    206217    HGCMFunctionParameter num_parms; /* OUT uint32_t */
    207218
    208219} VBoxGuestCtrlHGCMMsgType;
     220
     221typedef struct _VBoxGuestCtrlHGCMMsgCancelPendingWaits
     222{
     223    VBoxGuestHGCMCallInfo hdr;
     224} VBoxGuestCtrlHGCMMsgCancelPendingWaits;
    209225
    210226typedef struct _VBoxGuestCtrlHGCMMsgExecCmd
  • trunk/include/VBox/VBoxGuestLib.h

    r29307 r29438  
    509509VBGLR3DECL(int)     VbglR3GuestCtrlConnect(uint32_t *pu32ClientId);
    510510VBGLR3DECL(int)     VbglR3GuestCtrlDisconnect(uint32_t u32ClientId);
    511 VBGLR3DECL(int)     VbglR3GuestCtrlGetHostMsg(uint32_t u32ClientId, uint32_t *puMsg, uint32_t *puNumParms, uint32_t u32Timeout);
     511VBGLR3DECL(int)     VbglR3GuestCtrlGetHostMsg(uint32_t u32ClientId, uint32_t *puMsg, uint32_t *puNumParms);
     512VBGLR3DECL(int)     VbglR3GuestCtrlCancelPendingWaits(uint32_t u32ClientId);
    512513VBGLR3DECL(int)     VbglR3GuestCtrlExecGetHostCmd(uint32_t  u32ClientId,    uint32_t  uNumParms,
    513514                                                  uint32_t *puContext,
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp

    r28887 r29438  
    103103 *                          in a second call to the host.
    104104 */
    105 VBGLR3DECL(int) VbglR3GuestCtrlGetHostMsg(uint32_t u32ClientId, uint32_t *puMsg, uint32_t *puNumParms, uint32_t u32Timeout)
     105VBGLR3DECL(int) VbglR3GuestCtrlGetHostMsg(uint32_t u32ClientId, uint32_t *puMsg, uint32_t *puNumParms)
    106106{
    107107    AssertPtr(puMsg);
     
    127127                rc = Msg.hdr.result;
    128128                /* Ok, so now we know what message type and how much parameters there are. */
     129    }
     130    return rc;
     131}
     132
     133
     134/**
     135 * Asks the host to cancel (release) all pending waits which were deferred.
     136 *
     137 * @returns VBox status code.
     138 * @param   u32ClientId     The client id returned by VbglR3GuestCtrlConnect().
     139 */
     140VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(uint32_t u32ClientId)
     141{
     142    VBoxGuestCtrlHGCMMsgCancelPendingWaits Msg;
     143
     144    Msg.hdr.result = VERR_WRONG_ORDER;
     145    Msg.hdr.u32ClientID = u32ClientId;
     146    Msg.hdr.u32Function = GUEST_CANCEL_PENDING_WAITS;
     147    Msg.hdr.cParms = 0;
     148
     149    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     150    if (RT_SUCCESS(rc))
     151    {
     152        int rc2 = Msg.hdr.result;
     153        if (RT_FAILURE(rc2))
     154            rc = rc2;
    129155    }
    130156    return rc;
  • trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp

    r29345 r29438  
    358358        VBoxServiceVerbose(1, "Starting '%s' in the main thread\n", g_aServices[iMain].pDesc->pszName);
    359359        rc = g_aServices[iMain].pDesc->pfnWorker(&g_fShutdown);
    360         if (rc != VINF_SUCCESS) /* Only complain if service returned an error. Otherwise the service is a one-timer. */
    361         {
    362             VBoxServiceError("Service '%s' stopped unexpected; rc=%Rrc\n", g_aServices[iMain].pDesc->pszName, rc);
    363         }
     360        if (RT_SUCCESS(rc))
     361            VBoxServiceVerbose(1, "Main service '%s' successfully stopped.\n", g_aServices[iMain].pDesc->pszName);
     362        else /* Only complain if service returned an error. Otherwise the service is a one-timer. */
     363            VBoxServiceError("Service '%s' stopped unexpected; rc=%Rrc\n", g_aServices[iMain].pDesc->pszName, rc);           
     364        g_aServices[iMain].pDesc->pfnTerm();
    364365    }
    365366    return rc;
     
    376377{
    377378    int rc = VINF_SUCCESS;
     379    int iMain = VBoxServiceGetStartedServices();
    378380
    379381    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
     
    381383    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
    382384        if (g_aServices[j].fStarted)
     385        {
     386            VBoxServiceVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName);
    383387            g_aServices[j].pDesc->pfnStop();
    384     for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
    385         if (g_aServices[j].fEnabled)
     388        }
     389    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
     390
     391        if (    !g_aServices[j].fEnabled /* Only stop services which were started before. */
     392            ||  j == iMain)              /* Don't call the termination function for main service yet. */
     393        {
     394            continue;
     395        }
     396        else
    386397        {
    387398            if (g_aServices[j].Thread != NIL_RTTHREAD)
     
    405416        }
    406417
     418#ifdef RT_OS_WINDOWS
     419    /*
     420     * As we're now done terminating all service threads,
     421     * we have to stop the main thread as well (if defined). Note that the termination
     422     * function will be called in a later context (when the main thread returns from the worker
     423     * function).
     424     */
     425    if (iMain != ~0U)
     426    {
     427        VBoxServiceVerbose(3, "Stopping main service '%s' (%d) ...\n", g_aServices[iMain].pDesc->pszName, iMain);
     428
     429        ASMAtomicXchgBool(&g_fShutdown, true);
     430        g_aServices[iMain].pDesc->pfnStop();                     
     431    }
     432#endif
     433   
    407434    VBoxServiceVerbose(2, "Stopping services returned: rc=%Rrc\n", rc);
    408435    return rc;
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp

    r29345 r29438  
    247247        uint32_t uNumParms;
    248248        VBoxServiceVerbose(3, "Control: Waiting for host msg ...\n");
    249         rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms, 1000 /* 1s timeout */);
     249        rc = VbglR3GuestCtrlGetHostMsg(g_GuestControlSvcClientID, &uMsg, &uNumParms);
    250250        if (RT_FAILURE(rc))
    251251        {
     
    264264            switch(uMsg)
    265265            {
     266                case GETHOSTMSG_EXEC_HOST_CANCEL_WAIT:
     267                    VBoxServiceVerbose(3, "Control: Host asked us to quit ...\n");
     268                    break;
     269
    266270                case GETHOSTMSG_EXEC_START_PROCESS:
    267271                    rc = VBoxServiceControlHandleCmdStartProcess(g_GuestControlSvcClientID, uNumParms);
     
    283287
    284288        /* Do we need to shutdown? */
    285         if (*pfShutdown)
    286         {
    287             rc = 0;
     289        if (   *pfShutdown
     290            || uMsg == GETHOSTMSG_EXEC_HOST_CANCEL_WAIT)
     291        {
     292            rc = VINF_SUCCESS;
    288293            break;
    289294        }
     
    302307static DECLCALLBACK(void) VBoxServiceControlStop(void)
    303308{
     309    VBoxServiceVerbose(3, "Control: Stopping ...\n");
     310
    304311    /** @todo Later, figure what to do if we're in RTProcWait(). it's a very
    305312     *        annoying call since doesn't support timeouts in the posix world. */
    306313    RTSemEventMultiSignal(g_hControlEvent);
     314
     315    /*
     316     * Ask the host service to cancel all pending requests so that we can
     317     * shutdown properly here.
     318     */
     319    if (g_GuestControlSvcClientID)
     320    {
     321        int rc = VbglR3GuestCtrlCancelPendingWaits(g_GuestControlSvcClientID);
     322        if (RT_FAILURE(rc))
     323            VBoxServiceError("Control: Cancelling pending waits failed; rc=%Rrc\n", rc);
     324    }
    307325}
    308326
     
    311329static DECLCALLBACK(void) VBoxServiceControlTerm(void)
    312330{
     331    VBoxServiceVerbose(3, "Control: Terminating ...\n");
     332
    313333    /* Signal all threads that we want to shutdown. */
    314334    PVBOXSERVICECTRLTHREAD pNode;
     
    321341        if (pNode->Thread != NIL_RTTHREAD)
    322342        {
     343            /* Wait a bit ... */
    323344            int rc2 = RTThreadWait(pNode->Thread, 30 * 1000 /* Wait 30 seconds max. */, NULL);
    324345            if (RT_FAILURE(rc2))
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r29193 r29438  
    318318                        if (verbose)
    319319                            RTPrintf("No time left to wait for process!\n");
    320                     }                   
     320                    }
    321321                }
    322322                else if (verbose)
    323                     RTPrintf("Waiting for process to exit ...\n");                       
     323                    RTPrintf("Waiting for process to exit ...\n");
    324324
    325325                /* setup signal handling if cancelable */
     
    344344                while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
    345345                {
    346                     /* 
     346                    /*
    347347                     * because we want to get all the output data even if the process
    348348                     * already ended, we first need to check whether there is some data
    349349                     * left to output before checking the actual timeout and is-process-completed
    350                      * stuff. 
     350                     * stuff.
    351351                     */
    352352                    if (cbOutputData <= 0)
     
    363363                    }
    364364
    365                     if (   waitForStdOut 
     365                    if (   waitForStdOut
    366366                        || waitForStdErr)
    367367                    {
    368                         CHECK_ERROR_BREAK(guest, GetProcessOutput(uPID, 0 /* aFlags */, 
     368                        CHECK_ERROR_BREAK(guest, GetProcessOutput(uPID, 0 /* aFlags */,
    369369                                                                  u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)));
    370370                        cbOutputData = aOutputData.size();
     
    421421                }
    422422                else
    423                 {                   
     423                {
    424424                    if (fCompleted)
    425425                    {
     
    440440                            CHECK_ERROR_BREAK(guest, GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus));
    441441                            RTPrintf("Exit code=%u (Status=%u, Flags=%u)\n", uRetExitCode, uRetStatus, uRetFlags);
    442                         }       
    443                     }
    444                     else /* not completed yet? -> timeout */
    445                     {
    446                         RTPrintf("Process timed out!\n");
     442                        }
    447443                    }
    448444                }
  • trunk/src/VBox/HostServices/GuestControl/service.cpp

    r29220 r29438  
    220220    int sendHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    221221    int retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     222    int cancelPendingWaits(uint32_t u32ClientID);
    222223    int notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    223224    int processHostCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     
    443444}
    444445
     446int Service::cancelPendingWaits(uint32_t u32ClientID)
     447{
     448    int rc = VINF_SUCCESS;
     449    CallListIter it = mClientList.begin();
     450    while (it != mClientList.end())
     451    {
     452        if (it->mClientID == u32ClientID)
     453        {       
     454            if (it->mNumParms >= 2)
     455            {
     456                it->mParms[0].setUInt32(GETHOSTMSG_EXEC_HOST_CANCEL_WAIT); /* Message ID */
     457                it->mParms[1].setUInt32(0);                                /* Required parameters for message */
     458            }             
     459            if (mpHelpers)
     460                mpHelpers->pfnCallComplete(it->mHandle, rc);     
     461            it = mClientList.erase(it);
     462        }
     463        else
     464            it++;
     465    }
     466    return rc;
     467}
     468
    445469int Service::notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    446470{
     
    503527
    504528            /* In any case the client did something, so wake up and remove from list. */
     529            AssertPtr(mpHelpers);
    505530            mpHelpers->pfnCallComplete(guest.mHandle, rc);
    506531            mClientList.pop_front();                       
     
    559584                break;
    560585
     586            case GUEST_CANCEL_PENDING_WAITS:
     587                LogFlowFunc(("GUEST_CANCEL_PENDING_WAITS\n"));
     588                rc = cancelPendingWaits(u32ClientID);
     589                break;
     590
    561591            /* The guest notifies the host that some output at stdout/stderr is available. */
    562592            case GUEST_EXEC_SEND_OUTPUT:
     
    578608        {
    579609            /* Tell the client that the call is complete (unblocks waiting). */
     610            AssertPtr(mpHelpers);
    580611            mpHelpers->pfnCallComplete(callHandle, rc);
    581612        }
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