VirtualBox

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

Last change on this file since 68485 was 66895, checked in by vboxsync, 8 years ago

Main/MediumLock: fix for MediumLockListMap::Clear cleanup

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