VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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