VirtualBox

source: vbox/trunk/src/VBox/Main/ParallelPortImpl.cpp@ 25279

Last change on this file since 25279 was 25279, checked in by vboxsync, 15 years ago

Main: preparation for deadlock detection: clean up autolock classes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/* $Id: ParallelPortImpl.cpp 25279 2009-12-09 17:50:26Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "ParallelPortImpl.h"
23#include "MachineImpl.h"
24#include "VirtualBoxImpl.h"
25#include "Logging.h"
26
27#include <iprt/string.h>
28#include <iprt/cpputils.h>
29
30#include <VBox/settings.h>
31
32////////////////////////////////////////////////////////////////////////////////
33//
34// ParallelPort private data definition
35//
36////////////////////////////////////////////////////////////////////////////////
37
38struct ParallelPort::Data
39{
40 Data()
41 { }
42
43 const ComObjPtr<Machine, ComWeakRef> pMachine;
44 const ComObjPtr<ParallelPort> pPeer;
45
46 Backupable<settings::ParallelPort> bd;
47};
48
49// constructor / destructor
50/////////////////////////////////////////////////////////////////////////////
51
52HRESULT ParallelPort::FinalConstruct()
53{
54 return S_OK;
55}
56
57void ParallelPort::FinalRelease()
58{
59 uninit();
60}
61
62// public initializer/uninitializer for internal purposes only
63/////////////////////////////////////////////////////////////////////////////
64
65/**
66 * Initializes the Parallel Port object.
67 *
68 * @param aParent Handle of the parent object.
69 */
70HRESULT ParallelPort::init(Machine *aParent, ULONG aSlot)
71{
72 LogFlowThisFunc(("aParent=%p, aSlot=%d\n", aParent, aSlot));
73
74 ComAssertRet (aParent, E_INVALIDARG);
75
76 /* Enclose the state transition NotReady->InInit->Ready */
77 AutoInitSpan autoInitSpan(this);
78 AssertReturn(autoInitSpan.isOk(), E_FAIL);
79
80 m = new Data;
81
82 unconst(m->pMachine) = aParent;
83 /* m->pPeer is left null */
84
85 m->bd.allocate();
86
87 /* initialize data */
88 m->bd->ulSlot = aSlot;
89
90 /* Confirm a successful initialization */
91 autoInitSpan.setSucceeded();
92
93 return S_OK;
94}
95
96/**
97 * Initializes the Parallel Port object given another serial port object
98 * (a kind of copy constructor). This object shares data with
99 * the object passed as an argument.
100 *
101 * @note This object must be destroyed before the original object
102 * it shares data with is destroyed.
103 *
104 * @note Locks @a aThat object for reading.
105 */
106HRESULT ParallelPort::init(Machine *aParent, ParallelPort *aThat)
107{
108 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
109
110 ComAssertRet (aParent && aThat, E_INVALIDARG);
111
112 /* Enclose the state transition NotReady->InInit->Ready */
113 AutoInitSpan autoInitSpan(this);
114 AssertReturn(autoInitSpan.isOk(), E_FAIL);
115
116 m = new Data;
117
118 unconst(m->pMachine) = aParent;
119 unconst(m->pPeer) = aThat;
120
121 AutoCaller thatCaller (aThat);
122 AssertComRCReturnRC(thatCaller.rc());
123
124 AutoReadLock thatLock(aThat);
125 m->bd.share(aThat->m->bd);
126
127 /* Confirm a successful initialization */
128 autoInitSpan.setSucceeded();
129
130 return S_OK;
131}
132
133/**
134 * Initializes the guest object given another guest object
135 * (a kind of copy constructor). This object makes a private copy of data
136 * of the original object passed as an argument.
137 *
138 * @note Locks @a aThat object for reading.
139 */
140HRESULT ParallelPort::initCopy(Machine *aParent, ParallelPort *aThat)
141{
142 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
143
144 ComAssertRet (aParent && aThat, E_INVALIDARG);
145
146 /* Enclose the state transition NotReady->InInit->Ready */
147 AutoInitSpan autoInitSpan(this);
148 AssertReturn(autoInitSpan.isOk(), E_FAIL);
149
150 m = new Data;
151
152 unconst(m->pMachine) = aParent;
153 /* m->pPeer is left null */
154
155 AutoCaller thatCaller(aThat);
156 AssertComRCReturnRC(thatCaller.rc());
157
158 AutoReadLock thatLock(aThat);
159 m->bd.attachCopy(aThat->m->bd);
160
161 /* Confirm a successful initialization */
162 autoInitSpan.setSucceeded();
163
164 return S_OK;
165}
166
167/**
168 * Uninitializes the instance and sets the ready flag to FALSE.
169 * Called either from FinalRelease() or by the parent when it gets destroyed.
170 */
171void ParallelPort::uninit()
172{
173 LogFlowThisFunc(("\n"));
174
175 /* Enclose the state transition Ready->InUninit->NotReady */
176 AutoUninitSpan autoUninitSpan(this);
177 if (autoUninitSpan.uninitDone())
178 return;
179
180 m->bd.free();
181
182 unconst(m->pPeer).setNull();
183 unconst(m->pMachine).setNull();
184
185 delete m;
186 m = NULL;
187}
188
189// IParallelPort properties
190/////////////////////////////////////////////////////////////////////////////
191
192STDMETHODIMP ParallelPort::COMGETTER(Enabled) (BOOL *aEnabled)
193{
194 CheckComArgOutPointerValid(aEnabled);
195
196 AutoCaller autoCaller(this);
197 if (FAILED(autoCaller.rc())) return autoCaller.rc();
198
199 AutoReadLock alock(this);
200
201 *aEnabled = m->bd->fEnabled;
202
203 return S_OK;
204}
205
206STDMETHODIMP ParallelPort::COMSETTER(Enabled) (BOOL aEnabled)
207{
208 LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled));
209
210 AutoCaller autoCaller(this);
211 if (FAILED(autoCaller.rc())) return autoCaller.rc();
212
213 /* the machine needs to be mutable */
214 Machine::AutoMutableStateDependency adep(m->pMachine);
215 if (FAILED(adep.rc())) return adep.rc();
216
217 AutoWriteLock alock(this);
218
219 if (m->bd->fEnabled != aEnabled)
220 {
221 if (aEnabled &&
222 m->bd->strPath.isEmpty())
223 return setError (E_INVALIDARG,
224 tr ("Cannot enable the parallel port %d "
225 "because the port path is empty or null"),
226 m->bd->ulSlot);
227
228 m->bd.backup();
229 m->bd->fEnabled = aEnabled;
230
231 /* leave the lock before informing callbacks */
232 alock.release();
233
234 m->pMachine->onParallelPortChange (this);
235 }
236
237 return S_OK;
238}
239
240STDMETHODIMP ParallelPort::COMGETTER(Slot) (ULONG *aSlot)
241{
242 CheckComArgOutPointerValid(aSlot);
243
244 AutoCaller autoCaller(this);
245 if (FAILED(autoCaller.rc())) return autoCaller.rc();
246
247 AutoReadLock alock(this);
248
249 *aSlot = m->bd->ulSlot;
250
251 return S_OK;
252}
253
254STDMETHODIMP ParallelPort::COMGETTER(IRQ) (ULONG *aIRQ)
255{
256 CheckComArgOutPointerValid(aIRQ);
257
258 AutoCaller autoCaller(this);
259 if (FAILED(autoCaller.rc())) return autoCaller.rc();
260
261 AutoReadLock alock(this);
262
263 *aIRQ = m->bd->ulIRQ;
264
265 return S_OK;
266}
267
268STDMETHODIMP ParallelPort::COMSETTER(IRQ)(ULONG aIRQ)
269{
270 /* check IRQ limits
271 * (when changing this, make sure it corresponds to XML schema */
272 if (aIRQ > 255)
273 return setError (E_INVALIDARG,
274 tr ("Invalid IRQ number of the parallel port %d: "
275 "%lu (must be in range [0, %lu])"),
276 m->bd->ulSlot, aIRQ, 255);
277
278 AutoCaller autoCaller(this);
279 if (FAILED(autoCaller.rc())) return autoCaller.rc();
280
281 /* the machine needs to be mutable */
282 Machine::AutoMutableStateDependency adep(m->pMachine);
283 if (FAILED(adep.rc())) return adep.rc();
284
285 AutoWriteLock alock(this);
286
287 HRESULT rc = S_OK;
288 bool emitChangeEvent = false;
289
290 if (m->bd->ulIRQ != aIRQ)
291 {
292 m->bd.backup();
293 m->bd->ulIRQ = aIRQ;
294 emitChangeEvent = true;
295 }
296
297 if (emitChangeEvent)
298 {
299 /* leave the lock before informing callbacks */
300 alock.release();
301
302 m->pMachine->onParallelPortChange (this);
303 }
304
305 return rc;
306}
307
308STDMETHODIMP ParallelPort::COMGETTER(IOBase) (ULONG *aIOBase)
309{
310 CheckComArgOutPointerValid(aIOBase);
311
312 AutoCaller autoCaller(this);
313 if (FAILED(autoCaller.rc())) return autoCaller.rc();
314
315 AutoReadLock alock(this);
316
317 *aIOBase = m->bd->ulIOBase;
318
319 return S_OK;
320}
321
322STDMETHODIMP ParallelPort::COMSETTER(IOBase)(ULONG aIOBase)
323{
324 /* check IOBase limits
325 * (when changing this, make sure it corresponds to XML schema */
326 if (aIOBase > 0xFFFF)
327 return setError (E_INVALIDARG,
328 tr ("Invalid I/O port base address of the parallel port %d: "
329 "%lu (must be in range [0, 0x%X])"),
330 m->bd->ulSlot, aIOBase, 0, 0xFFFF);
331
332 AutoCaller autoCaller(this);
333 if (FAILED(autoCaller.rc())) return autoCaller.rc();
334
335 /* the machine needs to be mutable */
336 Machine::AutoMutableStateDependency adep(m->pMachine);
337 if (FAILED(adep.rc())) return adep.rc();
338
339 AutoWriteLock alock(this);
340
341 HRESULT rc = S_OK;
342 bool emitChangeEvent = false;
343
344 if (m->bd->ulIOBase != aIOBase)
345 {
346 m->bd.backup();
347 m->bd->ulIOBase = aIOBase;
348 emitChangeEvent = true;
349 }
350
351 if (emitChangeEvent)
352 {
353 /* leave the lock before informing callbacks */
354 alock.release();
355
356 m->pMachine->onParallelPortChange (this);
357 }
358
359 return rc;
360}
361
362STDMETHODIMP ParallelPort::COMGETTER(Path) (BSTR *aPath)
363{
364 CheckComArgOutPointerValid(aPath);
365
366 AutoCaller autoCaller(this);
367 if (FAILED(autoCaller.rc())) return autoCaller.rc();
368
369 AutoReadLock alock(this);
370
371 m->bd->strPath.cloneTo(aPath);
372
373 return S_OK;
374}
375
376STDMETHODIMP ParallelPort::COMSETTER(Path) (IN_BSTR aPath)
377{
378 AutoCaller autoCaller(this);
379 if (FAILED(autoCaller.rc())) return autoCaller.rc();
380
381 /* the machine needs to be mutable */
382 Machine::AutoMutableStateDependency adep(m->pMachine);
383 if (FAILED(adep.rc())) return adep.rc();
384
385 AutoWriteLock alock(this);
386
387 Utf8Str str(aPath);
388 if (str != m->bd->strPath)
389 {
390 HRESULT rc = checkSetPath(str);
391 if (FAILED(rc)) return rc;
392
393 m->bd.backup();
394 m->bd->strPath = str;
395
396 /* leave the lock before informing callbacks */
397 alock.release();
398
399 return m->pMachine->onParallelPortChange(this);
400 }
401
402 return S_OK;
403}
404
405// public methods only for internal purposes
406////////////////////////////////////////////////////////////////////////////////
407
408/**
409 * Loads settings from the given port node.
410 * May be called once right after this object creation.
411 *
412 * @param aPortNode <Port> node.
413 *
414 * @note Locks this object for writing.
415 */
416HRESULT ParallelPort::loadSettings(const settings::ParallelPort &data)
417{
418 AutoCaller autoCaller(this);
419 AssertComRCReturnRC(autoCaller.rc());
420
421 AutoWriteLock alock(this);
422
423 // simply copy
424 *m->bd.data() = data;
425
426 return S_OK;
427}
428
429/**
430 * Saves settings to the given port node.
431 *
432 * Note that the given Port node is comletely empty on input.
433 *
434 * @param aPortNode <Port> node.
435 *
436 * @note Locks this object for reading.
437 */
438HRESULT ParallelPort::saveSettings(settings::ParallelPort &data)
439{
440 AutoCaller autoCaller(this);
441 AssertComRCReturnRC(autoCaller.rc());
442
443 AutoReadLock alock(this);
444
445 // simply copy
446 data = *m->bd.data();
447
448 return S_OK;
449}
450
451bool ParallelPort::isModified()
452{
453 AutoWriteLock alock (this);
454 return m->bd.isBackedUp();
455}
456
457bool ParallelPort::isReallyModified()
458{
459 AutoWriteLock alock(this);
460 return m->bd.hasActualChanges();
461}
462
463/**
464 * @note Locks this object for writing.
465 */
466bool ParallelPort::rollback()
467{
468 /* sanity */
469 AutoCaller autoCaller(this);
470 AssertComRCReturn (autoCaller.rc(), false);
471
472 AutoWriteLock alock(this);
473
474 bool changed = false;
475
476 if (m->bd.isBackedUp())
477 {
478 /* we need to check all data to see whether anything will be changed
479 * after rollback */
480 changed = m->bd.hasActualChanges();
481 m->bd.rollback();
482 }
483
484 return changed;
485}
486
487/**
488 * @note Locks this object for writing, together with the peer object (also
489 * for writing) if there is one.
490 */
491void ParallelPort::commit()
492{
493 /* sanity */
494 AutoCaller autoCaller(this);
495 AssertComRCReturnVoid (autoCaller.rc());
496
497 /* sanity too */
498 AutoCaller peerCaller (m->pPeer);
499 AssertComRCReturnVoid (peerCaller.rc());
500
501 /* lock both for writing since we modify both (m->pPeer is "master" so locked
502 * first) */
503 AutoMultiWriteLock2 alock (m->pPeer, this);
504
505 if (m->bd.isBackedUp())
506 {
507 m->bd.commit();
508 if (m->pPeer)
509 {
510 /* attach new data to the peer and reshare it */
511 m->pPeer->m->bd.attach(m->bd);
512 }
513 }
514}
515
516/**
517 * @note Locks this object for writing, together with the peer object
518 * represented by @a aThat (locked for reading).
519 */
520void ParallelPort::copyFrom(ParallelPort *aThat)
521{
522 AssertReturnVoid (aThat != NULL);
523
524 /* sanity */
525 AutoCaller autoCaller(this);
526 AssertComRCReturnVoid (autoCaller.rc());
527
528 /* sanity too */
529 AutoCaller thatCaller (aThat);
530 AssertComRCReturnVoid (thatCaller.rc());
531
532 /* peer is not modified, lock it for reading (aThat is "master" so locked
533 * first) */
534 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
535
536 /* this will back up current data */
537 m->bd.assignCopy(aThat->m->bd);
538}
539
540/**
541 * Validates COMSETTER(Path) arguments.
542 */
543HRESULT ParallelPort::checkSetPath(const Utf8Str &str)
544{
545 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
546
547 if ( m->bd->fEnabled
548 && str.isEmpty()
549 )
550 return setError(E_INVALIDARG,
551 tr("Path of the parallel port %d may not be empty or null "
552 "when the port is enabled"),
553 m->bd->ulSlot);
554
555 return S_OK;
556}
557
558
559/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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