ProgressProxyImpl.cpp revision c58f1213e628a545081c70e26c6b67a841cff880
/* $Id$ */
/** @file
* IProgress implementation for Machine::openRemoteSession in VBoxSVC.
*/
/*
* Copyright (C) 2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#if defined (VBOX_WITH_XPCOM)
#include <nsIServiceManager.h>
#include <nsIExceptionService.h>
#include <nsCOMPtr.h>
#endif /* defined (VBOX_WITH_XPCOM) */
#include "ProgressProxyImpl.h"
#include "VirtualBoxImpl.h"
#include "VirtualBoxErrorInfoImpl.h"
#include "Logging.h"
#include <iprt/semaphore.h>
////////////////////////////////////////////////////////////////////////////////
// ProgressProxy class
////////////////////////////////////////////////////////////////////////////////
// constructor / destructor / uninitializer
////////////////////////////////////////////////////////////////////////////////
{
mfMultiOperation = false;
return rc;
}
/**
* Initialize it as a one operation Progress object.
*
* This is used by SessionMachine::OnSessionEnd.
*/
#if !defined (VBOX_COM_INPROC)
#endif
{
mfMultiOperation = false;
#if !defined (VBOX_COM_INPROC)
#endif
1 /* cOperations */,
1 /* ulTotalOperationsWeight */,
bstrDescription /* bstrFirstOperationDescription */,
1 /* ulFirstOperationWeight */,
NULL /* pId */);
}
/**
* Initialize for proxying one other progress object.
*
* This is tailored explicitly for the openRemoteSession code, so we start out
* with one operation where we don't have any remote object (powerUp). Then a
* remote object is added and stays with us till the end.
*
* The user must do normal completion notification or risk leave the threads
* waiting forever!
*/
#if !defined (VBOX_COM_INPROC)
#endif
{
mfMultiOperation = false;
#if !defined (VBOX_COM_INPROC)
#endif
NULL);
}
void ProgressProxy::FinalRelease()
{
uninit();
mfMultiOperation = false;
}
void ProgressProxy::uninit()
{
LogFlowThisFunc(("\n"));
}
// Public methods
////////////////////////////////////////////////////////////////////////////////
/** Just a wrapper so we can automatically do the handover before setting
* the result locally. */
{
clearOtherProgressObjectInternal(true /* fEarly */);
if (!mCompleted)
return hrc;
}
/** Just a wrapper so we can automatically do the handover before setting
* the result locally. */
const char *pcszComponent,
const char *aText,
...)
{
clearOtherProgressObjectInternal(true /* fEarly */);
if (!mCompleted)
{
}
return hrc;
}
/**
* Sets the other progress object unless the operation has been completed /
* canceled already.
*
* @param pOtherProgress The other progress object. Must not be NULL.
*/
{
/*
* Query information from the other progress object before we grab the
* lock.
*/
cOperations = 1;
bstrOperationDescription = "oops";
/*
* Take the lock and check for cancelation, cancel the other object if
* we've been canceled already.
*/
if (!fCompletedOrCanceled)
{
/*
* Advance to the next object and operation. If the other object has
* more operations than anticipated, adjust our internal count.
*/
/*
* Check for cancelation and completion.
*/
BOOL f;
if (!fCompletedOrCanceled)
{
}
if (fCompletedOrCanceled)
{
LogFlowThisFunc(("Other object completed or canceled, clearing...\n"));
clearOtherProgressObjectInternal(false /*fEarly*/);
}
else
{
/*
* Finally, mirror the cancelable property.
* Note! Note necessary if we do passthru!
*/
if (mCancelable)
{
{
LogFlowThisFunc(("The other progress object is not cancelable\n"));
mCancelable = FALSE;
}
}
}
}
else
{
LogFlowThisFunc(("mCompleted=%RTbool mCanceled=%RTbool - Canceling the other progress object!\n",
mCompleted, mCanceled));
}
return !fCompletedOrCanceled;
}
// Internal methods.
////////////////////////////////////////////////////////////////////////////////
/**
* Clear the other progress object reference, first copying over its state.
*
* This is used internally when completion is signalled one way or another.
*
* @param fEarly Early clearing or not.
*/
{
if (!mptrOtherProgress.isNull())
{
}
}
/**
* Called to copy over the progress information from @a pOtherProgress.
*
* @param pOtherProgress The source of the information.
* @param fEarly Early copy.
*
* @note The caller owns the write lock and as cleared mptrOtherProgress
* already (or we might recurse forever)!
*/
{
LogFlowThisFunc(("\n"));
/*
* No point in doing this if the progress object was canceled already.
*/
if (!mCanceled)
{
/* Detect if the other progress object was canceled. */
if (fCanceled)
{
LogFlowThisFunc(("Canceled\n"));
if (m_pfnCancelCallback)
}
else
{
/* Has it completed? */
fCompleted = TRUE;
if (fCompleted)
{
/* Check the result. */
LogFlowThisFunc(("Succeeded\n"));
else
{
/* Get the error information. */
{
bstrComponent = "failed";
bstrText = "<failed>";
}
else
{
"ProgressProxy",
tr("No error info"));
}
}
}
else
LogFlowThisFunc(("Not completed\n"));
}
}
else
LogFlowThisFunc(("Already canceled\n"));
/*
* Did cancelable state change (point of no return)?
*/
{
{
LogFlowThisFunc(("point-of-no-return reached\n"));
mCancelable = FALSE;
}
}
}
// IProgress properties
////////////////////////////////////////////////////////////////////////////////
{
AutoCaller autoCaller(this);
{
/* ASSUME: The cancelable property can only change to FALSE. */
else
{
{
LogFlowThisFunc(("point-of-no-return reached\n"));
mCancelable = FALSE;
}
}
}
return hrc;
}
{
AutoCaller autoCaller(this);
{
if (mptrOtherProgress.isNull())
else
{
/*
* Get the overall percent of the other object and adjust it with
* the weighting given to the period before proxying started.
*/
{
/ m_ulTotalOperationsWeight * 100;
*aPercent = RT_MIN((ULONG)rdPercent, 99); /* mptrOtherProgress is cleared when its completed, so we can never return 100%. */
}
}
}
return hrc;
}
{
AutoCaller autoCaller(this);
{
if (mptrOtherProgress.isNull())
else
}
return hrc;
}
{
/* Not proxied since we EXPECT a normal completion notification call. */
}
{
AutoCaller autoCaller(this);
{
/* Check the local data first, then the other object. */
&& !*aCanceled
&& !mptrOtherProgress.isNull()
&& mCancelable)
{
/* This will not complete the object, only mark it as canceled. */
clearOtherProgressObjectInternal(false /*fEarly*/);
}
}
return hrc;
}
{
/* Not proxied since we EXPECT a normal completion notification call. */
}
{
/* Not proxied since we EXPECT a normal completion notification call. */
}
{
AutoCaller autoCaller(this);
{
if (mptrOtherProgress.isNull())
else
{
}
}
return hrc;
}
{
AutoCaller autoCaller(this);
{
else
}
return hrc;
}
{
AutoCaller autoCaller(this);
{
else
}
return hrc;
}
{
/* Not currently supported. */
AssertFailed();
return E_NOTIMPL;
}
{
/* Not currently supported. */
AssertFailed();
return E_NOTIMPL;
}
// IProgress methods
/////////////////////////////////////////////////////////////////////////////
{
/* No need to wait on the proxied object for these since we'll get the
normal completion notifications. */
return hrc;
}
{
AutoCaller autoCaller(this);
{
/*
* Check if we can wait locally.
*/
|| mptrOtherProgress.isNull())
{
/* ASSUMES that Progress::WaitForOperationCompletion is using
AutoWriteLock::leave() as it saves us from duplicating the code! */
}
else
{
LogFlowThisFunc(("calling the other object...\n"));
}
}
return hrc;
}
{
LogFlowThisFunc(("\n"));
AutoCaller autoCaller(this);
{
else
{
clearOtherProgressObjectInternal(false /*fEarly*/);
}
}
return hrc;
}
{
/* Not supported - why do we actually expose this? */
return E_NOTIMPL;
}
STDMETHODIMP ProgressProxy::SetNextOperation(IN_BSTR bstrNextOperationDescription, ULONG ulNextOperationsWeight)
{
/* Not supported - why do we actually expose this? */
return E_NOTIMPL;
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */