- Timestamp:
- Mar 11, 2016 3:27:55 PM (9 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/AutoCaller.h
r55401 r59996 6 6 7 7 /* 8 * Copyright (C) 2006-201 4Oracle Corporation8 * Copyright (C) 2006-2016 Oracle Corporation 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 334 334 * to the NotReady state using AutoUninitSpan. 335 335 */ 336 void setFailed() { mResult = Failed; } 336 void setFailed(HRESULT rc = E_ACCESSDENIED) 337 { 338 mResult = Failed; 339 mFailedRC = rc; 340 mpFailedEI = new ErrorInfo(); 341 } 337 342 338 343 /** Returns the current initialization result. */ … … 347 352 Result mResult : 3; // must be at least total number of bits + 1 (sign) 348 353 bool mOk : 1; 354 HRESULT mFailedRC; 355 ErrorInfo *mpFailedEI; 349 356 }; 350 357 -
trunk/src/VBox/Main/include/ObjectState.h
r55401 r59996 6 6 7 7 /* 8 * Copyright (C) 2006-201 4Oracle Corporation8 * Copyright (C) 2006-2016 Oracle Corporation 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 22 22 #include "VBox/com/defs.h" 23 23 #include "VBox/com/AutoLock.h" 24 #include "VBox/com/ErrorInfo.h" 24 25 25 26 // Forward declaration needed, but nothing more. … … 97 98 98 99 bool autoInitSpanConstructor(State aExpectedState); 99 void autoInitSpanDestructor(State aNewState );100 void autoInitSpanDestructor(State aNewState, HRESULT aFailedRC, com::ErrorInfo *aFailedEI); 100 101 State autoUninitSpanConstructor(); 101 102 void autoUninitSpanDestructor(); … … 114 115 /** Thread that caused the last state change */ 115 116 RTTHREAD mStateChangeThread; 117 /** Result code for failed object initialization */ 118 HRESULT mFailedRC; 119 /** Error information for failed object initialization */ 120 com::ErrorInfo *mpFailedEI; 116 121 /** Total number of active calls to this object */ 117 122 unsigned mCallers; -
trunk/src/VBox/Main/src-all/AutoCaller.cpp
r52095 r59996 7 7 8 8 /* 9 * Copyright (C) 2006-201 4Oracle Corporation9 * Copyright (C) 2006-2016 Oracle Corporation 10 10 * 11 11 * This file is part of VirtualBox Open Source Edition (OSE), as … … 44 44 mStateChangeThread = NIL_RTTHREAD; 45 45 mCallers = 0; 46 mFailedRC = S_OK; 47 mpFailedEI = NULL; 46 48 mZeroCallersSem = NIL_RTSEMEVENT; 47 49 mInitUninitSem = NIL_RTSEMEVENTMULTI; … … 58 60 mStateChangeThread = NIL_RTTHREAD; 59 61 mState = NotReady; 62 mFailedRC = S_OK; 63 if (mpFailedEI) 64 { 65 delete mpFailedEI; 66 mpFailedEI = NULL; 67 } 60 68 mObj = NULL; 61 69 } … … 195 203 if (mState == Limited) 196 204 rc = mObj->setError(rc, "The object functionality is limited"); 205 else if (FAILED(mFailedRC) && mFailedRC != E_ACCESSDENIED) 206 { 207 /* replay recorded error information */ 208 if (mpFailedEI) 209 ErrorInfoKeeper eik(*mpFailedEI); 210 rc = mFailedRC; 211 } 197 212 else 198 213 rc = mObj->setError(rc, "The object is not ready"); … … 251 266 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); 252 267 268 mFailedRC = S_OK; 269 if (mpFailedEI) 270 { 271 delete mpFailedEI; 272 mpFailedEI = NULL; 273 } 274 253 275 if (mState == aExpectedState) 254 276 { … … 260 282 } 261 283 262 void ObjectState::autoInitSpanDestructor(State aNewState )284 void ObjectState::autoInitSpanDestructor(State aNewState, HRESULT aFailedRC, com::ErrorInfo *apFailedEI) 263 285 { 264 286 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); … … 271 293 * during InInit), signal that InInit is finished and they may go on. */ 272 294 RTSemEventMultiSignal(mInitUninitSem); 295 } 296 297 if (aNewState == InitFailed) 298 { 299 mFailedRC = aFailedRC; 300 /* apFailedEI may be NULL, when there is no explicit setFailed() call, 301 * which also implies that aFailedRC is S_OK. This case is used by 302 * objects (the majority) which don't want delayed error signalling. */ 303 mpFailedEI = apFailedEI; 304 } 305 else 306 { 307 Assert(SUCCEEDED(aFailedRC)); 308 Assert(apFailedEI == NULL); 309 Assert(mpFailedEI == NULL); 273 310 } 274 311 … … 376 413 : mObj(aObj), 377 414 mResult(aResult), 378 mOk(false) 415 mOk(false), 416 mFailedRC(S_OK), 417 mpFailedEI(NULL) 379 418 { 380 419 Assert(mObj); … … 394 433 /* if the state was other than NotReady, do nothing */ 395 434 if (!mOk) 435 { 436 Assert(SUCCEEDED(mFailedRC)); 437 Assert(mpFailedEI == NULL); 396 438 return; 439 } 397 440 398 441 ObjectState::State newState; … … 403 446 else 404 447 newState = ObjectState::InitFailed; 405 mObj->getObjectState().autoInitSpanDestructor(newState); 448 mObj->getObjectState().autoInitSpanDestructor(newState, mFailedRC, mpFailedEI); 449 mFailedRC = S_OK; 450 mpFailedEI = NULL; /* now owned by ObjectState instance */ 406 451 if (newState == ObjectState::InitFailed) 407 452 { 408 453 /* call uninit() to let the object uninit itself after failed init() */ 409 454 mObj->uninit(); 410 /* Note: the object may no longer exist here (for example, it can call411 * the destructor in uninit()) */412 455 } 413 456 } … … 453 496 else 454 497 newState = ObjectState::Limited; 455 mObj->getObjectState().autoInitSpanDestructor(newState); 456 /** @todo r=klaus: this is like the initial init() failure, but in this 457 * place uninit() is NOT called. Makes only limited sense. */ 498 mObj->getObjectState().autoInitSpanDestructor(newState, S_OK, NULL); 499 /* If later AutoReinitSpan can truly fail (today there is no way) then 500 * in this place there needs to be an mObj->uninit() call just like in 501 * the AutoInitSpan destructor. In that case it might make sense to 502 * let AutoReinitSpan inherit from AutoInitSpan, as the code can be 503 * made (almost) identical. */ 458 504 } 459 505 -
trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
r59252 r59996 140 140 * 1. The user must check for #rc() before using the created structure 141 141 * (e.g. passing it as a thread function argument). If #rc() returns a 142 * failure, the Console object may not be used by the task (see 143 * Console::addCaller() for more details). 142 * failure, the Console object may not be used by the task. 144 143 * 2. On successful initialization, the structure keeps the Console caller 145 144 * until destruction (to ensure Console remains in the Ready state and won't … … 9462 9461 ComObjPtr<Console> pConsole = task->mConsole; 9463 9462 9464 /* Note: no need to use addCaller()because VMPowerUpTask does that */9463 /* Note: no need to use AutoCaller because VMPowerUpTask does that */ 9465 9464 9466 9465 /* The lock is also used as a signal from the task initiator (which … … 9987 9986 const ComObjPtr<Console> &that = task->mConsole; 9988 9987 9989 /* Note: no need to use addCaller()to protect Console because VMTask does9988 /* Note: no need to use AutoCaller to protect Console because VMTask does 9990 9989 * that */ 9991 9990 -
trunk/src/VBox/Main/src-client/SessionImpl.cpp
r57326 r59996 1159 1159 * 1160 1160 * bird: Seems E_ACCESSDENIED is what gets returned these days; see 1161 * VirtualBoxBase::addCaller.1161 * ObjectState::addCaller. 1162 1162 */ 1163 1163 if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED)) -
trunk/src/VBox/Main/src-client/VirtualBoxClientImpl.cpp
r52442 r59996 5 5 6 6 /* 7 * Copyright (C) 2010-201 4Oracle Corporation7 * Copyright (C) 2010-2016 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 78 78 79 79 rc = mData.m_pVirtualBox.createLocalObject(CLSID_VirtualBox); 80 AssertComRCReturnRC(rc); 80 if (FAILED(rc)) 81 return rc; 82 83 /* Error return is postponed to method calls, fetch info now. */ 84 ULONG rev; 85 rc = mData.m_pVirtualBox->COMGETTER(Revision)(&rev); 86 if (FAILED(rc)) 87 return rc; 81 88 82 89 rc = unconst(mData.m_pEventSource).createObject(); -
trunk/src/VBox/Main/src-server/MachineImpl.cpp
r59926 r59996 831 831 * sessions. Since in this case we are definitely called by 832 832 * VirtualBox::uninit(), we may be sure that SessionMachine::uninit() 833 * won't happen on the client watcher thread (because it does834 * VirtualBox ::addCaller()for the duration of the835 * SessionMachine:: checkForDeath() call, so that VirtualBox::uninit()833 * won't happen on the client watcher thread (because it has a 834 * VirtualBox caller for the duration of the 835 * SessionMachine::i_checkForDeath() call, so that VirtualBox::uninit() 836 836 * cannot happen until the VirtualBox caller is released). This is 837 837 * important, because SessionMachine::uninit() cannot correctly operate … … 12474 12474 /** 12475 12475 * Uninitializes this session object. If the reason is other than 12476 * Uninit::Unexpected, then this method MUST be called from # checkForDeath()12476 * Uninit::Unexpected, then this method MUST be called from #i_checkForDeath() 12477 12477 * or the client watcher code. 12478 12478 * … … 12596 12596 if (aReason == Uninit::Unexpected) 12597 12597 { 12598 /* Uninitialization didn't come from # checkForDeath(), so tell the12598 /* Uninitialization didn't come from #i_checkForDeath(), so tell the 12599 12599 * client watcher thread to update the set of machines that have open 12600 12600 * sessions. */ … … 12654 12654 12655 12655 /* 12656 * An expected uninitialization can come only from # checkForDeath().12656 * An expected uninitialization can come only from #i_checkForDeath(). 12657 12657 * Otherwise it means that something's gone really wrong (for example, 12658 12658 * the Session implementation has released the VirtualBox reference … … 13333 13333 13334 13334 /* go to the closing state (essential for all open*Session() calls and 13335 * for # checkForDeath()) */13335 * for #i_checkForDeath()) */ 13336 13336 Assert(mData->mSession.mState == SessionState_Locked); 13337 13337 mData->mSession.mState = SessionState_Unlocking; … … 13352 13352 } 13353 13353 13354 /* 13355 * # checkForDeath() is called to uninitialize this session object after13354 /* Create the progress object the client will use to wait until 13355 * #i_checkForDeath() is called to uninitialize this session object after 13356 13356 * it releases the IPC semaphore. 13357 13357 * Note! Because we're "reusing" mProgress here, this must be a proxy … … 14720 14720 * process in this case is waiting inside Session::close() for the 14721 14721 * "end session" process object to complete, while #uninit() called by 14722 * # checkForDeath() on the Watcher thread is waiting for the pending14722 * #i_checkForDeath() on the Watcher thread is waiting for the pending 14723 14723 * operation to complete. For now, we accept this inconsistent behavior 14724 14724 * and simply do nothing here. */ -
trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp
r59571 r59996 5 5 6 6 /* 7 * Copyright (C) 2006-201 5Oracle Corporation7 * Copyright (C) 2006-2016 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 373 373 LogFlowThisFunc(("Version: %s, Package: %s, API Version: %s\n", sVersion.c_str(), sPackageType.c_str(), sAPIVersion.c_str())); 374 374 375 /* Get the VirtualBox home directory. */ 376 { 377 char szHomeDir[RTPATH_MAX]; 378 int vrc = com::GetVBoxUserHomeDirectory(szHomeDir, sizeof(szHomeDir)); 379 if (RT_FAILURE(vrc)) 380 return setError(E_FAIL, 381 tr("Could not create the VirtualBox home directory '%s' (%Rrc)"), 382 szHomeDir, vrc); 383 384 unconst(m->strHomeDir) = szHomeDir; 385 } 386 387 LogRel(("Home directory: '%s'\n", m->strHomeDir.c_str())); 388 389 i_reportDriverVersions(); 390 391 /* compose the VirtualBox.xml file name */ 392 unconst(m->strSettingsFilePath) = Utf8StrFmt("%s%c%s", 393 m->strHomeDir.c_str(), 394 RTPATH_DELIMITER, 395 VBOX_GLOBAL_SETTINGS_FILE); 375 /* Important: DO NOT USE any kind of "early return" (except the single 376 * one above, checking the init span success) in this method. It is vital 377 * for correct error handling that it has only one point of return, which 378 * does all the magic on COM to signal object creation success and 379 * reporting the error later for every API method. COM translates any 380 * unsuccessful object creation to REGDB_E_CLASSNOTREG errors or similar 381 * unhelpful ones which cause us a lot of grief with troubleshooting. */ 382 396 383 HRESULT rc = S_OK; 397 384 bool fCreate = false; 398 385 try 399 386 { 387 /* Get the VirtualBox home directory. */ 388 { 389 char szHomeDir[RTPATH_MAX]; 390 int vrc = com::GetVBoxUserHomeDirectory(szHomeDir, sizeof(szHomeDir)); 391 if (RT_FAILURE(vrc)) 392 throw setError(E_FAIL, 393 tr("Could not create the VirtualBox home directory '%s' (%Rrc)"), 394 szHomeDir, vrc); 395 396 unconst(m->strHomeDir) = szHomeDir; 397 } 398 399 LogRel(("Home directory: '%s'\n", m->strHomeDir.c_str())); 400 401 i_reportDriverVersions(); 402 403 /* compose the VirtualBox.xml file name */ 404 unconst(m->strSettingsFilePath) = Utf8StrFmt("%s%c%s", 405 m->strHomeDir.c_str(), 406 RTPATH_DELIMITER, 407 VBOX_GLOBAL_SETTINGS_FILE); 400 408 // load and parse VirtualBox.xml; this will throw on XML or logic errors 401 409 try … … 511 519 512 520 ComObjPtr<NATNetwork> pNATNetwork; 513 if (SUCCEEDED(rc = pNATNetwork.createObject())) 514 { 515 rc = pNATNetwork->init(this, net); 516 AssertComRCReturnRC(rc); 517 } 518 521 rc = pNATNetwork.createObject(); 522 AssertComRCThrowRC(rc); 523 rc = pNATNetwork->init(this, net); 524 AssertComRCThrowRC(rc); 519 525 rc = i_registerNATNetwork(pNATNetwork, false /* aSaveRegistry */); 520 AssertComRC ReturnRC(rc);526 AssertComRCThrowRC(rc); 521 527 } 522 528 … … 579 585 } 580 586 581 /* Confirm a successful initialization when it's the case */582 if (SUCCEEDED(rc))583 autoInitSpan.setSucceeded();584 585 587 #ifdef VBOX_WITH_EXTPACK 586 588 /* Let the extension packs have a go at things. */ … … 592 594 #endif 593 595 594 LogFlowThisFunc(("rc=%08X\n", rc)); 596 /* Confirm a successful initialization when it's the case. Must be last, 597 * as on failure it will uninitialize the object. */ 598 if (SUCCEEDED(rc)) 599 autoInitSpan.setSucceeded(); 600 else 601 autoInitSpan.setFailed(rc); 602 603 LogFlowThisFunc(("rc=%hrc\n", rc)); 595 604 LogFlowThisFuncLeave(); 596 605 LogFlow(("===========================================================\n")); 597 return rc; 606 /* Unconditionally return success, because the error return is delayed to 607 * the attribute/method calls through the Zombie object state. */ 608 return S_OK; 598 609 } 599 610 … … 735 746 void VirtualBox::uninit() 736 747 { 737 Assert(!m->uRegistryNeedsSaving); 738 if (m->uRegistryNeedsSaving) 739 i_saveSettings(); 748 /* Must be done outside the AutoUninitSpan, as it expects AutoCaller to 749 * be successful. This needs additional checks to protect against double 750 * uninit, as then the pointer is NULL. */ 751 if (RT_VALID_PTR(m)) 752 { 753 Assert(!m->uRegistryNeedsSaving); 754 if (m->uRegistryNeedsSaving) 755 i_saveSettings(); 756 } 740 757 741 758 /* Enclose the state transition Ready->InUninit->NotReady */ … … 840 857 // clean up our instance data 841 858 delete m; 859 m = NULL; 842 860 843 861 /* Unload hard disk plugin backends. */ … … 1259 1277 firmwareDesc[i].fileName); 1260 1278 int rc = i_calculateFullPath(shortName, fullName); 1261 AssertRCReturn(rc, rc);1279 AssertRCReturn(rc, VBOX_E_IPRT_ERROR); 1262 1280 if (RTFileExists(fullName.c_str())) 1263 1281 { … … 1269 1287 char pszVBoxPath[RTPATH_MAX]; 1270 1288 rc = RTPathExecDir(pszVBoxPath, RTPATH_MAX); 1271 AssertRCReturn(rc, rc);1289 AssertRCReturn(rc, VBOX_E_IPRT_ERROR); 1272 1290 fullName = Utf8StrFmt("%s%c%s", 1273 1291 pszVBoxPath, … … 2812 2830 2813 2831 AutoCaller autoCaller(this); 2814 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());2832 AssertComRCReturn(autoCaller.rc(), FALSE); 2815 2833 2816 2834 BOOL allowChange = TRUE; … … 3180 3198 3181 3199 AutoCaller autoCaller(this); 3182 AssertComRCReturn (autoCaller.rc(),autoCaller.rc());3200 AssertComRCReturnRC(autoCaller.rc()); 3183 3201 3184 3202 { … … 4141 4159 { 4142 4160 AutoCaller autoCaller(this); 4143 AssertComRCReturn (autoCaller.rc(),autoCaller.rc());4161 AssertComRCReturnRC(autoCaller.rc()); 4144 4162 4145 4163 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL); 4146 4164 AssertReturn(!m->strSettingsFilePath.isEmpty(), E_FAIL); 4165 4166 i_unmarkRegistryModified(i_getGlobalRegistryId()); 4147 4167 4148 4168 HRESULT rc = S_OK; … … 4315 4335 4316 4336 AutoCaller autoCaller(this); 4317 AssertComRCReturn (autoCaller.rc(),autoCaller.rc());4337 AssertComRCReturnRC(autoCaller.rc()); 4318 4338 4319 4339 AutoCaller mediumCaller(pMedium); 4320 AssertComRCReturn (mediumCaller.rc(),mediumCaller.rc());4340 AssertComRCReturnRC(mediumCaller.rc()); 4321 4341 4322 4342 const char *pszDevType = NULL; … … 4421 4441 4422 4442 AutoCaller autoCaller(this); 4423 AssertComRCReturn (autoCaller.rc(),autoCaller.rc());4443 AssertComRCReturnRC(autoCaller.rc()); 4424 4444 4425 4445 AutoCaller mediumCaller(pMedium); 4426 AssertComRCReturn (mediumCaller.rc(),mediumCaller.rc());4446 AssertComRCReturnRC(mediumCaller.rc()); 4427 4447 4428 4448 // caller must hold the media tree write lock … … 4511 4531 4512 4532 AutoCaller autoCaller(this); 4513 AssertComRCReturn (autoCaller.rc(),autoCaller.rc());4533 AssertComRCReturnRC(autoCaller.rc()); 4514 4534 4515 4535 MediaList llMedia2Close; … … 5007 5027 5008 5028 AutoCaller autoCaller(this); 5009 AssertComRCReturn (autoCaller.rc(),autoCaller.rc());5029 AssertComRCReturnRC(autoCaller.rc()); 5010 5030 5011 5031 // Acquire a lock on the VirtualBox object early to avoid lock order issues … … 5018 5038 5019 5039 AutoCaller dhcpServerCaller(aDHCPServer); 5020 AssertComRCReturn (dhcpServerCaller.rc(),dhcpServerCaller.rc());5040 AssertComRCReturnRC(dhcpServerCaller.rc()); 5021 5041 5022 5042 Bstr name; … … 5069 5089 5070 5090 AutoCaller autoCaller(this); 5071 AssertComRCReturn (autoCaller.rc(),autoCaller.rc());5091 AssertComRCReturnRC(autoCaller.rc()); 5072 5092 5073 5093 AutoCaller dhcpServerCaller(aDHCPServer); 5074 AssertComRCReturn (dhcpServerCaller.rc(),dhcpServerCaller.rc());5094 AssertComRCReturnRC(dhcpServerCaller.rc()); 5075 5095 5076 5096 AutoWriteLock vboxLock(this COMMA_LOCKVAL_SRC_POS); … … 5251 5271 5252 5272 AutoCaller autoCaller(this); 5253 AssertComRCReturn (autoCaller.rc(),autoCaller.rc());5273 AssertComRCReturnRC(autoCaller.rc()); 5254 5274 5255 5275 AutoCaller natNetworkCaller(aNATNetwork); 5256 AssertComRCReturn (natNetworkCaller.rc(),natNetworkCaller.rc());5276 AssertComRCReturnRC(natNetworkCaller.rc()); 5257 5277 5258 5278 Bstr name;
Note:
See TracChangeset
for help on using the changeset viewer.