VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/MediumLock.cpp@ 48935

Last change on this file since 48935 was 48297, checked in by vboxsync, 11 years ago

Main/Medium: redesign API level medium locking, needed conversions from MediaList to MediumLockLists in several places, forced cleanups elsewhere, too
Main/Token: introduced token objects for controlling the unlocking, will be used as a general concept in the future
Main/Snapshot: snapshot deletion needed significant cleanups as it was still using many shortcuts, directly calling the API to lock media instead of using lock lists. Now much better, and the online snapshot deletion is also a lot cleaner as it no longer passes unnecessary parameters around which are already known in the machine/snapshot code
Main/MediumLock: small improvements, now has a mode which skips locking already locked media, needed by the Snapshot code where we have overlapping lock lists and have to update the original one instead
Main/Console+Session+Machine: follow-up changes for the online snapshot merging parameter passing simplification, plus an unrelated lock order violation fix in Machine which happens only for inaccessible machines
Main/testcase: update correspondingly
doc: update SDK reference

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 KB
Line 
1/** @file
2 *
3 * Medium lock management helper classes
4 */
5
6/*
7 * Copyright (C) 2010-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "MediumLock.h"
19#include "MediumImpl.h"
20#include "MediumAttachmentImpl.h"
21
22
23MediumLock::MediumLock()
24 : mMedium(NULL), mMediumCaller(NULL), mLockWrite(false),
25 mIsLocked(false), mLockSkipped(false)
26{
27}
28
29MediumLock::~MediumLock()
30{
31 Unlock();
32}
33
34MediumLock::MediumLock(const MediumLock &aMediumLock)
35 : mMedium(aMediumLock.mMedium), mMediumCaller(NULL),
36 mLockWrite(aMediumLock.mLockWrite), mIsLocked(false), mLockSkipped(false)
37{
38}
39
40MediumLock::MediumLock(const ComObjPtr<Medium> &aMedium, bool aLockWrite)
41 : mMedium(aMedium), mMediumCaller(NULL), mLockWrite(aLockWrite),
42 mIsLocked(false), mLockSkipped(false)
43{
44}
45
46HRESULT MediumLock::UpdateLock(bool aLockWrite)
47{
48 bool fPrevLockWrite = mLockWrite;
49 if (mIsLocked)
50 {
51 Unlock();
52 mLockWrite = aLockWrite;
53 HRESULT rc = Lock();
54 if (FAILED(rc))
55 {
56 mLockWrite = fPrevLockWrite;
57 Lock();
58 return rc;
59 }
60 return S_OK;
61 }
62
63 mLockWrite = aLockWrite;
64 return S_OK;
65}
66
67const ComObjPtr<Medium> &MediumLock::GetMedium() const
68{
69 return mMedium;
70}
71
72bool MediumLock::GetLockRequest() const
73{
74 return mLockWrite;
75}
76
77bool MediumLock::IsLocked() const
78{
79 return mIsLocked;
80}
81
82HRESULT MediumLock::Lock(bool aIgnoreLockedMedia)
83{
84 if (mIsLocked)
85 return S_OK;
86
87 mMediumCaller.attach(mMedium);
88 if (FAILED(mMediumCaller.rc()))
89 {
90 mMediumCaller.attach(NULL);
91 return VBOX_E_INVALID_OBJECT_STATE;
92 }
93
94 HRESULT rc = S_OK;
95 MediumState_T state;
96 {
97 AutoReadLock alock(mMedium COMMA_LOCKVAL_SRC_POS);
98 state = mMedium->getState();
99 }
100 switch (state)
101 {
102 case MediumState_NotCreated:
103 case MediumState_Creating:
104 case MediumState_Deleting:
105 mLockSkipped = true;
106 break;
107 default:
108 if (mLockWrite)
109 {
110 if (aIgnoreLockedMedia && ( state == MediumState_LockedRead
111 || state == MediumState_LockedWrite))
112 return S_OK;
113 else
114 rc = mMedium->LockWrite(mToken.asOutParam());
115 }
116 else
117 {
118 if (aIgnoreLockedMedia && state == MediumState_LockedWrite)
119 return S_OK;
120 else
121 rc = mMedium->LockRead(mToken.asOutParam());
122 }
123 }
124 if (SUCCEEDED(rc))
125 {
126 mIsLocked = true;
127 return S_OK;
128 }
129 else
130 {
131 mMediumCaller.attach(NULL);
132 return VBOX_E_INVALID_OBJECT_STATE;
133 }
134}
135
136HRESULT MediumLock::Unlock()
137{
138 HRESULT rc = S_OK;
139 if (mIsLocked && !mLockSkipped && mToken)
140 {
141 mToken->Abandon();
142 mToken.setNull();
143 }
144 mMediumCaller.attach(NULL);
145 mLockSkipped = false;
146 mIsLocked = false;
147 return rc;
148}
149
150MediumLockList::MediumLockList()
151{
152 mIsLocked = false;
153}
154
155MediumLockList::~MediumLockList()
156{
157 Clear();
158 // rest is done by the list object's destructor
159}
160
161bool MediumLockList::IsEmpty()
162{
163 return mMediumLocks.empty();
164}
165
166HRESULT MediumLockList::Append(const ComObjPtr<Medium> &aMedium, bool aLockWrite)
167{
168 if (mIsLocked)
169 return VBOX_E_INVALID_OBJECT_STATE;
170 mMediumLocks.push_back(MediumLock(aMedium, aLockWrite));
171 return S_OK;
172}
173
174HRESULT MediumLockList::Prepend(const ComObjPtr<Medium> &aMedium, bool aLockWrite)
175{
176 if (mIsLocked)
177 return VBOX_E_INVALID_OBJECT_STATE;
178 mMediumLocks.push_front(MediumLock(aMedium, aLockWrite));
179 return S_OK;
180}
181
182HRESULT MediumLockList::Update(const ComObjPtr<Medium> &aMedium, bool aLockWrite)
183{
184 for (MediumLockList::Base::iterator it = mMediumLocks.begin();
185 it != mMediumLocks.end();
186 it++)
187 {
188 if (it->GetMedium() == aMedium)
189 return it->UpdateLock(aLockWrite);
190 }
191 return VBOX_E_INVALID_OBJECT_STATE;
192}
193
194HRESULT MediumLockList::RemoveByIterator(Base::iterator &aIt)
195{
196 HRESULT rc = aIt->Unlock();
197 aIt = mMediumLocks.erase(aIt);
198 return rc;
199}
200
201HRESULT MediumLockList::Clear()
202{
203 HRESULT rc = Unlock();
204 mMediumLocks.clear();
205 return rc;
206}
207
208MediumLockList::Base::iterator MediumLockList::GetBegin()
209{
210 return mMediumLocks.begin();
211}
212
213MediumLockList::Base::iterator MediumLockList::GetEnd()
214{
215 return mMediumLocks.end();
216}
217
218HRESULT MediumLockList::Lock(bool fSkipOverLockedMedia /* = false */)
219{
220 if (mIsLocked)
221 return S_OK;
222 HRESULT rc = S_OK;
223 for (MediumLockList::Base::iterator it = mMediumLocks.begin();
224 it != mMediumLocks.end();
225 it++)
226 {
227 rc = it->Lock(fSkipOverLockedMedia);
228 if (FAILED(rc))
229 {
230 for (MediumLockList::Base::iterator it2 = mMediumLocks.begin();
231 it2 != it;
232 it2++)
233 {
234 HRESULT rc2 = it2->Unlock();
235 AssertComRC(rc2);
236 }
237 break;
238 }
239 }
240 if (SUCCEEDED(rc))
241 mIsLocked = true;
242 return rc;
243}
244
245HRESULT MediumLockList::Unlock()
246{
247 if (!mIsLocked)
248 return S_OK;
249 HRESULT rc = S_OK;
250 for (MediumLockList::Base::iterator it = mMediumLocks.begin();
251 it != mMediumLocks.end();
252 it++)
253 {
254 HRESULT rc2 = it->Unlock();
255 if (SUCCEEDED(rc) && FAILED(rc2))
256 rc = rc2;
257 }
258 mIsLocked = false;
259 return rc;
260}
261
262
263MediumLockListMap::MediumLockListMap()
264{
265 mIsLocked = false;
266}
267
268MediumLockListMap::~MediumLockListMap()
269{
270 Clear();
271 // rest is done by the map object's destructor
272}
273
274bool MediumLockListMap::IsEmpty()
275{
276 return mMediumLocks.empty();
277}
278
279HRESULT MediumLockListMap::Insert(const ComObjPtr<MediumAttachment> &aMediumAttachment,
280 MediumLockList *aMediumLockList)
281{
282 if (mIsLocked)
283 return VBOX_E_INVALID_OBJECT_STATE;
284 mMediumLocks[aMediumAttachment] = aMediumLockList;
285 return S_OK;
286}
287
288HRESULT MediumLockListMap::ReplaceKey(const ComObjPtr<MediumAttachment> &aMediumAttachmentOld,
289 const ComObjPtr<MediumAttachment> &aMediumAttachmentNew)
290{
291 MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachmentOld);
292 if (it == mMediumLocks.end())
293 return VBOX_E_INVALID_OBJECT_STATE;
294 MediumLockList *pMediumLockList = it->second;
295 mMediumLocks.erase(it);
296 mMediumLocks[aMediumAttachmentNew] = pMediumLockList;
297 return S_OK;
298}
299
300HRESULT MediumLockListMap::Remove(const ComObjPtr<MediumAttachment> &aMediumAttachment)
301{
302 MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachment);
303 if (it == mMediumLocks.end())
304 return VBOX_E_INVALID_OBJECT_STATE;
305 MediumLockList *pMediumLockList = it->second;
306 mMediumLocks.erase(it);
307 delete pMediumLockList;
308 return S_OK;
309}
310
311HRESULT MediumLockListMap::Clear()
312{
313 HRESULT rc = Unlock();
314 for (MediumLockListMap::Base::iterator it = mMediumLocks.begin();
315 it != mMediumLocks.end();
316 )
317 {
318 MediumLockList *pMediumLockList = it->second;
319 // need an incremented iterator as otherwise erasing invalidates it
320 mMediumLocks.erase(it++);
321 delete pMediumLockList;
322 }
323 return rc;
324}
325
326HRESULT MediumLockListMap::Get(const ComObjPtr<MediumAttachment> &aMediumAttachment,
327 MediumLockList * &aMediumLockList)
328{
329 MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachment);
330 if (it == mMediumLocks.end())
331 {
332 aMediumLockList = NULL;
333 return VBOX_E_INVALID_OBJECT_STATE;
334 }
335 aMediumLockList = it->second;
336 return S_OK;
337}
338
339HRESULT MediumLockListMap::Lock()
340{
341 if (mIsLocked)
342 return S_OK;
343 HRESULT rc = S_OK;
344 for (MediumLockListMap::Base::const_iterator it = mMediumLocks.begin();
345 it != mMediumLocks.end();
346 it++)
347 {
348 rc = it->second->Lock();
349 if (FAILED(rc))
350 {
351 for (MediumLockListMap::Base::const_iterator it2 = mMediumLocks.begin();
352 it2 != it;
353 it2++)
354 {
355 HRESULT rc2 = it2->second->Unlock();
356 AssertComRC(rc2);
357 }
358 break;
359 }
360 }
361 if (SUCCEEDED(rc))
362 mIsLocked = true;
363 return rc;
364}
365
366HRESULT MediumLockListMap::Unlock()
367{
368 if (!mIsLocked)
369 return S_OK;
370 HRESULT rc = S_OK;
371 for (MediumLockListMap::Base::const_iterator it = mMediumLocks.begin();
372 it != mMediumLocks.end();
373 it++)
374 {
375 MediumLockList *pMediumLockList = it->second;
376 HRESULT rc2 = pMediumLockList->Unlock();
377 if (SUCCEEDED(rc) && FAILED(rc2))
378 rc = rc2;
379 }
380 mIsLocked = false;
381 return rc;
382}
Note: See TracBrowser for help on using the repository browser.

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