VirtualBox

Changeset 45415 in vbox


Ignore:
Timestamp:
Apr 8, 2013 9:40:42 PM (11 years ago)
Author:
vboxsync
Message:

GuestCtrl: Implemented using (public) VirtualBox events instead of own callback mechanisms. Bugfixes for testcases (still work in progress).

Location:
trunk
Files:
2 added
22 edited

Legend:

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

    r45109 r45415  
    6363/** Gets the session ID out of a context ID. */
    6464#define VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID) \
    65     ((uContextID) >> 27)
     65    (((uContextID) >> 27) & 0x1f)
    6666/** Gets the process ID out of a context ID. */
    6767#define VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID) \
     
    308308    GUEST_MSG_FILTER = 4,
    309309    /**
     310     * Skips the current assigned message returned by GUEST_MSG_WAIT.
     311     * Needed for telling the host service to not keep stale
     312     * host commands in the queue.
     313     */
     314    GUEST_MSG_SKIP = 5,
     315    /**
    310316     * Guest reports back a guest session status.
    311317     */
     
    414420/**
    415421 * Asks the guest control host service to set a command
    416  * filter for this client. The filter itself will affect
    417  * the context ID bound to a command.
     422 * filter for this client. This filter will then only
     423 * deliver messages to the client which match the
     424 * wanted context ID (ranges).
    418425 */
    419426typedef struct HGCMMsgCmdSetFilter
     
    429436
    430437/**
     438 * Asks the guest control host service to skip the
     439 * currently assigned host command returned by
     440 * VbglR3GuestCtrlMsgWaitFor().
     441 */
     442typedef struct HGCMMsgCmdSkip
     443{
     444    VBoxGuestHGCMCallInfo hdr;
     445
     446} HGCMMsgCmdSkip;
     447
     448/**
    431449 * Asks the guest control host service to cancel all pending (outstanding)
    432  * waits which were not processed yet.  This is handy for a graceful shutdown.
     450 * waits which were not processed yet. This is handy for a graceful shutdown.
    433451 */
    434452typedef struct HGCMMsgCancelPendingWaits
  • trunk/include/VBox/VBoxGuestLib.h

    r45369 r45415  
    603603VBGLR3DECL(int) VbglR3GuestCtrlMsgWaitFor(uint32_t uClientId, uint32_t *puMsg, uint32_t *puNumParms);
    604604VBGLR3DECL(int) VbglR3GuestCtrlMsgSetFilter(uint32_t uClientId, uint32_t uFilterAdd, uint32_t uFilterRemove);
     605VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t uClientId);
    605606VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(uint32_t u32ClientId);
    606607/* Guest session handling. */
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestCtrl.cpp

    r45109 r45415  
    156156    if (RT_SUCCESS(rc))
    157157        rc = Msg.hdr.result;
     158    return rc;
     159}
     160
     161
     162/**
     163 * Tells the host service to skip the current message returned by
     164 * VbglR3GuestCtrlMsgWaitFor().
     165 *
     166 * @return  IPRT status code.
     167 * @param   uClientId       The client id returned by VbglR3GuestCtrlConnect().
     168 */
     169VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t uClientId)
     170{
     171    HGCMMsgCmdSkip Msg;
     172
     173    Msg.hdr.result      = VERR_WRONG_ORDER;
     174    Msg.hdr.u32ClientID = uClientId;
     175    Msg.hdr.u32Function = GUEST_MSG_SKIP; /* Tell the host we want to skip
     176                                             the current assigned command. */
     177    Msg.hdr.cParms      = 0;              /* No parameters needed. */
     178
     179    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     180    if (RT_SUCCESS(rc))
     181        rc = Msg.hdr.result;
     182
    158183    return rc;
    159184}
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp

    r45109 r45415  
    274274                         * skip all not wanted messages here.
    275275                         */
    276                         VBoxServiceVerbose(3, "Skipping msg=%RU32 ...\n", uMsg);
     276                        rc = VbglR3GuestCtrlMsgSkip(g_uControlSvcClientID);
     277                        VBoxServiceVerbose(3, "Skipping msg=%RU32, rc=%Rrc\n", uMsg, rc);
    277278                    }
    278279                    break;
     
    323324                           pHostCtx->uClientID, pHostCtx->uProtocol);
    324325
    325         rc = GstCntlSessionThreadOpen(&g_lstControlSessionThreads,
    326                                       &ssInfo, NULL /* Session */);
     326        rc = GstCntlSessionThreadCreate(&g_lstControlSessionThreads,
     327                                        &ssInfo, NULL /* Session */);
    327328    }
    328329
     
    350351
    351352    uint32_t uSessionID, uFlags;
    352 
    353353    int rc = VbglR3GuestCtrlSessionGetClose(pHostCtx, &uFlags, &uSessionID);
    354354    if (RT_SUCCESS(rc))
     
    361361            if (pThread->StartupInfo.uSessionID == uSessionID)
    362362            {
    363                 rc = GstCntlSessionThreadClose(pThread, uFlags);
     363                rc = GstCntlSessionThreadDestroy(pThread, uFlags);
    364364                break;
    365365            }
    366366        }
    367 
     367#if 0
    368368        if (RT_FAILURE(rc))
    369369        {
     
    379379            }
    380380        }
    381     }
    382 
    383     VBoxServiceVerbose(2, "Closing guest session %RU32 returned rc=%Rrc\n",
    384                        uSessionID, rc);
     381#endif
     382        VBoxServiceVerbose(2, "Closing guest session %RU32 returned rc=%Rrc\n",
     383                           uSessionID, rc);
     384    }
     385    else
     386        VBoxServiceError("Closing guest session failed with rc=%Rrc\n", rc);
     387
    385388    return rc;
    386389}
     
    420423    VBoxServiceVerbose(2, "Shutting down ...\n");
    421424
    422     int rc2 = GstCntlSessionThreadCloseAll(&g_lstControlSessionThreads,
    423                                            0 /* Flags */);
     425    int rc2 = GstCntlSessionThreadDestroyAll(&g_lstControlSessionThreads,
     426                                             0 /* Flags */);
    424427    if (RT_FAILURE(rc2))
    425428        VBoxServiceError("Closing session threads failed with rc=%Rrc\n", rc2);
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h

    r45109 r45415  
    169169/**
    170170 * Structure for a guest session thread to
    171  * observe the forked session instance.
     171 * observe/control the forked session instance from
     172 * the VBoxService main executable.
    172173 */
    173174typedef struct VBOXSERVICECTRLSESSIONTHREAD
     
    243244typedef struct VBOXSERVICECTRLSESSION
    244245{
     246    /* The session's startup information. */
    245247    VBOXSERVICECTRLSESSIONSTARTUPINFO
    246248                                    StartupInfo;
    247     /** List of active guest control threads (VBOXSERVICECTRLTHREAD). */
    248     RTLISTANCHOR                    lstControlThreadsActive;
    249     /** List of inactive guest control threads (VBOXSERVICECTRLTHREAD). */
     249    /** List of active guest process threads (VBOXSERVICECTRLPROCESS). */
     250    RTLISTANCHOR                    lstProcessesActive;
     251    /** List of inactive guest process threads (VBOXSERVICECTRLPROCESS). */
    250252    /** @todo Still needed? */
    251     RTLISTANCHOR                    lstControlThreadsInactive;
     253    RTLISTANCHOR                    lstProcessesInactive;
    252254    /** List of guest control files (VBOXSERVICECTRLFILE). */
    253255    RTLISTANCHOR                    lstFiles;
    254     /** Critical section for protecting the guest process
    255      *  threading list. */
    256     RTCRITSECT                      csControlThreads;
     256    /** The session's critical section. */
     257    RTCRITSECT                      CritSect;
    257258    /** Session flags. */
    258259    uint32_t                        uFlags;
     
    330331    /** Critical section for thread-safe use. */
    331332    RTCRITSECT                      CritSect;
    332     /** @todo Document me! */
     333    /** Process startup information. */
     334    VBOXSERVICECTRLPROCSTARTUPINFO
     335                                    StartupInfo;
     336    /** The process' PID assigned by the guest OS. */
    333337    uint32_t                        uPID;
    334     char                           *pszCmd;
    335     uint32_t                        uFlags;
    336     char                          **papszArgs;
    337     uint32_t                        uNumArgs;
    338     char                          **papszEnv;
    339     uint32_t                        uNumEnvVars;
    340     /** Name of specified user account to run the
    341      *  guest process under. */
    342     char                           *pszUser;
    343     /** Password of specified user account. */
    344     char                           *pszPassword;
    345     /** Overall time limit (in ms) that the guest process
    346      *  is allowed to run. 0 for indefinite time. */
    347     uint32_t                        uTimeLimitMS;
    348338    /** Pointer to the current IPC request being
    349      *  processed. */
     339     *  processed. We only support one request at a
     340     *  time at the moment.
     341     ** @todo Implemenet a request queue. */
    350342    PVBOXSERVICECTRLREQUEST         pRequest;
    351343    /** StdIn pipe for addressing writes to the
     
    374366
    375367/* Guest session thread handling. */
    376 extern int                      GstCntlSessionThreadOpen(PRTLISTANCHOR pList, const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread);
    377 extern int                      GstCntlSessionThreadClose(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags);
    378 extern int                      GstCntlSessionThreadCloseAll(PRTLISTANCHOR pList, uint32_t uFlags);
     368extern int                      GstCntlSessionThreadCreate(PRTLISTANCHOR pList, const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo, PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread);
     369extern int                      GstCntlSessionThreadDestroy(PVBOXSERVICECTRLSESSIONTHREAD pSession, uint32_t uFlags);
     370extern int                      GstCntlSessionThreadDestroyAll(PRTLISTANCHOR pList, uint32_t uFlags);
    379371extern int                      GstCntlSessionThreadTerminate(PVBOXSERVICECTRLSESSIONTHREAD pSession);
    380372extern RTEXITCODE               VBoxServiceControlSessionForkInit(int argc, char **argv);
     
    392384extern int                      GstCntlProcessPerform(PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest);
    393385extern int                      GstCntlProcessStart(const PVBOXSERVICECTRLSESSION pSession, const PVBOXSERVICECTRLPROCSTARTUPINFO pStartupInfo, uint32_t uContext);
    394 extern int                      GstCntlProcessStop(const PVBOXSERVICECTRLPROCESS pThread);
    395 extern void                     GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pThread);
    396 extern int                      GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pThread, RTMSINTERVAL msTimeout, int *prc);
    397 extern int                      GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pThread);
     386extern int                      GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess);
     387extern void                     GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pProcess);
     388extern int                      GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pProcess, RTMSINTERVAL msTimeout, int *pRc);
     389extern int                      GstCntlProcessFree(PVBOXSERVICECTRLPROCESS pProcess);
    398390/* Process request handling. */
    399391extern int                      GstCntlProcessRequestAlloc(PVBOXSERVICECTRLREQUEST *ppReq, VBOXSERVICECTRLREQUESTTYPE enmType);
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp

    r45109 r45415  
    8787        return rc;
    8888
    89     pProcess->uPID         = 0;          /* Don't have a PID yet. */
    90     pProcess->pRequest     = NULL;       /* No request assigned yet. */
    91     pProcess->uFlags       = pProcess->uFlags;
    92     pProcess->uTimeLimitMS = (   pProcess->uTimeLimitMS == UINT32_MAX
    93                               || pProcess->uTimeLimitMS == 0)
    94                            ? RT_INDEFINITE_WAIT : pProcess->uTimeLimitMS;
    95 
    96     /* Prepare argument list. */
    97     pProcess->uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */
    98     rc = RTGetOptArgvFromString(&pProcess->papszArgs, (int*)&pProcess->uNumArgs,
    99                                 (pStartupInfo->uNumArgs > 0) ? pStartupInfo->szArgs : "", NULL);
    100     /* Did we get the same result? */
    101     Assert(pStartupInfo->uNumArgs == pProcess->uNumArgs);
    102 
    103     if (RT_SUCCESS(rc))
    104     {
    105         /* Prepare environment list. */
    106         pProcess->uNumEnvVars = 0;
    107         if (pProcess->uNumEnvVars)
    108         {
    109             pProcess->papszEnv = (char **)RTMemAlloc(pStartupInfo->uNumEnvVars * sizeof(char*));
    110             AssertPtr(pProcess->papszEnv);
    111             pProcess->uNumEnvVars = pProcess->uNumEnvVars;
    112 
    113             const char *pszCur = pStartupInfo->szEnv;
    114             uint32_t i = 0;
    115             uint32_t cbLen = 0;
    116             while (cbLen < pStartupInfo->cbEnv)
    117             {
    118                 /* sanity check */
    119                 if (i >= pStartupInfo->uNumEnvVars)
    120                 {
    121                     rc = VERR_INVALID_PARAMETER;
    122                     break;
    123                 }
    124                 int cbStr = RTStrAPrintf(&pProcess->papszEnv[i++], "%s", pszCur);
    125                 if (cbStr < 0)
    126                 {
    127                     rc = VERR_NO_STR_MEMORY;
    128                     break;
    129                 }
    130                 pszCur += cbStr + 1; /* Skip terminating '\0' */
    131                 cbLen  += cbStr + 1; /* Skip terminating '\0' */
    132             }
    133             Assert(i == pProcess->uNumEnvVars);
    134         }
    135 
    136         /* The actual command to execute. */
    137         pProcess->pszCmd      = RTStrDup(pStartupInfo->szCmd);
    138         AssertPtr(pProcess->pszCmd);
    139 
    140         /* User management. */
    141         pProcess->pszUser     = RTStrDup(pStartupInfo->szUser);
    142         AssertPtr(pProcess->pszUser);
    143         pProcess->pszPassword = RTStrDup(pStartupInfo->szPassword);
    144         AssertPtr(pProcess->pszPassword);
    145     }
     89    pProcess->uPID     = 0;          /* Don't have a PID yet. */
     90    pProcess->pRequest = NULL;       /* No request assigned yet. */
     91
     92    /* Copy over startup info. */
     93    memcpy(&pProcess->StartupInfo, pStartupInfo, sizeof(VBOXSERVICECTRLPROCSTARTUPINFO));
     94
     95    /* Adjust timeout value. */
     96    if (   pProcess->StartupInfo.uTimeLimitMS == UINT32_MAX
     97        || pProcess->StartupInfo.uTimeLimitMS == 0)
     98        pProcess->StartupInfo.uTimeLimitMS = RT_INDEFINITE_WAIT;
    14699
    147100    if (RT_FAILURE(rc)) /* Clean up on failure. */
     
    161114    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    162115
    163     VBoxServiceVerbose(3, "[PID %u]: Freeing ...\n",
     116    VBoxServiceVerbose(3, "[PID %RU32]: Freeing ...\n",
    164117                       pProcess->uPID);
    165118
    166     int rc = RTCritSectEnter(&pProcess->CritSect);
    167     if (RT_SUCCESS(rc))
    168     {
    169         if (pProcess->uNumEnvVars)
    170         {
    171             for (uint32_t i = 0; i < pProcess->uNumEnvVars; i++)
    172                 RTStrFree(pProcess->papszEnv[i]);
    173             RTMemFree(pProcess->papszEnv);
    174         }
    175         RTGetOptArgvFree(pProcess->papszArgs);
    176 
    177         RTStrFree(pProcess->pszCmd);
    178         RTStrFree(pProcess->pszUser);
    179         RTStrFree(pProcess->pszPassword);
    180 
    181         VBoxServiceVerbose(3, "[PID %u]: Setting stopped state\n",
    182                            pProcess->uPID);
    183 
    184         rc = RTCritSectLeave(&pProcess->CritSect);
    185         AssertRC(rc);
    186     }
    187119
    188120    /*
     
    198130    pProcess = NULL;
    199131
    200     return rc;
     132    return VINF_SUCCESS;
    201133}
    202134
     
    207139 *
    208140 * @return  IPRT status code.
    209  * @param   pThread             Thread to shut down.
    210  */
    211 int GstCntlProcessStop(const PVBOXSERVICECTRLPROCESS pThread)
    212 {
    213     AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    214 
    215     VBoxServiceVerbose(3, "[PID %u]: Stopping ...\n",
    216                        pThread->uPID);
    217 
    218     int rc = gstcntlProcessRequestCancel(pThread->pRequest);
    219     if (RT_FAILURE(rc))
    220         VBoxServiceError("[PID %u]: Signalling request event failed, rc=%Rrc\n",
    221                          pThread->uPID, rc);
    222 
    223     /* Do *not* set pThread->fShutdown or other stuff here!
    224      * The guest thread loop will do that as soon as it processes the quit message. */
    225 
    226     PVBOXSERVICECTRLREQUEST pRequest;
    227     rc = GstCntlProcessRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_QUIT);
     141 * @param   pProcess            Process to stop.
     142 */
     143int GstCntlProcessStop(PVBOXSERVICECTRLPROCESS pProcess)
     144{
     145    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     146
     147    VBoxServiceVerbose(3, "[PID %RU32]: Stopping ...\n",
     148                       pProcess->uPID);
     149
     150    int rc = RTCritSectEnter(&pProcess->CritSect);
    228151    if (RT_SUCCESS(rc))
    229152    {
    230         rc = GstCntlProcessPerform(pThread, pRequest);
    231         if (RT_FAILURE(rc))
    232             VBoxServiceVerbose(3, "[PID %u]: Sending quit request failed with rc=%Rrc\n",
    233                                pThread->uPID, rc);
    234 
    235         GstCntlProcessRequestFree(pRequest);
    236     }
     153        if (pProcess->pRequest)
     154        {
     155            rc = gstcntlProcessRequestCancel(pProcess->pRequest);
     156            if (RT_FAILURE(rc))
     157                VBoxServiceError("[PID %RU32]: Signalling request event failed, rc=%Rrc\n",
     158                                 pProcess->uPID, rc);
     159        }
     160
     161        /* Do *not* set pThread->fShutdown or other stuff here!
     162         * The guest thread loop will do that as soon as it processes the quit message. */
     163
     164        PVBOXSERVICECTRLREQUEST pRequest;
     165        rc = GstCntlProcessRequestAlloc(&pRequest, VBOXSERVICECTRLREQUEST_QUIT);
     166        if (RT_SUCCESS(rc))
     167        {
     168            rc = GstCntlProcessPerform(pProcess, pRequest);
     169            if (RT_FAILURE(rc))
     170                VBoxServiceVerbose(3, "[PID %RU32]: Sending quit request failed with rc=%Rrc\n",
     171                                   pProcess->uPID, rc);
     172
     173            GstCntlProcessRequestFree(pRequest);
     174        }
     175
     176        int rc2 = RTCritSectLeave(&pProcess->CritSect);
     177        AssertRC(rc2);
     178    }
     179
    237180    return rc;
    238181}
     
    242185 * Releases (unlocks) a previously locked guest process.
    243186 *
    244  * @param   pThread                 Thread to unlock.
    245  */
    246 void GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pThread)
    247 {
    248     AssertPtr(pThread);
    249 
    250     int rc = RTCritSectLeave(&pThread->CritSect);
     187 * @param   pProcess            Process to unlock.
     188 */
     189void GstCntlProcessRelease(const PVBOXSERVICECTRLPROCESS pProcess)
     190{
     191    AssertPtrReturnVoid(pProcess);
     192
     193    int rc = RTCritSectLeave(&pProcess->CritSect);
    251194    AssertRC(rc);
    252195}
     
    255198/**
    256199 * Wait for a guest process thread to shut down.
    257  *
    258  * @return  IPRT status code.
    259  * @param   pThread             Thread to wait shutting down for.
     200 * Note: Caller is responsible for locking!
     201 *
     202 * @return  IPRT status code.
     203 * @param   pProcess            Process to wait shutting down for.
    260204 * @param   RTMSINTERVAL        Timeout in ms to wait for shutdown.
    261  * @param   prc                 Where to store the thread's return code. Optional.
    262  */
    263 int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pThread,
    264                        RTMSINTERVAL msTimeout, int *prc)
    265 {
    266     AssertPtrReturn(pThread, VERR_INVALID_POINTER);
    267     /* prc is optional. */
     205 * @param   pRc                 Where to store the thread's return code. Optional.
     206 */
     207int GstCntlProcessWait(const PVBOXSERVICECTRLPROCESS pProcess,
     208                       RTMSINTERVAL msTimeout, int *pRc)
     209{
     210    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     211    /* pRc is optional. */
    268212
    269213    int rc = VINF_SUCCESS;
    270     if (   pThread->Thread != NIL_RTTHREAD
    271         && ASMAtomicReadBool(&pThread->fStarted))
    272     {
    273         VBoxServiceVerbose(2, "[PID %u]: Waiting for shutdown of pThread=0x%p = \"%s\"...\n",
    274                            pThread->uPID, pThread, pThread->pszCmd);
     214    if (   pProcess->Thread != NIL_RTTHREAD
     215        && ASMAtomicReadBool(&pProcess->fStarted))
     216    {
     217        VBoxServiceVerbose(2, "[PID %RU32]: Waiting for shutdown (%RU32ms) ...\n",
     218                           pProcess->uPID, msTimeout);
    275219
    276220        /* Wait a bit ... */
    277221        int rcThread;
    278         rc = RTThreadWait(pThread->Thread, msTimeout, &rcThread);
     222        rc = RTThreadWait(pProcess->Thread, msTimeout, &rcThread);
    279223        if (RT_FAILURE(rc))
    280224        {
    281             VBoxServiceError("[PID %u]: Waiting for shutting down thread returned error rc=%Rrc\n",
    282                              pThread->uPID, rc);
     225            VBoxServiceError("[PID %RU32]: Waiting for shutting down thread returned error rc=%Rrc\n",
     226                             pProcess->uPID, rc);
    283227        }
    284228        else
    285229        {
    286             VBoxServiceVerbose(3, "[PID %u]: Thread reported exit code=%Rrc\n",
    287                                pThread->uPID, rcThread);
    288             if (prc)
    289                 *prc = rcThread;
    290         }
    291     }
     230            VBoxServiceVerbose(3, "[PID %RU32]: Thread reported exit code=%Rrc\n",
     231                               pProcess->uPID, rcThread);
     232            if (pRc)
     233                *pRc = rcThread;
     234        }
     235    }
     236
    292237    return rc;
    293238}
     
    368313        && cbReadable)
    369314    {
    370         VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%u has %ld bytes left, vetoing close\n",
     315        VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%RU32 has %zu bytes left, vetoing close\n",
    371316                           idPollHnd, cbReadable);
    372317
     
    377322    }
    378323    else
    379         VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%u will be closed\n",
     324        VBoxServiceVerbose(3, "gstcntlProcessHandleOutputError: idPollHnd=%RU32 will be closed\n",
    380325                           idPollHnd);
    381326
     
    460405    pRequest->rc = rc;
    461406
    462 #ifdef _DEBUG
    463     VBoxServiceVerbose(4, "Handled req=%u, CID=%u, rc=%Rrc, cbData=%u, pvData=%p\n",
     407#ifdef DEBUG_andy
     408    VBoxServiceVerbose(4, "Handled req=%RU32, CID=%RU32, rc=%Rrc, cbData=%RU32, pvData=%p\n",
    464409                       pRequest->enmType, pRequest->uCID, pRequest->rc,
    465410                       pRequest->cbData, pRequest->pvData);
     
    477422static int gstcntlProcessHandleRequest(RTPOLLSET hPollSet, uint32_t fPollEvt,
    478423                                       PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR,
    479                                        PVBOXSERVICECTRLPROCESS pThread, PVBOXSERVICECTRLREQUEST pRequest)
     424                                       PVBOXSERVICECTRLPROCESS pProcess, PVBOXSERVICECTRLREQUEST pRequest)
    480425{
    481426    AssertPtrReturn(phStdInW, VERR_INVALID_POINTER);
    482427    AssertPtrReturn(phStdOutR, VERR_INVALID_POINTER);
    483428    AssertPtrReturn(phStdErrR, VERR_INVALID_POINTER);
    484     AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     429    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    485430    AssertPtrReturn(pRequest, VERR_INVALID_POINTER);
     431
     432    VBoxServiceVerbose(4, "[PID %RU32]: Handling pRequest=%p\n",
     433                       pProcess->uPID, pRequest);
    486434
    487435    /* Drain the notification pipe. */
    488436    uint8_t abBuf[8];
    489437    size_t cbIgnore;
    490     int rc = RTPipeRead(pThread->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore);
     438    int rc = RTPipeRead(pProcess->hNotificationPipeR, abBuf, sizeof(abBuf), &cbIgnore);
    491439    if (RT_FAILURE(rc))
    492440        VBoxServiceError("Draining IPC notification pipe failed with rc=%Rrc\n", rc);
     
    501449            /** @todo Check for some conditions to check to
    502450             *        veto quitting. */
    503             ASMAtomicXchgBool(&pThread->fShutdown, true);
     451            ASMAtomicXchgBool(&pProcess->fShutdown, true);
    504452            rcReq = VERR_CANCELLED;
    505453            break;
     
    572520
    573521        case VBOXSERVICECTRLREQUEST_PROC_TERM:
    574             ASMAtomicXchgBool(&pThread->fShutdown, true);
     522            ASMAtomicXchgBool(&pProcess->fShutdown, true);
    575523            fDefer = true;
    576524            break;
     
    589537        /* No access to pRequest here anymore -- could be out of scope
    590538         * or modified already! */
    591         pThread->pRequest = pRequest = NULL;
     539        pProcess->pRequest = pRequest = NULL;
    592540    }
    593541    else /* Completing the request defered. */
     
    603551 *
    604552 * @return  IPRT status code.
    605  * @param   pThread                     The process' thread handle.
     553 * @param   pProcess                    The guest process to handle.
    606554 * @param   hProcess                    The actual process handle.
    607555 * @param   cMsTimeout                  Time limit (in ms) of the process' life time.
     
    611559 * @param   hStdErrR                    Handle to the process' stderr read end.
    612560 */
    613 static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS pThread,
    614                                   RTPROCESS hProcess, RTMSINTERVAL cMsTimeout, RTPOLLSET hPollSet,
     561static int gstcntlProcessProcLoop(PVBOXSERVICECTRLPROCESS pProcess,
     562                                  RTPROCESS hProcess, RTPOLLSET hPollSet,
    615563                                  PRTPIPE phStdInW, PRTPIPE phStdOutR, PRTPIPE phStdErrR)
    616564{
    617     AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     565    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    618566    AssertPtrReturn(phStdInW, VERR_INVALID_PARAMETER);
    619567    /* Rest is optional. */
     
    621569    int                         rc;
    622570    int                         rc2;
    623     uint64_t const              MsStart             = RTTimeMilliTS();
     571    uint64_t const              uMsStart            = RTTimeMilliTS();
    624572    RTPROCSTATUS                ProcessStatus       = { 254, RTPROCEXITREASON_ABEND };
    625573    bool                        fProcessAlive       = true;
     
    636584     * the first (stale) entry will be found and we get really weird results!
    637585     */
    638     rc = gstcntlProcessAssignPID(pThread, hProcess);
     586    rc = gstcntlProcessAssignPID(pProcess, hProcess);
    639587    if (RT_FAILURE(rc))
    640588    {
     
    648596     * and that it's now OK to send input to the process.
    649597     */
    650     VBoxServiceVerbose(2, "[PID %u]: Process \"%s\" started, CID=%u, User=%s\n",
    651                        pThread->uPID, pThread->pszCmd, pThread->uContextID, pThread->pszUser);
    652     VBGLR3GUESTCTRLCMDCTX ctx = { pThread->uClientID, pThread->uContextID };
     598    VBoxServiceVerbose(2, "[PID %RU32]: Process \"%s\" started, CID=%u, User=%s, cMsTimeout=%RU32\n",
     599                       pProcess->uPID, pProcess->StartupInfo.szCmd, pProcess->uContextID,
     600                       pProcess->StartupInfo.szUser, pProcess->StartupInfo.uTimeLimitMS);
     601    VBGLR3GUESTCTRLCMDCTX ctx = { pProcess->uClientID, pProcess->uContextID };
    653602    rc = VbglR3GuestCtrlProcCbStatus(&ctx,
    654                                      pThread->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
     603                                     pProcess->uPID, PROC_STS_STARTED, 0 /* u32Flags */,
    655604                                     NULL /* pvData */, 0 /* cbData */);
    656605
     
    660609    PVBOXSERVICECTRLREQUEST pReq = NULL;
    661610    while (   RT_SUCCESS(rc)
    662            && RT_UNLIKELY(!pThread->fShutdown))
     611           && RT_UNLIKELY(!pProcess->fShutdown))
    663612    {
    664613        /*
     
    668617        uint32_t fPollEvt;
    669618        rc2 = RTPollNoResume(hPollSet, cMsPollCur, &fPollEvt, &idPollHnd);
    670         if (pThread->fShutdown)
     619        if (pProcess->fShutdown)
    671620            continue;
    672621
     
    675624        if (RT_SUCCESS(rc2))
    676625        {
    677             /*VBoxServiceVerbose(4, "[PID %u}: RTPollNoResume idPollHnd=%u\n",
    678                                  pThread->uPID, idPollHnd);*/
    679626            switch (idPollHnd)
    680627            {
     
    693640
    694641                case VBOXSERVICECTRLPIPEID_IPC_NOTIFY:
    695                     pReq = pThread->pRequest; /** @todo Implement request queue. */
     642                    pReq = pProcess->pRequest; /** @todo Implement request queue. */
    696643                    rc = gstcntlProcessHandleRequest(hPollSet, fPollEvt,
    697644                                                     phStdInW, phStdOutR, phStdErrR,
    698                                                      pThread, pReq);
     645                                                     pProcess, pReq);
    699646                    if (rc != VINF_AIO_TASK_PENDING)
    700647                        pReq = NULL;
     
    708655            if (RT_FAILURE(rc) || rc == VINF_EOF)
    709656                break; /* Abort command, or client dead or something. */
    710 
    711             if (RT_UNLIKELY(pThread->fShutdown))
    712                 break; /* We were asked to shutdown. */
    713 
    714             continue;
    715         }
    716 
    717 #if 0
    718         VBoxServiceVerbose(4, "[PID %u]: Polling done, pollRC=%Rrc, pollCnt=%u, rc=%Rrc, fShutdown=%RTbool\n",
    719                            pThread->uPID, rc2, RTPollSetGetCount(hPollSet), rc, pThread->fShutdown);
     657        }
     658#ifdef DEBUG_andy
     659        VBoxServiceVerbose(4, "[PID %RU32]: Polling done, pollRc=%Rrc, pollCnt=%u, idPollHnd=%RU32, rc=%Rrc, fProcessAlive=%RTbool, fShutdown=%RTbool\n",
     660                           pProcess->uPID, rc2, RTPollSetGetCount(hPollSet), idPollHnd, rc, fProcessAlive, pProcess->fShutdown);
    720661#endif
     662
     663        if (RT_UNLIKELY(pProcess->fShutdown))
     664            break; /* We were asked to shutdown. */
     665
    721666        /*
    722667         * Check for process death.
     
    725670        {
    726671            rc2 = RTProcWaitNoResume(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
     672#ifdef DEBUG_andy
     673            VBoxServiceVerbose(4, "[PID %RU32]: RTProcWaitNoResume=%Rrc, stdOut=%s, stdErrR=%s\n",
     674                               pProcess->uPID, rc2,
     675                               *phStdOutR == NIL_RTPIPE ? "closed" : "open",
     676                               *phStdErrR == NIL_RTPIPE ? "closed" : "open");
     677#endif
    727678            if (RT_SUCCESS_NP(rc2))
    728679            {
     
    756707         */
    757708        uint32_t cMilliesLeft = RT_INDEFINITE_WAIT;
    758         if (cMsTimeout != RT_INDEFINITE_WAIT)
     709        if (pProcess->StartupInfo.uTimeLimitMS != RT_INDEFINITE_WAIT)
    759710        {
    760711            uint64_t u64Now = RTTimeMilliTS();
    761             uint64_t cMsElapsed = u64Now - MsStart;
    762             if (cMsElapsed >= cMsTimeout)
     712            uint64_t cMsElapsed = u64Now - uMsStart;
     713            if (cMsElapsed >= pProcess->StartupInfo.uTimeLimitMS)
    763714            {
    764                 VBoxServiceVerbose(3, "[PID %u]: Timed out (%ums elapsed > %ums timeout), killing ...\n",
    765                                    pThread->uPID, cMsElapsed, cMsTimeout);
     715                VBoxServiceVerbose(3, "[PID %RU32]: Timed out (%RU32ms elapsed > %RU32ms timeout), killing ...\n",
     716                                   pProcess->uPID, cMsElapsed, pProcess->StartupInfo.uTimeLimitMS);
    766717
    767718                fProcessTimedOut = true;
     
    778729            }
    779730            else
    780                 cMilliesLeft = cMsTimeout - (uint32_t)cMsElapsed;
     731                cMilliesLeft = pProcess->StartupInfo.uTimeLimitMS - (uint32_t)cMsElapsed;
    781732        }
    782733
     
    787738        if (cMilliesLeft < cMsPollCur)
    788739            cMsPollCur = cMilliesLeft;
    789 
    790         /*
    791          * Need to exit?
    792          */
    793         if (pThread->fShutdown)
    794             break;
    795     }
    796 
    797     rc2 = RTCritSectEnter(&pThread->CritSect);
     740    }
     741
     742    rc2 = RTCritSectEnter(&pProcess->CritSect);
    798743    if (RT_SUCCESS(rc2))
    799744    {
    800         ASMAtomicXchgBool(&pThread->fShutdown, true);
    801 
    802         rc2 = RTCritSectLeave(&pThread->CritSect);
     745        ASMAtomicXchgBool(&pProcess->fShutdown, true);
     746
     747        rc2 = RTCritSectLeave(&pProcess->CritSect);
    803748        AssertRC(rc2);
    804749    }
     
    811756        if (MsProcessKilled == UINT64_MAX)
    812757        {
    813             VBoxServiceVerbose(3, "[PID %u]: Is still alive and not killed yet\n",
    814                                pThread->uPID);
     758            VBoxServiceVerbose(3, "[PID %RU32]: Is still alive and not killed yet\n",
     759                               pProcess->uPID);
    815760
    816761            MsProcessKilled = RTTimeMilliTS();
     
    821766        for (size_t i = 0; i < 10; i++)
    822767        {
    823             VBoxServiceVerbose(4, "[PID %u]: Kill attempt %d/10: Waiting to exit ...\n",
    824                                pThread->uPID, i + 1);
     768            VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Waiting to exit ...\n",
     769                               pProcess->uPID, i + 1);
    825770            rc2 = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &ProcessStatus);
    826771            if (RT_SUCCESS(rc2))
    827772            {
    828                 VBoxServiceVerbose(4, "[PID %u]: Kill attempt %d/10: Exited\n",
    829                                    pThread->uPID, i + 1);
     773                VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Exited\n",
     774                                   pProcess->uPID, i + 1);
    830775                fProcessAlive = false;
    831776                break;
     
    833778            if (i >= 5)
    834779            {
    835                 VBoxServiceVerbose(4, "[PID %u]: Kill attempt %d/10: Trying to terminate ...\n",
    836                                    pThread->uPID, i + 1);
     780                VBoxServiceVerbose(4, "[PID %RU32]: Kill attempt %d/10: Trying to terminate ...\n",
     781                                   pProcess->uPID, i + 1);
    837782                RTProcTerminate(hProcess);
    838783            }
     
    841786
    842787        if (fProcessAlive)
    843             VBoxServiceVerbose(3, "[PID %u]: Could not be killed\n", pThread->uPID);
     788            VBoxServiceVerbose(3, "[PID %RU32]: Could not be killed\n", pProcess->uPID);
    844789
    845790        if (   pReq /* Handle deferred termination request. */
     
    865810        if (     fProcessTimedOut  && !fProcessAlive && MsProcessKilled != UINT64_MAX)
    866811        {
    867             VBoxServiceVerbose(3, "[PID %u]: Timed out and got killed\n",
    868                                pThread->uPID);
     812            VBoxServiceVerbose(3, "[PID %RU32]: Timed out and got killed\n",
     813                               pProcess->uPID);
    869814            uStatus = PROC_STS_TOK;
    870815        }
    871816        else if (fProcessTimedOut  &&  fProcessAlive && MsProcessKilled != UINT64_MAX)
    872817        {
    873             VBoxServiceVerbose(3, "[PID %u]: Timed out and did *not* get killed\n",
    874                                pThread->uPID);
     818            VBoxServiceVerbose(3, "[PID %RU32]: Timed out and did *not* get killed\n",
     819                               pProcess->uPID);
    875820            uStatus = PROC_STS_TOA;
    876821        }
    877         else if (pThread->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX))
    878         {
    879             VBoxServiceVerbose(3, "[PID %u]: Got terminated because system/service is about to shutdown\n",
    880                                pThread->uPID);
     822        else if (pProcess->fShutdown && (fProcessAlive || MsProcessKilled != UINT64_MAX))
     823        {
     824            VBoxServiceVerbose(3, "[PID %RU32]: Got terminated because system/service is about to shutdown\n",
     825                               pProcess->uPID);
    881826            uStatus = PROC_STS_DWN; /* Service is stopping, process was killed. */
    882             uFlags = pThread->uFlags; /* Return handed-in execution flags back to the host. */
     827            uFlags = pProcess->StartupInfo.uFlags; /* Return handed-in execution flags back to the host. */
    883828        }
    884829        else if (fProcessAlive)
    885830        {
    886             VBoxServiceError("[PID %u]: Is alive when it should not!\n",
    887                              pThread->uPID);
     831            VBoxServiceError("[PID %RU32]: Is alive when it should not!\n",
     832                             pProcess->uPID);
    888833        }
    889834        else if (MsProcessKilled != UINT64_MAX)
    890835        {
    891             VBoxServiceError("[PID %u]: Has been killed when it should not!\n",
    892                              pThread->uPID);
     836            VBoxServiceError("[PID %RU32]: Has been killed when it should not!\n",
     837                             pProcess->uPID);
    893838        }
    894839        else if (ProcessStatus.enmReason == RTPROCEXITREASON_NORMAL)
    895840        {
    896             VBoxServiceVerbose(3, "[PID %u]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %u)\n",
    897                                pThread->uPID, ProcessStatus.iStatus);
     841            VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_NORMAL (Exit code: %u)\n",
     842                               pProcess->uPID, ProcessStatus.iStatus);
    898843
    899844            uStatus = PROC_STS_TEN;
     
    902847        else if (ProcessStatus.enmReason == RTPROCEXITREASON_SIGNAL)
    903848        {
    904             VBoxServiceVerbose(3, "[PID %u]: Ended with RTPROCEXITREASON_SIGNAL (Signal: %u)\n",
    905                                pThread->uPID, ProcessStatus.iStatus);
     849            VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_SIGNAL (Signal: %u)\n",
     850                               pProcess->uPID, ProcessStatus.iStatus);
    906851
    907852            uStatus = PROC_STS_TES;
     
    911856        {
    912857            /* ProcessStatus.iStatus will be undefined. */
    913             VBoxServiceVerbose(3, "[PID %u]: Ended with RTPROCEXITREASON_ABEND\n",
    914                                pThread->uPID);
     858            VBoxServiceVerbose(3, "[PID %RU32]: Ended with RTPROCEXITREASON_ABEND\n",
     859                               pProcess->uPID);
    915860
    916861            uStatus = PROC_STS_TEA;
     
    918863        }
    919864        else
    920             VBoxServiceVerbose(1, "[PID %u]: Handling process status %u not implemented\n",
    921                                pThread->uPID, ProcessStatus.enmReason);
    922 
    923         VBoxServiceVerbose(2, "[PID %u]: Ended, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",
    924                            pThread->uPID, pThread->uClientID, pThread->uContextID, uStatus, uFlags);
    925 
    926         if (!(pThread->uFlags & EXECUTEPROCESSFLAG_WAIT_START))
    927         {
    928             VBGLR3GUESTCTRLCMDCTX ctx = { pThread->uClientID, pThread->uContextID };
     865            VBoxServiceVerbose(1, "[PID %RU32]: Handling process status %u not implemented\n",
     866                               pProcess->uPID, ProcessStatus.enmReason);
     867
     868        VBoxServiceVerbose(2, "[PID %RU32]: Ended, ClientID=%u, CID=%u, Status=%u, Flags=0x%x\n",
     869                           pProcess->uPID, pProcess->uClientID, pProcess->uContextID, uStatus, uFlags);
     870
     871        if (!(pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_START))
     872        {
     873            VBGLR3GUESTCTRLCMDCTX ctx = { pProcess->uClientID, pProcess->uContextID };
    929874            rc2 = VbglR3GuestCtrlProcCbStatus(&ctx,
    930                                               pThread->uPID, uStatus, uFlags,
     875                                              pProcess->uPID, uStatus, uFlags,
    931876                                              NULL /* pvData */, 0 /* cbData */);
    932877            if (RT_FAILURE(rc2))
    933                 VBoxServiceError("[PID %u]: Error reporting final status to host; rc=%Rrc\n",
    934                                  pThread->uPID, rc2);
     878                VBoxServiceError("[PID %RU32]: Error reporting final status to host; rc=%Rrc\n",
     879                                 pProcess->uPID, rc2);
    935880            if (RT_SUCCESS(rc))
    936881                rc = rc2;
    937882        }
    938883        else
    939             VBoxServiceVerbose(3, "[PID %u]: Was started detached, no final status sent to host\n",
    940                                pThread->uPID);
    941 
    942         VBoxServiceVerbose(3, "[PID %u]: Process loop ended with rc=%Rrc\n",
    943                            pThread->uPID, rc);
     884            VBoxServiceVerbose(3, "[PID %RU32]: Was started detached, no final status sent to host\n",
     885                               pProcess->uPID);
     886
     887        VBoxServiceVerbose(3, "[PID %RU32]: Process loop ended with rc=%Rrc\n",
     888                           pProcess->uPID, rc);
    944889    }
    945890    else
    946         VBoxServiceError("[PID %u]: Loop failed with rc=%Rrc\n",
    947                          pThread->uPID, rc);
     891        VBoxServiceError("[PID %RU32]: Loop failed with rc=%Rrc\n",
     892                         pProcess->uPID, rc);
    948893    return rc;
    949894}
     
    1034979
    1035980/**
    1036  * Cancels a previously fired off guest thread request.
    1037  *
    1038  * Note: Does *not* do locking since GstCntlProcessRequestWait()
    1039  * holds the lock (critsect); so only trigger the signal; the owner
    1040  * needs to clean up afterwards.
     981 * Cancels a previously fired off guest process request.
     982 * Note: Caller is responsible for locking!
    1041983 *
    1042984 * @return  IPRT status code.
     
    13571299
    13581300    AssertPtr(pThread->pSession);
    1359     int rc = RTCritSectEnter(&pThread->pSession->csControlThreads);
     1301    int rc = RTCritSectEnter(&pThread->pSession->CritSect);
    13601302    if (RT_SUCCESS(rc))
    13611303    {
     
    13661308        do
    13671309        {
    1368             RTListForEach(&pThread->pSession->lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLPROCESS, Node)
     1310            RTListForEach(&pThread->pSession->lstProcessesActive, pThreadCur, VBOXSERVICECTRLPROCESS, Node)
    13691311            {
    13701312                if (pThreadCur->uPID == uPID)
     
    13841326        pThread->uPID = uPID;
    13851327
    1386         rc = RTCritSectLeave(&pThread->pSession->csControlThreads);
     1328        rc = RTCritSectLeave(&pThread->pSession->CritSect);
    13871329        AssertRC(rc);
    13881330    }
     
    15621504    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    15631505    VBoxServiceVerbose(3, "Thread of process pThread=0x%p = \"%s\" started\n",
    1564                        pProcess, pProcess->pszCmd);
     1506                       pProcess, pProcess->StartupInfo.szCmd);
    15651507
    15661508    int rc = GstCntlSessionListSet(pProcess->pSession,
     
    15761518    }
    15771519    VBoxServiceVerbose(3, "Guest process \"%s\" got client ID=%u, flags=0x%x\n",
    1578                        pProcess->pszCmd, pProcess->uClientID, pProcess->uFlags);
     1520                       pProcess->StartupInfo.szCmd, pProcess->uClientID, pProcess->StartupInfo.uFlags);
    15791521
    15801522    bool fSignalled = false; /* Indicator whether we signalled the thread user event already. */
     1523
     1524    /*
     1525     * Prepare argument list.
     1526     */
     1527    char **papszArgs;
     1528    uint32_t uNumArgs = 0; /* Initialize in case of RTGetOptArgvFromString() is failing ... */
     1529    rc = RTGetOptArgvFromString(&papszArgs, (int*)&uNumArgs,
     1530                                (pProcess->StartupInfo.uNumArgs > 0) ? pProcess->StartupInfo.szArgs : "", NULL);
     1531    /* Did we get the same result? */
     1532    Assert(pProcess->StartupInfo.uNumArgs == uNumArgs);
     1533
     1534    /*
     1535     * Prepare environment variables list.
     1536     */
     1537    char **papszEnv;
     1538    uint32_t uNumEnvVars = 0; /* Initialize in case of failing ... */
     1539    if (RT_SUCCESS(rc))
     1540    {
     1541        /* Prepare environment list. */
     1542        if (pProcess->StartupInfo.uNumEnvVars)
     1543        {
     1544            papszEnv = (char **)RTMemAlloc(pProcess->StartupInfo.uNumEnvVars * sizeof(char*));
     1545            AssertPtr(papszEnv);
     1546            uNumEnvVars = pProcess->StartupInfo.uNumEnvVars;
     1547
     1548            const char *pszCur = pProcess->StartupInfo.szEnv;
     1549            uint32_t i = 0;
     1550            uint32_t cbLen = 0;
     1551            while (cbLen < pProcess->StartupInfo.cbEnv)
     1552            {
     1553                /* sanity check */
     1554                if (i >= pProcess->StartupInfo.uNumEnvVars)
     1555                {
     1556                    rc = VERR_INVALID_PARAMETER;
     1557                    break;
     1558                }
     1559                int cbStr = RTStrAPrintf(&papszEnv[i++], "%s", pszCur);
     1560                if (cbStr < 0)
     1561                {
     1562                    rc = VERR_NO_STR_MEMORY;
     1563                    break;
     1564                }
     1565                pszCur += cbStr + 1; /* Skip terminating '\0' */
     1566                cbLen  += cbStr + 1; /* Skip terminating '\0' */
     1567            }
     1568            Assert(i == pProcess->StartupInfo.uNumEnvVars);
     1569        }
     1570    }
    15811571
    15821572    /*
     
    15881578    {
    15891579        size_t i;
    1590         for (i = 0; i < pProcess->uNumEnvVars && pProcess->papszEnv; i++)
    1591         {
    1592             rc = RTEnvPutEx(hEnv, pProcess->papszEnv[i]);
     1580        for (i = 0; i < uNumEnvVars && papszEnv; i++)
     1581        {
     1582            rc = RTEnvPutEx(hEnv, papszEnv[i]);
    15931583            if (RT_FAILURE(rc))
    15941584                break;
     
    16091599                PRTHANDLE   phStdOut;
    16101600                RTPIPE      pipeStdOutR;
    1611                 rc = gstcntlProcessSetupPipe(  (pProcess->uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)
     1601                rc = gstcntlProcessSetupPipe(  (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDOUT)
    16121602                                             ? "|" : "/dev/null",
    16131603                                             1 /*STDOUT_FILENO*/,
     
    16181608                    PRTHANDLE   phStdErr;
    16191609                    RTPIPE      pipeStdErrR;
    1620                     rc = gstcntlProcessSetupPipe(  (pProcess->uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)
     1610                    rc = gstcntlProcessSetupPipe(  (pProcess->StartupInfo.uFlags & EXECUTEPROCESSFLAG_WAIT_STDERR)
    16211611                                                 ? "|" : "/dev/null",
    16221612                                                 2 /*STDERR_FILENO*/,
     
    16581648
    16591649                                RTPROCESS hProcess;
    1660                                 rc = gstcntlProcessCreateProcess(pProcess->pszCmd, pProcess->papszArgs, hEnv, pProcess->uFlags,
     1650                                rc = gstcntlProcessCreateProcess(pProcess->StartupInfo.szCmd, papszArgs, hEnv, pProcess->StartupInfo.uFlags,
    16611651                                                                 phStdIn, phStdOut, phStdErr,
    1662                                                                  fNeedsImpersonation ? pProcess->pszUser : NULL,
    1663                                                                  fNeedsImpersonation ? pProcess->pszPassword : NULL,
     1652                                                                 fNeedsImpersonation ? pProcess->StartupInfo.szUser : NULL,
     1653                                                                 fNeedsImpersonation ? pProcess->StartupInfo.szPassword : NULL,
    16641654                                                                 &hProcess);
    16651655                                if (RT_FAILURE(rc))
     
    16891679
    16901680                                    /* Enter the process loop. */
    1691                                     rc = gstcntlProcessProcLoop(pProcess,
    1692                                                                 hProcess, pProcess->uTimeLimitMS, hPollSet,
     1681                                    rc = gstcntlProcessProcLoop(pProcess, hProcess, hPollSet,
    16931682                                                                &pProcess->pipeStdInW, &pipeStdOutR, &pipeStdErrR);
    16941683
     
    17591748        /* Disconnect this client from the guest control service. This also cancels all
    17601749         * outstanding host requests. */
    1761         VBoxServiceVerbose(3, "[PID %u]: Disconnecting (client ID=%u) ...\n",
     1750        VBoxServiceVerbose(3, "[PID %RU32]: Disconnecting (client ID=%u) ...\n",
    17621751                           pProcess->uPID, pProcess->uClientID);
    17631752        VbglR3GuestCtrlDisconnect(pProcess->uClientID);
     
    17651754    }
    17661755
    1767     VBoxServiceVerbose(3, "[PID %u]: Thread of process \"%s\" ended with rc=%Rrc\n",
    1768                        pProcess->uPID, pProcess->pszCmd, rc);
     1756    VBoxServiceVerbose(3, "[PID %RU32]: Thread of process \"%s\" ended with rc=%Rrc\n",
     1757                       pProcess->uPID, pProcess->StartupInfo.szCmd, rc);
     1758
     1759    /* Free argument + environment variable lists. */
     1760    if (uNumEnvVars)
     1761    {
     1762        for (uint32_t i = 0; i < uNumEnvVars; i++)
     1763            RTStrFree(papszEnv[i]);
     1764        RTMemFree(papszEnv);
     1765    }
     1766    if (uNumArgs)
     1767        RTGetOptArgvFree(papszArgs);
    17691768
    17701769    /* Update started/stopped status. */
     
    17791778        RTThreadUserSignal(RTThreadSelf());
    17801779
     1780    VBoxServiceVerbose(3, "[PID %RU32]: Thread returned with rc=%Rrc\n",
     1781                       pProcess->uPID, rc);
    17811782    return rc;
    17821783}
     
    18671868 * Performs a request to a specific (formerly started) guest process and waits
    18681869 * for its response.
    1869  * Note: Caller is responsible of locking!
     1870 * Note: Caller is responsible for locking!
    18701871 *
    18711872 * @return  IPRT status code.
     
    18891890    else
    18901891    {
     1892        VBoxServiceVerbose(3, "[PID %RU32]: Sending pRequest=%p\n",
     1893                           pProcess->uPID, pRequest);
     1894
    18911895        /* Set request structure pointer. */
    18921896        pProcess->pRequest = pRequest;
     
    18941898        /** @todo To speed up simultaneous guest process handling we could add a worker threads
    18951899         *        or queue in order to wait for the request to happen. Later. */
    1896         /* Wake up guest thrad by sending a wakeup byte to the notification pipe so
     1900        /* Wake up guest thread by sending a wakeup byte to the notification pipe so
    18971901         * that RTPoll unblocks (returns) and we then can do our requested operation. */
    18981902        Assert(pProcess->hNotificationPipeW != NIL_RTPIPE);
    1899         size_t cbWritten;
     1903        size_t cbWritten = 0;
    19001904        if (RT_SUCCESS(rc))
    19011905            rc = RTPipeWrite(pProcess->hNotificationPipeW, "i", 1, &cbWritten);
    19021906
    1903         if (   RT_SUCCESS(rc)
    1904             && cbWritten)
    1905         {
    1906             VBoxServiceVerbose(3, "[PID %u]: Waiting for response on enmType=%u, pvData=0x%p, cbData=%u\n",
    1907                                pProcess->uPID, pRequest->enmType, pRequest->pvData, pRequest->cbData);
     1907        if (RT_SUCCESS(rc))
     1908        {
     1909            Assert(cbWritten);
     1910            VBoxServiceVerbose(3, "[PID %RU32]: Waiting for response on pRequest=%p, enmType=%u, pvData=0x%p, cbData=%u\n",
     1911                               pProcess->uPID, pRequest, pRequest->enmType, pRequest->pvData, pRequest->cbData);
    19081912
    19091913            rc = GstCntlProcessRequestWait(pRequest);
     
    19111915    }
    19121916
    1913     VBoxServiceVerbose(3, "[PID %u]: Performed enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n",
    1914                        pProcess->uPID, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc);
     1917    VBoxServiceVerbose(3, "[PID %RU32]: Performed pRequest=%p, enmType=%u, uCID=%u, pvData=0x%p, cbData=%u, rc=%Rrc\n",
     1918                       pProcess->uPID, pRequest, pRequest->enmType, pRequest->uCID, pRequest->pvData, pRequest->cbData, rc);
    19151919    return rc;
    19161920}
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp

    r45109 r45415  
    7070    VBOXSERVICESESSIONOPT_USERNAME,
    7171    VBOXSERVICESESSIONOPT_SESSION_ID,
    72     VBOXSERVICESESSIONOPT_SESSION_PROTO
     72    VBOXSERVICESESSIONOPT_SESSION_PROTO,
     73    VBOXSERVICESESSIONOPT_THREAD_ID
    7374};
    7475
     
    568569        if (RT_SUCCESS(rc))
    569570        {
    570             VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, szUser=%s, szPassword=%s, uTimeout=%RU32\n",
     571            VBoxServiceVerbose(3, "Request to start process szCmd=%s, uFlags=0x%x, szArgs=%s, szEnv=%s, uTimeout=%RU32\n",
    571572                               startupInfo.szCmd, startupInfo.uFlags,
    572573                               startupInfo.uNumArgs ? startupInfo.szArgs : "<None>",
    573574                               startupInfo.uNumEnvVars ? startupInfo.szEnv : "<None>",
    574                                startupInfo.szUser,
    575 #ifdef DEBUG
    576                                startupInfo.szPassword,
    577 #else
    578                                "XXX", /* Never show passwords in release mode. */
    579 #endif
    580575                               startupInfo.uTimeLimitMS);
    581576
    582             rc = GstCntlSessionReapProcesses(pSession);
     577            /*rc = GstCntlSessionReapProcesses(pSession);
    583578            if (RT_FAILURE(rc))
    584                 VBoxServiceError("Reaping stopped guest processes failed with rc=%Rrc\n", rc);
     579                VBoxServiceError("Reaping stopped guest processes failed with rc=%Rrc\n", rc);*/
    585580            /* Keep going. */
    586581
     
    741736
    742737    int rc = VbglR3GuestCtrlProcGetOutput(pHostCtx, &uPID, &uHandleID, &uFlags);
     738#ifdef DEBUG_andy
     739    VBoxServiceVerbose(4, "[PID %RU32]: Get output CID=%RU32, uHandleID=%RU32, uFlags=%RU32\n",
     740                       uPID, pHostCtx->uContextID, uHandleID, uFlags);
     741#endif
    743742    if (RT_SUCCESS(rc))
    744743    {
     
    750749                                         pHostCtx->uContextID, uHandleID, RT_INDEFINITE_WAIT /* Timeout */,
    751750                                         pBuf, _64K /* cbSize */, &cbRead);
    752             VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=%u, cbRead=%u, uHandle=%u, uFlags=%u\n",
     751            VBoxServiceVerbose(3, "[PID %RU32]: Got output, rc=%Rrc, CID=%RU32, cbRead=%RU32, uHandle=%RU32, uFlags=%x\n",
    753752                               uPID, rc, pHostCtx->uContextID, cbRead, uHandleID, uFlags);
    754753
     
    973972
    974973        default:
    975             VBoxServiceVerbose(3, "Unsupported message from host, uMsg=%RU32, cParms=%RU32\n",
     974            rc = VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID);
     975            VBoxServiceVerbose(3, "Unsupported message (uMsg=%RU32, cParms=%RU32) from host, skipping\n",
    976976                               uMsg, pHostCtx->uNumParms);
    977             /* Don't terminate here; just wait for the next message. */
    978977            break;
    979978    }
     
    10081007    }
    10091008    else
     1009    {
    10101010        VBoxServiceError("Error connecting to guest control service, rc=%Rrc\n", rc);
     1011        return rc;
     1012    }
    10111013
    10121014    /* Let caller know that we're done initializing. */
    1013     int rc2 = RTThreadUserSignal(RTThreadSelf());
    1014     if (RT_SUCCESS(rc))
    1015         rc = rc2;
     1015    rc = RTThreadUserSignal(RTThreadSelf());
     1016    if (RT_FAILURE(rc))
     1017        return rc;
    10161018
    10171019    bool fProcessAlive = true;
     
    10191021    RT_ZERO(ProcessStatus);
    10201022
     1023    int rcWait;
    10211024    if (RT_SUCCESS(rc))
    10221025    {
     
    10241027        uint64_t u64TimeoutStart = 0;
    10251028
    1026         int rcWait;
    10271029        for (;;)
    10281030        {
     
    10481050                                       uSessionID);
    10491051                    u64TimeoutStart = RTTimeMilliTS();
     1052                    continue; /* Don't waste time on waiting. */
    10501053                }
    10511054                if (RTTimeMilliTS() - u64TimeoutStart > uTimeoutsMS)
     
    10841087        }
    10851088
    1086         VBoxServiceVerbose(2, "Guest session ID=%RU32 process has been killed with rc=%Rc\n",
     1089        VBoxServiceVerbose(2, "Guest session ID=%RU32 process termination resulted in rc=%Rrc\n",
    10871090                           uSessionID, rc);
    10881091
     
    10921095    else
    10931096    {
    1094         switch (ProcessStatus.enmReason)
    1095         {
    1096             case RTPROCEXITREASON_NORMAL:
    1097                 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN;
    1098                 break;
    1099 
    1100             case RTPROCEXITREASON_ABEND:
    1101                 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA;
    1102                 break;
    1103 
    1104             case RTPROCEXITREASON_SIGNAL:
    1105                 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TES;
    1106                 break;
    1107 
    1108             default:
    1109                 AssertMsgFailed(("Unhandled process termination reason (%ld)",
    1110                                  ProcessStatus.enmReason));
    1111                 uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA;
    1112                 break;
    1113         }
    1114     }
    1115 
    1116     VBoxServiceVerbose(3, "Guest session ID=%RU32 thread ended with sessionStatus=%ld, sessionRc=%Rrc\n",
     1097        if (RT_SUCCESS(rcWait))
     1098        {
     1099            switch (ProcessStatus.enmReason)
     1100            {
     1101                case RTPROCEXITREASON_NORMAL:
     1102                    uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN;
     1103                    break;
     1104
     1105                case RTPROCEXITREASON_ABEND:
     1106                    uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA;
     1107                    break;
     1108
     1109                case RTPROCEXITREASON_SIGNAL:
     1110                    uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TES;
     1111                    break;
     1112
     1113                default:
     1114                    AssertMsgFailed(("Unhandled process termination reason (%ld)\n",
     1115                                     ProcessStatus.enmReason));
     1116                    uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEA;
     1117                    break;
     1118            }
     1119        }
     1120        else
     1121        {
     1122            /* If we didn't find the guest process anymore, just assume it
     1123             * terminated normally. */
     1124            uSessionStatus = GUEST_SESSION_NOTIFYTYPE_TEN;
     1125        }
     1126    }
     1127
     1128    VBoxServiceVerbose(3, "Guest session ID=%RU32 thread ended with sessionStatus=%RU32, sessionRc=%Rrc\n",
    11171129                       uSessionID, uSessionStatus, uSessionRc);
    11181130
     
    11201132    Assert(uSessionStatus != GUEST_SESSION_NOTIFYTYPE_UNDEFINED);
    11211133    VBGLR3GUESTCTRLCMDCTX ctx = { uClientID, VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSessionID) };
    1122     rc2 = VbglR3GuestCtrlSessionNotify(&ctx,
    1123                                        uSessionStatus, uSessionRc);
     1134    int rc2 = VbglR3GuestCtrlSessionNotify(&ctx,
     1135                                           uSessionStatus, uSessionRc);
    11241136    if (RT_FAILURE(rc2))
    11251137        VBoxServiceError("Reporting session ID=%RU32 final status failed with rc=%Rrc\n",
     
    12541266    AssertPtrReturn(pSession, NULL);
    12551267
    1256     PVBOXSERVICECTRLPROCESS pThread = NULL;
    1257     int rc = RTCritSectEnter(&pSession->csControlThreads);
    1258     if (RT_SUCCESS(rc))
    1259     {
    1260         PVBOXSERVICECTRLPROCESS pThreadCur;
    1261         RTListForEach(&pSession->lstControlThreadsActive, pThreadCur, VBOXSERVICECTRLPROCESS, Node)
    1262         {
    1263             if (pThreadCur->uPID == uPID)
    1264             {
    1265                 rc = RTCritSectEnter(&pThreadCur->CritSect);
     1268    PVBOXSERVICECTRLPROCESS pProcess = NULL;
     1269    int rc = RTCritSectEnter(&pSession->CritSect);
     1270    if (RT_SUCCESS(rc))
     1271    {
     1272        PVBOXSERVICECTRLPROCESS pCurProcess;
     1273        RTListForEach(&pSession->lstProcessesActive, pCurProcess, VBOXSERVICECTRLPROCESS, Node)
     1274        {
     1275            if (pCurProcess->uPID == uPID)
     1276            {
     1277                rc = RTCritSectEnter(&pCurProcess->CritSect);
    12661278                if (RT_SUCCESS(rc))
    1267                     pThread = pThreadCur;
     1279                    pProcess = pCurProcess;
    12681280                break;
    12691281            }
    12701282        }
    12711283
    1272         int rc2 = RTCritSectLeave(&pSession->csControlThreads);
     1284        int rc2 = RTCritSectLeave(&pSession->CritSect);
    12731285        if (RT_SUCCESS(rc))
    12741286            rc = rc2;
    12751287    }
    12761288
    1277     return pThread;
     1289    return pProcess;
    12781290}
    12791291
     
    12861298                       pSession->StartupInfo.uSessionID);
    12871299
    1288     /*
    1289      * Close all guest processes.
    1290      */
    1291 
    1292     /* Signal all guest processes in the active list that we want to shutdown. */
    1293     PVBOXSERVICECTRLPROCESS pProcess;
    1294     RTListForEach(&pSession->lstControlThreadsActive, pProcess, VBOXSERVICECTRLPROCESS, Node)
    1295         GstCntlProcessStop(pProcess);
    1296 
    1297     /* Wait for all active threads to shutdown and destroy the active thread list. */
    1298     pProcess = RTListGetFirst(&pSession->lstControlThreadsActive, VBOXSERVICECTRLPROCESS, Node);
    1299     while (pProcess)
    1300     {
    1301         PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node);
    1302         bool fLast = RTListNodeIsLast(&pSession->lstControlThreadsActive, &pProcess->Node);
    1303 
    1304         int rc2 = GstCntlProcessWait(pProcess,
    1305                                      30 * 1000 /* Wait 30 seconds max. */,
    1306                                      NULL /* rc */);
    1307         if (RT_FAILURE(rc2))
    1308         {
    1309             VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2);
    1310             /* Keep going. */
    1311         }
    1312 
    1313         if (fLast)
    1314             break;
    1315 
    1316         pProcess = pNext;
    1317     }
    1318 
    1319     int rc = GstCntlSessionReapProcesses(pSession);
    1320     if (RT_FAILURE(rc))
    1321         VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc);
    1322 
    1323     AssertMsg(RTListIsEmpty(&pSession->lstControlThreadsActive),
    1324               ("Guest process active thread list still contains entries when it should not\n"));
    1325     AssertMsg(RTListIsEmpty(&pSession->lstControlThreadsInactive),
    1326               ("Guest process inactive thread list still contains entries when it should not\n"));
    1327 
    1328     /*
    1329      * Close all left guest files.
    1330      */
    1331     PVBOXSERVICECTRLFILE pFile;
    1332     pFile = RTListGetFirst(&pSession->lstFiles, VBOXSERVICECTRLFILE, Node);
    1333     while (pFile)
    1334     {
    1335         PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node);
    1336         bool fLast = RTListNodeIsLast(&pSession->lstFiles, &pFile->Node);
    1337 
    1338         int rc2 = gstcntlSessionFileDestroy(pFile);
    1339         if (RT_FAILURE(rc2))
    1340         {
    1341             VBoxServiceError("Unable to close file \"%s\"; rc=%Rrc\n",
    1342                              pFile->szName, rc2);
    1343             /* Keep going. */
    1344         }
    1345 
    1346         if (fLast)
    1347             break;
    1348 
    1349         pFile = pNext;
    1350     }
    1351 
    1352     AssertMsg(RTListIsEmpty(&pSession->lstFiles),
    1353               ("Guest file list still contains entries when it should not\n"));
     1300    int rc = RTCritSectEnter(&pSession->CritSect);
     1301    if (RT_SUCCESS(rc))
     1302    {
     1303        /*
     1304         * Close all guest processes.
     1305         */
     1306
     1307        /* Signal all guest processes in the active list that we want to shutdown. */
     1308        PVBOXSERVICECTRLPROCESS pProcess;
     1309        RTListForEach(&pSession->lstProcessesActive, pProcess, VBOXSERVICECTRLPROCESS, Node)
     1310            GstCntlProcessStop(pProcess);
     1311
     1312        /* Wait for all active threads to shutdown and destroy the active thread list. */
     1313        pProcess = RTListGetFirst(&pSession->lstProcessesActive, VBOXSERVICECTRLPROCESS, Node);
     1314        while (pProcess)
     1315        {
     1316            PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pProcess->Node, VBOXSERVICECTRLPROCESS, Node);
     1317            bool fLast = RTListNodeIsLast(&pSession->lstProcessesActive, &pProcess->Node);
     1318
     1319            int rc2 = GstCntlProcessWait(pProcess,
     1320                                         30 * 1000 /* Wait 30 seconds max. */,
     1321                                         NULL /* rc */);
     1322            if (RT_FAILURE(rc2))
     1323            {
     1324                VBoxServiceError("Guest process thread failed to stop; rc=%Rrc\n", rc2);
     1325                if (RT_SUCCESS(rc))
     1326                    rc = rc2;
     1327                /* Keep going. */
     1328            }
     1329
     1330            rc2 = GstCntlProcessFree(pProcess);
     1331            if (RT_FAILURE(rc2))
     1332            {
     1333                VBoxServiceError("Guest process thread failed to free; rc=%Rrc\n", rc2);
     1334                if (RT_SUCCESS(rc))
     1335                    rc = rc2;
     1336                /* Keep going. */
     1337            }
     1338
     1339            RTListNodeRemove(&pProcess->Node);
     1340
     1341            if (fLast)
     1342                break;
     1343
     1344            pProcess = pNext;
     1345        }
     1346
     1347        /*rc = GstCntlSessionReapProcesses(pSession);
     1348        if (RT_FAILURE(rc))
     1349            VBoxServiceError("Reaping inactive threads failed with rc=%Rrc\n", rc);*/
     1350
     1351        AssertMsg(RTListIsEmpty(&pSession->lstProcessesActive),
     1352                  ("Guest process active thread list still contains entries when it should not\n"));
     1353        /*AssertMsg(RTListIsEmpty(&pSession->lstProcessesInactive),
     1354                  ("Guest process inactive thread list still contains entries when it should not\n"));*/
     1355
     1356        /*
     1357         * Close all left guest files.
     1358         */
     1359        PVBOXSERVICECTRLFILE pFile;
     1360        pFile = RTListGetFirst(&pSession->lstFiles, VBOXSERVICECTRLFILE, Node);
     1361        while (pFile)
     1362        {
     1363            PVBOXSERVICECTRLFILE pNext = RTListNodeGetNext(&pFile->Node, VBOXSERVICECTRLFILE, Node);
     1364            bool fLast = RTListNodeIsLast(&pSession->lstFiles, &pFile->Node);
     1365
     1366            int rc2 = gstcntlSessionFileDestroy(pFile);
     1367            if (RT_FAILURE(rc2))
     1368            {
     1369                VBoxServiceError("Unable to close file \"%s\"; rc=%Rrc\n",
     1370                                 pFile->szName, rc2);
     1371                if (RT_SUCCESS(rc))
     1372                    rc = rc2;
     1373                /* Keep going. */
     1374            }
     1375
     1376            if (fLast)
     1377                break;
     1378
     1379            pFile = pNext;
     1380        }
     1381
     1382        AssertMsg(RTListIsEmpty(&pSession->lstFiles),
     1383                  ("Guest file list still contains entries when it should not\n"));
     1384
     1385        int rc2 = RTCritSectLeave(&pSession->CritSect);
     1386        if (RT_SUCCESS(rc))
     1387            rc = rc2;
     1388    }
    13541389
    13551390    return rc;
     
    13641399
    13651400    /* Destroy critical section. */
    1366     RTCritSectDelete(&pSession->csControlThreads);
     1401    RTCritSectDelete(&pSession->CritSect);
    13671402
    13681403    return rc;
     
    14411476    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    14421477
    1443     RTListInit(&pSession->lstControlThreadsActive);
    1444     RTListInit(&pSession->lstControlThreadsInactive);
     1478    RTListInit(&pSession->lstProcessesActive);
     1479    RTListInit(&pSession->lstProcessesInactive);
    14451480    RTListInit(&pSession->lstFiles);
    14461481
     
    14571492
    14581493    /* Init critical section for protecting the thread lists. */
    1459     int rc = RTCritSectInit(&pSession->csControlThreads);
     1494    int rc = RTCritSectInit(&pSession->CritSect);
    14601495    AssertRC(rc);
    14611496
     
    14811516    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
    14821517
    1483     int rc = RTCritSectEnter(&pSession->csControlThreads);
     1518    int rc = RTCritSectEnter(&pSession->CritSect);
    14841519    if (RT_SUCCESS(rc))
    14851520    {
     
    14911526        {
    14921527            case VBOXSERVICECTRLTHREADLIST_STOPPED:
    1493                 pAnchor = &pSession->lstControlThreadsInactive;
     1528                pAnchor = &pSession->lstProcessesInactive;
    14941529                break;
    14951530
    14961531            case VBOXSERVICECTRLTHREADLIST_RUNNING:
    1497                 pAnchor = &pSession->lstControlThreadsActive;
     1532                pAnchor = &pSession->lstProcessesActive;
    14981533                break;
    14991534
    15001535            default:
    1501                 AssertMsgFailed(("Unknown list type: %u", enmList));
     1536                AssertMsgFailed(("Unknown list type: %u\n",
     1537                                 enmList));
    15021538                break;
    15031539        }
     
    15201556        }
    15211557
    1522         int rc2 = RTCritSectLeave(&pSession->csControlThreads);
     1558        int rc2 = RTCritSectLeave(&pSession->CritSect);
    15231559        if (RT_SUCCESS(rc))
    15241560            rc = rc2;
     
    15461582    AssertPtrReturn(pbAllowed, VERR_INVALID_POINTER);
    15471583
    1548     int rc = RTCritSectEnter(&pSession->csControlThreads);
     1584    int rc = RTCritSectEnter(&pSession->CritSect);
    15491585    if (RT_SUCCESS(rc))
    15501586    {
     
    15571593        {
    15581594            uint32_t uProcsRunning = 0;
    1559             PVBOXSERVICECTRLPROCESS pThread;
    1560             RTListForEach(&pSession->lstControlThreadsActive, pThread, VBOXSERVICECTRLPROCESS, Node)
     1595            PVBOXSERVICECTRLPROCESS pProcess;
     1596            RTListForEach(&pSession->lstProcessesActive, pProcess, VBOXSERVICECTRLPROCESS, Node)
    15611597                uProcsRunning++;
    15621598
     
    15751611        *pbAllowed = !fLimitReached;
    15761612
    1577         int rc2 = RTCritSectLeave(&pSession->csControlThreads);
     1613        int rc2 = RTCritSectLeave(&pSession->CritSect);
    15781614        if (RT_SUCCESS(rc))
    15791615            rc = rc2;
     
    15831619}
    15841620
    1585 
     1621#if 0
    15861622/**
    15871623 * Reaps all inactive guest process threads.
     1624 * Does not do locking; this is the job of the caller.
    15881625 *
    15891626 * @return  IPRT status code.
     
    15931630    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    15941631
    1595     int rc = RTCritSectEnter(&pSession->csControlThreads);
    1596     if (RT_SUCCESS(rc))
    1597     {
    1598         PVBOXSERVICECTRLPROCESS pThread =
    1599             RTListGetFirst(&pSession->lstControlThreadsInactive, VBOXSERVICECTRLPROCESS, Node);
    1600         while (pThread)
    1601         {
    1602             PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLPROCESS, Node);
    1603             bool fLast = RTListNodeIsLast(&pSession->lstControlThreadsInactive, &pThread->Node);
    1604             int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */,
    1605                                          NULL /* rc */);
    1606             if (RT_SUCCESS(rc2))
    1607             {
    1608                 RTListNodeRemove(&pThread->Node);
    1609 
    1610                 rc2 = GstCntlProcessFree(pThread);
    1611                 if (RT_FAILURE(rc2))
    1612                 {
    1613                     VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2);
    1614                     if (RT_SUCCESS(rc)) /* Keep original failure. */
    1615                         rc = rc2;
    1616                 }
    1617             }
    1618             else
    1619                 VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2);
    1620             /* Keep going. */
    1621 
    1622             if (fLast)
    1623                 break;
    1624 
    1625             pThread = pNext;
    1626         }
    1627 
    1628         int rc2 = RTCritSectLeave(&pSession->csControlThreads);
    1629         if (RT_SUCCESS(rc))
    1630             rc = rc2;
     1632    PVBOXSERVICECTRLPROCESS pThread =
     1633        RTListGetFirst(&pSession->lstProcessesInactive, VBOXSERVICECTRLPROCESS, Node);
     1634    while (pThread)
     1635    {
     1636        PVBOXSERVICECTRLPROCESS pNext = RTListNodeGetNext(&pThread->Node, VBOXSERVICECTRLPROCESS, Node);
     1637        bool fLast = RTListNodeIsLast(&pSession->lstProcessesInactive, &pThread->Node);
     1638        int rc2 = GstCntlProcessWait(pThread, 30 * 1000 /* 30 seconds max. */,
     1639                                     NULL /* rc */);
     1640        if (RT_SUCCESS(rc2))
     1641        {
     1642            RTListNodeRemove(&pThread->Node);
     1643
     1644            rc2 = GstCntlProcessFree(pThread);
     1645            if (RT_FAILURE(rc2))
     1646            {
     1647                VBoxServiceError("Freeing guest process thread failed with rc=%Rrc\n", rc2);
     1648                if (RT_SUCCESS(rc)) /* Keep original failure. */
     1649                    rc = rc2;
     1650            }
     1651        }
     1652        else
     1653            VBoxServiceError("Waiting on guest process thread failed with rc=%Rrc\n", rc2);
     1654        /* Keep going. */
     1655
     1656        if (fLast)
     1657            break;
     1658
     1659        pThread = pNext;
    16311660    }
    16321661
     
    16341663    return rc;
    16351664}
     1665#endif
    16361666
    16371667
     
    17001730 *                                  Optional.
    17011731 */
    1702 int GstCntlSessionThreadOpen(PRTLISTANCHOR pList,
    1703                              const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo,
    1704                              PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread)
     1732int GstCntlSessionThreadCreate(PRTLISTANCHOR pList,
     1733                               const PVBOXSERVICECTRLSESSIONSTARTUPINFO pSessionStartupInfo,
     1734                               PVBOXSERVICECTRLSESSIONTHREAD *ppSessionThread)
    17051735{
    17061736    AssertPtrReturn(pList, VERR_INVALID_POINTER);
     
    17161746        if (pSessionCur->StartupInfo.uSessionID == pSessionStartupInfo->uSessionID)
    17171747        {
    1718             AssertMsgFailed(("Guest session %RU32 (%p) already exists when it should not",
     1748            AssertMsgFailed(("Guest session thread ID=%RU32 (%p) already exists when it should not\n",
    17191749                             pSessionCur->StartupInfo.uSessionID, pSessionCur));
    17201750            return VERR_ALREADY_EXISTS;
     
    17241754    int rc = VINF_SUCCESS;
    17251755
    1726     PVBOXSERVICECTRLSESSIONTHREAD pSession = (PVBOXSERVICECTRLSESSIONTHREAD)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSIONTHREAD));
    1727     if (pSession)
     1756    /* Static counter to help tracking session thread <-> process relations. */
     1757    static uint32_t s_uCtrlSessionThread = 0;
     1758    if (s_uCtrlSessionThread++ == UINT32_MAX)
     1759        s_uCtrlSessionThread = 0; /* Wrap around to not let IPRT freak out. */
     1760
     1761    PVBOXSERVICECTRLSESSIONTHREAD pSessionThread =
     1762        (PVBOXSERVICECTRLSESSIONTHREAD)RTMemAllocZ(sizeof(VBOXSERVICECTRLSESSIONTHREAD));
     1763    if (pSessionThread)
    17281764    {
    17291765        /* Copy over session startup info. */
    1730         memcpy(&pSession->StartupInfo, pSessionStartupInfo, sizeof(VBOXSERVICECTRLSESSIONSTARTUPINFO));
    1731 
    1732         pSession->fShutdown = false;
    1733         pSession->fStarted  = false;
    1734         pSession->fStopped  = false;
     1766        memcpy(&pSessionThread->StartupInfo, pSessionStartupInfo,
     1767               sizeof(VBOXSERVICECTRLSESSIONSTARTUPINFO));
     1768
     1769        pSessionThread->fShutdown = false;
     1770        pSessionThread->fStarted  = false;
     1771        pSessionThread->fStopped  = false;
    17351772
    17361773        /* Is this an anonymous session? */
    17371774        /* Anonymous sessions run with the same privileges as the main VBoxService executable. */
    1738         bool fAnonymous = !RT_BOOL(strlen(pSession->StartupInfo.szUser));
     1775        bool fAnonymous = !RT_BOOL(strlen(pSessionThread->StartupInfo.szUser));
    17391776        if (fAnonymous)
    17401777        {
    1741             Assert(!strlen(pSession->StartupInfo.szPassword));
    1742             Assert(!strlen(pSession->StartupInfo.szDomain));
     1778            Assert(!strlen(pSessionThread->StartupInfo.szPassword));
     1779            Assert(!strlen(pSessionThread->StartupInfo.szDomain));
    17431780
    17441781            VBoxServiceVerbose(3, "New anonymous guest session ID=%RU32 created, uFlags=%x, using protocol %RU32\n",
     
    17621799        }
    17631800
    1764         rc = RTCritSectInit(&pSession->CritSect);
     1801        rc = RTCritSectInit(&pSessionThread->CritSect);
    17651802        AssertRC(rc);
    17661803
     
    17731810            if (!fAnonymous)
    17741811            {
    1775                 if (!RTStrPrintf(szParmUserName, sizeof(szParmUserName), "--username=%s", pSession->StartupInfo.szUser))
     1812                if (!RTStrPrintf(szParmUserName, sizeof(szParmUserName), "--user=%s", pSessionThread->StartupInfo.szUser))
    17761813                    rc = VERR_BUFFER_OVERFLOW;
    17771814            }
    17781815            char szParmSessionID[32];
    17791816            if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionID, sizeof(szParmSessionID), "--session-id=%RU32",
    1780                                                pSession->StartupInfo.uSessionID))
     1817                                               pSessionThread->StartupInfo.uSessionID))
    17811818            {
    17821819                rc = VERR_BUFFER_OVERFLOW;
     
    17841821            char szParmSessionProto[32];
    17851822            if (RT_SUCCESS(rc) && !RTStrPrintf(szParmSessionProto, sizeof(szParmSessionProto), "--session-proto=%RU32",
    1786                                                pSession->StartupInfo.uProtocol))
     1823                                               pSessionThread->StartupInfo.uProtocol))
    17871824            {
    17881825                rc = VERR_BUFFER_OVERFLOW;
    17891826            }
    1790 
     1827#ifdef DEBUG
     1828            char szParmThreadId[32];
     1829            if (RT_SUCCESS(rc) && !RTStrPrintf(szParmThreadId, sizeof(szParmThreadId), "--thread-id=%RU32",
     1830                                               s_uCtrlSessionThread))
     1831            {
     1832                rc = VERR_BUFFER_OVERFLOW;
     1833            }
     1834#endif /* DEBUG */
    17911835            if (RT_SUCCESS(rc))
    17921836            {
    17931837                int iOptIdx = 0; /* Current index in argument vector. */
    17941838
    1795                 char const *papszArgs[8];
     1839                char const *papszArgs[16];
    17961840                papszArgs[iOptIdx++] = pszExeName;
    17971841                papszArgs[iOptIdx++] = "guestsession";
    17981842                papszArgs[iOptIdx++] = szParmSessionID;
    17991843                papszArgs[iOptIdx++] = szParmSessionProto;
     1844#ifdef DEBUG
     1845                papszArgs[iOptIdx++] = szParmThreadId;
     1846#endif /* DEBUG */
    18001847                if (!fAnonymous)
    18011848                    papszArgs[iOptIdx++] = szParmUserName;
     
    18291876                        RTPathStripExt(pszLogFile);
    18301877                        char *pszLogSuffix;
     1878#ifndef DEBUG
    18311879                        if (RTStrAPrintf(&pszLogSuffix, "-%RU32-%s",
    18321880                                         pSessionStartupInfo->uSessionID,
     
    18351883                            rc2 = VERR_NO_MEMORY;
    18361884                        }
     1885#else
     1886                        if (RTStrAPrintf(&pszLogSuffix, "-%RU32-%RU32-%s",
     1887                                         pSessionStartupInfo->uSessionID,
     1888                                         s_uCtrlSessionThread,
     1889                                         pSessionStartupInfo->szUser) < 0)
     1890                        {
     1891                            rc2 = VERR_NO_MEMORY;
     1892                        }
     1893#endif /* DEBUG */
    18371894                        else
    18381895                        {
     
    19401997                        hStdOutAndErr.enmType = RTHANDLETYPE_FILE;
    19411998
    1942                         /** @todo Do we need a custom/cloned environment block? */
     1999                        /** @todo Set custom/cloned guest session environment block. */
    19432000                        rc = RTProcCreateEx(pszExeName, papszArgs, RTENV_DEFAULT, uProcFlags,
    19442001                                            &hStdIn, &hStdOutAndErr, &hStdOutAndErr,
    1945                                             !fAnonymous ? pSession->StartupInfo.szUser : NULL,
    1946                                             !fAnonymous ? pSession->StartupInfo.szPassword : NULL,
    1947                                             &pSession->hProcess);
     2002                                            !fAnonymous ? pSessionThread->StartupInfo.szUser : NULL,
     2003                                            !fAnonymous ? pSessionThread->StartupInfo.szPassword : NULL,
     2004                                            &pSessionThread->hProcess);
    19482005
    19492006                        RTFileClose(hStdOutAndErr.u.hFile);
    19502007                    }
    19512008
    1952                     RTFileClose(hStdOutAndErr.u.hFile);
     2009                    RTFileClose(hStdIn.u.hFile);
    19532010                }
    19542011#endif
     
    19612018        {
    19622019            /* Start session thread. */
    1963             static uint32_t s_uCtrlSessionThread = 0;
    1964             if (s_uCtrlSessionThread++ == UINT32_MAX)
    1965                 s_uCtrlSessionThread = 0; /* Wrap around to not let IPRT freak out. */
    1966             rc = RTThreadCreateF(&pSession->Thread, gstcntlSessionThread,
    1967                                  pSession /*pvUser*/, 0 /*cbStack*/,
     2020            rc = RTThreadCreateF(&pSessionThread->Thread, gstcntlSessionThread,
     2021                                 pSessionThread /*pvUser*/, 0 /*cbStack*/,
    19682022                                 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "sess%u", s_uCtrlSessionThread);
    19692023            if (RT_FAILURE(rc))
     
    19742028            {
    19752029                /* Wait for the thread to initialize. */
    1976                 rc = RTThreadUserWait(pSession->Thread, 60 * 1000 /* 60s timeout */);
    1977                 AssertRC(rc);
    1978                 if (   ASMAtomicReadBool(&pSession->fShutdown)
     2030                rc = RTThreadUserWait(pSessionThread->Thread, 60 * 1000 /* 60s timeout */);
     2031                if (   ASMAtomicReadBool(&pSessionThread->fShutdown)
    19792032                    || RT_FAILURE(rc))
    19802033                {
    19812034                    VBoxServiceError("Thread for session ID=%RU32 failed to start, rc=%Rrc\n",
    1982                                      pSession->StartupInfo.uSessionID, rc);
     2035                                     pSessionThread->StartupInfo.uSessionID, rc);
    19832036                    if (RT_SUCCESS(rc))
    19842037                        rc = VERR_CANT_CREATE; /** @todo Find a better rc. */
     
    19862039                else
    19872040                {
    1988                     ASMAtomicXchgBool(&pSession->fStarted, true);
     2041                    VBoxServiceVerbose(2, "Thread for session ID=%RU32 started\n",
     2042                                       pSessionThread->StartupInfo.uSessionID);
     2043
     2044                    ASMAtomicXchgBool(&pSessionThread->fStarted, true);
    19892045
    19902046                    /* Add session to list. */
    1991                     /* rc = */ RTListAppend(pList, &pSession->Node);
     2047                    /* rc = */ RTListAppend(pList, &pSessionThread->Node);
    19922048                    if (ppSessionThread) /* Return session if wanted. */
    1993                         *ppSessionThread = pSession;
     2049                        *ppSessionThread = pSessionThread;
    19942050                }
    19952051            }
     
    19982054        if (RT_FAILURE(rc))
    19992055        {
    2000             RTMemFree(pSession);
     2056            RTMemFree(pSessionThread);
    20012057        }
    20022058    }
     
    20042060        rc = VERR_NO_MEMORY;
    20052061
    2006     VBoxServiceVerbose(3, "Forking returned returned rc=%Rrc\n", rc);
     2062    VBoxServiceVerbose(3, "Forking session thread returned returned rc=%Rrc\n", rc);
    20072063    return rc;
    20082064}
     
    20102066
    20112067/**
    2012  * Closes a formerly opened guest session and removes it from
    2013  * the session list.
     2068 * Waits for a formerly opened guest session process to close.
    20142069 *
    20152070 * @return  IPRT status code.
    2016  * @param   pThread                 Guest session thread to close.
     2071 * @param   pThread                 Guest session thread to wait for.
     2072 * @param   uTimeoutMS              Waiting timeout (in ms).
    20172073 * @param   uFlags                  Closing flags.
    20182074 */
    2019 int GstCntlSessionThreadClose(PVBOXSERVICECTRLSESSIONTHREAD pThread, uint32_t uFlags)
     2075int GstCntlSessionThreadWait(PVBOXSERVICECTRLSESSIONTHREAD pThread,
     2076                             uint32_t uTimeoutMS, uint32_t uFlags)
    20202077{
    20212078    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     
    20242081    if (pThread->Thread == NIL_RTTHREAD)
    20252082    {
    2026         AssertMsgFailed(("Guest session thread of session %p does not exist when it should",
     2083        AssertMsgFailed(("Guest session thread of session %p does not exist when it should\n",
    20272084                         pThread));
    20282085        return VERR_NOT_FOUND;
     
    20312088    int rc = VINF_SUCCESS;
    20322089
    2033     /* The fork should have received the same closing request,
     2090    /*
     2091     * The fork should have received the same closing request,
    20342092     * so just wait 30s for the process to close. On timeout kill
    2035      * it in a not so gentle manner. */
     2093     * it in a not so gentle manner.
     2094     */
    20362095    if (ASMAtomicReadBool(&pThread->fStarted))
    20372096    {
     
    20392098        ASMAtomicXchgBool(&pThread->fShutdown, true);
    20402099
    2041         uint32_t cMsTimeout = 30 * 1000; /** @todo 30s default. Make this configurable. Later. */
    2042 
    20432100        VBoxServiceVerbose(3, "Waiting for session thread ID=%RU32 to close (%RU32ms) ...\n",
    2044                            pThread->StartupInfo.uSessionID, cMsTimeout);
     2101                           pThread->StartupInfo.uSessionID, uTimeoutMS);
    20452102
    20462103        int rcThread;
    2047         rc = RTThreadWait(pThread->Thread, cMsTimeout, &rcThread);
     2104        rc = RTThreadWait(pThread->Thread, uTimeoutMS, &rcThread);
    20482105        if (RT_FAILURE(rc))
    20492106        {
     
    20542111            VBoxServiceVerbose(3, "Session thread ID=%RU32 ended with rc=%Rrc\n",
    20552112                               pThread->StartupInfo.uSessionID, rcThread);
    2056 
    2057         /* Remove session from list and destroy object. */
    2058         RTListNodeRemove(&pThread->Node);
    2059 
    2060         if (RT_FAILURE(rc))
    2061             VBoxServiceError("Closing session ID=%RU32 failed with rc=%Rrc\n",
    2062                              pThread->StartupInfo.uSessionID, rc);
    2063 
    2064         RTMemFree(pThread);
    2065         pThread = NULL;
    2066     }
    2067 
    2068     return rc;
    2069 }
    2070 
     2113    }
     2114
     2115    return rc;
     2116}
     2117
     2118/**
     2119 * Waits for the specified session thread to end and remove
     2120 * it from the session thread list.
     2121 *
     2122 * @return  IPRT status code.
     2123 * @param   pThread                 Session thread to destroy.
     2124 * @param   uFlags                  Closing flags.
     2125 */
     2126int GstCntlSessionThreadDestroy(PVBOXSERVICECTRLSESSIONTHREAD pThread, uint32_t uFlags)
     2127{
     2128    AssertPtrReturn(pThread, VERR_INVALID_POINTER);
     2129
     2130    int rc = GstCntlSessionThreadWait(pThread,
     2131                                      30 * 1000 /* 30s timeout */, uFlags);
     2132    /** @todo Kill session process if still around? */
     2133
     2134    /* Remove session from list and destroy object. */
     2135    RTListNodeRemove(&pThread->Node);
     2136    RTMemFree(pThread);
     2137
     2138    return rc;
     2139}
    20712140
    20722141/**
     
    20772146 * @param   uFlags                  Closing flags.
    20782147 */
    2079 int GstCntlSessionThreadCloseAll(PRTLISTANCHOR pList, uint32_t uFlags)
     2148int GstCntlSessionThreadDestroyAll(PRTLISTANCHOR pList, uint32_t uFlags)
    20802149{
    20812150    AssertPtrReturn(pList, VERR_INVALID_POINTER);
     
    20832152    int rc = VINF_SUCCESS;
    20842153
    2085     PVBOXSERVICECTRLSESSIONTHREAD pSessionCur
     2154    PVBOXSERVICECTRLSESSIONTHREAD pSessionThread
    20862155         = RTListGetFirst(pList, VBOXSERVICECTRLSESSIONTHREAD, Node);
    2087     while (pSessionCur)
    2088     {
    2089         PVBOXSERVICECTRLSESSIONTHREAD pSessionNext =
    2090             RTListGetNext(pList, pSessionCur, VBOXSERVICECTRLSESSIONTHREAD, Node);
    2091         bool fLast = RTListNodeIsLast(pList, &pSessionCur->Node);
    2092 
    2093         int rc2 = GstCntlSessionThreadClose(pSessionCur, uFlags);
    2094         if (RT_SUCCESS(rc))
    2095         {
    2096             rc = rc2;
     2156    while (pSessionThread)
     2157    {
     2158        PVBOXSERVICECTRLSESSIONTHREAD pSessionThreadNext =
     2159            RTListGetNext(pList, pSessionThread, VBOXSERVICECTRLSESSIONTHREAD, Node);
     2160        bool fLast = RTListNodeIsLast(pList, &pSessionThread->Node);
     2161
     2162        int rc2 = GstCntlSessionThreadDestroy(pSessionThread, uFlags);
     2163        if (RT_FAILURE(rc2))
     2164        {
     2165            VBoxServiceError("Closing session thread failed with rc=%Rrc\n", rc2);
     2166            if (RT_SUCCESS(rc))
     2167                rc = rc2;
    20972168            /* Keep going. */
    20982169        }
     
    21012172            break;
    21022173
    2103         pSessionCur = pSessionNext;
    2104     }
    2105 
    2106     return rc;
    2107 }
    2108 
     2174        pSessionThread = pSessionThreadNext;
     2175    }
     2176
     2177    return rc;
     2178}
    21092179
    21102180RTEXITCODE VBoxServiceControlSessionForkInit(int argc, char **argv)
     
    21132183    {
    21142184        { "--logfile",         VBOXSERVICESESSIONOPT_LOG_FILE,        RTGETOPT_REQ_STRING },
    2115         { "--username",        VBOXSERVICESESSIONOPT_USERNAME,        RTGETOPT_REQ_STRING },
     2185        { "--user",            VBOXSERVICESESSIONOPT_USERNAME,        RTGETOPT_REQ_STRING },
    21162186        { "--session-id",      VBOXSERVICESESSIONOPT_SESSION_ID,      RTGETOPT_REQ_UINT32 },
    21172187        { "--session-proto",   VBOXSERVICESESSIONOPT_SESSION_PROTO,   RTGETOPT_REQ_UINT32 },
     2188#ifdef DEBUG
     2189        { "--thread-id",       VBOXSERVICESESSIONOPT_THREAD_ID,       RTGETOPT_REQ_UINT32 },
     2190#endif /* DEBUG */
    21182191        { "--verbose",         'v',                                   RTGETOPT_REQ_NOTHING }
    21192192    };
     
    21572230                break;
    21582231
     2232            case VBOXSERVICESESSIONOPT_THREAD_ID:
     2233                /* Not handled. */
     2234                break;
     2235
    21592236            /** @todo Implement help? */
    21602237
  • trunk/src/VBox/HostServices/GuestControl/service.cpp

    r45010 r45415  
    5959*   Header Files                                                               *
    6060*******************************************************************************/
    61 #define LOG_GROUP LOG_GROUP_HGCM
     61#ifdef LOG_GROUP
     62 #undef LOG_GROUP
     63#endif
     64#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
    6265#include <VBox/HostServices/GuestControlSvc.h>
    6366
     
    8487
    8588/** Flag for indicating that the client only is interested in
    86  *  messages for specific contexts. */
     89 *  messages of specific context IDs. */
    8790#define CLIENTSTATE_FLAG_CONTEXTFILTER      RT_BIT(0)
    8891
     
    113116    uint32_t AddRef(void)
    114117    {
     118#ifdef DEBUG_andy
     119        LogFlowFunc(("Adding reference pHostCmd=%p, CID=%RU32, new refCount=%RU32\n",
     120                     this, mContextID, mRefCount + 1));
     121#endif
    115122        return ++mRefCount;
    116123    }
     
    118125    uint32_t Release(void)
    119126    {
    120         LogFlowFunc(("Releasing CID=%RU32, refCount=%RU32\n",
    121                      mContextID, mRefCount));
    122 
     127#ifdef DEBUG_andy
     128        LogFlowFunc(("Releasing reference pHostCmd=%p, CID=%RU32, new refCount=%RU32\n",
     129                     this, mContextID, mRefCount - 1));
     130#endif
    123131        /* Release reference for current command. */
    124132        Assert(mRefCount);
     
    139147    int Allocate(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    140148    {
    141         LogFlowFunc(("Allocating uMsg=%RU32, cParms=%RU32, paParms=%p\n",
    142                      uMsg, cParms, paParms));
     149        LogFlowFunc(("Allocating pHostCmd=%p, uMsg=%RU32, cParms=%RU32, paParms=%p\n",
     150                     this, uMsg, cParms, paParms));
    143151
    144152        if (!cParms) /* At least one parameter (context ID) must be present. */
     
    219227             */
    220228            rc = mpParms[0].getUInt32(&mContextID);
     229
     230            /* Set timestamp so that clients can distinguish between already
     231             * processed commands and new ones. */
     232            mTimestamp = RTTimeNanoTS();
    221233        }
    222234
     
    232244    void Free(void)
    233245    {
    234         AssertMsg(mRefCount == 0, ("Command CID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n",
    235                                    mContextID, mRefCount));
    236 
    237         LogFlowFunc(("Freeing host command CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
    238                      mContextID, mMsgType, mParmCount, mpParms));
     246        AssertMsg(mRefCount == 0, ("pHostCmd=%p, CID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n",
     247                                   this, mContextID, mRefCount));
     248
     249        LogFlowFunc(("Freeing host command pHostCmd=%p, CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
     250                     this, mContextID, mMsgType, mParmCount, mpParms));
    239251
    240252        for (uint32_t i = 0; i < mParmCount; i++)
     
    260272        mParmCount = 0;
    261273
    262        /* Removes the command from its list */
    263        RTListNodeRemove(&Node);
     274        /* Removes the command from its list */
     275        RTListNodeRemove(&Node);
    264276    }
    265277
     
    274286    int CopyTo(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms) const
    275287    {
     288        LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mContextID=%RU32\n",
     289                     this, mMsgType, mParmCount, mContextID));
     290
    276291        int rc = VINF_SUCCESS;
    277292        if (cDstParms != mParmCount)
     
    294309                else
    295310                {
    296 #ifdef DEBUG_andy
    297                     LogFlowFunc(("\tmpParms[%RU32] type = %RU32\n",
    298                                  i, mpParms[i].type));
    299 #endif
    300311                    switch (mpParms[i].type)
    301312                    {
     
    362373        int rc;
    363374
    364         LogFlowFunc(("mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
    365                      mMsgType, mParmCount, mpParms));
     375        LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
     376                     this, mMsgType, mParmCount, mpParms));
    366377
    367378        /* Does the current host command need more parameter space which
     
    392403        }
    393404
    394         LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    395405        return rc;
    396406    }
     
    400410        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    401411
    402         LogFlowFunc(("mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
    403                      mMsgType, mParmCount, mpParms));
    404         LogFlowFunc(("Telling client the next upcoming message type=%RU32, count=%RU32\n",
    405                      mMsgType, mParmCount));
     412        LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",
     413                     this, mMsgType, mParmCount, mpParms));
    406414
    407415        if (pConnection->mNumParms >= 2)
     
    431439    /** Dynamic structure for holding the HGCM parms */
    432440    uint32_t mMsgType;
     441    /** Number of HGCM parameters. */
    433442    uint32_t mParmCount;
     443    /** Array of HGCM parameters. */
    434444    PVBOXHGCMSVCPARM mpParms;
     445    /** Incoming timestamp (us). */
     446    uint64_t mTimestamp;
    435447} HostCommand;
     448typedef std::list< HostCommand *> HostCmdList;
     449typedef std::list< HostCommand *>::iterator HostCmdListIter;
     450typedef std::list< HostCommand *>::const_iterator HostCmdListIterConst;
    436451
    437452/**
     
    459474{
    460475    ClientState(void)
    461         : mSvcHelpers(NULL),
     476        : mID(0),
     477          mSvcHelpers(NULL),
    462478          mFlags(0), mContextFilter(0),
    463           mpHostCmd(NULL), mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),
    464           mIsPending(false) {}
    465 
    466     ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers)
    467         : mSvcHelpers(pSvcHelpers),
     479          mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),
     480          mHostCmdTS(0),
     481          mIsPending(false) { }
     482
     483    ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t uClientID)
     484        : mID(uClientID),
     485          mSvcHelpers(pSvcHelpers),
    468486          mFlags(0), mContextFilter(0),
    469           mpHostCmd(NULL), mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),
    470           mIsPending(false) {}
     487          mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0),
     488          mHostCmdTS(0),
     489          mIsPending(false) { }
     490
     491    void DequeueAll(void)
     492    {
     493        HostCmdListIter curItem = mHostCmdList.begin();
     494        while (curItem != mHostCmdList.end())
     495            Dequeue(curItem++);
     496    }
     497
     498    void DequeueCurrent(void)
     499    {
     500        HostCmdListIter curCmd = mHostCmdList.begin();
     501        if (curCmd != mHostCmdList.end())
     502            Dequeue(curCmd);
     503    }
     504
     505    void Dequeue(HostCommand *pHostCmd)
     506    {
     507        AssertPtrReturnVoid(pHostCmd);
     508
     509        HostCmdListIter curItem = mHostCmdList.begin();
     510        while (curItem != mHostCmdList.end())
     511        {
     512            if ((*curItem) == pHostCmd)
     513            {
     514                Dequeue(curItem);
     515                break;
     516            }
     517
     518            curItem++;
     519        }
     520    }
     521
     522    void Dequeue(HostCmdListIter &curItem)
     523    {
     524        HostCommand *pHostCmd = (*curItem);
     525        AssertPtr(pHostCmd);
     526
     527        if (pHostCmd->Release() == 0)
     528        {
     529            LogFlowFunc(("[Client %RU32] Destroying pHostCmd=%p\n",
     530                         mID, (*curItem)));
     531
     532            delete pHostCmd;
     533            pHostCmd = NULL;
     534        }
     535
     536        mHostCmdList.erase(curItem);
     537
     538        /* Reset everything else. */
     539        mHostCmdRc    = VINF_SUCCESS;
     540        mHostCmdTries = 0;
     541    }
     542
     543    int EnqueueCommand(HostCommand *pHostCmd)
     544    {
     545        AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
     546
     547        int rc = VINF_SUCCESS;
     548
     549        try
     550        {
     551            mHostCmdList.push_back(pHostCmd);
     552            pHostCmd->AddRef();
     553        }
     554        catch (std::bad_alloc)
     555        {
     556            rc = VERR_NO_MEMORY;
     557        }
     558
     559        return rc;
     560    }
    471561
    472562    bool WantsHostCommand(const HostCommand *pHostCmd) const
     
    475565
    476566#ifdef DEBUG_andy
    477             LogFlowFunc(("mFlags=%x, mContextID=%RU32, mContextFilter=%x, filterRes=%x\n",
    478                          mFlags, pHostCmd->mContextID, mContextFilter, pHostCmd->mContextID & mContextFilter));
     567        LogFlowFunc(("mHostCmdTS=%RU64, pHostCmdTS=%RU64\n",
     568                     mHostCmdTS, pHostCmd->mTimestamp));
     569#endif
     570
     571        /* Only process newer commands. */
     572        if (pHostCmd->mTimestamp <= mHostCmdTS)
     573            return false;
     574
     575#ifdef DEBUG_andy
     576            LogFlowFunc(("[Client %RU32] mFlags=%x, mContextID=%RU32, mContextFilter=%x, filterRes=%x, sessionID=%RU32\n",
     577                         mID, mFlags, pHostCmd->mContextID, mContextFilter,
     578                         pHostCmd->mContextID & mContextFilter, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->mContextID)));
    479579#endif
    480580        /*
    481581         * If a sesseion filter is set, only obey those sessions we're interested in.
    482582         */
     583        bool fWant = false;
    483584        if (mFlags & CLIENTSTATE_FLAG_CONTEXTFILTER)
    484585        {
    485586            if ((pHostCmd->mContextID & mContextFilter) == mContextFilter)
    486                 return true;
     587                fWant = true;
    487588        }
    488589        else /* Client is interested in all commands. */
    489             return true;
    490 
    491         return false;
     590            fWant = true;
     591
     592        return fWant;
    492593    }
    493594
     
    496597        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    497598
    498         LogFlowFunc(("mIsPending=%RTbool, mpHostCmd=%p, CID=%RU32, type=%RU32\n",
    499                      mIsPending, mpHostCmd,
    500                      mpHostCmd ? mpHostCmd->mContextID : 0,
    501                      mpHostCmd ? mpHostCmd->mMsgType : 0));
    502 
    503599        if (mIsPending)
    504600        {
    505             LogFlowFunc(("Client already is in pending mode\n"));
     601            LogFlowFunc(("[Client %RU32] Already is in pending mode\n", mID));
    506602
    507603            /*
     
    511607        }
    512608
    513         if (mpHostCmd == NULL)
     609        if (mHostCmdList.empty())
    514610        {
    515611            AssertMsg(mIsPending == false,
    516                       ("Client %p already is pending but tried to receive a new host command\n", this));
    517 
    518             mPending.mHandle   = pConnection->mHandle;
    519             mPending.mNumParms = pConnection->mNumParms;
    520             mPending.mParms    = pConnection->mParms;
     612                      ("Client ID=%RU32 already is pending but tried to receive a new host command\n", mID));
     613
     614            mPendingCon.mHandle   = pConnection->mHandle;
     615            mPendingCon.mNumParms = pConnection->mNumParms;
     616            mPendingCon.mParms    = pConnection->mParms;
    521617
    522618            mIsPending = true;
    523619
    524             LogFlowFunc(("Client now is in pending mode\n"));
     620            LogFlowFunc(("[Client %RU32] Is now in pending mode\n", mID));
    525621
    526622            /*
     
    538634    }
    539635
    540     int SetNextCommand(HostCommand *pHostCmd)
    541     {
     636    int Run(const ClientConnection *pConnection,
     637                  HostCommand      *pHostCmd)
     638    {
     639        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    542640        AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
    543641
    544         mpHostCmd = pHostCmd;
    545         AssertPtr(mpHostCmd);
    546         mpHostCmd->AddRef();
    547 
    548         /* Create a command context to keep track of client-specific
    549          * information about a certain command. */
    550         Assert(mContextMap.find(mpHostCmd->mContextID) == mContextMap.end());
    551         mContextMap[mpHostCmd->mContextID] = ClientContext(mpHostCmd);
    552         /** @todo Exception handling! */
    553 
    554         LogFlowFunc(("Assigning next host comamnd CID=%RU32, cmdType=%RU32, cmdParms=%RU32, new refCount=%RU32\n",
    555                      mpHostCmd->mContextID, mpHostCmd->mMsgType, mpHostCmd->mParmCount, mpHostCmd->mRefCount));
    556 
    557         return VINF_SUCCESS;
    558     }
    559 
    560     int Run(const ClientConnection *pConnection,
    561             const RTLISTANCHOR     *pHostCmdList)
    562     {
    563642        int rc = VINF_SUCCESS;
    564643
    565         LogFlowFunc(("Client pConnection=%p, pHostCmdList=%p\n",
    566                       pConnection, pHostCmdList));
    567         LogFlowFunc(("Client hostCmd=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n",
    568                       mpHostCmd, mHostCmdRc, mHostCmdTries));
    569 
    570         /* No current command? Try getting a new one to process now. */
    571         if (mpHostCmd == NULL)
    572         {
    573             /* Get the next host command the clienet is interested in. */
    574             bool fFoundCmd = false;
    575             HostCommand *pCurCmd;
    576             RTListForEach(pHostCmdList, pCurCmd, HostCommand, Node)
     644        LogFlowFunc(("[Client %RU32] pConnection=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n",
     645                      mID, pConnection, mHostCmdRc, mHostCmdTries));
     646
     647        mHostCmdRc = SendReply(pConnection, pHostCmd);
     648        LogFlowFunc(("[Client %RU32] Processing pHostCmd=%p ended with rc=%Rrc\n",
     649                     mID, pHostCmd, mHostCmdRc));
     650
     651        bool fRemove = false;
     652        if (RT_FAILURE(mHostCmdRc))
     653        {
     654            mHostCmdTries++;
     655
     656            /*
     657             * If the client understood the message but supplied too little buffer space
     658             * don't send this message again and drop it after 3 unsuccessful attempts.
     659             * The host then should take care of next actions (maybe retry it with a smaller buffer).
     660             */
     661            if (mHostCmdRc == VERR_TOO_MUCH_DATA)
    577662            {
    578                 fFoundCmd = WantsHostCommand(pCurCmd);
    579                 if (fFoundCmd)
    580                 {
    581                     int rc2 = SetNextCommand(pCurCmd);
    582                     if (RT_SUCCESS(rc2))
    583                         break;
    584                 }
    585             }
    586 
    587             LogFlowFunc(("Client %s new command\n",
    588                          fFoundCmd ? "found" : "did not find a"));
    589 
    590             /* If no new command was found, set client into pending state. */
    591             if (!fFoundCmd)
    592                 rc = SetPending(pConnection);
    593         }
    594 
    595         if (mpHostCmd)
    596         {
    597             AssertPtr(mpHostCmd);
    598             mHostCmdRc = SendReply(pConnection, mpHostCmd);
    599             LogFlowFunc(("Processing command CID=%RU32 ended with rc=%Rrc\n",
    600                          mpHostCmd->mContextID, mHostCmdRc));
    601 
    602             bool fRemove = false;
    603             if (RT_FAILURE(mHostCmdRc))
    604             {
    605                 mHostCmdTries++;
    606 
    607                 /*
    608                  * If the client understood the message but supplied too little buffer space
    609                  * don't send this message again and drop it after 3 unsuccessful attempts.
    610                  * The host then should take care of next actions (maybe retry it with a smaller buffer).
    611                  */
    612                 if (   mHostCmdRc    == VERR_TOO_MUCH_DATA
    613                     && mHostCmdTries >= 3)
    614                 {
    615                     fRemove = true;
    616                 }
    617                 /* Client did not understand the message or something else weird happened. Try again one
    618                  * more time and drop it if it didn't get handled then. */
    619                 else if (mHostCmdTries > 1)
     663                if (mHostCmdTries >= 3)
    620664                    fRemove = true;
    621665            }
     666            /* Client did not understand the message or something else weird happened. Try again one
     667             * more time and drop it if it didn't get handled then. */
     668            else if (mHostCmdTries > 1)
     669                fRemove = true;
     670        }
     671        else
     672            fRemove = true; /* Everything went fine, remove it. */
     673
     674        LogFlowFunc(("[Client %RU32] Tried pHostCmd=%p for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n",
     675                     mID, pHostCmd, mHostCmdTries, mHostCmdRc, fRemove));
     676
     677        if (RT_SUCCESS(rc))
     678            rc = mHostCmdRc;
     679
     680        if (fRemove)
     681            Dequeue(pHostCmd);
     682
     683        LogFlowFunc(("[Client %RU32] Returned with rc=%Rrc\n", mID, rc));
     684        return rc;
     685    }
     686
     687    int RunCurrent(const ClientConnection *pConnection)
     688    {
     689        AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
     690
     691        int rc;
     692        if (mHostCmdList.empty())
     693        {
     694            rc = SetPending(pConnection);
     695        }
     696        else
     697        {
     698            AssertMsgReturn(!mIsPending,
     699                            ("Client ID=%RU32 still is in pending mode; can't use another connection\n", mID), VERR_INVALID_PARAMETER);
     700
     701            HostCmdListIter curCmd = mHostCmdList.begin();
     702            Assert(curCmd != mHostCmdList.end());
     703            HostCommand *pHostCmd = (*curCmd);
     704            AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
     705
     706            rc = Run(pConnection, pHostCmd);
     707        }
     708
     709        return rc;
     710    }
     711
     712    int Wakeup(void)
     713    {
     714        int rc = VINF_NO_CHANGE;
     715
     716        if (mIsPending)
     717        {
     718            LogFlowFunc(("[Client %RU32] Waking up ...\n", mID));
     719
     720            rc = VINF_SUCCESS;
     721
     722            HostCmdListIter curCmd = mHostCmdList.begin();
     723            if (curCmd != mHostCmdList.end())
     724            {
     725                HostCommand *pHostCmd = (*curCmd);
     726                AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);
     727
     728                LogFlowFunc(("[Client %RU32] Current host command is pHostCmd=%p, CID=%RU32, cmdType=%RU32, cmdParms=%RU32, refCount=%RU32\n",
     729                             mID, pHostCmd, pHostCmd->mContextID, pHostCmd->mMsgType, pHostCmd->mParmCount, pHostCmd->mRefCount));
     730
     731                rc = Run(&mPendingCon, pHostCmd);
     732            }
    622733            else
    623                 fRemove = true; /* Everything went fine, remove it. */
    624 
    625             LogFlowFunc(("Client tried CID=%RU32 for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n",
    626                          mpHostCmd->mContextID, mHostCmdTries, mHostCmdRc, fRemove));
    627 
    628             if (fRemove)
    629             {
    630                 /* Try fetching next command. */
    631                 HostCommand *pCmdNext = RTListGetNext(pHostCmdList, mpHostCmd, HostCommand, Node);
    632 
    633                 LogFlowFunc(("Client removes itself from command CID=%RU32 (next command: %p, CID=%RU32)\n",
    634                               mpHostCmd->mContextID, pCmdNext, pCmdNext ? pCmdNext->mContextID : 0));
    635 
    636                 /* Remove command from context map. */
    637                 /** @todo Exception handling! */
    638                 mContextMap.erase(mpHostCmd->mContextID);
    639 
    640                 /* Release reference for current command. */
    641                 if (mpHostCmd->Release() == 0)
    642                 {
    643                     LogFlowFunc(("Destroying command CID=%RU32\n",
    644                                  mpHostCmd->mContextID));
    645 
    646                     RTMemFree(mpHostCmd);
    647                 }
    648 
    649                 /* Assign next command (if any) to this client. */
    650                 if (pCmdNext)
    651                 {
    652                     rc = SetNextCommand(pCmdNext);
    653                 }
    654                 else
    655                     mpHostCmd = NULL;
    656 
    657                 /* Reset everything else. */
    658                 mHostCmdRc    = VINF_SUCCESS;
    659                 mHostCmdTries = 0;
    660             }
    661 
    662             if (RT_SUCCESS(rc))
    663                 rc = mHostCmdRc;
    664         }
    665 
    666         LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    667         return rc;
    668     }
    669 
    670     int RunNow(const ClientConnection *pConnection,
    671                const PRTLISTANCHOR     pHostCmdList)
    672     {
    673         AssertPtrReturn(pConnection, VERR_INVALID_POINTER);
    674         AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER);
    675 
    676         AssertMsgReturn(!mIsPending, ("Can't use another connection when client still is in pending mode\n"),
    677                         VERR_INVALID_PARAMETER);
    678 
    679         int rc = Run(pConnection, pHostCmdList);
    680 
    681         LogFlowFunc(("Returned with rc=%Rrc\n"));
    682         return rc;
    683     }
    684 
    685     int Wakeup(const PRTLISTANCHOR pHostCmdList)
    686     {
    687         AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER);
    688         AssertMsgReturn(mIsPending, ("Cannot wake up a client which is not in pending mode\n"),
    689                         VERR_INVALID_PARAMETER);
    690 
    691         int rc = Run(&mPending, pHostCmdList);
    692 
    693         /* Reset pending state. */
    694         mIsPending = false;
    695 
    696         LogFlowFunc(("Returned with rc=%Rrc\n"));
    697         return rc;
     734                AssertMsgFailed(("Waking up client ID=%RU32 with no host command in queue is a bad idea\n", mID));
     735
     736            return rc;
     737        }
     738
     739        return VINF_NO_CHANGE;
    698740    }
    699741
    700742    int CancelWaiting(int rcPending)
    701743    {
    702         LogFlowFunc(("Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n",
    703                      rcPending, mIsPending, mPending.mNumParms, mFlags));
     744        LogFlowFunc(("[Client %RU32] Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n",
     745                     mID, rcPending, mIsPending, mPendingCon.mNumParms, mFlags));
    704746
    705747        if (   mIsPending
    706             && mPending.mNumParms >= 2)
    707         {
    708             mPending.mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */
    709             mPending.mParms[1].setUInt32(0);                         /* Required parameters for message. */
     748            && mPendingCon.mNumParms >= 2)
     749        {
     750            mPendingCon.mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */
     751            mPendingCon.mParms[1].setUInt32(0);                         /* Required parameters for message. */
    710752
    711753            AssertPtr(mSvcHelpers);
    712             mSvcHelpers->pfnCallComplete(mPending.mHandle, rcPending);
     754            mSvcHelpers->pfnCallComplete(mPendingCon.mHandle, rcPending);
    713755
    714756            mIsPending = false;
     
    740782        }
    741783
     784        /* Reset pending status. */
     785        mIsPending = false;
     786
    742787        /* In any case the client did something, so complete
    743788         * the pending call with the result we just got. */
     
    745790        mSvcHelpers->pfnCallComplete(pConnection->mHandle, rc);
    746791
    747         LogFlowFunc(("pConnection=%p, pHostCmd=%p, rc=%Rrc\n",
    748                      pConnection, pHostCmd, rc));
     792        LogFlowFunc(("[Client %RU32] pConnection=%p, pHostCmd=%p, replyRc=%Rrc\n",
     793                     mID, pConnection, pHostCmd, rc));
    749794        return rc;
    750795    }
    751796
    752797    PVBOXHGCMSVCHELPERS mSvcHelpers;
     798    /** The client's ID. */
     799    uint32_t mID;
    753800    /** Client flags. @sa CLIENTSTATE_FLAG_ flags. */
    754801    uint32_t mFlags;
    755802    /** The context ID filter, based on the flags set. */
    756803    uint32_t mContextFilter;
    757     /** Pointer to current host command to process. */
    758     HostCommand *mpHostCmd;
     804    /** Host command list to process. */
     805    HostCmdList mHostCmdList;
    759806    /** Last (most recent) rc after handling the
    760807     *  host command. */
     
    763810     *  command to the according client. */
    764811    uint32_t mHostCmdTries;
    765     /** Map containing all context IDs a client is assigned to. */
    766     ClientContextMap mContextMap;
     812    /** Timestamp (us) of last host command processed. */
     813    uint64_t mHostCmdTS;
    767814    /** Flag indicating whether the client currently is pending. */
    768815    bool mIsPending;
    769816    /** The client's pending connection. */
    770     ClientConnection mPending;
     817    ClientConnection mPendingCon;
    771818} ClientState;
    772819typedef std::map< uint32_t, ClientState > ClientStateMap;
     
    831878    {
    832879        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    833         LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
    834880        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     881        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    835882        return pSelf->clientConnect(u32ClientID, pvClient);
    836883    }
     
    845892    {
    846893        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    847         LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
    848894        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     895        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    849896        return pSelf->clientDisconnect(u32ClientID, pvClient);
    850897    }
     
    863910    {
    864911        AssertLogRelReturnVoid(VALID_PTR(pvService));
    865         LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n",
    866                       pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
    867912        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     913        AssertPtrReturnVoid(pSelf);
    868914        pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
    869915    }
     
    879925    {
    880926        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    881         LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
    882927        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     928        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    883929        return pSelf->hostCall(u32Function, cParms, paParms);
    884930    }
     
    894940        AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
    895941        SELF *pSelf = reinterpret_cast<SELF *>(pvService);
     942        AssertPtrReturn(pSelf, VERR_INVALID_POINTER);
    896943        pSelf->mpfnHostCallback = pfnExtension;
    897944        pSelf->mpvHostData = pvExtension;
     
    906953    int clientGetCommand(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    907954    int clientSetMsgFilter(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     955    int clientSkipMsg(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    908956    int cancelHostCmd(uint32_t u32ContextID);
    909957    int cancelPendingWaits(uint32_t u32ClientID, int rcPending);
     
    924972int Service::clientConnect(uint32_t u32ClientID, void *pvClient)
    925973{
    926     LogFlowFunc(("New client with ID=%RU32 connected\n", u32ClientID));
     974    LogFlowFunc(("[Client %RU32] Connected\n", u32ClientID));
    927975#ifdef VBOX_STRICT
    928976    ClientStateMapIterConst it = mClientStateMap.find(u32ClientID);
     
    934982    }
    935983#endif
    936     ClientState cs(mpHelpers);
    937     mClientStateMap[u32ClientID] = cs;
     984    ClientState clientState(mpHelpers, u32ClientID);
     985    mClientStateMap[u32ClientID] = clientState;
    938986    /** @todo Exception handling! */
    939987    return VINF_SUCCESS;
     
    951999int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient)
    9521000{
    953     LogFlowFunc(("Client with ID=%RU32 (%zu clients total) disconnected\n",
     1001    LogFlowFunc(("[Client %RU32] Disonnected (%zu clients total)\n",
    9541002                 u32ClientID, mClientStateMap.size()));
    9551003
    956     /* If this was the last connected (guest) client we need to
    957      * unblock all eventually queued up (waiting) host calls. */
     1004    AssertMsg(mClientStateMap.size(),
     1005              ("No clients in list anymore when there should (client ID=%RU32)\n", u32ClientID));
     1006
     1007    int rc = VINF_SUCCESS;
     1008
     1009    ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID);
     1010    AssertMsg(itClientState != mClientStateMap.end(),
     1011              ("Clients ID=%RU32 not found in client list when it should be there\n", u32ClientID));
     1012
     1013    if (itClientState != mClientStateMap.end())
     1014    {
     1015        itClientState->second.DequeueAll();
     1016
     1017        mClientStateMap.erase(itClientState);
     1018    }
     1019
    9581020    bool fAllClientsDisconnected = mClientStateMap.size() == 0;
    9591021    if (fAllClientsDisconnected)
    960         LogFlowFunc(("No connected clients left, notifying all queued up host callbacks\n"));
    961 
    962     /*
    963      * Throw out all stale clients.
    964      */
    965     int rc = VINF_SUCCESS;
    966 
    967     ClientStateMapIter itClientState = mClientStateMap.begin();
    968     while (   itClientState != mClientStateMap.end()
    969            && RT_SUCCESS(rc))
    970     {
    971         /*
    972          * Unblock/call back all queued items of the specified client
    973          * or for all items in case there is no waiting client around
    974          * anymore.
    975          */
    976         if (   itClientState->first == u32ClientID
    977             || fAllClientsDisconnected)
    978         {
    979             LogFlowFunc(("Cancelling %RU32 context(s) of client ID=%RU32\n",
    980                          itClientState->second.mContextMap.size(), u32ClientID));
    981 
    982             ClientContextMapIter itContext = itClientState->second.mContextMap.begin();
    983             while (itContext != itClientState->second.mContextMap.end())
    984             {
    985                 uint32_t uContextID = itContext->first;
    986 
    987                 /*
    988                  * Notify the host that clients with u32ClientID are no longer
    989                  * around and need to be cleaned up (canceling waits etc).
    990                  */
    991                 LogFlowFunc(("Notifying CID=%RU32 of disconnect ...\n", uContextID));
    992                 int rc2 = cancelHostCmd(uContextID);
    993                 if (RT_FAILURE(rc2))
    994                 {
    995                     LogFlowFunc(("Cancelling host command with CID=%RU32 failed with rc=%Rrc\n",
    996                                  uContextID, rc2));
    997                     /* Keep going. */
    998                 }
    999 
    1000                 AssertPtr(itContext->second.mpHostCmd);
    1001                 itContext->second.mpHostCmd->Release();
    1002 
    1003                 itContext++;
    1004             }
    1005 
    1006             itClientState->second.mContextMap.clear();
    1007 
    1008             /** @todo Exception handling! */
    1009             mClientStateMap.erase(itClientState++);
    1010         }
    1011         else
    1012             itClientState++;
    1013     }
    1014 
    1015     if (fAllClientsDisconnected)
    1016     {
     1022    {
     1023        LogFlowFunc(("All clients disconnected, cancelling all host commands ...\n"));
     1024
    10171025        /*
    10181026         * If all clients disconnected we also need to make sure that all buffered
     
    10341042            }
    10351043
    1036             pCurCmd->Free();
    1037 
    1038             RTListNodeRemove(&pCurCmd->Node);
    1039             RTMemFree(pCurCmd);
     1044            while (pCurCmd->Release());
     1045
     1046            delete pCurCmd;
     1047            pCurCmd = NULL;
    10401048
    10411049            if (fLast)
     
    10821090    thisCon.mParms    = paParms;
    10831091
    1084     /*
    1085      * If host command list is empty (nothing to do right now) just
    1086      * defer the call until we got something to do (makes the client
    1087      * wait).
    1088      */
    1089     int rc;
    1090     if (RTListIsEmpty(&mHostCmdList))
    1091     {
    1092         rc = clientState.SetPending(&thisCon);
    1093     }
    1094     else
    1095     {
    1096         rc = clientState.RunNow(&thisCon, &mHostCmdList);
    1097     }
    1098 
    1099     LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    1100     return rc;
     1092    return clientState.RunCurrent(&thisCon);
    11011093}
    11021094
     
    11231115    if (RT_SUCCESS(rc))
    11241116    {
    1125         /* paParms[1] unused yet. */
    1126 
    11271117        ClientState &clientState = itClientState->second;
    11281118
     
    11381128    }
    11391129
    1140     LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    11411130    return rc;
     1131}
     1132
     1133int Service::clientSkipMsg(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle,
     1134                           uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     1135{
     1136    /*
     1137     * Lookup client in our list so that we can assign the context ID of
     1138     * a command to that client.
     1139     */
     1140    ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID);
     1141    AssertMsg(itClientState != mClientStateMap.end(), ("Client ID=%RU32 not found when it should be present\n",
     1142                                                       u32ClientID));
     1143    if (itClientState == mClientStateMap.end())
     1144        return VERR_NOT_FOUND; /* Should never happen. */
     1145
     1146    if (cParms != 0)
     1147        return VERR_INVALID_PARAMETER;
     1148
     1149    LogFlowFunc(("Client ID=%RU32 skipping message ...\n", u32ClientID));
     1150
     1151    itClientState->second.DequeueCurrent();
     1152
     1153    return VINF_SUCCESS;
    11421154}
    11431155
     
    12281240
    12291241    int rc;
    1230     HostCommand *pHostCmd = (HostCommand*)RTMemAllocZ(sizeof(HostCommand));
    1231     if (pHostCmd)
    1232     {
     1242
     1243    HostCommand *pHostCmd = NULL;
     1244    try
     1245    {
     1246        pHostCmd = new HostCommand();
    12331247        rc = pHostCmd->Allocate(eFunction, cParms, paParms);
    12341248        if (RT_SUCCESS(rc))
    1235             RTListAppend(&mHostCmdList, &pHostCmd->Node);
    1236     }
    1237     else
     1249            /* rc = */ RTListAppend(&mHostCmdList, &pHostCmd->Node);
     1250    }
     1251    catch (std::bad_alloc)
     1252    {
    12381253        rc = VERR_NO_MEMORY;
     1254    }
    12391255
    12401256    if (RT_SUCCESS(rc))
    12411257    {
    1242         LogFlowFunc(("Handling host command CID=%RU32, numClients=%zu\n",
    1243                      pHostCmd->mContextID, mClientStateMap.size()));
     1258        LogFlowFunc(("Handling host command CID=%RU32, eFunction=%RU32, cParms=%RU32, paParms=%p, numClients=%zu\n",
     1259                     pHostCmd->mContextID, eFunction, cParms, paParms, mClientStateMap.size()));
    12441260
    12451261        /*
     
    12501266        uint32_t uClientsWokenUp = 0;
    12511267#endif
    1252 
    12531268        ClientStateMapIter itClientState = mClientStateMap.begin();
    12541269        AssertMsg(itClientState != mClientStateMap.end(), ("Client state map is empty when it should not\n"));
    12551270        while (itClientState != mClientStateMap.end())
    12561271        {
    1257             if (itClientState->second.mIsPending) /* Only wake up pending clients. */
     1272            ClientState &clientState = itClientState->second;
     1273
     1274            /* If a client indicates that it it wants the new host command,
     1275             * add a reference to not delete it.*/
     1276            if (clientState.WantsHostCommand(pHostCmd))
    12581277            {
    1259                 LogFlowFunc(("Waking up client ID=%RU32 (isPending=%RTbool) ...\n",
    1260                              itClientState->first, itClientState->second.mIsPending));
    1261 
    1262                 ClientState &clientState = itClientState->second;
    1263                 int rc2 = clientState.Wakeup(&mHostCmdList);
    1264                 LogFlowFunc(("Client ID=%RU32 wakeup ended with rc=%Rrc\n",
    1265                              itClientState->first, rc2));
    1266 #ifdef DEBUG
     1278                clientState.EnqueueCommand(pHostCmd);
     1279
     1280                int rc2 = clientState.Wakeup();
     1281                if (RT_FAILURE(rc2))
     1282                    LogFlowFunc(("Waking up client ID=%RU32 failed with rc=%Rrc\n",
     1283                                 itClientState->first, rc2));
     1284#ifdef DEBUG_andy
    12671285                uClientsWokenUp++;
    12681286#endif
    12691287            }
    1270             else
    1271                 LogFlowFunc(("Client ID=%RU32 is not in pending state\n",
    1272                              itClientState->first));
    12731288
    12741289            itClientState++;
    12751290        }
    12761291
    1277 #ifdef DEBUG
    1278         LogFlowFunc(("%RU32 clients have been succcessfully woken up\n",
    1279                       uClientsWokenUp));
     1292#ifdef DEBUG_andy
     1293        LogFlowFunc(("%RU32 clients have been woken up\n", uClientsWokenUp));
    12801294#endif
    12811295    }
    12821296
    1283     LogFlowFunc(("Returned with rc=%Rrc\n", rc));
    12841297    return rc;
    12851298}
     
    12991312{
    13001313    int rc = VINF_SUCCESS;
    1301     LogFlowFunc(("u32ClientID=%RU32, fn=%RU32, cParms=%RU32, paParms=0x%p\n",
     1314    LogFlowFunc(("[Client %RU32] eFunction=%RU32, cParms=%RU32, paParms=0x%p\n",
    13021315                 u32ClientID, eFunction, cParms, paParms));
    13031316    try
     
    13081321        if (eFunction == GUEST_MSG_WAIT)
    13091322        {
    1310             LogFlowFunc(("GUEST_MSG_GET\n"));
     1323            LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", u32ClientID));
    13111324            rc = clientGetCommand(u32ClientID, callHandle, cParms, paParms);
    13121325        }
     
    13211334                 */
    13221335                case GUEST_CANCEL_PENDING_WAITS:
    1323                     LogFlowFunc(("GUEST_CANCEL_PENDING_WAITS\n"));
     1336                    LogFlowFunc(("[Client %RU32] GUEST_CANCEL_PENDING_WAITS\n", u32ClientID));
    13241337                    rc = cancelPendingWaits(u32ClientID, VINF_SUCCESS /* Pending result */);
    13251338                    break;
     
    13301343                 */
    13311344                case GUEST_MSG_FILTER:
    1332                     LogFlowFunc(("GUEST_MSG_FILTER\n"));
     1345                    LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER\n", u32ClientID));
    13331346                    rc = clientSetMsgFilter(u32ClientID, callHandle, cParms, paParms);
     1347                    break;
     1348
     1349                /*
     1350                 * The guest only wants skip the currently assigned messages.
     1351                 * Since VBox 4.3+.
     1352                 */
     1353                case GUEST_MSG_SKIP:
     1354                    LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", u32ClientID));
     1355                    rc = clientSkipMsg(u32ClientID, callHandle, cParms, paParms);
    13341356                    break;
    13351357
     
    14161438 * @copydoc VBOXHGCMSVCLOAD
    14171439 */
    1418 extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable)
     1440extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
    14191441{
    14201442    int rc = VINF_SUCCESS;
    14211443
    1422     LogFlowFunc(("ptable = %p\n", ptable));
    1423 
    1424     if (!VALID_PTR(ptable))
     1444    LogFlowFunc(("pTable=%p\n", pTable));
     1445
     1446    if (!VALID_PTR(pTable))
    14251447    {
    14261448        rc = VERR_INVALID_PARAMETER;
     
    14281450    else
    14291451    {
    1430         LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
    1431 
    1432         if (   ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
    1433             || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
     1452        LogFlowFunc(("pTable->cbSize=%d, pTable->u32Version=0x%08X\n", pTable->cbSize, pTable->u32Version));
     1453
     1454        if (   pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
     1455            || pTable->u32Version != VBOX_HGCM_SVC_VERSION)
    14341456        {
    14351457            rc = VERR_VERSION_MISMATCH;
     
    14401462            /* No exceptions may propagate outside. */
    14411463            try {
    1442                 apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
     1464                apService = std::auto_ptr<Service>(new Service(pTable->pHelpers));
    14431465            } catch (int rcThrown) {
    14441466                rc = rcThrown;
     
    14531475                 * because we're a class which can have members for that :-).
    14541476                 */
    1455                 ptable->cbClient = 0;
     1477                pTable->cbClient = 0;
    14561478
    14571479                /* Register functions. */
    1458                 ptable->pfnUnload             = Service::svcUnload;
    1459                 ptable->pfnConnect            = Service::svcConnect;
    1460                 ptable->pfnDisconnect         = Service::svcDisconnect;
    1461                 ptable->pfnCall               = Service::svcCall;
    1462                 ptable->pfnHostCall           = Service::svcHostCall;
    1463                 ptable->pfnSaveState          = NULL;  /* The service is stateless, so the normal */
    1464                 ptable->pfnLoadState          = NULL;  /* construction done before restoring suffices */
    1465                 ptable->pfnRegisterExtension  = Service::svcRegisterExtension;
     1480                pTable->pfnUnload             = Service::svcUnload;
     1481                pTable->pfnConnect            = Service::svcConnect;
     1482                pTable->pfnDisconnect         = Service::svcDisconnect;
     1483                pTable->pfnCall               = Service::svcCall;
     1484                pTable->pfnHostCall           = Service::svcHostCall;
     1485                pTable->pfnSaveState          = NULL;  /* The service is stateless, so the normal */
     1486                pTable->pfnLoadState          = NULL;  /* construction done before restoring suffices */
     1487                pTable->pfnRegisterExtension  = Service::svcRegisterExtension;
    14661488
    14671489                /* Service specific initialization. */
    1468                 ptable->pvService = apService.release();
     1490                pTable->pvService = apService.release();
    14691491            }
    14701492        }
    14711493    }
    14721494
    1473     LogFlowFunc(("returning %Rrc\n", rc));
     1495    LogFlowFunc(("Returning %Rrc\n", rc));
    14741496    return rc;
    14751497}
  • trunk/src/VBox/Main/Makefile.kmk

    r45276 r45415  
    611611        src-client/GuestImpl.cpp \
    612612        src-client/GuestDirectoryImpl.cpp \
     613        src-client/GuestErrorInfoImpl.cpp \
    613614        src-client/GuestFileImpl.cpp \
    614615        src-client/GuestFsObjInfoImpl.cpp \
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r45284 r45415  
    94919491      Process execution statuses.
    94929492    </desc>
     9493   
    94939494    <const name="Undefined"             value="0">
    94949495      <desc>Process is in an undefined state.</desc>
     
    95289529    </const>
    95299530  </enum>
    9530 
     9531 
     9532  <enum
     9533    name="ProcessInputStatus"
     9534    uuid="a4a0ef9c-29cc-4805-9803-c8215ae9da6c"
     9535    >
     9536    <desc>
     9537      Process input statuses.
     9538    </desc>
     9539   
     9540    <const name="Undefined"             value="0">
     9541      <desc>Undefined state.</desc>
     9542    </const>
     9543    <const name="Broken"                value="1">
     9544      <desc>TODO</desc>
     9545    </const>
     9546    <const name="Available"             value="10">
     9547      <desc>TODO</desc>
     9548    </const>
     9549    <const name="Written"               value="50">
     9550      <desc>TODO</desc>
     9551    </const>
     9552    <const name="Overflow"              value="100">
     9553      <desc>TODO</desc>
     9554    </const>
     9555  </enum>
     9556
     9557  <enum
     9558    name="FileStatus"
     9559    uuid="8c86468b-b97b-4080-8914-e29f5b0abd2c"
     9560    >
     9561    <desc>
     9562      File statuses.
     9563    </desc>
     9564   
     9565    <const name="Undefined"             value="0">
     9566      <desc>File is in an undefined state.</desc>
     9567    </const>
     9568    <const name="Opening"               value="10">
     9569      <desc>TODO</desc>
     9570    </const>
     9571    <const name="Open"                  value="100">
     9572      <desc>TODO</desc>
     9573    </const>
     9574    <const name="Closing"               value="150">
     9575      <desc>TODO</desc>
     9576    </const>
     9577    <const name="Closed"                value="200">
     9578      <desc>TODO</desc>
     9579    </const>
     9580    <const name="Down"                  value="600">
     9581      <desc>TODO</desc>
     9582    </const>
     9583    <const name="Error"                 value="800">
     9584      <desc>Something went wrong.</desc>
     9585    </const>
     9586  </enum>
     9587 
    95319588  <enum
    95329589    name="FsObjType"
     
    96059662    </const>
    96069663  </enum>
     9664 
     9665  <interface
     9666    name="IGuestErrorInfo" extends="$unknown"
     9667    uuid="ab576a37-dcfc-4d80-9a73-493d15e293c4"
     9668    wsmap="managed"
     9669    >
     9670    <desc>
     9671      TODO
     9672    </desc>
     9673
     9674    <attribute name="result" type="long" readonly="yes">
     9675      <desc>TODO</desc>
     9676    </attribute>
     9677   
     9678    <attribute name="text" type="wstring" readonly="yes">
     9679      <desc>TODO</desc>
     9680    </attribute>
     9681   
     9682  </interface>
    96079683
    96089684  <interface
    96099685    name="IGuestSession" extends="$unknown"
    9610     uuid="56f551a2-f924-43ab-8a69-a954109db878"
     9686    uuid="c8e8607b-5e67-4073-8f14-146515d0c1ff"
    96119687    wsmap="managed"
    96129688    >
     
    96899765      </desc>
    96909766    </attribute>
     9767   
     9768    <attribute name="eventSource" type="IEventSource" readonly="yes">
     9769      <desc>
     9770        Event source for guest session events.
     9771      </desc>
     9772    </attribute>
    96919773
    96929774    <method name="close">
     
    1070610788  <interface
    1070710789    name="IFile" extends="$unknown"
    10708     uuid="b702a560-6139-4a8e-a892-bbf14b97bf97"
     10790    uuid="0b45a95f-6267-499e-a7f2-efa5f8e081f2"
    1070910791    wsmap="managed"
    1071010792    >
     
    1071210794      Abstract parent interface for files handled by VirtualBox.
    1071310795    </desc>
     10796    <attribute name="status" type="FileStatus" readonly="yes">
     10797      <desc>
     10798        TODO
     10799      </desc>
     10800    </attribute>
    1071410801    <attribute name="creationMode" type="unsigned long" readonly="yes">
    1071510802      <desc>
     
    1857318660  <enum
    1857418661    name="VBoxEventType"
    18575     uuid="0d67e79e-b7b1-4919-aab3-b36866075515"
     18662    uuid="83c03e4b-ffe5-421c-a0fb-0b27b2d56753"
    1857618663    >
    1857718664
     
    1887118958      </desc>
    1887218959    </const>
    18873 
     18960    <const name="OnGuestSessionStateChanged" value="80">
     18961      <desc>
     18962        TODO
     18963      </desc>
     18964    </const>
     18965    <const name="OnGuestSessionRegistered" value="81">
     18966      <desc>
     18967        TODO
     18968      </desc>
     18969    </const>
     18970    <const name="OnGuestProcessRegistered" value="82">
     18971      <desc>
     18972        TODO
     18973      </desc>
     18974    </const>
     18975    <const name="OnGuestProcessStateChanged" value="83">
     18976      <desc>
     18977        TODO
     18978      </desc>
     18979    </const>
     18980    <const name="OnGuestProcessInputNotify" value="84">
     18981      <desc>
     18982        TODO
     18983      </desc>
     18984    </const>
     18985    <const name="OnGuestProcessOutput" value="85">
     18986      <desc>
     18987        TODO
     18988      </desc>
     18989    </const>
     18990    <const name="OnGuestFileStateChanged" value="86">
     18991      <desc>
     18992        TODO
     18993      </desc>
     18994    </const>
     18995    <const name="OnGuestFileOffsetChanged" value="87">
     18996      <desc>
     18997        TODO
     18998      </desc>
     18999    </const>
     19000    <const name="OnGuestFileRead" value="88">
     19001      <desc>
     19002        For performance reasons ... TODO
     19003      </desc>
     19004    </const>
     19005    <const name="OnGuestFileWrite" value="89">
     19006      <desc>
     19007        For performance reasons ... TODO
     19008      </desc>
     19009    </const>
    1887419010    <!-- Last event marker -->
    18875     <const name="Last" value="80">
     19011    <const name="Last" value="90">
    1887619012      <desc>
    1887719013        Must be last event, used for iterations and structures relying on numerical event values.
     
    1974519881  </interface>
    1974619882
    19747 
     19883  <interface
     19884    name="IGuestSessionEvent" extends="IEvent"
     19885    uuid="b9acd33f-647d-45ac-8fe9-f49b3183ba37"
     19886    wsmap="managed" id="GuestSessionEvent"
     19887    >
     19888    <desc>Base abstract interface for all guest session events.</desc>
     19889
     19890    <attribute name="session" type="IGuestSession" readonly="yes">
     19891      <desc>Guest session that is subject to change.</desc>
     19892    </attribute>
     19893
     19894  </interface>
     19895 
     19896  <interface
     19897    name="IGuestSessionStateChangedEvent" extends="IGuestSessionEvent"
     19898    uuid="9c288479-6564-451d-9574-7e7ac0b7e443"
     19899    wsmap="managed" autogen="VBoxEvent" id="OnGuestSessionStateChanged"
     19900    >
     19901    <desc>
     19902      TODO
     19903    </desc>
     19904   
     19905    <attribute name="id" type="unsigned long" readonly="yes">
     19906      <desc>
     19907        TODO
     19908      </desc>
     19909    </attribute>
     19910    <attribute name="status" type="GuestSessionStatus" readonly="yes">
     19911      <desc>
     19912        TODO
     19913      </desc>
     19914    </attribute>   
     19915    <attribute name="error" type="IGuestErrorInfo" readonly="yes">
     19916      <desc>
     19917        TODO
     19918      </desc>
     19919    </attribute>
     19920 
     19921  </interface>
     19922 
     19923  <interface
     19924    name="IGuestSessionRegisteredEvent" extends="IGuestSessionEvent"
     19925    uuid="b79de686-eabd-4fa6-960a-f1756c99ea1c"
     19926    wsmap="managed" autogen="VBoxEvent" id="OnGuestSessionRegistered"
     19927    >
     19928    <desc>
     19929      TODO
     19930    </desc>
     19931   
     19932    <attribute name="registered" type="boolean" readonly="yes">
     19933      <desc>
     19934        TODO
     19935      </desc>
     19936    </attribute>
     19937 
     19938  </interface>
     19939 
     19940  <interface
     19941    name="IGuestProcessEvent" extends="IGuestSessionEvent"
     19942    uuid="ee4be6e7-76c5-4517-a623-d4b1957d4ea4"
     19943    wsmap="managed" id="GuestProcessEvent"
     19944    >
     19945    <desc>Base abstract interface for all guest process events.</desc>
     19946
     19947    <attribute name="process" type="IGuestProcess" readonly="yes">
     19948      <desc>
     19949        TODO
     19950      </desc>
     19951    </attribute>
     19952    <attribute name="pid" type="unsigned long" readonly="yes">
     19953      <desc>
     19954        TODO
     19955      </desc>
     19956    </attribute>
     19957
     19958  </interface>
     19959 
     19960  <interface
     19961    name="IGuestProcessRegisteredEvent" extends="IGuestProcessEvent"
     19962    uuid="1d89e2b3-c6ea-45b6-9d43-dc6f70cc9f02"
     19963    wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessRegistered"
     19964    >
     19965    <desc>
     19966      TODO
     19967    </desc>
     19968   
     19969    <attribute name="registered" type="boolean" readonly="yes">
     19970      <desc>
     19971        TODO
     19972      </desc>
     19973    </attribute>
     19974 
     19975  </interface>
     19976 
     19977  <interface
     19978    name="IGuestProcessStateChangedEvent" extends="IGuestProcessEvent"
     19979    uuid="9360d372-d4d9-4948-8e67-e0a0e603acf9"
     19980    wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessStateChanged"
     19981    >
     19982    <desc>
     19983      TODO
     19984    </desc>
     19985   
     19986    <attribute name="status" type="ProcessStatus" readonly="yes">
     19987      <desc>
     19988        TODO
     19989      </desc>
     19990    </attribute>
     19991    <attribute name="error" type="IGuestErrorInfo" readonly="yes">
     19992      <desc>
     19993        TODO
     19994      </desc>
     19995    </attribute>
     19996
     19997  </interface>
     19998 
     19999  <interface
     20000    name="IGuestProcessInputNotifyEvent" extends="IGuestProcessEvent"
     20001    uuid="b3d6bb71-0392-4971-a908-f71c931995fd"
     20002    wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessInputNotify"
     20003    >
     20004    <desc>
     20005      TODO
     20006    </desc>
     20007   
     20008    <attribute name="status" type="ProcessInputStatus" readonly="yes">
     20009      <desc>
     20010        TODO
     20011      </desc>
     20012    </attribute>
     20013   
     20014    <attribute name="handle" type="unsigned long" readonly="yes">
     20015      <desc>
     20016        TODO
     20017      </desc>
     20018    </attribute>
     20019   
     20020    <attribute name="processed" type="unsigned long" readonly="yes">
     20021      <desc>
     20022        TODO
     20023      </desc>
     20024    </attribute>
     20025
     20026  </interface>
     20027 
     20028  <interface
     20029    name="IGuestProcessOutputEvent" extends="IGuestProcessEvent"
     20030    uuid="a13533b9-4aba-4937-836e-81325859c9d8"
     20031    wsmap="managed" autogen="VBoxEvent" id="OnGuestProcessOutput"
     20032    >
     20033    <desc>
     20034      TODO
     20035    </desc>
     20036   
     20037    <attribute name="handle" type="unsigned long" readonly="yes">
     20038      <desc>
     20039        TODO
     20040      </desc>
     20041    </attribute>
     20042   
     20043    <attribute name="data" type="octet" safearray="yes" readonly="yes">
     20044      <desc>
     20045        TODO
     20046      </desc>
     20047    </attribute>
     20048
     20049  </interface>
     20050 
     20051  <interface
     20052    name="IGuestFileEvent" extends="IGuestSessionEvent"
     20053    uuid="912f748f-d2f9-4fea-84d2-d36a017cc5f8"
     20054    wsmap="managed" id="GuestFileEvent"
     20055    >
     20056    <desc>Base abstract interface for all guest file events.</desc>
     20057
     20058    <attribute name="file" type="IGuestFile" readonly="yes">
     20059      <desc>
     20060        TODO
     20061      </desc>
     20062    </attribute>
     20063
     20064  </interface>
     20065 
     20066  <interface
     20067    name="IGuestFileStateChangedEvent" extends="IGuestFileEvent"
     20068    uuid="841951c4-4df3-4ee1-bb99-91e5761c18ff"
     20069    wsmap="managed" autogen="VBoxEvent" id="OnGuestFileStateChanged"
     20070    >
     20071    <desc>
     20072      TODO
     20073    </desc>
     20074   
     20075    <attribute name="status" type="FileStatus" readonly="yes">
     20076      <desc>
     20077        TODO
     20078      </desc>
     20079    </attribute>
     20080    <attribute name="error" type="IGuestErrorInfo" readonly="yes">
     20081      <desc>
     20082        TODO
     20083      </desc>
     20084    </attribute>
     20085    <!-- Note: No events for reads/writes for performance reasons.
     20086               See dedidcated events IGuestFileReadEvent and
     20087               IGuestFileWriteEvent. -->
     20088
     20089  </interface>
     20090 
     20091  <interface
     20092    name="IGuestFileIOEvent" extends="IGuestFileEvent"
     20093    uuid="b5191a7c-9536-4ef8-820e-3b0e17e5bbc8"
     20094    wsmap="managed" id="OnGuestFileIO"
     20095    >
     20096    <desc>
     20097      TODO
     20098    </desc>
     20099
     20100    <attribute name="offset" type="long long" readonly="yes">
     20101      <desc>
     20102        TODO
     20103      </desc>
     20104    </attribute>
     20105    <attribute name="processed" type="unsigned long" readonly="yes">
     20106      <desc>
     20107        TODO
     20108      </desc>
     20109     
     20110    </attribute>
     20111   
     20112  </interface>
     20113 
     20114  <interface
     20115    name="IGuestFileOffsetChangedEvent" extends="IGuestFileIOEvent"
     20116    uuid="e8f79a21-1207-4179-94cf-ca250036308f"
     20117    wsmap="managed" autogen="VBoxEvent" id="OnGuestFileOffsetChanged"
     20118    >
     20119    <desc>
     20120      TODO
     20121    </desc>
     20122
     20123  </interface>
     20124 
     20125  <interface
     20126    name="IGuestFileReadEvent" extends="IGuestFileIOEvent"
     20127    uuid="4ee3cbcb-486f-40db-9150-deee3fd24189"
     20128    wsmap="managed" autogen="VBoxEvent" id="OnGuestFileRead"
     20129    >
     20130    <desc>
     20131      TODO
     20132    </desc>
     20133   
     20134    <attribute name="data" type="octet" safearray="yes" readonly="yes">
     20135      <desc>
     20136        TODO
     20137      </desc>
     20138    </attribute>
     20139   
     20140  </interface>
     20141 
     20142  <interface
     20143    name="IGuestFileWriteEvent" extends="IGuestFileIOEvent"
     20144    uuid="e062a915-3cf5-4c0a-bc90-9b8d4cc94d89"
     20145    wsmap="managed" autogen="VBoxEvent" id="OnGuestFileWrite"
     20146    >
     20147    <desc>
     20148      TODO
     20149    </desc>
     20150   
     20151  </interface>
     20152 
    1974820153  <interface
    1974920154    name="IVRDEServerChangedEvent" extends="IEvent"
  • trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h

    r45109 r45415  
    132132    int Init(CALLBACKTYPE enmType);
    133133
    134     CALLBACKTYPE GetCallbackType(void) { return mType; }
     134    CALLBACKTYPE GetType(void) { return mType; }
    135135
    136136    const void* GetDataRaw(void) const { return pvData; }
     
    568568};
    569569
    570 /**
    571  * Pure virtual class (interface) for guest objects (processes, files, ...) --
     570class GuestBase
     571{
     572
     573public:
     574
     575    GuestBase(void);
     576    virtual ~GuestBase(void);
     577
     578public:
     579
     580    int generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID);
     581
     582protected:
     583
     584    /** Pointer to the console object. Needed
     585     *  for HGCM (VMMDev) communication. */
     586    Console                 *mConsole;
     587    /** The next upcoming context ID for this object. */
     588    uint32_t                 mNextContextID;
     589};
     590
     591/**
     592 * Virtual class (interface) for guest objects (processes, files, ...) --
    572593 * contains all per-object callback management.
    573594 */
    574 class GuestObject
    575 {
    576 
    577 public:
    578 
    579     ULONG getObjectID(void) { return mObject.mObjectID; }
     595class GuestObject : public GuestBase
     596{
     597
     598public:
     599
     600    GuestObject(void);
     601    virtual ~GuestObject(void);
     602
     603public:
     604
     605    ULONG getObjectID(void) { return mObjectID; }
    580606
    581607protected:
     
    587613
    588614    int bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID);
    589     int callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID);
    590     void callbackDelete(GuestCtrlCallback *pCallback);
    591     bool callbackExists(uint32_t uContextID);
    592     int callbackRemove(uint32_t uContextID);
    593     int callbackRemoveAll(void);
    594615    int sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
    595616
     
    597618
    598619    /**
    599      * Commom structure for all derived objects, when then have
     620     * Commom parameters for all derived objects, when then have
    600621     * an own mData structure to keep their specific data around.
    601622     */
    602     struct Object
    603     {
    604         /** Pointer to parent session. Per definition
    605          *  this objects *always* lives shorter than the
    606          *  parent. */
    607         GuestSession            *mSession;
    608         /** Pointer to the console object. Needed
    609          *  for HGCM (VMMDev) communication. */
    610         Console                 *mConsole;
    611         /** All related callbacks to this object. */
    612         GuestCtrlCallbacks       mCallbacks;
    613         /** The next upcoming context ID for this object. */
    614         ULONG                    mNextContextID;
    615         /** The object ID -- must be unique for each guest
    616          *  session and is encoded into the context ID. Must
    617          *  be set manually when initializing the object.
    618          *
    619          *  For guest processes this is the internal PID,
    620          *  for guest files this is the internal file ID. */
    621         uint32_t                 mObjectID;
    622     } mObject;
    623 };
    624 
    625 #if 0
    626 /*
    627  * Guest (HGCM) callbacks. All classes will throw
    628  * an exception on misuse.
    629  */
    630 
    631 /** Callback class for guest process status. */
    632 class GuestCbProcessStatus : public GuestCtrlCallback
    633 {
    634 
    635 public:
    636 
    637     int Init(uint32_t uProtocol, uint32_t uFunction,
    638              PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
    639     {
    640         AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
    641 
    642         int rc = GuestCtrlCallback::Init();
    643         if (RT_FAILURE(rc))
    644             return rc;
    645 
    646         if (   uFunction != GUEST_EXEC_SEND_STATUS
    647             || pSvcCb->mParms < 5)
    648             return VERR_INVALID_PARAMETER;
    649 
    650         /* pSvcCb->mpaParms[0] always contains the context ID. */
    651         pSvcCb->mpaParms[1].getUInt32(&mPID);
    652         pSvcCb->mpaParms[2].getUInt32(&mStatus);
    653         pSvcCb->mpaParms[3].getUInt32(&mFlags); /* Can contain an IPRT error, which is a signed int. */
    654         pSvcCb->mpaParms[4].getPointer(&mData, &mcbData);
    655 
    656         return VINF_SUCCESS;
    657     }
    658 
    659     void Destroy(void) { }
    660 
    661     uint32_t  mPID;
    662     uint32_t  mStatus;
    663     uint32_t  mFlags;
    664     void     *mData;
    665     uint32_t  mcbData;
    666 };
    667 
    668 /** Callback class for guest process input. */
    669 class GuestCbProcessInput : public GuestCtrlCallback
    670 {
    671 
    672 public:
    673 
    674     int Init(uint32_t uProtocol, uint32_t uFunction,
    675              PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
    676     {
    677         AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
    678 
    679         int rc = GuestCtrlCallback::Init();
    680         if (RT_FAILURE(rc))
    681             return rc;
    682 
    683         if (   uFunction != GUEST_EXEC_SEND_INPUT_STATUS
    684             || pSvcCb->mParms < 5)
    685             return VERR_INVALID_PARAMETER;
    686 
    687         /* pSvcCb->mpaParms[0] always contains the context ID. */
    688         pSvcCb->mpaParms[1].getUInt32(&mPID);
    689         /* Associated file handle. */
    690         pSvcCb->mpaParms[2].getUInt32(&mStatus);
    691         pSvcCb->mpaParms[3].getUInt32(&mFlags);
    692         pSvcCb->mpaParms[4].getUInt32(&mProcessed);
    693 
    694         return VINF_SUCCESS;
    695     }
    696 
    697     void Destroy(void) { }
    698 
    699     GuestCbProcessInput& operator=(const GuestCbProcessInput &that)
    700     {
    701         mPID = that.mPID;
    702         mStatus = that.mStatus;
    703         mFlags = that.mFlags;
    704         mProcessed = that.mProcessed;
    705         return *this;
    706     }
    707 
    708     uint32_t  mPID;
    709     uint32_t  mStatus;
    710     uint32_t  mFlags;
    711     uint32_t  mProcessed;
    712 };
    713 
    714 /** Callback class for guest process output. */
    715 class GuestCbProcessOutput : public GuestCtrlCallback
    716 {
    717 
    718 public:
    719 
    720     int Init(uint32_t uProtocol, uint32_t uFunction,
    721              PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
    722     {
    723         AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
    724 
    725         int rc = GuestCtrlCallback::Init();
    726         if (RT_FAILURE(rc))
    727             return rc;
    728 
    729         if (   uFunction != GUEST_EXEC_SEND_OUTPUT
    730             || pSvcCb->mParms < 5)
    731             return VERR_INVALID_PARAMETER;
    732 
    733         /* pSvcCb->mpaParms[0] always contains the context ID. */
    734         pSvcCb->mpaParms[1].getUInt32(&mPID);
    735         /* Associated file handle. */
    736         pSvcCb->mpaParms[2].getUInt32(&mHandle);
    737         pSvcCb->mpaParms[3].getUInt32(&mFlags);
    738 
    739         void *pbData; uint32_t cbData;
    740         rc = pSvcCb->mpaParms[4].getPointer(&pbData, &cbData);
    741         if (RT_SUCCESS(rc))
    742         {
    743             Assert(cbData);
    744             mData = RTMemAlloc(cbData);
    745             AssertPtrReturn(mData, VERR_NO_MEMORY);
    746             memcpy(mData, pbData, cbData);
    747             mcbData = cbData;
    748         }
    749 
    750         return rc;
    751     }
    752 
    753     void Destroy(void)
    754     {
    755         if (mData)
    756         {
    757             RTMemFree(mData);
    758             mData = NULL;
    759             mcbData = 0;
    760         }
    761     }
    762 
    763     GuestCbProcessOutput& operator=(const GuestCbProcessOutput &that)
    764     {
    765         mPID = that.mPID;
    766         mHandle = that.mHandle;
    767         mFlags = that.mFlags;
    768 
    769         Destroy();
    770         if (that.mcbData)
    771         {
    772             void *pvData = RTMemAlloc(that.mcbData);
    773             if (pvData)
    774             {
    775                 AssertPtr(pvData);
    776                 memcpy(pvData, that.mData, that.mcbData);
    777                 mData = pvData;
    778                 mcbData = that.mcbData;
    779             }
    780         }
    781 
    782         return *this;
    783     }
    784 
    785     uint32_t  mPID;
    786     uint32_t  mHandle;
    787     uint32_t  mFlags;
    788     void     *mData;
    789     size_t    mcbData;
    790 };
    791 
    792 /** Callback class for guest process IO notifications. */
    793 class GuestCbProcessIO : public GuestCtrlCallback
    794 {
    795 
    796 public:
    797 
    798     int Init(uint32_t uProtocol, uint32_t uFunction,
    799              PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
    800     {
    801         AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
    802 
    803         int rc = GuestCtrlCallback::Init();
    804         if (RT_FAILURE(rc))
    805             return rc;
    806 
    807         return VERR_NOT_IMPLEMENTED;
    808     }
    809 
    810     void Destroy(void) { GuestCtrlCallback::Destroy(); }
    811 
    812     GuestCbProcessIO& operator=(const GuestCbProcessIO &that)
    813     {
    814         return *this;
    815     }
    816 };
    817 #endif
     623
     624    /** Pointer to parent session. Per definition
     625     *  this objects *always* lives shorter than the
     626     *  parent. */
     627    GuestSession            *mSession;
     628    /** The object ID -- must be unique for each guest
     629     *  object and is encoded into the context ID. Must
     630     *  be set manually when initializing the object.
     631     *
     632     *  For guest processes this is the internal PID,
     633     *  for guest files this is the internal file ID. */
     634    uint32_t                 mObjectID;
     635};
    818636#endif // ____H_GUESTIMPLPRIVATE
    819637
  • trunk/src/VBox/Main/include/GuestFileImpl.h

    r45109 r45415  
    2121
    2222#include "VirtualBoxBase.h"
     23#include "EventImpl.h"
    2324
    2425#include "GuestFsObjInfoImpl.h"
     
    6364    STDMETHOD(COMGETTER(Offset))(LONG64 *aOffset);
    6465    STDMETHOD(COMGETTER(OpenMode))(ULONG *aOpenMode);
     66    STDMETHOD(COMGETTER(Status))(FileStatus_T *aStatus);
    6567
    6668    STDMETHOD(Close)(void);
     
    8082    int             closeFile(int *pGuestRc);
    8183    static uint32_t getDispositionFromString(const Utf8Str &strDisposition);
     84    EventSource    *getEventSource(void) { return mEventSource; }
    8285    static uint32_t getOpenModeFromString(const Utf8Str &strOpenMode);
    8386    static Utf8Str  guestErrorToString(int guestRc);
    84     int             onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData, GuestCtrlCallback *pCallback);
    85     int             onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData, GuestCtrlCallback *pCallback);
     87    int             onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
     88    int             onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
    8689    int             openFile(int *pGuestRc);
    87     int             readData(uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc);
    88     int             readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc);
    89     int             seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, uint32_t uTimeoutMS, int *pGuestRc);
    90     int             sendFileCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms, uint32_t uTimeoutMS, int *pGuestRc, GuestCtrlCallback **ppCallback);
     90    int             readData(uint32_t uSize, uint32_t uTimeoutMS, void* pvData, uint32_t cbData, uint32_t* pcbRead);
     91    int             readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS, void* pvData, size_t cbData, size_t* pcbRead);
     92    int             seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType, uint32_t uTimeoutMS, uint64_t *puOffset);
    9193    static HRESULT  setErrorExternal(VirtualBoxBase *pInterface, int guestRc);
    92     int             writeData(uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbWritten, int *pGuestRc);
    93     int             writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, size_t cbData, uint32_t *pcbWritten, int *pGuestRc);
     94    int             setFileStatus(FileStatus_T fileStatus, int fileRc);
     95    int             waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset);
     96    int             waitForRead(uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead);
     97    int             waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus);
     98    int             waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten);
     99    int             writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten);
     100    int             writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS, void *pvData, uint32_t cbData, uint32_t *pcbWritten);
    94101    /** @}  */
    95102
    96103private:
    97104
     105    /** The internal console object. */
     106    Console                *mConsole;
     107    /** The associate session this file belongs to. */
     108    GuestSession           *mSession;
     109    /** This can safely be used without holding any locks.
     110     * An AutoCaller suffices to prevent it being destroy while in use and
     111     * internally there is a lock providing the necessary serialization. */
     112    const ComObjPtr<EventSource> mEventSource;
     113
    98114    struct Data
    99115    {
    100         /** The internal console object. */
    101         Console                *mConsole;
    102         /** The associate session this file belongs to. */
    103         GuestSession           *mSession;
    104116        /** All related callbacks to this file. */
    105117        GuestCtrlCallbacks      mCallbacks;
     
    110122        /** The file's internal ID. */
    111123        uint32_t                mID;
     124        /** The current file status. */
     125        FileStatus_T            mStatus;
    112126        /** The file's current offset. */
    113127        uint64_t                mOffCurrent;
  • trunk/src/VBox/Main/include/GuestImpl.h

    r44935 r45415  
    177177        GuestSessions           mGuestSessions;
    178178        uint32_t                mNextSessionID;
    179     };
    180 
    181     ULONG             mMemoryBalloonSize;
    182     ULONG             mStatUpdateInterval;
    183     uint64_t          mNetStatRx;
    184     uint64_t          mNetStatTx;
    185     uint64_t          mNetStatLastTs;
    186     ULONG             mCurrentGuestStat[GUESTSTATTYPE_MAX];
    187     ULONG             mVmValidStats;
    188     BOOL              mCollectVMMStats;
    189     BOOL              mfPageFusionEnabled;
    190 
    191     Console *mParent;
    192     Data mData;
    193 
    194 #ifdef VBOX_WITH_GUEST_CONTROL
     179    } mData;
     180
     181    ULONG                           mMemoryBalloonSize;
     182    ULONG                           mStatUpdateInterval;
     183    uint64_t                        mNetStatRx;
     184    uint64_t                        mNetStatTx;
     185    uint64_t                        mNetStatLastTs;
     186    ULONG                           mCurrentGuestStat[GUESTSTATTYPE_MAX];
     187    ULONG                           mVmValidStats;
     188    BOOL                            mCollectVMMStats;
     189    BOOL                            mfPageFusionEnabled;
     190
     191    Console                        *mParent;
     192
     193#ifdef VBOX_WITH_GUEST_CONTROL
     194    /**
     195     * This can safely be used without holding any locks.
     196     * An AutoCaller suffices to prevent it being destroy while in use and
     197     * internally there is a lock providing the necessary serialization.
     198     */
     199    const ComObjPtr<EventSource>    mEventSource;
    195200    /** General extension callback for guest control. */
    196     HGCMSVCEXTHANDLE  mhExtCtrl;
     201    HGCMSVCEXTHANDLE                mhExtCtrl;
    197202#endif
    198203
  • trunk/src/VBox/Main/include/GuestProcessImpl.h

    r45010 r45415  
    8383    int terminateProcess(int *pGuestRc);
    8484    int waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc);
     85    int waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS, ProcessInputStatus_T *pInputStatus, size_t *pcbProcessed);
     86    int waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS, void* pvData, size_t cbData, size_t* pcbRead);
     87    int waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, ProcessStatus_T *pProcessStatus, int *pGuestRc);
    8588    int writeData(uint32_t uHandle, uint32_t uFlags, void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc);
    8689    /** @}  */
     
    9093     * @{ */
    9194    inline bool isAlive(void);
    92     int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
    93     int onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
    94     int onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback * pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
    95     int onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
    96     int onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
     95    int onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
     96    int onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
     97    int onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
     98    int onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
     99    int onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
    97100    int prepareExecuteEnv(const char *pszEnv, void **ppvList, ULONG *pcbList, ULONG *pcEnvVars);
    98101    int setProcessStatus(ProcessStatus_T procStatus, int procRc);
    99     int signalWaiters(ProcessWaitResult_T enmWaitResult, int rc = VINF_SUCCESS);
    100102    static DECLCALLBACK(int) startProcessThread(RTTHREAD Thread, void *pvUser);
    101103    /** @}  */
    102104
    103105private:
     106
     107    /**
     108     * This can safely be used without holding any locks.
     109     * An AutoCaller suffices to prevent it being destroy while in use and
     110     * internally there is a lock providing the necessary serialization.
     111     */
     112    const ComObjPtr<EventSource> mEventSource;
    104113
    105114    struct Data
     
    116125         *  returned from the guest side. */
    117126        int                      mRC;
    118         /** How many waiters? At the moment there can only
    119          *  be one. */
    120         uint32_t                 mWaitCount;
    121         /** The actual process event for doing the waits.
    122          *  At the moment we only support one wait a time. */
    123         GuestProcessWaitEvent   *mWaitEvent;
    124127    } mData;
    125128};
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r45010 r45415  
    2121
    2222#include "VirtualBoxBase.h"
     23#include "EventImpl.h"
    2324
    2425#include "GuestCtrlImplPrivate.h"
     
    238239class ATL_NO_VTABLE GuestSession :
    239240    public VirtualBoxBase,
     241    public GuestBase,
    240242    VBOX_SCRIPTABLE_IMPL(IGuestSession)
    241243{
     
    271273    STDMETHOD(COMGETTER(Directories))(ComSafeArrayOut(IGuestDirectory *, aDirectories));
    272274    STDMETHOD(COMGETTER(Files))(ComSafeArrayOut(IGuestFile *, aFiles));
     275    STDMETHOD(COMGETTER(EventSource))(IEventSource ** aEventSource);
    273276    /** @}  */
    274277
     
    345348    const GuestCredentials &getCredentials(void);
    346349    const GuestEnvironment &getEnvironment(void);
     350    EventSource            *getEventSource(void) { return mEventSource; }
    347351    Utf8Str                 getName(void);
    348352    ULONG                   getId(void) { return mData.mSession.mID; }
    349353    static Utf8Str          guestErrorToString(int guestRc);
    350     int                     onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
     354    HRESULT                 isReadyExternal(void);
     355    int                     onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
    351356    int                     startSessionIntenal(int *pGuestRc);
    352357    int                     startSessionAsync(void);
    353358    static DECLCALLBACK(int)
    354359                            startSessionThread(RTTHREAD Thread, void *pvUser);
    355     Guest                  *getParent(void) { return mData.mParent; }
     360    Guest                  *getParent(void) { return mParent; }
    356361    uint32_t                getProtocolVersion(void) { return mData.mProtocolVersion; }
    357362    int                     processRemoveFromList(GuestProcess *pProcess);
     
    361366    int                     sendCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms);
    362367    static HRESULT          setErrorExternal(VirtualBoxBase *pInterface, int guestRc);
     368    int                     setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc);
     369    int                     signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */);
    363370    int                     startTaskAsync(const Utf8Str &strTaskDesc, GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress);
    364371    int                     queryInfo(void);
    365372    int                     waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc);
     373    int                     waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS, GuestSessionStatus_T *pSessionStatus, int *pGuestRc);
    366374    /** @}  */
    367375
    368376private:
     377
     378    /** Pointer to the parent (Guest). */
     379    Guest                          *mParent;
     380    /**
     381     * This can safely be used without holding any locks.
     382     * An AutoCaller suffices to prevent it being destroy while in use and
     383     * internally there is a lock providing the necessary serialization.
     384     */
     385    const ComObjPtr<EventSource>    mEventSource;
    369386
    370387    struct Data
    371388    {
    372         /** Pointer to the parent (Guest). */
    373         Guest                      *mParent;
    374389        /** The session credentials. */
    375390        GuestCredentials            mCredentials;
     
    381396         *  overwritten/extended by ProcessCreate(Ex). */
    382397        GuestEnvironment            mEnvironment;
    383         /** The session callback, needed for communicating
    384          *  with the guest. */
    385         GuestCtrlCallback           mCallback;
    386398        /** Directory objects bound to this session. */
    387399        SessionDirectories          mDirectories;
     
    402414         *  returned from the guest side. */
    403415        int                         mRC;
    404         /** How many waiters? At the moment there can only
    405          *  be one. */
    406         uint32_t                    mWaitCount;
    407         /** The actual session event for doing the waits.
    408          *  At the moment we only support one wait a time. */
    409         GuestSessionWaitEvent      *mWaitEvent;
    410416    } mData;
    411417};
  • trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp

    r45078 r45415  
    55
    66/*
    7  * Copyright (C) 2006-2012 Oracle Corporation
     7 * Copyright (C) 2006-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2323#include "ConsoleImpl.h"
    2424#include "ProgressImpl.h"
     25#include "VBoxEvents.h"
    2526#include "VMMDev.h"
    2627
     
    159160        {
    160161            case VERR_MAX_PROCS_REACHED:
    161                 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),
     162                hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"),
    162163                              VBOX_GUESTCTRL_MAX_SESSIONS);
    163164                break;
     
    316317    LogFlowFunc(("Closing session (ID=%RU32) ...\n", pSession->getId()));
    317318
    318     for (GuestSessions::iterator itSessions = mData.mGuestSessions.begin();
    319          itSessions != mData.mGuestSessions.end(); ++itSessions)
     319    GuestSessions::iterator itSessions = mData.mGuestSessions.begin();
     320    while (itSessions != mData.mGuestSessions.end())
    320321    {
    321322        if (pSession == itSessions->second)
     
    324325                         (GuestSession *)itSessions->second, itSessions->second->getId(), mData.mGuestSessions.size() - 1));
    325326
    326             mData.mGuestSessions.erase(itSessions++);
    327 
     327            mData.mGuestSessions.erase(itSessions);
     328
     329            fireGuestSessionRegisteredEvent(mEventSource, pSession,
     330                                            false /* Unregistered */);
    328331            rc = VINF_SUCCESS;
    329332            break;
    330333        }
     334
     335        itSessions++;
    331336    }
    332337
     
    398403         * Add session object to our session map. This is necessary
    399404         * before calling openSession because the guest calls back
    400          * with the creation result to this session.
     405         * with the creation result of this session.
    401406         */
    402407        mData.mGuestSessions[uNewSessionID] = pGuestSession;
    403408
    404         /* Drop write lock before opening session, because this will
    405          * involve the main dispatcher to run. */
    406         alock.release();
     409        fireGuestSessionRegisteredEvent(mEventSource, pGuestSession,
     410                                        true /* Registered */);
    407411    }
    408412    catch (int rc2)
     
    459463    }
    460464
    461     int guestRc;
    462465    if (RT_SUCCESS(rc))
    463466    {
    464         /** @todo Do we need to use openSessioAsync() here? Otherwise
    465          *        there might be a problem on webservice calls (= timeouts)
    466          *        if opening the guest session takes too long -> Use
    467          *        the new session.getStatus() API call! */
    468 
    469         /* Start (fork) the session on the guest. */
    470         rc = pSession->startSessionIntenal(&guestRc);
    471         if (RT_SUCCESS(rc))
    472         {
    473             LogFlowFunc(("Created new guest session (pSession=%p), now %zu sessions total\n",
    474                          (GuestSession *)pSession, mData.mGuestSessions.size()));
    475         }
     467        /* Start (fork) the session asynchronously
     468         * on the guest. */
     469        rc = pSession->startSessionAsync();
    476470    }
    477471
     
    482476        switch (rc)
    483477        {
    484             case VERR_GSTCTL_GUEST_ERROR:
    485                 hr = GuestSession::setErrorExternal(this, guestRc);
    486                 break;
    487 
    488478            case VERR_MAX_PROCS_REACHED:
    489                 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest sessions (%ld) reached"),
     479                hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"),
    490480                              VBOX_GUESTCTRL_MAX_SESSIONS);
    491481                break;
  • trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp

    r45367 r45415  
    12581258}
    12591259
     1260GuestBase::GuestBase(void)
     1261    : mConsole(NULL),
     1262      mNextContextID(0)
     1263{
     1264}
     1265
     1266GuestBase::~GuestBase(void)
     1267{
     1268}
     1269
     1270int GuestBase::generateContextID(uint32_t uSessionID, uint32_t uObjectID, uint32_t *puContextID)
     1271{
     1272    AssertPtrReturn(puContextID, VERR_INVALID_POINTER);
     1273
     1274    uint32_t uCount = mNextContextID++;
     1275    if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)
     1276        uCount = 0;
     1277
     1278    uint32_t uNewContextID =
     1279        VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount);
     1280
     1281    *puContextID = uNewContextID;
     1282}
     1283
     1284GuestObject::GuestObject(void)
     1285    : mSession(NULL),
     1286      mObjectID(0)
     1287{
     1288}
     1289
     1290GuestObject::~GuestObject(void)
     1291{
     1292}
     1293
    12601294int GuestObject::bindToSession(Console *pConsole, GuestSession *pSession, uint32_t uObjectID)
    12611295{
     
    12631297    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
    12641298
    1265     mObject.mConsole = pConsole;
    1266     mObject.mSession = pSession;
    1267 
    1268     mObject.mNextContextID = 0;
    1269     mObject.mObjectID = uObjectID;
     1299    mConsole  = pConsole;
     1300    mSession  = pSession;
     1301    mObjectID = uObjectID;
    12701302
    12711303    return VINF_SUCCESS;
    1272 }
    1273 
    1274 int GuestObject::callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID)
    1275 {
    1276     const ComObjPtr<GuestSession> pSession(mObject.mSession);
    1277     Assert(!pSession.isNull());
    1278     ULONG uSessionID = 0;
    1279     pSession->COMGETTER(Id)(&uSessionID);
    1280 
    1281     /* Create a new context ID and assign it. */
    1282     int vrc = VERR_NOT_FOUND;
    1283 
    1284     ULONG uCount = mObject.mNextContextID++;
    1285     ULONG uNewContextID = 0;
    1286     ULONG uTries = 0;
    1287     for (;;)
    1288     {
    1289         if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)
    1290             uCount = 0;
    1291 
    1292         /* Create a new context ID ... */
    1293         uNewContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, mObject.mObjectID, uCount);
    1294 
    1295         /* Is the context ID already used?  Try next ID ... */
    1296         if (!callbackExists(uCount))
    1297         {
    1298             /* Callback with context ID was not found. This means
    1299              * we can use this context ID for our new callback we want
    1300              * to add below. */
    1301             vrc = VINF_SUCCESS;
    1302             break;
    1303         }
    1304 
    1305         uCount++;
    1306         if (++uTries == UINT32_MAX)
    1307             break; /* Don't try too hard. */
    1308     }
    1309 
    1310     if (RT_SUCCESS(vrc))
    1311     {
    1312         /* Add callback with new context ID to our callback map.
    1313          * Note: This is *not* uNewContextID (which also includes
    1314          *       the session + process ID), just the context count
    1315          *       will be used here. */
    1316         mObject.mCallbacks[uCount] = pCallback;
    1317         Assert(mObject.mCallbacks.size());
    1318 
    1319         /* Report back new context ID. */
    1320         if (puContextID)
    1321             *puContextID = uNewContextID;
    1322 
    1323         LogFlowThisFunc(("Added new callback (Session: %RU32, Object: %RU32, Count: %RU32) CID=%RU32\n",
    1324                          uSessionID, mObject.mObjectID, uCount, uNewContextID));
    1325     }
    1326 
    1327     return vrc;
    1328 }
    1329 
    1330 void GuestObject::callbackDelete(GuestCtrlCallback *pCallback)
    1331 {
    1332     if (pCallback)
    1333     {
    1334         delete pCallback;
    1335         pCallback = NULL;
    1336     }
    1337 }
    1338 
    1339 bool GuestObject::callbackExists(uint32_t uContextID)
    1340 {
    1341     GuestCtrlCallbacks::const_iterator it =
    1342         mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
    1343     return (it == mObject.mCallbacks.end()) ? false : true;
    1344 }
    1345 
    1346 int GuestObject::callbackRemove(uint32_t uContextID)
    1347 {
    1348     LogFlowThisFunc(("Removing callback (Session=%RU32, Object=%RU32, Count=%RU32) CID=%RU32\n",
    1349                      VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID),
    1350                      VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID),
    1351                      VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID),
    1352                      uContextID));
    1353 
    1354     GuestCtrlCallbacks::iterator it =
    1355         mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
    1356     if (it != mObject.mCallbacks.end())
    1357     {
    1358         mObject.mCallbacks.erase(it);
    1359 
    1360         return VINF_SUCCESS;
    1361     }
    1362 
    1363     return VERR_NOT_FOUND;
    1364 }
    1365 
    1366 int GuestObject::callbackRemoveAll(void)
    1367 {
    1368     int vrc = VINF_SUCCESS;
    1369 
    1370     /*
    1371      * Cancel all callbacks + waiters.
    1372      * Note: Deleting them is the job of the caller!
    1373      */
    1374     for (GuestCtrlCallbacks::iterator itCallbacks = mObject.mCallbacks.begin();
    1375          itCallbacks != mObject.mCallbacks.end(); ++itCallbacks)
    1376     {
    1377         GuestCtrlCallback *pCallback = itCallbacks->second;
    1378         AssertPtr(pCallback);
    1379         int rc2 = pCallback->Cancel();
    1380         if (RT_SUCCESS(vrc))
    1381             vrc = rc2;
    1382     }
    1383     mObject.mCallbacks.clear();
    1384 
    1385     return vrc;
    13861304}
    13871305
     
    13921310
    13931311#ifndef VBOX_GUESTCTRL_TEST_CASE
    1394     ComObjPtr<Console> pConsole = mObject.mConsole;
     1312    ComObjPtr<Console> pConsole = mConsole;
    13951313    Assert(!pConsole.isNull());
    13961314
  • trunk/src/VBox/Main/src-client/GuestFileImpl.cpp

    r45109 r45415  
    2121*   Header Files                                                               *
    2222*******************************************************************************/
     23#include "GuestErrorInfoImpl.h"
    2324#include "GuestFileImpl.h"
    2425#include "GuestSessionImpl.h"
     
    2829#include "Global.h"
    2930#include "AutoCaller.h"
    30 
     31#include "VBoxEvents.h"
     32
     33#include <iprt/cpp/utils.h> /* For unconst(). */
    3134#include <iprt/file.h>
    3235#include <VBox/com/array.h>
     
    8891        mData.mID = 0;
    8992        mData.mInitialSize = 0;
    90 
     93        mData.mStatus = FileStatus_Undefined;
     94
     95        unconst(mEventSource).createObject();
     96        HRESULT hr = mEventSource->init(static_cast<IGuestFile*>(this));
     97        if (FAILED(hr))
     98            vrc = VERR_COM_UNEXPECTED;
     99    }
     100
     101    if (RT_SUCCESS(vrc))
     102    {
    91103        /* Confirm a successful initialization when it's the case. */
    92104        autoInitSpan.setSucceeded();
    93         return vrc;
    94     }
    95 
    96     autoInitSpan.setFailed();
     105    }
     106    else
     107        autoInitSpan.setFailed();
     108
     109    LogFlowFuncLeaveRC(vrc);
    97110    return vrc;
    98111}
     
    112125
    113126#ifdef VBOX_WITH_GUEST_CONTROL
    114     /*
    115      * Cancel + remove all callbacks + waiters.
    116      * Note: Deleting them is the job of the caller!
    117      */
    118     callbackRemoveAll();
     127    unconst(mEventSource).setNull();
    119128#endif
    120129
     
    230239
    231240    *aOpenMode = getOpenModeFromString(mData.mOpenInfo.mOpenMode);
     241
     242    return S_OK;
     243#endif /* VBOX_WITH_GUEST_CONTROL */
     244}
     245
     246STDMETHODIMP GuestFile::COMGETTER(Status)(FileStatus_T *aStatus)
     247{
     248#ifndef VBOX_WITH_GUEST_CONTROL
     249    ReturnComNotImplemented();
     250#else
     251    LogFlowThisFuncEnter();
     252
     253    AutoCaller autoCaller(this);
     254    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     255
     256    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     257
     258    *aStatus = mData.mStatus;
    232259
    233260    return S_OK;
     
    248275    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    249276
    250     /* Get the optional callback associated to this context ID.
    251      * The callback may not be around anymore if just kept locally by the caller when
    252      * doing the actual HGCM sending stuff. */
    253     GuestCtrlCallback *pCallback = NULL;
    254     GuestCtrlCallbacks::const_iterator it
    255         = mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID));
    256     if (it != mData.mCallbacks.end())
    257     {
    258         pCallback = it->second;
    259         AssertPtr(pCallback);
    260 #ifdef DEBUG
    261         LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",
    262                          pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));
    263 #endif
    264     }
    265 
    266277    int vrc;
    267278    switch (pCbCtx->uFunction)
    268279    {
    269280        case GUEST_DISCONNECTED:
    270             vrc = onGuestDisconnected(pCbCtx, pSvcCb, pCallback); /* Affects all callbacks. */
     281            vrc = onGuestDisconnected(pCbCtx, pSvcCb);
    271282            break;
    272283
    273284        case GUEST_FILE_NOTIFY:
    274             vrc = onFileNotify(pCbCtx, pSvcCb, pCallback);
     285            vrc = onFileNotify(pCbCtx, pSvcCb);
    275286            break;
    276287
     
    291302    LogFlowThisFunc(("strFile=%s\n", mData.mOpenInfo.mFileName.c_str()));
    292303
    293     /* Prepare HGCM call. */
    294     VBOXHGCMSVCPARM paParms[4];
    295     int i = 1; /* Context ID will be set in sendFileComannd(). */
    296     paParms[i++].setUInt32(mData.mID /* Guest file ID */);
    297 
    298     int guestRc;
    299     int vrc = sendFileCommand(HOST_FILE_CLOSE, i, paParms, 30 * 1000 /* 30s timeout */,
    300                               &guestRc, NULL /* ppCallback */);
    301     if (pGuestRc)
    302         *pGuestRc = guestRc;
     304    uint32_t uContextID;
     305    int vrc = generateContextID(mSession->getId(), mObjectID,
     306                                &uContextID);
     307    if (RT_SUCCESS(vrc))
     308    {
     309        /* Prepare HGCM call. */
     310        VBOXHGCMSVCPARM paParms[4];
     311        int i = 0;
     312        paParms[i++].setUInt32(mData.mID /* Guest file ID */);
     313
     314        vrc = sendCommand(HOST_FILE_CLOSE, i, paParms);
     315        if (RT_SUCCESS(vrc))
     316            vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */,
     317                                      NULL /* FileStatus */);
     318    }
    303319
    304320    LogFlowFuncLeaveRC(vrc);
     
    383399}
    384400
    385 int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData,
    386                             GuestCtrlCallback *pCallback)
     401int GuestFile::onFileNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    387402{
    388403    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    389404    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
    390     /* pCallback is optional. */
    391405
    392406    if (pSvcCbData->mParms < 3)
     
    401415    pSvcCbData->mpaParms[idx++].getUInt32(&dataCb.rc);
    402416
     417    int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
     418
    403419    switch (dataCb.uType)
    404420    {
    405421        case GUEST_FILE_NOTIFYTYPE_ERROR:
    406             /* No extra data. */
    407             break;
     422        {
     423            AssertMsg(mData.mStatus != FileStatus_Error, ("File status already set to error\n"));
     424
     425            int rc2 = setFileStatus(FileStatus_Error, guestRc);
     426            AssertRC(rc2);
     427            break;
     428        }
    408429
    409430        case GUEST_FILE_NOTIFYTYPE_OPEN:
     431        {
    410432            if (pSvcCbData->mParms == 4)
    411433            {
     
    417439                          ("File ID %RU32 does not match context ID %RU32\n", mData.mID,
    418440                           VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCbCtx->uContextID)));
     441
     442                /* Set the process status. */
     443                int rc2 = setFileStatus(FileStatus_Open, guestRc);
     444                if (RT_SUCCESS(vrc))
     445                    vrc = rc2;
    419446            }
    420447            else
    421448                vrc = VERR_NOT_SUPPORTED;
    422             break;
     449
     450            break;
     451        }
    423452
    424453        case GUEST_FILE_NOTIFYTYPE_CLOSE:
    425             /* No extra data. */
    426             break;
     454        {
     455            int rc2 = setFileStatus(FileStatus_Closed, guestRc);
     456            AssertRC(rc2);
     457
     458            break;
     459        }
    427460
    428461        case GUEST_FILE_NOTIFYTYPE_READ:
     
    431464                pSvcCbData->mpaParms[idx++].getPointer(&dataCb.u.read.pvData,
    432465                                                       &dataCb.u.read.cbData);
    433 
    434                 mData.mOffCurrent += dataCb.u.read.cbData;
     466                uint32_t cbRead = dataCb.u.read.cbData;
     467                if (cbRead)
     468                {
     469                    mData.mOffCurrent += cbRead;
     470
     471                    com::SafeArray<BYTE> data((size_t)cbRead);
     472                    data.initFrom((BYTE*)dataCb.u.read.pvData, cbRead);
     473                    fireGuestFileReadEvent(mEventSource, mSession, this, mData.mOffCurrent,
     474                                           cbRead, ComSafeArrayAsInParam(data));
     475                }
    435476            }
    436477            else
     
    444485
    445486                mData.mOffCurrent += dataCb.u.write.cbWritten;
     487
     488                if (dataCb.u.write.cbWritten)
     489                    fireGuestFileWriteEvent(mEventSource, mSession, this, mData.mOffCurrent,
     490                                            dataCb.u.write.cbWritten);
    446491            }
    447492            else
     
    455500
    456501                mData.mOffCurrent = dataCb.u.seek.uOffActual;
     502
     503                if (dataCb.u.seek.uOffActual)
     504                    fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
     505                                                    mData.mOffCurrent, 0 /* Processed */);
    457506            }
    458507            else
     
    465514                pSvcCbData->mpaParms[idx++].getUInt64(&dataCb.u.tell.uOffActual);
    466515
    467                 mData.mOffCurrent = dataCb.u.tell.uOffActual;
     516                if (mData.mOffCurrent != dataCb.u.tell.uOffActual)
     517                {
     518                    mData.mOffCurrent = dataCb.u.tell.uOffActual;
     519
     520                    fireGuestFileOffsetChangedEvent(mEventSource, mSession, this,
     521                                                    mData.mOffCurrent, 0 /* Processed */);
     522                }
    468523            }
    469524            else
     
    476531    }
    477532
    478     LogFlowThisFunc(("strName=%s, uType=%RU32, rc=%Rrc, pCallback=%p\n",
    479                      mData.mOpenInfo.mFileName.c_str(), dataCb.uType, dataCb.rc, pCallback));
    480 
    481     int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
     533    LogFlowThisFunc(("strName=%s, uType=%RU32, guestRc=%Rrc\n",
     534                     mData.mOpenInfo.mFileName.c_str(), dataCb.uType, dataCb.rc));
     535
    482536    if (RT_SUCCESS(vrc))
    483537    {
     
    490544    }
    491545
    492     /* Signal callback in every case (if available). */
    493     if (pCallback)
    494     {
    495         int rc2 = pCallback->SetData(&dataCb, sizeof(dataCb));
    496         if (RT_SUCCESS(vrc))
    497             vrc = rc2;
    498         rc2 = pCallback->Signal(guestRc);
    499         if (RT_SUCCESS(vrc))
    500             vrc = rc2;
    501     }
    502 
    503546    LogFlowFuncLeaveRC(vrc);
    504547    return vrc;
    505548}
    506549
    507 int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData,
    508                                    GuestCtrlCallback *pCallback)
     550int GuestFile::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    509551{
    510552    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    511553    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
    512     /* pCallback is optional. */
    513 
    514     LogFlowThisFunc(("strFile=%s, pCallback=%p\n",
    515                      mData.mOpenInfo.mFileName.c_str(), pCallback));
    516 
    517     /* First, signal callback in every case. */
    518     if (pCallback)
    519         pCallback->Signal();
    520 
    521     /** @todo More on onGuestDisconnected? */
    522     int vrc = VINF_SUCCESS;
     554
     555    LogFlowThisFunc(("strFile=%s\n",
     556                     mData.mOpenInfo.mFileName.c_str()));
     557
     558    int vrc = setFileStatus(FileStatus_Down, VINF_SUCCESS);
    523559
    524560    LogFlowFuncLeaveRC(vrc);
     
    534570    /* Prepare HGCM call. */
    535571    VBOXHGCMSVCPARM paParms[8];
    536     int i = 1; /* Context ID will be set in sendFileComannd(). */
     572    int i = 0;
    537573    paParms[i++].setPointer((void*)mData.mOpenInfo.mFileName.c_str(),
    538574                            (ULONG)mData.mOpenInfo.mFileName.length() + 1);
     
    544580    paParms[i++].setUInt64(mData.mOpenInfo.mInitialOffset);
    545581
    546     int vrc = sendFileCommand(HOST_FILE_OPEN, i, paParms, 30 * 1000 /* 30s timeout */,
    547                               pGuestRc, NULL /* ppCallback */);
     582    int vrc = sendCommand(HOST_FILE_OPEN, i, paParms);
     583    if (RT_SUCCESS(vrc))
     584        vrc = waitForStatusChange(30 * 1000 /* Timeout in ms */,
     585                                  NULL /* FileStatus */);
    548586
    549587    LogFlowFuncLeaveRC(vrc);
     
    551589}
    552590
    553 int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS, void *pvData, size_t cbData,
    554                         size_t *pcbRead, int *pGuestRc)
     591int GuestFile::readData(uint32_t uSize, uint32_t uTimeoutMS,
     592                        void* pvData, uint32_t cbData, uint32_t* pcbRead)
    555593{
    556594    LogFlowThisFunc(("uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
    557595                     uSize, uTimeoutMS, pvData, cbData));
    558596
     597    uint32_t uContextID;
     598    int vrc = generateContextID(mSession->getId(), mObjectID,
     599                                &uContextID);
     600    if (RT_SUCCESS(vrc))
     601    {
     602        /* Prepare HGCM call. */
     603        VBOXHGCMSVCPARM paParms[4];
     604        int i = 0;
     605        paParms[i++].setUInt32(mData.mID /* File handle */);
     606        paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
     607
     608        uint32_t cbRead;
     609        vrc = sendCommand(HOST_FILE_READ, i, paParms);
     610        if (RT_SUCCESS(vrc))
     611            vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead);
     612
     613        if (RT_SUCCESS(vrc))
     614        {
     615            LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
     616
     617            if (pcbRead)
     618                *pcbRead = cbRead;
     619        }
     620    }
     621
     622    LogFlowFuncLeaveRC(vrc);
     623    return vrc;
     624}
     625
     626int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
     627                          void* pvData, size_t cbData, size_t* pcbRead)
     628{
     629    LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
     630                     uOffset, uSize, uTimeoutMS, pvData, cbData));
     631
     632    uint32_t uContextID;
     633    int vrc = generateContextID(mSession->getId(), mObjectID,
     634                                &uContextID);
     635    if (RT_SUCCESS(vrc))
     636    {
     637
     638        /* Prepare HGCM call. */
     639        VBOXHGCMSVCPARM paParms[4];
     640        int i = 0;
     641        paParms[i++].setUInt32(mData.mID /* File handle */);
     642        paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
     643        paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
     644
     645        uint32_t cbRead;
     646        int vrc = sendCommand(HOST_FILE_READ_AT, i, paParms);
     647        if (RT_SUCCESS(vrc))
     648            vrc = waitForRead(uTimeoutMS, pvData, cbData, &cbRead);
     649
     650        if (RT_SUCCESS(vrc))
     651        {
     652            LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
     653
     654            if (pcbRead)
     655                *pcbRead = cbRead;
     656        }
     657    }
     658
     659    LogFlowFuncLeaveRC(vrc);
     660    return vrc;
     661}
     662
     663int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType,
     664                      uint32_t uTimeoutMS, uint64_t *puOffset)
     665{
     666    LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n",
     667                     uOffset, uTimeoutMS));
     668
    559669    /* Prepare HGCM call. */
    560670    VBOXHGCMSVCPARM paParms[4];
    561     int i = 1; /* Context ID will be set in sendFileComannd(). */
    562     paParms[i++].setUInt32(mData.mID /* File handle */);
    563     paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
    564 
    565     GuestCtrlCallback *pCallback = NULL; int guestRc;
    566     int vrc = sendFileCommand(HOST_FILE_READ, i, paParms, uTimeoutMS,
    567                               &guestRc, &pCallback);
    568 
    569     if (RT_SUCCESS(vrc))
    570     {
    571         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    572 
    573         Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY));
    574         PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw();
    575         AssertPtr(pData);
    576         Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_READ);
    577 
    578         size_t cbRead = pData->u.read.cbData;
    579         if (cbRead)
    580         {
    581             Assert(cbData >= cbRead);
    582             memcpy(pvData, pData->u.read.pvData, cbRead);
    583         }
    584 
    585         LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
    586 
    587         if (pcbRead)
    588             *pcbRead = cbRead;
    589     }
    590 
    591     callbackDelete(pCallback);
    592 
    593     if (pGuestRc)
    594         *pGuestRc = guestRc;
    595 
    596     LogFlowFuncLeaveRC(vrc);
    597     return vrc;
    598 }
    599 
    600 int GuestFile::readDataAt(uint64_t uOffset, uint32_t uSize, uint32_t uTimeoutMS,
    601                           void *pvData, size_t cbData,
    602                           size_t *pcbRead, int *pGuestRc)
    603 {
    604     LogFlowThisFunc(("uOffset=%RU64, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu\n",
    605                      uOffset, uSize, uTimeoutMS, pvData, cbData));
    606 
    607     /* Prepare HGCM call. */
    608     VBOXHGCMSVCPARM paParms[4];
    609     int i = 1; /* Context ID will be set in sendFileComannd(). */
    610     paParms[i++].setUInt32(mData.mID /* File handle */);
    611     paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
    612     paParms[i++].setUInt32(uSize /* Size (in bytes) to read */);
    613 
    614     GuestCtrlCallback *pCallback = NULL; int guestRc;
    615     int vrc = sendFileCommand(HOST_FILE_READ_AT, i, paParms, uTimeoutMS,
    616                               &guestRc, &pCallback);
    617 
    618     if (RT_SUCCESS(vrc))
    619     {
    620         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    621 
    622         Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY));
    623         PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw();
    624         AssertPtr(pData);
    625         Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_READ);
    626 
    627         size_t cbRead = pData->u.read.cbData;
    628         if (cbRead)
    629         {
    630             Assert(cbData >= cbRead);
    631             memcpy(pvData, pData->u.read.pvData, cbRead);
    632         }
    633 
    634         LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
    635 
    636         if (pcbRead)
    637             *pcbRead = cbRead;
    638     }
    639 
    640     callbackDelete(pCallback);
    641 
    642     if (pGuestRc)
    643         *pGuestRc = guestRc;
    644 
    645     LogFlowFuncLeaveRC(vrc);
    646     return vrc;
    647 }
    648 
    649 int GuestFile::seekAt(uint64_t uOffset, GUEST_FILE_SEEKTYPE eSeekType,
    650                       uint32_t uTimeoutMS, int *pGuestRc)
    651 {
    652     LogFlowThisFunc(("uOffset=%RU64, uTimeoutMS=%RU32\n",
    653                      uOffset, uTimeoutMS));
    654 
    655     /* Prepare HGCM call. */
    656     VBOXHGCMSVCPARM paParms[4];
    657     int i = 1; /* Context ID will be set in sendFileComannd(). */
     671    int i = 0;
    658672    paParms[i++].setUInt32(mData.mID /* File handle */);
    659673    paParms[i++].setUInt32(eSeekType /* Seek method */);
    660674    paParms[i++].setUInt64(uOffset /* Offset (in bytes) to start reading */);
    661675
    662     int guestRc;
    663     int vrc = sendFileCommand(HOST_FILE_SEEK, i, paParms, uTimeoutMS,
    664                               &guestRc, NULL /* ppCallback */);
    665     if (pGuestRc)
    666         *pGuestRc = guestRc;
    667 
    668     LogFlowFuncLeaveRC(vrc);
    669     return vrc;
    670 }
    671 
    672 /**
    673  * Handles the common parts of sending a file command to the guest.
    674  * If ppCallback is returned it must be removed via callbackRemove()
    675  * by the caller in any case.
    676  *
    677  * @return  IPRT status code.
    678  * @param   uFunction               HGCM function of command to send.
    679  * @param   uParms                  Number of HGCM parameters to send.
    680  *                                  At least one parameter must be present.
    681  * @param   paParms                 Array of HGCM parameters to send.
    682  *                                  Index [0] must not be used and will be
    683  *                                  filled out by the function.
    684  * @param   uTimeoutMS              Timeout (in ms).
    685  * @param   pGuestRc                Guest result. Optional.
    686  * @param   ppCallback              Pointer which will receive the callback for
    687  *                                  further processing by the caller. Must
    688  *                                  be deleted with callbackDelete() when done. Optional.
    689  */
    690 int GuestFile::sendFileCommand(uint32_t uFunction, uint32_t uParms, PVBOXHGCMSVCPARM paParms,
    691                                uint32_t uTimeoutMS, int *pGuestRc, GuestCtrlCallback **ppCallback)
    692 {
    693     AssertReturn(uParms, VERR_INVALID_PARAMETER);
    694     AssertPtrReturn(paParms, VERR_INVALID_POINTER);
    695     /** pGuestRc is optional. */
    696     /** ppCallback is optional. */
    697 
    698     LogFlowThisFunc(("strFile=%s, uFunction=%RU32, uParms=%RU32\n",
    699                      mData.mOpenInfo.mFileName.c_str(), uFunction, uParms));
    700 
    701     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    702 
    703     AssertPtr(mData.mSession);
    704     uint32_t uProtocol = mData.mSession->getProtocolVersion();
    705     if (uProtocol < 2)
    706         return VERR_NOT_SUPPORTED;
    707 
    708     int vrc = VINF_SUCCESS;
    709     uint32_t uContextID = 0;
    710 
    711     GuestCtrlCallback *pCallback;
    712     try
    713     {
    714         pCallback = new GuestCtrlCallback();
    715     }
    716     catch(std::bad_alloc &)
    717     {
    718         vrc = VERR_NO_MEMORY;
    719     }
    720 
     676    int vrc = sendCommand(HOST_FILE_SEEK, i, paParms);
    721677    if (RT_SUCCESS(vrc))
    722     {
    723         /* Create callback and add it to the map. */
    724         vrc = pCallback->Init(CALLBACKTYPE_FILE_NOTIFY);
    725         if (RT_SUCCESS(vrc))
    726             vrc = callbackAdd(pCallback, &uContextID);
    727     }
    728 
    729     if (RT_SUCCESS(vrc))
    730     {
    731         /* Assign context ID. */
    732         paParms[0].setUInt32(uContextID);
    733 
    734         GuestSession *pSession = mData.mSession;
    735         AssertPtr(pSession);
    736 
    737         alock.release(); /* Drop the write lock again. */
    738 
    739         /* Note: Don't hold the write lock in here. */
    740         vrc = sendCommand(uFunction, uParms, paParms);
    741 
    742         if (RT_SUCCESS(vrc))
    743         {
    744             /*
    745              * Let's wait for the process being started.
    746              * Note: Be sure not keeping a AutoRead/WriteLock here.
    747              */
    748             LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n",
    749                              uTimeoutMS));
    750             vrc = pCallback->Wait(uTimeoutMS);
    751             if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    752             {
    753                 int guestRc = pCallback->GetResultCode();
    754                 if (RT_SUCCESS(guestRc))
    755                 {
    756                     /* Nothing to do here yet. */
    757                 }
    758                 else
    759                     vrc = VERR_GSTCTL_GUEST_ERROR;
    760 
    761                 if (pGuestRc)
    762                     *pGuestRc = guestRc;
    763                 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
    764             }
    765         }
    766 
    767         alock.acquire(); /* Get write lock again. */
    768 
    769         AssertPtr(pCallback);
    770         int rc2 = callbackRemove(uContextID);
    771         if (RT_SUCCESS(vrc))
    772             vrc = rc2;
    773 
    774         if (ppCallback)
    775         {
    776             /* Return callback to the caller which then will be
    777              * responsible for removing it. Don't forget to lock write
    778              * access before using this callback then! */
    779             *ppCallback = pCallback;
    780         }
    781         else
    782         {
    783             delete pCallback;
    784         }
    785     }
     678        vrc = waitForOffsetChange(uTimeoutMS, puOffset);
    786679
    787680    LogFlowFuncLeaveRC(vrc);
     
    798691}
    799692
    800 int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, size_t cbData,
    801                          uint32_t *pcbWritten, int *pGuestRc)
     693/* Does not do locking; caller is responsible for that! */
     694int GuestFile::setFileStatus(FileStatus_T fileStatus, int fileRc)
     695{
     696    LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, fileRc=%Rrc\n",
     697                     mData.mStatus, fileStatus, fileRc));
     698
     699#ifdef VBOX_STRICT
     700    if (fileStatus == FileStatus_Error)
     701    {
     702        AssertMsg(RT_FAILURE(fileRc), ("Guest rc must be an error (%Rrc)\n", fileRc));
     703    }
     704    else
     705        AssertMsg(RT_SUCCESS(fileRc), ("Guest rc must not be an error (%Rrc)\n", fileRc));
     706#endif
     707
     708    if (mData.mStatus != fileStatus)
     709    {
     710        mData.mStatus = fileStatus;
     711
     712        ComObjPtr<GuestErrorInfo> errorInfo;
     713        HRESULT hr = errorInfo.createObject();
     714        ComAssertComRC(hr);
     715        if (RT_FAILURE(fileRc))
     716        {
     717            int rc2 = errorInfo->init(fileRc, guestErrorToString(fileRc));
     718            AssertRC(rc2);
     719        }
     720
     721        fireGuestFileStateChangedEvent(mEventSource, mSession,
     722                                       this, mData.mStatus, errorInfo);
     723    }
     724
     725    return VINF_SUCCESS;
     726}
     727
     728int GuestFile::waitForOffsetChange(uint32_t uTimeoutMS, uint64_t *puOffset)
     729{
     730    return VINF_SUCCESS;
     731}
     732
     733int GuestFile::waitForRead(uint32_t uTimeoutMS, void* pvData, size_t cbData, uint32_t *pcbRead)
     734{
     735    return VINF_SUCCESS;
     736}
     737
     738int GuestFile::waitForStatusChange(uint32_t uTimeoutMS, FileStatus_T *pFileStatus)
     739{
     740    int vrc;
     741
     742    /** @todo Parameter validation. */
     743
     744    ComPtr<IEventListener> pListener;
     745    HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
     746    if (SUCCEEDED(hr))
     747    {
     748        com::SafeArray <VBoxEventType_T> eventTypes(1);
     749        eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
     750        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false);
     751    }
     752    else
     753        vrc = VERR_COM_UNEXPECTED;
     754
     755    if (SUCCEEDED(hr))
     756    {
     757        LogFlowThisFunc(("Waiting for guest file status change event (timeout=%RU32ms) ...\n",
     758                         uTimeoutMS));
     759
     760        vrc = VINF_SUCCESS;
     761
     762        uint64_t u64Started = RTTimeMilliTS();
     763        bool fSignalled = false;
     764        do
     765        {
     766            unsigned cMsWait;
     767            if (uTimeoutMS == RT_INDEFINITE_WAIT)
     768                cMsWait = 1000;
     769            else
     770            {
     771                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
     772                if (cMsElapsed >= uTimeoutMS)
     773                    break; /* timed out */
     774                cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
     775            }
     776
     777            ComPtr<IEvent> pEvent;
     778            hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam());
     779            if (   SUCCEEDED(hr)
     780                && !pEvent.isNull())
     781            {
     782                VBoxEventType_T aType;
     783                hr = pEvent->COMGETTER(Type)(&aType);
     784                ComAssertComRC(hr);
     785                switch (aType)
     786                {
     787                    case VBoxEventType_OnGuestFileStateChanged:
     788                    {
     789                        ComPtr<IGuestFileStateChangedEvent> pChangedEvent = pEvent;
     790                        Assert(!pChangedEvent.isNull());
     791
     792                        ComPtr<IGuestFile> pFile;
     793                        pChangedEvent->COMGETTER(File)(pFile.asOutParam());
     794                        Assert(!pFile.isNull());
     795
     796                        if (pFile != this)
     797                            continue;
     798                    }
     799
     800                    default:
     801                        AssertMsgFailed(("Unhandled event type %ld\n", aType));
     802                        break;
     803                }
     804
     805                fSignalled = true;
     806                break;
     807            }
     808
     809        } while (!fSignalled);
     810
     811        if (   RT_SUCCESS(vrc)
     812            && !fSignalled)
     813        {
     814            vrc = VERR_TIMEOUT;
     815        }
     816
     817        mEventSource->UnregisterListener(pListener);
     818    }
     819    else
     820        vrc = VERR_COM_UNEXPECTED;
     821
     822    LogFlowFuncLeaveRC(vrc);
     823    return vrc;
     824}
     825
     826int GuestFile::waitForWrite(uint32_t uTimeoutMS, uint32_t *pcbWritten)
     827{
     828    return VINF_SUCCESS;
     829}
     830
     831int GuestFile::writeData(uint32_t uTimeoutMS, void *pvData, uint32_t cbData,
     832                         uint32_t *pcbWritten)
    802833{
    803834    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     
    807838                     uTimeoutMS, pvData, cbData));
    808839
    809     /* Prepare HGCM call. */
    810     VBOXHGCMSVCPARM paParms[4];
    811     int i = 1; /* Context ID will be set in sendFileComannd(). */
    812     paParms[i++].setUInt32(mData.mID /* File handle */);
    813     paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
    814     paParms[i++].setPointer(pvData, cbData);
    815 
    816     GuestCtrlCallback *pCallback = NULL; int guestRc;
    817     int vrc = sendFileCommand(HOST_FILE_WRITE, i, paParms, uTimeoutMS,
    818                               &guestRc, &pCallback);
    819 
     840    uint32_t uContextID;
     841    int vrc = generateContextID(mSession->getId(), mObjectID,
     842                                &uContextID);
    820843    if (RT_SUCCESS(vrc))
    821844    {
    822         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    823 
    824         Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY));
    825         PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw();
    826         AssertPtr(pData);
    827         Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_WRITE);
    828 
    829         size_t cbWritten = pData->u.write.cbWritten;
    830         LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
    831 
    832         if (pcbWritten)
    833             *pcbWritten = cbWritten;
    834     }
    835 
    836     callbackDelete(pCallback);
    837 
    838     if (pGuestRc)
    839         *pGuestRc = guestRc;
     845        /* Prepare HGCM call. */
     846        VBOXHGCMSVCPARM paParms[8];
     847        int i = 0;
     848        paParms[i++].setUInt32(uContextID);
     849        paParms[i++].setUInt32(mData.mID /* File handle */);
     850        paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
     851        paParms[i++].setPointer(pvData, cbData);
     852
     853        uint32_t cbWritten;
     854        vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
     855        if (RT_SUCCESS(vrc))
     856            vrc = waitForWrite(uTimeoutMS, &cbWritten);
     857
     858        if (RT_SUCCESS(vrc))
     859        {
     860            LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
     861
     862            if (cbWritten)
     863                *pcbWritten = cbWritten;
     864        }
     865    }
    840866
    841867    LogFlowFuncLeaveRC(vrc);
     
    844870
    845871int GuestFile::writeDataAt(uint64_t uOffset, uint32_t uTimeoutMS,
    846                            void *pvData, size_t cbData,
    847                            uint32_t *pcbWritten, int *pGuestRc)
     872                           void *pvData, uint32_t cbData, uint32_t *pcbWritten)
    848873{
    849874    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     
    853878                     uOffset, uTimeoutMS, pvData, cbData));
    854879
    855     /* Prepare HGCM call. */
    856     VBOXHGCMSVCPARM paParms[4];
    857     int i = 1; /* Context ID will be set in sendFileComannd(). */
    858     paParms[i++].setUInt32(mData.mID /* File handle */);
    859     paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
    860     paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
    861     paParms[i++].setPointer(pvData, cbData);
    862 
    863     GuestCtrlCallback *pCallback = NULL; int guestRc;
    864     int vrc = sendFileCommand(HOST_FILE_WRITE_AT, i, paParms, uTimeoutMS,
    865                               &guestRc, &pCallback);
    866 
     880    uint32_t uContextID;
     881    int vrc = generateContextID(mSession->getId(), mObjectID,
     882                                &uContextID);
    867883    if (RT_SUCCESS(vrc))
    868884    {
    869         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    870 
    871         Assert(pCallback->GetDataSize() == sizeof(CALLBACKDATA_FILE_NOTIFY));
    872         PCALLBACKDATA_FILE_NOTIFY pData = (PCALLBACKDATA_FILE_NOTIFY)pCallback->GetDataRaw();
    873         AssertPtr(pData);
    874         Assert(pData->uType == GUEST_FILE_NOTIFYTYPE_WRITE);
    875 
    876         size_t cbWritten = pData->u.write.cbWritten;
    877         LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
    878 
    879         if (pcbWritten)
    880             *pcbWritten = cbWritten;
    881     }
    882 
    883     callbackDelete(pCallback);
    884 
    885     if (pGuestRc)
    886         *pGuestRc = guestRc;
     885        /* Prepare HGCM call. */
     886        VBOXHGCMSVCPARM paParms[8];
     887        int i = 0;
     888        paParms[i++].setUInt32(mData.mID /* File handle */);
     889        paParms[i++].setUInt64(uOffset /* Offset where to starting writing */);
     890        paParms[i++].setUInt32(cbData /* Size (in bytes) to write */);
     891        paParms[i++].setPointer(pvData, cbData);
     892
     893        vrc = sendCommand(HOST_FILE_WRITE_AT, i, paParms);
     894        if (RT_SUCCESS(vrc))
     895        {
     896            uint32_t cbWritten;
     897            vrc = sendCommand(HOST_FILE_WRITE, i, paParms);
     898            if (RT_SUCCESS(vrc))
     899                vrc = waitForWrite(uTimeoutMS, &cbWritten);
     900
     901            if (RT_SUCCESS(vrc))
     902            {
     903                LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
     904
     905                if (cbWritten)
     906                    *pcbWritten = cbWritten;
     907            }
     908        }
     909    }
    887910
    888911    LogFlowFuncLeaveRC(vrc);
     
    909932     * work first and then return an error. */
    910933
    911     AssertPtr(mData.mSession);
    912     int rc2 = mData.mSession->fileRemoveFromList(this);
     934    AssertPtr(mSession);
     935    int rc2 = mSession->fileRemoveFromList(this);
    913936    if (RT_SUCCESS(rc))
    914937        rc = rc2;
     
    964987    HRESULT hr = S_OK;
    965988
    966     size_t cbRead; int guestRc;
     989    uint32_t cbRead;
    967990    int vrc = readData(aToRead, aTimeoutMS,
    968                        data.raw(), aToRead, &cbRead, &guestRc);
     991                       data.raw(), aToRead, &cbRead);
    969992    if (RT_SUCCESS(vrc))
    970993    {
     
    9771000        switch (vrc)
    9781001        {
    979             case VERR_GSTCTL_GUEST_ERROR:
    980                 hr = GuestFile::setErrorExternal(this, guestRc);
    981                 break;
    982 
    9831002            default:
    9841003                hr = setError(VBOX_E_IPRT_ERROR,
     
    10131032    HRESULT hr = S_OK;
    10141033
    1015     size_t cbRead; int guestRc;
     1034    size_t cbRead;
    10161035    int vrc = readDataAt(aOffset, aToRead, aTimeoutMS,
    1017                          data.raw(), aToRead, &cbRead, &guestRc);
     1036                         data.raw(), aToRead, &cbRead);
    10181037    if (RT_SUCCESS(vrc))
    10191038    {
     
    10261045        switch (vrc)
    10271046        {
    1028             case VERR_GSTCTL_GUEST_ERROR:
    1029                 hr = GuestFile::setErrorExternal(this, guestRc);
    1030                 break;
    1031 
    10321047            default:
    10331048                hr = setError(VBOX_E_IPRT_ERROR,
     
    10731088    }
    10741089
    1075     int guestRc;
    10761090    int vrc = seekAt(aOffset, eSeekType,
    1077                      30 * 1000 /* 30s timeout */, &guestRc);
     1091                     30 * 1000 /* 30s timeout */, NULL /* puOffset */);
    10781092    if (RT_FAILURE(vrc))
    10791093    {
    10801094        switch (vrc)
    10811095        {
    1082             case VERR_GSTCTL_GUEST_ERROR:
    1083                 hr = GuestFile::setErrorExternal(this, guestRc);
    1084                 break;
    1085 
    10861096            default:
    10871097                hr = setError(VBOX_E_IPRT_ERROR,
     
    11231133    HRESULT hr = S_OK;
    11241134
    1125     com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc;
    1126     int vrc = writeData(aTimeoutMS, data.raw(), data.size(), (uint32_t*)aWritten, &guestRc);
     1135    com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
     1136    int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
     1137                        (uint32_t*)aWritten);
    11271138    if (RT_FAILURE(vrc))
    11281139    {
    11291140        switch (vrc)
    11301141        {
    1131             case VERR_GSTCTL_GUEST_ERROR:
    1132                 hr = GuestFile::setErrorExternal(this, guestRc);
    1133                 break;
    1134 
    11351142            default:
    11361143                hr = setError(VBOX_E_IPRT_ERROR,
     
    11621169    HRESULT hr = S_OK;
    11631170
    1164     com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc;
    1165     int vrc = writeData(aTimeoutMS, data.raw(), data.size(), (uint32_t*)aWritten, &guestRc);
     1171    com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
     1172    int vrc = writeData(aTimeoutMS, data.raw(), (uint32_t)data.size(),
     1173                         (uint32_t*)aWritten);
    11661174    if (RT_FAILURE(vrc))
    11671175    {
    11681176        switch (vrc)
    11691177        {
    1170             case VERR_GSTCTL_GUEST_ERROR:
    1171                 hr = GuestFile::setErrorExternal(this, guestRc);
    1172                 break;
    1173 
    11741178            default:
    11751179                hr = setError(VBOX_E_IPRT_ERROR,
  • trunk/src/VBox/Main/src-client/GuestImpl.cpp

    r44903 r45415  
    8080
    8181    ULONG aMemoryBalloonSize;
    82     HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
    83     if (ret == S_OK)
     82    HRESULT hr = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
     83    if (hr == S_OK) /** @todo r=andy SUCCEEDED? */
    8484        mMemoryBalloonSize = aMemoryBalloonSize;
    8585    else
    86         mMemoryBalloonSize = 0;                     /* Default is no ballooning */
     86        mMemoryBalloonSize = 0; /* Default is no ballooning */
    8787
    8888    BOOL fPageFusionEnabled;
    89     ret = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);
    90     if (ret == S_OK)
     89    hr = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);
     90    if (hr == S_OK) /** @todo r=andy SUCCEEDED? */
    9191        mfPageFusionEnabled = fPageFusionEnabled;
    9292    else
    93         mfPageFusionEnabled = false;                /* Default is no page fusion*/
    94 
    95     mStatUpdateInterval = 0;                    /* Default is not to report guest statistics at all */
     93        mfPageFusionEnabled = false; /* Default is no page fusion*/
     94
     95    mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
    9696    mCollectVMMStats = false;
    9797
     
    106106    int vrc = RTTimerLRCreate(&mStatTimer, 1000 /* ms */,
    107107                              &Guest::staticUpdateStats, this);
    108     AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc));
     108    AssertMsgRC(vrc, ("Failed to create guest statistics update timer (%Rrc)\n", vrc));
     109
     110#ifdef VBOX_WITH_GUEST_CONTROL
     111    unconst(mEventSource).createObject();
     112    Assert(!mEventSource.isNull());
     113    hr = mEventSource->init(static_cast<IGuest*>(this));
     114#else
     115    hr = S_OK;
     116#endif
    109117
    110118    try
     
    117125    catch(std::bad_alloc &)
    118126    {
    119         return E_OUTOFMEMORY;
    120     }
    121 
    122     return S_OK;
     127        hr = E_OUTOFMEMORY;
     128    }
     129
     130    return hr;
    123131}
    124132
     
    167175#endif
    168176
     177#ifdef VBOX_WITH_GUEST_CONTROL
     178    unconst(mEventSource).setNull();
     179#endif
    169180    unconst(mParent) = NULL;
    170181
  • trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp

    r45109 r45415  
    2929*   Header Files                                                               *
    3030*******************************************************************************/
     31#include "GuestErrorInfoImpl.h"
    3132#include "GuestProcessImpl.h"
    3233#include "GuestSessionImpl.h"
    3334#include "GuestCtrlImplPrivate.h"
    3435#include "ConsoleImpl.h"
     36#include "VBoxEvents.h"
    3537
    3638#include "Global.h"
     
    4042
    4143#include <iprt/asm.h>
     44#include <iprt/cpp/utils.h> /* For unconst(). */
    4245#include <iprt/getopt.h>
     46
    4347#include <VBox/com/array.h>
    4448
     
    9296    mData.mStatus = ProcessStatus_Undefined;
    9397
    94     mData.mWaitCount = 0;
    95     mData.mWaitEvent = NULL;
    96 
    97     HRESULT hr = BaseFinalConstruct();
    98     return hr;
     98    return BaseFinalConstruct();
    9999}
    100100
     
    124124
    125125    int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */);
     126    if (RT_SUCCESS(vrc))
     127    {
     128        unconst(mEventSource).createObject();
     129        Assert(!mEventSource.isNull());
     130        HRESULT hr = mEventSource->init(static_cast<IGuestProcess*>(this));
     131        if (FAILED(hr))
     132            vrc = VERR_COM_UNEXPECTED;
     133    }
     134
    126135    if (RT_SUCCESS(vrc))
    127136    {
     
    156165
    157166#ifdef VBOX_WITH_GUEST_CONTROL
    158     /*
    159      * Cancel + remove all callbacks + waiters.
    160      * Note: Deleting them is the job of the caller!
    161      */
    162     callbackRemoveAll();
    163 
    164     if (mData.mWaitEvent)
    165     {
    166         int rc2 = mData.mWaitEvent->Cancel();
    167         if (RT_SUCCESS(vrc))
    168             vrc = rc2;
    169     }
    170 
    171     mData.mStatus = ProcessStatus_Down; /** @todo Correct? */
     167    unconst(mEventSource).setNull();
    172168#endif
    173169
     
    346342    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    347343
    348     /* Get the optional callback associated to this context ID.
    349      * The callback may not be around anymore if just kept locally by the caller when
    350      * doing the actual HGCM sending stuff. */
    351     GuestCtrlCallback *pCallback = NULL;
    352     GuestCtrlCallbacks::const_iterator it
    353         = mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID));
    354     if (it != mObject.mCallbacks.end())
    355     {
    356         pCallback = it->second;
    357         AssertPtr(pCallback);
    358 #ifdef DEBUG
    359         LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",
    360                          pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));
    361 #endif
    362     }
    363 
    364344    int vrc;
    365345    switch (pCbCtx->uFunction)
     
    367347        case GUEST_DISCONNECTED:
    368348        {
    369             vrc = onGuestDisconnected(pCbCtx, pCallback, pSvcCb); /* Affects all callbacks. */
     349            vrc = onGuestDisconnected(pCbCtx, pSvcCb);
    370350            break;
    371351        }
     
    373353        case GUEST_EXEC_STATUS:
    374354        {
    375             vrc = onProcessStatusChange(pCbCtx, pCallback, pSvcCb);
     355            vrc = onProcessStatusChange(pCbCtx, pSvcCb);
    376356            break;
    377357        }
     
    379359        case GUEST_EXEC_OUTPUT:
    380360        {
    381             vrc = onProcessOutput(pCbCtx, pCallback, pSvcCb);
     361            vrc = onProcessOutput(pCbCtx, pSvcCb);
    382362            break;
    383363        }
     
    385365        case GUEST_EXEC_INPUT_STATUS:
    386366        {
    387             vrc = onProcessInputStatus(pCbCtx, pCallback, pSvcCb);
     367            vrc = onProcessInputStatus(pCbCtx, pSvcCb);
    388368            break;
    389369        }
     
    422402
    423403         */
    424         if (mObject.mSession->getProtocolVersion() < 2)
     404        if (mSession->getProtocolVersion() < 2)
    425405        {
    426406            /* Simply ignore the stale requests. */
     
    487467
    488468        case VERR_MAX_PROCS_REACHED:
    489             strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
     469            strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
    490470            break;
    491471
     
    526506}
    527507
    528 int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    529                                       GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    530 {
    531     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
    532 
    533     LogFlowThisFunc(("uPID=%RU32, pCallback=%p\n", mData.mPID, pCallback));
    534 
    535     mData.mStatus = ProcessStatus_Down;
    536 
    537     /* First, signal callback in every case. */
    538     if (pCallback)
    539         pCallback->Signal();
    540 
    541     /* Do we need to report a termination? */
    542     ProcessWaitResult_T waitRes;
    543     if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
    544         waitRes = ProcessWaitResult_Status; /* No, just report a status. */
    545     else
    546         waitRes = ProcessWaitResult_Terminate;
    547 
    548     /* Signal in any case. */
    549     int vrc = signalWaiters(waitRes);
    550     AssertRC(vrc);
     508int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     509{
     510    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
     511    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
     512
     513    LogFlowThisFunc(("uPID=%RU32\n", mData.mPID));
     514
     515    int vrc = setProcessStatus(ProcessStatus_Down, VINF_SUCCESS);
    551516
    552517    LogFlowFuncLeaveRC(vrc);
     
    554519}
    555520
    556 int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    557                                        GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    558 {
    559     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     521int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     522{
     523    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    560524    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
     525    /* pCallback is optional. */
    561526
    562527    if (pSvcCbData->mParms < 5)
     
    574539    AssertRCReturn(vrc, vrc);
    575540
    576     LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32, pCallback=%p\n",
    577                      dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed, pCallback));
     541    LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32\n",
     542                     dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed));
    578543
    579544    vrc = checkPID(dataCb.uPID);
    580545    AssertRCReturn(vrc, vrc);
    581546
    582     /* First, signal callback in every case (if available). */
    583     if (pCallback)
    584     {
    585         vrc = pCallback->SetData(&dataCb, sizeof(dataCb));
    586 
    587         int rc2 = pCallback->Signal();
    588         if (RT_SUCCESS(vrc))
    589             vrc = rc2;
    590     }
    591 
    592     /* Then do the WaitFor signalling stuff. */
    593     uint32_t uWaitFlags = mData.mWaitEvent
    594                         ? mData.mWaitEvent->GetWaitFlags() : 0;
    595     if (uWaitFlags & ProcessWaitForFlag_StdIn)
    596     {
    597         int rc2 = signalWaiters(ProcessWaitResult_StdIn);
    598         if (RT_SUCCESS(vrc))
    599             vrc = rc2;
     547    ProcessInputStatus_T inputStatus = ProcessInputStatus_Undefined;
     548    switch (dataCb.uStatus)
     549    {
     550        case INPUT_STS_WRITTEN:
     551            inputStatus = ProcessInputStatus_Written;
     552            break;
     553        case INPUT_STS_ERROR:
     554            inputStatus = ProcessInputStatus_Broken;
     555            break;
     556        case INPUT_STS_TERMINATED:
     557            inputStatus = ProcessInputStatus_Broken;
     558            break;
     559        case INPUT_STS_OVERFLOW:
     560            inputStatus = ProcessInputStatus_Overflow;
     561            break;
     562        case INPUT_STS_UNDEFINED:
     563            /* Fall through is intentional. */
     564        default:
     565            AssertMsg(!dataCb.uProcessed, ("Processed data is not 0 in undefined input state\n"));
     566            break;
     567    }
     568
     569    if (inputStatus != ProcessInputStatus_Undefined)
     570    {
     571        fireGuestProcessInputNotifyEvent(mEventSource, mSession, this,
     572                                         mData.mPID, inputStatus, 0 /* StdIn */, dataCb.uProcessed);
    600573    }
    601574
     
    604577}
    605578
    606 int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    607                                     GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    608 {
    609     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     579int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     580{
     581    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
     582    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
    610583
    611584    return VERR_NOT_IMPLEMENTED;
    612585}
    613586
    614 int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    615                                         GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     587int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    616588{
    617589    /* pCallback is optional. */
     
    632604    AssertRCReturn(vrc, vrc);
    633605
    634     LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, pCallback=%p, pSvcCbData=%p\n",
    635                      dataCb.uPID, dataCb.uStatus, dataCb.uFlags, pCallback, pSvcCbData));
     606    LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32\n",
     607                     dataCb.uPID, dataCb.uStatus, dataCb.uFlags));
    636608
    637609    vrc = checkPID(dataCb.uPID);
     
    641613    int procRc = VINF_SUCCESS;
    642614
    643     bool fSignalWaiters = false;
    644     ProcessWaitResult_T waitRes;
    645 
    646     uint32_t uWaitFlags = mData.mWaitEvent
    647                         ? mData.mWaitEvent->GetWaitFlags() : 0;
    648615    switch (dataCb.uStatus)
    649616    {
    650617        case PROC_STS_STARTED:
    651618        {
    652             fSignalWaiters = (uWaitFlags & ProcessWaitForFlag_Start);
    653             /* If the caller only wants to wait until the process has been started,
    654              * notify in any case. */
    655             if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
    656                 fSignalWaiters = true;
    657             waitRes = ProcessWaitResult_Start;
    658 
    659619            procStatus = ProcessStatus_Started;
    660620            mData.mPID = dataCb.uPID; /* Set the process PID. */
     
    664624        case PROC_STS_TEN:
    665625        {
    666             fSignalWaiters = true; /* Signal in any case. */
    667             waitRes = ProcessWaitResult_Terminate;
    668 
    669626            procStatus = ProcessStatus_TerminatedNormally;
    670627            mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */
     
    674631        case PROC_STS_TES:
    675632        {
    676             fSignalWaiters = true; /* Signal in any case. */
    677             waitRes = ProcessWaitResult_Terminate;
    678 
    679633            procStatus = ProcessStatus_TerminatedSignal;
    680634            mData.mExitCode = dataCb.uFlags; /* Contains the signal. */
     
    684638        case PROC_STS_TEA:
    685639        {
    686             fSignalWaiters = true; /* Signal in any case. */
    687             waitRes = ProcessWaitResult_Terminate;
    688 
    689640            procStatus = ProcessStatus_TerminatedAbnormally;
    690641            break;
     
    693644        case PROC_STS_TOK:
    694645        {
    695             fSignalWaiters = true; /* Signal in any case. */
    696             waitRes = ProcessWaitResult_Timeout;
    697 
    698646            procStatus = ProcessStatus_TimedOutKilled;
    699647            break;
     
    702650        case PROC_STS_TOA:
    703651        {
    704             fSignalWaiters = true; /* Signal in any case. */
    705             waitRes = ProcessWaitResult_Timeout;
    706 
    707652            procStatus = ProcessStatus_TimedOutAbnormally;
    708653            break;
     
    711656        case PROC_STS_DWN:
    712657        {
    713             fSignalWaiters = true; /* Signal in any case. */
    714             /* Do we need to report termination? */
    715             if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
    716                 waitRes = ProcessWaitResult_Status;
    717             else
    718                 waitRes = ProcessWaitResult_Terminate;
    719 
    720658            procStatus = ProcessStatus_Down;
    721659            break;
     
    724662        case PROC_STS_ERROR:
    725663        {
    726             fSignalWaiters = true; /* Signal in any case. */
    727             waitRes = ProcessWaitResult_Error;
    728 
    729664            procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */
    730665            procStatus = ProcessStatus_Error;
     
    736671        {
    737672            /* Silently skip this request. */
    738             fSignalWaiters = true; /* Signal in any case. */
    739             waitRes = ProcessWaitResult_Status;
    740 
    741673            procStatus = ProcessStatus_Undefined;
    742674            break;
     
    744676    }
    745677
    746     LogFlowThisFunc(("Got rc=%Rrc, waitRes=%d, procSts=%ld, procRc=%Rrc, fSignalWaiters=%RTbool\n",
    747                      vrc, waitRes, procStatus, procRc, fSignalWaiters));
     678    LogFlowThisFunc(("Got rc=%Rrc, procSts=%ld, procRc=%Rrc\n",
     679                     vrc, procStatus, procRc));
    748680
    749681    /* Set the process status. */
     
    752684        vrc = rc2;
    753685
    754     /*
    755      * Now do the signalling stuff.
    756      */
    757     if (pCallback)
    758     {
    759         rc2 = pCallback->Signal(procRc);
    760         if (RT_SUCCESS(vrc))
    761             vrc = rc2;
    762     }
    763 
    764     if (fSignalWaiters)
    765     {
    766         rc2 = signalWaiters(waitRes, procRc);
    767         if (RT_SUCCESS(vrc))
    768             vrc = rc2;
    769     }
    770 
    771686    LogFlowFuncLeaveRC(vrc);
    772687    return vrc;
    773688}
    774689
    775 int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    776                                   GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    777 {
    778     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
     690int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     691{
    779692    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
    780693
     
    793706    AssertRCReturn(vrc, vrc);
    794707
    795     LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32, pCallback=%p\n",
    796                      dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData, pCallback));
     708    LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32\n",
     709                     dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData));
    797710
    798711    vrc = checkPID(dataCb.uPID);
    799712    AssertRCReturn(vrc, vrc);
    800713
    801     /* First, signal callback in every case (if available). */
    802     if (pCallback)
    803     {
    804         vrc = pCallback->SetData(&dataCb, sizeof(dataCb));
    805 
    806         int rc2 = pCallback->Signal();
    807         if (RT_SUCCESS(vrc))
    808             vrc = rc2;
    809     }
    810 
    811     /* Then do the WaitFor signalling stuff. */
    812     BOOL fSignal = FALSE;
    813     uint32_t uWaitFlags = mData.mWaitEvent
    814                         ? mData.mWaitEvent->GetWaitFlags() : 0;
    815 
    816     if (    (uWaitFlags & ProcessWaitForFlag_StdOut)
    817          || (uWaitFlags & ProcessWaitForFlag_StdErr))
    818     {
    819         fSignal = TRUE;
    820     }
    821     else if (   (uWaitFlags & ProcessWaitForFlag_StdOut)
    822              && (dataCb.uHandle == OUTPUT_HANDLE_ID_STDOUT))
    823     {
    824         fSignal = TRUE;
    825     }
    826     else if (   (uWaitFlags & ProcessWaitForFlag_StdErr)
    827              && (dataCb.uHandle == OUTPUT_HANDLE_ID_STDERR))
    828     {
    829         fSignal = TRUE;
    830     }
    831 
    832     if (fSignal)
    833     {
    834         int rc2 = VINF_SUCCESS;
    835         if (dataCb.uHandle == OUTPUT_HANDLE_ID_STDOUT)
    836             rc2 = signalWaiters(ProcessWaitResult_StdOut);
    837         else if (dataCb.uHandle == OUTPUT_HANDLE_ID_STDERR)
    838             rc2 = signalWaiters(ProcessWaitResult_StdErr);
    839         if (RT_SUCCESS(vrc))
    840             vrc = rc2;
    841     }
     714    com::SafeArray<BYTE> data((size_t)dataCb.cbData);
     715    data.initFrom((BYTE*)dataCb.pvData, dataCb.cbData);
     716
     717    fireGuestProcessOutputEvent(mEventSource, mSession, this,
     718                                mData.mPID, dataCb.uHandle, ComSafeArrayAsInParam(data));
    842719
    843720    LogFlowFuncLeaveRC(vrc);
     
    855732    /* pcbRead is optional. */
    856733
     734    /** @todo Validate uHandle. */
     735
    857736    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    858737
     
    866745    }
    867746
    868     int vrc = VINF_SUCCESS;
    869 
    870     GuestCtrlCallback *pCallbackRead = NULL;
    871     try
    872     {
    873         pCallbackRead = new GuestCtrlCallback();
    874     }
    875     catch(std::bad_alloc &)
    876     {
    877         vrc = VERR_NO_MEMORY;
    878     }
    879 
    880     /* Create callback and add it to the map. */
    881     uint32_t uContextID = 0;
     747    uint32_t uContextID;
     748    int vrc = generateContextID(mSession->getId(), mObjectID,
     749                                &uContextID);
    882750    if (RT_SUCCESS(vrc))
    883751    {
    884         vrc = pCallbackRead->Init(CALLBACKTYPE_PROC_OUTPUT);
    885         if (RT_SUCCESS(vrc))
    886             vrc = callbackAdd(pCallbackRead, &uContextID);
    887     }
    888 
    889     alock.release(); /* Drop the write lock again. */
    890 
    891     if (RT_SUCCESS(vrc))
    892     {
    893         VBOXHGCMSVCPARM paParms[5];
    894 
     752        VBOXHGCMSVCPARM paParms[8];
    895753        int i = 0;
    896754        paParms[i++].setUInt32(uContextID);
     
    900758
    901759        vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms);
    902         if (RT_FAILURE(vrc))
    903         {
    904             int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
    905             AssertRC(rc2);
    906         }
    907760    }
    908761
    909762    if (RT_SUCCESS(vrc))
    910763    {
    911         /*
    912          * Let's wait for the process being started.
    913          * Note: Be sure not keeping a AutoRead/WriteLock here.
    914          */
    915         LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
    916         vrc = pCallbackRead->Wait(uTimeoutMS);
    917         if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    918         {
    919             int guestRc = pCallbackRead->GetResultCode();
    920             LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackRead->GetDataSize()));
    921 
    922             if (RT_SUCCESS(guestRc))
    923             {
    924                 Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATA_PROC_OUTPUT));
    925                 PCALLBACKDATA_PROC_OUTPUT pData = (PCALLBACKDATA_PROC_OUTPUT)pCallbackRead->GetDataRaw();
    926                 AssertPtr(pData);
    927 
    928                 size_t cbRead = pData->cbData;
    929                 if (cbRead)
    930                 {
    931                     Assert(cbData >= cbRead);
    932                     memcpy(pvData, pData->pvData, cbRead);
    933                 }
    934 
    935                 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
    936 
    937                 if (pcbRead)
    938                     *pcbRead = cbRead;
    939             }
    940             else
    941                 vrc = VERR_GSTCTL_GUEST_ERROR;
    942 
    943             if (pGuestRc)
    944                 *pGuestRc = guestRc;
    945             LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
    946         }
    947     }
    948 
    949     alock.acquire();
    950 
    951     int rc2 = callbackRemove(uContextID);
    952     if (RT_SUCCESS(vrc))
    953         vrc = rc2;
    954 
    955     callbackDelete(pCallbackRead);
     764        alock.release(); /* Drop the write lock before waiting. */
     765
     766        vrc = waitForOutput(uHandle, uTimeoutMS,
     767                            pvData, cbData, pcbRead);
     768    }
    956769
    957770    LogFlowFuncLeaveRC(vrc);
     
    970783        /* Do not allow overwriting an already set error. If this happens
    971784         * this means we forgot some error checking/locking somewhere. */
    972         AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
     785        //AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
    973786    }
    974787    else
    975788        AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
    976789
    977     mData.mStatus = procStatus;
    978     mData.mRC     = procRc;
     790    if (mData.mStatus != procStatus)
     791    {
     792        mData.mStatus = procStatus;
     793        mData.mRC     = procRc;
     794
     795        ComObjPtr<GuestErrorInfo> errorInfo;
     796        HRESULT hr = errorInfo.createObject();
     797        ComAssertComRC(hr);
     798        if (RT_FAILURE(mData.mRC))
     799        {
     800            int rc2 = errorInfo->init(mData.mRC, guestErrorToString(mData.mRC));
     801            AssertRC(rc2);
     802        }
     803
     804        fireGuestProcessStateChangedEvent(mEventSource, mSession, this,
     805                                          mData.mPID, mData.mStatus, errorInfo);
     806    }
    979807
    980808    return VINF_SUCCESS;
     
    988816
    989817    return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str());
    990 }
    991 
    992 int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
    993 {
    994     LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
    995                      enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));
    996 
    997     /* Note: No write locking here -- already done in the caller. */
    998 
    999     int vrc = VINF_SUCCESS;
    1000     if (mData.mWaitEvent)
    1001         vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);
    1002     LogFlowFuncLeaveRC(vrc);
    1003     return vrc;
    1004818}
    1005819
     
    1013827    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1014828
    1015     int vrc = VINF_SUCCESS;
    1016     uint32_t uContextID = 0;
    1017 
    1018     GuestCtrlCallback *pCallbackStart = NULL;
    1019     try
    1020     {
    1021         pCallbackStart = new GuestCtrlCallback();
    1022     }
    1023     catch(std::bad_alloc &)
    1024     {
    1025         vrc = VERR_NO_MEMORY;
    1026     }
    1027 
     829    mData.mStatus = ProcessStatus_Starting;
     830
     831    uint32_t uContextID;
     832    int vrc = generateContextID(mSession->getId(), mObjectID,
     833                                &uContextID);
    1028834    if (RT_SUCCESS(vrc))
    1029835    {
    1030         mData.mStatus = ProcessStatus_Starting;
    1031 
    1032         /* Create callback and add it to the map. */
    1033         vrc = pCallbackStart->Init(CALLBACKTYPE_PROC_STATUS);
    1034         if (RT_SUCCESS(vrc))
    1035             vrc = callbackAdd(pCallbackStart, &uContextID);
    1036     }
    1037 
    1038     if (RT_SUCCESS(vrc))
    1039     {
    1040         GuestSession *pSession = mObject.mSession;
     836        GuestSession *pSession = mSession;
    1041837        AssertPtr(pSession);
    1042838
     
    1088884        if (RT_SUCCESS(vrc))
    1089885        {
    1090             AssertPtr(mObject.mSession);
    1091             uint32_t uProtocol = mObject.mSession->getProtocolVersion();
     886            AssertPtr(mSession);
     887            uint32_t uProtocol = mSession->getProtocolVersion();
    1092888
    1093889            /* Prepare HGCM call. */
     
    1151947        if (RT_SUCCESS(vrc))
    1152948        {
    1153             /*
    1154              * Let's wait for the process being started.
    1155              * Note: Be sure not keeping a AutoRead/WriteLock here.
    1156              */
    1157             LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
    1158             vrc = pCallbackStart->Wait(uTimeoutMS);
    1159             if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    1160             {
    1161                 int guestRc = pCallbackStart->GetResultCode();
    1162                 if (RT_SUCCESS(guestRc))
    1163                 {
    1164                     /* Nothing to do here right now. */
    1165                 }
    1166                 else
    1167                     vrc = VERR_GSTCTL_GUEST_ERROR;
    1168 
    1169                 if (pGuestRc)
    1170                     *pGuestRc = guestRc;
    1171                 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
    1172             }
    1173         }
    1174 
    1175         AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
    1176 
    1177         int rc2 = callbackRemove(uContextID);
    1178         if (RT_SUCCESS(vrc))
    1179             vrc = rc2;
    1180     }
    1181 
    1182     callbackDelete(pCallbackStart);
     949            vrc = waitForStatusChange(ProcessWaitForFlag_Start, 30 * 1000 /* Timeout */,
     950                                      NULL /* Process status */, pGuestRc);
     951        }
     952    }
    1183953
    1184954    LogFlowFuncLeaveRC(vrc);
     
    12451015    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    12461016
    1247     if (mObject.mSession->getProtocolVersion() < 2)
     1017    AssertPtr(mSession);
     1018    if (mSession->getProtocolVersion() < 99)
    12481019        return VERR_NOT_SUPPORTED;
    12491020
     
    12511022        return VINF_SUCCESS; /* Nothing to do (anymore). */
    12521023
    1253     int vrc = VINF_SUCCESS;
    1254 
    1255     GuestCtrlCallback *pCallbackTerminate = NULL;
    1256     try
    1257     {
    1258         pCallbackTerminate = new GuestCtrlCallback();
    1259     }
    1260     catch(std::bad_alloc &)
    1261     {
    1262         vrc = VERR_NO_MEMORY;
    1263     }
    1264 
    1265     /* Create callback and add it to the map. */
    12661024    uint32_t uContextID;
     1025    int vrc = generateContextID(mSession->getId(), mObjectID,
     1026                                &uContextID);
    12671027    if (RT_SUCCESS(vrc))
    1268         vrc = callbackAdd(pCallbackTerminate, &uContextID);
    1269 
    1270     alock.release(); /* Drop the write lock again. */
    1271 
    1272     if (RT_SUCCESS(vrc))
    1273     {
    1274         VBOXHGCMSVCPARM paParms[5];
    1275 
     1028    {
     1029        VBOXHGCMSVCPARM paParms[4];
    12761030        int i = 0;
    12771031        paParms[i++].setUInt32(uContextID);
    12781032        paParms[i++].setUInt32(mData.mPID);
    12791033
    1280         //vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
     1034        vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
    12811035    }
    12821036
    12831037    if (RT_SUCCESS(vrc))
    12841038    {
    1285         /*
    1286          * Let's wait for the process being terminated.
    1287          * Note: Be sure not keeping a AutoRead/WriteLock here.
    1288          */
    1289         LogFlowThisFunc(("Waiting for callback (30s) ...\n"));
    1290         vrc = pCallbackTerminate->Wait(30 * 1000);
    1291         if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    1292         {
    1293             int guestRc = pCallbackTerminate->GetResultCode();
    1294             if (RT_SUCCESS(guestRc))
    1295             {
    1296                 /* Nothing to do here right now. */
    1297             }
    1298             else
    1299                 vrc = VERR_GSTCTL_GUEST_ERROR;
    1300 
    1301             if (pGuestRc)
    1302                 *pGuestRc = guestRc;
    1303             LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
    1304         }
    1305     }
    1306 
    1307     alock.acquire();
    1308 
    1309     int rc2 = callbackRemove(uContextID);
    1310     if (RT_SUCCESS(vrc))
    1311         vrc = rc2;
    1312 
    1313     callbackDelete(pCallbackTerminate);
     1039        alock.release(); /* Drop the write lock before waiting. */
     1040
     1041        vrc = waitForStatusChange(ProcessWaitForFlag_Terminate,
     1042                                  30 * 1000 /* 30s timeout */,
     1043                                  NULL /* ProcessStatus */, pGuestRc);
     1044    }
    13141045
    13151046    LogFlowFuncLeaveRC(vrc);
     
    13231054    AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
    13241055
    1325     LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
    1326                      fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));
     1056    /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
     1057                     fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/
    13271058
    13281059    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    14191150
    14201151    /* Filter out waits which are *not* supported using
    1421      * older guest control Guest Additions. */
    1422     if (mObject.mSession->getProtocolVersion() < 2)
     1152     * older guest control Guest Additions.
     1153     *
     1154     ** @todo ProcessWaitForFlag_Std* flags are not implemented yet.
     1155     */
     1156    if (mSession->getProtocolVersion() < 99)
    14231157    {
    14241158        if (   waitResult == ProcessWaitResult_None
     
    14471181    }
    14481182
    1449     if (mData.mWaitCount > 0) /* We only support one waiting caller a time at the moment. */
    1450         return VERR_ALREADY_EXISTS;
    1451     mData.mWaitCount++;
    1452 
    1453     int vrc = VINF_SUCCESS;
    1454     try
    1455     {
    1456         Assert(mData.mWaitEvent == NULL);
    1457         mData.mWaitEvent = new GuestProcessWaitEvent(fWaitFlags);
    1458     }
    1459     catch(std::bad_alloc &)
    1460     {
    1461         vrc = VERR_NO_MEMORY;
    1462     }
    1463 
     1183    alock.release(); /* Release lock before waiting. */
     1184
     1185    ProcessStatus_T processStatus;
     1186    int vrc = waitForStatusChange(fWaitFlags, uTimeoutMS, &processStatus, pGuestRc);
    14641187    if (RT_SUCCESS(vrc))
    14651188    {
    1466         GuestProcessWaitEvent *pEvent = mData.mWaitEvent;
    1467         AssertPtr(pEvent);
    1468 
    1469         alock.release(); /* Release lock before waiting. */
    1470 
    1471         vrc = pEvent->Wait(uTimeoutMS);
    1472         LogFlowThisFunc(("Waiting completed with rc=%Rrc\n", vrc));
    1473         if (RT_SUCCESS(vrc))
    1474         {
    1475             waitResult = pEvent->GetWaitResult();
    1476             int guestRc = pEvent->GetWaitRc();
    1477             if (RT_FAILURE(guestRc))
    1478                 vrc = VERR_GSTCTL_GUEST_ERROR;
    1479 
    1480             LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", guestRc));
    1481 
    1482             if (pGuestRc)
    1483                 *pGuestRc = guestRc;
    1484         }
    1485 
    1486         alock.acquire(); /* Get the lock again. */
    1487 
    1488         /* Note: The caller always is responsible of deleting the
    1489          *       stuff it created before. See close() for more information. */
    1490         delete mData.mWaitEvent;
    1491         mData.mWaitEvent = NULL;
    1492     }
    1493 
    1494     Assert(mData.mWaitCount);
    1495     mData.mWaitCount--;
     1189        switch (processStatus)
     1190        {
     1191            case ProcessStatus_Started:
     1192                waitResult = ProcessWaitResult_Start;
     1193                break;
     1194
     1195            case ProcessStatus_TerminatedNormally:
     1196            case ProcessStatus_TerminatedAbnormally:
     1197            case ProcessStatus_TerminatedSignal:
     1198                waitResult = ProcessWaitResult_Terminate;
     1199                break;
     1200
     1201            case ProcessStatus_TimedOutKilled:
     1202            case ProcessStatus_TimedOutAbnormally:
     1203                waitResult = ProcessWaitResult_Timeout;
     1204                break;
     1205
     1206            case ProcessStatus_Down:
     1207                waitResult = ProcessWaitResult_Terminate;
     1208                break;
     1209
     1210            case ProcessStatus_Error:
     1211                waitResult = ProcessWaitResult_Error;
     1212                break;
     1213
     1214            default:
     1215                waitResult = ProcessWaitResult_Status;
     1216                break;
     1217        }
     1218    }
     1219
     1220    LogFlowFuncLeaveRC(vrc);
     1221    return vrc;
     1222}
     1223
     1224int GuestProcess::waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS,
     1225                                     ProcessInputStatus_T *pInputStatus, size_t *pcbProcessed)
     1226{
     1227    int vrc;
     1228
     1229    /** @todo Parameter validation. */
     1230
     1231    ComPtr<IEventListener> pListener;
     1232    HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
     1233    if (SUCCEEDED(hr))
     1234    {
     1235        com::SafeArray <VBoxEventType_T> eventTypes(1);
     1236        eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
     1237        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false);
     1238    }
     1239    else
     1240        vrc = VERR_COM_UNEXPECTED;
     1241
     1242    if (SUCCEEDED(hr))
     1243    {
     1244        LogFlowThisFunc(("Waiting for guest process input notify event (timeout=%RU32ms, handle=%RU32) ...\n",
     1245                         uTimeoutMS, uHandle));
     1246
     1247        vrc = VINF_SUCCESS;
     1248
     1249        uint64_t u64Started = RTTimeMilliTS();
     1250        bool fSignalled = false;
     1251        do
     1252        {
     1253            unsigned cMsWait;
     1254            if (uTimeoutMS == RT_INDEFINITE_WAIT)
     1255                cMsWait = 1000;
     1256            else
     1257            {
     1258                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
     1259                if (cMsElapsed >= uTimeoutMS)
     1260                    break; /* timed out */
     1261                cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
     1262            }
     1263
     1264            ComPtr<IEvent> pEvent;
     1265            hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam());
     1266            if (   SUCCEEDED(hr)
     1267                && !pEvent.isNull())
     1268            {
     1269                VBoxEventType_T aType;
     1270                hr = pEvent->COMGETTER(Type)(&aType);
     1271                ComAssertComRC(hr);
     1272                switch (aType)
     1273                {
     1274                    case VBoxEventType_OnGuestProcessInputNotify:
     1275                    {
     1276                        ComPtr<IGuestProcessInputNotifyEvent> pOutputEvent = pEvent;
     1277                        Assert(!pOutputEvent.isNull());
     1278
     1279                        ComPtr<IGuestSession> pSession;
     1280                        pOutputEvent->COMGETTER(Session)(pSession.asOutParam());
     1281                        Assert(!pSession.isNull());
     1282                        ULONG uSessionID;
     1283                        hr = pSession->COMGETTER(Id)(&uSessionID);
     1284                        ComAssertComRC(hr);
     1285                        if (uSessionID != mSession->getId())
     1286                            continue; /* Only the session this process runs in is of interest. */
     1287
     1288                        ULONG uPID;
     1289                        hr = pOutputEvent->COMGETTER(Pid)(&uPID);
     1290                        ComAssertComRC(hr);
     1291                        if (uPID != mData.mPID)
     1292                            continue; /* Only the this process is of interest. */
     1293
     1294                        ULONG uHandleEvent;
     1295                        hr = pOutputEvent->COMGETTER(Handle)(&uHandleEvent);
     1296                        ComAssertComRC(hr);
     1297
     1298                        LogFlowThisFunc(("Got output event for process PID=%RU32, handle=%RU32 (session ID=%RU32)\n",
     1299                                         mData.mPID, uHandleEvent, mSession->getId()));
     1300
     1301                        bool fSignal = uHandleEvent == uHandle;
     1302                        if (!fSignal)
     1303                            continue;
     1304
     1305                        ProcessInputStatus_T inputStatus;
     1306                        hr = pOutputEvent->COMGETTER(Status)(&inputStatus);
     1307                        ComAssertComRC(hr);
     1308
     1309                        ULONG uProcessed;
     1310                        hr = pOutputEvent->COMGETTER(Processed)(&uProcessed);
     1311                        ComAssertComRC(hr);
     1312
     1313                        if (pInputStatus)
     1314                            *pInputStatus = inputStatus;
     1315                        if (pcbProcessed)
     1316                            *pcbProcessed = uProcessed;
     1317
     1318                        LogFlowThisFunc(("Input notify event for process PID=%RU32 (session ID=%RU32): %zubytes read\n",
     1319                                         uPID, mSession->getId(), uProcessed));
     1320
     1321                        fSignalled = true;
     1322                        break;
     1323                    }
     1324
     1325                    default:
     1326                         AssertMsgFailed(("Unhandled event type %ld\n", aType));
     1327                         break;
     1328                }
     1329            }
     1330
     1331        } while (!fSignalled);
     1332
     1333        if (   RT_SUCCESS(vrc)
     1334            && !fSignalled)
     1335        {
     1336            vrc = VERR_TIMEOUT;
     1337        }
     1338
     1339        mEventSource->UnregisterListener(pListener);
     1340    }
     1341    else
     1342        vrc = VERR_COM_UNEXPECTED;
     1343
     1344    LogFlowFuncLeaveRC(vrc);
     1345    return vrc;
     1346}
     1347
     1348int GuestProcess::waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS,
     1349                                void *pvData, size_t cbData, size_t *pcbRead)
     1350{
     1351    int vrc;
     1352
     1353    /** @todo Parameter validation. */
     1354
     1355    ComPtr<IEventListener> pListener;
     1356    HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
     1357    if (SUCCEEDED(hr))
     1358    {
     1359        com::SafeArray <VBoxEventType_T> eventTypes(1);
     1360        eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
     1361        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false);
     1362    }
     1363    else
     1364        vrc = VERR_COM_UNEXPECTED;
     1365
     1366    if (SUCCEEDED(hr))
     1367    {
     1368        LogFlowThisFunc(("Waiting for guest process output event (timeout=%RU32ms, handle=%RU32) ...\n",
     1369                         uTimeoutMS, uHandle));
     1370
     1371        vrc = VINF_SUCCESS;
     1372
     1373        uint64_t u64Started = RTTimeMilliTS();
     1374        bool fSignalled = false;
     1375        do
     1376        {
     1377            unsigned cMsWait;
     1378            if (uTimeoutMS == RT_INDEFINITE_WAIT)
     1379                cMsWait = 1000;
     1380            else
     1381            {
     1382                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
     1383                if (cMsElapsed >= uTimeoutMS)
     1384                    break; /* timed out */
     1385                cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
     1386            }
     1387
     1388            ComPtr<IEvent> pEvent;
     1389            hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam());
     1390            if (   SUCCEEDED(hr)
     1391                && !pEvent.isNull())
     1392            {
     1393                VBoxEventType_T aType;
     1394                hr = pEvent->COMGETTER(Type)(&aType);
     1395                ComAssertComRC(hr);
     1396                switch (aType)
     1397                {
     1398                    case VBoxEventType_OnGuestProcessOutput:
     1399                    {
     1400                        ComPtr<IGuestProcessOutputEvent> pOutputEvent = pEvent;
     1401                        Assert(!pOutputEvent.isNull());
     1402
     1403                        ComPtr<IGuestSession> pSession;
     1404                        pOutputEvent->COMGETTER(Session)(pSession.asOutParam());
     1405                        Assert(!pSession.isNull());
     1406                        ULONG uSessionID;
     1407                        hr = pSession->COMGETTER(Id)(&uSessionID);
     1408                        ComAssertComRC(hr);
     1409                        if (uSessionID != mSession->getId())
     1410                            continue; /* Only the session this process runs in is of interest. */
     1411
     1412                        ULONG uPID;
     1413                        hr = pOutputEvent->COMGETTER(Pid)(&uPID);
     1414                        ComAssertComRC(hr);
     1415                        if (uPID != mData.mPID)
     1416                            continue; /* Only the this process is of interest. */
     1417
     1418                        ULONG uHandleEvent;
     1419                        hr = pOutputEvent->COMGETTER(Handle)(&uHandleEvent);
     1420                        ComAssertComRC(hr);
     1421
     1422                        LogFlowThisFunc(("Got output event for process PID=%RU32, handle=%RU32 (session ID=%RU32): %ld\n",
     1423                                         mData.mPID, uHandleEvent, mSession->getId()));
     1424
     1425                        bool fSignal = uHandleEvent == uHandle;
     1426                        if (!fSignal)
     1427                            continue;
     1428
     1429                        com::SafeArray <BYTE> data;
     1430                        hr = pOutputEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
     1431                        ComAssertComRC(hr);
     1432
     1433                        size_t cbRead = data.size();
     1434
     1435                        if (pvData)
     1436                        {
     1437                            if (cbRead < cbData)
     1438                                cbData = cbRead;
     1439                            memcpy(pvData, data.raw(), cbData);
     1440                        }
     1441
     1442                        if (pcbRead)
     1443                            *pcbRead = cbRead;
     1444
     1445                        LogFlowThisFunc(("Output event for process PID=%RU32 (session ID=%RU32): %zubytes read\n",
     1446                                         uPID, mSession->getId(), cbRead));
     1447
     1448                        fSignalled = true;
     1449                        break;
     1450                    }
     1451
     1452                    default:
     1453                         AssertMsgFailed(("Unhandled event type %ld\n", aType));
     1454                         break;
     1455                }
     1456            }
     1457
     1458        } while (!fSignalled);
     1459
     1460        if (   RT_SUCCESS(vrc)
     1461            && !fSignalled)
     1462        {
     1463            vrc = VERR_TIMEOUT;
     1464        }
     1465
     1466        mEventSource->UnregisterListener(pListener);
     1467    }
     1468    else
     1469        vrc = VERR_COM_UNEXPECTED;
     1470
     1471    LogFlowFuncLeaveRC(vrc);
     1472    return vrc;
     1473}
     1474
     1475int GuestProcess::waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS,
     1476                                      ProcessStatus_T *pProcessStatus, int *pGuestRc)
     1477{
     1478    int vrc;
     1479
     1480    ComPtr<IEventListener> pListener;
     1481    HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
     1482    if (SUCCEEDED(hr))
     1483    {
     1484        com::SafeArray <VBoxEventType_T> eventTypes(1);
     1485        eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
     1486        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false);
     1487    }
     1488    else
     1489        vrc = VERR_COM_UNEXPECTED;
     1490
     1491    if (SUCCEEDED(hr))
     1492    {
     1493        LogFlowThisFunc(("Waiting for guest process state changed event (timeout=%RU32ms, flags=%x) ...\n",
     1494                         uTimeoutMS, fWaitFlags));
     1495
     1496        vrc = VINF_SUCCESS;
     1497
     1498        uint64_t u64Started = RTTimeMilliTS();
     1499        bool fSignalled = false;
     1500        do
     1501        {
     1502            unsigned cMsWait;
     1503            if (uTimeoutMS == RT_INDEFINITE_WAIT)
     1504                cMsWait = 1000;
     1505            else
     1506            {
     1507                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
     1508                if (cMsElapsed >= uTimeoutMS)
     1509                    break; /* timed out */
     1510                cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
     1511            }
     1512
     1513            ComPtr<IEvent> pEvent;
     1514            hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam());
     1515            if (   SUCCEEDED(hr)
     1516                && !pEvent.isNull())
     1517            {
     1518                VBoxEventType_T aType;
     1519                hr = pEvent->COMGETTER(Type)(&aType);
     1520                ComAssertComRC(hr);
     1521                switch (aType)
     1522                {
     1523                    case VBoxEventType_OnGuestProcessStateChanged:
     1524                    {
     1525                        ComPtr<IGuestProcessStateChangedEvent> pChangedEvent = pEvent;
     1526                        Assert(!pChangedEvent.isNull());
     1527
     1528                        ComPtr<IGuestSession> pSession;
     1529                        pChangedEvent->COMGETTER(Session)(pSession.asOutParam());
     1530                        Assert(!pSession.isNull());
     1531                        ULONG uSessionID;
     1532                        hr = pSession->COMGETTER(Id)(&uSessionID);
     1533                        ComAssertComRC(hr);
     1534                        if (uSessionID != mSession->getId())
     1535                            continue; /* Only the session this process runs in is of interest. */
     1536
     1537                        ULONG uPID;
     1538                        hr = pChangedEvent->COMGETTER(Pid)(&uPID);
     1539                        ComAssertComRC(hr);
     1540                        if (uPID != mData.mPID)
     1541                            continue; /* Only the this process is of interest. */
     1542
     1543                        ProcessStatus_T processStatus;
     1544                        pChangedEvent->COMGETTER(Status)(&processStatus);
     1545                        if (pProcessStatus)
     1546                            *pProcessStatus = processStatus;
     1547
     1548                        LogFlowThisFunc(("Got status changed event for process PID=%RU32 (session ID=%RU32): %ld\n",
     1549                                         mData.mPID, mSession->getId(), processStatus));
     1550
     1551                        bool fSignal = false;
     1552                        if (fWaitFlags)
     1553                        {
     1554                            switch (processStatus)
     1555                            {
     1556                                case ProcessStatus_Started:
     1557                                    fSignal = (fWaitFlags & ProcessWaitForFlag_Start);
     1558                                    break;
     1559
     1560                                default:
     1561                                    fSignal = true;
     1562                                    break;
     1563                            }
     1564                        }
     1565                        else
     1566                            fSignal = true;
     1567
     1568                        if (!fSignal)
     1569                            continue;
     1570
     1571                        ComPtr<IGuestErrorInfo> errorInfo;
     1572                        hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
     1573                        ComAssertComRC(hr);
     1574
     1575                        LONG lGuestRc;
     1576                        hr = errorInfo->COMGETTER(Result)(&lGuestRc);
     1577                        ComAssertComRC(hr);
     1578                        if (RT_FAILURE((int)lGuestRc))
     1579                            vrc = VERR_GSTCTL_GUEST_ERROR;
     1580                        if (pGuestRc)
     1581                            *pGuestRc = (int)lGuestRc;
     1582
     1583                        LogFlowThisFunc(("Status changed event for process PID=%RU32 (session ID=%RU32): %ld (%Rrc)\n",
     1584                                         uPID, mSession->getId(), processStatus,
     1585                                         RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
     1586
     1587                        fSignalled = true;
     1588                        break;
     1589                    }
     1590
     1591                    default:
     1592                         AssertMsgFailed(("Unhandled event type %ld\n", aType));
     1593                         break;
     1594                }
     1595            }
     1596
     1597        } while (!fSignalled);
     1598
     1599        if (   RT_SUCCESS(vrc)
     1600            && !fSignalled)
     1601        {
     1602            vrc = VERR_TIMEOUT;
     1603        }
     1604
     1605        mEventSource->UnregisterListener(pListener);
     1606    }
     1607    else
     1608        vrc = VERR_COM_UNEXPECTED;
    14961609
    14971610    LogFlowFuncLeaveRC(vrc);
     
    15171630    }
    15181631
    1519     int vrc = VINF_SUCCESS;
    1520 
    1521     GuestCtrlCallback *pCallbackWrite = NULL;
    1522     try
    1523     {
    1524         pCallbackWrite = new GuestCtrlCallback();
    1525     }
    1526     catch(std::bad_alloc &)
    1527     {
    1528         vrc = VERR_NO_MEMORY;
    1529     }
    1530 
    1531     /* Create callback and add it to the map. */
    1532     uint32_t uContextID = 0;
    1533     if (RT_SUCCESS(vrc))
    1534     {
    1535         vrc = pCallbackWrite->Init(CALLBACKTYPE_PROC_INPUT);
    1536         if (RT_SUCCESS(vrc))
    1537             vrc = callbackAdd(pCallbackWrite, &uContextID);
    1538     }
    1539 
    1540     alock.release(); /* Drop the write lock again. */
    1541 
     1632    uint32_t uContextID;
     1633    int vrc = generateContextID(mSession->getId(), mObjectID,
     1634                                &uContextID);
    15421635    if (RT_SUCCESS(vrc))
    15431636    {
     
    15521645
    15531646        vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
    1554         if (RT_FAILURE(vrc))
    1555         {
    1556             int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
    1557             AssertRC(rc2);
    1558         }
    15591647    }
    15601648
    15611649    if (RT_SUCCESS(vrc))
    15621650    {
    1563         /*
    1564          * Let's wait for the process being started.
    1565          * Note: Be sure not keeping a AutoRead/WriteLock here.
    1566          */
    1567         LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
    1568         vrc = pCallbackWrite->Wait(uTimeoutMS);
    1569         if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    1570         {
    1571             int guestRc = pCallbackWrite->GetResultCode();
    1572             if (RT_SUCCESS(guestRc))
    1573             {
    1574                 Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATA_PROC_INPUT));
    1575                 PCALLBACKDATA_PROC_INPUT pData = (PCALLBACKDATA_PROC_INPUT)pCallbackWrite->GetDataRaw();
    1576                 AssertPtr(pData);
    1577 
    1578                 uint32_t cbWritten = 0;
    1579                 switch (pData->uStatus)
    1580                 {
    1581                     case INPUT_STS_WRITTEN:
    1582                         cbWritten = pData->uProcessed;
    1583                         break;
    1584 
    1585                     case INPUT_STS_ERROR:
    1586                         vrc = pData->uFlags; /** @todo Fix int vs. uint32_t! */
    1587                         break;
    1588 
    1589                     case INPUT_STS_TERMINATED:
    1590                         vrc = VERR_CANCELLED;
    1591                         break;
    1592 
    1593                     case INPUT_STS_OVERFLOW:
    1594                         vrc = VERR_BUFFER_OVERFLOW;
    1595                         break;
    1596 
    1597                     default:
    1598                         /* Silently skip unknown errors. */
    1599                         break;
    1600                 }
    1601 
    1602                 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
    1603 
    1604                 if (puWritten)
    1605                     *puWritten = cbWritten;
    1606             }
    1607             else
    1608                 vrc = VERR_GSTCTL_GUEST_ERROR;
    1609 
    1610             if (pGuestRc)
    1611                 *pGuestRc = guestRc;
    1612             LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
    1613         }
    1614     }
    1615 
    1616     alock.acquire();
    1617 
    1618     int rc2 = callbackRemove(uContextID);
    1619     if (RT_SUCCESS(vrc))
    1620         vrc = rc2;
    1621 
    1622     callbackDelete(pCallbackWrite);
     1651        alock.release(); /* Drop the write lock before waiting. */
     1652
     1653        ProcessInputStatus_T inputStatus;
     1654        size_t cbProcessed;
     1655        vrc = waitForInputNotify(uHandle, uTimeoutMS, &inputStatus, &cbProcessed);
     1656        if (RT_SUCCESS(vrc))
     1657        {
     1658            /** @todo Set guestRc. */
     1659
     1660            if (puWritten)
     1661                *puWritten = cbProcessed;
     1662        }
     1663        /** @todo Error handling. */
     1664    }
    16231665
    16241666    LogFlowFuncLeaveRC(vrc);
     
    17131755    }
    17141756
    1715     AssertPtr(mObject.mSession);
    1716     mObject.mSession->processRemoveFromList(this);
     1757    AssertPtr(mSession);
     1758    mSession->processRemoveFromList(this);
    17171759
    17181760    /*
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r45109 r45415  
    2222*******************************************************************************/
    2323#include "GuestImpl.h"
     24#include "GuestErrorInfoImpl.h"
    2425#include "GuestSessionImpl.h"
    2526#include "GuestCtrlImplPrivate.h"
     
    2829#include "AutoCaller.h"
    2930#include "ProgressImpl.h"
     31#include "VBoxEvents.h"
    3032#include "VMMDev.h"
    3133
    3234#include <memory> /* For auto_ptr. */
    3335
     36#include <iprt/cpp/utils.h> /* For unconst(). */
    3437#include <iprt/env.h>
    3538#include <iprt/file.h> /* For CopyTo/From. */
    3639
    3740#include <VBox/com/array.h>
     41#include <VBox/com/listeners.h>
    3842#include <VBox/version.h>
    3943
     
    9195    mData.mRC = VINF_SUCCESS;
    9296    mData.mStatus = GuestSessionStatus_Undefined;
    93 
    94     mData.mWaitCount = 0;
    95     mData.mWaitEvent = NULL;
    9697
    9798    return BaseFinalConstruct();
     
    128129    AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
    129130
    130     mData.mParent = pGuest;
     131    mParent = pGuest;
    131132
    132133    /* Copy over startup info. */
     
    149150    if (RT_SUCCESS(rc))
    150151    {
     152        unconst(mEventSource).createObject();
     153        Assert(!mEventSource.isNull());
     154        HRESULT hr = mEventSource->init(static_cast<IGuestSession*>(this));
     155        if (FAILED(hr))
     156            rc = VERR_COM_UNEXPECTED;
     157    }
     158
     159    if (RT_SUCCESS(rc))
     160    {
    151161        /* Confirm a successful initialization when it's the case. */
    152162        autoInitSpan.setSucceeded();
     
    174184    int rc = VINF_SUCCESS;
    175185
    176 #ifndef VBOX_WITH_GUEST_CONTROL
     186#ifdef VBOX_WITH_GUEST_CONTROL
    177187    LogFlowThisFunc(("Closing directories (%RU64 total)\n",
    178188                     mData.mDirectories.size()));
     
    180190         itDirs != mData.mDirectories.end(); ++itDirs)
    181191    {
    182 #ifdef DEBUG
     192# ifdef DEBUG
    183193        ULONG cRefs = (*itDirs)->AddRef();
    184         LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs));
     194        LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itDirs), cRefs - 1));
    185195        (*itDirs)->Release();
    186 #endif
     196# endif
    187197        (*itDirs)->uninit();
    188198    }
     
    194204         itFiles != mData.mFiles.end(); ++itFiles)
    195205    {
    196 #ifdef DEBUG
    197         ULONG cRefs = (*itFiles)->AddRef();
    198         LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs));
    199         (*itFiles)->Release();
    200 #endif
    201         (*itFiles)->uninit();
     206# ifdef DEBUG
     207        ULONG cRefs = itFiles->second->AddRef();
     208        LogFlowThisFunc(("pFile=%p, cRefs=%RU32\n", (*itFiles), cRefs - 1));
     209        itFiles->second->Release();
     210# endif
     211        itFiles->second->uninit();
    202212    }
    203213    mData.mFiles.clear();
     
    208218         itProcs != mData.mProcesses.end(); ++itProcs)
    209219    {
    210 #ifdef DEBUG
     220# ifdef DEBUG
    211221        ULONG cRefs = itProcs->second->AddRef();
    212         LogFlowThisFunc(("pProcess=%p, cRefs=%RU32\n", itProcs->second, cRefs));
     222        LogFlowThisFunc(("pProcess=%p, cRefs=%RU32\n", itProcs->second, cRefs - 1));
    213223        itProcs->second->Release();
    214 #endif
     224# endif
    215225        itProcs->second->uninit();
    216226    }
     
    218228
    219229    LogFlowThisFunc(("mNumObjects=%RU32\n", mData.mNumObjects));
    220 #endif
     230
     231    unconst(mEventSource).setNull();
     232
     233#endif /* VBOX_WITH_GUEST_CONTROL */
    221234    LogFlowFuncLeaveRC(rc);
    222235}
     
    495508}
    496509
     510STDMETHODIMP GuestSession::COMGETTER(EventSource)(IEventSource ** aEventSource)
     511{
     512    CheckComArgOutPointerValid(aEventSource);
     513
     514    AutoCaller autoCaller(this);
     515    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     516
     517    // no need to lock - lifetime constant
     518    mEventSource.queryInterfaceTo(aEventSource);
     519
     520    return S_OK;
     521}
     522
    497523// private methods
    498524///////////////////////////////////////////////////////////////////////////////
     
    501527{
    502528    LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS));
     529
     530    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    503531
    504532    /* Legacy Guest Additions don't support opening dedicated
     
    512540    /** @todo uFlags validation. */
    513541
    514     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    515 
    516     /* Destroy a pending callback request. */
    517     mData.mCallback.Destroy();
    518 
    519     int vrc = mData.mCallback.Init(CALLBACKTYPE_SESSION_NOTIFY);
    520 
    521     alock.release(); /* Drop the write lock again. */
    522 
     542    if (mData.mStatus != GuestSessionStatus_Started)
     543        return VINF_SUCCESS;
     544
     545    uint32_t uContextID;
     546    int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */,
     547                                &uContextID);
    523548    if (RT_SUCCESS(vrc))
    524549    {
    525         /* The context ID only contains this session's ID; all other
    526          * parameters like object and the count itself are not needed
    527          * and therefore 0. */
    528         uint32_t uContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */,
    529                                                             0 /* Object */, 0 /* Count */);
    530 
    531         VBOXHGCMSVCPARM paParms[4];
    532 
    533         int i = 0;
    534         paParms[i++].setUInt32(uContextID);
    535         paParms[i++].setUInt32(uFlags);
    536 
    537         vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
    538     }
    539 
    540     if (RT_SUCCESS(vrc))
    541     {
    542         /*
    543          * Let's wait for the process being started.
    544          * Note: Be sure not keeping a AutoRead/WriteLock here.
    545          */
    546         LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
    547         vrc = mData.mCallback.Wait(uTimeoutMS);
    548         if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    549         {
    550             int guestRc = mData.mCallback.GetResultCode();
    551             if (RT_SUCCESS(guestRc))
    552             {
    553                 /* Nothing to do here right now. */
    554             }
    555             else
    556                 vrc = VERR_GSTCTL_GUEST_ERROR;
    557 
    558             if (pGuestRc)
    559                 *pGuestRc = guestRc;
    560             LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
    561         }
    562     }
    563 
    564     AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
    565 
    566     mData.mCallback.Destroy();
     550        if (RT_SUCCESS(vrc))
     551        {
     552            LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n",
     553                             mData.mSession.mID, uFlags));
     554
     555            VBOXHGCMSVCPARM paParms[4];
     556            int i = 0;
     557            paParms[i++].setUInt32(uContextID);
     558            paParms[i++].setUInt32(uFlags);
     559
     560            vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
     561        }
     562
     563        if (RT_SUCCESS(vrc))
     564        {
     565            alock.release(); /* Drop the write lock before waiting. */
     566
     567            vrc = waitForStateChange(GuestSessionWaitForFlag_Terminate, uTimeoutMS,
     568                                     NULL /* Session status */, pGuestRc);
     569        }
     570    }
    567571
    568572    LogFlowFuncLeaveRC(vrc);
     
    813817
    814818#ifdef DEBUG
    815     LogFlowThisFunc(("ID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
     819    LogFlowThisFunc(("sessionID=%RU32, CID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
    816820                     mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
    817821#endif
     
    821825    {
    822826        case GUEST_DISCONNECTED:
    823             /** @todo Handle closing all processes. */
     827            /** @todo Handle closing all guest objects. */
    824828            break;
    825829
    826830        case GUEST_SESSION_NOTIFY:
    827831        {
    828             rc = onSessionStatusChange(pCbCtx,
    829                                        &mData.mCallback, pSvcCb);
     832            rc = onSessionStatusChange(pCbCtx, pSvcCb);
    830833            break;
    831834        }
     
    960963        return VERR_COM_UNEXPECTED;
    961964
    962     Console *pConsole = mData.mParent->getConsole();
     965    Console *pConsole = mParent->getConsole();
    963966    AssertPtr(pConsole);
    964967
     
    11031106
    11041107        case VERR_MAX_PROCS_REACHED:
    1105             strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
     1108            strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
    11061109            break;
    11071110
     
    11221125}
    11231126
     1127/**
     1128 * Checks if this session is ready state where it can handle
     1129 * all session-bound actions (like guest processes, guest files).
     1130 * Only used by official API methods. Will set an external
     1131 * error when not ready.
     1132 */
     1133HRESULT GuestSession::isReadyExternal(void)
     1134{
     1135    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     1136
     1137    /** @todo Be a bit more informative. */
     1138    if (mData.mStatus != GuestSessionStatus_Started)
     1139        return setError(E_UNEXPECTED, tr("Session is not in started state"));
     1140
     1141    return S_OK;
     1142}
     1143
    11241144/** No locking! */
    1125 int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
    1126                                         GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
    1127 {
     1145int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
     1146{
     1147    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
    11281148    /* pCallback is optional. */
    11291149    AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
     
    11371157    pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult);
    11381158
    1139     LogFlowThisFunc(("ID=%RU32, uType=%RU32, rc=%Rrc, pCallback=%p, pData=%p\n",
    1140                      mData.mSession.mID, dataCb.uType, dataCb.uResult, pCallback, pSvcCbData));
     1159    LogFlowThisFunc(("ID=%RU32, uType=%RU32, guestRc=%Rrc\n",
     1160                     mData.mSession.mID, dataCb.uType, dataCb.uResult));
    11411161
    11421162    int vrc = VINF_SUCCESS;
     1163
     1164    GuestSessionStatus_T sessionStatus = GuestSessionStatus_Undefined;
    11431165
    11441166    int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */
     
    11461168    {
    11471169        case GUEST_SESSION_NOTIFYTYPE_ERROR:
    1148             mData.mStatus = GuestSessionStatus_Error;
     1170            sessionStatus = GuestSessionStatus_Error;
    11491171            break;
    11501172
    11511173        case GUEST_SESSION_NOTIFYTYPE_STARTED:
    1152             mData.mStatus = GuestSessionStatus_Started;
     1174            sessionStatus = GuestSessionStatus_Started;
    11531175            break;
    11541176
     
    11561178        case GUEST_SESSION_NOTIFYTYPE_TES:
    11571179        case GUEST_SESSION_NOTIFYTYPE_TEA:
    1158             mData.mStatus = GuestSessionStatus_Terminated;
     1180            sessionStatus = GuestSessionStatus_Terminated;
    11591181            break;
    11601182
    11611183        case GUEST_SESSION_NOTIFYTYPE_TOK:
    1162             mData.mStatus = GuestSessionStatus_TimedOutKilled;
     1184            sessionStatus = GuestSessionStatus_TimedOutKilled;
    11631185            break;
    11641186
    11651187        case GUEST_SESSION_NOTIFYTYPE_TOA:
    1166             mData.mStatus = GuestSessionStatus_TimedOutAbnormally;
     1188            sessionStatus = GuestSessionStatus_TimedOutAbnormally;
    11671189            break;
    11681190
    11691191        case GUEST_SESSION_NOTIFYTYPE_DWN:
    1170             mData.mStatus = GuestSessionStatus_Down;
     1192            sessionStatus = GuestSessionStatus_Down;
    11711193            break;
    11721194
     1195        case GUEST_SESSION_NOTIFYTYPE_UNDEFINED:
    11731196        default:
    11741197            vrc = VERR_NOT_SUPPORTED;
     
    11791202    {
    11801203        if (RT_FAILURE(guestRc))
    1181             mData.mStatus = GuestSessionStatus_Error;
    1182     }
    1183     else if (vrc == VERR_NOT_SUPPORTED)
    1184     {
    1185         /* Also let the callback know. */
    1186         guestRc = VERR_NOT_SUPPORTED;
    1187     }
    1188 
    1189     /*
    1190      * Now do the signalling stuff.
    1191      */
    1192     if (pCallback)
    1193     {
    1194         int rc2 = pCallback->SetData(&dataCb, sizeof(dataCb));
    1195         AssertRC(rc2);
    1196         rc2 = pCallback->Signal(guestRc);
    1197         AssertRC(rc2);
    1198     }
    1199 
    1200     LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n",
    1201                      mData.mSession.mID, guestRc));
     1204            sessionStatus = GuestSessionStatus_Error;
     1205    }
     1206
     1207    /* Set the session status. */
     1208    if (sessionStatus != GuestSessionStatus_Undefined)
     1209    {
     1210        int rc2 = setSessionStatus(sessionStatus, guestRc);
     1211        if (RT_SUCCESS(vrc))
     1212            vrc = rc2;
     1213    }
     1214
     1215    LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", mData.mSession.mID, guestRc));
    12021216
    12031217    LogFlowFuncLeaveRC(vrc);
     
    12091223    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    12101224
    1211     LogFlowThisFunc(("uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n",
    1212                      mData.mProtocolVersion, mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS));
     1225    LogFlowThisFunc(("mID=%RU32, mName=%s, uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n",
     1226                     mData.mSession.mID, mData.mSession.mName.c_str(), mData.mProtocolVersion,
     1227                     mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS));
    12131228
    12141229    /* Legacy Guest Additions don't support opening dedicated
     
    12221237    }
    12231238
     1239    if (mData.mStatus != GuestSessionStatus_Undefined)
     1240        return VINF_SUCCESS;
     1241
    12241242    /** @todo mData.mSession.uFlags validation. */
    12251243
     
    12271245    mData.mStatus = GuestSessionStatus_Starting;
    12281246
    1229     /* Destroy a pending callback request. */
    1230     mData.mCallback.Destroy();
    1231 
    1232     int vrc = mData.mCallback.Init(CALLBACKTYPE_SESSION_NOTIFY);
    1233 
    1234     alock.release(); /* Drop the write lock again. */
    1235 
     1247    uint32_t uContextID;
     1248    int vrc = generateContextID(mData.mSession.mID, 0 /* Object ID */,
     1249                                &uContextID);
    12361250    if (RT_SUCCESS(vrc))
    12371251    {
    1238         uint32_t uContextID =
    1239             VBOX_GUESTCTRL_CONTEXTID_MAKE(mData.mSession.mID /* Session ID */,
    1240                                           0 /* Object */, 0 /* Count */);
    1241 
    12421252        VBOXHGCMSVCPARM paParms[8];
    12431253
     
    12581268    if (RT_SUCCESS(vrc))
    12591269    {
    1260         /*
    1261          * Let's wait for the process being started.
    1262          * Note: Be sure not keeping a AutoRead/WriteLock here.
    1263          */
    1264         LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", mData.mSession.mOpenTimeoutMS));
    1265         vrc = mData.mCallback.Wait(mData.mSession.mOpenTimeoutMS);
    1266         if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
    1267         {
    1268             int guestRc = mData.mCallback.GetResultCode();
    1269             if (RT_SUCCESS(guestRc))
    1270             {
    1271                 /* Nothing to do here right now. */
    1272             }
    1273             else
    1274                 vrc = VERR_GSTCTL_GUEST_ERROR;
    1275 
    1276             if (pGuestRc)
    1277                 *pGuestRc = guestRc;
    1278             LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
    1279         }
    1280     }
    1281 
    1282     alock.acquire();
    1283 
    1284     /* Destroy callback. */
    1285     mData.mCallback.Destroy();
     1270        alock.release(); /* Drop write lock before waiting. */
     1271
     1272        vrc = waitForStateChange(GuestSessionWaitForFlag_Start,  30 * 1000 /* 30s timeout */,
     1273                                 NULL /* Session status */, pGuestRc);
     1274    }
    12861275
    12871276    LogFlowFuncLeaveRC(vrc);
     
    13441333int GuestSession::processRemoveFromList(GuestProcess *pProcess)
    13451334{
    1346     LogFlowThisFuncEnter();
     1335    AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
     1336
     1337    LogFlowThisFunc(("pProcess=%p\n", pProcess));
    13471338
    13481339    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    13521343    ULONG uPID;
    13531344    HRESULT hr = pProcess->COMGETTER(PID)(&uPID);
     1345    ComAssertComRC(hr);
    13541346
    13551347    LogFlowFunc(("Closing process (PID=%RU32) ...\n", uPID));
    13561348
    1357     for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
    1358          itProcs != mData.mProcesses.end(); ++itProcs)
     1349    SessionProcesses::iterator itProcs = mData.mProcesses.begin();
     1350    while (itProcs != mData.mProcesses.end())
    13591351    {
    13601352        if (pProcess == itProcs->second)
     
    13671359
    13681360            Assert(mData.mNumObjects);
    1369             LogFlowFunc(("Removing process (Session: %RU32) with process ID=%RU32, guest PID=%RU32 (now total %ld processes, %ld objects)\n",
    1370                          mData.mSession.mID, pCurProc->getObjectID(), uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1));
    1371 
     1361            LogFlowFunc(("Removing process ID=%RU32 (Session: %RU32), guest PID=%RU32 (now total %ld processes, %ld objects)\n",
     1362                         pCurProc->getObjectID(), mData.mSession.mID, uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1));
     1363
     1364            LogFlowFunc(("1\n"));
    13721365            mData.mProcesses.erase(itProcs);
    13731366            mData.mNumObjects--;
    13741367
     1368            LogFlowFunc(("2\n"));
     1369            fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, NULL /* Process */,
     1370                                            uPID, false /* Process unregistered */);
     1371            LogFlowFunc(("3\n"));
    13751372            rc = VINF_SUCCESS;
    13761373            break;
    13771374        }
     1375
     1376        LogFlowFunc(("4\n"));
     1377        itProcs++;
    13781378    }
    13791379
     
    14751475        return VERR_COM_UNEXPECTED;
    14761476
    1477     rc = pProcess->init(mData.mParent->getConsole() /* Console */, this /* Session */,
     1477    rc = pProcess->init(mParent->getConsole() /* Console */, this /* Session */,
    14781478                        uNewProcessID, procInfo);
    14791479    if (RT_FAILURE(rc))
     
    14851485    Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
    14861486
     1487    fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess,
     1488                                    0 /* PID */, true /* Process registered */);
     1489
    14871490    LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n",
    14881491                 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
     
    15371540
    15381541#ifndef VBOX_GUESTCTRL_TEST_CASE
    1539     ComObjPtr<Console> pConsole = mData.mParent->getConsole();
     1542    ComObjPtr<Console> pConsole = mParent->getConsole();
    15401543    Assert(!pConsole.isNull());
    15411544
     
    15651568
    15661569    return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::guestErrorToString(guestRc).c_str());
     1570}
     1571
     1572/* Does not do locking; caller is responsible for that! */
     1573int GuestSession::setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc)
     1574{
     1575    LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, sessionRc=%Rrc\n",
     1576                     mData.mStatus, sessionStatus, sessionRc));
     1577
     1578    if (sessionStatus == GuestSessionStatus_Error)
     1579    {
     1580        AssertMsg(RT_FAILURE(sessionRc), ("Guest rc must be an error (%Rrc)\n", sessionRc));
     1581        /* Do not allow overwriting an already set error. If this happens
     1582         * this means we forgot some error checking/locking somewhere. */
     1583        AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
     1584    }
     1585    else
     1586        AssertMsg(RT_SUCCESS(sessionRc), ("Guest rc must not be an error (%Rrc)\n", sessionRc));
     1587
     1588    if (mData.mStatus != sessionStatus)
     1589    {
     1590        mData.mStatus = sessionStatus;
     1591        mData.mRC     = sessionRc;
     1592
     1593        ComObjPtr<GuestErrorInfo> errorInfo;
     1594        HRESULT hr = errorInfo.createObject();
     1595        ComAssertComRC(hr);
     1596        int rc2 = errorInfo->init(sessionRc, guestErrorToString(sessionRc));
     1597        AssertRC(rc2);
     1598
     1599        fireGuestSessionStateChangedEvent(mEventSource, this,
     1600                                          mData.mSession.mID, sessionStatus, errorInfo);
     1601    }
     1602
     1603    return VINF_SUCCESS;
     1604}
     1605
     1606int GuestSession::signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
     1607{
     1608    /*LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
     1609                     enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));*/
     1610
     1611    /* Note: No write locking here -- already done in the caller. */
     1612
     1613    int vrc = VINF_SUCCESS;
     1614    /*if (mData.mWaitEvent)
     1615        vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);*/
     1616    LogFlowFuncLeaveRC(vrc);
     1617    return vrc;
    15671618}
    15681619
     
    16211672     * This is done using the Guest Additions version
    16221673     */
    1623     ComObjPtr<Guest> pGuest = mData.mParent;
     1674    ComObjPtr<Guest> pGuest = mParent;
    16241675    Assert(!pGuest.isNull());
    16251676
     
    16471698    AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
    16481699
    1649     LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
    1650                      fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));
     1700    /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
     1701                     fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/
    16511702
    16521703    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    17371788    }
    17381789
    1739     if (mData.mWaitCount > 0) /* We only support one waiting caller a time at the moment. */
    1740         return VERR_ALREADY_EXISTS;
    1741     mData.mWaitCount++;
    1742 
    1743     int vrc = VINF_SUCCESS;
    1744     try
    1745     {
    1746         Assert(mData.mWaitEvent == NULL);
    1747         mData.mWaitEvent = new GuestSessionWaitEvent(fWaitFlags);
    1748     }
    1749     catch(std::bad_alloc &)
    1750     {
    1751         vrc = VERR_NO_MEMORY;
    1752     }
    1753 
     1790    alock.release(); /* Release lock before waiting. */
     1791
     1792    GuestSessionStatus_T sessionStatus;
     1793    int vrc = waitForStateChange(fWaitFlags, uTimeoutMS, &sessionStatus, pGuestRc);
    17541794    if (RT_SUCCESS(vrc))
    17551795    {
    1756         GuestSessionWaitEvent *pEvent = mData.mWaitEvent;
    1757         AssertPtr(pEvent);
    1758 
    1759         alock.release(); /* Release lock before waiting. */
    1760 
    1761         vrc = pEvent->Wait(uTimeoutMS);
    1762         LogFlowThisFunc(("Waiting completed with rc=%Rrc\n", vrc));
    1763         if (RT_SUCCESS(vrc))
    1764         {
    1765             waitResult = pEvent->GetWaitResult();
    1766             int guestRc = pEvent->GetWaitRc();
    1767             if (RT_FAILURE(guestRc))
    1768                 vrc = VERR_GSTCTL_GUEST_ERROR;
    1769 
    1770             LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", guestRc));
    1771 
    1772             if (pGuestRc)
    1773                 *pGuestRc = guestRc;
    1774         }
    1775 
    1776         alock.acquire(); /* Get the lock again. */
    1777 
    1778         /* Note: The caller always is responsible of deleting the
    1779          *       stuff it created before. See close() for more information. */
    1780         delete mData.mWaitEvent;
    1781         mData.mWaitEvent = NULL;
    1782     }
    1783 
    1784     Assert(mData.mWaitCount);
    1785     mData.mWaitCount--;
     1796        switch (sessionStatus)
     1797        {
     1798            case GuestSessionStatus_Started:
     1799                waitResult = GuestSessionWaitResult_Start;
     1800                break;
     1801
     1802            case GuestSessionStatus_Terminated:
     1803                waitResult = GuestSessionWaitResult_Terminate;
     1804                break;
     1805
     1806            case GuestSessionStatus_TimedOutKilled:
     1807            case GuestSessionStatus_TimedOutAbnormally:
     1808                waitResult = GuestSessionWaitResult_Timeout;
     1809                break;
     1810
     1811            case GuestSessionStatus_Down:
     1812                waitResult = GuestSessionWaitResult_Terminate;
     1813                break;
     1814
     1815            case GuestSessionStatus_Error:
     1816                waitResult = GuestSessionWaitResult_Error;
     1817                break;
     1818
     1819            default:
     1820                waitResult = GuestSessionWaitResult_Status;
     1821                break;
     1822        }
     1823    }
     1824
     1825    LogFlowFuncLeaveRC(vrc);
     1826    return vrc;
     1827}
     1828
     1829int GuestSession::waitForStateChange(uint32_t fWaitFlags, uint32_t uTimeoutMS,
     1830                                     GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
     1831{
     1832    /** @todo Param validation. */
     1833
     1834    int vrc;
     1835
     1836    ComPtr<IEventListener> pListener;
     1837    HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
     1838    if (SUCCEEDED(hr))
     1839    {
     1840        com::SafeArray <VBoxEventType_T> eventTypes(1);
     1841        eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
     1842        hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes), false);
     1843    }
     1844    else
     1845        vrc = VERR_COM_UNEXPECTED;
     1846
     1847    if (SUCCEEDED(hr))
     1848    {
     1849        LogFlowThisFunc(("Waiting for guest session state changed event (timeout=%RU32ms, flags=%x) ...\n",
     1850                         uTimeoutMS, fWaitFlags));
     1851
     1852        vrc = VINF_SUCCESS;
     1853
     1854        uint64_t u64Started = RTTimeMilliTS();
     1855        bool fSignalled = false;
     1856        do
     1857        {
     1858            unsigned cMsWait;
     1859            if (uTimeoutMS == RT_INDEFINITE_WAIT)
     1860                cMsWait = 1000;
     1861            else
     1862            {
     1863                uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
     1864                if (cMsElapsed >= uTimeoutMS)
     1865                    break; /* timed out */
     1866                cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
     1867            }
     1868
     1869            ComPtr<IEvent> pEvent;
     1870            hr = mEventSource->GetEvent(pListener, cMsWait, pEvent.asOutParam());
     1871            if (   SUCCEEDED(hr)
     1872                && !pEvent.isNull())
     1873            {
     1874                VBoxEventType_T aType;
     1875                hr = pEvent->COMGETTER(Type)(&aType);
     1876                ComAssertComRC(hr);
     1877                switch (aType)
     1878                {
     1879                    case VBoxEventType_OnGuestSessionStateChanged:
     1880                    {
     1881                        ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pEvent;
     1882                        Assert(!pChangedEvent.isNull());
     1883
     1884                        ULONG uSessionID;
     1885                        pChangedEvent->COMGETTER(Id)(&uSessionID);
     1886                        if (uSessionID != mData.mSession.mID)
     1887                            continue; /* Only our own session is of interest. */
     1888
     1889                        GuestSessionStatus_T sessionStatus;
     1890                        pChangedEvent->COMGETTER(Status)(&sessionStatus);
     1891                        if (pSessionStatus)
     1892                            *pSessionStatus = sessionStatus;
     1893
     1894                        LogFlowThisFunc(("Got status changed event for session ID=%RU32: %ld\n",
     1895                                         mData.mSession.mID, sessionStatus));
     1896
     1897                        bool fSignal = false;
     1898                        if (fWaitFlags)
     1899                        {
     1900                            switch (sessionStatus)
     1901                            {
     1902                                case GuestSessionStatus_Started:
     1903                                    fSignal = (   fWaitFlags & GuestSessionWaitForFlag_Start
     1904                                               || fWaitFlags & GuestSessionWaitForFlag_Status);
     1905                                    break;
     1906
     1907                                default:
     1908                                    fSignal = true;
     1909                                    break;
     1910                            }
     1911                        }
     1912                        else
     1913                            fSignal = true;
     1914
     1915                        if (!fSignal)
     1916                            continue;
     1917
     1918                        ComPtr<IGuestErrorInfo> errorInfo;
     1919                        hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
     1920                        ComAssertComRC(hr);
     1921
     1922                        LONG lGuestRc;
     1923                        hr = errorInfo->COMGETTER(Result)(&lGuestRc);
     1924                        ComAssertComRC(hr);
     1925                        if (RT_FAILURE((int)lGuestRc))
     1926                            vrc = VERR_GSTCTL_GUEST_ERROR;
     1927                        if (pGuestRc)
     1928                            *pGuestRc = (int)lGuestRc;
     1929
     1930                        LogFlowThisFunc(("Status changed event for session ID=%RU32: %ld (%Rrc)\n",
     1931                                         mData.mSession.mID, sessionStatus,
     1932                                         RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
     1933
     1934                        fSignalled = true;
     1935                        break;
     1936                    }
     1937
     1938                    default:
     1939                         AssertMsgFailed(("Unhandled event type %ld\n", aType));
     1940                         break;
     1941                }
     1942            }
     1943
     1944        } while (!fSignalled);
     1945
     1946        if (   RT_SUCCESS(vrc)
     1947            && !fSignalled)
     1948        {
     1949            vrc = VERR_TIMEOUT;
     1950        }
     1951
     1952        mEventSource->UnregisterListener(pListener);
     1953    }
     1954    else
     1955        vrc = VERR_COM_UNEXPECTED;
    17861956
    17871957    LogFlowFuncLeaveRC(vrc);
     
    18101980
    18111981    /* Remove ourselves from the session list. */
    1812     int rc2 = mData.mParent->sessionRemove(this);
     1982    int rc2 = mParent->sessionRemove(this);
    18131983    if (RT_SUCCESS(rc))
    18141984        rc = rc2;
     
    18281998
    18291999        return setError(VBOX_E_IPRT_ERROR,
    1830                         tr("Closing guest session failed with %Rrc\n"), rc);
     2000                        tr("Closing guest session failed with %Rrc"), rc);
    18312001    }
    18322002
     
    24662636    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    24672637
     2638    HRESULT hr = isReadyExternal();
     2639    if (FAILED(hr))
     2640        return hr;
     2641
    24682642    /** @todo Validate open mode. */
    24692643    /** @todo Validate disposition mode. */
     
    24712645    /** @todo Validate creation mode. */
    24722646    uint32_t uCreationMode = 0;
    2473 
    2474     HRESULT hr = S_OK;
    24752647
    24762648    GuestFileOpenInfo openInfo;
     
    26602832    AutoCaller autoCaller(this);
    26612833    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     2834
     2835    HRESULT hr = isReadyExternal();
     2836    if (FAILED(hr))
     2837        return hr;
    26622838
    26632839    GuestProcessStartupInfo procInfo;
     
    26882864    }
    26892865
    2690     HRESULT hr = S_OK;
    2691 
    26922866    if (RT_SUCCESS(rc))
    26932867    {
     
    27322906        {
    27332907            case VERR_MAX_PROCS_REACHED:
    2734                 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of guest objects per session (%ld) reached"),
     2908                hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"),
    27352909                                                    VBOX_GUESTCTRL_MAX_OBJECTS);
    27362910                break;
  • trunk/src/VBox/Main/testcase/tstGuestCtrlContextID.cpp

    r44863 r45415  
    3535{
    3636    RTTEST hTest;
    37     int rc = RTTestInitAndCreate("tstMakeup", &hTest);
     37    int rc = RTTestInitAndCreate("tstGuestCtrlContextID", &hTest);
    3838    if (rc)
    3939        return rc;
     
    7676    RTTestIPrintf(RTTESTLVL_DEBUG, "Max context is: %RU32\n", uContextMax);
    7777
    78     /* Do 64 tests total. */
    79     for (int t = 0; t < 64 && !RTTestErrorCount(hTest); t++)
     78    /* Do 4048 tests total. */
     79    for (int t = 0; t < 4048 && !RTTestErrorCount(hTest); t++)
    8080    {
    8181        /* VBOX_GUESTCTRL_MAX_* includes 0 as an object, so subtract one. */
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