VirtualBox

Changeset 35952 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Feb 14, 2011 10:17:07 AM (14 years ago)
Author:
vboxsync
Message:

VBoxService/GuestCtrl: Introduced pipe buffer events for waiting on input/output data.

Location:
trunk/src/VBox/Additions/common/VBoxService
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlExec.cpp

    r35692 r35952  
    7676
    7777        /* Mark the stdin buffer as dead; we're not using it anymore. */
    78         pStdInBuf->fAlive = false;
     78        pStdInBuf->fEnabled = false;
    7979
    8080        rc2 = RTPollSetRemove(hPollSet, VBOXSERVICECTRLPIPEID_STDIN_ERROR);
     
    113113        cbToWrite = RT_MIN(cbToWrite, _1M);
    114114        *pfClose = false;
    115         if (   pStdInBuf->fAlive
     115        if (   pStdInBuf->fEnabled
    116116            && cbToWrite)
    117117        {
     
    148148            {
    149149                *pcbWritten = 0;
    150                 pStdInBuf->fAlive = pStdInBuf->fAlive;
     150                pStdInBuf->fEnabled = pStdInBuf->fEnabled;
    151151            }
    152152#ifdef DEBUG
     
    159159        {
    160160            *pcbWritten = 0;
    161             pStdInBuf->fNeedNotification = pStdInBuf->fAlive;
     161            pStdInBuf->fNeedNotification = pStdInBuf->fEnabled;
    162162        }
    163163
    164164        if (   !*pcbWritten
    165             && pStdInBuf->fAlive)
     165            && pStdInBuf->fEnabled)
    166166        {
    167167            /*
     
    298298#endif
    299299            uint32_t cbWritten;
    300             rc = VBoxServiceControlExecWritePipeBuffer(pStdOutBuf, abBuf,
    301                                                        cbRead, false /* Pending close */, &cbWritten);
     300            rc = VBoxServiceControlExecPipeBufWrite(pStdOutBuf, abBuf,
     301                                                    cbRead, false /* Pending close */, &cbWritten);
    302302            if (RT_SUCCESS(rc))
    303303            {
     
    581581    if (RT_SUCCESS(rc))
    582582    {
     583        VBoxServiceControlExecPipeBufSetStatus(&pData->stdIn, false /* Disabled */);
     584        VBoxServiceControlExecPipeBufSetStatus(&pData->stdOut, false /* Disabled */);
     585        VBoxServiceControlExecPipeBufSetStatus(&pData->stdErr, false /* Disabled */);
     586
    583587        /* Since the process is not alive anymore, destroy its local
    584588         * stdin pipe buffer - it's not used anymore and can eat up quite
    585589         * a bit of memory. */
    586         VBoxServiceControlExecDeletePipeBuffer(&pData->stdIn);
     590        VBoxServiceControlExecPipeBufDestroy(&pData->stdIn);
    587591
    588592        uint32_t uStatus = PROC_STS_UNDEFINED;
     
    710714 *                                  pipe or not.
    711715 */
    712 static int VBoxServiceControlExecInitPipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf, bool fNeedNotificationPipe)
     716static int VBoxServiceControlExecPipeBufInit(PVBOXSERVICECTRLEXECPIPEBUF pBuf, bool fNeedNotificationPipe)
    713717{
    714718    AssertPtrReturn(pBuf, VERR_INVALID_PARAMETER);
     
    720724    pBuf->cbSize = 0;
    721725    pBuf->cbOffset = 0;
    722     pBuf->fAlive = true;
     726    pBuf->fEnabled = true;
    723727    pBuf->fPendingClose = false;
    724728    pBuf->fNeedNotification = fNeedNotificationPipe;
    725729    pBuf->hNotificationPipeW = NIL_RTPIPE;
    726730    pBuf->hNotificationPipeR = NIL_RTPIPE;
    727 
    728     int rc = RTCritSectInit(&pBuf->CritSect);
    729     if (RT_SUCCESS(rc) && fNeedNotificationPipe)
    730     {
    731         rc = RTPipeCreate(&pBuf->hNotificationPipeR, &pBuf->hNotificationPipeW, 0);
    732         if (RT_FAILURE(rc))
    733             RTCritSectDelete(&pBuf->CritSect);
    734     }
    735     return rc;
    736 }
    737 
    738 
    739 /**
    740  * Deletes a pipe buffer.
    741  *
    742  * @param   pBuf            The pipe buffer.
    743  */
    744 void VBoxServiceControlExecDeletePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf)
    745 {
    746     AssertPtr(pBuf);
    747     if (pBuf->pbData)
    748     {
    749         RTMemFree(pBuf->pbData);
    750         pBuf->pbData = NULL;
    751         pBuf->cbAllocated = 0;
    752         pBuf->cbSize = 0;
    753         pBuf->cbOffset = 0;
    754         pBuf->fAlive = false;
    755     }
    756 
    757     RTPipeClose(pBuf->hNotificationPipeR);
    758     pBuf->hNotificationPipeR = NIL_RTPIPE;
    759     RTPipeClose(pBuf->hNotificationPipeW);
    760     pBuf->hNotificationPipeW = NIL_RTPIPE;
    761     RTCritSectDelete(&pBuf->CritSect);
     731    pBuf->hEventSem = NIL_RTSEMEVENT;
     732
     733    int rc = RTSemEventCreate(&pBuf->hEventSem);
     734    if (RT_SUCCESS(rc))
     735    {
     736        rc = RTCritSectInit(&pBuf->CritSect);
     737        if (RT_SUCCESS(rc) && fNeedNotificationPipe)
     738        {
     739            rc = RTPipeCreate(&pBuf->hNotificationPipeR, &pBuf->hNotificationPipeW, 0);
     740            if (RT_FAILURE(rc))
     741                RTCritSectDelete(&pBuf->CritSect);
     742        }
     743    }
     744    return rc;
    762745}
    763746
     
    773756 *                                      will reflect the actual amount read on return.
    774757 */
    775 int VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
    776                                                 uint8_t *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead)
     758static int VBoxServiceControlExecPipeBufRead(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     759                                             uint8_t *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead)
    777760{
    778761    AssertPtrReturn(pBuf, VERR_INVALID_PARAMETER);
     
    795778            memcpy(pbBuffer, pBuf->pbData + pBuf->cbOffset, *pcbToRead);
    796779            pBuf->cbOffset += *pcbToRead;
     780
     781            RTSemEventSignal(pBuf->hEventSem);
    797782        }
    798783        else
     
    817802 * @param   pcbWritten                  Pointer to where the amount of written bytes get stored. Optional.
    818803 */
    819 int VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
    820                                           uint8_t *pbData, uint32_t cbData, bool fPendingClose,
    821                                           uint32_t *pcbWritten)
     804static int VBoxServiceControlExecPipeBufWrite(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     805                                              uint8_t *pbData, uint32_t cbData, bool fPendingClose,
     806                                              uint32_t *pcbWritten)
    822807{
    823808    AssertPtrReturn(pBuf, VERR_INVALID_PARAMETER);
     
    825810
    826811    int rc;
    827     if (pBuf->fAlive)
     812    if (pBuf->fEnabled)
    828813    {
    829814        rc = RTCritSectEnter(&pBuf->CritSect);
     
    885870            if (RT_SUCCESS(rc))
    886871            {
    887                 /* Report back written bytes (if wanted). */
    888                 if (pcbWritten)
    889                     *pcbWritten = cbData;
    890 
    891872                /*
    892873                 * Was this the final read/write to do on this buffer? Then close it
     
    908889                    pBuf->fNeedNotification = !RT_SUCCESS(rc2);
    909890                }
     891
     892                /* Report back written bytes (if wanted). */
     893                if (pcbWritten)
     894                    *pcbWritten = cbData;
     895
     896                RTSemEventSignal(pBuf->hEventSem);
    910897            }
    911898            int rc2 = RTCritSectLeave(&pBuf->CritSect);
     
    917904        rc = VERR_BAD_PIPE;
    918905    return rc;
     906}
     907
     908
     909/**
     910 * Returns whether a pipe buffer is active or not.
     911 *
     912 * @return  bool            True if pipe buffer is active, false if not.
     913 * @param   pBuf            The pipe buffer.
     914 */
     915static bool VBoxServiceControlExecPipeBufIsEnabled(PVBOXSERVICECTRLEXECPIPEBUF pBuf)
     916{
     917    AssertPtrReturn(pBuf, VERR_INVALID_PARAMETER);
     918
     919    bool fEnabled = false;
     920    if (RT_SUCCESS(RTCritSectEnter(&pBuf->CritSect)))
     921    {
     922        fEnabled = pBuf->fEnabled;
     923        RTCritSectLeave(&pBuf->CritSect);
     924    }
     925    return fEnabled;
     926}
     927
     928
     929/**
     930 * Sets the current status (enabled/disabled) of a pipe buffer.
     931 *
     932 * @return  IPRT status code.
     933 * @param   pBuf            The pipe buffer.
     934 * @param   fEnabled        Pipe buffer status to set.
     935 */
     936static int VBoxServiceControlExecPipeBufSetStatus(PVBOXSERVICECTRLEXECPIPEBUF pBuf, bool fEnabled)
     937{
     938    AssertPtrReturn(pBuf, VERR_INVALID_PARAMETER);
     939
     940    int rc = RTCritSectEnter(&pBuf->CritSect);
     941    if (RT_SUCCESS(rc))
     942    {
     943        pBuf->fEnabled = fEnabled;
     944        /* Let waiter know that something has changed ... */
     945        if (pBuf->hEventSem)
     946            RTSemEventSignal(pBuf->hEventSem);
     947        rc = RTCritSectLeave(&pBuf->CritSect);
     948    }
     949    return rc;
     950}
     951
     952
     953/**
     954 * Deletes a pipe buffer.
     955 * Note: Not thread safe -- only call this when nobody is relying on the
     956 *       data anymore!
     957 *
     958 * @param   pBuf            The pipe buffer.
     959 */
     960static void VBoxServiceControlExecPipeBufDestroy(PVBOXSERVICECTRLEXECPIPEBUF pBuf)
     961{
     962    AssertPtr(pBuf);
     963    if (pBuf->pbData)
     964    {
     965        RTMemFree(pBuf->pbData);
     966        pBuf->pbData = NULL;
     967        pBuf->cbAllocated = 0;
     968        pBuf->cbSize = 0;
     969        pBuf->cbOffset = 0;
     970    }
     971
     972    RTPipeClose(pBuf->hNotificationPipeR);
     973    pBuf->hNotificationPipeR = NIL_RTPIPE;
     974    RTPipeClose(pBuf->hNotificationPipeW);
     975    pBuf->hNotificationPipeW = NIL_RTPIPE;
     976
     977    RTSemEventDestroy(pBuf->hEventSem);
     978    RTCritSectDelete(&pBuf->CritSect);
    919979}
    920980
     
    10171077
    10181078        /* Init buffers. */
    1019         rc = VBoxServiceControlExecInitPipeBuffer(&pData->stdOut, false /*fNeedNotificationPipe*/);
     1079        rc = VBoxServiceControlExecPipeBufInit(&pData->stdOut, false /*fNeedNotificationPipe*/);
    10201080        if (RT_SUCCESS(rc))
    10211081        {
    1022             rc = VBoxServiceControlExecInitPipeBuffer(&pData->stdErr, false /*fNeedNotificationPipe*/);
     1082            rc = VBoxServiceControlExecPipeBufInit(&pData->stdErr, false /*fNeedNotificationPipe*/);
    10231083            if (RT_SUCCESS(rc))
    1024                 rc = VBoxServiceControlExecInitPipeBuffer(&pData->stdIn, true /*fNeedNotificationPipe*/);
     1084                rc = VBoxServiceControlExecPipeBufInit(&pData->stdIn, true /*fNeedNotificationPipe*/);
    10251085        }
    10261086    }
     
    10591119        RTStrFree(pData->pszPassword);
    10601120
    1061         VBoxServiceControlExecDeletePipeBuffer(&pData->stdOut);
    1062         VBoxServiceControlExecDeletePipeBuffer(&pData->stdErr);
    1063         VBoxServiceControlExecDeletePipeBuffer(&pData->stdIn);
     1121        VBoxServiceControlExecPipeBufDestroy(&pData->stdOut);
     1122        VBoxServiceControlExecPipeBufDestroy(&pData->stdErr);
     1123        VBoxServiceControlExecPipeBufDestroy(&pData->stdIn);
    10641124
    10651125        RTMemFree(pData);
     
    17111771             */
    17121772            uint32_t cbWritten;
    1713             rc = VBoxServiceControlExecWritePipeBuffer(&pData->stdIn, pabBuffer, cbSize, fPendingClose, &cbWritten);
     1773            rc = VBoxServiceControlExecPipeBufWrite(&pData->stdIn, pabBuffer,
     1774                                                    cbSize, fPendingClose, &cbWritten);
    17141775#ifdef DEBUG
    17151776            VBoxServiceVerbose(4, "ControlExec: Written to StdIn buffer (PID %u): rc=%Rrc, uFlags=0x%x, cbAlloc=%u, cbSize=%u, cbOffset=%u\n",
     
    17871848            if (pBuf)
    17881849            {
    1789                 /** @todo Use uHandleID to distinguish between stdout/stderr! */
    1790                 rc = VBoxServiceControlExecReadPipeBufferContent(&pData->stdOut, pBuf, cbSize, &cbRead);
     1850                /* If the stdout pipe buffer is enabled (that is, still could be filled by a running
     1851                 * process) wait for the signal to arrive so that we don't return without any actual
     1852                 * data read. */
     1853                if (VBoxServiceControlExecPipeBufIsEnabled(&pData->stdOut))
     1854                {
     1855                    VBoxServiceVerbose(4, "ControlExec: Waiting for output data becoming ready ...\n");
     1856                    rc = RTSemEventWait(pData->stdOut.hEventSem, RT_INDEFINITE_WAIT);
     1857                }
    17911858                if (RT_SUCCESS(rc))
    17921859                {
    1793                     /* Note: Since the context ID is unique the request *has* to be completed here,
    1794                      *       regardless whether we got data or not! Otherwise the progress object
    1795                      *       on the host never will get completed! */
    1796                     /* cbRead now contains actual size. */
    1797                     rc = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, 0 /* Handle ID */, 0 /* Flags */,
    1798                                                     pBuf, cbRead);
     1860                    /** @todo Use uHandleID to distinguish between stdout/stderr! */
     1861                    rc = VBoxServiceControlExecPipeBufRead(&pData->stdOut, pBuf, cbSize, &cbRead);
     1862                    if (RT_SUCCESS(rc))
     1863                    {
     1864                        /* Note: Since the context ID is unique the request *has* to be completed here,
     1865                         *       regardless whether we got data or not! Otherwise the progress object
     1866                         *       on the host never will get completed! */
     1867                        /* cbRead now contains actual size. */
     1868                        rc = VbglR3GuestCtrlExecSendOut(u32ClientId, uContextID, uPID, 0 /* Handle ID */, 0 /* Flags */,
     1869                                                        pBuf, cbRead);
     1870                    }
    17991871                }
    18001872                RTMemFree(pBuf);
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h

    r34867 r35952  
    55
    66/*
    7  * Copyright (C) 2007-2010 Oracle Corporation
     7 * Copyright (C) 2007-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    136136    /** Critical section protecting this buffer structure. */
    137137    RTCRITSECT  CritSect;
    138     /** Indicates the health condition of the child process. */
    139     bool        fAlive;
     138    /** Flag indicating whether this pipe buffer accepts new
     139     *  data to be written to or not. If not enabled, already
     140     *  (allocated) buffered data still can be read out. */
     141    bool        fEnabled;
    140142    /** Set if it's necessary to write to the notification pipe. */
    141143    bool        fNeedNotification;
     
    147149    /** The other end of hNotificationPipeW. */
    148150    RTPIPE      hNotificationPipeR;
     151    /** The event semaphore for getting notified whether something
     152     *  has changed, e.g. written or read from this buffer. */
     153    RTSEMEVENT  hEventSem;
    149154} VBOXSERVICECTRLEXECPIPEBUF;
    150155/** Pointer to buffered pipe data. */
     
    299304                                                  const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS);
    300305extern void         VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREADDATAEXEC pThread);
    301 extern void         VBoxServiceControlExecDeletePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf);
    302 extern int          VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
    303                                                                 uint8_t *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead);
    304 extern int          VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
    305                                                           uint8_t *pbData, uint32_t cbData, bool fPendingClose, uint32_t *pcbWritten);
     306
     307extern int          VBoxServiceControlExecPipeInit(PVBOXSERVICECTRLEXECPIPEBUF pBuf, bool fNeedNotificationPipe);
     308extern int          VBoxServiceControlExecPipeBufRead(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     309                                                      uint8_t *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead);
     310extern int          VBoxServiceControlExecPipeBufWrite(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
     311                                                       uint8_t *pbData, uint32_t cbData, bool fPendingClose, uint32_t *pcbWritten);
     312extern bool         VBoxServiceControlExecPipeBufIsEnabled(PVBOXSERVICECTRLEXECPIPEBUF pBuf);
     313extern int          VBoxServiceControlExecPipeBufSetStatus(PVBOXSERVICECTRLEXECPIPEBUF pBuf, bool fEnabled);
     314extern void         VBoxServiceControlExecPipeBufDestroy(PVBOXSERVICECTRLEXECPIPEBUF pBuf);
    306315#endif /* VBOX_WITH_GUEST_CONTROL */
    307316
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