VirtualBox

source: vbox/trunk/src/VBox/Main/FloppyDriveImpl.cpp@ 8061

Last change on this file since 8061 was 7992, checked in by vboxsync, 17 years ago

Main: Implemented true AutoReaderLock (#2768).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.1 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 "FloppyDriveImpl.h"
19#include "MachineImpl.h"
20#include "HostImpl.h"
21#include "HostFloppyDriveImpl.h"
22#include "VirtualBoxImpl.h"
23
24#include "Logging.h"
25
26#include <iprt/string.h>
27#include <iprt/cpputils.h>
28
29// constructor / destructor
30/////////////////////////////////////////////////////////////////////////////
31
32DEFINE_EMPTY_CTOR_DTOR (FloppyDrive)
33
34HRESULT FloppyDrive::FinalConstruct()
35{
36 return S_OK;
37}
38
39void FloppyDrive::FinalRelease()
40{
41 uninit();
42}
43
44// public initializer/uninitializer for internal purposes only
45/////////////////////////////////////////////////////////////////////////////
46
47/**
48 * Initializes the Floppy drive object.
49 *
50 * @param aParent Handle of the parent object.
51 */
52HRESULT FloppyDrive::init (Machine *aParent)
53{
54 LogFlowThisFunc (("aParent=%p\n", aParent));
55
56 ComAssertRet (aParent, E_INVALIDARG);
57
58 /* Enclose the state transition NotReady->InInit->Ready */
59 AutoInitSpan autoInitSpan (this);
60 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
61
62 unconst (mParent) = aParent;
63 /* mPeer is left null */
64
65 mData.allocate();
66
67 /* Confirm a successful initialization */
68 autoInitSpan.setSucceeded();
69
70 return S_OK;
71}
72
73/**
74 * Initializes the Floppy drive object given another Floppy drive object
75 * (a kind of copy constructor). This object shares data with
76 * the object passed as an argument.
77 *
78 * @note This object must be destroyed before the original object
79 * it shares data with is destroyed.
80 *
81 * @note Locks @a aThat object for reading.
82 */
83HRESULT FloppyDrive::init (Machine *aParent, FloppyDrive *aThat)
84{
85 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
86
87 ComAssertRet (aParent && aThat, E_INVALIDARG);
88
89 /* Enclose the state transition NotReady->InInit->Ready */
90 AutoInitSpan autoInitSpan (this);
91 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
92
93 unconst (mParent) = aParent;
94 unconst (mPeer) = aThat;
95
96 AutoCaller thatCaller (aThat);
97 AssertComRCReturnRC (thatCaller.rc());
98
99 AutoReaderLock thatLock (aThat);
100 mData.share (aThat->mData);
101
102 /* Confirm a successful initialization */
103 autoInitSpan.setSucceeded();
104
105 return S_OK;
106}
107
108/**
109 * Initializes the guest object given another guest object
110 * (a kind of copy constructor). This object makes a private copy of data
111 * of the original object passed as an argument.
112 *
113 * @note Locks @a aThat object for reading.
114 */
115HRESULT FloppyDrive::initCopy (Machine *aParent, FloppyDrive *aThat)
116{
117 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
118
119 ComAssertRet (aParent && aThat, E_INVALIDARG);
120
121 /* Enclose the state transition NotReady->InInit->Ready */
122 AutoInitSpan autoInitSpan (this);
123 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
124
125 unconst (mParent) = aParent;
126 /* mPeer is left null */
127
128 AutoCaller thatCaller (aThat);
129 AssertComRCReturnRC (thatCaller.rc());
130
131 AutoReaderLock thatLock (aThat);
132 mData.attachCopy (aThat->mData);
133
134 /* Confirm a successful initialization */
135 autoInitSpan.setSucceeded();
136
137 return S_OK;
138}
139
140/**
141 * Uninitializes the instance and sets the ready flag to FALSE.
142 * Called either from FinalRelease() or by the parent when it gets destroyed.
143 */
144void FloppyDrive::uninit()
145{
146 LogFlowThisFunc (("\n"));
147
148 /* Enclose the state transition Ready->InUninit->NotReady */
149 AutoUninitSpan autoUninitSpan (this);
150 if (autoUninitSpan.uninitDone())
151 return;
152
153 mData.free();
154
155 unconst (mPeer).setNull();
156 unconst (mParent).setNull();
157}
158
159// IFloppyDrive properties
160/////////////////////////////////////////////////////////////////////////////
161
162STDMETHODIMP FloppyDrive::COMGETTER(Enabled) (BOOL *aEnabled)
163{
164 if (!aEnabled)
165 return E_POINTER;
166
167 AutoCaller autoCaller (this);
168 CheckComRCReturnRC (autoCaller.rc());
169
170 AutoReaderLock alock (this);
171
172 *aEnabled = mData->mEnabled;
173
174 return S_OK;
175}
176
177STDMETHODIMP FloppyDrive::COMSETTER(Enabled) (BOOL aEnabled)
178{
179 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
180
181 AutoCaller autoCaller (this);
182 CheckComRCReturnRC (autoCaller.rc());
183
184 /* the machine needs to be mutable */
185 Machine::AutoMutableStateDependency adep (mParent);
186 CheckComRCReturnRC (adep.rc());
187
188 AutoLock alock (this);
189
190 if (mData->mEnabled != aEnabled)
191 {
192 mData.backup();
193 mData->mEnabled = aEnabled;
194
195 /* leave the lock before informing callbacks */
196 alock.unlock();
197
198 mParent->onFloppyDriveChange();
199 }
200
201 return S_OK;
202}
203
204STDMETHODIMP FloppyDrive::COMGETTER(State) (DriveState_T *aDriveState)
205{
206 if (!aDriveState)
207 return E_POINTER;
208
209 AutoCaller autoCaller (this);
210 CheckComRCReturnRC (autoCaller.rc());
211
212 AutoReaderLock alock (this);
213
214 *aDriveState = mData->mDriveState;
215
216 return S_OK;
217}
218
219// IFloppyDrive methods
220/////////////////////////////////////////////////////////////////////////////
221
222STDMETHODIMP FloppyDrive::MountImage (INPTR GUIDPARAM aImageId)
223{
224 if (Guid::isEmpty (aImageId))
225 return E_INVALIDARG;
226
227 AutoCaller autoCaller (this);
228 CheckComRCReturnRC (autoCaller.rc());
229
230 /* the machine needs to be mutable */
231 Machine::AutoMutableStateDependency adep (mParent);
232 CheckComRCReturnRC (adep.rc());
233
234 AutoLock alock (this);
235
236 HRESULT rc = E_FAIL;
237
238 /* Our lifetime is bound to mParent's lifetime, so we don't add caller.
239 * We also don't lock mParent since its mParent field is const. */
240
241 ComPtr <IFloppyImage> image;
242 rc = mParent->virtualBox()->GetFloppyImage (aImageId, image.asOutParam());
243
244 if (SUCCEEDED (rc))
245 {
246 if (mData->mDriveState != DriveState_ImageMounted ||
247 !mData->mFloppyImage.equalsTo (image))
248 {
249 mData.backup();
250
251 unmount();
252
253 mData->mFloppyImage = image;
254 mData->mDriveState = DriveState_ImageMounted;
255
256 /* leave the lock before informing callbacks */
257 alock.unlock();
258
259 mParent->onFloppyDriveChange();
260 }
261 }
262
263 return rc;
264}
265
266STDMETHODIMP FloppyDrive::CaptureHostDrive (IHostFloppyDrive *aHostFloppyDrive)
267{
268 if (!aHostFloppyDrive)
269 return E_INVALIDARG;
270
271 AutoCaller autoCaller (this);
272 CheckComRCReturnRC (autoCaller.rc());
273
274 /* the machine needs to be mutable */
275 Machine::AutoMutableStateDependency adep (mParent);
276 CheckComRCReturnRC (adep.rc());
277
278 AutoLock alock (this);
279
280 if (mData->mDriveState != DriveState_HostDriveCaptured ||
281 !mData->mHostDrive.equalsTo (aHostFloppyDrive))
282 {
283 mData.backup();
284
285 unmount();
286
287 mData->mHostDrive = aHostFloppyDrive;
288 mData->mDriveState = DriveState_HostDriveCaptured;
289
290 /* leave the lock before informing callbacks */
291 alock.unlock();
292
293 mParent->onFloppyDriveChange();
294 }
295
296 return S_OK;
297}
298
299STDMETHODIMP FloppyDrive::Unmount()
300{
301 AutoCaller autoCaller (this);
302 CheckComRCReturnRC (autoCaller.rc());
303
304 /* the machine needs to be mutable */
305 Machine::AutoMutableStateDependency adep (mParent);
306 CheckComRCReturnRC (adep.rc());
307
308 AutoLock alock (this);
309
310 if (mData->mDriveState != DriveState_NotMounted)
311 {
312 mData.backup();
313
314 unmount();
315
316 mData->mDriveState = DriveState_NotMounted;
317
318 /* leave the lock before informing callbacks */
319 alock.unlock();
320
321 mParent->onFloppyDriveChange();
322 }
323
324 return S_OK;
325}
326
327STDMETHODIMP FloppyDrive::GetImage (IFloppyImage **aFloppyImage)
328{
329 if (!aFloppyImage)
330 return E_POINTER;
331
332 AutoCaller autoCaller (this);
333 CheckComRCReturnRC (autoCaller.rc());
334
335 AutoReaderLock alock (this);
336
337 mData->mFloppyImage.queryInterfaceTo (aFloppyImage);
338
339 return S_OK;
340}
341
342STDMETHODIMP FloppyDrive::GetHostDrive (IHostFloppyDrive **aHostDrive)
343{
344 if (!aHostDrive)
345 return E_POINTER;
346
347 AutoCaller autoCaller (this);
348 CheckComRCReturnRC (autoCaller.rc());
349
350 AutoReaderLock alock (this);
351
352 mData->mHostDrive.queryInterfaceTo (aHostDrive);
353
354 return S_OK;
355}
356
357// public methods only for internal purposes
358/////////////////////////////////////////////////////////////////////////////
359
360/**
361 * Loads settings from the given machine node.
362 * May be called once right after this object creation.
363 *
364 * @param aMachineNode <Machine> node.
365 *
366 * @note Locks this object for writing.
367 */
368HRESULT FloppyDrive::loadSettings (const settings::Key &aMachineNode)
369{
370 using namespace settings;
371
372 AssertReturn (!aMachineNode.isNull(), E_FAIL);
373
374 AutoCaller autoCaller (this);
375 AssertComRCReturnRC (autoCaller.rc());
376
377 AutoLock alock (this);
378
379 /* Note: we assume that the default values for attributes of optional
380 * nodes are assigned in the Data::Data() constructor and don't do it
381 * here. It implies that this method may only be called after constructing
382 * a new BIOSSettings object while all its data fields are in the default
383 * values. Exceptions are fields whose creation time defaults don't match
384 * values that should be applied when these fields are not explicitly set
385 * in the settings file (for backwards compatibility reasons). This takes
386 * place when a setting of a newly created object must default to A while
387 * the same setting of an object loaded from the old settings file must
388 * default to B. */
389
390 HRESULT rc = S_OK;
391
392 /* Floppy drive (required, contains either Image or HostDrive or nothing) */
393 Key floppyDriveNode = aMachineNode.key ("FloppyDrive");
394
395 /* optional, defaults to true */
396 mData->mEnabled = floppyDriveNode.value <bool> ("enabled");
397
398 Key typeNode;
399
400 if (!(typeNode = floppyDriveNode.findKey ("Image")).isNull())
401 {
402 Guid uuid = typeNode.value <Guid> ("uuid");
403 rc = MountImage (uuid);
404 CheckComRCReturnRC (rc);
405 }
406 else if (!(typeNode = floppyDriveNode.findKey ("HostDrive")).isNull())
407 {
408
409 Bstr src = typeNode.stringValue ("src");
410
411 /* find the correspoding object */
412 ComObjPtr <Host> host = mParent->virtualBox()->host();
413
414 ComPtr <IHostFloppyDriveCollection> coll;
415 rc = host->COMGETTER(FloppyDrives) (coll.asOutParam());
416 AssertComRC (rc);
417
418 ComPtr <IHostFloppyDrive> drive;
419 rc = coll->FindByName (src, drive.asOutParam());
420 if (SUCCEEDED (rc))
421 {
422 rc = CaptureHostDrive (drive);
423 CheckComRCReturnRC (rc);
424 }
425 else if (rc == E_INVALIDARG)
426 {
427 /* the host DVD drive is not currently available. we
428 * assume it will be available later and create an
429 * extra object now */
430 ComObjPtr <HostFloppyDrive> hostDrive;
431 hostDrive.createObject();
432 rc = hostDrive->init (src);
433 AssertComRC (rc);
434 rc = CaptureHostDrive (hostDrive);
435 CheckComRCReturnRC (rc);
436 }
437 else
438 AssertComRC (rc);
439 }
440
441 return S_OK;
442}
443
444/**
445 * Saves settings to the given machine node.
446 *
447 * @param aMachineNode <Machine> node.
448 *
449 * @note Locks this object for reading.
450 */
451HRESULT FloppyDrive::saveSettings (settings::Key &aMachineNode)
452{
453 using namespace settings;
454
455 AssertReturn (!aMachineNode.isNull(), E_FAIL);
456
457 AutoCaller autoCaller (this);
458 AssertComRCReturnRC (autoCaller.rc());
459
460 AutoReaderLock alock (this);
461
462 Key node = aMachineNode.createKey ("FloppyDrive");
463
464 node.setValue <bool> ("enabled", !!mData->mEnabled);
465
466 switch (mData->mDriveState)
467 {
468 case DriveState_ImageMounted:
469 {
470 Assert (!mData->mFloppyImage.isNull());
471
472 Guid id;
473 HRESULT rc = mData->mFloppyImage->COMGETTER(Id) (id.asOutParam());
474 AssertComRC (rc);
475 Assert (!id.isEmpty());
476
477 Key imageNode = node.createKey ("Image");
478 imageNode.setValue <Guid> ("uuid", id);
479 break;
480 }
481 case DriveState_HostDriveCaptured:
482 {
483 Assert (!mData->mHostDrive.isNull());
484
485 Bstr name;
486 HRESULT rc = mData->mHostDrive->COMGETTER(Name) (name.asOutParam());
487 AssertComRC (rc);
488 Assert (!name.isEmpty());
489
490 Key hostDriveNode = node.createKey ("HostDrive");
491 hostDriveNode.setValue <Bstr> ("src", name);
492 break;
493 }
494 case DriveState_NotMounted:
495 /* do nothing, i.e.leave the drive node empty */
496 break;
497 default:
498 ComAssertMsgFailedRet (("Invalid drive state: %d\n",
499 mData->mDriveState),
500 E_FAIL);
501 }
502
503 return S_OK;
504}
505
506/**
507 * @note Locks this object for writing.
508 */
509bool FloppyDrive::rollback()
510{
511 /* sanity */
512 AutoCaller autoCaller (this);
513 AssertComRCReturn (autoCaller.rc(), false);
514
515 AutoLock alock (this);
516
517 bool changed = false;
518
519 if (mData.isBackedUp())
520 {
521 /* we need to check all data to see whether anything will be changed
522 * after rollback */
523 changed = mData.hasActualChanges();
524 mData.rollback();
525 }
526
527 return changed;
528}
529
530/**
531 * @note Locks this object for writing, together with the peer object (also
532 * for writing) if there is one.
533 */
534void FloppyDrive::commit()
535{
536 /* sanity */
537 AutoCaller autoCaller (this);
538 AssertComRCReturnVoid (autoCaller.rc());
539
540 /* sanity too */
541 AutoCaller peerCaller (mPeer);
542 AssertComRCReturnVoid (peerCaller.rc());
543
544 /* lock both for writing since we modify both (mPeer is "master" so locked
545 * first) */
546 AutoMultiWriteLock2 alock (mPeer, this);
547
548 if (mData.isBackedUp())
549 {
550 mData.commit();
551 if (mPeer)
552 {
553 /* attach new data to the peer and reshare it */
554 mPeer->mData.attach (mData);
555 }
556 }
557}
558
559/**
560 * @note Locks this object for writing, together with the peer object (locked
561 * for reading) if there is one.
562 */
563void FloppyDrive::copyFrom (FloppyDrive *aThat)
564{
565 /* sanity */
566 AutoCaller autoCaller (this);
567 AssertComRCReturnVoid (autoCaller.rc());
568
569 /* sanity too */
570 AutoCaller thatCaller (aThat);
571 AssertComRCReturnVoid (thatCaller.rc());
572
573 /* peer is not modified, lock it for reading (aThat is "master" so locked
574 * first) */
575 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
576
577 /* this will back up current data */
578 mData.assignCopy (aThat->mData);
579}
580
581// private methods
582/////////////////////////////////////////////////////////////////////////////
583
584/**
585 * Helper to unmount a drive.
586 *
587 * @return COM status code
588 */
589HRESULT FloppyDrive::unmount()
590{
591 AssertReturn (isLockedOnCurrentThread(), E_FAIL);
592
593 if (mData->mFloppyImage)
594 mData->mFloppyImage.setNull();
595 if (mData->mHostDrive)
596 mData->mHostDrive.setNull();
597
598 return S_OK;
599}
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