diff options
Diffstat (limited to 'src/VBox/Main/src-all/ProgressImpl.cpp')
-rw-r--r-- | src/VBox/Main/src-all/ProgressImpl.cpp | 889 |
1 files changed, 122 insertions, 767 deletions
diff --git a/src/VBox/Main/src-all/ProgressImpl.cpp b/src/VBox/Main/src-all/ProgressImpl.cpp index 3d78b2bc..fa3ecea8 100644 --- a/src/VBox/Main/src-all/ProgressImpl.cpp +++ b/src/VBox/Main/src-all/ProgressImpl.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2012 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -18,15 +18,18 @@ #include <iprt/types.h> + #if defined(VBOX_WITH_XPCOM) #include <nsIServiceManager.h> #include <nsIExceptionService.h> #include <nsCOMPtr.h> #endif /* defined(VBOX_WITH_XPCOM) */ -#include "ProgressCombinedImpl.h" +#include "ProgressImpl.h" -#include "VirtualBoxImpl.h" +#if !defined(VBOX_COM_INPROC) +# include "VirtualBoxImpl.h" +#endif #include "VirtualBoxErrorInfoImpl.h" #include "Logging.h" @@ -36,181 +39,25 @@ #include <iprt/cpp/utils.h> #include <VBox/err.h> +#include "AutoCaller.h" -//////////////////////////////////////////////////////////////////////////////// -// ProgressBase class -//////////////////////////////////////////////////////////////////////////////// -// constructor / destructor -//////////////////////////////////////////////////////////////////////////////// - -ProgressBase::ProgressBase() +Progress::Progress() #if !defined(VBOX_COM_INPROC) : mParent(NULL) #endif { } -ProgressBase::~ProgressBase() +Progress::~Progress() { } -/** - * Subclasses must call this method from their FinalConstruct() implementations. - */ -HRESULT ProgressBase::FinalConstruct() -{ - mCancelable = FALSE; - mCompleted = FALSE; - mCanceled = FALSE; - mResultCode = S_OK; - - m_cOperations - = m_ulTotalOperationsWeight - = m_ulOperationsCompletedWeight - = m_ulCurrentOperation - = m_ulCurrentOperationWeight - = m_ulOperationPercent - = m_cMsTimeout - = 0; - - // get creation timestamp - m_ullTimestamp = RTTimeMilliTS(); - - m_pfnCancelCallback = NULL; - m_pvCancelUserArg = NULL; - - return BaseFinalConstruct(); -} - -// protected initializer/uninitializer for internal purposes only -//////////////////////////////////////////////////////////////////////////////// - -/** - * Initializes the progress base object. - * - * Subclasses should call this or any other #protectedInit() method from their - * init() implementations. - * - * @param aAutoInitSpan AutoInitSpan object instantiated by a subclass. - * @param aParent Parent object (only for server-side Progress objects). - * @param aInitiator Initiator of the task (for server-side objects. Can be - * NULL which means initiator = parent, otherwise must not - * be NULL). - * @param aDescription ask description. - * @param aID Address of result GUID structure (optional). - * - * @return COM result indicator. - */ -HRESULT ProgressBase::protectedInit(AutoInitSpan &aAutoInitSpan, -#if !defined(VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, - OUT_GUID aId /* = NULL */) -{ - /* Guarantees subclasses call this method at the proper time */ - NOREF(aAutoInitSpan); - - AutoCaller autoCaller(this); - AssertReturn(autoCaller.state() == InInit, E_FAIL); - -#if !defined(VBOX_COM_INPROC) - AssertReturn(aParent, E_INVALIDARG); -#else - AssertReturn(aInitiator, E_INVALIDARG); -#endif - - AssertReturn(aDescription, E_INVALIDARG); - -#if !defined(VBOX_COM_INPROC) - /* share parent weakly */ - unconst(mParent) = aParent; -#endif - -#if !defined(VBOX_COM_INPROC) - /* assign (and therefore addref) initiator only if it is not VirtualBox - * (to avoid cycling); otherwise mInitiator will remain null which means - * that it is the same as the parent */ - if (aInitiator) - { - ComObjPtr<VirtualBox> pVirtualBox(mParent); - if (!(pVirtualBox == aInitiator)) - unconst(mInitiator) = aInitiator; - } -#else - unconst(mInitiator) = aInitiator; -#endif - - unconst(mId).create(); - if (aId) - mId.cloneTo(aId); - -#if !defined(VBOX_COM_INPROC) - /* add to the global collection of progress operations (note: after - * creating mId) */ - mParent->addProgress(this); -#endif - - unconst(mDescription) = aDescription; - - return S_OK; -} - -/** - * Initializes the progress base object. - * - * This is a special initializer that doesn't initialize any field. Used by one - * of the Progress::init() forms to create sub-progress operations combined - * together using a CombinedProgress instance, so it doesn't require the parent, - * initiator, description and doesn't create an ID. - * - * Subclasses should call this or any other #protectedInit() method from their - * init() implementations. - * - * @param aAutoInitSpan AutoInitSpan object instantiated by a subclass. - */ -HRESULT ProgressBase::protectedInit(AutoInitSpan &aAutoInitSpan) -{ - /* Guarantees subclasses call this method at the proper time */ - NOREF(aAutoInitSpan); - - return S_OK; -} - -/** - * Uninitializes the instance. - * - * Subclasses should call this from their uninit() implementations. - * - * @param aAutoUninitSpan AutoUninitSpan object instantiated by a subclass. - * - * @note Using the mParent member after this method returns is forbidden. - */ -void ProgressBase::protectedUninit(AutoUninitSpan &aAutoUninitSpan) -{ - /* release initiator (effective only if mInitiator has been assigned in - * init()) */ - unconst(mInitiator).setNull(); - -#if !defined(VBOX_COM_INPROC) - if (mParent) - { - /* remove the added progress on failure to complete the initialization */ - if (aAutoUninitSpan.initFailed() && !mId.isEmpty()) - mParent->removeProgress(mId.ref()); - - unconst(mParent) = NULL; - } -#endif -} - // IProgress properties ///////////////////////////////////////////////////////////////////////////// -STDMETHODIMP ProgressBase::COMGETTER(Id)(BSTR *aId) +STDMETHODIMP Progress::COMGETTER(Id)(BSTR *aId) { CheckComArgOutPointerValid(aId); @@ -223,7 +70,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Id)(BSTR *aId) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Description)(BSTR *aDescription) +STDMETHODIMP Progress::COMGETTER(Description)(BSTR *aDescription) { CheckComArgOutPointerValid(aDescription); @@ -236,7 +83,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Description)(BSTR *aDescription) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Initiator)(IUnknown **aInitiator) +STDMETHODIMP Progress::COMGETTER(Initiator)(IUnknown **aInitiator) { CheckComArgOutPointerValid(aInitiator); @@ -260,7 +107,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Initiator)(IUnknown **aInitiator) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Cancelable)(BOOL *aCancelable) +STDMETHODIMP Progress::COMGETTER(Cancelable)(BOOL *aCancelable) { CheckComArgOutPointerValid(aCancelable); @@ -283,7 +130,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Cancelable)(BOOL *aCancelable) * * @return fractional percentage as a double value. */ -double ProgressBase::calcTotalPercent() +double Progress::calcTotalPercent() { // avoid division by zero if (m_ulTotalOperationsWeight == 0) @@ -301,7 +148,7 @@ double ProgressBase::calcTotalPercent() * * The caller should hold the object write lock. */ -void ProgressBase::checkForAutomaticTimeout(void) +void Progress::checkForAutomaticTimeout(void) { if ( m_cMsTimeout && mCancelable @@ -312,7 +159,7 @@ void ProgressBase::checkForAutomaticTimeout(void) } -STDMETHODIMP ProgressBase::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) +STDMETHODIMP Progress::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) { CheckComArgOutPointerValid(aTimeRemaining); @@ -335,7 +182,7 @@ STDMETHODIMP ProgressBase::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) uint64_t ullTimeTotal = (uint64_t)(ullTimeElapsed * 100 / dPercentDone); uint64_t ullTimeRemaining = ullTimeTotal - ullTimeElapsed; -// Log(("ProgressBase::GetTimeRemaining: dPercentDone %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n", +// Log(("Progress::GetTimeRemaining: dPercentDone %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n", // (uint32_t)dPercentDone, ullTimeNow, ullTimeElapsed, ullTimeTotal, ullTimeRemaining)); *aTimeRemaining = (LONG)(ullTimeRemaining / 1000); @@ -345,7 +192,7 @@ STDMETHODIMP ProgressBase::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Percent)(ULONG *aPercent) +STDMETHODIMP Progress::COMGETTER(Percent)(ULONG *aPercent) { CheckComArgOutPointerValid(aPercent); @@ -378,7 +225,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Percent)(ULONG *aPercent) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Completed)(BOOL *aCompleted) +STDMETHODIMP Progress::COMGETTER(Completed)(BOOL *aCompleted) { CheckComArgOutPointerValid(aCompleted); @@ -392,7 +239,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Completed)(BOOL *aCompleted) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Canceled)(BOOL *aCanceled) +STDMETHODIMP Progress::COMGETTER(Canceled)(BOOL *aCanceled) { CheckComArgOutPointerValid(aCanceled); @@ -406,7 +253,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Canceled)(BOOL *aCanceled) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(ResultCode)(LONG *aResultCode) +STDMETHODIMP Progress::COMGETTER(ResultCode)(LONG *aResultCode) { CheckComArgOutPointerValid(aResultCode); @@ -424,7 +271,7 @@ STDMETHODIMP ProgressBase::COMGETTER(ResultCode)(LONG *aResultCode) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo) +STDMETHODIMP Progress::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo) { CheckComArgOutPointerValid(aErrorInfo); @@ -442,7 +289,7 @@ STDMETHODIMP ProgressBase::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInf return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(OperationCount)(ULONG *aOperationCount) +STDMETHODIMP Progress::COMGETTER(OperationCount)(ULONG *aOperationCount) { CheckComArgOutPointerValid(aOperationCount); @@ -456,7 +303,7 @@ STDMETHODIMP ProgressBase::COMGETTER(OperationCount)(ULONG *aOperationCount) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Operation)(ULONG *aOperation) +STDMETHODIMP Progress::COMGETTER(Operation)(ULONG *aOperation) { CheckComArgOutPointerValid(aOperation); @@ -470,7 +317,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Operation)(ULONG *aOperation) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(OperationDescription)(BSTR *aOperationDescription) +STDMETHODIMP Progress::COMGETTER(OperationDescription)(BSTR *aOperationDescription) { CheckComArgOutPointerValid(aOperationDescription); @@ -484,7 +331,7 @@ STDMETHODIMP ProgressBase::COMGETTER(OperationDescription)(BSTR *aOperationDescr return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(OperationPercent)(ULONG *aOperationPercent) +STDMETHODIMP Progress::COMGETTER(OperationPercent)(ULONG *aOperationPercent) { CheckComArgOutPointerValid(aOperationPercent); @@ -501,7 +348,7 @@ STDMETHODIMP ProgressBase::COMGETTER(OperationPercent)(ULONG *aOperationPercent) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(OperationWeight)(ULONG *aOperationWeight) +STDMETHODIMP Progress::COMGETTER(OperationWeight)(ULONG *aOperationWeight) { CheckComArgOutPointerValid(aOperationWeight); @@ -515,7 +362,7 @@ STDMETHODIMP ProgressBase::COMGETTER(OperationWeight)(ULONG *aOperationWeight) return S_OK; } -STDMETHODIMP ProgressBase::COMSETTER(Timeout)(ULONG aTimeout) +STDMETHODIMP Progress::COMSETTER(Timeout)(ULONG aTimeout) { AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); @@ -531,7 +378,7 @@ STDMETHODIMP ProgressBase::COMSETTER(Timeout)(ULONG aTimeout) return S_OK; } -STDMETHODIMP ProgressBase::COMGETTER(Timeout)(ULONG *aTimeout) +STDMETHODIMP Progress::COMGETTER(Timeout)(ULONG *aTimeout) { CheckComArgOutPointerValid(aTimeout); @@ -558,7 +405,7 @@ STDMETHODIMP ProgressBase::COMGETTER(Timeout)(ULONG *aTimeout) * @param pfnCallback The function to be called upon cancelation. * @param pvUser The callback argument. */ -bool ProgressBase::setCancelCallback(void (*pfnCallback)(void *), void *pvUser) +bool Progress::setCancelCallback(void (*pfnCallback)(void *), void *pvUser) { AutoCaller autoCaller(this); AssertComRCReturn(autoCaller.rc(), false); @@ -574,13 +421,29 @@ bool ProgressBase::setCancelCallback(void (*pfnCallback)(void *), void *pvUser) return true; } -//////////////////////////////////////////////////////////////////////////////// -// Progress class -//////////////////////////////////////////////////////////////////////////////// - HRESULT Progress::FinalConstruct() { - HRESULT rc = ProgressBase::FinalConstruct(); + mCancelable = FALSE; + mCompleted = FALSE; + mCanceled = FALSE; + mResultCode = S_OK; + + m_cOperations + = m_ulTotalOperationsWeight + = m_ulOperationsCompletedWeight + = m_ulCurrentOperation + = m_ulCurrentOperationWeight + = m_ulOperationPercent + = m_cMsTimeout + = 0; + + // get creation timestamp + m_ullTimestamp = RTTimeMilliTS(); + + m_pfnCancelCallback = NULL; + m_pvCancelUserArg = NULL; + + HRESULT rc = Progress::BaseFinalConstruct(); if (FAILED(rc)) return rc; mCompletedSem = NIL_RTSEMEVENTMULTI; @@ -636,16 +499,16 @@ void Progress::FinalRelease() * Even simpler, if you need no sub-operations at all, pass in cOperations = * ulTotalOperationsWeight = ulFirstOperationWeight = 1. * - * @param aParent See ProgressBase::init(). - * @param aInitiator See ProgressBase::init(). - * @param aDescription See ProgressBase::init(). + * @param aParent See Progress::init(). + * @param aInitiator See Progress::init(). + * @param aDescription See Progress::init(). * @param aCancelable Flag whether the task maybe canceled. * @param cOperations Number of operations within this task (at least 1). * @param ulTotalOperationsWeight Total weight of operations; must be the sum of ulFirstOperationWeight and * what is later passed with each subsequent setNextOperation() call. * @param bstrFirstOperationDescription Description of the first operation. * @param ulFirstOperationWeight Weight of first sub-operation. - * @param aId See ProgressBase::init(). + * @param aId See Progress::init(). */ HRESULT Progress::init( #if !defined(VBOX_COM_INPROC) @@ -676,11 +539,55 @@ HRESULT Progress::init( HRESULT rc = S_OK; - rc = ProgressBase::protectedInit(autoInitSpan, +// rc = Progress::init( +//#if !defined(VBOX_COM_INPROC) +// aParent, +//#endif +// aInitiator, aDescription, FALSE, aId); +// NA #if !defined(VBOX_COM_INPROC) - aParent, + AssertReturn(aParent, E_INVALIDARG); +#else + AssertReturn(aInitiator, E_INVALIDARG); +#endif + + AssertReturn(aDescription, E_INVALIDARG); + +#if !defined(VBOX_COM_INPROC) + /* share parent weakly */ + unconst(mParent) = aParent; #endif - aInitiator, aDescription, aId); + +#if !defined(VBOX_COM_INPROC) + /* assign (and therefore addref) initiator only if it is not VirtualBox + * * (to avoid cycling); otherwise mInitiator will remain null which means + * * that it is the same as the parent */ + if (aInitiator) + { + ComObjPtr<VirtualBox> pVirtualBox(mParent); + if (!(pVirtualBox == aInitiator)) + unconst(mInitiator) = aInitiator; + } +#else + unconst(mInitiator) = aInitiator; +#endif + + unconst(mId).create(); + if (aId) + mId.cloneTo(aId); + +#if !defined(VBOX_COM_INPROC) + /* add to the global collection of progress operations (note: after + * * creating mId) */ + mParent->addProgress(this); +#endif + + unconst(mDescription) = aDescription; + + +// end of assertion + + if (FAILED(rc)) return rc; mCancelable = aCancelable; @@ -710,7 +617,7 @@ HRESULT Progress::init( * the whole task. * * Objects initialized with this method are then combined together into the - * single task using a CombinedProgress instance, so it doesn't require the + * single task using a Progress instance, so it doesn't require the * parent, initiator, description and doesn't create an ID. Note that calling * respective getter methods on an object initialized with this method is * useless. Such objects are used only to provide a separate wait semaphore and @@ -731,8 +638,9 @@ HRESULT Progress::init(BOOL aCancelable, AssertReturn(autoInitSpan.isOk(), E_FAIL); HRESULT rc = S_OK; + /* Guarantees subclasses call this method at the proper time */ + NOREF(autoInitSpan); - rc = ProgressBase::protectedInit(autoInitSpan); if (FAILED(rc)) return rc; mCancelable = aCancelable; @@ -759,6 +667,7 @@ HRESULT Progress::init(BOOL aCancelable, return rc; } + /** * Uninitializes the instance and sets the ready flag to FALSE. * @@ -783,9 +692,23 @@ void Progress::uninit() RTSemEventMultiDestroy(mCompletedSem); - ProgressBase::protectedUninit(autoUninitSpan); + /* release initiator (effective only if mInitiator has been assigned in + * * init()) */ + unconst(mInitiator).setNull(); + +#if !defined(VBOX_COM_INPROC) + if (mParent) + { + /* remove the added progress on failure to complete the initialization */ + if (autoUninitSpan.initFailed() && mId.isValid() && !mId.isZero()) + mParent->removeProgress(mId.ref()); + + unconst(mParent) = NULL; + } +#endif } + // IProgress properties ///////////////////////////////////////////////////////////////////////////// @@ -962,7 +885,7 @@ STDMETHODIMP Progress::WaitForAsyncProgressCompletion(IProgress *pProgressAsync) * in the meantime more than one async operation was finished. So we * have to loop as long as we reached the same operation count. */ ULONG curOp; - for(;;) + for (;;) { rc = pProgressAsync->COMGETTER(Operation(&curOp)); if (FAILED(rc)) return rc; @@ -1321,571 +1244,3 @@ bool Progress::notifyPointOfNoReturn(void) return true; } -//////////////////////////////////////////////////////////////////////////////// -// CombinedProgress class -//////////////////////////////////////////////////////////////////////////////// - -HRESULT CombinedProgress::FinalConstruct() -{ - HRESULT rc = ProgressBase::FinalConstruct(); - if (FAILED(rc)) return rc; - - mProgress = 0; - mCompletedOperations = 0; - - return BaseFinalConstruct(); -} - -void CombinedProgress::FinalRelease() -{ - uninit(); - BaseFinalRelease(); -} - -// public initializer/uninitializer for internal purposes only -//////////////////////////////////////////////////////////////////////////////// - -/** - * Initializes this object based on individual combined progresses. - * Must be called only from #init()! - * - * @param aAutoInitSpan AutoInitSpan object instantiated by a subclass. - * @param aParent See ProgressBase::init(). - * @param aInitiator See ProgressBase::init(). - * @param aDescription See ProgressBase::init(). - * @param aId See ProgressBase::init(). - */ -HRESULT CombinedProgress::protectedInit(AutoInitSpan &aAutoInitSpan, -#if !defined(VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, OUT_GUID aId) -{ - LogFlowThisFunc(("aDescription={%ls} mProgresses.size()=%d\n", - aDescription, mProgresses.size())); - - HRESULT rc = S_OK; - - rc = ProgressBase::protectedInit(aAutoInitSpan, -#if !defined(VBOX_COM_INPROC) - aParent, -#endif - aInitiator, aDescription, aId); - if (FAILED(rc)) return rc; - - mProgress = 0; /* the first object */ - mCompletedOperations = 0; - - mCompleted = FALSE; - mCancelable = TRUE; /* until any progress returns FALSE */ - mCanceled = FALSE; - - m_cOperations = 0; /* will be calculated later */ - - m_ulCurrentOperation = 0; - rc = mProgresses[0]->COMGETTER(OperationDescription)(m_bstrOperationDescription.asOutParam()); - if (FAILED(rc)) return rc; - - for (size_t i = 0; i < mProgresses.size(); i ++) - { - if (mCancelable) - { - BOOL cancelable = FALSE; - rc = mProgresses[i]->COMGETTER(Cancelable)(&cancelable); - if (FAILED(rc)) return rc; - - if (!cancelable) - mCancelable = FALSE; - } - - { - ULONG opCount = 0; - rc = mProgresses[i]->COMGETTER(OperationCount)(&opCount); - if (FAILED(rc)) return rc; - - m_cOperations += opCount; - } - } - - rc = checkProgress(); - if (FAILED(rc)) return rc; - - return rc; -} - -/** - * Initializes the combined progress object given two normal progress - * objects. - * - * @param aParent See ProgressBase::init(). - * @param aInitiator See ProgressBase::init(). - * @param aDescription See ProgressBase::init(). - * @param aProgress1 First normal progress object. - * @param aProgress2 Second normal progress object. - * @param aId See ProgressBase::init(). - */ -HRESULT CombinedProgress::init( -#if !defined(VBOX_COM_INPROC) - VirtualBox *aParent, -#endif - IUnknown *aInitiator, - CBSTR aDescription, - IProgress *aProgress1, - IProgress *aProgress2, - OUT_GUID aId /* = NULL */) -{ - /* Enclose the state transition NotReady->InInit->Ready */ - AutoInitSpan autoInitSpan(this); - AssertReturn(autoInitSpan.isOk(), E_FAIL); - - mProgresses.resize(2); - mProgresses[0] = aProgress1; - mProgresses[1] = aProgress2; - - HRESULT rc = protectedInit(autoInitSpan, -#if !defined(VBOX_COM_INPROC) - aParent, -#endif - aInitiator, - aDescription, - aId); - - /* Confirm a successful initialization when it's the case */ - if (SUCCEEDED(rc)) - autoInitSpan.setSucceeded(); - - return rc; -} - -/** - * Uninitializes the instance and sets the ready flag to FALSE. - * - * Called either from FinalRelease() or by the parent when it gets destroyed. - */ -void CombinedProgress::uninit() -{ - LogFlowThisFunc(("\n")); - - /* Enclose the state transition Ready->InUninit->NotReady */ - AutoUninitSpan autoUninitSpan(this); - if (autoUninitSpan.uninitDone()) - return; - - mProgress = 0; - mProgresses.clear(); - - ProgressBase::protectedUninit(autoUninitSpan); -} - -// IProgress properties -//////////////////////////////////////////////////////////////////////////////// - -STDMETHODIMP CombinedProgress::COMGETTER(Percent)(ULONG *aPercent) -{ - CheckComArgOutPointerValid(aPercent); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (mCompleted && SUCCEEDED(mResultCode)) - *aPercent = 100; - else - { - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - /* global percent = - * (100 / m_cOperations) * mOperation + - * ((100 / m_cOperations) / 100) * m_ulOperationPercent */ - *aPercent = (100 * m_ulCurrentOperation + m_ulOperationPercent) / m_cOperations; - } - - return S_OK; -} - -STDMETHODIMP CombinedProgress::COMGETTER(Completed)(BOOL *aCompleted) -{ - CheckComArgOutPointerValid(aCompleted); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(Completed)(aCompleted); -} - -STDMETHODIMP CombinedProgress::COMGETTER(Canceled)(BOOL *aCanceled) -{ - CheckComArgOutPointerValid(aCanceled); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(Canceled)(aCanceled); -} - -STDMETHODIMP CombinedProgress::COMGETTER(ResultCode)(LONG *aResultCode) -{ - CheckComArgOutPointerValid(aResultCode); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(ResultCode)(aResultCode); -} - -STDMETHODIMP CombinedProgress::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo) -{ - CheckComArgOutPointerValid(aErrorInfo); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(ErrorInfo)(aErrorInfo); -} - -STDMETHODIMP CombinedProgress::COMGETTER(Operation)(ULONG *aOperation) -{ - CheckComArgOutPointerValid(aOperation); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(Operation)(aOperation); -} - -STDMETHODIMP CombinedProgress::COMGETTER(OperationDescription)(BSTR *aOperationDescription) -{ - CheckComArgOutPointerValid(aOperationDescription); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(OperationDescription)(aOperationDescription); -} - -STDMETHODIMP CombinedProgress::COMGETTER(OperationPercent)(ULONG *aOperationPercent) -{ - CheckComArgOutPointerValid(aOperationPercent); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* checkProgress needs a write lock */ - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - HRESULT rc = checkProgress(); - if (FAILED(rc)) return rc; - - return ProgressBase::COMGETTER(OperationPercent)(aOperationPercent); -} - -STDMETHODIMP CombinedProgress::COMSETTER(Timeout)(ULONG aTimeout) -{ - NOREF(aTimeout); - AssertFailed(); - return E_NOTIMPL; -} - -STDMETHODIMP CombinedProgress::COMGETTER(Timeout)(ULONG *aTimeout) -{ - CheckComArgOutPointerValid(aTimeout); - - AssertFailed(); - return E_NOTIMPL; -} - -// IProgress methods -///////////////////////////////////////////////////////////////////////////// - -/** - * @note XPCOM: when this method is called not on the main XPCOM thread, it - * simply blocks the thread until mCompletedSem is signalled. If the - * thread has its own event queue (hmm, what for?) that it must run, then - * calling this method will definitely freeze event processing. - */ -STDMETHODIMP CombinedProgress::WaitForCompletion(LONG aTimeout) -{ - LogFlowThisFuncEnter(); - LogFlowThisFunc(("aTtimeout=%d\n", aTimeout)); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - /* if we're already completed, take a shortcut */ - if (!mCompleted) - { - HRESULT rc = S_OK; - bool forever = aTimeout < 0; - int64_t timeLeft = aTimeout; - int64_t lastTime = RTTimeMilliTS(); - - while (!mCompleted && (forever || timeLeft > 0)) - { - alock.release(); - rc = mProgresses.back()->WaitForCompletion(forever ? -1 : (LONG) timeLeft); - alock.acquire(); - - if (SUCCEEDED(rc)) - rc = checkProgress(); - - if (FAILED(rc)) break; - - if (!forever) - { - int64_t now = RTTimeMilliTS(); - timeLeft -= now - lastTime; - lastTime = now; - } - } - - if (FAILED(rc)) return rc; - } - - LogFlowThisFuncLeave(); - - return S_OK; -} - -/** - * @note XPCOM: when this method is called not on the main XPCOM thread, it - * simply blocks the thread until mCompletedSem is signalled. If the - * thread has its own event queue (hmm, what for?) that it must run, then - * calling this method will definitely freeze event processing. - */ -STDMETHODIMP CombinedProgress::WaitForOperationCompletion(ULONG aOperation, LONG aTimeout) -{ - LogFlowThisFuncEnter(); - LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout)); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (aOperation >= m_cOperations) - return setError(E_FAIL, - tr("Operation number must be in range [0, %d]"), m_ulCurrentOperation - 1); - - /* if we're already completed or if the given operation is already done, - * then take a shortcut */ - if (!mCompleted && aOperation >= m_ulCurrentOperation) - { - HRESULT rc = S_OK; - - /* find the right progress object to wait for */ - size_t progress = mProgress; - ULONG operation = 0, completedOps = mCompletedOperations; - do - { - ULONG opCount = 0; - rc = mProgresses[progress]->COMGETTER(OperationCount)(&opCount); - if (FAILED(rc)) - return rc; - - if (completedOps + opCount > aOperation) - { - /* found the right progress object */ - operation = aOperation - completedOps; - break; - } - - completedOps += opCount; - progress ++; - ComAssertRet(progress < mProgresses.size(), E_FAIL); - } - while (1); - - LogFlowThisFunc(("will wait for mProgresses [%d] (%d)\n", - progress, operation)); - - bool forever = aTimeout < 0; - int64_t timeLeft = aTimeout; - int64_t lastTime = RTTimeMilliTS(); - - while (!mCompleted && aOperation >= m_ulCurrentOperation && - (forever || timeLeft > 0)) - { - alock.release(); - /* wait for the appropriate progress operation completion */ - rc = mProgresses[progress]-> WaitForOperationCompletion(operation, - forever ? -1 : (LONG) timeLeft); - alock.acquire(); - - if (SUCCEEDED(rc)) - rc = checkProgress(); - - if (FAILED(rc)) break; - - if (!forever) - { - int64_t now = RTTimeMilliTS(); - timeLeft -= now - lastTime; - lastTime = now; - } - } - - if (FAILED(rc)) return rc; - } - - LogFlowThisFuncLeave(); - - return S_OK; -} - -STDMETHODIMP CombinedProgress::Cancel() -{ - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (!mCancelable) - return setError(E_FAIL, tr("Operation cannot be canceled")); - - if (!mCanceled) - { - LogThisFunc(("Canceling\n")); - mCanceled = TRUE; -/** @todo Teleportation: Shouldn't this be propagated to mProgresses? If - * powerUp creates passes a combined progress object to the client, I - * won't get called back since I'm only getting the powerupProgress ... - * Or what? */ - if (m_pfnCancelCallback) - m_pfnCancelCallback(m_pvCancelUserArg); - - } - else - LogThisFunc(("Already canceled\n")); - - return S_OK; -} - -// private methods -//////////////////////////////////////////////////////////////////////////////// - -/** - * Fetches the properties of the current progress object and, if it is - * successfully completed, advances to the next uncompleted or unsuccessfully - * completed object in the vector of combined progress objects. - * - * @note Must be called from under this object's write lock! - */ -HRESULT CombinedProgress::checkProgress() -{ - /* do nothing if we're already marked ourselves as completed */ - if (mCompleted) - return S_OK; - - AssertReturn(mProgress < mProgresses.size(), E_FAIL); - - ComPtr<IProgress> progress = mProgresses[mProgress]; - ComAssertRet(!progress.isNull(), E_FAIL); - - HRESULT rc = S_OK; - BOOL fCompleted = FALSE; - - do - { - rc = progress->COMGETTER(Completed)(&fCompleted); - if (FAILED(rc)) - return rc; - - if (fCompleted) - { - rc = progress->COMGETTER(Canceled)(&mCanceled); - if (FAILED(rc)) - return rc; - - LONG iRc; - rc = progress->COMGETTER(ResultCode)(&iRc); - if (FAILED(rc)) - return rc; - mResultCode = iRc; - - if (FAILED(mResultCode)) - { - rc = progress->COMGETTER(ErrorInfo)(mErrorInfo.asOutParam()); - if (FAILED(rc)) - return rc; - } - - if (FAILED(mResultCode) || mCanceled) - { - mCompleted = TRUE; - } - else - { - ULONG opCount = 0; - rc = progress->COMGETTER(OperationCount)(&opCount); - if (FAILED(rc)) - return rc; - - mCompletedOperations += opCount; - mProgress ++; - - if (mProgress < mProgresses.size()) - progress = mProgresses[mProgress]; - else - mCompleted = TRUE; - } - } - } - while (fCompleted && !mCompleted); - - rc = progress->COMGETTER(OperationPercent)(&m_ulOperationPercent); - if (SUCCEEDED(rc)) - { - ULONG operation = 0; - rc = progress->COMGETTER(Operation)(&operation); - if (SUCCEEDED(rc) && mCompletedOperations + operation > m_ulCurrentOperation) - { - m_ulCurrentOperation = mCompletedOperations + operation; - rc = progress->COMGETTER(OperationDescription)(m_bstrOperationDescription.asOutParam()); - } - } - - return rc; -} -/* vi: set tabstop=4 shiftwidth=4 expandtab: */ |