Changeset 29934 in vbox for trunk/src/VBox/Main/ProgressProxyImpl.cpp
- Timestamp:
- Jun 1, 2010 6:39:21 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/ProgressProxyImpl.cpp
r29932 r29934 46 46 HRESULT ProgressProxy::FinalConstruct() 47 47 { 48 mfMultiOperation = false; 49 muOtherProgressStartWeight = 0; 50 muOtherProgressWeight = 0; 51 muOtherProgressStartOperation = 0; 48 mcOtherProgressObjects = 1; 49 miCurOtherProgressObject = 0; 52 50 53 51 HRESULT rc = Progress::FinalConstruct(); … … 68 66 BOOL fCancelable) 69 67 { 70 mfMultiOperation = false; 71 muOtherProgressStartWeight = 1; 72 muOtherProgressWeight = 1; 73 muOtherProgressStartOperation = 1; 68 miCurOtherProgressObject = 0; 69 mcOtherProgressObjects = 0; 74 70 75 71 return Progress::init( … … 88 84 89 85 /** 90 * Initialize for proxying one other progress object. 91 * 92 * This is tailored explicitly for the openRemoteSession code, so we start out 93 * with one operation where we don't have any remote object (powerUp). Then a 94 * remote object is added and stays with us till the end. 95 * 96 * The user must do normal completion notification or risk leave the threads 97 * waiting forever! 86 * Initialize for proxying one or more other objects, assuming we start out and 87 * end without proxying anyone. 88 * 89 * The user must call clearOtherProgressObject when there are no more progress 90 * objects to be proxied or we'll leave threads waiting forever. 98 91 */ 99 92 HRESULT ProgressProxy::init( … … 104 97 CBSTR bstrDescription, 105 98 BOOL fCancelable, 99 ULONG cOtherProgressObjects, 106 100 ULONG uTotalOperationsWeight, 107 101 CBSTR bstrFirstOperationDescription, 108 102 ULONG uFirstOperationWeight, 109 ULONG cOtherProgressObjectOperations) 110 { 111 mfMultiOperation = false; 112 muOtherProgressStartWeight = uFirstOperationWeight; 113 muOtherProgressWeight = uTotalOperationsWeight - uFirstOperationWeight; 114 muOtherProgressStartOperation = 1; 103 OUT_GUID pId) 104 { 105 miCurOtherProgressObject = 0; 106 mcOtherProgressObjects = cOtherProgressObjects; 115 107 116 108 return Progress::init( … … 121 113 bstrDescription, 122 114 fCancelable, 123 1 + cOtherProgressObject Operations/* cOperations */,115 1 + cOtherProgressObjects + 1 /* cOperations */, 124 116 uTotalOperationsWeight, 125 117 bstrFirstOperationDescription, 126 118 uFirstOperationWeight, 127 NULL);119 pId); 128 120 } 129 121 … … 131 123 { 132 124 uninit(); 133 mfMultiOperation = false; 134 muOtherProgressStartWeight = 0; 135 muOtherProgressWeight = 0; 136 muOtherProgressStartOperation = 0; 125 miCurOtherProgressObject = 0; 137 126 } 138 127 … … 186 175 /** Just a wrapper so we can automatically do the handover before setting 187 176 * the result locally. */ 188 bool ProgressProxy::notifyPointOfNoReturn(void)177 bool ProgressProxy::notifyPointOfNoReturn(void) 189 178 { 190 179 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); … … 199 188 * @returns false if failed/canceled, true if not. 200 189 * @param pOtherProgress The other progress object. Must not be NULL. 201 */ 202 bool ProgressProxy::setOtherProgressObject(IProgress *pOtherProgress) 203 { 204 LogFlowThisFunc(("setOtherProgressObject: %p\n", pOtherProgress)); 190 * @param uOperationWeight The weight of this operation. (The description 191 * is taken from the other progress object.) 192 */ 193 bool ProgressProxy::setOtherProgressObject(IProgress *pOtherProgress, ULONG uOperationWeight) 194 { 195 LogFlowThisFunc(("setOtherProgressObject: %p %u\n", pOtherProgress, uOperationWeight)); 205 196 ComPtr<IProgress> ptrOtherProgress = pOtherProgress; 206 197 207 /* 208 * Query information from the other progress object before we grab the 209 * lock. 210 */ 211 ULONG cOperations; 212 HRESULT hrc = pOtherProgress->COMGETTER(OperationCount)(&cOperations); 213 if (FAILED(hrc)) 214 cOperations = 1; 215 216 Bstr bstrOperationDescription; 217 hrc = pOtherProgress->COMGETTER(Description)(bstrOperationDescription.asOutParam()); 198 /* Get the description first. */ 199 Bstr bstrOperationDescription; 200 HRESULT hrc = pOtherProgress->COMGETTER(Description)(bstrOperationDescription.asOutParam()); 218 201 if (FAILED(hrc)) 219 202 bstrOperationDescription = "oops"; 220 203 221 222 /*223 * Take the lock and check for cancelation, cancel the other object if224 * we've been canceled already.225 */226 204 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 227 205 206 /* Do the hand over from any previous progress object. */ 207 clearOtherProgressObjectInternal(false /*fEarly*/); 228 208 BOOL fCompletedOrCanceled = mCompleted || mCanceled; 229 209 if (!fCompletedOrCanceled) 230 210 { 231 /* 232 * Advance to the next object and operation. If the other object has 233 * more operations than anticipated, adjust our internal count. 234 */ 211 /* Advance to the next object and operation, checking for cancelation 212 and completion right away to be on the safe side. */ 213 Assert(miCurOtherProgressObject < mcOtherProgressObjects); 235 214 mptrOtherProgress = ptrOtherProgress; 236 mfMultiOperation = cOperations > 1; 237 238 muOtherProgressStartWeight = m_ulOperationsCompletedWeight + m_ulCurrentOperationWeight; 239 muOtherProgressWeight = m_ulTotalOperationsWeight - muOtherProgressStartWeight; 240 Progress::SetNextOperation(bstrOperationDescription, muOtherProgressWeight); 241 242 muOtherProgressStartOperation = m_ulCurrentOperation; 243 m_cOperations = cOperations + m_ulCurrentOperation; 244 245 /* 246 * Check for cancelation and completion. 247 */ 215 216 Progress::SetNextOperation(bstrOperationDescription, uOperationWeight); 217 248 218 BOOL f; 249 219 hrc = ptrOtherProgress->COMGETTER(Completed)(&f); … … 263 233 else 264 234 { 265 /* 266 * Finally, mirror the cancelable property. 267 * Note! Note necessary if we do passthru! 268 */ 235 /* Mirror the cancelable property. */ 269 236 if (mCancelable) 270 237 { … … 290 257 } 291 258 259 /** 260 * Clears the last other progress objects. 261 * 262 * @returns false if failed/canceled, true if not. 263 * @param pszLastOperationDescription The description of the final bit. 264 * @param uLastOperationWeight The weight of the final bit. 265 */ 266 bool ProgressProxy::clearOtherProgressObject(const char *pszLastOperationDescription, ULONG uLastOperationWeight) 267 { 268 LogFlowThisFunc(("%p %u\n", pszLastOperationDescription, uLastOperationWeight)); 269 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 270 271 clearOtherProgressObjectInternal(false /* fEarly */); 272 273 /* Advance to the next operation if applicable. */ 274 bool fCompletedOrCanceled = mCompleted || mCanceled; 275 if (!fCompletedOrCanceled) 276 Progress::SetNextOperation(Bstr(pszLastOperationDescription), uLastOperationWeight); 277 278 LogFlowThisFunc(("Returns %RTbool\n", !fCompletedOrCanceled)); 279 return !fCompletedOrCanceled; 280 } 281 292 282 // Internal methods. 293 283 //////////////////////////////////////////////////////////////////////////////// … … 295 285 296 286 /** 297 * Clear the other progress object reference, first copying over its state. 298 * 299 * This is used internally when completion is signalled one way or another. 287 * Internal version of clearOtherProgressObject that doesn't advance to the next 288 * operation. 289 * 290 * This is used both by clearOtherProgressObject as well as a number of places 291 * where we automatically do the hand over because of failure/completion. 300 292 * 301 293 * @param fEarly Early clearing or not. … … 303 295 void ProgressProxy::clearOtherProgressObjectInternal(bool fEarly) 304 296 { 305 if ( mptrOtherProgress.isNotNull())297 if (!mptrOtherProgress.isNull()) 306 298 { 307 299 ComPtr<IProgress> ptrOtherProgress = mptrOtherProgress; 308 300 mptrOtherProgress.setNull(); 309 301 copyProgressInfo(ptrOtherProgress, fEarly); 302 303 miCurOtherProgressObject++; 304 Assert(miCurOtherProgressObject <= mcOtherProgressObjects); 310 305 } 311 306 } … … 418 413 //////////////////////////////////////////////////////////////////////////////// 419 414 420 STDMETHODIMP ProgressProxy::COMGETTER(Cancelable)(BOOL *aCancelable) 421 { 422 CheckComArgOutPointerValid(aCancelable); 415 STDMETHODIMP ProgressProxy::COMGETTER(Percent)(ULONG *aPercent) 416 { 417 #if 0 418 CheckComArgOutPointerValid(aPercent); 423 419 424 420 AutoCaller autoCaller(this); 425 421 HRESULT hrc = autoCaller.rc(); 426 if (SUCCEEDED( hrc))422 if (SUCCEEDED(rc)) 427 423 { 428 424 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 429 425 430 /* ASSUME: The cancelable property can only change to FALSE. */ 431 if (!mCancelable || mptrOtherProgress.isNull()) 432 *aCancelable = mCancelable; 433 else 434 { 435 hrc = mptrOtherProgress->COMGETTER(Cancelable)(aCancelable); 436 if (SUCCEEDED(hrc) && !*aCancelable) 437 { 438 LogFlowThisFunc(("point-of-no-return reached\n")); 439 mCancelable = FALSE; 440 } 441 } 442 } 443 return hrc; 444 } 445 446 STDMETHODIMP ProgressProxy::COMGETTER(Percent)(ULONG *aPercent) 447 { 448 CheckComArgOutPointerValid(aPercent); 449 450 AutoCaller autoCaller(this); 451 HRESULT hrc = autoCaller.rc(); 452 if (SUCCEEDED(hrc)) 453 { 454 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 455 456 if (mptrOtherProgress.isNotNull()) 426 if (mptrOtherProgress.isNull()) 457 427 hrc = Progress::COMGETTER(Percent)(aPercent); 458 428 else 459 429 { 460 /*461 * Get the overall percent of the other object and adjust it with462 * the weighting given to the period before proxying started.463 */464 430 ULONG uPct; 465 431 hrc = mptrOtherProgress->COMGETTER(Percent)(&uPct); 466 if (SUCCEEDED(hrc)) 467 { 468 double rdPercent = ((double)uPct / 100 * muOtherProgressWeight + muOtherProgressStartWeight) 469 / m_ulTotalOperationsWeight * 100; 470 *aPercent = RT_MIN((ULONG)rdPercent, 99); /* mptrOtherProgress is cleared when its completed, so we can never return 100%. */ 471 } 432 .... 472 433 } 473 434 } 474 435 return hrc; 475 } 476 477 STDMETHODIMP ProgressProxy::COMGETTER(TimeRemaining)(LONG *aTimeRemaining) 478 { 479 CheckComArgOutPointerValid(aTimeRemaining); 480 481 AutoCaller autoCaller(this); 482 HRESULT hrc = autoCaller.rc(); 483 if (SUCCEEDED(hrc)) 484 { 485 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 486 487 if (mptrOtherProgress.isNotNull()) 488 hrc = Progress::COMGETTER(TimeRemaining)(aTimeRemaining); 489 else 490 hrc = mptrOtherProgress->COMGETTER(TimeRemaining)(aTimeRemaining); 491 } 492 return hrc; 436 #else 437 return Progress::COMGETTER(Percent)(aPercent); 438 #endif 493 439 } 494 440 495 441 STDMETHODIMP ProgressProxy::COMGETTER(Completed)(BOOL *aCompleted) 496 442 { 497 /* Not proxied since we EXPECT a normal completion notificationcall. */443 /* Not proxied since we EXPECT a hand back call. */ 498 444 return Progress::COMGETTER(Completed)(aCompleted); 499 445 } … … 512 458 if ( SUCCEEDED(hrc) 513 459 && !*aCanceled 514 && mptrOtherProgress.isNotNull() 515 && mCancelable) 460 && !mptrOtherProgress.isNull()) 516 461 { 517 462 hrc = mptrOtherProgress->COMGETTER(Canceled)(aCanceled); 518 463 if (SUCCEEDED(hrc) && *aCanceled) 519 /* This will not complete the object, only mark it as canceled. */ 520 clearOtherProgressObjectInternal(false /*fEarly*/); 464 clearOtherProgressObjectInternal(true /*fEarly*/); 521 465 } 522 466 } … … 526 470 STDMETHODIMP ProgressProxy::COMGETTER(ResultCode)(LONG *aResultCode) 527 471 { 528 /* Not proxied since we EXPECT a normal completion notificationcall. */472 /* Not proxied yet since we EXPECT a hand back call. */ 529 473 return Progress::COMGETTER(ResultCode)(aResultCode); 530 474 } … … 532 476 STDMETHODIMP ProgressProxy::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo) 533 477 { 534 /* Not proxied since we EXPECT a normal completion notificationcall. */478 /* Not proxied yet since we EXPECT a hand back call. */ 535 479 return Progress::COMGETTER(ErrorInfo)(aErrorInfo); 536 480 } 537 481 538 STDMETHODIMP ProgressProxy::COMGETTER(Operation)(ULONG *aOperation)539 {540 CheckComArgOutPointerValid(aOperation);541 542 AutoCaller autoCaller(this);543 HRESULT hrc = autoCaller.rc();544 if (SUCCEEDED(hrc))545 {546 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);547 if (mptrOtherProgress.isNull())548 hrc = Progress::COMGETTER(Operation)(aOperation);549 else550 {551 ULONG uCurOtherOperation;552 hrc = mptrOtherProgress->COMGETTER(Operation)(&uCurOtherOperation);553 if (SUCCEEDED(hrc))554 *aOperation = uCurOtherOperation + muOtherProgressStartOperation;555 }556 }557 return hrc;558 }559 560 STDMETHODIMP ProgressProxy::COMGETTER(OperationDescription)(BSTR *aOperationDescription)561 {562 CheckComArgOutPointerValid(aOperationDescription);563 564 AutoCaller autoCaller(this);565 HRESULT hrc = autoCaller.rc();566 if (SUCCEEDED(hrc))567 {568 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);569 if (mptrOtherProgress.isNull() || !mfMultiOperation)570 hrc = Progress::COMGETTER(OperationDescription)(aOperationDescription);571 else572 hrc = mptrOtherProgress->COMGETTER(OperationDescription)(aOperationDescription);573 }574 return hrc;575 }576 577 482 STDMETHODIMP ProgressProxy::COMGETTER(OperationPercent)(ULONG *aOperationPercent) 578 483 { 579 CheckComArgOutPointerValid(aOperationPercent); 580 581 AutoCaller autoCaller(this); 582 HRESULT hrc = autoCaller.rc(); 583 if (SUCCEEDED(hrc)) 584 { 585 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 586 if (mptrOtherProgress.isNull() || !mfMultiOperation) 587 hrc = Progress::COMGETTER(OperationPercent)(aOperationPercent); 588 else 589 hrc = mptrOtherProgress->COMGETTER(OperationPercent)(aOperationPercent); 590 } 591 return hrc; 484 /* Not proxied, should be proxied later on. */ 485 return Progress::COMGETTER(OperationPercent)(aOperationPercent); 592 486 } 593 487 … … 618 512 LogFlowThisFunc(("aTimeout=%d\n", aTimeout)); 619 513 620 /* No need to wait on the proxied object for these since we'll get the 621 normal completion notifications. */ 514 /* For now we'll always block locally. */ 622 515 hrc = Progress::WaitForCompletion(aTimeout); 623 516 … … 628 521 STDMETHODIMP ProgressProxy::WaitForOperationCompletion(ULONG aOperation, LONG aTimeout) 629 522 { 523 HRESULT hrc; 630 524 LogFlowThisFuncEnter(); 631 525 LogFlowThisFunc(("aOperation=%d aTimeout=%d\n", aOperation, aTimeout)); 632 526 633 AutoCaller autoCaller(this); 634 HRESULT hrc = autoCaller.rc(); 635 if (SUCCEEDED(hrc)) 636 { 637 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 638 639 CheckComArgExpr(aOperation, aOperation < m_cOperations); 640 641 /* 642 * Check if we can wait locally. 643 */ 644 if ( aOperation + 1 == m_cOperations /* final operation */ 645 || mptrOtherProgress.isNull()) 646 { 647 /* ASSUMES that Progress::WaitForOperationCompletion is using 648 AutoWriteLock::leave() as it saves us from duplicating the code! */ 649 hrc = Progress::WaitForOperationCompletion(aOperation, aTimeout); 650 } 651 else 652 { 653 LogFlowThisFunc(("calling the other object...\n")); 654 ComPtr<IProgress> ptrOtherProgress = mptrOtherProgress; 655 alock.release(); 656 657 hrc = ptrOtherProgress->WaitForOperationCompletion(aOperation, aTimeout); 658 } 659 } 527 /* For now we'll always block locally. Later though, we could consider 528 blocking remotely when we can. */ 529 hrc = Progress::WaitForOperationCompletion(aOperation, aTimeout); 660 530 661 531 LogFlowThisFuncLeave(); … … 671 541 { 672 542 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 673 if (mptrOtherProgress.isNull() || !mCancelable) 674 hrc = Progress::Cancel(); 543 if (mCancelable) 544 { 545 if (!mptrOtherProgress.isNull()) 546 { 547 hrc = mptrOtherProgress->Cancel(); 548 if (SUCCEEDED(hrc)) 549 { 550 if (m_pfnCancelCallback) 551 m_pfnCancelCallback(m_pvCancelUserArg); 552 clearOtherProgressObjectInternal(true /*fEarly*/); 553 } 554 } 555 else 556 hrc = Progress::Cancel(); 557 } 675 558 else 676 { 677 hrc = mptrOtherProgress->Cancel(); 678 if (SUCCEEDED(hrc)) 679 clearOtherProgressObjectInternal(false /*fEarly*/); 680 } 559 hrc = setError(E_FAIL, tr("Operation cannot be canceled")); 681 560 } 682 561
Note:
See TracChangeset
for help on using the changeset viewer.