VirtualBox

Changeset 25936 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jan 20, 2010 2:51:25 PM (15 years ago)
Author:
vboxsync
Message:

Main: make deleteSnapshot() work with the lock validator

Location:
trunk/src/VBox/Main
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/MachineImpl.cpp

    r25930 r25936  
    57925792        if (mData->mFirstSnapshot)
    57935793        {
     5794            // snapshots tree is protected by media write lock; strictly
     5795            // this isn't necessary here since we're deleting the entire
     5796            // machine, but otherwise we assert in Snapshot::uninit()
     5797            AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    57945798            mData->mFirstSnapshot->uninit();
    57955799            mData->mFirstSnapshot.setNull();
  • trunk/src/VBox/Main/SnapshotImpl.cpp

    r25930 r25936  
    8484    {}
    8585
    86     Guid                        uuid;
     86    const Guid                  uuid;
    8787    Utf8Str                     strName;
    8888    Utf8Str                     strDescription;
     
    149149    m->pParent = aParent;
    150150
    151     m->uuid = aId;
     151    unconst(m->uuid) = aId;
    152152    m->strName = aName;
    153153    m->strDescription = aDescription;
     
    168168 *  Called either from FinalRelease(), by the parent when it gets destroyed,
    169169 *  or by a third party when it decides this object is no more valid.
     170 *
     171 *  Since this manipulates the snapshots tree, the caller must hold the
     172 *  machine lock in write mode (which protects the snapshots tree)!
    170173 */
    171174void Snapshot::uninit()
     
    177180    if (autoUninitSpan.uninitDone())
    178181        return;
     182
     183    Assert(m->pMachine->isWriteLockOnCurrentThread());
    179184
    180185    // uninit all children
     
    211216 *  the number of callers to become 0 (it is 1 because of the AutoCaller in here).
    212217 *
    213  *  NOTE: this does NOT lock the snapshot, it is assumed that the caller has
    214  *  locked a) the machine and b) the snapshots tree in write mode!
     218 *  NOTE: this does NOT lock the snapshot, it is assumed that the machine state
     219 *  (and the snapshots tree) is protected by the caller having requested the machine
     220 *  lock in write mode AND the machine state must be DeletingSnapshot.
    215221 */
    216222void Snapshot::beginDiscard()
     
    220226        return;
    221227
    222     /* for now, the snapshot must have only one child when discarded,
    223         * or no children at all */
     228    // caller must have acquired the machine's write lock
     229    Assert(m->pMachine->mData->mMachineState == MachineState_DeletingSnapshot);
     230    Assert(m->pMachine->isWriteLockOnCurrentThread());
     231
     232    // the snapshot must have only one child when discarded or no children at all
    224233    AssertReturnVoid(m->llChildren.size() <= 1);
    225234
     
    259268    {
    260269        ComObjPtr<Snapshot> child = *it;
    261         AutoWriteLock childLock(child COMMA_LOCKVAL_SRC_POS);
    262 
     270        // no need to lock, snapshots tree is protected by machine lock
    263271        child->m->pParent = m->pParent;
    264272        if (m->pParent)
     
    274282 * parent. Used in uninit() and other places when reparenting is necessary.
    275283 *
    276  * The caller must hold the snapshots tree lock!
     284 * The caller must hold the machine lock in write mode (which protects the snapshots tree)!
    277285 */
    278286void Snapshot::deparent()
    279287{
     288    Assert(m->pMachine->isWriteLockOnCurrentThread());
     289
    280290    SnapshotsList &llParent = m->pParent->m->llChildren;
    281291    for (SnapshotsList::iterator it = llParent.begin();
     
    577587 *  Searches for a snapshot with the given ID among children, grand-children,
    578588 *  etc. of this snapshot. This snapshot itself is also included in the search.
    579  *  Caller must hold the snapshots tree lock!
     589 *
     590 *  Caller must hold the machine lock (which protects the snapshots tree!)
    580591 */
    581592ComObjPtr<Snapshot> Snapshot::findChildOrSelf(IN_GUID aId)
     
    586597    AssertComRC(autoCaller.rc());
    587598
    588     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    589 
     599    // no need to lock, uuid is const
    590600    if (m->uuid == aId)
    591601        child = this;
    592602    else
    593603    {
    594         alock.release();
    595604        for (SnapshotsList::const_iterator it = m->llChildren.begin();
    596605             it != m->llChildren.end();
     
    609618 *  grand-children, etc. of this snapshot. This snapshot itself is also included
    610619 *  in the search.
    611  *  Caller must hold the snapshots tree lock!
     620 *
     621 *  Caller must hold the machine lock (which protects the snapshots tree!)
    612622 */
    613623ComObjPtr<Snapshot> Snapshot::findChildOrSelf(const Utf8Str &aName)
     
    678688 *  @param aNewPath new path (full)
    679689 *
    680  *  @note Locks this object + children for writing.
     690 *  @note Locks the machine (for the snapshots tree) +  this object + children for writing.
    681691 */
    682692void Snapshot::updateSavedStatePaths(const char *aOldPath, const char *aNewPath)
     
    20362046    }
    20372047
    2038     /* set the proper machine state (note: after creating a Task instance) */
     2048    // the task might start running but will block on acquiring the machine's write lock
     2049    // which we acquired above; once this function leaves, the task will be unblocked;
     2050    // set the proper machine state here now (note: after creating a Task instance)
    20392051    setMachineState(MachineState_DeletingSnapshot);
    20402052
     
    20952107 * SessionMachine::DeleteSnapshot, through which progress and results are reported.
    20962108 *
    2097  * @note Locks mParent + this + child objects for writing!
     2109 * SessionMachine::DeleteSnapshot() has set the machne state to MachineState_DeletingSnapshot
     2110 * right after creating this task. Since we block on the machine write lock at the beginning,
     2111 * once that has been acquired, we can assume that the machine state is indeed that.
     2112 *
     2113 * @note Locks the machine + the snapshot + the media tree for writing!
    20982114 *
    20992115 * @param aTask Task data.
     
    21182134    }
    21192135
    2120     /* Locking order:  */
    2121     AutoMultiWriteLock3 alock(this->lockHandle(),
    2122                               aTask.pSnapshot->lockHandle(),
    2123                               &mParent->getMediaTreeLockHandle()
    2124                               COMMA_LOCKVAL_SRC_POS);
    2125 
    2126     ComObjPtr<SnapshotMachine> pSnapMachine = aTask.pSnapshot->getSnapshotMachine();
    2127     /* no need to lock the snapshot machine since it is const by definiton */
     2136    MediumDiscardRecList toDiscard;
    21282137
    21292138    HRESULT rc = S_OK;
    2130 
    2131     /* save the snapshot ID (for callbacks) */
    2132     Guid snapshotId1 = aTask.pSnapshot->getId();
    2133 
    2134     MediumDiscardRecList toDiscard;
    21352139
    21362140    bool fMachineSettingsChanged = false;       // Machine
    21372141    bool fNeedsSaveSettings = false;            // VirtualBox.xml
    21382142
     2143    Guid snapshotId1;
     2144
    21392145    try
    21402146    {
    2141         /* first pass: */
     2147        /* Locking order:  */
     2148        AutoMultiWriteLock3 multiLock(this->lockHandle(),                   // machine
     2149                                      aTask.pSnapshot->lockHandle(),        // snapshot
     2150                                      &mParent->getMediaTreeLockHandle()    // media tree
     2151                                      COMMA_LOCKVAL_SRC_POS);
     2152            // once we have this lock, we know that SessionMachine::DeleteSnapshot()
     2153            // has exited after setting the machine state to MachineState_DeletingSnapshot
     2154
     2155        ComObjPtr<SnapshotMachine> pSnapMachine = aTask.pSnapshot->getSnapshotMachine();
     2156        // no need to lock the snapshot machine since it is const by definiton
     2157
     2158        // save the snapshot ID (for callbacks)
     2159        snapshotId1 = aTask.pSnapshot->getId();
     2160
     2161        // first pass:
    21422162        LogFlowThisFunc(("1: Checking hard disk merge prerequisites...\n"));
    21432163
     
    21482168        // diff image holding the changes written after the snapshot was taken)
    21492169        for (MediaData::AttachmentList::iterator it = pSnapMachine->mMediaData->mAttachments.begin();
    2150             it != pSnapMachine->mMediaData->mAttachments.end();
    2151             ++it)
     2170             it != pSnapMachine->mMediaData->mAttachments.end();
     2171             ++it)
    21522172        {
    21532173            ComObjPtr<MediumAttachment> &pAttach = *it;
     
    22512271        }
    22522272
     2273        // we can release the lock now since the machine state is MachineState_DeletingSnapshot
     2274        multiLock.release();
     2275
    22532276        /* Now we checked that we can successfully merge all normal hard disks
    22542277         * (unless a runtime error like end-of-disc happens). Prior to
     
    22622285
    22632286        {
     2287            // saveAllSnapshots() needs a machine lock, and the snapshots
     2288            // tree is protected by the machine lock as well
     2289            AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
     2290
    22642291            ComObjPtr<Snapshot> parentSnapshot = aTask.pSnapshot->getParent();
    22652292            Utf8Str stateFilePath = aTask.pSnapshot->stateFilePath();
    22662293
    2267             /* Note that discarding the snapshot will deassociate it from the
    2268              * hard disks which will allow the merge+delete operation for them*/
     2294            // Note that discarding the snapshot will deassociate it from the
     2295            // hard disks which will allow the merge+delete operation for them
    22692296            aTask.pSnapshot->beginDiscard();
    22702297            aTask.pSnapshot->uninit();
     2298                    // this requests the machine lock in turn when deleting all the children
     2299                    // in the snapshot machine
    22712300
    22722301            rc = saveAllSnapshots();
     2302            machineLock.release();
    22732303            if (FAILED(rc)) throw rc;
    22742304
    2275             /// @todo (dmik)
    2276             //  if we implement some warning mechanism later, we'll have
    2277             //  to return a warning if the state file path cannot be deleted
    22782305            if (!stateFilePath.isEmpty())
    22792306            {
     
    23022329        LogFlowThisFunc(("3: Performing actual hard disk merging...\n"));
    23032330
    2304         /* leave the locks before the potentially lengthy operation */
    2305         alock.leave();
    2306 
    23072331        /// @todo NEWMEDIA turn the following errors into warnings because the
    23082332        /// snapshot itself has been already deleted (and interpret these
    23092333        /// warnings properly on the GUI side)
    2310 
    23112334        for (MediumDiscardRecList::iterator it = toDiscard.begin();
    23122335             it != toDiscard.end();)
     
    23212344            it = toDiscard.erase(it);
    23222345        }
    2323 
    2324         LogFlowThisFunc(("Entering locks again...\n"));
    2325         alock.enter();
    2326         LogFlowThisFunc(("Entered locks OK\n"));
    23272346    }
    23282347    catch (HRESULT aRC) { rc = aRC; }
     
    23322351        HRESULT rc2 = S_OK;
    23332352
    2334         /* un-prepare the remaining hard disks */
     2353        AutoMultiWriteLock2 multiLock(this->lockHandle(),                   // machine
     2354                                      &mParent->getMediaTreeLockHandle()    // media tree
     2355                                      COMMA_LOCKVAL_SRC_POS);
     2356
     2357        // un-prepare the remaining hard disks
    23352358        for (MediumDiscardRecList::const_iterator it = toDiscard.begin();
    2336              it != toDiscard.end(); ++it)
     2359             it != toDiscard.end();
     2360             ++it)
    23372361        {
    2338             it->hd->cancelDiscard (it->chain);
     2362            it->hd->cancelDiscard(it->chain);
    23392363
    23402364            if (!it->replaceHd.isNull())
    23412365            {
    2342                 /* undo hard disk replacement */
    2343 
    23442366                rc2 = it->replaceHd->attachTo(mData->mUuid, it->snapshotId);
    23452367                AssertComRC(rc2);
    23462368
    2347                 rc2 = it->hd->detachFrom (mData->mUuid, it->snapshotId);
     2369                rc2 = it->hd->detachFrom(mData->mUuid, it->snapshotId);
    23482370                AssertComRC(rc2);
    23492371
     
    23532375        }
    23542376    }
    2355 
    2356     alock.release();
    23572377
    23582378    // whether we were successful or not, we need to set the machine
     
    23762396            if (fMachineSettingsChanged)
    23772397            {
    2378                 alock.acquire();
     2398                AutoWriteLock machineLock(this COMMA_LOCKVAL_SRC_POS);
    23792399                saveSettings(SaveS_InformCallbacksAnyway);
    23802400            }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette