VirtualBox

Changeset 74804 in vbox for trunk


Ignore:
Timestamp:
Oct 12, 2018 3:09:44 PM (6 years ago)
Author:
vboxsync
Message:

Main/Progress: Split into safe public interface and a private one which is used purely by API implementation code (for updating). Needed quite a few minor adjustments elsewhere.

Location:
trunk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/ExtPack/ExtPack.h

    r74219 r74804  
    281281     * @param   pProgressOther  Pointer to an IProgress object reference, the one
    282282     *                          to be waited for.
     283     * @param   cTimeoutMS      Timeout in milliseconds, 0 for indefinite wait.
    283284     */
    284285    DECLR3CALLBACKMEMBER(uint32_t, pfnWaitOtherProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
    285                                                          VBOXEXTPACK_IF_CS(IProgress) *pProgressOther));
     286                                                         VBOXEXTPACK_IF_CS(IProgress) *pProgressOther,
     287                                                         uint32_t cTimeoutMS));
    286288
    287289    /**
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r74778 r74804  
    1426914269  <interface
    1427014270    name="IProgress" extends="$unknown"
    14271     uuid="64c7fb5c-ce8f-4681-9c8c-d523cb4dea3d"
     14271    uuid="d3ee3588-a762-4ba1-9e9e-23146587ed3a"
    1427214272    wsmap="managed"
    14273     reservedMethods="1" reservedAttributes="2"
     14273    wrap-hint-server-addinterfaces="IInternalProgressControl"
     14274    reservedMethods="4" reservedAttributes="8"
    1427414275    >
    1427514276    <desc>
     
    1440814409    <attribute name="eventSource" type="IEventSource" readonly="yes"/>
    1440914410
    14410     <method name="setCurrentOperationProgress">
    14411       <desc>Internal method, not to be called externally.</desc>
    14412       <param name="percent" type="unsigned long" dir="in" />
    14413     </method>
    14414     <method name="setNextOperation">
    14415       <desc>Internal method, not to be called externally.</desc>
    14416       <param name="nextOperationDescription" type="wstring" dir="in" />
    14417       <param name="nextOperationsWeight" type="unsigned long" dir="in" />
    14418     </method>
    14419 
    1442014411    <method name="waitForCompletion">
    1442114412      <desc>
     
    1448014471
    1448114472      </desc>
     14473    </method>
     14474
     14475  </interface>
     14476
     14477  <interface
     14478    name="IInternalProgressControl" extends="$unknown"
     14479    uuid="9bf38c56-ac64-4f72-871a-321a25f52a57"
     14480    internal="yes"
     14481    wsmap="suppress"
     14482    reservedMethods="4" reservedAttributes="8"
     14483    >
     14484
     14485    <method name="setCurrentOperationProgress">
     14486      <desc>Internal method, not to be called externally.</desc>
     14487      <param name="percent" type="unsigned long" dir="in" />
     14488    </method>
     14489
     14490    <method name="waitForOtherProgressCompletion">
     14491      <desc>
     14492        Internal method, not to be called externally.
     14493
     14494        Waits until the other task is completed (including all sub-operations)
     14495        and forward all changes from the other progress to this progress. This
     14496        means sub-operation number, description, percent and so on.
     14497
     14498        The caller is responsible for having at least the same count of
     14499        sub-operations in this progress object as there are in the other
     14500        progress object.
     14501
     14502        If the other progress object supports cancel and this object gets any
     14503        cancel request (when here enabled as well), it will be forwarded to
     14504        the other progress object.
     14505
     14506        Error information is automatically preserved (by transferring it to
     14507        the current thread's error information). If the caller wants to set it
     14508        as the completion state of this progress it needs to be done separately.
     14509
     14510        <result name="VBOX_E_TIMEOUT">
     14511          Waiting time has expired.
     14512        </result>
     14513      </desc>
     14514      <param name="progressOther" type="IProgress" dir="in" />
     14515      <param name="timeoutMS" type="unsigned long" dir="in">
     14516        <desc>Timeout (in ms). Pass 0 for an infinite timeout.</desc>
     14517      </param>
     14518    </method>
     14519
     14520    <method name="setNextOperation">
     14521      <desc>Internal method, not to be called externally.</desc>
     14522      <param name="nextOperationDescription" type="wstring" dir="in" />
     14523      <param name="nextOperationsWeight" type="unsigned long" dir="in" />
     14524    </method>
     14525
     14526    <method name="notifyPointOfNoReturn">
     14527      <desc>Internal method, not to be called externally.</desc>
     14528    </method>
     14529
     14530    <method name="notifyComplete">
     14531      <desc>Internal method, not to be called externally.</desc>
     14532      <param name="resultCode" type="long" dir="in" />
     14533      <param name="errorInfo" type="IVirtualBoxErrorInfo" dir="in" />
    1448214534    </method>
    1448314535
  • trunk/src/VBox/Main/include/ExtPackManagerImpl.h

    r74219 r74804  
    163163                                                             uint32_t uNextOperationWeight);
    164164    static DECLCALLBACK(uint32_t) i_hlpWaitOtherProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
    165                                                          VBOXEXTPACK_IF_CS(IProgress) *pProgressOther);
     165                                                         VBOXEXTPACK_IF_CS(IProgress) *pProgressOther,
     166                                                         uint32_t cTimeoutMS);
    166167    static DECLCALLBACK(uint32_t) i_hlpCompleteProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
    167168                                                        uint32_t uResultCode);
  • trunk/src/VBox/Main/include/ProgressImpl.h

    r73824 r74804  
    136136                              const char *aText,
    137137                              va_list va);
    138     HRESULT i_notifyCompleteEI(HRESULT aResultCode,
    139                                const ComPtr<IVirtualBoxErrorInfo> &aErrorInfo);
    140     /**
    141      * Waits until the other task is completed (including all sub-operations)
    142      * and forward all changes from the other progress to this progress. This
    143      * means sub-operation number, description, percent and so on.
    144      *
    145      * The caller is responsible for having at least the same count of
    146      * sub-operations in this progress object as there are in the other
    147      * progress object.
    148      *
    149      * If the other progress object supports cancel and this object gets any
    150      * cancel request (when here enabled as well), it will be forwarded to
    151      * the other progress object.
    152      *
    153      * Error information is automatically preserved (by transferring it to
    154      * the current thread's error information). If the caller wants to set it
    155      * as the completion state of this progress it needs to be done separately.
    156      *
    157      * @param   aProgressOther  Progress object from which the state is
    158      *                  forwarded until it is signalling completion.
    159      * @return COM error status, also reflecting the failed completion.
    160      */
    161     HRESULT i_waitForOtherProgressCompletion(const ComPtr<IProgress> &aProgressOther);
    162 
    163     bool i_notifyPointOfNoReturn(void);
     138
    164139    bool i_setCancelCallback(void (*pfnCallback)(void *), void *pvUser);
    165140
     
    229204
    230205    // wrapped IProgress methods
    231     HRESULT setCurrentOperationProgress(ULONG aPercent);
    232     HRESULT setNextOperation(const com::Utf8Str &aNextOperationDescription,
    233                              ULONG aNextOperationsWeight);
    234206    HRESULT waitForCompletion(LONG aTimeout);
    235207    HRESULT waitForOperationCompletion(ULONG aOperation,
     
    237209    HRESULT cancel();
    238210
     211    // wrapped IInternalProgressControl methods
     212    HRESULT setCurrentOperationProgress(ULONG aPercent);
     213    HRESULT waitForOtherProgressCompletion(const ComPtr<IProgress> &aProgressOther,
     214                                           ULONG aTimeoutMS);
     215    HRESULT setNextOperation(const com::Utf8Str &aNextOperationDescription,
     216                             ULONG aNextOperationsWeight);
     217    HRESULT notifyPointOfNoReturn();
     218    HRESULT notifyComplete(LONG aResultCode,
     219                           const ComPtr<IVirtualBoxErrorInfo> &aErrorInfo);
     220
    239221    // internal helper methods
    240222    double i_calcTotalPercent();
  • trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp

    r74219 r74804  
    18101810    AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
    18111811
    1812     return pProgress->SetCurrentOperationProgress(uPercent);
     1812    ComPtr<IInternalProgressControl> pProgressControl(pProgress);
     1813    AssertReturn(!!pProgressControl, E_INVALIDARG);
     1814    return pProgressControl->SetCurrentOperationProgress(uPercent);
    18131815}
    18141816
     
    18281830    AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
    18291831
    1830     return pProgress->SetNextOperation(Bstr(pcszNextOperationDescription).raw(), uNextOperationWeight);
     1832    ComPtr<IInternalProgressControl> pProgressControl(pProgress);
     1833    AssertReturn(!!pProgressControl, E_INVALIDARG);
     1834    return pProgressControl->SetNextOperation(Bstr(pcszNextOperationDescription).raw(), uNextOperationWeight);
    18311835}
    18321836
    18331837/*static*/ DECLCALLBACK(uint32_t)
    18341838ExtPack::i_hlpWaitOtherProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
    1835                                 VBOXEXTPACK_IF_CS(IProgress) *pProgressOther)
     1839                                VBOXEXTPACK_IF_CS(IProgress) *pProgressOther, uint32_t cTimeoutMS)
    18361840{
    18371841    /*
     
    18441848    AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
    18451849
    1846     Progress *pProgressInt = static_cast<Progress *>(pProgress);
    1847     return pProgressInt->i_waitForOtherProgressCompletion(pProgressOther);
     1850    ComPtr<IInternalProgressControl> pProgressControl(pProgress);
     1851    AssertReturn(!!pProgressControl, E_INVALIDARG);
     1852    return pProgressControl->WaitForOtherProgressCompletion(pProgressOther, cTimeoutMS);
    18481853}
    18491854
     
    18601865    AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
    18611866
    1862     Progress *pProgressInt = static_cast<Progress *>(pProgress);
    1863     return pProgressInt->i_notifyComplete(uResultCode);
     1867    ComPtr<IInternalProgressControl> pProgressControl(pProgress);
     1868    AssertReturn(!!pProgressControl, E_INVALIDARG);
     1869
     1870    ComPtr<IVirtualBoxErrorInfo> errorInfo;
     1871    if (FAILED((HRESULT)uResultCode))
     1872    {
     1873        ErrorInfoKeeper eik;
     1874        eik.getVirtualBoxErrorInfo(errorInfo);
     1875    }
     1876    return pProgressControl->NotifyComplete(uResultCode, errorInfo);
    18641877}
    18651878
  • trunk/src/VBox/Main/src-all/ProgressImpl.cpp

    r74759 r74804  
    370370    }
    371371
    372     return i_notifyCompleteEI(aResultCode, errorInfo);
     372    return notifyComplete(aResultCode, errorInfo);
    373373}
    374374
     
    414414    errorInfo->init(aResultCode, aIID, pcszComponent, text);
    415415
    416     return i_notifyCompleteEI(aResultCode, errorInfo);
    417 }
    418 
    419 /**
    420  * Marks the operation as complete and attaches full error info.
    421  *
    422  * This is where the actual work is done, the related methods all end up here.
    423  *
    424  * @param aResultCode   Operation result (error) code, must not be S_OK.
    425  * @param aErrorInfo            List of arguments for the format string.
    426  */
    427 HRESULT Progress::i_notifyCompleteEI(HRESULT aResultCode, const ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
    428 {
    429     LogThisFunc(("aResultCode=%d\n", aResultCode));
    430     /* on failure we expect error info, on success there must be none */
    431     AssertMsg(FAILED(aResultCode) ^ aErrorInfo.isNull(),
    432               ("No error info but trying to set a failed result (%08X)!\n",
    433                aResultCode));
    434 
     416    return notifyComplete(aResultCode, errorInfo);
     417}
     418
     419/**
     420 * Sets the cancelation callback, checking for cancelation first.
     421 *
     422 * @returns Success indicator.
     423 * @retval  true on success.
     424 * @retval  false if the progress object has already been canceled or is in an
     425 *          invalid state
     426 *
     427 * @param   pfnCallback     The function to be called upon cancelation.
     428 * @param   pvUser          The callback argument.
     429 */
     430bool Progress::i_setCancelCallback(void (*pfnCallback)(void *), void *pvUser)
     431{
    435432    AutoCaller autoCaller(this);
    436     AssertComRCReturnRC(autoCaller.rc());
     433    AssertComRCReturn(autoCaller.rc(), false);
    437434
    438435    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    439436
    440     AssertReturn(mCompleted == FALSE, E_FAIL);
    441 
    442     if (mCanceled && SUCCEEDED(aResultCode))
    443         aResultCode = E_FAIL;
    444 
    445     mCompleted = TRUE;
    446     mResultCode = aResultCode;
    447     if (SUCCEEDED(aResultCode))
    448     {
    449         m_ulCurrentOperation = m_cOperations - 1; /* last operation */
    450         m_ulOperationPercent = 100;
    451     }
    452     mErrorInfo = aErrorInfo;
    453 
     437    i_checkForAutomaticTimeout();
     438    if (mCanceled)
     439        return false;
     440
     441    m_pvCancelUserArg   = pvUser;
     442    m_pfnCancelCallback = pfnCallback;
     443    return true;
     444}
     445
     446/**
     447 * @callback_method_impl{FNRTPROGRESS,
     448 *      Works the progress of the current operation.}
     449 */
     450/*static*/ DECLCALLBACK(int) Progress::i_iprtProgressCallback(unsigned uPercentage, void *pvUser)
     451{
     452    Progress *pThis = (Progress *)pvUser;
     453
     454    /*
     455     * Same as setCurrentOperationProgress, except we don't fail on mCompleted.
     456     */
     457    AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
     458    int vrc = VINF_SUCCESS;
     459    if (!pThis->mCompleted)
     460    {
     461        pThis->i_checkForAutomaticTimeout();
     462        if (!pThis->mCanceled)
     463        {
     464            if (uPercentage > pThis->m_ulOperationPercent)
     465                pThis->setCurrentOperationProgress(uPercentage);
     466        }
     467        else
     468        {
     469            Assert(pThis->mCancelable);
     470            vrc = VERR_CANCELLED;
     471        }
     472    }
     473    /* else ignored */
     474    return vrc;
     475}
     476
     477/**
     478 * @callback_method_impl{FNVDPROGRESS,
     479 *      Progress::i_iprtProgressCallback with parameters switched around.}
     480 */
     481/*static*/ DECLCALLBACK(int) Progress::i_vdProgressCallback(void *pvUser, unsigned uPercentage)
     482{
     483    return i_iprtProgressCallback(uPercentage, pvUser);
     484}
     485
     486
     487// IProgress properties
     488/////////////////////////////////////////////////////////////////////////////
     489
     490HRESULT Progress::getId(com::Guid &aId)
     491{
     492    /* mId is constant during life time, no need to lock */
     493    aId = mId;
     494
     495    return S_OK;
     496}
     497
     498HRESULT Progress::getDescription(com::Utf8Str &aDescription)
     499{
     500    /* mDescription is constant during life time, no need to lock */
     501    aDescription = mDescription;
     502
     503    return S_OK;
     504}
     505HRESULT Progress::getInitiator(ComPtr<IUnknown> &aInitiator)
     506{
     507    /* mInitiator/mParent are constant during life time, no need to lock */
    454508#if !defined(VBOX_COM_INPROC)
    455     /* remove from the global collection of pending progress operations */
    456     if (mParent)
    457         mParent->i_removeProgress(mId.ref());
     509    if (mInitiator)
     510        mInitiator.queryInterfaceTo(aInitiator.asOutParam());
     511    else
     512    {
     513        ComObjPtr<VirtualBox> pVirtualBox(mParent);
     514        pVirtualBox.queryInterfaceTo(aInitiator.asOutParam());
     515    }
     516#else
     517    mInitiator.queryInterfaceTo(aInitiator.asOutParam());
    458518#endif
    459519
    460     /* wake up all waiting threads */
    461     if (mWaitersCount > 0)
    462         RTSemEventMultiSignal(mCompletedSem);
    463 
    464     fireProgressTaskCompletedEvent(pEventSource, mId.toUtf16().raw());
    465 
    466     return S_OK;
    467 }
    468 
    469 HRESULT Progress::i_waitForOtherProgressCompletion(const ComPtr<IProgress> &aProgressOther)
     520    return S_OK;
     521}
     522
     523HRESULT Progress::getCancelable(BOOL *aCancelable)
     524{
     525    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     526
     527    *aCancelable = mCancelable;
     528
     529    return S_OK;
     530}
     531
     532HRESULT Progress::getPercent(ULONG *aPercent)
     533{
     534    /* i_checkForAutomaticTimeout requires a write lock. */
     535    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     536
     537    if (mCompleted && SUCCEEDED(mResultCode))
     538        *aPercent = 100;
     539    else
     540    {
     541        ULONG ulPercent = (ULONG)i_calcTotalPercent();
     542        // do not report 100% until we're really really done with everything
     543        // as the Qt GUI dismisses progress dialogs in that case
     544        if (    ulPercent == 100
     545             && (    m_ulOperationPercent < 100
     546                  || (m_ulCurrentOperation < m_cOperations -1)
     547                )
     548           )
     549            *aPercent = 99;
     550        else
     551            *aPercent = ulPercent;
     552    }
     553
     554    i_checkForAutomaticTimeout();
     555
     556    return S_OK;
     557}
     558
     559HRESULT Progress::getTimeRemaining(LONG *aTimeRemaining)
     560{
     561    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     562
     563    if (mCompleted)
     564        *aTimeRemaining = 0;
     565    else
     566    {
     567        double dPercentDone = i_calcTotalPercent();
     568        if (dPercentDone < 1)
     569            *aTimeRemaining = -1;       // unreliable, or avoid division by 0 below
     570        else
     571        {
     572            uint64_t ullTimeNow = RTTimeMilliTS();
     573            uint64_t ullTimeElapsed = ullTimeNow - m_ullTimestamp;
     574            uint64_t ullTimeTotal = (uint64_t)((double)ullTimeElapsed * 100 / dPercentDone);
     575            uint64_t ullTimeRemaining = ullTimeTotal - ullTimeElapsed;
     576
     577//          LogFunc(("dPercentDone = %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n",
     578//                   (uint32_t)dPercentDone, ullTimeNow, ullTimeElapsed, ullTimeTotal, ullTimeRemaining));
     579
     580            *aTimeRemaining = (LONG)(ullTimeRemaining / 1000);
     581        }
     582    }
     583
     584    return S_OK;
     585}
     586
     587HRESULT Progress::getCompleted(BOOL *aCompleted)
     588{
     589    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     590
     591    *aCompleted = mCompleted;
     592
     593    return S_OK;
     594}
     595
     596HRESULT Progress::getCanceled(BOOL *aCanceled)
     597{
     598    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     599
     600    *aCanceled = mCanceled;
     601
     602    return S_OK;
     603}
     604
     605HRESULT Progress::getResultCode(LONG *aResultCode)
     606{
     607    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     608
     609    if (!mCompleted)
     610        return setError(E_FAIL, tr("Result code is not available, operation is still in progress"));
     611
     612    *aResultCode = mResultCode;
     613
     614    return S_OK;
     615}
     616
     617HRESULT Progress::getErrorInfo(ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
     618{
     619    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     620
     621    if (!mCompleted)
     622        return setError(E_FAIL, tr("Error info is not available, operation is still in progress"));
     623
     624    mErrorInfo.queryInterfaceTo(aErrorInfo.asOutParam());
     625
     626    return S_OK;
     627}
     628
     629HRESULT Progress::getOperationCount(ULONG *aOperationCount)
     630{
     631    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     632
     633    *aOperationCount = m_cOperations;
     634
     635    return S_OK;
     636}
     637
     638HRESULT Progress::getOperation(ULONG *aOperation)
     639{
     640    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     641
     642    *aOperation = m_ulCurrentOperation;
     643
     644    return S_OK;
     645}
     646
     647HRESULT Progress::getOperationDescription(com::Utf8Str &aOperationDescription)
     648{
     649    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     650
     651    aOperationDescription = m_operationDescription;
     652
     653    return S_OK;
     654}
     655
     656HRESULT Progress::getOperationPercent(ULONG *aOperationPercent)
     657{
     658    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     659
     660    if (mCompleted && SUCCEEDED(mResultCode))
     661        *aOperationPercent = 100;
     662    else
     663        *aOperationPercent = m_ulOperationPercent;
     664
     665    return S_OK;
     666}
     667
     668HRESULT Progress::getOperationWeight(ULONG *aOperationWeight)
     669{
     670    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     671
     672    *aOperationWeight = m_ulCurrentOperationWeight;
     673
     674    return S_OK;
     675}
     676
     677HRESULT Progress::getTimeout(ULONG *aTimeout)
     678{
     679    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     680
     681    *aTimeout = m_cMsTimeout;
     682
     683    return S_OK;
     684}
     685
     686HRESULT Progress::setTimeout(ULONG aTimeout)
     687{
     688    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     689
     690    if (!mCancelable)
     691        return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled"));
     692    m_cMsTimeout = aTimeout;
     693
     694    return S_OK;
     695}
     696
     697HRESULT Progress::getEventSource(ComPtr<IEventSource> &aEventSource)
     698{
     699    /* event source is const, no need to lock */
     700    pEventSource.queryInterfaceTo(aEventSource.asOutParam());
     701    return S_OK;
     702}
     703
     704
     705// IProgress methods
     706/////////////////////////////////////////////////////////////////////////////
     707
     708/**
     709 * @note XPCOM: when this method is not called on the main XPCOM thread, it
     710 *       simply blocks the thread until mCompletedSem is signalled. If the
     711 *       thread has its own event queue (hmm, what for?) that it must run, then
     712 *       calling this method will definitely freeze event processing.
     713 */
     714HRESULT Progress::waitForCompletion(LONG aTimeout)
     715{
     716    LogFlowThisFuncEnter();
     717    LogFlowThisFunc(("aTimeout=%d\n", aTimeout));
     718
     719    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     720
     721    /* if we're already completed, take a shortcut */
     722    if (!mCompleted)
     723    {
     724        int vrc = VINF_SUCCESS;
     725        bool fForever = aTimeout < 0;
     726        int64_t timeLeft = aTimeout;
     727        int64_t lastTime = RTTimeMilliTS();
     728
     729        while (!mCompleted && (fForever || timeLeft > 0))
     730        {
     731            mWaitersCount++;
     732            alock.release();
     733            vrc = RTSemEventMultiWait(mCompletedSem,
     734                                      fForever ? RT_INDEFINITE_WAIT : (RTMSINTERVAL)timeLeft);
     735            alock.acquire();
     736            mWaitersCount--;
     737
     738            /* the last waiter resets the semaphore */
     739            if (mWaitersCount == 0)
     740                RTSemEventMultiReset(mCompletedSem);
     741
     742            if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
     743                break;
     744
     745            if (!fForever)
     746            {
     747                int64_t now = RTTimeMilliTS();
     748                timeLeft -= now - lastTime;
     749                lastTime = now;
     750            }
     751        }
     752
     753        if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
     754            return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to wait for the task completion (%Rrc)"), vrc);
     755    }
     756
     757    LogFlowThisFuncLeave();
     758
     759    return S_OK;
     760}
     761
     762/**
     763 * @note XPCOM: when this method is not called on the main XPCOM thread, it
     764 *       simply blocks the thread until mCompletedSem is signalled. If the
     765 *       thread has its own event queue (hmm, what for?) that it must run, then
     766 *       calling this method will definitely freeze event processing.
     767 */
     768HRESULT Progress::waitForOperationCompletion(ULONG aOperation, LONG aTimeout)
     769
     770{
     771    LogFlowThisFuncEnter();
     772    LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout));
     773
     774    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     775
     776    CheckComArgExpr(aOperation, aOperation < m_cOperations);
     777
     778    /* if we're already completed or if the given operation is already done,
     779     * then take a shortcut */
     780    if (    !mCompleted
     781         && aOperation >= m_ulCurrentOperation)
     782    {
     783        int vrc = VINF_SUCCESS;
     784        bool fForever = aTimeout < 0;
     785        int64_t timeLeft = aTimeout;
     786        int64_t lastTime = RTTimeMilliTS();
     787
     788        while (    !mCompleted && aOperation >= m_ulCurrentOperation
     789                && (fForever || timeLeft > 0))
     790        {
     791            mWaitersCount ++;
     792            alock.release();
     793            vrc = RTSemEventMultiWait(mCompletedSem,
     794                                      fForever ? RT_INDEFINITE_WAIT : (unsigned) timeLeft);
     795            alock.acquire();
     796            mWaitersCount--;
     797
     798            /* the last waiter resets the semaphore */
     799            if (mWaitersCount == 0)
     800                RTSemEventMultiReset(mCompletedSem);
     801
     802            if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
     803                break;
     804
     805            if (!fForever)
     806            {
     807                int64_t now = RTTimeMilliTS();
     808                timeLeft -= now - lastTime;
     809                lastTime = now;
     810            }
     811        }
     812
     813        if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
     814            return setErrorBoth(E_FAIL, vrc, tr("Failed to wait for the operation completion (%Rrc)"), vrc);
     815    }
     816
     817    LogFlowThisFuncLeave();
     818
     819    return S_OK;
     820}
     821
     822HRESULT Progress::cancel()
     823{
     824    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     825
     826    if (!mCancelable)
     827        return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled"));
     828
     829    if (!mCanceled)
     830    {
     831        LogThisFunc(("Canceling\n"));
     832        mCanceled = TRUE;
     833        if (m_pfnCancelCallback)
     834            m_pfnCancelCallback(m_pvCancelUserArg);
     835
     836    }
     837    else
     838        LogThisFunc(("Already canceled\n"));
     839
     840    return S_OK;
     841}
     842
     843
     844// IInternalProgressControl methods
     845/////////////////////////////////////////////////////////////////////////////
     846
     847/**
     848 * Updates the percentage value of the current operation.
     849 *
     850 * @param aPercent  New percentage value of the operation in progress
     851 *                  (in range [0, 100]).
     852 */
     853HRESULT Progress::setCurrentOperationProgress(ULONG aPercent)
     854{
     855    AssertMsgReturn(aPercent <= 100, ("%u\n", aPercent), E_INVALIDARG);
     856
     857    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     858
     859    i_checkForAutomaticTimeout();
     860    if (mCancelable && mCanceled)
     861        AssertReturn(!mCompleted, E_FAIL);
     862    AssertReturn(!mCompleted && !mCanceled, E_FAIL);
     863
     864    if (m_ulOperationPercent != aPercent)
     865    {
     866        m_ulOperationPercent = aPercent;
     867        ULONG actualPercent = 0;
     868        getPercent(&actualPercent);
     869        fireProgressPercentageChangedEvent(pEventSource, mId.toUtf16().raw(), actualPercent);
     870    }
     871
     872    return S_OK;
     873}
     874
     875HRESULT Progress::waitForOtherProgressCompletion(const ComPtr<IProgress> &aProgressOther,
     876                                                 ULONG aTimeoutMS)
    470877{
    471878    LogFlowThisFuncEnter();
     
    483890    rc = aProgressOther->COMGETTER(Cancelable)(&fCancelable);
    484891    if (FAILED(rc)) return rc;
     892
     893    uint64_t u64StopTime = UINT64_MAX;
     894    if (aTimeoutMS > 0)
     895        u64StopTime = RTTimeMilliTS() + aTimeoutMS;
    485896    /* Loop as long as the sync process isn't completed. */
    486897    while (SUCCEEDED(aProgressOther->COMGETTER(Completed(&fCompleted))))
     
    541952            break;
    542953
    543         /* Make sure the loop is not too tight */
    544         rc = aProgressOther->WaitForCompletion(100);
    545         if (FAILED(rc)) return rc;
     954        if (aTimeoutMS != 0)
     955        {
     956            /* Make sure the loop is not too tight */
     957            uint64_t u64Now = RTTimeMilliTS();
     958            uint64_t u64RemainingMS = u64StopTime - u64Now;
     959            if (u64RemainingMS < 10)
     960                u64RemainingMS = 10;
     961            else if (u64RemainingMS > 200)
     962                u64RemainingMS = 200;
     963            rc = aProgressOther->WaitForCompletion((LONG)u64RemainingMS);
     964            if (FAILED(rc)) return rc;
     965
     966            if (RTTimeMilliTS() >= u64StopTime)
     967                return VBOX_E_TIMEOUT;
     968        }
     969        else
     970        {
     971            /* Make sure the loop is not too tight */
     972            rc = aProgressOther->WaitForCompletion(200);
     973            if (FAILED(rc)) return rc;
     974        }
    546975    }
    547976
     
    562991
    563992/**
     993 * Signals that the current operation is successfully completed and advances to
     994 * the next operation. The operation percentage is reset to 0.
     995 *
     996 * @param aNextOperationDescription  Description of the next operation.
     997 * @param aNextOperationsWeight     Weight of the next operation.
     998 *
     999 * @note The current operation must not be the last one.
     1000 */
     1001HRESULT Progress::setNextOperation(const com::Utf8Str &aNextOperationDescription, ULONG aNextOperationsWeight)
     1002{
     1003    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1004
     1005    if (mCanceled)
     1006        return E_FAIL;
     1007    AssertReturn(!mCompleted, E_FAIL);
     1008    AssertReturn(m_ulCurrentOperation + 1 < m_cOperations, E_FAIL);
     1009
     1010    ++m_ulCurrentOperation;
     1011    m_ulOperationsCompletedWeight += m_ulCurrentOperationWeight;
     1012
     1013    m_operationDescription = aNextOperationDescription;
     1014    m_ulCurrentOperationWeight = aNextOperationsWeight;
     1015    m_ulOperationPercent = 0;
     1016
     1017    LogThisFunc(("%s: aNextOperationsWeight = %d; m_ulCurrentOperation is now %d, m_ulOperationsCompletedWeight is now %d\n",
     1018                 m_operationDescription.c_str(), aNextOperationsWeight, m_ulCurrentOperation, m_ulOperationsCompletedWeight));
     1019
     1020    /* wake up all waiting threads */
     1021    if (mWaitersCount > 0)
     1022        RTSemEventMultiSignal(mCompletedSem);
     1023
     1024    ULONG actualPercent = 0;
     1025    getPercent(&actualPercent);
     1026    fireProgressPercentageChangedEvent(pEventSource, mId.toUtf16().raw(), actualPercent);
     1027
     1028    return S_OK;
     1029}
     1030
     1031/**
    5641032 * Notify the progress object that we're almost at the point of no return.
    5651033 *
     
    5701038 * user believe it was rolled back.
    5711039 *
    572  * @returns Success indicator.
    573  * @retval  true on success.
    574  * @retval  false if the progress object has already been canceled or is in an
     1040 * @returns COM error status.
     1041 * @retval  S_OK on success.
     1042 * @retval  E_FAIL if the progress object has already been canceled or is in an
    5751043 *          invalid state
    5761044 */
    577 bool Progress::i_notifyPointOfNoReturn(void)
    578 {
    579     AutoCaller autoCaller(this);
    580     AssertComRCReturn(autoCaller.rc(), false);
    581 
     1045HRESULT Progress::notifyPointOfNoReturn(void)
     1046{
    5821047    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    5831048
    5841049    if (mCanceled)
    5851050    {
    586         LogThisFunc(("returns false\n"));
    587         return false;
     1051        LogThisFunc(("returns failure\n"));
     1052        return E_FAIL;
    5881053    }
    5891054
    5901055    mCancelable = FALSE;
    591     LogThisFunc(("returns true\n"));
    592     return true;
    593 }
    594 
    595 /**
    596  * Sets the cancelation callback, checking for cancelation first.
    597  *
    598  * @returns Success indicator.
    599  * @retval  true on success.
    600  * @retval  false if the progress object has already been canceled or is in an
    601  *          invalid state
    602  *
    603  * @param   pfnCallback     The function to be called upon cancelation.
    604  * @param   pvUser          The callback argument.
    605  */
    606 bool Progress::i_setCancelCallback(void (*pfnCallback)(void *), void *pvUser)
    607 {
    608     AutoCaller autoCaller(this);
    609     AssertComRCReturn(autoCaller.rc(), false);
     1056    LogThisFunc(("returns success\n"));
     1057    return S_OK;
     1058}
     1059
     1060/**
     1061 * Marks the operation as complete and attaches full error info.
     1062 *
     1063 * This is where the actual work is done, the related methods all end up here.
     1064 *
     1065 * @param aResultCode   Operation result (error) code, must not be S_OK.
     1066 * @param aErrorInfo            List of arguments for the format string.
     1067 */
     1068HRESULT Progress::notifyComplete(LONG aResultCode, const ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
     1069{
     1070    LogThisFunc(("aResultCode=%d\n", aResultCode));
     1071    /* on failure we expect error info, on success there must be none */
     1072    AssertMsg(FAILED(aResultCode) ^ aErrorInfo.isNull(),
     1073              ("No error info but trying to set a failed result (%08X)!\n",
     1074               aResultCode));
    6101075
    6111076    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    6121077
    613     i_checkForAutomaticTimeout();
    614     if (mCanceled)
    615         return false;
    616 
    617     m_pvCancelUserArg   = pvUser;
    618     m_pfnCancelCallback = pfnCallback;
    619     return true;
    620 }
    621 
    622 /**
    623  * @callback_method_impl{FNRTPROGRESS,
    624  *      Works the progress of the current operation.}
    625  */
    626 /*static*/ DECLCALLBACK(int) Progress::i_iprtProgressCallback(unsigned uPercentage, void *pvUser)
    627 {
    628     Progress *pThis = (Progress *)pvUser;
    629 
    630     /*
    631      * Same as setCurrentOperationProgress, except we don't fail on mCompleted.
    632      */
    633     AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
    634     int vrc = VINF_SUCCESS;
    635     if (!pThis->mCompleted)
    636     {
    637         pThis->i_checkForAutomaticTimeout();
    638         if (!pThis->mCanceled)
    639         {
    640             if (uPercentage > pThis->m_ulOperationPercent)
    641                 pThis->setCurrentOperationProgress(uPercentage);
    642         }
    643         else
    644         {
    645             Assert(pThis->mCancelable);
    646             vrc = VERR_CANCELLED;
    647         }
    648     }
    649     /* else ignored */
    650     return vrc;
    651 }
    652 
    653 /**
    654  * @callback_method_impl{FNVDPROGRESS,
    655  *      Progress::i_iprtProgressCallback with parameters switched around.}
    656  */
    657 /*static*/ DECLCALLBACK(int) Progress::i_vdProgressCallback(void *pvUser, unsigned uPercentage)
    658 {
    659     return i_iprtProgressCallback(uPercentage, pvUser);
    660 }
    661 
    662 // IProgress properties
    663 /////////////////////////////////////////////////////////////////////////////
    664 
    665 HRESULT Progress::getId(com::Guid &aId)
    666 {
    667     /* mId is constant during life time, no need to lock */
    668     aId = mId;
    669 
    670     return S_OK;
    671 }
    672 
    673 HRESULT Progress::getDescription(com::Utf8Str &aDescription)
    674 {
    675     /* mDescription is constant during life time, no need to lock */
    676     aDescription = mDescription;
    677 
    678     return S_OK;
    679 }
    680 HRESULT Progress::getInitiator(ComPtr<IUnknown> &aInitiator)
    681 {
    682     /* mInitiator/mParent are constant during life time, no need to lock */
     1078    AssertReturn(mCompleted == FALSE, E_FAIL);
     1079
     1080    if (mCanceled && SUCCEEDED(aResultCode))
     1081        aResultCode = E_FAIL;
     1082
     1083    mCompleted = TRUE;
     1084    mResultCode = aResultCode;
     1085    if (SUCCEEDED(aResultCode))
     1086    {
     1087        m_ulCurrentOperation = m_cOperations - 1; /* last operation */
     1088        m_ulOperationPercent = 100;
     1089    }
     1090    mErrorInfo = aErrorInfo;
     1091
    6831092#if !defined(VBOX_COM_INPROC)
    684     if (mInitiator)
    685         mInitiator.queryInterfaceTo(aInitiator.asOutParam());
    686     else
    687     {
    688         ComObjPtr<VirtualBox> pVirtualBox(mParent);
    689         pVirtualBox.queryInterfaceTo(aInitiator.asOutParam());
    690     }
    691 #else
    692     mInitiator.queryInterfaceTo(aInitiator.asOutParam());
     1093    /* remove from the global collection of pending progress operations */
     1094    if (mParent)
     1095        mParent->i_removeProgress(mId.ref());
    6931096#endif
    694 
    695     return S_OK;
    696 }
    697 
    698 HRESULT Progress::getCancelable(BOOL *aCancelable)
    699 {
    700     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    701 
    702     *aCancelable = mCancelable;
    703 
    704     return S_OK;
    705 }
    706 
    707 HRESULT Progress::getPercent(ULONG *aPercent)
    708 {
    709     /* i_checkForAutomaticTimeout requires a write lock. */
    710     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    711 
    712     if (mCompleted && SUCCEEDED(mResultCode))
    713         *aPercent = 100;
    714     else
    715     {
    716         ULONG ulPercent = (ULONG)i_calcTotalPercent();
    717         // do not report 100% until we're really really done with everything
    718         // as the Qt GUI dismisses progress dialogs in that case
    719         if (    ulPercent == 100
    720              && (    m_ulOperationPercent < 100
    721                   || (m_ulCurrentOperation < m_cOperations -1)
    722                 )
    723            )
    724             *aPercent = 99;
    725         else
    726             *aPercent = ulPercent;
    727     }
    728 
    729     i_checkForAutomaticTimeout();
    730 
    731     return S_OK;
    732 }
    733 
    734 HRESULT Progress::getTimeRemaining(LONG *aTimeRemaining)
    735 {
    736     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    737 
    738     if (mCompleted)
    739         *aTimeRemaining = 0;
    740     else
    741     {
    742         double dPercentDone = i_calcTotalPercent();
    743         if (dPercentDone < 1)
    744             *aTimeRemaining = -1;       // unreliable, or avoid division by 0 below
    745         else
    746         {
    747             uint64_t ullTimeNow = RTTimeMilliTS();
    748             uint64_t ullTimeElapsed = ullTimeNow - m_ullTimestamp;
    749             uint64_t ullTimeTotal = (uint64_t)((double)ullTimeElapsed * 100 / dPercentDone);
    750             uint64_t ullTimeRemaining = ullTimeTotal - ullTimeElapsed;
    751 
    752 //          LogFunc(("dPercentDone = %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n",
    753 //                   (uint32_t)dPercentDone, ullTimeNow, ullTimeElapsed, ullTimeTotal, ullTimeRemaining));
    754 
    755             *aTimeRemaining = (LONG)(ullTimeRemaining / 1000);
    756         }
    757     }
    758 
    759     return S_OK;
    760 }
    761 
    762 HRESULT Progress::getCompleted(BOOL *aCompleted)
    763 {
    764     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    765 
    766     *aCompleted = mCompleted;
    767 
    768     return S_OK;
    769 }
    770 
    771 HRESULT Progress::getCanceled(BOOL *aCanceled)
    772 {
    773     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    774 
    775     *aCanceled = mCanceled;
    776 
    777     return S_OK;
    778 }
    779 
    780 HRESULT Progress::getResultCode(LONG *aResultCode)
    781 {
    782     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    783 
    784     if (!mCompleted)
    785         return setError(E_FAIL, tr("Result code is not available, operation is still in progress"));
    786 
    787     *aResultCode = mResultCode;
    788 
    789     return S_OK;
    790 }
    791 
    792 HRESULT Progress::getErrorInfo(ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
    793 {
    794     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    795 
    796     if (!mCompleted)
    797         return setError(E_FAIL, tr("Error info is not available, operation is still in progress"));
    798 
    799     mErrorInfo.queryInterfaceTo(aErrorInfo.asOutParam());
    800 
    801     return S_OK;
    802 }
    803 
    804 HRESULT Progress::getOperationCount(ULONG *aOperationCount)
    805 {
    806     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    807 
    808     *aOperationCount = m_cOperations;
    809 
    810     return S_OK;
    811 }
    812 
    813 HRESULT Progress::getOperation(ULONG *aOperation)
    814 {
    815     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    816 
    817     *aOperation = m_ulCurrentOperation;
    818 
    819     return S_OK;
    820 }
    821 
    822 HRESULT Progress::getOperationDescription(com::Utf8Str &aOperationDescription)
    823 {
    824     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    825 
    826     aOperationDescription = m_operationDescription;
    827 
    828     return S_OK;
    829 }
    830 
    831 HRESULT Progress::getOperationPercent(ULONG *aOperationPercent)
    832 {
    833     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    834 
    835     if (mCompleted && SUCCEEDED(mResultCode))
    836         *aOperationPercent = 100;
    837     else
    838         *aOperationPercent = m_ulOperationPercent;
    839 
    840     return S_OK;
    841 }
    842 
    843 HRESULT Progress::getOperationWeight(ULONG *aOperationWeight)
    844 {
    845     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    846 
    847     *aOperationWeight = m_ulCurrentOperationWeight;
    848 
    849     return S_OK;
    850 }
    851 
    852 HRESULT Progress::getTimeout(ULONG *aTimeout)
    853 {
    854     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    855 
    856     *aTimeout = m_cMsTimeout;
    857 
    858     return S_OK;
    859 }
    860 
    861 HRESULT Progress::setTimeout(ULONG aTimeout)
    862 {
    863     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    864 
    865     if (!mCancelable)
    866         return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled"));
    867     m_cMsTimeout = aTimeout;
    868 
    869     return S_OK;
    870 }
    871 
    872 
    873 // IProgress methods
    874 /////////////////////////////////////////////////////////////////////////////
    875 
    876 /**
    877  * Updates the percentage value of the current operation.
    878  *
    879  * @param aPercent  New percentage value of the operation in progress
    880  *                  (in range [0, 100]).
    881  */
    882 HRESULT Progress::setCurrentOperationProgress(ULONG aPercent)
    883 {
    884     AssertMsgReturn(aPercent <= 100, ("%u\n", aPercent), E_INVALIDARG);
    885 
    886     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    887 
    888     i_checkForAutomaticTimeout();
    889     if (mCancelable && mCanceled)
    890         AssertReturn(!mCompleted, E_FAIL);
    891     AssertReturn(!mCompleted && !mCanceled, E_FAIL);
    892 
    893     if (m_ulOperationPercent != aPercent)
    894     {
    895         m_ulOperationPercent = aPercent;
    896         ULONG actualPercent = 0;
    897         getPercent(&actualPercent);
    898         fireProgressPercentageChangedEvent(pEventSource, mId.toUtf16().raw(), actualPercent);
    899     }
    900 
    901     return S_OK;
    902 }
    903 
    904 /**
    905  * Signals that the current operation is successfully completed and advances to
    906  * the next operation. The operation percentage is reset to 0.
    907  *
    908  * @param aNextOperationDescription  Description of the next operation.
    909  * @param aNextOperationsWeight     Weight of the next operation.
    910  *
    911  * @note The current operation must not be the last one.
    912  */
    913 HRESULT Progress::setNextOperation(const com::Utf8Str &aNextOperationDescription, ULONG aNextOperationsWeight)
    914 {
    915     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    916 
    917     if (mCanceled)
    918         return E_FAIL;
    919     AssertReturn(!mCompleted, E_FAIL);
    920     AssertReturn(m_ulCurrentOperation + 1 < m_cOperations, E_FAIL);
    921 
    922     ++m_ulCurrentOperation;
    923     m_ulOperationsCompletedWeight += m_ulCurrentOperationWeight;
    924 
    925     m_operationDescription = aNextOperationDescription;
    926     m_ulCurrentOperationWeight = aNextOperationsWeight;
    927     m_ulOperationPercent = 0;
    928 
    929     LogThisFunc(("%s: aNextOperationsWeight = %d; m_ulCurrentOperation is now %d, m_ulOperationsCompletedWeight is now %d\n",
    930                  m_operationDescription.c_str(), aNextOperationsWeight, m_ulCurrentOperation, m_ulOperationsCompletedWeight));
    9311097
    9321098    /* wake up all waiting threads */
     
    9341100        RTSemEventMultiSignal(mCompletedSem);
    9351101
    936     ULONG actualPercent = 0;
    937     getPercent(&actualPercent);
    938     fireProgressPercentageChangedEvent(pEventSource, mId.toUtf16().raw(), actualPercent);
    939 
    940     return S_OK;
    941 }
    942 
    943 /**
    944  * @note XPCOM: when this method is not called on the main XPCOM thread, it
    945  *       simply blocks the thread until mCompletedSem is signalled. If the
    946  *       thread has its own event queue (hmm, what for?) that it must run, then
    947  *       calling this method will definitely freeze event processing.
    948  */
    949 HRESULT Progress::waitForCompletion(LONG aTimeout)
    950 {
    951     LogFlowThisFuncEnter();
    952     LogFlowThisFunc(("aTimeout=%d\n", aTimeout));
    953 
    954     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    955 
    956     /* if we're already completed, take a shortcut */
    957     if (!mCompleted)
    958     {
    959         int vrc = VINF_SUCCESS;
    960         bool fForever = aTimeout < 0;
    961         int64_t timeLeft = aTimeout;
    962         int64_t lastTime = RTTimeMilliTS();
    963 
    964         while (!mCompleted && (fForever || timeLeft > 0))
    965         {
    966             mWaitersCount++;
    967             alock.release();
    968             vrc = RTSemEventMultiWait(mCompletedSem,
    969                                       fForever ? RT_INDEFINITE_WAIT : (RTMSINTERVAL)timeLeft);
    970             alock.acquire();
    971             mWaitersCount--;
    972 
    973             /* the last waiter resets the semaphore */
    974             if (mWaitersCount == 0)
    975                 RTSemEventMultiReset(mCompletedSem);
    976 
    977             if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
    978                 break;
    979 
    980             if (!fForever)
    981             {
    982                 int64_t now = RTTimeMilliTS();
    983                 timeLeft -= now - lastTime;
    984                 lastTime = now;
    985             }
    986         }
    987 
    988         if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
    989             return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to wait for the task completion (%Rrc)"), vrc);
    990     }
    991 
    992     LogFlowThisFuncLeave();
    993 
    994     return S_OK;
    995 }
    996 
    997 /**
    998  * @note XPCOM: when this method is not called on the main XPCOM thread, it
    999  *       simply blocks the thread until mCompletedSem is signalled. If the
    1000  *       thread has its own event queue (hmm, what for?) that it must run, then
    1001  *       calling this method will definitely freeze event processing.
    1002  */
    1003 HRESULT Progress::waitForOperationCompletion(ULONG aOperation, LONG aTimeout)
    1004 
    1005 {
    1006     LogFlowThisFuncEnter();
    1007     LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout));
    1008 
    1009     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1010 
    1011     CheckComArgExpr(aOperation, aOperation < m_cOperations);
    1012 
    1013     /* if we're already completed or if the given operation is already done,
    1014      * then take a shortcut */
    1015     if (    !mCompleted
    1016          && aOperation >= m_ulCurrentOperation)
    1017     {
    1018         int vrc = VINF_SUCCESS;
    1019         bool fForever = aTimeout < 0;
    1020         int64_t timeLeft = aTimeout;
    1021         int64_t lastTime = RTTimeMilliTS();
    1022 
    1023         while (    !mCompleted && aOperation >= m_ulCurrentOperation
    1024                 && (fForever || timeLeft > 0))
    1025         {
    1026             mWaitersCount ++;
    1027             alock.release();
    1028             vrc = RTSemEventMultiWait(mCompletedSem,
    1029                                       fForever ? RT_INDEFINITE_WAIT : (unsigned) timeLeft);
    1030             alock.acquire();
    1031             mWaitersCount--;
    1032 
    1033             /* the last waiter resets the semaphore */
    1034             if (mWaitersCount == 0)
    1035                 RTSemEventMultiReset(mCompletedSem);
    1036 
    1037             if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
    1038                 break;
    1039 
    1040             if (!fForever)
    1041             {
    1042                 int64_t now = RTTimeMilliTS();
    1043                 timeLeft -= now - lastTime;
    1044                 lastTime = now;
    1045             }
    1046         }
    1047 
    1048         if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
    1049             return setErrorBoth(E_FAIL, vrc, tr("Failed to wait for the operation completion (%Rrc)"), vrc);
    1050     }
    1051 
    1052     LogFlowThisFuncLeave();
    1053 
    1054     return S_OK;
    1055 }
    1056 
    1057 HRESULT Progress::cancel()
    1058 {
    1059     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1060 
    1061     if (!mCancelable)
    1062         return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled"));
    1063 
    1064     if (!mCanceled)
    1065     {
    1066         LogThisFunc(("Canceling\n"));
    1067         mCanceled = TRUE;
    1068         if (m_pfnCancelCallback)
    1069             m_pfnCancelCallback(m_pvCancelUserArg);
    1070 
    1071     }
    1072     else
    1073         LogThisFunc(("Already canceled\n"));
    1074 
    1075     return S_OK;
    1076 }
    1077 
    1078 HRESULT Progress::getEventSource(ComPtr<IEventSource> &aEventSource)
    1079 {
    1080     /* event source is const, no need to lock */
    1081     pEventSource.queryInterfaceTo(aEventSource.asOutParam());
    1082     return S_OK;
    1083 }
     1102    fireProgressTaskCompletedEvent(pEventSource, mId.toUtf16().raw());
     1103
     1104    return S_OK;
     1105}
     1106
    10841107
    10851108// private internal helpers
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r74765 r74804  
    62396239    IProgress *pProgress = static_cast<IProgress *>(pvUser);
    62406240    if (pProgress)
    6241         rc = pProgress->SetCurrentOperationProgress(uPercentage);
     6241    {
     6242        ComPtr<IInternalProgressControl> pProgressControl(pProgress);
     6243        AssertReturn(!!pProgressControl, VERR_INVALID_PARAMETER);
     6244        rc = pProgressControl->SetCurrentOperationProgress(uPercentage);
     6245    }
    62426246    return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
    62436247}
     
    78557859    AssertComRCReturnRC(autoCaller.rc());
    78567860
     7861    ComPtr<IInternalProgressControl> pProgressControl(aProgress);
     7862
    78577863    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    78587864
     
    79477953
    79487954    /* advance percent count */
    7949     if (aProgress)
    7950         aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount );
     7955    if (pProgressControl)
     7956        pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
    79517957
    79527958
     
    79767982
    79777983    /* advance percent count */
    7978     if (aProgress)
    7979         aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount );
     7984    if (pProgressControl)
     7985        pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
    79807986
    79817987    vrc = VINF_SUCCESS;
     
    80018007
    80028008    /* advance percent count */
    8003     if (aProgress)
    8004         aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount );
     8009    if (pProgressControl)
     8010        pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
    80058011
    80068012#ifdef VBOX_WITH_HGCM
     
    80198025
    80208026    /* advance percent count */
    8021     if (aProgress)
    8022         aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount);
     8027    if (pProgressControl)
     8028        pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
    80238029
    80248030#endif /* VBOX_WITH_HGCM */
     
    80618067
    80628068        /* advance percent count */
    8063         if (aProgress)
    8064             aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount);
     8069        if (pProgressControl)
     8070            pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
    80658071
    80668072        if (RT_SUCCESS(vrc))
     
    80938099
    80948100        /* advance percent count */
    8095         if (aProgress)
    8096             aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount);
     8101        if (pProgressControl)
     8102            pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
    80978103    }
    80988104    else
     
    95049510    /* update the progress object */
    95059511    if (pProgress)
    9506         pProgress->SetCurrentOperationProgress(uPercent);
     9512    {
     9513        ComPtr<IInternalProgressControl> pProgressControl(pProgress);
     9514        AssertReturn(!!pProgressControl, VERR_INVALID_PARAMETER);
     9515        pProgressControl->SetCurrentOperationProgress(uPercent);
     9516    }
    95079517
    95089518    NOREF(pUVM);
  • trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp

    r73003 r74804  
    718718     * We're at the point of no return.
    719719     */
    720     if (!pState->mptrProgress->i_notifyPointOfNoReturn())
     720    if (FAILED(pState->mptrProgress->NotifyPointOfNoReturn()))
    721721    {
    722722        i_teleporterSrcSubmitCommand(pState, "cancel", false /*fWaitForAck*/);
     
    14141414             *       make it possible to recover from some VMR3Resume failures.
    14151415             */
    1416             if (   pState->mptrProgress->i_notifyPointOfNoReturn()
     1416            if (   SUCCEEDED(pState->mptrProgress->NotifyPointOfNoReturn())
    14171417                && pState->mfLockedMedia)
    14181418            {
  • trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp

    r73784 r74804  
    26562656                /* Now wait for the background import operation to complete; this throws
    26572657                 * HRESULTs on error. */
    2658                 stack.pProgress->i_waitForOtherProgressCompletion(pProgressImport);
     2658                stack.pProgress->WaitForOtherProgressCompletion(pProgressImport, 0 /* indefinite wait */);
    26592659            }
    26602660        }
  • trunk/src/VBox/Main/src-server/MachineImpl.cpp

    r74474 r74804  
    54985498                rc = pMedium->DeleteStorage(pProgress2.asOutParam());
    54995499                if (FAILED(rc)) throw rc;
    5500                 rc = task.m_pProgress->i_waitForOtherProgressCompletion(pProgress2);
     5500                rc = task.m_pProgress->WaitForOtherProgressCompletion(pProgress2, 0 /* indefinite wait */);
    55015501                if (FAILED(rc)) throw rc;
    55025502            }
     
    1094310943    LogFlowThisFunc(("aOnline=%d\n", aOnline));
    1094410944
     10945    ComPtr<IInternalProgressControl> pProgressControl(aProgress);
     10946    AssertReturn(!!pProgressControl, E_INVALIDARG);
     10947
    1094510948    AutoCaller autoCaller(this);
    1094610949    AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
     
    1104811051                {
    1104911052                    if (pMedium == NULL)
    11050                         aProgress->SetNextOperation(Bstr(tr("Skipping attachment without medium")).raw(),
    11051                                                     aWeight);        // weight
     11053                        pProgressControl->SetNextOperation(Bstr(tr("Skipping attachment without medium")).raw(),
     11054                                                           aWeight);        // weight
    1105211055                    else
    11053                         aProgress->SetNextOperation(BstrFmt(tr("Skipping medium '%s'"),
    11054                                                             pMedium->i_getBase()->i_getName().c_str()).raw(),
    11055                                                     aWeight);        // weight
     11056                        pProgressControl->SetNextOperation(BstrFmt(tr("Skipping medium '%s'"),
     11057                                                                   pMedium->i_getBase()->i_getName().c_str()).raw(),
     11058                                                           aWeight);        // weight
    1105611059                }
    1105711060
     
    1106111064
    1106211065            /* need a diff */
    11063             aProgress->SetNextOperation(BstrFmt(tr("Creating differencing hard disk for '%s'"),
    11064                                                 pMedium->i_getBase()->i_getName().c_str()).raw(),
    11065                                         aWeight);        // weight
     11066            pProgressControl->SetNextOperation(BstrFmt(tr("Creating differencing hard disk for '%s'"),
     11067                                                       pMedium->i_getBase()->i_getName().c_str()).raw(),
     11068                                               aWeight);        // weight
    1106611069
    1106711070            Utf8Str strFullSnapshotFolder;
  • trunk/src/VBox/Main/src-server/MachineImplCloneVM.cpp

    r73743 r74804  
    12901290                        /* Wait until the async process has finished. */
    12911291                        srcLock.release();
    1292                         rc = d->pProgress->i_waitForOtherProgressCompletion(progress2);
     1292                        rc = d->pProgress->WaitForOtherProgressCompletion(progress2, 0 /* indefinite wait */);
    12931293                        srcLock.acquire();
    12941294                        if (FAILED(rc)) throw rc;
  • trunk/src/VBox/Main/src-server/MachineImplMoveVM.cpp

    r74530 r74804  
    11141114                 */
    11151115                /* Wait until the other process has finished. */
    1116                 rc = m_pProgress->i_waitForOtherProgressCompletion(moveDiskProgress);
     1116                rc = m_pProgress->WaitForOtherProgressCompletion(moveDiskProgress, 0 /* indefinite wait */);
    11171117            }
    11181118
  • trunk/src/VBox/Main/src-server/SnapshotImpl.cpp

    r70236 r74804  
    17471747                LogRel(("Machine: skipped saving state as part of online snapshot\n"));
    17481748
    1749             if (!task.m_pProgress->i_notifyPointOfNoReturn())
     1749            if (FAILED(task.m_pProgress->NotifyPointOfNoReturn()))
    17501750                throw setError(E_FAIL, tr("Canceled"));
    17511751
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