VirtualBox

Changeset 30020 in vbox for trunk


Ignore:
Timestamp:
Jun 4, 2010 8:09:58 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
62351
Message:

Guest Control/Main: Get rid of busy waiting, use multi stage progress objects, clean up temporary callback contexts.

Location:
trunk/src/VBox
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r30013 r30020  
    388388                     * Some data left to output?
    389389                     */
    390 
    391390                    if (   fWaitForStdOut
    392391                        || fWaitForStdErr)
    393392                    {
    394                         CHECK_ERROR_BREAK(guest, GetProcessOutput(uPID, 0 /* aFlags */,
    395                                                                   u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)));
    396                         cbOutputData = aOutputData.size();
    397                         if (cbOutputData > 0)
     393
     394                        rc = guest->GetProcessOutput(uPID, 0 /* aFlags */,
     395                                                     u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData));
     396                        if (FAILED(rc))
    398397                        {
    399                             /* aOutputData has a platform dependent line ending, standardize on
    400                              * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
    401                              * Windows. Otherwise we end up with CR/CR/LF on Windows. */
    402                             ULONG cbOutputDataPrint = cbOutputData;
    403                             for (BYTE *s = aOutputData.raw(), *d = s;
    404                                  s - aOutputData.raw() < (ssize_t)cbOutputData;
    405                                  s++, d++)
     398                            /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
     399                             * because it contains more accurate info about what went wrong. */
     400                            ErrorInfo info(guest);
     401                            if (info.isFullAvailable())
    406402                            {
    407                                 if (*s == '\r')
     403                                if (rc == VBOX_E_IPRT_ERROR)
    408404                                {
    409                                     /* skip over CR, adjust destination */
    410                                     d--;
    411                                     cbOutputDataPrint--;
     405                                    RTPrintf("%ls.\n", info.getText().raw());
    412406                                }
    413                                 else if (s != d)
    414                                     *d = *s;
     407                                else
     408                                {
     409                                    RTPrintf("ERROR: %ls (%Rhrc).\n", info.getText().raw(), info.getResultCode());
     410                                }
    415411                            }
    416                             RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint);
     412                            cbOutputData = 0;
    417413                        }
    418                     }
    419 
    420                     if (cbOutputData <= 0)
     414                        else
     415                        {
     416                            cbOutputData = aOutputData.size();
     417                            if (cbOutputData > 0)
     418                            {
     419                                /* aOutputData has a platform dependent line ending, standardize on
     420                                 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
     421                                 * Windows. Otherwise we end up with CR/CR/LF on Windows. */
     422                                ULONG cbOutputDataPrint = cbOutputData;
     423                                for (BYTE *s = aOutputData.raw(), *d = s;
     424                                     s - aOutputData.raw() < (ssize_t)cbOutputData;
     425                                     s++, d++)
     426                                {
     427                                    if (*s == '\r')
     428                                    {
     429                                        /* skip over CR, adjust destination */
     430                                        d--;
     431                                        cbOutputDataPrint--;
     432                                    }
     433                                    else if (s != d)
     434                                        *d = *s;
     435                                }
     436                                RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint);
     437                            }
     438                        }
     439                    }
     440
     441                    if (cbOutputData <= 0) /* No more output data left? */
    421442                    {
    422443                        if (fCompleted)
     
    431452                    }
    432453
    433                     /* process async cancelation */
     454                    /* Process async cancelation */
    434455                    if (g_fExecCanceled && !fCanceledAlready)
    435456                    {
     
    441462                    }
    442463
    443                     /* progress canceled by Main API? */
     464                    /* Progress canceled by Main API? */
    444465                    if (   SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled)))
    445466                        && fCanceled)
     
    447468                        break;
    448469                    }
    449 
    450                     progress->WaitForCompletion(100);
    451                 }
    452 
    453                 /* undo signal handling */
     470                }
     471
     472                /* Undo signal handling */
    454473                if (fCancelable)
    455474                {
     
    465484                        RTPrintf("Process execution canceled!\n");
    466485                }
    467                 else if (fCompleted)
     486                else if (   fCompleted
     487                         && SUCCEEDED(rc))
    468488                {
    469489                    LONG iRc = false;
     
    474494                        rc = progress->COMGETTER(ErrorInfo)(execError.asOutParam());
    475495                        com::ErrorInfo info (execError);
    476                         RTPrintf("\n\nProcess error details:\n");
    477                         GluePrintErrorInfo(info);
    478                         RTPrintf("\n");
    479                     }
    480                     if (fVerbose)
     496                        if (SUCCEEDED(rc) && info.isFullAvailable())
     497                        {
     498                            /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
     499                             * because it contains more accurate info about what went wrong. */
     500                            if (info.getResultCode() == VBOX_E_IPRT_ERROR)
     501                            {
     502                                RTPrintf("%ls.\n", info.getText().raw());
     503                            }
     504                            else
     505                            {
     506                                RTPrintf("\n\nProcess error details:\n");
     507                                GluePrintErrorInfo(info);
     508                                RTPrintf("\n");
     509                            }
     510                        }
     511                        else
     512                            AssertMsgFailed(("Full error description is missing!\n"));
     513                    }
     514                    else if (fVerbose)
    481515                    {
    482516                        ULONG uRetStatus, uRetExitCode, uRetFlags;
    483                         CHECK_ERROR_BREAK(guest, GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus));
    484                         RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, getStatus(uRetStatus), uRetFlags);
    485                     }
    486                 }
    487                 else /* If neither canceled nor completed we got a hard abort (shouldn't happen). */
     517                        rc = guest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus);
     518                        if (SUCCEEDED(rc))
     519                            RTPrintf("Exit code=%u (Status=%u [%s], Flags=%u)\n", uRetExitCode, uRetStatus, getStatus(uRetStatus), uRetFlags);
     520                    }
     521                }
     522                else
    488523                {
    489524                    if (fVerbose)
  • trunk/src/VBox/Main/GuestImpl.cpp

    r30002 r30020  
    114114
    115115#ifdef VBOX_WITH_GUEST_CONTROL
    116     /*
    117      * Cleanup must be done *before* AutoUninitSpan to cancel all
    118      * all outstanding waits in API functions (which hold AutoCaller
    119      * ref counts).
    120      */
    121     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    122 
    123     /* Clean up callback data. */
    124     CallbackListIter it;
    125     for (it = mCallbackList.begin(); it != mCallbackList.end(); it++)
    126         destroyCtrlCallbackContext(it);
    127 
    128     /* Clear process list. */
    129     mGuestProcessList.clear();
     116    /* Scope write lock as much as possible. */
     117    {
     118        /*
     119         * Cleanup must be done *before* AutoUninitSpan to cancel all
     120         * all outstanding waits in API functions (which hold AutoCaller
     121         * ref counts).
     122         */
     123        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     124   
     125        /* Clean up callback data. */
     126        CallbackListIter it;
     127        for (it = mCallbackList.begin(); it != mCallbackList.end(); it++)
     128            destroyCtrlCallbackContext(it);
     129   
     130        /* Clear process list. */
     131        mGuestProcessList.clear();
     132    }
    130133#endif
    131134
     
    493496     * changes to the object state.
    494497     */
     498#ifdef DEBUG_andy
    495499    LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
    496500                 pvExtension, u32Function, pvParms, cbParms));
     501#endif
    497502    ComObjPtr<Guest> pGuest = reinterpret_cast<Guest *>(pvExtension);
    498503
     
    540545                                PCALLBACKDATAEXECSTATUS pData)
    541546{
    542     LogFlowFuncEnter();
    543547    int rc = VINF_SUCCESS;
    544548
     
    560564
    561565        /* Was progress canceled before? */
    562         BOOL fCancelled;
    563         it->pProgress->COMGETTER(Canceled)(&fCancelled);
    564 
    565         /* Do progress handling. */
     566        BOOL fCanceled;
     567        ComAssert(it->pProgress.isNotNull());
     568        it->pProgress->COMGETTER(Canceled)(&fCanceled);
     569
    566570        Utf8Str errMsg;
    567         HRESULT rc2 = S_OK;
    568         switch (pData->u32Status)
    569         {
    570             case PROC_STS_STARTED:
    571                 break;
    572 
    573             case PROC_STS_TEN: /* Terminated normally. */
    574                 if (   !it->pProgress->getCompleted()
    575                     && !fCancelled)
     571        if (!fCanceled)
     572        {           
     573            /* Do progress handling. */
     574            switch (pData->u32Status)
     575            {
     576                case PROC_STS_STARTED:
     577                    rc = it->pProgress->SetNextOperation(BstrFmt(tr("Waiting for process to exit ...")), 1 /* Weight */);
     578                    if (FAILED(rc))
     579                        errMsg = Utf8StrFmt(Guest::tr("Cannot enter waiting for process exit stage! rc=%u"),
     580                                            rc);
     581                    break;
     582   
     583                case PROC_STS_TEN: /* Terminated normally. */
     584                    it->pProgress->notifyComplete(S_OK);
     585                    LogFlowFunc(("Proccess (context ID=%u, status=%u) terminated successfully\n",
     586                                 pData->hdr.u32ContextID, pData->u32Status));
     587                    break;
     588   
     589                case PROC_STS_TEA: /* Terminated abnormally. */
     590                    errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
     591                                        pCBData->u32Flags);
     592                    break;
     593   
     594                case PROC_STS_TES: /* Terminated through signal. */
     595                    errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
     596                                        pCBData->u32Flags);
     597                    break;
     598   
     599                case PROC_STS_TOK:
     600                    errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
     601                    break;
     602   
     603                case PROC_STS_TOA:
     604                    errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
     605                    break;
     606   
     607                case PROC_STS_DWN:
     608                    errMsg = Utf8StrFmt(Guest::tr("Process exited because system is shutting down"));
     609                    break;
     610   
     611                case PROC_STS_ERROR:
     612                    errMsg = Utf8StrFmt(Guest::tr("Process execution failed with rc=%Rrc"), pCBData->u32Flags);
     613                    break;
     614   
     615                default:
     616                    break;
     617            }
     618           
     619            /* Handle process list. */
     620            /** @todo What happens on/deal with PID reuse? */
     621            /** @todo How to deal with multiple updates at once? */
     622            if (pCBData->u32PID > 0)
     623            {
     624                GuestProcessIter it_proc = getProcessByPID(pCBData->u32PID);
     625                if (it_proc == mGuestProcessList.end())
    576626                {
    577                     it->pProgress->notifyComplete(S_OK);
     627                    /* Not found, add to list. */
     628                    GuestProcess p;
     629                    p.mPID = pCBData->u32PID;
     630                    p.mStatus = pCBData->u32Status;
     631                    p.mExitCode = pCBData->u32Flags; /* Contains exit code. */
     632                    p.mFlags = 0;
     633       
     634                    mGuestProcessList.push_back(p);
    578635                }
    579                 break;
    580 
    581             case PROC_STS_TEA: /* Terminated abnormally. */
    582                 errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
    583                                     pCBData->u32Flags);
    584                 break;
    585 
    586             case PROC_STS_TES: /* Terminated through signal. */
    587                 errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
    588                                     pCBData->u32Flags);
    589                 break;
    590 
    591             case PROC_STS_TOK:
    592                 errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
    593                 break;
    594 
    595             case PROC_STS_TOA:
    596                 errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
    597                 break;
    598 
    599             case PROC_STS_DWN:
    600                 errMsg = Utf8StrFmt(Guest::tr("Process exited because system is shutting down"));
    601                 break;
    602 
    603             default:
    604                 break;
    605         }
    606 
    607         /* Handle process list. */
    608         /** @todo What happens on/deal with PID reuse? */
    609         /** @todo How to deal with multiple updates at once? */
    610         GuestProcessIter it_proc = getProcessByPID(pCBData->u32PID);
    611         if (it_proc == mGuestProcessList.end())
    612         {
    613             /* Not found, add to list. */
    614             GuestProcess p;
    615             p.mPID = pCBData->u32PID;
    616             p.mStatus = pCBData->u32Status;
    617             p.mExitCode = pCBData->u32Flags; /* Contains exit code. */
    618             p.mFlags = 0;
    619 
    620             mGuestProcessList.push_back(p);
    621         }
    622         else /* Update list. */
    623         {
    624             it_proc->mStatus = pCBData->u32Status;
    625             it_proc->mExitCode = pCBData->u32Flags; /* Contains exit code. */
    626             it_proc->mFlags = 0;
    627         }
    628 
    629         if (   !it->pProgress.isNull()
    630             && errMsg.length())
    631         {
    632             if (   !it->pProgress->getCompleted()
    633                 && !fCancelled)
     636                else /* Update list. */
     637                {
     638                    it_proc->mStatus = pCBData->u32Status;
     639                    it_proc->mExitCode = pCBData->u32Flags; /* Contains exit code. */
     640                    it_proc->mFlags = 0;
     641                }
     642            }
     643        }
     644        else
     645            errMsg = Utf8StrFmt(Guest::tr("Process execution canceled"));
     646       
     647        if (!it->pProgress->getCompleted())
     648        {
     649            if (   errMsg.length()
     650                || fCanceled) /* If cancelled we have to report E_FAIL! */
    634651            {
    635                 it->pProgress->notifyComplete(E_FAIL /** @todo Find a better rc! */, COM_IIDOF(IGuest),
     652                it->pProgress->notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest),
    636653                                              (CBSTR)Guest::getComponentName(), errMsg.c_str());
    637                 LogFlowFunc(("Callback (context ID=%u, status=%u) progress marked as completed\n",
    638                              pData->hdr.u32ContextID, pData->u32Status));
     654                LogFlowFunc(("Process (context ID=%u, status=%u) reported error: %s\n",
     655                             pData->hdr.u32ContextID, pData->u32Status, errMsg.c_str()));
    639656            }
    640             else
    641                 LogFlowFunc(("Callback (context ID=%u, status=%u) progress already marked as completed\n",
    642                              pData->hdr.u32ContextID, pData->u32Status));
    643         }
    644         ASMAtomicWriteBool(&it->fCalled, true);
     657        }       
    645658    }
    646659    else
    647660        LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
    648     LogFlowFuncLeave();
    649661    return rc;
    650662}
     
    654666                             PCALLBACKDATAEXECOUT pData)
    655667{
    656     LogFlowFuncEnter();
    657668    int rc = VINF_SUCCESS;
    658669
     
    663674    if (it != mCallbackList.end())
    664675    {
    665         Assert(!it->fCalled);
    666676        PCALLBACKDATAEXECOUT pCBData = (CALLBACKDATAEXECOUT*)it->pvData;
    667677        AssertPtr(pCBData);
     
    687697            pCBData->cbData = 0;
    688698        }
    689         ASMAtomicWriteBool(&it->fCalled, true);
     699
     700        /* Was progress canceled before? */
     701        BOOL fCanceled;
     702        ComAssert(it->pProgress.isNotNull());
     703        it->pProgress->COMGETTER(Canceled)(&fCanceled);
     704
     705        if (!fCanceled)
     706            it->pProgress->notifyComplete(S_OK);
     707        else
     708            it->pProgress->notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest),
     709                                          (CBSTR)Guest::getComponentName(), Guest::tr("The output operation was cancelled"));
    690710    }
    691711    else
    692712        LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
    693     LogFlowFuncLeave();
    694713    return rc;
    695714}
     
    698717                                        PCALLBACKDATACLIENTDISCONNECTED pData)
    699718{
    700     LogFlowFuncEnter();
    701719    int rc = VINF_SUCCESS;
    702720
     
    708726    {
    709727        if (it->mContextID == pData->hdr.u32ContextID)
     728        {
     729            LogFlowFunc(("Client with context ID=%u disconnected\n", it->mContextID));
    710730            destroyCtrlCallbackContext(it);
    711     }
    712 
    713     LogFlowFuncLeave();
     731        }
     732    }
    714733    return rc;
    715734}
     
    746765void Guest::destroyCtrlCallbackContext(Guest::CallbackListIter it)
    747766{
    748     LogFlowFuncEnter();
    749767    if (it->pvData)
    750768    {
     769        LogFlowFunc(("Destroying callback with context ID=%u ...\n", it->mContextID));
     770
    751771        RTMemFree(it->pvData);
    752772        it->pvData = NULL;
     
    755775
    756776    /* Notify outstanding waits for progress ... */
    757     if (it->pProgress && !it->pProgress.isNull())
    758     {
    759         /* Only cancel if not canceled before! */
    760         BOOL fCancelled;
    761         if (SUCCEEDED(it->pProgress->COMGETTER(Canceled)(&fCancelled)) && !fCancelled)
    762             it->pProgress->Cancel();
     777    if (it->pProgress && it->pProgress.isNotNull())
     778    {
     779        LogFlowFunc(("Handling progress of context ID=%u ...\n", it->mContextID));
     780
     781        BOOL fCompleted;
     782        it->pProgress->COMGETTER(Completed)(&fCompleted);
     783        if (!fCompleted)
     784        {
     785            /* Only cancel if not canceled before! */
     786            BOOL fCanceled;
     787            if (SUCCEEDED(it->pProgress->COMGETTER(Canceled)(&fCanceled)) && !fCanceled)
     788                it->pProgress->Cancel();       
     789
     790            /* To get waitForCompletion notified we have to notify it if necessary. */
     791            it->pProgress->notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest),
     792                                          (CBSTR)Guest::getComponentName(), Guest::tr("The operation was canceled during shutdown"));
     793        }       
    763794        /*
    764795         * Do *not NULL pProgress here, because waiting function like executeProcess()
     
    766797         */
    767798    }
    768     LogFlowFuncLeave();
    769799}
    770800
     
    774804uint32_t Guest::addCtrlCallbackContext(eVBoxGuestCtrlCallbackType enmType, void *pvData, uint32_t cbData, Progress *pProgress)
    775805{
    776     LogFlowFuncEnter();
     806    AssertPtr(pProgress);
    777807    uint32_t uNewContext = ASMAtomicIncU32(&mNextContextID);
    778808    if (uNewContext == UINT32_MAX)
     
    783813    context.mContextID = uNewContext;
    784814    context.mType = enmType;
    785     context.fCalled = false;
    786815    context.pvData = pvData;
    787816    context.cbData = cbData;
     
    807836    }
    808837#endif
    809 
    810     LogFlowFuncLeave();
    811838    return uNewContext;
    812839}
     
    844871    {
    845872        /*
    846          * Create progress object.
     873         * Create progress object.  Note that this is a multi operation
     874         * object to perform the following steps:
     875         * - Operation 1 (0): Create/start process.
     876         * - Operation 2 (1): Wait for process to exit.
     877         * If this progress completed successfully (S_OK), the process
     878         * started and exited normally. In any other case an error/exception
     879         * occured.
    847880         */
    848881        ComObjPtr <Progress> progress;
     
    852885            rc = progress->init(static_cast<IGuest*>(this),
    853886                                BstrFmt(tr("Executing process")),
    854                                 TRUE);
     887                                TRUE,
     888                                2,                                      /* Number of operations. */
     889                                BstrFmt(tr("Starting process ...")));   /* Description of first stage. */
    855890        }
    856891        if (FAILED(rc)) return rc;
     
    919954                    PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
    920955                    AssertReturn(pData, VBOX_E_IPRT_ERROR);
     956                    RT_ZERO(*pData);
    921957                    uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START,
    922958                                                        pData, sizeof(CALLBACKDATAEXECSTATUS), progress);
     
    9741010                if (it != mCallbackList.end())
    9751011                {
    976                     uint64_t u64Started = RTTimeMilliTS();
    977                     while (!it->fCalled)
     1012                    ComAssert(it->pProgress.isNotNull());
     1013
     1014                    /*
     1015                     * Wait for the first stage (=0) to complete (that is starting the process).
     1016                     */
     1017                    PCALLBACKDATAEXECSTATUS pData = NULL;
     1018                    rc = it->pProgress->WaitForOperationCompletion(0, aTimeoutMS);
     1019                    if (SUCCEEDED(rc))
    9781020                    {
    979                         /* Check for timeout. */
    980                         unsigned cMsWait;
    981                         if (aTimeoutMS == RT_INDEFINITE_WAIT)
    982                             cMsWait = 10;
    983                         else
     1021                        /* Was the operation canceled by one of the parties? */
     1022                        rc = it->pProgress->COMGETTER(Canceled)(&fCanceled);
     1023                        if (FAILED(rc)) throw rc;
     1024
     1025                        if (!fCanceled)
    9841026                        {
    985                             uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
    986                             if (cMsElapsed >= aTimeoutMS)
    987                                 break; /* Timed out. */
    988                             cMsWait = RT_MIN(10, aTimeoutMS - (uint32_t)cMsElapsed);
     1027                            AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     1028   
     1029                            pData = (PCALLBACKDATAEXECSTATUS)it->pvData;
     1030                            Assert(it->cbData == sizeof(CALLBACKDATAEXECSTATUS));
     1031                            AssertPtr(pData);
     1032   
     1033                            /* Did we get some status? */
     1034                            switch (pData->u32Status)
     1035                            {
     1036                                case PROC_STS_STARTED:
     1037                                    /* Process is (still) running; get PID. */
     1038                                    *aPID = pData->u32PID;
     1039                                    break;
     1040       
     1041                                /* In any other case the process either already
     1042                                 * terminated or something else went wrong, so no PID ... */
     1043                                case PROC_STS_TEN: /* Terminated normally. */
     1044                                case PROC_STS_TEA: /* Terminated abnormally. */
     1045                                case PROC_STS_TES: /* Terminated through signal. */
     1046                                case PROC_STS_TOK:
     1047                                case PROC_STS_TOA:
     1048                                case PROC_STS_DWN:
     1049                                    /*
     1050                                     * Process (already) ended, but we want to get the
     1051                                     * PID anyway to retrieve the output in a later call.
     1052                                     */
     1053                                    *aPID = pData->u32PID;
     1054                                    break;
     1055       
     1056                                case PROC_STS_ERROR:
     1057                                    vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */
     1058                                    break;
     1059       
     1060                                case PROC_STS_UNDEFINED:
     1061                                    vrc = VERR_TIMEOUT;    /* Operation did not complete within time. */
     1062                                    break;
     1063
     1064                                default:
     1065                                    vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */
     1066                                    break;
     1067                            }
    9891068                        }
    990 
    991                         /* Check for manual stop. */
    992                         if (!it->pProgress.isNull())
    993                         {
    994                             rc = it->pProgress->COMGETTER(Canceled)(&fCanceled);
    995                             if (FAILED(rc)) throw rc;
    996                             if (fCanceled)
    997                                 break; /* HGCM/guest wants to abort because of status change. */
    998 
    999                         }
    1000                         /// @todo r=bird: two operation progress object and wait first operation.
    1001                         /// IProgress::WaitForOperationCompletion.
    1002                         RTThreadSleep(cMsWait);
     1069                        else /* Operation was canceled. */
     1070                            vrc = VERR_CANCELLED;
    10031071                    }
    1004                 }
    1005 
    1006                 /* Was the whole thing canceled? */
    1007                 if (!fCanceled)
    1008                 {
    1009                     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1010 
    1011                     PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)it->pvData;
    1012                     Assert(it->cbData == sizeof(CALLBACKDATAEXECSTATUS));
    1013                     AssertPtr(pData);
    1014 
    1015                     if (it->fCalled)
    1016                     {
    1017                         /* Did we get some status? */
    1018                         switch (pData->u32Status)
    1019                         {
    1020                             case PROC_STS_STARTED:
    1021                                 /* Process is (still) running; get PID. */
    1022                                 *aPID = pData->u32PID;
    1023                                 break;
    1024 
    1025                             /* In any other case the process either already
    1026                              * terminated or something else went wrong, so no PID ... */
    1027                             case PROC_STS_TEN: /* Terminated normally. */
    1028                             case PROC_STS_TEA: /* Terminated abnormally. */
    1029                             case PROC_STS_TES: /* Terminated through signal. */
    1030                             case PROC_STS_TOK:
    1031                             case PROC_STS_TOA:
    1032                             case PROC_STS_DWN:
    1033                                 /*
    1034                                  * Process (already) ended, but we want to get the
    1035                                  * PID anyway to retrieve the output in a later call.
    1036                                  */
    1037                                 *aPID = pData->u32PID;
    1038                                 break;
    1039 
    1040                             case PROC_STS_ERROR:
    1041                                 vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */
    1042                                 break;
    1043 
    1044                             default:
    1045                                 vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */
    1046                                 break;
    1047                         }
    1048                     }
    1049                     else /* If callback not called within time ... well, that's a timeout! */
     1072                    else /* Operation did not complete within time. */
    10501073                        vrc = VERR_TIMEOUT;
    1051 
    1052                      /*
     1074   
     1075                    /*
    10531076                     * Do *not* remove the callback yet - we might wait with the IProgress object on something
    10541077                     * else (like end of process) ...
     
    10811104                                          tr("The guest did not respond within time (%ums)"), aTimeoutMS);
    10821105                        }
     1106                        else if (vrc == VERR_CANCELLED)
     1107                        {
     1108                            rc = setError(VBOX_E_IPRT_ERROR,
     1109                                          tr("The execution operation was canceled"));
     1110                        }
    10831111                        else if (vrc == VERR_PERMISSION_DENIED)
    10841112                        {
     
    10881116                        else
    10891117                        {
    1090                             if (pData->u32Status == PROC_STS_ERROR)
     1118                            if (pData && pData->u32Status == PROC_STS_ERROR)
    10911119                                rc = setError(VBOX_E_IPRT_ERROR,
    10921120                                              tr("Process could not be started: %Rrc"), pData->u32Flags);
     
    10941122                                rc = setError(E_UNEXPECTED,
    10951123                                              tr("The service call failed with error %Rrc"), vrc);
    1096                         }
     1124                        }               
    10971125                    }
    10981126                    else /* Execution went fine. */
     
    11021130                    }
    11031131                }
    1104                 else /* Operation was canceled. */
    1105                 {
    1106                     rc = setError(VBOX_E_IPRT_ERROR,
    1107                                   tr("The operation was canceled"));
    1108                 }
     1132                else /* Callback context not found; should never happen! */
     1133                    AssertMsg(it != mCallbackList.end(), ("Callback context with ID %u not found!", uContextID));
    11091134            }
    11101135            else /* HGCM related error codes .*/
     
    11631188        /*
    11641189         * Create progress object.
    1165          * Note that we need at least a local progress object here in order
    1166          * to get notified when someone cancels the operation.
     1190         * This progress object, compared to the one in executeProgress() above,
     1191         * is only local and is used to determine whether the operation finished
     1192         * or got cancelled.
    11671193         */
    11681194        ComObjPtr <Progress> progress;
     
    11831209        PCALLBACKDATAEXECOUT pData = (CALLBACKDATAEXECOUT*)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT));
    11841210        AssertReturn(pData, VBOX_E_IPRT_ERROR);
     1211        RT_ZERO(*pData);
    11851212        uint32_t uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT,
    11861213                                                     pData, sizeof(CALLBACKDATAEXECOUT), progress);
     
    12321259            if (it != mCallbackList.end())
    12331260            {
    1234                 uint64_t u64Started = RTTimeMilliTS();
    1235                 while (!it->fCalled)
    1236                 {
    1237                     /* Check for timeout. */
    1238                     unsigned cMsWait;
    1239                     if (aTimeoutMS == RT_INDEFINITE_WAIT)
    1240                         cMsWait = 10;
    1241                     else
    1242                     {
    1243                         uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
    1244                         if (cMsElapsed >= aTimeoutMS)
    1245                             break; /* Timed out. */
    1246                         cMsWait = RT_MIN(10, aTimeoutMS - (uint32_t)cMsElapsed);
    1247                     }
    1248 
    1249                     /* Check for manual stop. */
    1250                     if (!it->pProgress.isNull())
    1251                     {
    1252                         rc = it->pProgress->COMGETTER(Canceled)(&fCanceled);
    1253                         if (FAILED(rc)) throw rc;
    1254                         if (fCanceled)
    1255                             break; /* Client wants to abort. */
    1256                     }
    1257                     RTThreadSleep(cMsWait);
    1258                 }
    1259 
    1260                 /* Was the whole thing canceled? */
     1261                ComAssert(it->pProgress.isNotNull());
     1262
     1263                /* Wait until operation completed. */
     1264                rc = it->pProgress->WaitForCompletion(aTimeoutMS);
     1265                if (FAILED(rc)) throw rc;
     1266               
     1267                /* Was the operation canceled by one of the parties? */
     1268                rc = it->pProgress->COMGETTER(Canceled)(&fCanceled);
     1269                if (FAILED(rc)) throw rc;
     1270
    12611271                if (!fCanceled)
    12621272                {
    1263                     if (it->fCalled)
     1273                    BOOL fCompleted;
     1274                    if (   SUCCEEDED(it->pProgress->COMGETTER(Completed)(&fCompleted))
     1275                        && fCompleted)
    12641276                    {
    12651277                        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     
    12871299                }
    12881300                else /* Operation was canceled. */
     1301                {
    12891302                    vrc = VERR_CANCELLED;
     1303                }
    12901304
    12911305                if (RT_FAILURE(vrc))
     
    12941308                    {
    12951309                        /* This is not an error we want to report to COM. */
     1310                        rc = NO_ERROR;
    12961311                    }
    12971312                    else if (vrc == VERR_TIMEOUT)
     
    13031318                    {
    13041319                        rc = setError(VBOX_E_IPRT_ERROR,
    1305                                       tr("The operation was canceled"));
     1320                                      tr("The output operation was canceled"));
    13061321                    }
    13071322                    else
     
    13161331                    destroyCtrlCallbackContext(it);
    13171332                }
     1333
     1334                /* Remove callback context (not used anymore). */
     1335                mCallbackList.erase(it);
    13181336            }
    13191337            else /* PID lookup failed. */
  • trunk/src/VBox/Main/include/GuestImpl.h

    r29785 r30020  
    122122    struct CallbackContext
    123123    {
     124        /** Associated context ID. */
    124125        uint32_t                    mContextID;
    125126        eVBoxGuestCtrlCallbackType  mType;
     127        /** Pointer to user-supplied data. */       
    126128        void                       *pvData;
     129        /** Size of user-supplied data. */
    127130        uint32_t                    cbData;
    128         /** Atomic flag whether callback was called. */
    129         volatile bool               fCalled;
    130131        /** Pointer to user-supplied IProgress. */
    131132        ComObjPtr<Progress>         pProgress;
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette