VirtualBox

Changeset 47545 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Aug 5, 2013 7:09:25 PM (11 years ago)
Author:
vboxsync
Message:

VBoxService/GuestCtrl: Implemented asynchronous request queue, bugfixes.

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

Legend:

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

    r45415 r47545  
    210210        if (rc == VERR_TOO_MUCH_DATA)
    211211        {
     212#ifdef DEBUG
    212213            VBoxServiceVerbose(4, "Message requires %ld parameters, but only 2 supplied -- retrying request (no error!)...\n", cParms);
     214#endif
    213215            rc = VINF_SUCCESS; /* Try to get "real" message in next block below. */
    214216        }
     
    217219        if (RT_SUCCESS(rc))
    218220        {
     221#ifdef DEBUG
    219222            VBoxServiceVerbose(3, "Msg=%RU32 (%RU32 parms) retrieved\n", uMsg, cParms);
    220 
     223#endif
    221224            /* Set number of parameters for current host context. */
    222225            ctxHost.uNumParms = cParms;
     
    275278                         */
    276279                        rc = VbglR3GuestCtrlMsgSkip(g_uControlSvcClientID);
    277                         VBoxServiceVerbose(3, "Skipping msg=%RU32, rc=%Rrc\n", uMsg, rc);
     280                        VBoxServiceVerbose(3, "Skipping uMsg=%RU32, cParms=%RU32, rc=%Rrc\n",
     281                                           uMsg, cParms, rc);
    278282                    }
    279283                    break;
     
    469473    "              [--control-dump-stderr] [--control-dump-stdout]\n"
    470474#endif
    471     "              [--control-interval <ms>]\n"
    472     "              [--control-procs-mem-std[in|out|err] <KB>]"
     475    "              [--control-interval <ms>]"
    473476    ,
    474477    /* pszOptions. */
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h

    r47334 r47545  
    1919#define ___VBoxServiceControl_h
    2020
     21#include <iprt/critsect.h>
    2122#include <iprt/list.h>
    22 #include <iprt/critsect.h>
     23#include <iprt/req.h>
    2324
    2425#include <VBox/VBoxGuestLib.h>
     
    4243    VBOXSERVICECTRLPIPEID_IPC_NOTIFY        = 100
    4344} VBOXSERVICECTRLPIPEID;
    44 
    45 /**
    46  * Request types to perform on a started guest process.
    47  */
    48 typedef enum VBOXSERVICECTRLREQUESTTYPE
    49 {
    50     /** Unknown request. */
    51     VBOXSERVICECTRLREQUEST_UNKNOWN          = 0,
    52     /** Performs reading from stdout. */
    53     VBOXSERVICECTRLREQUEST_PROC_STDOUT      = 50,
    54     /** Performs reading from stderr. */
    55     VBOXSERVICECTRLREQUEST_PROC_STDERR      = 60,
    56     /** Performs writing to stdin. */
    57     VBOXSERVICECTRLREQUEST_PROC_STDIN       = 70,
    58     /** Same as VBOXSERVICECTRLREQUEST_STDIN_WRITE, but
    59      *  marks the end of input. */
    60     VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF   = 71,
    61     /** Kill/terminate process. */
    62     VBOXSERVICECTRLREQUEST_PROC_TERM        = 90,
    63     /** Gently ask process to terminate. */
    64     /** @todo Implement this! */
    65     VBOXSERVICECTRLREQUEST_PROC_HUP         = 91,
    66     /** Wait for a certain event to happen. */
    67     VBOXSERVICECTRLREQUEST_WAIT_FOR         = 100
    68 } VBOXSERVICECTRLREQUESTTYPE;
    69 
    70 /**
    71  * Thread list types.
    72  */
    73 typedef enum VBOXSERVICECTRLTHREADLISTTYPE
    74 {
    75     /** Unknown list -- uncool to use. */
    76     VBOXSERVICECTRLTHREADLIST_UNKNOWN       = 0,
    77     /** Stopped list: Here all guest threads end up
    78      *  when they reached the stopped state and can
    79      *  be shut down / free'd safely. */
    80     VBOXSERVICECTRLTHREADLIST_STOPPED       = 1,
    81     /**
    82      * Started list: Here all threads are registered
    83      * when they're up and running (that is, accepting
    84      * commands).
    85      */
    86     VBOXSERVICECTRLTHREADLIST_RUNNING       = 2
    87 } VBOXSERVICECTRLTHREADLISTTYPE;
    88 
    89 /**
    90  * Structure to perform a request on a started guest
    91  * process. Needed for letting the main guest control thread
    92  * to communicate (and wait) for a certain operation which
    93  * will be done in context of the started guest process thread.
    94  */
    95 typedef struct VBOXSERVICECTRLREQUEST
    96 {
    97     /** Event semaphore to serialize access. */
    98     RTSEMEVENTMULTI            Event;
    99     /** Flag indicating if this request is asynchronous or not.
    100      *  If asynchronous, this request will be deleted automatically
    101      *  on completion. Otherwise the caller has to delete the
    102      *  request again. */
    103     bool                       fAsync;
    104     /** The request type to handle. */
    105     VBOXSERVICECTRLREQUESTTYPE enmType;
    106     /** Payload size; on input, this contains the (maximum) amount
    107      *  of data the caller  wants to write or to read. On output,
    108      *  this show the actual amount of data read/written. */
    109     size_t                     cbData;
    110     /** Payload data; a pre-allocated data buffer for input/output. */
    111     void                      *pvData;
    112     /** The context ID which is required to complete the
    113      *  request. Not used at the moment. */
    114     uint32_t                   uCID;
    115     /** The overall result of the operation. */
    116     int                        rc;
    117 } VBOXSERVICECTRLREQUEST;
    118 /** Pointer to request. */
    119 typedef VBOXSERVICECTRLREQUEST *PVBOXSERVICECTRLREQUEST;
    120 
    121 typedef struct VBOXSERVICECTRLREQDATA_WAIT_FOR
    122 {
    123     /** Waiting flags. */
    124     uint32_t uWaitFlags;
    125     /** Timeout in (ms) for the waiting operation. */
    126     uint32_t uTimeoutMS;
    127 } VBOXSERVICECTRLREQDATA_WAIT_FOR, *PVBOXSERVICECTRLREQDATA_WAIT_FOR;
    12845
    12946/**
     
    250167    VBOXSERVICECTRLSESSIONSTARTUPINFO
    251168                                    StartupInfo;
    252     /** List of active guest process threads (VBOXSERVICECTRLPROCESS). */
    253     RTLISTANCHOR                    lstProcessesActive;
    254     /** List of inactive guest process threads (VBOXSERVICECTRLPROCESS). */
    255     /** @todo Still needed? */
    256     RTLISTANCHOR                    lstProcessesInactive;
     169    /** List of active guest process threads
     170     *  (VBOXSERVICECTRLPROCESS). */
     171    RTLISTANCHOR                    lstProcesses;
    257172    /** List of guest control files (VBOXSERVICECTRLFILE). */
    258173    RTLISTANCHOR                    lstFiles;
     
    310225typedef struct VBOXSERVICECTRLPROCESS
    311226{
    312     /** Pointer to list archor of following
    313      *  list node.
    314      *  @todo Would be nice to have a RTListGetAnchor(). */
    315     PRTLISTANCHOR                   pAnchor;
    316227    /** Node. */
    317228    RTLISTNODE                      Node;
     229    /** Process handle. */
     230    RTPROCESS                       hProcess;
    318231    /** Number of references using this struct. */
    319232    uint32_t                        cRefs;
     
    326239      * needs (or is asked) to shutdown. */
    327240    bool volatile                   fShutdown;
    328     /** Whether the guest process thread already was
    329      *  stopped or not. */
     241    /** Whether the guest process thread was stopped
     242     *  or not. */
    330243    bool volatile                   fStopped;
    331244    /** Whether the guest process thread was started
     
    343256    /** The process' PID assigned by the guest OS. */
    344257    uint32_t                        uPID;
    345     /** Pointer to the current IPC request being
    346      *  processed. We only support one request at a
    347      *  time at the moment.
    348      ** @todo Implemenet a request queue. */
    349     PVBOXSERVICECTRLREQUEST         pRequest;
     258    /** The process' request queue to handle requests
     259     *  from the outside, e.g. the session. */
     260    RTREQQUEUE                      hReqQueue;
     261    /** Our pollset, used for accessing the process'
     262     *  std* pipes + the notification pipe. */
     263    RTPOLLSET                       hPollSet;
    350264    /** StdIn pipe for addressing writes to the
    351265     *  guest process' stdin.*/
    352     RTPIPE                          pipeStdInW;
     266    RTPIPE                          hPipeStdInW;
     267    /** StdOut pipe for addressing reads from
     268     *  guest process' stdout.*/
     269    RTPIPE                          hPipeStdOutR;
     270    /** StdOut pipe for addressing reads from
     271     *  guest process' stdout.*/
     272    RTPIPE                          hPipeStdErrR;
    353273    /** The notification pipe associated with this guest process.
    354274     *  This is NIL_RTPIPE for output pipes. */
     
    378298extern int                      GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession);
    379299extern RTEXITCODE               VBoxServiceControlSessionForkInit(int argc, char **argv);
    380 
    381 /* asdf */
    382 extern PVBOXSERVICECTRLPROCESS  GstCntlSessionAcquireProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID);
     300/* Per-session functions. */
     301extern PVBOXSERVICECTRLPROCESS  GstCntlSessionRetainProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID);
    383302extern int                      GstCntlSessionClose(PVBOXSERVICECTRLSESSION pSession);
    384303extern int                      GstCntlSessionDestroy(PVBOXSERVICECTRLSESSION pSession);
    385304extern int                      GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags);
    386305extern int                      GstCntlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf, volatile bool *pfShutdown);
    387 extern int                      GstCntlSessionListSet(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pThread, VBOXSERVICECTRLTHREADLISTTYPE enmList);
     306extern int                      GstCntlSessionProcessAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess);
     307extern int                      GstCntlSessionProcessRemove(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLPROCESS pProcess);
    388308extern int                      GstCntlSessionProcessStartAllowed(const PVBOXSERVICECTRLSESSION pSession, bool *pbAllowed);
    389309extern int                      GstCntlSessionReapProcesses(PVBOXSERVICECTRLSESSION pSession);
    390 /* Per-thread guest process functions. */
    391 extern int                      GstCntlProcessPerform(PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest, bool fAsync);
     310/* Per-guest process functions. */
     311extern int                      GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess);
     312extern int                      GstCntlProcessHandleInput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx, bool fPendingClose, void *pvBuf, uint32_t cbBuf);
     313extern int                      GstCntlProcessHandleOutput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx, uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags);
     314extern int                      GstCntlProcessHandleTerm(PVBOXSERVICECTRLPROCESS pProcess);
     315extern void                     GstCntlProcessRelease(PVBOXSERVICECTRLPROCESS pProcess);
    392316extern int                      GstCntlProcessStart(const PVBOXSERVICECTRLSESSION pSession, const PVBOXSERVICECTRLPROCSTARTUPINFO pStartupInfo, uint32_t uContext);
    393317extern int                      GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess);
    394 extern void                     GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pProcess);
    395318extern int                      GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pProcess, RTMSINTERVAL msTimeout, int *pRc);
    396 extern int                      GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess);
    397 /* Process request handling. */
    398 extern int                      GstCntlProcessRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE enmType);
    399 extern int                      GstCntlProcessRequestAllocEx(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE  enmType, void *pvData, size_t cbData, uint32_t uCID);
    400 extern void                     GstCntlProcessRequestFree(PVBOXSERVICECTRLREQUEST pReq);
    401 /* Per-session functions. */
    402 extern int                      GstCntlSessionHandleProcExec(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
    403 extern int                      GstCntlSessionHandleProcInput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);
    404 extern int                      GstCntlSessionHandleProcOutput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
    405 extern int                      GstCntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
    406 extern int                      GstCntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
    407319
    408320RT_C_DECLS_END
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp

    r47490 r47545  
    4848static int                  gstcntlProcessAssignPID(PVBOXSERVICECTRLPROCESS pThread, uint32_t uPID);
    4949static int                  gstcntlProcessLock(PVBOXSERVICECTRLPROCESS pProcess);
    50 static int                  gstcntlProcessRequestCancel(PVBOXSERVICECTRLREQUEST pThread);
     50static int                  gstcntlProcessRequest(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, PFNRT pfnFunction, unsigned cArgs, ...);
    5151static int                  gstcntlProcessSetupPipe(const char *pszHowTo, int fd, PRTHANDLE ph, PRTHANDLE *pph, PRTPIPE phPipe);
    5252static int                  gstcntlProcessUnlock(PVBOXSERVICECTRLPROCESS pProcess);
     53/* Request handlers. */
     54static DECLCALLBACK(int)    gstcntlProcessOnInput(PVBOXSERVICECTRLPROCESS pThis, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, bool fPendingClose, void *pvBuf, uint32_t cbBuf);
     55static DECLCALLBACK(int)    gstcntlProcessOnOutput(PVBOXSERVICECTRLPROCESS pThis, const PVBGLR3GUESTCTRLCMDCTX pHostCtx, uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags);
     56static DECLCALLBACK(int)    gstcntlProcessOnTerm(PVBOXSERVICECTRLPROCESS pThis);
    5357
    5458/**
     
    7175
    7276    /* General stuff. */
     77    pProcess->hProcess   = NIL_RTPROCESS;
    7378    pProcess->pSession   = pSession;
    74     pProcess->pAnchor    = NULL;
    7579    pProcess->Node.pPrev = NULL;
    7680    pProcess->Node.pNext = NULL;
    7781
    78     pProcess->fShutdown = false;
    79     pProcess->fStarted  = false;
    80     pProcess->fStopped  = false;
    81 
     82    pProcess->fShutdown  = false;
     83    pProcess->fStarted   = false;
     84    pProcess->fStopped   = false;
     85
     86    pProcess->uPID       = 0; /* Don't have a PID yet. */
     87    pProcess->cRefs      = 0;
     88    /*
     89     * Use the initial context ID we got for starting
     90     * the process to report back its status with the
     91     * same context ID.
     92     */
    8293    pProcess->uContextID = u32ContextID;
    83     /* ClientID will be assigned when thread is started; every guest
    84      * process has its own client ID to detect crashes on a per-guest-process
    85      * level. */
     94    /*
     95     * Note: pProcess->ClientID will be assigned when thread is started;
     96     * every guest process has its own client ID to detect crashes on
     97     * a per-guest-process level.
     98     */
    8699
    87100    int rc = RTCritSectInit(&pProcess->CritSect);
     
    89102        return rc;
    90103
    91     pProcess->uPID     = 0;          /* Don't have a PID yet. */
    92     pProcess->pRequest = NULL;       /* No request assigned yet. */
     104    pProcess->hPollSet = NIL_RTPOLLSET;
     105    pProcess->hPipeStdInW = NIL_RTPIPE;
     106    pProcess->hPipeStdOutR = NIL_RTPIPE;
     107    pProcess->hPipeStdErrR = NIL_RTPIPE;
     108    pProcess->hNotificationPipeW = NIL_RTPIPE;
     109    pProcess->hNotificationPipeR = NIL_RTPIPE;
     110
     111    rc = RTReqQueueCreate(&pProcess->hReqQueue);
     112    AssertReleaseRC(rc);
    93113
    94114    /* Copy over startup info. */
     
    107127
    108128/**
    109  * Frees a guest process.
     129 * Frees a guest process. On success, pProcess will be
     130 * free'd and thus won't be available anymore.
    110131 *
    111132 * @return  IPRT status code.
     
    116137    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    117138
    118     VBoxServiceVerbose(3, "[PID %RU32]: Freeing ...\n",
    119                        pProcess->uPID);
    120 
     139    VBoxServiceVerbose(3, "[PID %RU32]: Freeing (cRefs=%RU32)...\n",
     140                       pProcess->uPID, pProcess->cRefs);
     141    Assert(pProcess->cRefs == 0);
    121142
    122143    /*
     
    126147        RTCritSectDelete(&pProcess->CritSect);
    127148
     149    int rc = RTReqQueueDestroy(pProcess->hReqQueue);
     150    AssertRC(rc);
     151
     152    /*
     153     * Remove from list.
     154     */
     155    AssertPtr(pProcess->pSession);
     156    rc = GstCntlSessionProcessRemove(pProcess->pSession, pProcess);
     157    AssertRC(rc);
     158
    128159    /*
    129160     * Destroy thread structure as final step.
     
    151182
    152183    /* Do *not* set pThread->fShutdown or other stuff here!
    153      * The guest thread loop will do that as soon as it processes the quit message. */
    154 
    155     PVBOXSERVICECTRLREQUEST pRequest;
    156     int rc = GstCntlProcessRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_PROC_TERM);
    157     if (RT_SUCCESS(rc))
    158     {
    159         rc = GstCntlProcessPerform(pProcess, pRequest,
    160                                    true /* Async */);
    161         if (RT_FAILURE(rc))
    162             VBoxServiceVerbose(3, "[PID %RU32]: Sending termination request failed with rc=%Rrc\n",
    163                                pProcess->uPID, rc);
    164         /* Deletion of pRequest will be done on request completion (asynchronous). */
    165     }
    166 
    167     return rc;
     184     * The guest thread loop will clean up itself. */
     185
     186    return GstCntlProcessHandleTerm(pProcess);
    168187}
    169188
    170189
    171190/**
    172  * Releases a previously acquired guest process (decreses the refcount).
     191 * Releases a previously acquired guest process (decreases the refcount).
    173192 *
    174193 * @param   pProcess            Process to unlock.
    175194 */
    176 void GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pProcess)
     195void GstCntlProcessRelease(PVBOXSERVICECTRLPROCESS pProcess)
    177196{
    178197    AssertPtrReturnVoid(pProcess);
     198
     199    bool fShutdown = false;
    179200
    180201    int rc = RTCritSectEnter(&pProcess->CritSect);
     
    183204        Assert(pProcess->cRefs);
    184205        pProcess->cRefs--;
     206        fShutdown = pProcess->fStopped; /* Has the process' thread been stopped? */
     207
    185208        rc = RTCritSectLeave(&pProcess->CritSect);
    186209        AssertRC(rc);
    187210    }
     211
     212    if (fShutdown)
     213        GstCntlProcessFree(pProcess);
    188214}
    189215
     
    191217/**
    192218 * Wait for a guest process thread to shut down.
    193  * Note: Caller is responsible for locking!
    194219 *
    195220 * @return  IPRT status code.
     
    204229    /* pRc is optional. */
    205230
    206     AssertMsgReturn(ASMAtomicReadBool(&pProcess->fStarted),
    207                     ("Tried to wait on guest process=%p which has not been started yet\n",
    208                      pProcess), VERR_INVALID_PARAMETER);
    209 
    210     /* Guest process already has been stopped, no need to wait. */
    211     if (ASMAtomicReadBool(&pProcess->fStopped))
    212         return VINF_SUCCESS;
    213 
    214     VBoxServiceVerbose(2, "[PID %RU32]: Waiting for shutdown (%RU32ms) ...\n",
    215                        pProcess->uPID, msTimeout);
    216 
    217     /* Wait a bit ... */
    218     int rcThread;
    219     Assert(pProcess->Thread != NIL_RTTHREAD);
    220     int rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread);
    221     if (RT_FAILURE(rc))
    222     {
    223         VBoxServiceError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n",
    224                          pProcess->uPID, rc);
    225     }
    226     else
    227     {
    228         VBoxServiceVerbose(3, "[PID %RU32]: Thread reported exit code=%Rrc\n",
    229                            pProcess->uPID, rcThread);
    230         if (pRc)
    231             *pRc = rcThread;
    232     }
    233 
     231    int rc = gstcntlProcessLock(pProcess);
     232    if (RT_SUCCESS(rc))
     233    {
     234        VBoxServiceVerbose(2, "[PID %RU32]: Waiting for shutdown (%RU32ms) ...\n",
     235                           pProcess->uPID, msTimeout);
     236
     237        AssertMsgReturn(pProcess->fStarted,
     238                        ("Tried to wait on guest process=%p (PID %RU32) which has not been started yet\n",
     239                         pProcess, pProcess->uPID), VERR_INVALID_PARAMETER);
     240
     241        /* Guest process already has been stopped, no need to wait. */
     242        if (!pProcess->fStopped)
     243        {
     244            /* Unlock process before waiting. */
     245            rc = gstcntlProcessUnlock(pProcess);
     246            AssertRC(rc);
     247
     248            /* Do the actual waiting. */
     249            int rcThread;
     250            Assert(pProcess->Thread != NIL_RTTHREAD);
     251            rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread);
     252            if (RT_FAILURE(rc))
     253            {
     254                VBoxServiceError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n",
     255                                 pProcess->uPID, rc);
     256            }
     257            else
     258            {
     259                VBoxServiceVerbose(3, "[PID %RU32]: Thread shutdown complete, thread rc=%Rrc\n",
     260                                   pProcess->uPID, rcThread);
     261                if (pRc)
     262                    *pRc = rcThread;
     263            }
     264        }
     265        else
     266        {
     267            VBoxServiceVerbose(3, "[PID %RU32]: Thread already shut down, no waiting needed\n",
     268                               pProcess->uPID);
     269
     270            int rc2 = gstcntlProcessUnlock(pProcess);
     271            AssertRC(rc2);
     272        }
     273    }
     274
     275    VBoxServiceVerbose(3, "[PID %RU32]: Waiting resulted in rc=%Rrc\n",
     276                       pProcess->uPID, rc);
    234277    return rc;
    235278}
     
    243286 * @param   phStdInW            The standard input pipe handle.
    244287 */
    245 static int gstcntlProcessCloseStdIn(RTPOLLSET hPollSet, PRTPIPE phStdInW)
    246 {
     288static int gstcntlProcessPollsetCloseInput(PVBOXSERVICECTRLPROCESS pProcess,
     289                                           PRTPIPE phStdInW)
     290{
     291    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    247292    AssertPtrReturn(phStdInW, VERR_INVALID_POINTER);
    248293
    249     int rc = RTPollSetRemove(hPollSet, VBOXSERVICECTRLPIPEID_STDIN);
     294    int rc = RTPollSetRemove(pProcess->hPollSet, VBOXSERVICECTRLPIPEID_STDIN);
    250295    if (rc != VERR_POLL_HANDLE_ID_NOT_FOUND)
    251296        AssertRC(rc);
     
    290335 *
    291336 * @return  IPRT status code.
    292  * @param   hPollSet            The polling set.
     337 * @param   pProcess            Process to handle pollset for.
    293338 * @param   fPollEvt            The event mask returned by RTPollNoResume.
    294339 * @param   phStdInW            The standard input pipe handle.
    295340 */
    296 static int gstcntlProcessHandleStdInErrorEvent(RTPOLLSET hPollSet, uint32_t fPollEvt, PRTPIPE phStdInW)
    297 {
     341static int gstcntlProcessPollsetOnInput(PVBOXSERVICECTRLPROCESS pProcess,
     342                                        uint32_t fPollEvt, PRTPIPE phStdInW)
     343{
     344    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     345
    298346    NOREF(fPollEvt);
    299347
    300     return gstcntlProcessCloseStdIn(hPollSet, phStdInW);
     348    return gstcntlProcessPollsetCloseInput(pProcess, phStdInW);
    301349}
    302350
     
    306354 *
    307355 * @returns IPRT status code from client send.
    308  * @param   hPollSet            The polling set.
     356 * @param   pProcess            Process to handle pollset for.
    309357 * @param   fPollEvt            The event mask returned by RTPollNoResume.
    310358 * @param   phPipeR             The pipe handle.
     
    312360 *
    313361 */
    314 static int gstcntlProcessHandleOutputError(RTPOLLSET hPollSet, uint32_t fPollEvt,
    315                                            PRTPIPE phPipeR, uint32_t idPollHnd)
    316 {
    317     AssertPtrReturn(phPipeR, VERR_INVALID_POINTER);
     362static int gstcntlProcessHandleOutputError(PVBOXSERVICECTRLPROCESS pProcess,
     363                                           uint32_t fPollEvt, PRTPIPE phPipeR, uint32_t idPollHnd)
     364{
     365    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     366
     367    if (!phPipeR)
     368        return VINF_SUCCESS;
    318369
    319370#ifdef DEBUG
    320     VBoxServiceVerbose(4, "gstcntlProcessHandleOutputError: fPollEvt=0x%x, idPollHnd=%s\n",
    321                        fPollEvt, gstcntlProcessPollHandleToString(idPollHnd));
     371    VBoxServiceVerbose(4, "[PID %RU32]: Output error: idPollHnd=%s, fPollEvt=0x%x\n",
     372                       pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd), fPollEvt);
    322373#endif
    323374
    324375    /* Remove pipe from poll set. */
    325     int rc2 = RTPollSetRemove(hPollSet, idPollHnd);
     376    int rc2 = RTPollSetRemove(pProcess->hPollSet, idPollHnd);
    326377    AssertMsg(RT_SUCCESS(rc2) || rc2 == VERR_POLL_HANDLE_ID_NOT_FOUND, ("%Rrc\n", rc2));
    327378
     
    329380
    330381    /* Check if there's remaining data to read from the pipe. */
    331     size_t cbReadable;
    332     rc2 = RTPipeQueryReadable(*phPipeR, &cbReadable);
    333     if (   RT_SUCCESS(rc2)
    334         && cbReadable)
    335     {
    336         VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%s has %zu bytes left, vetoing close\n",
    337                            gstcntlProcessPollHandleToString(idPollHnd), cbReadable);
    338 
    339         /* Veto closing the pipe yet because there's still stuff to read
    340          * from the pipe. This can happen on UNIX-y systems where on
    341          * error/hangup there still can be data to be read out. */
    342         fClosePipe = false;
    343     }
     382    if (*phPipeR != NIL_RTPIPE)
     383    {
     384        size_t cbReadable;
     385        rc2 = RTPipeQueryReadable(*phPipeR, &cbReadable);
     386        if (   RT_SUCCESS(rc2)
     387            && cbReadable)
     388        {
     389#ifdef DEBUG
     390            VBoxServiceVerbose(3, "[PID %RU32]: idPollHnd=%s has %zu bytes left, vetoing close\n",
     391                               pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd), cbReadable);
     392#endif
     393            /* Veto closing the pipe yet because there's still stuff to read
     394             * from the pipe. This can happen on UNIX-y systems where on
     395             * error/hangup there still can be data to be read out. */
     396            fClosePipe = false;
     397        }
     398    }
     399#ifdef DEBUG
    344400    else
    345         VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%s will be closed\n",
    346                            gstcntlProcessPollHandleToString(idPollHnd));
     401        VBoxServiceVerbose(3, "[PID %RU32]: idPollHnd=%s will be closed\n",
     402                           pProcess->uPID, gstcntlProcessPollHandleToString(idPollHnd));
     403#endif
    347404
    348405    if (   *phPipeR != NIL_RTPIPE
     
    362419 *
    363420 * @returns IPRT status code from client send.
    364  * @param   hPollSet            The polling set.
     421 * @param   pProcess            Process to handle pollset for.
    365422 * @param   fPollEvt            The event mask returned by RTPollNoResume.
    366423 * @param   phPipeR             The pipe handle.
     
    368425 *
    369426 */
    370 static int gstcntlProcessHandleOutputEvent(RTPOLLSET hPollSet, uint32_t fPollEvt,
    371                                            PRTPIPE phPipeR, uint32_t idPollHnd)
    372 {
    373 #ifdef DEBUG_andy
    374     VBoxServiceVerbose(4, "GstCntlProcessHandleOutputEvent: fPollEvt=0x%x, idPollHnd=%s\n",
    375                        fPollEvt, gstcntlProcessPollHandleToString(idPollHnd));
    376 #endif
     427static int gstcntlProcessPollsetOnOutput(PVBOXSERVICECTRLPROCESS pProcess,
     428                                         uint32_t fPollEvt, PRTPIPE phPipeR, uint32_t idPollHnd)
     429{
     430    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     431
     432#ifdef DEBUG
     433    VBoxServiceVerbose(4, "[PID %RU32]: Output event phPipeR=%p, idPollHnd=%s, fPollEvt=0x%x\n",
     434                       pProcess->uPID, phPipeR, gstcntlProcessPollHandleToString(idPollHnd), fPollEvt);
     435#endif
     436
     437    if (!phPipeR)
     438        return VINF_SUCCESS;
    377439
    378440    int rc = VINF_SUCCESS;
    379441
    380442#ifdef DEBUG
    381     size_t cbReadable;
    382     rc = RTPipeQueryReadable(*phPipeR, &cbReadable);
    383     if (   RT_SUCCESS(rc)
    384         && cbReadable)
    385     {
    386         VBoxServiceVerbose(4, "gstcntlProcessHandleOutputEvent: cbReadable=%ld\n",
    387                            cbReadable);
     443    if (*phPipeR != NIL_RTPIPE)
     444    {
     445        size_t cbReadable;
     446        rc = RTPipeQueryReadable(*phPipeR, &cbReadable);
     447        if (   RT_SUCCESS(rc)
     448            && cbReadable)
     449        {
     450            VBoxServiceVerbose(4, "[PID %RU32]: Output event cbReadable=%zu\n",
     451                               pProcess->uPID, cbReadable);
     452        }
    388453    }
    389454#endif
    390455
    391456#if 0
    392     //if (fPollEvt & RTPOLL_EVT_READ)
     457    /* Push output to the host. */
     458    if (fPollEvt & RTPOLL_EVT_READ)
    393459    {
    394460        size_t cbRead = 0;
     
    406472
    407473    if (fPollEvt & RTPOLL_EVT_ERROR)
    408         rc = gstcntlProcessHandleOutputError(hPollSet, fPollEvt,
    409                                              phPipeR, idPollHnd);
    410     return rc;
    411 }
    412 
    413 
    414 /**
    415  * Completes the given request. After returning pRequest won't be valid
    416  * anymore!
    417  *
    418  * @return  IPRT status code.
    419  * @param   pRequest                Pointer to request to signal.
    420  * @param   rc                      rc to set request result to.
    421  */
    422 static int gstcntlProcessRequestComplete(PVBOXSERVICECTRLREQUEST pRequest, int rc)
    423 {
    424     AssertPtrReturn(pRequest, VERR_INVALID_POINTER);
    425 
    426     int rc2;
    427     if (!pRequest->fAsync)
    428     {
    429         /* Assign overall result. */
    430         pRequest->rc = rc;
    431 
    432 #ifdef DEBUG_andy
    433         VBoxServiceVerbose(4, "Handled req=%RU32, CID=%RU32, rc=%Rrc, cbData=%RU32, pvData=%p\n",
    434                            pRequest->enmType, pRequest->uCID, pRequest->rc,
    435                            pRequest->cbData, pRequest->pvData);
    436 #endif
    437         /* Signal waiters. */
    438         rc2 = RTSemEventMultiSignal(pRequest->Event);
    439         AssertRC(rc2);
    440 
    441         pRequest = NULL;
    442     }
    443     else
    444     {
    445 #ifdef DEBUG_andy
    446         VBoxServiceVerbose(4, "Deleting async req=%RU32, CID=%RU32, rc=%Rrc, cbData=%RU32, pvData=%p\n",
    447                            pRequest->enmType, pRequest->uCID, pRequest->rc,
    448                            pRequest->cbData, pRequest->pvData);
    449 #endif
    450         GstCntlProcessRequestFree(pRequest);
    451         rc2 = VINF_SUCCESS;
    452     }
    453 
    454     return rc2;
    455 }
    456 
    457 
    458 static int gstcntlProcessRequestHandle(PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest,
    459                                        RTPOLLSET hPollSet, uint32_t fPollEvt,
    460                                        PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR)
    461 {
    462     AssertPtrReturn(phStdInW, VERR_INVALID_POINTER);
    463     AssertPtrReturn(phStdOutR, VERR_INVALID_POINTER);
    464     AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER);
    465     AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    466     AssertPtrReturn(pRequest, VERR_INVALID_POINTER);
    467 
    468     VBoxServiceVerbose(4, "[PID %RU32]: Handling pRequest=%p\n",
    469                        pProcess->uPID, pRequest);
    470 
    471     /* Drain the notification pipe. */
    472     uint8_t abBuf[8];
    473     size_t cbIgnore;
    474     int rc = RTPipeRead(pProcess->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore);
    475     if (RT_FAILURE(rc))
    476         VBoxServiceError("Draining IPC notification pipe failed with rc=%Rrc\n", rc);
    477 
    478     bool fDefer = false; /* Whether the request completion should be deferred or not. */
    479     int rcReq = VINF_SUCCESS; /* Actual request result. */
    480 
    481     switch (pRequest->enmType)
    482     {
    483         case VBOXSERVICECTRLREQUEST_PROC_STDIN:
    484         case VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF:
    485         {
    486             size_t cbWritten = 0;
    487             if (pRequest->cbData)
    488             {
    489                 AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER);
    490                 if (*phStdInW != NIL_RTPIPE)
    491                 {
    492                     rcReq = RTPipeWrite(*phStdInW,
    493                                         pRequest->pvData, pRequest->cbData, &cbWritten);
    494                 }
    495                 else
    496                     rcReq = VINF_EOF;
    497             }
    498 
    499             /*
    500              * If this is the last write + we have really have written all data
    501              * we need to close the stdin pipe on our end and remove it from
    502              * the poll set.
    503              */
    504             if (   pRequest->enmType == VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF
    505                 && pRequest->cbData  == cbWritten)
    506             {
    507                 rc = gstcntlProcessCloseStdIn(hPollSet, phStdInW);
    508             }
    509 
    510             /* Report back actual data written (if any). */
    511             pRequest->cbData = cbWritten;
    512             break;
    513         }
    514 
    515         case VBOXSERVICECTRLREQUEST_PROC_STDOUT:
    516         case VBOXSERVICECTRLREQUEST_PROC_STDERR:
    517         {
    518             AssertPtrReturn(pRequest->pvData, VERR_INVALID_POINTER);
    519             AssertReturn(pRequest->cbData, VERR_INVALID_PARAMETER);
    520 
    521             PRTPIPE pPipeR = pRequest->enmType == VBOXSERVICECTRLREQUEST_PROC_STDERR
    522                            ? phStdErrR : phStdOutR;
    523             AssertPtr(pPipeR);
    524 
    525             size_t cbRead = 0;
    526             if (*pPipeR != NIL_RTPIPE)
    527             {
    528                 rcReq = RTPipeRead(*pPipeR,
    529                                    pRequest->pvData, pRequest->cbData, &cbRead);
    530                 if (RT_FAILURE(rcReq))
    531                 {
    532                     RTPollSetRemove(hPollSet, pRequest->enmType == VBOXSERVICECTRLREQUEST_PROC_STDERR
    533                                               ? VBOXSERVICECTRLPIPEID_STDERR : VBOXSERVICECTRLPIPEID_STDOUT);
    534                     RTPipeClose(*pPipeR);
    535                     *pPipeR = NIL_RTPIPE;
    536                     if (rcReq == VERR_BROKEN_PIPE)
    537                         rcReq = VINF_EOF;
    538                 }
    539             }
    540             else
    541                 rcReq = VINF_EOF;
    542 
    543             /* Report back actual data read (if any). */
    544             pRequest->cbData = cbRead;
    545             break;
    546         }
    547 
    548         case VBOXSERVICECTRLREQUEST_PROC_TERM:
    549             pProcess->fShutdown = true;
    550             fDefer = true;
    551             break;
    552 
    553         default:
    554             rcReq = VERR_NOT_IMPLEMENTED;
    555             break;
    556     }
    557 
    558     if (   RT_FAILURE(rc)
    559         || !fDefer)
    560     {
    561         rc = gstcntlProcessRequestComplete(pRequest,
    562                                            RT_SUCCESS(rc) ? rcReq : rc);
    563     }
    564     else /* Completing the request defered. */
    565         rc = VINF_AIO_TASK_PENDING; /** @todo Find an own rc! */
    566 
     474        rc = gstcntlProcessHandleOutputError(pProcess,
     475                                             fPollEvt, phPipeR, idPollHnd);
    567476    return rc;
    568477}
     
    575484 * @return  IPRT status code.
    576485 * @param   pProcess                    The guest process to handle.
    577  * @param   hProcess                    The actual process handle.
    578  * @param   cMsTimeout                  Time limit (in ms) of the process' life time.
    579  * @param   hPollSet                    The poll set to use.
    580  * @param   hStdInW                     Handle to the process' stdin write end.
    581  * @param   hStdOutR                    Handle to the process' stdout read end.
    582  * @param   hStdErrR                    Handle to the process' stderr read end.
    583  */
    584 static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS pProcess,
    585                                   RTPROCESS hProcess, RTPOLLSET hPollSet,
    586                                   PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR)
     486 */
     487static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS pProcess)
    587488{
    588489    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    589     AssertPtrReturn(phStdInW, VERR_INVALID_PARAMETER);
    590     /* Rest is optional. */
    591490
    592491    int                         rc;
     
    597496    bool                        fProcessTimedOut    = false;
    598497    uint64_t                    MsProcessKilled     = UINT64_MAX;
    599     RTMSINTERVAL const          cMsPollBase         = *phStdInW != NIL_RTPIPE
     498    RTMSINTERVAL const          cMsPollBase         = pProcess->hPipeStdInW != NIL_RTPIPE
    600499                                                      ? 100   /* Need to poll for input. */
    601500                                                      : 1000; /* Need only poll for process exit and aborts. */
     
    607506     * the first (stale) entry will be found and we get really weird results!
    608507     */
    609     rc = gstcntlProcessAssignPID(pProcess, hProcess);
     508    rc = gstcntlProcessAssignPID(pProcess, pProcess->hProcess /* Opaque PID handle */);
    610509    if (RT_FAILURE(rc))
    611510    {
    612511        VBoxServiceError("Unable to assign PID=%u, to new thread, rc=%Rrc\n",
    613                          hProcess, rc);
     512                         pProcess->hProcess, rc);
    614513        return rc;
    615514    }
     
    638537        uint32_t idPollHnd;
    639538        uint32_t fPollEvt;
    640         rc2 = RTPollNoResume(hPollSet, cMsPollCur, &fPollEvt, &idPollHnd);
     539        rc2 = RTPollNoResume(pProcess->hPollSet, cMsPollCur, &fPollEvt, &idPollHnd);
    641540        if (pProcess->fShutdown)
    642541            continue;
     
    649548            {
    650549                case VBOXSERVICECTRLPIPEID_STDIN:
    651                     rc = gstcntlProcessHandleStdInErrorEvent(hPollSet, fPollEvt, phStdInW);
     550                    rc = gstcntlProcessPollsetOnInput(pProcess, fPollEvt,
     551                                                      &pProcess->hPipeStdInW);
    652552                    break;
    653553
    654554                case VBOXSERVICECTRLPIPEID_STDOUT:
    655                     rc = gstcntlProcessHandleOutputEvent(hPollSet, fPollEvt,
    656                                                          phStdOutR, idPollHnd);
     555                    rc = gstcntlProcessPollsetOnOutput(pProcess, fPollEvt,
     556                                                       &pProcess->hPipeStdOutR, idPollHnd);
    657557                    break;
    658558
    659559                case VBOXSERVICECTRLPIPEID_STDERR:
    660                     rc = gstcntlProcessHandleOutputEvent(hPollSet, fPollEvt,
    661                                                          phStdErrR, idPollHnd);
     560                    rc = gstcntlProcessPollsetOnOutput(pProcess, fPollEvt,
     561                                                       &pProcess->hPipeStdOutR, idPollHnd);
    662562                    break;
    663563
     
    666566                    VBoxServiceVerbose(4, "[PID %RU32]: IPC notify\n", pProcess->uPID);
    667567#endif
    668                     rc = gstcntlProcessLock(pProcess);
    669                     if (RT_SUCCESS(rc))
     568                    rc2 = gstcntlProcessLock(pProcess);
     569                    if (RT_SUCCESS(rc2))
    670570                    {
    671                         /** @todo Implement request queue. */
    672                         rc = gstcntlProcessRequestHandle(pProcess, pProcess->pRequest,
    673                                                          hPollSet, fPollEvt,
    674                                                          phStdInW, phStdOutR, phStdErrR);
    675                         if (rc != VINF_AIO_TASK_PENDING)
    676                         {
    677                             pProcess->pRequest = NULL;
    678                         }
    679                         else
    680                             VBoxServiceVerbose(4, "[PID %RU32]: pRequest=%p will be handled deferred\n",
    681                                                pProcess->uPID, pProcess->pRequest);
    682 
    683                         rc2 = gstcntlProcessUnlock(pProcess);
    684                         AssertRC(rc2);
     571                        /* Drain the notification pipe. */
     572                        uint8_t abBuf[8];
     573                        size_t cbIgnore;
     574                        rc2 = RTPipeRead(pProcess->hNotificationPipeR,
     575                                         abBuf, sizeof(abBuf), &cbIgnore);
     576                        if (RT_FAILURE(rc2))
     577                            VBoxServiceError("Draining IPC notification pipe failed with rc=%Rrc\n", rc2);
     578#ifdef DEBUG
     579                        VBoxServiceVerbose(4, "[PID %RU32]: Processing pending requests ...\n",
     580                                           pProcess->uPID);
     581#endif
     582                        /* Process all pending requests. */
     583                        Assert(pProcess->hReqQueue != NIL_RTREQQUEUE);
     584                        rc2 = RTReqQueueProcess(pProcess->hReqQueue,
     585                                                0 /* Only process all pending requests, don't wait for new ones */);
     586                        if (   RT_FAILURE(rc2)
     587                            && rc2 != VERR_TIMEOUT)
     588                            VBoxServiceError("Processing requests failed with with rc=%Rrc\n", rc2);
     589
     590                        int rc3 = gstcntlProcessUnlock(pProcess);
     591                        AssertRC(rc3);
     592#ifdef DEBUG
     593                        VBoxServiceVerbose(4, "[PID %RU32]: Processing pending requests done, rc=%Rrc\n",
     594                                           pProcess->uPID, rc2);
     595#endif
    685596                    }
     597
    686598                    break;
    687599
     
    694606                break; /* Abort command, or client dead or something. */
    695607        }
    696 #ifdef DEBUG_andy
     608#if 0
    697609        VBoxServiceVerbose(4, "[PID %RU32]: Polling done, pollRc=%Rrc, pollCnt=%RU32, idPollHnd=%s, rc=%Rrc, fProcessAlive=%RTbool, fShutdown=%RTbool\n",
    698610                           pProcess->uPID, rc2, RTPollSetGetCount(hPollSet), gstcntlProcessPollHandleToString(idPollHnd), rc, fProcessAlive, pProcess->fShutdown);
     
    710622        if (fProcessAlive)
    711623        {
    712             rc2 = RTProcWaitNoResume(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
    713 #ifdef DEBUG_andy
     624            rc2 = RTProcWaitNoResume(pProcess->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
     625#if 0
    714626            VBoxServiceVerbose(4, "[PID %RU32]: RTProcWaitNoResume=%Rrc\n",
    715627                               pProcess->uPID, rc2);
     
    744656        {
    745657            if (   fProcessTimedOut
    746                 || (   *phStdOutR == NIL_RTPIPE
    747                     && *phStdErrR == NIL_RTPIPE)
     658                || (   pProcess->hPipeStdOutR == NIL_RTPIPE
     659                    && pProcess->hPipeStdErrR == NIL_RTPIPE)
    748660               )
    749661            {
     
    763675            if (cMsElapsed >= pProcess->StartupInfo.uTimeLimitMS)
    764676            {
    765                 VBoxServiceVerbose(3, "[PID %RU32]: Timed out (%RU64ms elapsed > %RU64ms timeout), killing ...\n",
    766                                    pProcess->uPID, cMsElapsed, pProcess->StartupInfo.uTimeLimitMS);
    767 
    768677                fProcessTimedOut = true;
    769678                if (    MsProcessKilled == UINT64_MAX
     
    772681                    if (u64Now - MsProcessKilled > 20*60*1000)
    773682                        break; /* Give up after 20 mins. */
    774                     rc2 = RTProcTerminate(hProcess);
     683
     684                    VBoxServiceVerbose(3, "[PID %RU32]: Timed out (%RU64ms elapsed > %RU32ms timeout), killing ...\n",
     685                                       pProcess->uPID, cMsElapsed, pProcess->StartupInfo.uTimeLimitMS);
     686
     687                    rc2 = RTProcTerminate(pProcess->hProcess);
    775688                    VBoxServiceVerbose(3, "[PID %RU32]: Killing process resulted in rc=%Rrc\n",
    776689                                       pProcess->uPID, rc2);
     
    792705    }
    793706
    794     VBoxServiceVerbose(3, "[PID %RU32]: Loop ended: fShutdown=%RTbool, fProcessAlive=%RTbool, fProcessTimedOut=%RTbool, MsProcessKilled=%RU64\n",
    795                        pProcess->uPID, pProcess->fShutdown, fProcessAlive, fProcessTimedOut, MsProcessKilled, MsProcessKilled);
     707    VBoxServiceVerbose(3, "[PID %RU32]: Loop ended: rc=%Rrc, fShutdown=%RTbool, fProcessAlive=%RTbool, fProcessTimedOut=%RTbool, MsProcessKilled=%RU64\n",
     708                       pProcess->uPID, rc, pProcess->fShutdown, fProcessAlive, fProcessTimedOut, MsProcessKilled, MsProcessKilled);
    796709    VBoxServiceVerbose(3, "[PID %RU32]: *phStdOutR=%s, *phStdErrR=%s\n",
    797                        pProcess->uPID, *phStdOutR == NIL_RTPIPE ? "closed" : "open", *phStdErrR == NIL_RTPIPE ? "closed" : "open");
     710                       pProcess->uPID,
     711                       pProcess->hPipeStdOutR == NIL_RTPIPE ? "closed" : "open",
     712                       pProcess->hPipeStdErrR == NIL_RTPIPE ? "closed" : "open");
    798713
    799714    /* Signal that this thread is in progress of shutting down. */
     
    801716
    802717    /*
    803      * Try kill the process if it's still alive at this point.
     718     * Try killing the process if it's still alive at this point.
    804719     */
    805720    if (fProcessAlive)
     
    811726
    812727            MsProcessKilled = RTTimeMilliTS();
    813             rc2 = RTProcTerminate(hProcess);
    814             if (RT_FAILURE(rc))
     728            rc2 = RTProcTerminate(pProcess->hProcess);
     729            if (rc2 == VERR_NOT_FOUND)
     730            {
     731                fProcessAlive = false;
     732            }
     733            else if (RT_FAILURE(rc2))
    815734                VBoxServiceError("PID %RU32]: Killing process failed with rc=%Rrc\n",
    816                                  pProcess->uPID, rc);
     735                                 pProcess->uPID, rc2);
    817736            RTThreadSleep(500);
    818737        }
    819738
    820         for (size_t i = 0; i < 10; i++)
     739        for (int i = 0; i < 10 && fProcessAlive; i++)
    821740        {
    822741            VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Waiting to exit ...\n",
    823742                               pProcess->uPID, i + 1);
    824             rc2 = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
     743            rc2 = RTProcWait(pProcess->hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
    825744            if (RT_SUCCESS(rc2))
    826745            {
     
    834753                VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Trying to terminate ...\n",
    835754                                   pProcess->uPID, i + 1);
    836                 rc2 = RTProcTerminate(hProcess);
    837                 if (RT_FAILURE(rc))
     755                rc2 = RTProcTerminate(pProcess->hProcess);
     756                if (   RT_FAILURE(rc)
     757                    && rc2 != VERR_NOT_FOUND)
    838758                    VBoxServiceError("PID %RU32]: Killing process failed with rc=%Rrc\n",
    839                                      pProcess->uPID, rc);
     759                                     pProcess->uPID, rc2);
    840760            }
    841761            RTThreadSleep(i >= 5 ? 2000 : 500);
     
    846766    }
    847767
     768    /*
     769     * Shutdown procedure:
     770     * - Set the pProcess->fShutdown indicator to let others know we're
     771     *   not accepting any new requests anymore.
     772     * - After setting the indicator, try to process all outstanding
     773     *   requests to make sure they're getting delivered.
     774     *
     775     * Note: After removing the process from the session's list it's not
     776     *       even possible for the session anymore to control what's
     777     *       happening to this thread, so be careful and don't mess it up.
     778     */
     779
    848780    rc2 = gstcntlProcessLock(pProcess);
    849781    if (RT_SUCCESS(rc2))
    850782    {
    851         if (pProcess->pRequest)
    852         {
    853             switch (pProcess->pRequest->enmType)
    854             {
    855                 /* Handle deferred termination request. */
    856                 case VBOXSERVICECTRLREQUEST_PROC_TERM:
    857                     rc2 = gstcntlProcessRequestComplete(pProcess->pRequest,
    858                                                         fProcessAlive ? VINF_SUCCESS : VERR_PROCESS_RUNNING);
    859                     AssertRC(rc2);
    860                     break;
    861 
    862                 /* Cancel all others.
    863                  ** @todo Clear request queue as soon as it's implemented. */
    864                 default:
    865                     rc2 = gstcntlProcessRequestCancel(pProcess->pRequest);
    866                     AssertRC(rc2);
    867                     break;
    868             }
    869 
    870             pProcess->pRequest = NULL;
    871         }
    872 #ifdef DEBUG
    873         else
    874             VBoxServiceVerbose(3, "[PID %RU32]: No pending request found\n", pProcess->uPID);
    875 #endif
     783        VBoxServiceVerbose(3, "[PID %RU32]: Processing outstanding requests ...\n",
     784                           pProcess->uPID);
     785
     786        /* Process all pending requests (but don't wait for new ones). */
     787        Assert(pProcess->hReqQueue != NIL_RTREQQUEUE);
     788        rc2 = RTReqQueueProcess(pProcess->hReqQueue, 0 /* No timeout */);
     789        if (   RT_FAILURE(rc2)
     790            && rc2 != VERR_TIMEOUT)
     791            VBoxServiceError("[PID %RU32]: Processing outstanding requests failed with with rc=%Rrc\n",
     792                             pProcess->uPID, rc2);
     793
     794        VBoxServiceVerbose(3, "[PID %RU32]: Processing outstanding requests done, rc=%Rrc\n",
     795                           pProcess->uPID, rc2);
     796
    876797        rc2 = gstcntlProcessUnlock(pProcess);
    877798        AssertRC(rc2);
     
    918839        else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL)
    919840        {
    920             VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %u)\n",
     841            VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %d)\n",
    921842                               pProcess->uPID, ProcessStatus.iStatus);
    922843
     
    948869                           pProcess->uPID, pProcess->uClientID, pProcess->uContextID, uStatus, uFlags);
    949870
    950             VBGLR3GUESTCTRLCMDCTX ctxEnd = { pProcess->uClientID, pProcess->uContextID };
    951             rc2 = VbglR3GuestCtrlProcCbStatus(&ctxEnd,
    952                                               pProcess->uPID, uStatus, uFlags,
    953                                               NULL /* pvData */, 0 /* cbData */);
    954             if (   RT_FAILURE(rc2)
    955                 && rc2 == VERR_NOT_FOUND)
    956                 VBoxServiceError("[PID %RU32]: Error reporting final status to host; rc=%Rrc\n",
    957                                  pProcess->uPID, rc2);
     871        VBGLR3GUESTCTRLCMDCTX ctxEnd = { pProcess->uClientID, pProcess->uContextID };
     872        rc2 = VbglR3GuestCtrlProcCbStatus(&ctxEnd,
     873                                          pProcess->uPID, uStatus, uFlags,
     874                                          NULL /* pvData */, 0 /* cbData */);
     875        if (   RT_FAILURE(rc2)
     876            && rc2 == VERR_NOT_FOUND)
     877            VBoxServiceError("[PID %RU32]: Error reporting final status to host; rc=%Rrc\n",
     878                             pProcess->uPID, rc2);
    958879    }
    959880
     
    981902
    982903    return VINF_SUCCESS;
    983 }
    984 
    985 
    986 /**
    987  * Allocates a guest thread request with the specified request data.
    988  *
    989  * @return  IPRT status code.
    990  * @param   ppReq                   Pointer that will receive the newly allocated request.
    991  *                                  Must be freed later with GstCntlProcessRequestFree().
    992  * @param   enmType                 Request type.
    993  * @param   pvData                  Payload data, based on request type.
    994  * @param   cbData                  Size of payload data (in bytes).
    995  * @param   uCID                    Context ID to which this request belongs to.
    996  */
    997 int GstCntlProcessRequestAllocEx(PVBOXSERVICECTRLREQUEST   *ppReq,
    998                                  VBOXSERVICECTRLREQUESTTYPE enmType,
    999                                  void                      *pvData,
    1000                                  size_t                     cbData,
    1001                                  uint32_t                   uCID)
    1002 {
    1003     AssertPtrReturn(ppReq, VERR_INVALID_POINTER);
    1004 
    1005     PVBOXSERVICECTRLREQUEST pReq =
    1006         (PVBOXSERVICECTRLREQUEST)RTMemAlloc(sizeof(VBOXSERVICECTRLREQUEST));
    1007     AssertPtrReturn(pReq, VERR_NO_MEMORY);
    1008 
    1009     RT_ZERO(*pReq);
    1010     pReq->fAsync  = false;
    1011     pReq->enmType = enmType;
    1012     pReq->uCID    = uCID;
    1013     pReq->cbData  = cbData;
    1014     pReq->pvData  = pvData;
    1015 
    1016     /* Set request result to some defined state in case
    1017      * it got cancelled. */
    1018     pReq->rc      = VERR_CANCELLED;
    1019 
    1020     int rc = RTSemEventMultiCreate(&pReq->Event);
    1021     AssertRC(rc);
    1022 
    1023     if (RT_SUCCESS(rc))
    1024     {
    1025         *ppReq = pReq;
    1026         return VINF_SUCCESS;
    1027     }
    1028 
    1029     RTMemFree(pReq);
    1030     return rc;
    1031 }
    1032 
    1033 
    1034 /**
    1035  * Allocates a guest thread request with the specified request data.
    1036  *
    1037  * @return  IPRT status code.
    1038  * @param   ppReq                   Pointer that will receive the newly allocated request.
    1039  *                                  Must be freed later with GstCntlProcessRequestFree().
    1040  * @param   enmType                 Request type.
    1041  */
    1042 int GstCntlProcessRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq,
    1043                                VBOXSERVICECTRLREQUESTTYPE enmType)
    1044 {
    1045     return GstCntlProcessRequestAllocEx(ppReq, enmType,
    1046                                         NULL /* pvData */, 0 /* cbData */,
    1047                                         0 /* ContextID */);
    1048 }
    1049 
    1050 
    1051 /**
    1052  * Cancels a previously fired off guest process request.
    1053  * Note: Caller is responsible for locking!
    1054  *
    1055  * @return  IPRT status code.
    1056  * @param   pReq                    Request to cancel.
    1057  */
    1058 static int gstcntlProcessRequestCancel(PVBOXSERVICECTRLREQUEST pReq)
    1059 {
    1060     if (!pReq) /* Silently skip non-initialized requests. */
    1061         return VINF_SUCCESS;
    1062 
    1063     VBoxServiceVerbose(4, "Cancelling outstanding request=0x%p\n", pReq);
    1064 
    1065     return RTSemEventMultiSignal(pReq->Event);
    1066 }
    1067 
    1068 
    1069 /**
    1070  * Frees a formerly allocated guest thread request.
    1071  *
    1072  * @return  IPRT status code.
    1073  * @param   pReq                    Request to free.
    1074  */
    1075 void GstCntlProcessRequestFree(PVBOXSERVICECTRLREQUEST pReq)
    1076 {
    1077     AssertPtrReturnVoid(pReq);
    1078 
    1079     VBoxServiceVerbose(4, "Freeing request=0x%p (event=%RTsem)\n",
    1080                        pReq, &pReq->Event);
    1081 
    1082     int rc = RTSemEventMultiDestroy(pReq->Event);
    1083     AssertRC(rc);
    1084 
    1085     RTMemFree(pReq);
    1086     pReq = NULL;
    1087 }
    1088 
    1089 
    1090 /**
    1091  * Waits for a guest thread's event to get triggered.
    1092  *
    1093  * @return  IPRT status code.
    1094  * @param   pReq                    Request to wait for.
    1095  */
    1096 int GstCntlProcessRequestWait(PVBOXSERVICECTRLREQUEST pReq)
    1097 {
    1098     AssertPtrReturn(pReq, VERR_INVALID_POINTER);
    1099 
    1100     /* Wait on the request to get completed (or we are asked to abort/shutdown). */
    1101     int rc = RTSemEventMultiWait(pReq->Event, RT_INDEFINITE_WAIT);
    1102     if (RT_SUCCESS(rc))
    1103     {
    1104         VBoxServiceVerbose(4, "Performed request with rc=%Rrc, cbData=%RU32\n",
    1105                            pReq->rc, pReq->cbData);
    1106 
    1107         /* Give back overall request result. */
    1108         rc = pReq->rc;
    1109     }
    1110     else
    1111         VBoxServiceError("Waiting for request failed, rc=%Rrc\n", rc);
    1112 
    1113     return rc;
    1114904}
    1115905
     
    13801170        {
    13811171            fTryAgain = false;
    1382             RTListForEach(&pProcess->pSession->lstProcessesActive, pProcessCur, VBOXSERVICECTRLPROCESS, Node)
     1172            RTListForEach(&pProcess->pSession->lstProcesses, pProcessCur, VBOXSERVICECTRLPROCESS, Node)
    13831173            {
    13841174                if (pProcessCur->uPID == uPID)
     
    16041394                       pProcess, pProcess->StartupInfo.szCmd);
    16051395
    1606     int rc = GstCntlSessionListSet(pProcess->pSession,
    1607                                    pProcess, VBOXSERVICECTRLTHREADLIST_RUNNING);
    1608     AssertRC(rc);
    1609 
    1610     rc = VbglR3GuestCtrlConnect(&pProcess->uClientID);
     1396    int rc = VbglR3GuestCtrlConnect(&pProcess->uClientID);
    16111397    if (RT_FAILURE(rc))
    16121398    {
    1613         VBoxServiceError("Thread failed to connect to the guest control service, aborted! Error: %Rrc\n", rc);
     1399        VBoxServiceError("Process thread \"%s\" (%p) failed to connect to the guest control service, rc=%Rrc\n",
     1400                         pProcess->StartupInfo.szCmd, pProcess, rc);
    16141401        RTThreadUserSignal(RTThreadSelf());
    16151402        return rc;
    16161403    }
     1404
     1405    rc = GstCntlSessionProcessAdd(pProcess->pSession, pProcess);
     1406    if (RT_FAILURE(rc))
     1407    {
     1408        VBoxServiceError("Errorwhile adding guest process \"%s\" (%p) to session process list, rc=%Rrc\n",
     1409                         pProcess->StartupInfo.szCmd, pProcess, rc);
     1410        RTThreadUserSignal(RTThreadSelf());
     1411        return rc;
     1412    }
     1413
    16171414    VBoxServiceVerbose(3, "Guest process \"%s\" got client ID=%u, flags=0x%x\n",
    16181415                       pProcess->StartupInfo.szCmd, pProcess->uClientID, pProcess->StartupInfo.uFlags);
     
    16921489            PRTHANDLE   phStdIn;
    16931490            rc = gstcntlProcessSetupPipe("|", 0 /*STDIN_FILENO*/,
    1694                                          &hStdIn, &phStdIn, &pProcess->pipeStdInW);
     1491                                         &hStdIn, &phStdIn, &pProcess->hPipeStdInW);
    16951492            if (RT_SUCCESS(rc))
    16961493            {
    16971494                RTHANDLE    hStdOut;
    16981495                PRTHANDLE   phStdOut;
    1699                 RTPIPE      pipeStdOutR;
    17001496                rc = gstcntlProcessSetupPipe(  (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)
    17011497                                             ? "|" : "/dev/null",
    17021498                                             1 /*STDOUT_FILENO*/,
    1703                                              &hStdOut, &phStdOut, &pipeStdOutR);
     1499                                             &hStdOut, &phStdOut, &pProcess->hPipeStdOutR);
    17041500                if (RT_SUCCESS(rc))
    17051501                {
    17061502                    RTHANDLE    hStdErr;
    17071503                    PRTHANDLE   phStdErr;
    1708                     RTPIPE      pipeStdErrR;
    17091504                    rc = gstcntlProcessSetupPipe(  (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)
    17101505                                                 ? "|" : "/dev/null",
    17111506                                                 2 /*STDERR_FILENO*/,
    1712                                                  &hStdErr, &phStdErr, &pipeStdErrR);
     1507                                                 &hStdErr, &phStdErr, &pProcess->hPipeStdErrR);
    17131508                    if (RT_SUCCESS(rc))
    17141509                    {
     
    17171512                         * transport layer add stuff to it as well.
    17181513                         */
    1719                         RTPOLLSET hPollSet;
    1720                         rc = RTPollSetCreate(&hPollSet);
     1514                        rc = RTPollSetCreate(&pProcess->hPollSet);
    17211515                        if (RT_SUCCESS(rc))
    17221516                        {
     
    17281522                            /* Stdin. */
    17291523                            if (RT_SUCCESS(rc))
    1730                                 rc = RTPollSetAddPipe(hPollSet, pProcess->pipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN);
     1524                                rc = RTPollSetAddPipe(pProcess->hPollSet,
     1525                                                      pProcess->hPipeStdInW, RTPOLL_EVT_ERROR, VBOXSERVICECTRLPIPEID_STDIN);
    17311526                            /* Stdout. */
    17321527                            if (RT_SUCCESS(rc))
    1733                                 rc = RTPollSetAddPipe(hPollSet, pipeStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT);
     1528                                rc = RTPollSetAddPipe(pProcess->hPollSet,
     1529                                                      pProcess->hPipeStdOutR, uFlags, VBOXSERVICECTRLPIPEID_STDOUT);
    17341530                            /* Stderr. */
    17351531                            if (RT_SUCCESS(rc))
    1736                                 rc = RTPollSetAddPipe(hPollSet, pipeStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR);
     1532                                rc = RTPollSetAddPipe(pProcess->hPollSet,
     1533                                                      pProcess->hPipeStdErrR, uFlags, VBOXSERVICECTRLPIPEID_STDERR);
    17371534                            /* IPC notification pipe. */
    17381535                            if (RT_SUCCESS(rc))
    17391536                                rc = RTPipeCreate(&pProcess->hNotificationPipeR, &pProcess->hNotificationPipeW, 0 /* Flags */);
    17401537                            if (RT_SUCCESS(rc))
    1741                                 rc = RTPollSetAddPipe(hPollSet, pProcess->hNotificationPipeR, RTPOLL_EVT_READ, VBOXSERVICECTRLPIPEID_IPC_NOTIFY);
    1742 
     1538                                rc = RTPollSetAddPipe(pProcess->hPollSet,
     1539                                                      pProcess->hNotificationPipeR, RTPOLL_EVT_READ, VBOXSERVICECTRLPIPEID_IPC_NOTIFY);
    17431540                            if (RT_SUCCESS(rc))
    17441541                            {
     
    17461543                                bool fNeedsImpersonation = !(pProcess->pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_FORK);
    17471544
    1748                                 RTPROCESS hProcess;
    17491545                                rc = gstcntlProcessCreateProcess(pProcess->StartupInfo.szCmd, papszArgs, hEnv, pProcess->StartupInfo.uFlags,
    17501546                                                                 phStdIn, phStdOut, phStdErr,
    17511547                                                                 fNeedsImpersonation ? pProcess->StartupInfo.szUser : NULL,
    17521548                                                                 fNeedsImpersonation ? pProcess->StartupInfo.szPassword : NULL,
    1753                                                                  &hProcess);
     1549                                                                 &pProcess->hProcess);
    17541550                                if (RT_FAILURE(rc))
    17551551                                    VBoxServiceError("Error starting process, rc=%Rrc\n", rc);
     
    17771573                                    phStdErr   = NULL;
    17781574
    1779                                     /* Enter the process loop. */
    1780                                     rc = gstcntlProcessProcLoop(pProcess, hProcess, hPollSet,
    1781                                                                 &pProcess->pipeStdInW, &pipeStdOutR, &pipeStdErrR);
     1575                                    /* Enter the process main loop. */
     1576                                    rc = gstcntlProcessProcLoop(pProcess);
    17821577
    17831578                                    /*
     
    17871582                                     * So, NIL the handles to avoid closing them again.
    17881583                                     */
    1789                                     if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_IPC_NOTIFY, NULL)))
     1584                                    if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
     1585                                                                        VBOXSERVICECTRLPIPEID_IPC_NOTIFY, NULL)))
    17901586                                    {
    17911587                                        pProcess->hNotificationPipeR = NIL_RTPIPE;
    17921588                                        pProcess->hNotificationPipeW = NIL_RTPIPE;
    17931589                                    }
    1794                                     if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDERR, NULL)))
    1795                                         pipeStdErrR = NIL_RTPIPE;
    1796                                     if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDOUT, NULL)))
    1797                                         pipeStdOutR = NIL_RTPIPE;
    1798                                     if (RT_FAILURE(RTPollSetQueryHandle(hPollSet, VBOXSERVICECTRLPIPEID_STDIN, NULL)))
    1799                                         pProcess->pipeStdInW = NIL_RTPIPE;
     1590                                    if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
     1591                                                                        VBOXSERVICECTRLPIPEID_STDERR, NULL)))
     1592                                        pProcess->hPipeStdErrR = NIL_RTPIPE;
     1593                                    if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
     1594                                                                        VBOXSERVICECTRLPIPEID_STDOUT, NULL)))
     1595                                        pProcess->hPipeStdOutR = NIL_RTPIPE;
     1596                                    if (RT_FAILURE(RTPollSetQueryHandle(pProcess->hPollSet,
     1597                                                                        VBOXSERVICECTRLPIPEID_STDIN, NULL)))
     1598                                        pProcess->hPipeStdInW = NIL_RTPIPE;
    18001599                                }
    18011600                            }
    1802                             RTPollSetDestroy(hPollSet);
     1601                            RTPollSetDestroy(pProcess->hPollSet);
    18031602
    18041603                            RTPipeClose(pProcess->hNotificationPipeR);
     
    18071606                            pProcess->hNotificationPipeW = NIL_RTPIPE;
    18081607                        }
    1809                         RTPipeClose(pipeStdErrR);
    1810                         pipeStdErrR = NIL_RTPIPE;
     1608                        RTPipeClose(pProcess->hPipeStdErrR);
     1609                        pProcess->hPipeStdErrR = NIL_RTPIPE;
    18111610                        RTHandleClose(phStdErr);
    18121611                        if (phStdErr)
    18131612                            RTHandleClose(phStdErr);
    18141613                    }
    1815                     RTPipeClose(pipeStdOutR);
    1816                     pipeStdOutR = NIL_RTPIPE;
     1614                    RTPipeClose(pProcess->hPipeStdOutR);
     1615                    pProcess->hPipeStdOutR = NIL_RTPIPE;
    18171616                    RTHandleClose(&hStdOut);
    18181617                    if (phStdOut)
    18191618                        RTHandleClose(phStdOut);
    18201619                }
    1821                 RTPipeClose(pProcess->pipeStdInW);
    1822                 pProcess->pipeStdInW = NIL_RTPIPE;
     1620                RTPipeClose(pProcess->hPipeStdInW);
     1621                pProcess->hPipeStdInW = NIL_RTPIPE;
    18231622                RTHandleClose(phStdIn);
    18241623            }
     
    18261625        RTEnvDestroy(hEnv);
    18271626    }
    1828 
    1829     /* Move thread to stopped thread list. */
    1830     /*int rc2 = GstCntlSessionListSet(pProcess->pSession,
    1831                                     pProcess, VBOXSERVICECTRLTHREADLIST_STOPPED);
    1832     AssertRC(rc2);*/
    18331627
    18341628    if (pProcess->uClientID)
     
    18401634                                                  pProcess->uPID, PROC_STS_ERROR, rc,
    18411635                                                  NULL /* pvData */, 0 /* cbData */);
    1842             if (RT_FAILURE(rc2))
    1843                 VBoxServiceError("Could not report process failure error; rc=%Rrc (process error %Rrc)\n",
    1844                                  rc2, rc);
     1636            if (   RT_FAILURE(rc2)
     1637                && rc2 != VERR_NOT_FOUND)
     1638                VBoxServiceError("[PID %RU32]: Could not report process failure error; rc=%Rrc (process error %Rrc)\n",
     1639                                 pProcess->uPID, rc2, rc);
    18451640        }
    18461641
     
    18631658        RTGetOptArgvFree(papszArgs);
    18641659
    1865     /* Update stopped status. */
    1866     ASMAtomicXchgBool(&pProcess->fStopped, true);
    1867 
    18681660    /*
    18691661     * If something went wrong signal the user event so that others don't wait
     
    18751667    VBoxServiceVerbose(3, "[PID %RU32]: Thread of process \"%s\" ended with rc=%Rrc\n",
    18761668                       pProcess->uPID, pProcess->StartupInfo.szCmd, rc);
     1669
     1670    /* Finally, update stopped status. */
     1671    ASMAtomicXchgBool(&pProcess->fStopped, true);
     1672
    18771673    return rc;
    18781674}
     
    19481744        if (RT_FAILURE(rc))
    19491745        {
    1950             VBoxServiceError("Creating thread for guest process failed: rc=%Rrc, pProcess=%p\n",
    1951                              rc, pProcess);
     1746            VBoxServiceError("Creating thread for guest process \"%s\" failed: rc=%Rrc, pProcess=%p\n",
     1747                             pStartupInfo->szCmd, rc, pProcess);
     1748
     1749            GstCntlProcessFree(pProcess);
    19521750        }
    19531751        else
     
    19631761                VBoxServiceError("Thread for process \"%s\" failed to start, rc=%Rrc\n",
    19641762                                 pStartupInfo->szCmd, rc);
     1763
     1764                GstCntlProcessFree(pProcess);
    19651765            }
    19661766            else
     
    19711771    }
    19721772
    1973     if (RT_FAILURE(rc))
    1974         GstCntlProcessFree(pProcess);
    1975 
    19761773    return rc;
    19771774}
    19781775
    19791776
    1980 /**
    1981  * Performs a request to a specific (formerly started) guest process and waits
    1982  * for its response.
    1983  * Note: Caller is responsible for locking!
    1984  *
    1985  * @return  IPRT status code.
    1986  * @param   pProcess            Guest process to perform operation on.
    1987  * @param   pRequest            Pointer to request  to perform.
    1988  */
    1989 int GstCntlProcessPerform(PVBOXSERVICECTRLPROCESS pProcess,
    1990                           PVBOXSERVICECTRLREQUEST pRequest,
    1991                           bool                    fAsync)
     1777static DECLCALLBACK(int) gstcntlProcessOnInput(PVBOXSERVICECTRLPROCESS pThis,
     1778                                               const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
     1779                                               bool fPendingClose, void *pvBuf, uint32_t cbBuf)
     1780{
     1781    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     1782    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     1783
     1784    int rc;
     1785
     1786    size_t cbWritten = 0;
     1787    if (pvBuf && cbBuf)
     1788    {
     1789        if (pThis->hPipeStdInW != NIL_RTPIPE)
     1790        {
     1791            rc = RTPipeWrite(pThis->hPipeStdInW,
     1792                             pvBuf, cbBuf, &cbWritten);
     1793        }
     1794        else
     1795            rc = VINF_EOF;
     1796    }
     1797    else
     1798        rc = VERR_INVALID_PARAMETER;
     1799
     1800    /*
     1801     * If this is the last write + we have really have written all data
     1802     * we need to close the stdin pipe on our end and remove it from
     1803     * the poll set.
     1804     */
     1805    if (   fPendingClose
     1806        && (cbBuf == cbWritten))
     1807    {
     1808        int rc2 = gstcntlProcessPollsetCloseInput(pThis, &pThis->hPipeStdInW);
     1809        if (RT_SUCCESS(rc))
     1810            rc = rc2;
     1811    }
     1812
     1813    uint32_t uStatus = INPUT_STS_UNDEFINED; /* Status to send back to the host. */
     1814    uint32_t uFlags = 0; /* No flags at the moment. */
     1815    if (RT_SUCCESS(rc))
     1816    {
     1817        VBoxServiceVerbose(4, "[PID %RU32]: Written %RU32 bytes input, CID=%RU32, fPendingClose=%RTbool\n",
     1818                           pThis->uPID, cbWritten, pHostCtx->uContextID, fPendingClose);
     1819        uStatus = INPUT_STS_WRITTEN;
     1820    }
     1821    else
     1822    {
     1823        if (rc == VERR_BAD_PIPE)
     1824            uStatus = INPUT_STS_TERMINATED;
     1825        else if (rc == VERR_BUFFER_OVERFLOW)
     1826            uStatus = INPUT_STS_OVERFLOW;
     1827        /* else undefined */
     1828    }
     1829
     1830    /*
     1831     * If there was an error and we did not set the host status
     1832     * yet, then do it now.
     1833     */
     1834    if (   RT_FAILURE(rc)
     1835        && uStatus == INPUT_STS_UNDEFINED)
     1836    {
     1837        uStatus = INPUT_STS_ERROR;
     1838        uFlags = rc;
     1839    }
     1840    Assert(uStatus > INPUT_STS_UNDEFINED);
     1841
     1842#ifdef DEBUG
     1843
     1844#endif
     1845    int rc2 = VbglR3GuestCtrlProcCbStatusInput(pHostCtx, pThis->uPID,
     1846                                               uStatus, uFlags, (uint32_t)cbWritten);
     1847    if (RT_SUCCESS(rc))
     1848        rc = rc2;
     1849
     1850#ifdef DEBUG
     1851    VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessOnInput returned with rc=%Rrc\n",
     1852                       pThis->uPID, rc);
     1853#endif
     1854    return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */
     1855}
     1856
     1857
     1858static DECLCALLBACK(int) gstcntlProcessOnOutput(PVBOXSERVICECTRLPROCESS pThis,
     1859                                                const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
     1860                                                uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags)
     1861{
     1862    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     1863    AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
     1864
     1865    const PVBOXSERVICECTRLSESSION pSession = pThis->pSession;
     1866    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     1867
     1868    int rc;
     1869
     1870    uint32_t cbBuf = cbToRead;
     1871    uint8_t *pvBuf = (uint8_t *)RTMemAlloc(cbBuf);
     1872    if (pvBuf)
     1873    {
     1874        PRTPIPE phPipe =   uHandle == OUTPUT_HANDLE_ID_STDOUT
     1875                         ? &pThis->hPipeStdOutR
     1876                         : &pThis->hPipeStdErrR;
     1877        AssertPtr(phPipe);
     1878
     1879        size_t cbRead = 0;
     1880        if (*phPipe != NIL_RTPIPE)
     1881        {
     1882            rc = RTPipeRead(*phPipe, pvBuf, cbBuf, &cbRead);
     1883            if (RT_FAILURE(rc))
     1884            {
     1885                RTPollSetRemove(pThis->hPollSet,   uHandle == OUTPUT_HANDLE_ID_STDERR
     1886                                                 ? VBOXSERVICECTRLPIPEID_STDERR : VBOXSERVICECTRLPIPEID_STDOUT);
     1887                RTPipeClose(*phPipe);
     1888                *phPipe = NIL_RTPIPE;
     1889                if (rc == VERR_BROKEN_PIPE)
     1890                    rc = VINF_EOF;
     1891            }
     1892        }
     1893        else
     1894            rc = VINF_EOF;
     1895
     1896#if 0
     1897        if (RT_SUCCESS(rc))
     1898        {
     1899            if (   (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT)
     1900                && (uHandle == OUTPUT_HANDLE_ID_STDERR))
     1901            {
     1902                char szDumpFile[RTPATH_MAX];
     1903                if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdOut.txt",
     1904                                 pSession->StartupInfo.uSessionID, pThis->uPID)) rc = VERR_BUFFER_UNDERFLOW;
     1905                if (RT_SUCCESS(rc))
     1906                    rc = gstcntlSessionDumpToFile(szDumpFile, pvBuf, cbRead);
     1907                AssertRC(rc);
     1908            }
     1909            else if (   (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR)
     1910                     && (   uHandle == OUTPUT_HANDLE_ID_STDOUT
     1911                         || uHandle == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED))
     1912            {
     1913                char szDumpFile[RTPATH_MAX];
     1914                if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdErr.txt",
     1915                                 pSession->StartupInfo.uSessionID, pThis->uPID))
     1916                    rc = VERR_BUFFER_UNDERFLOW;
     1917                if (RT_SUCCESS(rc))
     1918                    rc = gstcntlSessionDumpToFile(szDumpFile, pvBuf, cbRead);
     1919                AssertRC(rc);
     1920            }
     1921        }
     1922#endif
     1923
     1924        if (RT_SUCCESS(rc))
     1925        {
     1926#ifdef DEBUG
     1927            VBoxServiceVerbose(3, "[PID %RU32]: Read %RU32 bytes output: uHandle=%RU32, CID=%RU32, uFlags=%x\n",
     1928                               pThis->uPID, cbRead, uHandle, pHostCtx->uContextID, uFlags);
     1929#endif
     1930            /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary
     1931             *        data which the host needs to work with -- so just pass through all data unfiltered! */
     1932
     1933            /* Note: Since the context ID is unique the request *has* to be completed here,
     1934             *       regardless whether we got data or not! Otherwise the waiting events
     1935             *       on the host never will get completed! */
     1936            rc = VbglR3GuestCtrlProcCbOutput(pHostCtx, pThis->uPID, uHandle, uFlags,
     1937                                             pvBuf, cbRead);
     1938            if (   RT_FAILURE(rc)
     1939                && rc == VERR_NOT_FOUND) /* Not critical if guest PID is not found on the host (anymore). */
     1940                rc = VINF_SUCCESS;
     1941        }
     1942
     1943        RTMemFree(pvBuf);
     1944    }
     1945    else
     1946        rc = VERR_NO_MEMORY;
     1947
     1948#ifdef DEBUG
     1949    VBoxServiceVerbose(3, "[PID %RU32]: Reading output returned with rc=%Rrc\n",
     1950                       pThis->uPID, rc);
     1951#endif
     1952    return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */
     1953}
     1954
     1955
     1956static DECLCALLBACK(int) gstcntlProcessOnTerm(PVBOXSERVICECTRLPROCESS pThis)
     1957{
     1958    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     1959
     1960    if (!ASMAtomicXchgBool(&pThis->fShutdown, true))
     1961    {
     1962        VBoxServiceVerbose(3, "[PID %RU32]: Setting shutdown flag ...\n",
     1963                           pThis->uPID);
     1964    }
     1965
     1966    return VINF_SUCCESS; /** @todo Return rc here as soon as RTReqQueue todos are fixed. */
     1967}
     1968
     1969
     1970int gstcntlProcessRequestExV(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
     1971                             bool fAsync, RTMSINTERVAL uTimeoutMS, PRTREQ pReq, PFNRT pfnFunction,
     1972                             unsigned cArgs, va_list Args)
    19921973{
    19931974    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    1994     AssertPtrReturn(pRequest, VERR_INVALID_POINTER);
    1995     AssertReturn(pRequest->enmType > VBOXSERVICECTRLREQUEST_UNKNOWN, VERR_INVALID_PARAMETER);
    1996     /* Rest in pRequest is optional (based on the request type). */
    1997 
    1998     int rc = VINF_SUCCESS;
    1999 
    2000     if (   ASMAtomicReadBool(&pProcess->fShutdown)
    2001         || ASMAtomicReadBool(&pProcess->fStopped))
    2002     {
    2003         rc = VERR_CANCELLED;
    2004     }
    2005     else
    2006     {
    2007         rc = gstcntlProcessLock(pProcess);
     1975    /* pHostCtx is optional. */
     1976    AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
     1977    if (!fAsync)
     1978        AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
     1979
     1980    int rc = gstcntlProcessLock(pProcess);
     1981    if (RT_SUCCESS(rc))
     1982    {
     1983#ifdef DEBUG
     1984    VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessRequestExV fAsync=%RTbool, uTimeoutMS=%RU32, cArgs=%u\n",
     1985                       pProcess->uPID, fAsync, uTimeoutMS, cArgs);
     1986#endif
     1987        uint32_t uFlags = RTREQFLAGS_IPRT_STATUS;
     1988        if (fAsync)
     1989        {
     1990            Assert(uTimeoutMS == 0);
     1991            uFlags |= RTREQFLAGS_NO_WAIT;
     1992        }
     1993
     1994        rc = RTReqQueueCallV(pProcess->hReqQueue, &pReq, uTimeoutMS, uFlags,
     1995                             pfnFunction, cArgs, Args);
    20081996        if (RT_SUCCESS(rc))
    20091997        {
    2010             AssertMsgReturn(pProcess->pRequest == NULL,
    2011                             ("Another request still is in progress (%p)\n", pProcess->pRequest),
    2012                             VERR_ALREADY_EXISTS);
    2013 
    2014             VBoxServiceVerbose(3, "[PID %RU32]: Sending pRequest=%p\n",
    2015                                pProcess->uPID, pRequest);
    2016 
    2017             /* Set request structure pointer. */
    2018             pProcess->pRequest = pRequest;
    2019 
    2020             /** @todo To speed up simultaneous guest process handling we could add a worker threads
    2021              *        or queue in order to wait for the request to happen. Later. */
    2022             /* Wake up guest thread by sending a wakeup byte to the notification pipe so
    2023              * that RTPoll unblocks (returns) and we then can do our requested operation. */
     1998            /* Wake up the process' notification pipe to get
     1999             * the request being processed. */
    20242000            Assert(pProcess->hNotificationPipeW != NIL_RTPIPE);
    20252001            size_t cbWritten = 0;
    2026             if (RT_SUCCESS(rc))
    2027                 rc = RTPipeWrite(pProcess->hNotificationPipeW, "i", 1, &cbWritten);
    2028 
    2029             int rcWait = VINF_SUCCESS;
    2030             if (RT_SUCCESS(rc))
    2031             {
    2032                 Assert(cbWritten);
    2033                 if (!fAsync)
    2034                 {
    2035                     VBoxServiceVerbose(3, "[PID %RU32]: Waiting for response on pRequest=%p, enmType=%u, pvData=0x%p, cbData=%u\n",
    2036                                        pProcess->uPID, pRequest, pRequest->enmType, pRequest->pvData, pRequest->cbData);
    2037 
    2038                     rc = gstcntlProcessUnlock(pProcess);
    2039                     if (RT_SUCCESS(rc))
    2040                         rcWait = GstCntlProcessRequestWait(pRequest);
    2041 
    2042                     /* NULL current request in any case. */
    2043                     pProcess->pRequest = NULL;
    2044                 }
    2045             }
    2046 
    2047             if (   RT_FAILURE(rc)
    2048                 || fAsync)
    2049             {
    2050                 int rc2 = gstcntlProcessUnlock(pProcess);
    2051                 AssertRC(rc2);
    2052             }
    2053 
    2054             if (RT_SUCCESS(rc))
    2055                 rc = rcWait;
    2056         }
    2057     }
    2058 
    2059     VBoxServiceVerbose(3, "[PID %RU32]: Performed pRequest=%p, enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n",
    2060                        pProcess->uPID, pRequest, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc);
     2002            rc = RTPipeWrite(pProcess->hNotificationPipeW, "i", 1, &cbWritten);
     2003            if (   RT_SUCCESS(rc)
     2004                && cbWritten != 1)
     2005            {
     2006                VBoxServiceError("[PID %RU32]: Notification pipe got %zu bytes instead of 1\n",
     2007                                 pProcess->uPID, cbWritten);
     2008            }
     2009            else if (RT_UNLIKELY(RT_FAILURE(rc)))
     2010                VBoxServiceError("[PID %RU32]: Writing to notification pipe failed, rc=%Rrc\n",
     2011                                 pProcess->uPID, rc);
     2012        }
     2013        else
     2014            VBoxServiceError("[PID %RU32]: RTReqQueueCallV failed, rc=%Rrc\n",
     2015                             pProcess->uPID, rc);
     2016
     2017        int rc2 = gstcntlProcessUnlock(pProcess);
     2018        if (RT_SUCCESS(rc))
     2019            rc = rc2;
     2020    }
     2021
     2022#ifdef DEBUG
     2023    VBoxServiceVerbose(3, "[PID %RU32]: gstcntlProcessRequestExV returned rc=%Rrc\n",
     2024                       pProcess->uPID, rc);
     2025#endif
    20612026    return rc;
    20622027}
    20632028
     2029
     2030int gstcntlProcessRequestAsync(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
     2031                               PFNRT pfnFunction, unsigned cArgs, ...)
     2032{
     2033    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     2034    /* pHostCtx is optional. */
     2035    AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
     2036
     2037    va_list va;
     2038    va_start(va, cArgs);
     2039    int rc = gstcntlProcessRequestExV(pProcess, pHostCtx, true /* fAsync */, 0 /* uTimeoutMS */,
     2040                                      NULL /* pReq */, pfnFunction, cArgs, va);
     2041    va_end(va);
     2042
     2043    return rc;
     2044}
     2045
     2046
     2047int gstcntlProcessRequestWait(PVBOXSERVICECTRLPROCESS pProcess, const PVBGLR3GUESTCTRLCMDCTX pHostCtx,
     2048                              RTMSINTERVAL uTimeoutMS, PRTREQ pReq, PFNRT pfnFunction, unsigned cArgs, ...)
     2049{
     2050    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     2051    /* pHostCtx is optional. */
     2052    AssertPtrReturn(pfnFunction, VERR_INVALID_POINTER);
     2053
     2054    va_list va;
     2055    va_start(va, cArgs);
     2056    int rc = gstcntlProcessRequestExV(pProcess, pHostCtx, false /* fAsync */, uTimeoutMS,
     2057                                      pReq, pfnFunction, cArgs, va);
     2058    va_end(va);
     2059
     2060    return rc;
     2061}
     2062
     2063
     2064int GstCntlProcessHandleInput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
     2065                              bool fPendingClose, void *pvBuf, uint32_t cbBuf)
     2066{
     2067    if (!ASMAtomicReadBool(&pProcess->fShutdown))
     2068        return gstcntlProcessRequestAsync(pProcess, pHostCtx, (PFNRT)gstcntlProcessOnInput,
     2069                                          5 /* cArgs */, pProcess, pHostCtx, fPendingClose, pvBuf, cbBuf);
     2070
     2071    return gstcntlProcessOnInput(pProcess, pHostCtx, fPendingClose, pvBuf, cbBuf);
     2072}
     2073
     2074
     2075int GstCntlProcessHandleOutput(PVBOXSERVICECTRLPROCESS pProcess, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
     2076                               uint32_t uHandle, uint32_t cbToRead, uint32_t uFlags)
     2077{
     2078    if (!ASMAtomicReadBool(&pProcess->fShutdown))
     2079        return gstcntlProcessRequestAsync(pProcess, pHostCtx, (PFNRT)gstcntlProcessOnOutput,
     2080                                          5 /* cArgs */, pProcess, pHostCtx, uHandle, cbToRead, uFlags);
     2081
     2082    return gstcntlProcessOnOutput(pProcess, pHostCtx, uHandle, cbToRead, uFlags);
     2083}
     2084
     2085
     2086int GstCntlProcessHandleTerm(PVBOXSERVICECTRLPROCESS pProcess)
     2087{
     2088    if (!ASMAtomicReadBool(&pProcess->fShutdown))
     2089        return gstcntlProcessRequestAsync(pProcess, NULL /* pHostCtx */, (PFNRT)gstcntlProcessOnTerm,
     2090                                          1 /* cArgs */, pProcess);
     2091
     2092    return gstcntlProcessOnTerm(pProcess);
     2093}
     2094
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp

    r47482 r47545  
    5353*******************************************************************************/
    5454static int                  gstcntlSessionFileDestroy(PVBOXSERVICECTRLFILE pFile);
    55 static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle);
    56 static int                  gstcntlSessionGetOutput(const PVBOXSERVICECTRLSESSION pSession, uint32_t uPID, uint32_t uCID, uint32_t uHandleId, uint32_t cMsTimeout, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
     55static int                  gstcntlSessionFileAdd(PVBOXSERVICECTRLSESSION pSession, PVBOXSERVICECTRLFILE pFile);
     56static PVBOXSERVICECTRLFILE gstcntlSessionFileGetLocked(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle);
     57static DECLCALLBACK(int)    gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser);
     58/* Host -> Guest handlers. */
    5759static int                  gstcntlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
    5860static int                  gstcntlSessionHandleFileClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
     
    6163static int                  gstcntlSessionHandleFileSeek(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
    6264static int                  gstcntlSessionHandleFileTell(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
    63 static int                  gstcntlSessionSetInput(const PVBOXSERVICECTRLSESSION pSession, uint32_t uPID, uint32_t uCID, bool fPendingClose, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
    64 static DECLCALLBACK(int)    gstcntlSessionThread(RTTHREAD ThreadSelf, void *pvUser);
     65extern int                  gstcntlSessionHandleProcExec(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
     66extern int                  gstcntlSessionHandleProcInput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx, void *pvScratchBuf, size_t cbScratchBuf);
     67extern int                  gstcntlSessionHandleProcOutput(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
     68extern int                  gstcntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
     69extern int                  gstcntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx);
     70/* Guest -> Host handlers. */
     71
    6572
    6673/** Generic option indices for session fork arguments. */
     
    9299
    93100
    94 static PVBOXSERVICECTRLFILE gstcntlSessionGetFile(const PVBOXSERVICECTRLSESSION pSession,
    95                                                   uint32_t uHandle)
     101static PVBOXSERVICECTRLFILE gstcntlSessionFileGetLocked(const PVBOXSERVICECTRLSESSION pSession,
     102                                                        uint32_t uHandle)
    96103{
    97104    AssertPtrReturn(pSession, NULL);
     
    196203                uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID);
    197204                pFile->uHandle = uHandle;
     205
    198206                /* rc = */ RTListAppend(&pSession->lstFiles, &pFile->Node);
    199207
     
    232240    if (RT_SUCCESS(rc))
    233241    {
    234         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
     242        PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
    235243        if (pFile)
    236244        {
     
    247255            rc = rc2;
    248256    }
     257
    249258    return rc;
    250259}
     
    267276        size_t cbRead = 0;
    268277
    269         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
     278        PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
    270279        if (pFile)
    271280        {
     
    320329        size_t cbRead = 0;
    321330
    322         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
     331        PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
    323332        if (pFile)
    324333        {
     
    374383    {
    375384        size_t cbWritten = 0;
    376         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
     385        PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
    377386        if (pFile)
    378387        {
     
    411420    {
    412421        size_t cbWritten = 0;
    413         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
     422        PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
    414423        if (pFile)
    415424        {
     
    447456    if (RT_SUCCESS(rc))
    448457    {
    449         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
     458        PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
    450459        if (pFile)
    451460        {
     
    500509    if (RT_SUCCESS(rc))
    501510    {
    502         PVBOXSERVICECTRLFILE pFile = gstcntlSessionGetFile(pSession, uHandle);
     511        PVBOXSERVICECTRLFILE pFile = gstcntlSessionFileGetLocked(pSession, uHandle);
    503512        if (pFile)
    504513        {
     
    526535 * @param   pHostCtx        Host context.
    527536 */
    528 int GstCntlSessionHandleProcExec(PVBOXSERVICECTRLSESSION pSession,
     537int gstcntlSessionHandleProcExec(PVBOXSERVICECTRLSESSION pSession,
    529538                                 PVBGLR3GUESTCTRLCMDCTX pHostCtx)
    530539{
     
    575584                               startupInfo.uTimeLimitMS);
    576585
    577             /*rc = GstCntlSessionReapProcesses(pSession);
    578             if (RT_FAILURE(rc))
    579                 VBoxServiceError("Reaping stopped guest processes failed with rc=%Rrc\n", rc);*/
    580             /* Keep going. */
    581 
    582586            rc = GstCntlSessionProcessStartAllowed(pSession, &fStartAllowed);
    583587            if (RT_SUCCESS(rc))
     
    622626
    623627/**
    624  * Handles input for a started process by copying the received data into its
    625  * stdin pipe.
     628 * Sends stdin input to a specific guest process.
    626629 *
    627630 * @returns IPRT status code.
    628  * @param   pvScratchBuf                The scratch buffer.
    629  * @param   cbScratchBuf                The scratch buffer size for retrieving the input data.
     631 * @param pSession            The session which is in charge.
     632 * @param pHostCtx            The host context to use.
     633 * @param pvScratchBuf        The scratch buffer.
     634 * @param cbScratchBuf        The scratch buffer size for retrieving the input data.
    630635 */
    631 int GstCntlSessionHandleProcInput(PVBOXSERVICECTRLSESSION pSession,
     636int gstcntlSessionHandleProcInput(PVBOXSERVICECTRLSESSION pSession,
    632637                                  PVBGLR3GUESTCTRLCMDCTX pHostCtx,
    633638                                  void *pvScratchBuf, size_t cbScratchBuf)
     
    652657    if (RT_FAILURE(rc))
    653658    {
    654         VBoxServiceError("[PID %RU32]: Failed to retrieve exec input command! Error: %Rrc\n",
     659        VBoxServiceError("Failed to retrieve process input command for PID=%RU32, rc=%Rrc\n",
    655660                         uPID, rc);
    656661    }
    657662    else if (cbSize > cbScratchBuf)
    658663    {
    659         VBoxServiceError("[PID %RU32]: Too much input received! cbSize=%u, cbScratchBuf=%u\n",
     664        VBoxServiceError("Too much process input received, rejecting: uPID=%RU32, cbSize=%RU32, cbScratchBuf=%RU32\n",
    660665                         uPID, cbSize, cbScratchBuf);
    661         rc = VERR_INVALID_PARAMETER;
     666        rc = VERR_TOO_MUCH_DATA;
    662667    }
    663668    else
     
    670675        {
    671676            fPendingClose = true;
    672             VBoxServiceVerbose(4, "[PID %RU32]: Got last input block of size %u ...\n",
     677#ifdef DEBUG_andy
     678            VBoxServiceVerbose(4, "Got last process input block for PID=%RU32 of size %RU32 ...\n",
    673679                               uPID, cbSize);
    674         }
    675 
    676         rc = gstcntlSessionSetInput(pSession, uPID,
    677                                     pHostCtx->uContextID, fPendingClose, pvScratchBuf,
    678                                     cbSize, &cbWritten);
    679         VBoxServiceVerbose(4, "[PID %RU32]: Written input, CID=%u, rc=%Rrc, uFlags=0x%x, fPendingClose=%d, cbSize=%u, cbWritten=%u\n",
    680                            uPID, pHostCtx->uContextID, rc, uFlags, fPendingClose, cbSize, cbWritten);
    681         if (RT_SUCCESS(rc))
    682         {
    683             uStatus = INPUT_STS_WRITTEN;
    684             uFlags = 0; /* No flags at the moment. */
     680#endif
     681        }
     682
     683        PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID);
     684        if (pProcess)
     685        {
     686            rc = GstCntlProcessHandleInput(pProcess, pHostCtx, fPendingClose,
     687                                           pvScratchBuf, cbSize);
     688            if (RT_FAILURE(rc))
     689                VBoxServiceError("Error handling input command for PID=%RU32, rc=%Rrc\n",
     690                                 uPID, rc);
     691            GstCntlProcessRelease(pProcess);
    685692        }
    686693        else
    687         {
    688             if (rc == VERR_BAD_PIPE)
    689                 uStatus = INPUT_STS_TERMINATED;
    690             else if (rc == VERR_BUFFER_OVERFLOW)
    691                 uStatus = INPUT_STS_OVERFLOW;
    692         }
    693     }
    694 
    695     /*
    696      * If there was an error and we did not set the host status
    697      * yet, then do it now.
    698      */
    699     if (   RT_FAILURE(rc)
    700         && uStatus == INPUT_STS_UNDEFINED)
    701     {
    702         uStatus = INPUT_STS_ERROR;
    703         uFlags = rc;
    704     }
    705     Assert(uStatus > INPUT_STS_UNDEFINED);
    706 
    707     VBoxServiceVerbose(3, "[PID %RU32]: Input processed, CID=%u, uStatus=%u, uFlags=0x%x, cbWritten=%u\n",
    708                        uPID, pHostCtx->uContextID, uStatus, uFlags, cbWritten);
    709 
    710     /* Note: Since the context ID is unique the request *has* to be completed here,
    711      *       regardless whether we got data or not! Otherwise the progress object
    712      *       on the host never will get completed! */
    713     rc = VbglR3GuestCtrlProcCbStatusInput(pHostCtx, uPID,
    714                                           uStatus, uFlags, (uint32_t)cbWritten);
    715 
    716     if (RT_FAILURE(rc))
    717         VBoxServiceError("[PID %RU32]: Failed to report input status! Error: %Rrc\n",
    718                          uPID, rc);
     694            rc = VERR_NOT_FOUND;
     695    }
     696
     697
     698#ifdef DEBUG_andy
     699    VBoxServiceVerbose(4, "Setting input for PID=%RU32 resulted in rc=%Rrc\n",
     700                       uPID, rc);
     701#endif
    719702    return rc;
    720703}
     
    722705
    723706/**
    724  * Handles the guest control output command.
     707 * Gets stdout/stderr output of a specific guest process.
    725708 *
    726  * @return  IPRT status code.
     709 * @return IPRT status code.
     710 * @param pSession            The session which is in charge.
     711 * @param pHostCtx            The host context to use.
    727712 */
    728 int GstCntlSessionHandleProcOutput(PVBOXSERVICECTRLSESSION pSession,
     713int gstcntlSessionHandleProcOutput(PVBOXSERVICECTRLSESSION pSession,
    729714                                   PVBGLR3GUESTCTRLCMDCTX pHostCtx)
    730715{
     
    738723    int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &uFlags);
    739724#ifdef DEBUG_andy
    740     VBoxServiceVerbose(4, "[PID %RU32]: Get output CID=%RU32, uHandleID=%RU32, uFlags=%RU32\n",
     725    VBoxServiceVerbose(4, "Getting output for PID=%RU32, CID=%RU32, uHandleID=%RU32, uFlags=%RU32\n",
    741726                       uPID, pHostCtx->uContextID, uHandleID, uFlags);
    742727#endif
    743728    if (RT_SUCCESS(rc))
    744729    {
    745         uint8_t *pBuf = (uint8_t*)RTMemAlloc(_64K);
    746         if (pBuf)
    747         {
    748             uint32_t cbRead = 0;
    749             rc = gstcntlSessionGetOutput(pSession, uPID,
    750                                          pHostCtx->uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,
    751                                          pBuf, _64K /* cbSize */, &cbRead);
    752             VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=%RU32, cbRead=%RU32, uHandle=%RU32, uFlags=%x\n",
    753                                uPID, rc, pHostCtx->uContextID, cbRead, uHandleID, uFlags);
    754 
    755 #ifdef DEBUG
    756             if (   (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDOUT)
    757                 && (uHandleID == OUTPUT_HANDLE_ID_STDERR))
    758             {
    759                 char szDumpFile[RTPATH_MAX];
    760                 if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdOut.txt",
    761                                  pSession->StartupInfo.uSessionID, uPID))
    762                     rc = VERR_BUFFER_UNDERFLOW;
    763                 if (RT_SUCCESS(rc))
    764                     rc = gstcntlSessionDumpToFile(szDumpFile, pBuf, cbRead);
    765             }
    766             else if (   (pSession->uFlags & VBOXSERVICECTRLSESSION_FLAG_DUMPSTDERR)
    767                      && (   uHandleID == OUTPUT_HANDLE_ID_STDOUT
    768                          || uHandleID == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED))
    769             {
    770                 char szDumpFile[RTPATH_MAX];
    771                 if (!RTStrPrintf(szDumpFile, sizeof(szDumpFile), "VBoxService_Session%RU32_PID%RU32_StdErr.txt",
    772                                  pSession->StartupInfo.uSessionID, uPID))
    773                     rc = VERR_BUFFER_UNDERFLOW;
    774                 if (RT_SUCCESS(rc))
    775                     rc = gstcntlSessionDumpToFile(szDumpFile, pBuf, cbRead);
    776                 AssertRC(rc);
    777             }
     730        PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID);
     731        if (pProcess)
     732        {
     733            rc = GstCntlProcessHandleOutput(pProcess, pHostCtx,
     734                                            uHandleID, _64K /* cbToRead */, uFlags);
     735            if (RT_FAILURE(rc))
     736                VBoxServiceError("Error getting output for PID=%RU32, rc=%Rrc\n",
     737                                 uPID, rc);
     738            GstCntlProcessRelease(pProcess);
     739        }
     740        else
     741            rc = VERR_NOT_FOUND;
     742    }
     743
     744#ifdef DEBUG_andy
     745    VBoxServiceVerbose(4, "Getting output for PID=%RU32 resulted in rc=%Rrc\n",
     746                       uPID, rc);
    778747#endif
    779             /** Note: Don't convert/touch/modify/whatever the output data here! This might be binary
    780              *        data which the host needs to work with -- so just pass through all data unfiltered! */
    781 
    782             /* Note: Since the context ID is unique the request *has* to be completed here,
    783              *       regardless whether we got data or not! Otherwise the progress object
    784              *       on the host never will get completed! */
    785             int rc2 = VbglR3GuestCtrlProcCbOutput(pHostCtx, uPID, uHandleID, uFlags,
    786                                                   pBuf, cbRead);
    787             if (RT_SUCCESS(rc))
    788                 rc = rc2;
    789             else if (rc == VERR_NOT_FOUND) /* It's not critical if guest process (PID) is not found. */
    790                 rc = VINF_SUCCESS;
    791 
    792             RTMemFree(pBuf);
    793         }
    794         else
    795             rc = VERR_NO_MEMORY;
    796     }
    797 
    798     if (RT_FAILURE(rc))
    799         VBoxServiceError("[PID %RU32]: Error handling output command! Error: %Rrc\n",
    800                          uPID, rc);
    801     return rc;
    802 }
    803 
    804 
    805 int GstCntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession,
     748    return rc;
     749}
     750
     751
     752/**
     753 * Tells a guest process to terminate.
     754 *
     755 * @return  IPRT status code.
     756 * @param pSession            The session which is in charge.
     757 * @param pHostCtx            The host context to use.
     758 */
     759int gstcntlSessionHandleProcTerminate(const PVBOXSERVICECTRLSESSION pSession,
    806760                                      PVBGLR3GUESTCTRLCMDCTX pHostCtx)
    807761{
     
    813767    if (RT_SUCCESS(rc))
    814768    {
    815         PVBOXSERVICECTRLREQUEST pRequest;
    816         rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_PROC_TERM,
    817                                           NULL /* pvBuf */, 0 /* cbBuf */, pHostCtx->uContextID);
    818         if (RT_SUCCESS(rc))
    819         {
    820             PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionAcquireProcess(pSession, uPID);
    821             if (pProcess)
    822             {
    823                 rc = GstCntlProcessPerform(pProcess, pRequest, false /* Async */);
    824                 GstCntlProcessRelease(pProcess);
    825             }
    826             else
    827                 rc = VERR_NOT_FOUND;
    828 
    829             GstCntlProcessRequestFree(pRequest);
    830         }
    831     }
    832 
    833     return rc;
    834 }
    835 
    836 
    837 int GstCntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession,
     769        PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID);
     770        if (pProcess)
     771        {
     772            rc = GstCntlProcessHandleTerm(pProcess);
     773
     774            GstCntlProcessRelease(pProcess);
     775        }
     776        else
     777            rc = VERR_NOT_FOUND;
     778    }
     779
     780#ifdef DEBUG_andy
     781    VBoxServiceVerbose(4, "Terminating PID=%RU32 resulted in rc=%Rrc\n",
     782                       uPID, rc);
     783#endif
     784    return rc;
     785}
     786
     787
     788int gstcntlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pSession,
    838789                                    PVBGLR3GUESTCTRLCMDCTX pHostCtx)
    839790{
     
    847798    if (RT_SUCCESS(rc))
    848799    {
    849         PVBOXSERVICECTRLREQUEST pRequest;
    850         VBOXSERVICECTRLREQDATA_WAIT_FOR reqData = { uWaitFlags, uTimeoutMS };
    851         rc = GstCntlProcessRequestAllocEx(&pRequest, VBOXSERVICECTRLREQUEST_WAIT_FOR,
    852                                           &reqData, sizeof(reqData), pHostCtx->uContextID);
    853         if (RT_SUCCESS(rc))
    854         {
    855             PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionAcquireProcess(pSession, uPID);
    856             if (pProcess)
    857             {
    858                 rc = GstCntlProcessPerform(pProcess, pRequest, false /* Async */);
    859                 GstCntlProcessRelease(pProcess);
    860             }
    861             else
    862                 rc = VERR_NOT_FOUND;
    863 
    864             GstCntlProcessRequestFree(pRequest);
    865         }
     800        PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionRetainProcess(pSession, uPID);
     801        if (pProcess)
     802        {
     803            rc = VERR_NOT_IMPLEMENTED; /** @todo */
     804            GstCntlProcessRelease(pProcess);
     805        }
     806        else
     807            rc = VERR_NOT_FOUND;
    866808    }
    867809
     
    906848
    907849        case HOST_EXEC_CMD:
    908             rc = GstCntlSessionHandleProcExec(pSession, pHostCtx);
     850            rc = gstcntlSessionHandleProcExec(pSession, pHostCtx);
    909851            break;
    910852
    911853        case HOST_EXEC_SET_INPUT:
    912             rc = GstCntlSessionHandleProcInput(pSession, pHostCtx,
     854            rc = gstcntlSessionHandleProcInput(pSession, pHostCtx,
    913855                                               pvScratchBuf, cbScratchBuf);
    914856            break;
    915857
    916858        case HOST_EXEC_GET_OUTPUT:
    917             rc = GstCntlSessionHandleProcOutput(pSession, pHostCtx);
     859            rc = gstcntlSessionHandleProcOutput(pSession, pHostCtx);
    918860            break;
    919861
    920862        case HOST_EXEC_TERMINATE:
    921             rc = GstCntlSessionHandleProcTerminate(pSession, pHostCtx);
     863            rc = gstcntlSessionHandleProcTerminate(pSession, pHostCtx);
    922864            break;
    923865
    924866        case HOST_EXEC_WAIT_FOR:
    925             rc = GstCntlSessionHandleProcWaitFor(pSession, pHostCtx);
     867            rc = gstcntlSessionHandleProcWaitFor(pSession, pHostCtx);
    926868            break;
    927869
     
    12641206 * Finds a (formerly) started guest process given by its PID and increases
    12651207 * its reference count. Must be decreased by the caller with GstCntlProcessRelease().
     1208 * Note: This does *not lock the process!
    12661209 *
    1267  * @return  PVBOXSERVICECTRLTHREAD      Locked guest process if found, otherwise NULL.
     1210 * @return  PVBOXSERVICECTRLTHREAD      Guest process if found, otherwise NULL.
    12681211 * @param   PVBOXSERVICECTRLSESSION     Pointer to guest session where to search process in.
    12691212 * @param   uPID                        PID to search for.
    12701213 */
    1271 PVBOXSERVICECTRLPROCESS GstCntlSessionAcquireProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID)
     1214PVBOXSERVICECTRLPROCESS GstCntlSessionRetainProcess(PVBOXSERVICECTRLSESSION pSession, uint32_t uPID)
    12721215{
    12731216    AssertPtrReturn(pSession, NULL);
     
    12781221    {
    12791222        PVBOXSERVICECTRLPROCESS pCurProcess;
    1280         RTListForEach(&pSession->lstProcessesActive, pCurProcess, VBOXSERVICECTRLPROCESS, Node)
     1223        RTListForEach(&pSession->lstProcesses, pCurProcess, VBOXSERVICECTRLPROCESS, Node)
    12811224        {
    12821225            if (pCurProcess->uPID == uPID)
     
    13201263
    13211264        /* Signal all guest processes in the active list that we want to shutdown. */
     1265        size_t cProcesses = 0;
    13221266        PVBOXSERVICECTRLPROCESS pProcess;
    1323         RTListForEach(&pSession->lstProcessesActive, pProcess, VBOXSERVICECTRLPROCESS, Node)
     1267        RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node)
     1268        {
    13241269            GstCntlProcessStop(pProcess);
    1325 
    1326         VBoxServiceVerbose(1, "All guest processes signalled to stop\n");
     1270            cProcesses++;
     1271        }
     1272
     1273        VBoxServiceVerbose(1, "%zu guest processes were signalled to stop\n", cProcesses);
    13271274
    13281275        /* Wait for all active threads to shutdown and destroy the active thread list. */
    1329         pProcess = RTListGetFirst(&pSession->lstProcessesActive, VBOXSERVICECTRLPROCESS, Node);
     1276        pProcess = RTListGetFirst(&pSession->lstProcesses, VBOXSERVICECTRLPROCESS, Node);
    13301277        while (pProcess)
    13311278        {
    13321279            PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node);
    1333             bool fLast = RTListNodeIsLast(&pSession->lstProcessesActive, &pProcess->Node);
    1334 
    1335             int rc2 = GstCntlProcessWait(pProcess,
    1336                                          30 * 1000 /* Wait 30 seconds max. */,
    1337                                          NULL /* rc */);
    1338             if (RT_FAILURE(rc2))
    1339             {
    1340                 VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2);
    1341                 if (RT_SUCCESS(rc))
    1342                     rc = rc2;
    1343                 /* Keep going. */
    1344             }
    1345 
    1346             RTListNodeRemove(&pProcess->Node);
    1347 
    1348             rc2 = GstCntlProcessFree(pProcess);
    1349             if (RT_FAILURE(rc2))
    1350             {
    1351                 VBoxServiceError("Guest process thread failed to free; rc=%Rrc\n", rc2);
    1352                 if (RT_SUCCESS(rc))
    1353                     rc = rc2;
    1354                 /* Keep going. */
    1355             }
     1280            bool fLast = RTListNodeIsLast(&pSession->lstProcesses, &pProcess->Node);
     1281
     1282            int rc2 = RTCritSectLeave(&pSession->CritSect);
     1283            AssertRC(rc2);
     1284
     1285            rc2 = GstCntlProcessWait(pProcess,
     1286                                     30 * 1000 /* Wait 30 seconds max. */,
     1287                                     NULL /* rc */);
     1288
     1289            int rc3 = RTCritSectEnter(&pSession->CritSect);
     1290            AssertRC(rc3);
     1291
     1292            if (RT_SUCCESS(rc2))
     1293                GstCntlProcessFree(pProcess);
    13561294
    13571295            if (fLast)
     
    13611299        }
    13621300
    1363         /*rc = GstCntlSessionReapProcesses(pSession);
    1364         if (RT_FAILURE(rc))
    1365             VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc);*/
    1366 
    1367         AssertMsg(RTListIsEmpty(&pSession->lstProcessesActive),
    1368                   ("Guest process active thread list still contains entries when it should not\n"));
    1369         /*AssertMsg(RTListIsEmpty(&pSession->lstProcessesInactive),
    1370                   ("Guest process inactive thread list still contains entries when it should not\n"));*/
     1301#ifdef DEBUG
     1302        pProcess = RTListGetFirst(&pSession->lstProcesses, VBOXSERVICECTRLPROCESS, Node);
     1303        while (pProcess)
     1304        {
     1305            PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node);
     1306            bool fLast = RTListNodeIsLast(&pSession->lstProcesses, &pProcess->Node);
     1307
     1308            VBoxServiceVerbose(1, "Process %p (PID %RU32) still in list\n",
     1309                               pProcess, pProcess->uPID);
     1310            if (fLast)
     1311                break;
     1312
     1313            pProcess = pNext;
     1314        }
     1315#endif
     1316        AssertMsg(RTListIsEmpty(&pSession->lstProcesses),
     1317                  ("Guest process list still contains entries when it should not\n"));
    13711318
    13721319        /*
     
    14231370
    14241371
    1425 /**
    1426  * Gets output from stdout/stderr of a specified guest process.
    1427  *
    1428  * @return  IPRT status code.
    1429  * @param   pSession                Guest session.
    1430  * @param   uPID                    PID of process to retrieve the output from.
    1431  * @param   uCID                    Context ID.
    1432  * @param   uHandleId               Stream ID (stdout = 0, stderr = 2) to get the output from.
    1433  * @param   cMsTimeout              Timeout (in ms) to wait for output becoming
    1434  *                                  available.
    1435  * @param   pvBuf                   Pointer to a pre-allocated buffer to store the output.
    1436  * @param   cbBuf                   Size (in bytes) of the pre-allocated buffer.
    1437  * @param   pcbRead                 Pointer to number of bytes read.  Optional.
    1438  */
    1439 static int gstcntlSessionGetOutput(const PVBOXSERVICECTRLSESSION pSession,
    1440                                    uint32_t uPID, uint32_t uCID,
    1441                                    uint32_t uHandleId, uint32_t cMsTimeout,
    1442                                    void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
     1372int GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags)
    14431373{
    14441374    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    1445     AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    1446     AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
    1447     /* pcbRead is optional. */
    1448 
    1449     int                         rc      = VINF_SUCCESS;
    1450     VBOXSERVICECTRLREQUESTTYPE  reqType = VBOXSERVICECTRLREQUEST_UNKNOWN; /* (gcc maybe, well, wrong.) */
    1451     switch (uHandleId)
    1452     {
    1453         case OUTPUT_HANDLE_ID_STDERR:
    1454             reqType = VBOXSERVICECTRLREQUEST_PROC_STDERR;
    1455             break;
    1456 
    1457         case OUTPUT_HANDLE_ID_STDOUT:
    1458         case OUTPUT_HANDLE_ID_STDOUT_DEPRECATED:
    1459             reqType = VBOXSERVICECTRLREQUEST_PROC_STDOUT;
    1460             break;
    1461 
    1462         default:
    1463             rc = VERR_INVALID_PARAMETER;
    1464             break;
    1465     }
    1466 
    1467     if (RT_SUCCESS(rc))
    1468     {
    1469         PVBOXSERVICECTRLREQUEST pRequest;
    1470         rc = GstCntlProcessRequestAllocEx(&pRequest, reqType, pvBuf, cbBuf, uCID);
    1471         if (RT_SUCCESS(rc))
    1472         {
    1473             PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionAcquireProcess(pSession, uPID);
    1474             if (pProcess)
    1475             {
    1476                 rc = GstCntlProcessPerform(pProcess, pRequest, false /* Async */);
    1477                 GstCntlProcessRelease(pProcess);
    1478             }
    1479             else
    1480                 rc = VERR_NOT_FOUND;
    1481 
    1482             if (RT_SUCCESS(rc) && pcbRead)
    1483                 *pcbRead = pRequest->cbData;
    1484             GstCntlProcessRequestFree(pRequest);
    1485         }
    1486     }
    1487 
    1488     return rc;
    1489 }
    1490 
    1491 
    1492 int GstCntlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t uFlags)
    1493 {
    1494     AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    1495 
    1496     RTListInit(&pSession->lstProcessesActive);
    1497     RTListInit(&pSession->lstProcessesInactive);
     1375
     1376    RTListInit(&pSession->lstProcesses);
    14981377    RTListInit(&pSession->lstFiles);
    14991378
     
    15181397
    15191398/**
    1520  * Sets the specified guest thread to a certain list.
    1521  ** @todo Still needed?
     1399 * Adds a guest process to a session's process list.
    15221400 *
    15231401 * @return  IPRT status code.
    1524  * @param   pSession                Guest session.
    1525  * @param   enmList                 List to move thread to.
    1526  * @param   pProcess                Guest process to set.
     1402 * @param   pSession                Guest session to add process to.
     1403 * @param   pProcess                Guest process to add.
    15271404 */
    1528 int GstCntlSessionListSet(PVBOXSERVICECTRLSESSION pSession,
    1529                           PVBOXSERVICECTRLPROCESS pProcess,
    1530                           VBOXSERVICECTRLTHREADLISTTYPE enmList)
     1405int GstCntlSessionProcessAdd(PVBOXSERVICECTRLSESSION pSession,
     1406                             PVBOXSERVICECTRLPROCESS pProcess)
    15311407{
    15321408    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    1533     AssertReturn(enmList > VBOXSERVICECTRLTHREADLIST_UNKNOWN, VERR_INVALID_PARAMETER);
    15341409    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    15351410
     
    15371412    if (RT_SUCCESS(rc))
    15381413    {
    1539         VBoxServiceVerbose(3, "Setting thread (PID %RU32) to list %d\n",
    1540                            pProcess->uPID, enmList);
    1541 
    1542         PRTLISTANCHOR pAnchor = NULL;
    1543         switch (enmList)
    1544         {
    1545             case VBOXSERVICECTRLTHREADLIST_STOPPED:
    1546                 pAnchor = &pSession->lstProcessesInactive;
    1547                 break;
    1548 
    1549             case VBOXSERVICECTRLTHREADLIST_RUNNING:
    1550                 pAnchor = &pSession->lstProcessesActive;
    1551                 break;
    1552 
    1553             default:
    1554                 AssertMsgFailed(("Unknown list type: %u\n",
    1555                                  enmList));
    1556                 break;
    1557         }
    1558 
    1559         if (!pAnchor)
    1560             rc = VERR_INVALID_PARAMETER;
    1561 
    1562         if (RT_SUCCESS(rc))
    1563         {
    1564             if (pProcess->pAnchor != NULL)
    1565             {
    1566                 /* If thread was assigned to a list before,
    1567                  * remove the thread from the old list first. */
    1568                 /* rc = */ RTListNodeRemove(&pProcess->Node);
    1569             }
    1570 
    1571             /* Add thread to desired list. */
    1572             /* rc = */ RTListAppend(pAnchor, &pProcess->Node);
    1573             pProcess->pAnchor = pAnchor;
    1574         }
     1414        VBoxServiceVerbose(3, "Adding process (PID %RU32) to session ID=%RU32\n",
     1415                           pProcess->uPID, pSession->StartupInfo.uSessionID);
     1416
     1417        /* Add process to session list. */
     1418        /* rc = */ RTListAppend(&pSession->lstProcesses, &pProcess->Node);
    15751419
    15761420        int rc2 = RTCritSectLeave(&pSession->CritSect);
     
    15831427
    15841428
    1585 
     1429/**
     1430 * Removes a guest process from a session's process list.
     1431 *
     1432 * @return  IPRT status code.
     1433 * @param   pSession                Guest session to remove process from.
     1434 * @param   pProcess                Guest process to remove.
     1435 */
     1436int GstCntlSessionProcessRemove(PVBOXSERVICECTRLSESSION pSession,
     1437                                PVBOXSERVICECTRLPROCESS pProcess)
     1438{
     1439    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
     1440    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     1441
     1442    int rc = RTCritSectEnter(&pSession->CritSect);
     1443    if (RT_SUCCESS(rc))
     1444    {
     1445        VBoxServiceVerbose(3, "Removing process (PID %RU32) from session ID=%RU32\n",
     1446                           pProcess->uPID, pSession->StartupInfo.uSessionID);
     1447        Assert(pProcess->cRefs == 0);
     1448
     1449        RTListNodeRemove(&pProcess->Node);
     1450
     1451        int rc2 = RTCritSectLeave(&pSession->CritSect);
     1452        if (RT_SUCCESS(rc))
     1453            rc = rc2;
     1454    }
     1455
     1456    return VINF_SUCCESS;
     1457}
    15861458
    15871459
     
    16121484            uint32_t uProcsRunning = 0;
    16131485            PVBOXSERVICECTRLPROCESS pProcess;
    1614             RTListForEach(&pSession->lstProcessesActive, pProcess, VBOXSERVICECTRLPROCESS, Node)
     1486            RTListForEach(&pSession->lstProcesses, pProcess, VBOXSERVICECTRLPROCESS, Node)
    16151487                uProcsRunning++;
    16161488
     
    16321504        if (RT_SUCCESS(rc))
    16331505            rc = rc2;
    1634     }
    1635 
    1636     return rc;
    1637 }
    1638 
    1639 #if 0
    1640 /**
    1641  * Reaps all inactive guest process threads.
    1642  * Does not do locking; this is the job of the caller.
    1643  *
    1644  * @return  IPRT status code.
    1645  */
    1646 int GstCntlSessionReapProcesses(PVBOXSERVICECTRLSESSION pSession)
    1647 {
    1648     AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    1649 
    1650     PVBOXSERVICECTRLPROCESS pThread =
    1651         RTListGetFirst(&pSession->lstProcessesInactive, VBOXSERVICECTRLPROCESS, Node);
    1652     while (pThread)
    1653     {
    1654         PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLPROCESS, Node);
    1655         bool fLast = RTListNodeIsLast(&pSession->lstProcessesInactive, &pThread->Node);
    1656         int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */,
    1657                                      NULL /* rc */);
    1658         if (RT_SUCCESS(rc2))
    1659         {
    1660             RTListNodeRemove(&pThread->Node);
    1661 
    1662             rc2 = GstCntlProcessFree(pThread);
    1663             if (RT_FAILURE(rc2))
    1664             {
    1665                 VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2);
    1666                 if (RT_SUCCESS(rc)) /* Keep original failure. */
    1667                     rc = rc2;
    1668             }
    1669         }
    1670         else
    1671             VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2);
    1672         /* Keep going. */
    1673 
    1674         if (fLast)
    1675             break;
    1676 
    1677         pThread = pNext;
    1678     }
    1679 
    1680     VBoxServiceVerbose(4, "Reaping threads returned with rc=%Rrc\n", rc);
    1681     return rc;
    1682 }
    1683 #endif
    1684 
    1685 
    1686 /**
    1687  * Injects input to a specified running guest process.
    1688  *
    1689  * @return  IPRT status code.
    1690  * @param   pSession                Guest session.
    1691  * @param   uPID                    PID of process to set the input for.
    1692  * @param   uCID                    Context ID to use for reporting back.
    1693  * @param   fPendingClose           Flag indicating whether this is the last input block sent to the process.
    1694  * @param   pvBuf                   Pointer to a buffer containing the actual input data.
    1695  * @param   cbBuf                   Size (in bytes) of the input buffer data.
    1696  * @param   pcbWritten              Pointer to number of bytes written to the process.  Optional.
    1697  */
    1698 int gstcntlSessionSetInput(const PVBOXSERVICECTRLSESSION pSession,
    1699                            uint32_t uPID, uint32_t uCID,
    1700                            bool fPendingClose,
    1701                            void *pvBuf, uint32_t cbBuf,
    1702                            uint32_t *pcbWritten)
    1703 {
    1704     AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    1705     /* pvBuf is optional. */
    1706     /* cbBuf is optional. */
    1707     /* pcbWritten is optional. */
    1708 
    1709     PVBOXSERVICECTRLREQUEST pRequest;
    1710     int rc = GstCntlProcessRequestAllocEx(&pRequest,
    1711                                           fPendingClose
    1712                                           ? VBOXSERVICECTRLREQUEST_PROC_STDIN_EOF
    1713                                           : VBOXSERVICECTRLREQUEST_PROC_STDIN,
    1714                                           pvBuf, cbBuf, uCID);
    1715     if (RT_SUCCESS(rc))
    1716     {
    1717         PVBOXSERVICECTRLPROCESS pProcess = GstCntlSessionAcquireProcess(pSession, uPID);
    1718         if (pProcess)
    1719         {
    1720             rc = GstCntlProcessPerform(pProcess, pRequest, false /* Async */);
    1721             GstCntlProcessRelease(pProcess);
    1722         }
    1723         else
    1724             rc = VERR_NOT_FOUND;
    1725 
    1726         if (RT_SUCCESS(rc))
    1727         {
    1728             if (pcbWritten)
    1729                 *pcbWritten = pRequest->cbData;
    1730         }
    1731 
    1732         GstCntlProcessRequestFree(pRequest);
    17331506    }
    17341507
     
    21581931/**
    21591932 * Close all formerly opened guest session threads.
     1933 * Note: Caller is responsible for locking!
    21601934 *
    21611935 * @return  IPRT status code.
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