VirtualBox

Changeset 22228 in vbox


Ignore:
Timestamp:
Aug 13, 2009 10:26:00 AM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
51030
Message:

Main: fix both SetExtraData() implementations to call onExtraDataCanChange() outside of any locks

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

Legend:

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

    r22199 r22228  
    26452645    CheckComArgNotNull(aKey);
    26462646
    2647     AutoCaller autoCaller (this);
     2647    AutoCaller autoCaller(this);
    26482648    CheckComRCReturnRC (autoCaller.rc());
    26492649
    2650     Bstr val;
    2651     if (!aValue)
    2652         val = (const char *)"";
    2653     else
    2654         val = aValue;
    2655 
    26562650    Utf8Str strKey(aKey);
    2657     Bstr oldVal("");
    2658 
    2659     /* VirtualBox::onExtraDataCanChange() and saveSettings() need mParent
    2660      * lock (saveSettings() needs a write one). This object's write lock is
    2661      * also necessary to serialize file access (prevent concurrent reads and
    2662      * writes). */
    2663     AutoMultiWriteLock2 alock(mParent, this);
    2664 
    2665     if (mType == IsSnapshotMachine)
    2666     {
    2667         HRESULT rc = checkStateDependency(MutableStateDep);
    2668         CheckComRCReturnRC (rc);
    2669     }
    2670 
    2671     settings::ExtraDataItemsMap::const_iterator it = mData->m_pMachineConfigFile->mapExtraDataItems.find(strKey);
    2672     if (it != mData->m_pMachineConfigFile->mapExtraDataItems.end())
    2673     {
    2674         // key exists:
    2675         const Utf8Str &strValue = it->second;
    2676         oldVal = strValue;
    2677     }
    2678 
    2679     bool fChanged = (oldVal != val);
    2680     if (fChanged)
    2681     {
    2682         /* ask for permission from all listeners */
     2651    Utf8Str strValue(aValue);
     2652    Utf8Str strOldValue;            // empty
     2653
     2654    // locking note: we only hold the read lock briefly to look up the old value,
     2655    // then release it and call the onExtraCanChange callbacks. There is a small
     2656    // chance of a race insofar as the callback might be called twice if two callers
     2657    // change the same key at the same time, but that's a much better solution
     2658    // than the deadlock we had here before. The actual changing of the extradata
     2659    // is then performed under the write lock and race-free.
     2660
     2661    // look up the old value first; if nothing's changed then we need not do anything
     2662    {
     2663        AutoReadLock alock(this); // hold read lock only while looking up
     2664        settings::ExtraDataItemsMap::const_iterator it = mData->m_pMachineConfigFile->mapExtraDataItems.find(strKey);
     2665        if (it != mData->m_pMachineConfigFile->mapExtraDataItems.end())
     2666            strOldValue = it->second;
     2667    }
     2668
     2669    bool fChanged;
     2670    if (fChanged = (strOldValue != strValue))
     2671    {
     2672        // ask for permission from all listeners outside the locks;
     2673        // onExtraDataCanChange() only briefly requests the VirtualBox
     2674        // lock to copy the list of callbacks to invoke
    26832675        Bstr error;
    2684         if (!mParent->onExtraDataCanChange(mData->mUuid, aKey, val, error))
     2676        Bstr bstrValue;
     2677        if (aValue)
     2678            bstrValue = aValue;
     2679        else
     2680            bstrValue = (const char *)"";
     2681
     2682        if (!mParent->onExtraDataCanChange(mData->mUuid, aKey, bstrValue, error))
    26852683        {
    26862684            const char *sep = error.isEmpty() ? "" : ": ";
     
    26912689                            tr("Could not set extra data because someone refused the requested change of '%ls' to '%ls'%s%ls"),
    26922690                            aKey,
    2693                             val.raw(),
     2691                            bstrValue.raw(),
    26942692                            sep,
    26952693                            err);
    26962694        }
    26972695
    2698         mData->m_pMachineConfigFile->mapExtraDataItems[strKey] = val;
     2696        // data is changing and change not vetoed: then write it out under the locks
     2697
     2698        /* VirtualBox::onExtraDataCanChange() and saveSettings() need mParent
     2699         * lock (saveSettings() needs a write one). This object's write lock is
     2700         * also necessary to serialize file access (prevent concurrent reads and
     2701         * writes). */
     2702        AutoMultiWriteLock2 alock(mParent, this);
     2703
     2704        if (mType == IsSnapshotMachine)
     2705        {
     2706            HRESULT rc = checkStateDependency(MutableStateDep);
     2707            CheckComRCReturnRC (rc);
     2708        }
     2709
     2710        mData->m_pMachineConfigFile->mapExtraDataItems[strKey] = strValue;
     2711                // creates a new key if needed
    26992712
    27002713        /* save settings on success */
     
    27032716    }
    27042717
    2705     /* fire a notification */
     2718    // fire notification outside the lock
    27062719    if (fChanged)
    27072720        mParent->onExtraDataChange(mData->mUuid, aKey, aValue);
  • trunk/src/VBox/Main/VirtualBoxImpl.cpp

    r22209 r22228  
    15111511    CheckComRCReturnRC(autoCaller.rc());
    15121512
    1513     Guid emptyGuid;
    1514     Bstr val;
    1515     if (!aValue)
    1516         val = (const char *)"";
    1517     else
    1518         val = aValue;
    1519 
    15201513    Utf8Str strKey(aKey);
    1521     Bstr oldVal("");
    1522 
    1523     /* serialize file access (prevent concurrent reads and writes) */
    1524     AutoWriteLock alock(this);
    1525 
    1526     settings::ExtraDataItemsMap::const_iterator it = m_pMainConfigFile->mapExtraDataItems.find(strKey);
    1527     if (it != m_pMainConfigFile->mapExtraDataItems.end())
    1528     {
    1529         // key exists:
    1530         const Utf8Str &strValue = it->second;
    1531         oldVal = strValue;
    1532     }
    1533 
    1534     bool fChanged = (oldVal != val);
    1535     if (fChanged)
    1536     {
    1537         /* ask for permission from all listeners */
     1514    Utf8Str strValue(aValue);
     1515    Utf8Str strOldValue;            // empty
     1516
     1517    // locking note: we only hold the read lock briefly to look up the old value,
     1518    // then release it and call the onExtraCanChange callbacks. There is a small
     1519    // chance of a race insofar as the callback might be called twice if two callers
     1520    // change the same key at the same time, but that's a much better solution
     1521    // than the deadlock we had here before. The actual changing of the extradata
     1522    // is then performed under the write lock and race-free.
     1523
     1524    // look up the old value first; if nothing's changed then we need not do anything
     1525    {
     1526        AutoReadLock alock(this); // hold read lock only while looking up
     1527        settings::ExtraDataItemsMap::const_iterator it = m_pMainConfigFile->mapExtraDataItems.find(strKey);
     1528        if (it != m_pMainConfigFile->mapExtraDataItems.end())
     1529            strOldValue = it->second;
     1530    }
     1531
     1532    bool fChanged;
     1533    if (fChanged = (strOldValue != strValue))
     1534    {
     1535        // ask for permission from all listeners outside the locks;
     1536        // onExtraDataCanChange() only briefly requests the VirtualBox
     1537        // lock to copy the list of callbacks to invoke
    15381538        Bstr error;
    1539         if (!onExtraDataCanChange(Guid::Empty, aKey, val, error))
     1539        Bstr bstrValue;
     1540        if (aValue)
     1541            bstrValue = aValue;
     1542        else
     1543            bstrValue = (const char *)"";
     1544
     1545        if (!onExtraDataCanChange(Guid::Empty, aKey, bstrValue, error))
    15401546        {
    15411547            const char *sep = error.isEmpty() ? "" : ": ";
     
    15461552                            tr("Could not set extra data because someone refused the requested change of '%ls' to '%ls'%s%ls"),
    15471553                            aKey,
    1548                             val.raw(),
     1554                            bstrValue.raw(),
    15491555                            sep,
    15501556                            err);
    15511557        }
    15521558
    1553         m_pMainConfigFile->mapExtraDataItems[strKey] = val;
     1559        // data is changing and change not vetoed: then write it out under the lock
     1560
     1561        AutoWriteLock alock(this);
     1562
     1563        m_pMainConfigFile->mapExtraDataItems[strKey] = strValue;
     1564                // creates a new key if needed
    15541565
    15551566        /* save settings on success */
     
    15581569    }
    15591570
    1560     /* fire a notification */
     1571    // fire notification outside the lock
    15611572    if (fChanged)
    15621573        onExtraDataChange(Guid::Empty, aKey, aValue);
Note: See TracChangeset for help on using the changeset viewer.

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