VirtualBox

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

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

Main/MediumLock: when destroying locks, lock lists or lock list maps, keep the error information unchanged, because it's very surprising behavior that the potential unlock errors are showing up in the thread's error info, often losing it during error handling

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.6 KB
Line 
1/* $Id: MediumLock.cpp 64213 2016-10-11 15:58:12Z 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 )
327 {
328 MediumLockList *pMediumLockList = it->second;
329 // need an incremented iterator as otherwise erasing invalidates it
330 mMediumLocks.erase(it++);
331 delete pMediumLockList;
332 }
333 return rc;
334}
335
336HRESULT MediumLockListMap::Get(const ComObjPtr<MediumAttachment> &aMediumAttachment,
337 MediumLockList * &aMediumLockList)
338{
339 MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachment);
340 if (it == mMediumLocks.end())
341 {
342 aMediumLockList = NULL;
343 return VBOX_E_INVALID_OBJECT_STATE;
344 }
345 aMediumLockList = it->second;
346 return S_OK;
347}
348
349HRESULT MediumLockListMap::Lock()
350{
351 if (mIsLocked)
352 return S_OK;
353 HRESULT rc = S_OK;
354 for (MediumLockListMap::Base::const_iterator it = mMediumLocks.begin();
355 it != mMediumLocks.end();
356 ++it)
357 {
358 rc = it->second->Lock();
359 if (FAILED(rc))
360 {
361 for (MediumLockListMap::Base::const_iterator it2 = mMediumLocks.begin();
362 it2 != it;
363 ++it2)
364 {
365 HRESULT rc2 = it2->second->Unlock();
366 AssertComRC(rc2);
367 }
368 break;
369 }
370 }
371 if (SUCCEEDED(rc))
372 mIsLocked = true;
373 return rc;
374}
375
376HRESULT MediumLockListMap::Unlock()
377{
378 if (!mIsLocked)
379 return S_OK;
380 HRESULT rc = S_OK;
381 for (MediumLockListMap::Base::const_iterator it = mMediumLocks.begin();
382 it != mMediumLocks.end();
383 ++it)
384 {
385 MediumLockList *pMediumLockList = it->second;
386 HRESULT rc2 = pMediumLockList->Unlock();
387 if (SUCCEEDED(rc) && FAILED(rc2))
388 rc = rc2;
389 }
390 mIsLocked = false;
391 return rc;
392}
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