VirtualBox

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

Last change on this file since 98110 was 98103, checked in by vboxsync, 23 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 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 *
4 * Medium lock management helper classes
5 */
6
7/*
8 * Copyright (C) 2010-2023 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 rc = Lock();
68 if (FAILED(rc))
69 {
70 mLockWrite = fPrevLockWrite;
71 Lock();
72 return rc;
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.rc()))
103 {
104 mMediumCaller.attach(NULL);
105 return VBOX_E_INVALID_OBJECT_STATE;
106 }
107
108 HRESULT rc = 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 else
128 rc = mMedium->LockWrite(mToken.asOutParam());
129 }
130 else
131 {
132 if (aIgnoreLockedMedia && state == MediumState_LockedWrite)
133 return S_OK;
134 else
135 rc = mMedium->LockRead(mToken.asOutParam());
136 }
137 }
138 if (SUCCEEDED(rc))
139 {
140 mIsLocked = true;
141 return S_OK;
142 }
143 else
144 {
145 mMediumCaller.attach(NULL);
146 return VBOX_E_INVALID_OBJECT_STATE;
147 }
148}
149
150HRESULT MediumLock::Unlock()
151{
152 HRESULT rc = S_OK;
153 if (mIsLocked && !mLockSkipped && mToken)
154 {
155 mToken->Abandon();
156 mToken.setNull();
157 }
158 mMediumCaller.attach(NULL);
159 mLockSkipped = false;
160 mIsLocked = false;
161 return rc;
162}
163
164MediumLockList::MediumLockList()
165{
166 mIsLocked = false;
167}
168
169MediumLockList::~MediumLockList()
170{
171 // destroying medium lock lists is routinely done as part of error handling
172 // and it's not expected to lose error info
173 ErrorInfoKeeper eik;
174 Clear();
175 // rest is done by the list object's destructor
176}
177
178bool MediumLockList::IsEmpty()
179{
180 return mMediumLocks.empty();
181}
182
183HRESULT MediumLockList::Append(const ComObjPtr<Medium> &aMedium, bool aLockWrite)
184{
185 if (mIsLocked)
186 return VBOX_E_INVALID_OBJECT_STATE;
187 mMediumLocks.push_back(MediumLock(aMedium, aLockWrite));
188 return S_OK;
189}
190
191HRESULT MediumLockList::Prepend(const ComObjPtr<Medium> &aMedium, bool aLockWrite)
192{
193 if (mIsLocked)
194 return VBOX_E_INVALID_OBJECT_STATE;
195 mMediumLocks.push_front(MediumLock(aMedium, aLockWrite));
196 return S_OK;
197}
198
199HRESULT MediumLockList::Update(const ComObjPtr<Medium> &aMedium, bool aLockWrite)
200{
201 for (MediumLockList::Base::iterator it = mMediumLocks.begin();
202 it != mMediumLocks.end();
203 ++it)
204 {
205 if (it->GetMedium() == aMedium)
206 return it->UpdateLock(aLockWrite);
207 }
208 return VBOX_E_INVALID_OBJECT_STATE;
209}
210
211HRESULT MediumLockList::RemoveByIterator(Base::iterator &aIt)
212{
213 HRESULT rc = aIt->Unlock();
214 aIt = mMediumLocks.erase(aIt);
215 return rc;
216}
217
218HRESULT MediumLockList::Clear()
219{
220 HRESULT rc = Unlock();
221 mMediumLocks.clear();
222 return rc;
223}
224
225MediumLockList::Base::iterator MediumLockList::GetBegin()
226{
227 return mMediumLocks.begin();
228}
229
230MediumLockList::Base::iterator MediumLockList::GetEnd()
231{
232 return mMediumLocks.end();
233}
234
235HRESULT MediumLockList::Lock(bool fSkipOverLockedMedia /* = false */)
236{
237 if (mIsLocked)
238 return S_OK;
239 HRESULT rc = S_OK;
240 for (MediumLockList::Base::iterator it = mMediumLocks.begin();
241 it != mMediumLocks.end();
242 ++it)
243 {
244 rc = it->Lock(fSkipOverLockedMedia);
245 if (FAILED(rc))
246 {
247 for (MediumLockList::Base::iterator it2 = mMediumLocks.begin();
248 it2 != it;
249 ++it2)
250 {
251 HRESULT rc2 = it2->Unlock();
252 AssertComRC(rc2);
253 }
254 break;
255 }
256 }
257 if (SUCCEEDED(rc))
258 mIsLocked = true;
259 return rc;
260}
261
262HRESULT MediumLockList::Unlock()
263{
264 if (!mIsLocked)
265 return S_OK;
266 HRESULT rc = S_OK;
267 for (MediumLockList::Base::iterator it = mMediumLocks.begin();
268 it != mMediumLocks.end();
269 ++it)
270 {
271 HRESULT rc2 = it->Unlock();
272 if (SUCCEEDED(rc) && FAILED(rc2))
273 rc = rc2;
274 }
275 mIsLocked = false;
276 return rc;
277}
278
279
280MediumLockListMap::MediumLockListMap()
281{
282 mIsLocked = false;
283}
284
285MediumLockListMap::~MediumLockListMap()
286{
287 // destroying medium lock list maps is routinely done as part of
288 // error handling and it's not expected to lose error info
289 ErrorInfoKeeper eik;
290 Clear();
291 // rest is done by the map object's destructor
292}
293
294bool MediumLockListMap::IsEmpty()
295{
296 return mMediumLocks.empty();
297}
298
299HRESULT MediumLockListMap::Insert(const ComObjPtr<MediumAttachment> &aMediumAttachment,
300 MediumLockList *aMediumLockList)
301{
302 if (mIsLocked)
303 return VBOX_E_INVALID_OBJECT_STATE;
304 mMediumLocks[aMediumAttachment] = aMediumLockList;
305 return S_OK;
306}
307
308HRESULT MediumLockListMap::ReplaceKey(const ComObjPtr<MediumAttachment> &aMediumAttachmentOld,
309 const ComObjPtr<MediumAttachment> &aMediumAttachmentNew)
310{
311 MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachmentOld);
312 if (it == mMediumLocks.end())
313 return VBOX_E_INVALID_OBJECT_STATE;
314 MediumLockList *pMediumLockList = it->second;
315 mMediumLocks.erase(it);
316 mMediumLocks[aMediumAttachmentNew] = pMediumLockList;
317 return S_OK;
318}
319
320HRESULT MediumLockListMap::Remove(const ComObjPtr<MediumAttachment> &aMediumAttachment)
321{
322 MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachment);
323 if (it == mMediumLocks.end())
324 return VBOX_E_INVALID_OBJECT_STATE;
325 MediumLockList *pMediumLockList = it->second;
326 mMediumLocks.erase(it);
327 delete pMediumLockList;
328 return S_OK;
329}
330
331HRESULT MediumLockListMap::Clear()
332{
333 HRESULT rc = Unlock();
334 for (MediumLockListMap::Base::iterator it = mMediumLocks.begin();
335 it != mMediumLocks.end();
336 ++it)
337 {
338 MediumLockList *pMediumLockList = it->second;
339 delete pMediumLockList;
340 }
341 mMediumLocks.clear();
342 return rc;
343}
344
345HRESULT MediumLockListMap::Get(const ComObjPtr<MediumAttachment> &aMediumAttachment,
346 MediumLockList * &aMediumLockList)
347{
348 MediumLockListMap::Base::iterator it = mMediumLocks.find(aMediumAttachment);
349 if (it == mMediumLocks.end())
350 {
351 aMediumLockList = NULL;
352 return VBOX_E_INVALID_OBJECT_STATE;
353 }
354 aMediumLockList = it->second;
355 return S_OK;
356}
357
358HRESULT MediumLockListMap::Lock()
359{
360 if (mIsLocked)
361 return S_OK;
362 HRESULT rc = S_OK;
363 for (MediumLockListMap::Base::const_iterator it = mMediumLocks.begin();
364 it != mMediumLocks.end();
365 ++it)
366 {
367 rc = it->second->Lock();
368 if (FAILED(rc))
369 {
370 for (MediumLockListMap::Base::const_iterator it2 = mMediumLocks.begin();
371 it2 != it;
372 ++it2)
373 {
374 HRESULT rc2 = it2->second->Unlock();
375 AssertComRC(rc2);
376 }
377 break;
378 }
379 }
380 if (SUCCEEDED(rc))
381 mIsLocked = true;
382 return rc;
383}
384
385HRESULT MediumLockListMap::Unlock()
386{
387 if (!mIsLocked)
388 return S_OK;
389 HRESULT rc = S_OK;
390 for (MediumLockListMap::Base::const_iterator it = mMediumLocks.begin();
391 it != mMediumLocks.end();
392 ++it)
393 {
394 MediumLockList *pMediumLockList = it->second;
395 HRESULT rc2 = pMediumLockList->Unlock();
396 if (SUCCEEDED(rc) && FAILED(rc2))
397 rc = rc2;
398 }
399 mIsLocked = false;
400 return rc;
401}
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