ProgressImpl.cpp revision 7e0127386476802a0c4ed41530a4f50e7c05eb14
202N/A * VirtualBox Progress COM class implementation 202N/A * Copyright (C) 2006-2013 Oracle Corporation 202N/A * This file is part of VirtualBox Open Source Edition (OSE), as 202N/A * you can redistribute it and/or modify it under the terms of the GNU 202N/A * General Public License (GPL) as published by the Free Software 202N/A * Foundation, in version 2 as it comes in the "COPYING" file of the 202N/A * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 202N/A * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 921N/A#
endif /* defined(VBOX_WITH_XPCOM) */ 202N/A///////////////////////////////////////////////////////////////////////////// 202N/A /* mId is constant during life time, no need to lock */ 202N/A /* mDescription is constant during life time, no need to lock */ * Internal helper to compute the total percent value based on the member values and * returns it as a "double". This is used both by GetPercent (which returns it as a * rounded ULONG) and GetTimeRemaining(). * Requires locking by the caller! * @return fractional percentage as a double value. // avoid division by zero * Internal helper for automatically timing out the operation. * The caller should hold the object write lock. // LogFunc(("dPercentDone = %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n", // (uint32_t)dPercentDone, ullTimeNow, ullTimeElapsed, ullTimeTotal, ullTimeRemaining)); /* checkForAutomaticTimeout requires a write lock. */ // do not report 100% until we're really really done with everything as the Qt GUI dismisses progress dialogs in that case tr(
"Result code is not available, operation is still in progress"));
tr(
"Error info is not available, operation is still in progress"));
tr(
"Operation cannot be canceled"));
// public methods only for internal purposes //////////////////////////////////////////////////////////////////////////////// * Sets the cancelation callback, checking for cancelation first. * @returns Success indicator. * @retval true on success. * @retval false if the progress object has already been canceled or is in an * @param pfnCallback The function to be called upon cancelation. * @param pvUser The callback argument. // get creation timestamp //////////////////////////////////////////////////////////////////////////////// * Initializes the normal progress object. With this variant, one can have * an arbitrary number of sub-operation which IProgress can analyze to * have a weighted progress computed. * For example, say that one IProgress is supposed to track the cloning * of two hard disk images, which are 100 MB and 1000 MB in size, respectively, * and each of these hard disks should be one sub-operation of the IProgress. * Obviously the progress would be misleading if the progress displayed 50% * after the smaller image was cloned and would then take much longer for * With weighted progress, one can invoke the following calls: * 1) create progress object with cOperations = 2 and ulTotalOperationsWeight = * 1100 (100 MB plus 1100, but really the weights can be any ULONG); pass * in ulFirstOperationWeight = 100 for the first sub-operation * 2) Then keep calling setCurrentOperationProgress() with a percentage * for the first image; the total progress will increase up to a value * of 9% (100MB / 1100MB * 100%). * 3) Then call setNextOperation with the second weight (1000 for the megabytes * 4) Then keep calling setCurrentOperationProgress() with a percentage for * the second image, where 100% of the operation will then yield a 100% * progress of the entire task. * Weighting is optional; you can simply assign a weight of 1 to each operation * and pass ulTotalOperationsWeight == cOperations to this constructor (but * for that variant and for backwards-compatibility a simpler constructor exists * Even simpler, if you need no sub-operations at all, pass in cOperations = * ulTotalOperationsWeight = ulFirstOperationWeight = 1. * @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 Progress::init(). LogFlowThisFunc((
"aDescription=\"%s\", cOperations=%d, ulTotalOperationsWeight=%d, aFirstOperationDescription=\"%s\", ulFirstOperationWeight=%d\n",
/* Enclose the state transition NotReady->InInit->Ready */ //#if !defined(VBOX_COM_INPROC) // aInitiator, aDescription, FALSE, aId); /* share parent weakly */ /* 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 */ /* add to the global collection of progress operations (note: after /* Confirm a successful initialization when it's the case */ * Initializes the sub-progress object that represents a specific operation of * Objects initialized with this method are then combined together into 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 * store individual operation descriptions. * @param aCancelable Flag whether the task maybe canceled. * @param aOperationCount Number of sub-operations within this task (at least 1). * @param aOperationDescription Description of the individual operation. /* Enclose the state transition NotReady->InInit->Ready */ /* Guarantees subclasses call this method at the proper time */ // for this variant we assume for now that all operations are weighed "1" // and equal total weight = operation count /* Confirm a successful initialization when it's the case */ * Uninitializes the instance and sets the ready flag to FALSE. * Called either from FinalRelease() or by the parent when it gets destroyed. /* Enclose the state transition Ready->InUninit->NotReady */ /* wake up all threads still waiting on occasion */ LogFlow((
"WARNING: There are still %d threads waiting for '%s' completion!\n",
/* release initiator (effective only if mInitiator has been assigned in /* remove the added progress on failure to complete the initialization */ ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// * @note XPCOM: when this method is not called 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. /* if we're already completed, take a shortcut */ /* the last waiter resets the semaphore */ tr(
"Failed to wait for the task completion (%Rrc)"),
* @note XPCOM: when this method is not called 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. /* if we're already completed or if the given operation is already done, * then take a shortcut */ /* the last waiter resets the semaphore */ tr(
"Failed to wait for the operation completion (%Rrc)"),
/* Note: we don't lock here, cause we just using public methods. */ /* Is the async process cancelable? */ /* Loop as long as the sync process isn't completed. */ /* We can forward any cancel request to the async process only when /* Even if the user canceled the process, we have to wait until the async task has finished his work (cleanup and such). Otherwise there will be sync trouble (still wrong state, dead locks, ...) on the used objects. So just do nothing, but wait for the complete /* Check if the current operation has changed. It is also possible that * in the meantime more than one async operation was finished. So we * have to loop as long as we reached the same operation count. */ /* Make sure the loop is not too tight */ tr(
"Operation cannot be canceled"));
* Updates the percentage value of the current operation. * @param aPercent New percentage value of the operation in progress * Signals that the current operation is successfully completed and advances to * the next operation. The operation percentage is reset to 0. * @param aOperationDescription Description of the next operation. * @note The current operation must not be the last one. Log((
"Progress::setNextOperation(%s): aNextOperationsWeight = %d; m_ulCurrentOperation is now %d, m_ulOperationsCompletedWeight is now %d\n",
/* wake up all waiting threads */ // public methods only for internal purposes ///////////////////////////////////////////////////////////////////////////// * Sets the internal result code and attempts to retrieve additional error * info from the current thread. Gets called from Progress::notifyComplete(), * but can be called again to override a previous result set with /* try to import error info from the current thread */ #
else /* !defined(VBOX_WITH_XPCOM) */#
endif /* !defined(VBOX_WITH_XPCOM) */ AssertMsg(
rc ==
S_OK, (
"Couldn't get error info (rc=%08X) while trying to set a failed result (%08X)!\n",
* Marks the whole task as complete and sets the result code. * If the result code indicates a failure (|FAILED(@a aResultCode)|) then this * method will import the error info from the current thread and assign it to * the errorInfo attribute (it will return an error if no info is available in * If the result code indicates a success (|SUCCEEDED(@a aResultCode)|) then * the current operation is set to the last. * Note that this method may be called only once for the given Progress object. * Subsequent calls will assert. * @param aResultCode Operation result code. /* remove from the global collection of pending progress operations */ /* wake up all waiting threads */ * Wrapper around Progress:notifyCompleteV. * Marks the operation as complete and attaches full error info. * See VirtualBoxBase::setError(HRESULT, const GUID &, const wchar_t * *, const char *, ...) for more info. * @param aResultCode Operation result (error) code, must not be S_OK. * @param aIID IID of the interface that defines the error. * @param aComponent Name of the component that generates the error. * @param aText Error message (must not be null), an RTStrPrintf-like * format string in UTF-8 encoding. * @param va List of arguments for the format string. /* remove from the global collection of pending progress operations */ /* wake up all waiting threads */ * Notify the progress object that we're almost at the point of no return. * This atomically checks for and disables cancelation. Calls to * IProgress::Cancel() made after a successful call to this method will fail * and the user can be told. While this isn't entirely clean behavior, it * prevents issues with an irreversible actually operation succeeding while the * user believe it was rolled back. * @returns Success indicator. * @retval true on success. * @retval false if the progress object has already been canceled or is in an