VirtualBox

source: vbox/trunk/src/VBox/Main/include/AutoCaller.h@ 28398

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

Main/VirtualBoxCallback: rename OnSnapshotDiscard to OnSnapshotDeleted for consistency, clean up wording and other minor issues

  • 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 base classes definition
4 */
5
6/*
7 * Copyright (C) 2006-2010 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#ifndef ____H_AUTOCALLER
23#define ____H_AUTOCALLER
24
25////////////////////////////////////////////////////////////////////////////////
26//
27// AutoCaller* classes
28//
29////////////////////////////////////////////////////////////////////////////////
30
31/**
32 * Smart class that automatically increases the number of callers of the
33 * given VirtualBoxBase object when an instance is constructed and decreases
34 * it back when the created instance goes out of scope (i.e. gets destroyed).
35 *
36 * If #rc() returns a failure after the instance creation, it means that
37 * the managed VirtualBoxBase object is not Ready, or in any other invalid
38 * state, so that the caller must not use the object and can return this
39 * failed result code to the upper level.
40 *
41 * See VirtualBoxBase::addCaller(), VirtualBoxBase::addLimitedCaller() and
42 * VirtualBoxBase::releaseCaller() for more details about object callers.
43 *
44 * @param aLimited |false| if this template should use
45 * VirtualBoxBase::addCaller() calls to add callers, or
46 * |true| if VirtualBoxBase::addLimitedCaller() should be
47 * used.
48 *
49 * @note It is preferable to use the AutoCaller and AutoLimitedCaller
50 * classes than specify the @a aLimited argument, for better
51 * self-descriptiveness.
52 */
53template<bool aLimited>
54class AutoCallerBase
55{
56public:
57
58 /**
59 * Increases the number of callers of the given object by calling
60 * VirtualBoxBase::addCaller().
61 *
62 * @param aObj Object to add a caller to. If NULL, this
63 * instance is effectively turned to no-op (where
64 * rc() will return S_OK and state() will be
65 * NotReady).
66 */
67 AutoCallerBase(VirtualBoxBase *aObj)
68 : mObj(aObj), mRC(S_OK), mState(VirtualBoxBase::NotReady)
69 {
70 if (mObj)
71 mRC = mObj->addCaller(&mState, aLimited);
72 }
73
74 /**
75 * If the number of callers was successfully increased, decreases it
76 * using VirtualBoxBase::releaseCaller(), otherwise does nothing.
77 */
78 ~AutoCallerBase()
79 {
80 if (mObj && SUCCEEDED(mRC))
81 mObj->releaseCaller();
82 }
83
84 /**
85 * Stores the result code returned by VirtualBoxBase::addCaller() after
86 * instance creation or after the last #add() call. A successful result
87 * code means the number of callers was successfully increased.
88 */
89 HRESULT rc() const { return mRC; }
90
91 /**
92 * Returns |true| if |SUCCEEDED(rc())| is |true|, for convenience.
93 * |true| means the number of callers was successfully increased.
94 */
95 bool isOk() const { return SUCCEEDED(mRC); }
96
97 /**
98 * Stores the object state returned by VirtualBoxBase::addCaller() after
99 * instance creation or after the last #add() call.
100 */
101 VirtualBoxBase::State state() const { return mState; }
102
103 /**
104 * Temporarily decreases the number of callers of the managed object.
105 * May only be called if #isOk() returns |true|. Note that #rc() will
106 * return E_FAIL after this method succeeds.
107 */
108 void release()
109 {
110 Assert(SUCCEEDED(mRC));
111 if (SUCCEEDED(mRC))
112 {
113 if (mObj)
114 mObj->releaseCaller();
115 mRC = E_FAIL;
116 }
117 }
118
119 /**
120 * Restores the number of callers decreased by #release(). May only be
121 * called after #release().
122 */
123 void add()
124 {
125 Assert(!SUCCEEDED(mRC));
126 if (mObj && !SUCCEEDED(mRC))
127 mRC = mObj->addCaller(&mState, aLimited);
128 }
129
130 /**
131 * Attaches another object to this caller instance.
132 * The previous object's caller is released before the new one is added.
133 *
134 * @param aObj New object to attach, may be @c NULL.
135 */
136 void attach(VirtualBoxBase *aObj)
137 {
138 /* detect simple self-reattachment */
139 if (mObj != aObj)
140 {
141 if (mObj && SUCCEEDED(mRC))
142 release();
143 else if (!mObj)
144 {
145 /* Fix up the success state when nothing is attached. Otherwise
146 * there are a couple of assertion which would trigger. */
147 mRC = E_FAIL;
148 }
149 mObj = aObj;
150 add();
151 }
152 }
153
154 /** Verbose equivalent to <tt>attach (NULL)</tt>. */
155 void detach() { attach(NULL); }
156
157private:
158
159 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoCallerBase)
160 DECLARE_CLS_NEW_DELETE_NOOP(AutoCallerBase)
161
162 VirtualBoxBase *mObj;
163 HRESULT mRC;
164 VirtualBoxBase::State mState;
165};
166
167/**
168 * Smart class that automatically increases the number of normal
169 * (non-limited) callers of the given VirtualBoxBase object when an instance
170 * is constructed and decreases it back when the created instance goes out
171 * of scope (i.e. gets destroyed).
172 *
173 * A typical usage pattern to declare a normal method of some object (i.e. a
174 * method that is valid only when the object provides its full
175 * functionality) is:
176 * <code>
177 * STDMETHODIMP Component::Foo()
178 * {
179 * AutoCaller autoCaller(this);
180 * if (FAILED(autoCaller.rc())) return autoCaller.rc();
181 * ...
182 * </code>
183 *
184 * Using this class is equivalent to using the AutoCallerBase template with
185 * the @a aLimited argument set to |false|, but this class is preferred
186 * because provides better self-descriptiveness.
187 *
188 * See AutoCallerBase for more information about auto caller functionality.
189 */
190typedef AutoCallerBase<false> AutoCaller;
191
192/**
193 * Smart class that automatically increases the number of limited callers of
194 * the given VirtualBoxBase object when an instance is constructed and
195 * decreases it back when the created instance goes out of scope (i.e. gets
196 * destroyed).
197 *
198 * A typical usage pattern to declare a limited method of some object (i.e.
199 * a method that is valid even if the object doesn't provide its full
200 * functionality) is:
201 * <code>
202 * STDMETHODIMP Component::Bar()
203 * {
204 * AutoLimitedCaller autoCaller(this);
205 * if (FAILED(autoCaller.rc())) return autoCaller.rc();
206 * ...
207 * </code>
208 *
209 * Using this class is equivalent to using the AutoCallerBase template with
210 * the @a aLimited argument set to |true|, but this class is preferred
211 * because provides better self-descriptiveness.
212 *
213 * See AutoCallerBase for more information about auto caller functionality.
214 */
215typedef AutoCallerBase<true> AutoLimitedCaller;
216
217/**
218 * Smart class to enclose the state transition NotReady->InInit->Ready.
219 *
220 * The purpose of this span is to protect object initialization.
221 *
222 * Instances must be created as a stack-based variable taking |this| pointer
223 * as the argument at the beginning of init() methods of VirtualBoxBase
224 * subclasses. When this variable is created it automatically places the
225 * object to the InInit state.
226 *
227 * When the created variable goes out of scope (i.e. gets destroyed) then,
228 * depending on the result status of this initialization span, it either
229 * places the object to Ready or Limited state or calls the object's
230 * VirtualBoxBase::uninit() method which is supposed to place the object
231 * back to the NotReady state using the AutoUninitSpan class.
232 *
233 * The initial result status of the initialization span is determined by the
234 * @a aResult argument of the AutoInitSpan constructor (Result::Failed by
235 * default). Inside the initialization span, the success status can be set
236 * to Result::Succeeded using #setSucceeded(), to to Result::Limited using
237 * #setLimited() or to Result::Failed using #setFailed(). Please don't
238 * forget to set the correct success status before getting the AutoInitSpan
239 * variable destroyed (for example, by performing an early return from
240 * the init() method)!
241 *
242 * Note that if an instance of this class gets constructed when the object
243 * is in the state other than NotReady, #isOk() returns |false| and methods
244 * of this class do nothing: the state transition is not performed.
245 *
246 * A typical usage pattern is:
247 * <code>
248 * HRESULT Component::init()
249 * {
250 * AutoInitSpan autoInitSpan (this);
251 * AssertReturn (autoInitSpan.isOk(), E_FAIL);
252 * ...
253 * if (FAILED(rc))
254 * return rc;
255 * ...
256 * if (SUCCEEDED(rc))
257 * autoInitSpan.setSucceeded();
258 * return rc;
259 * }
260 * </code>
261 *
262 * @note Never create instances of this class outside init() methods of
263 * VirtualBoxBase subclasses and never pass anything other than |this|
264 * as the argument to the constructor!
265 */
266class AutoInitSpan
267{
268public:
269
270 enum Result { Failed = 0x0, Succeeded = 0x1, Limited = 0x2 };
271
272 AutoInitSpan(VirtualBoxBase *aObj, Result aResult = Failed);
273 ~AutoInitSpan();
274
275 /**
276 * Returns |true| if this instance has been created at the right moment
277 * (when the object was in the NotReady state) and |false| otherwise.
278 */
279 bool isOk() const { return mOk; }
280
281 /**
282 * Sets the initialization status to Succeeded to indicates successful
283 * initialization. The AutoInitSpan destructor will place the managed
284 * VirtualBoxBase object to the Ready state.
285 */
286 void setSucceeded() { mResult = Succeeded; }
287
288 /**
289 * Sets the initialization status to Succeeded to indicate limited
290 * (partly successful) initialization. The AutoInitSpan destructor will
291 * place the managed VirtualBoxBase object to the Limited state.
292 */
293 void setLimited() { mResult = Limited; }
294
295 /**
296 * Sets the initialization status to Failure to indicates failed
297 * initialization. The AutoInitSpan destructor will place the managed
298 * VirtualBoxBase object to the InitFailed state and will automatically
299 * call its uninit() method which is supposed to place the object back
300 * to the NotReady state using AutoUninitSpan.
301 */
302 void setFailed() { mResult = Failed; }
303
304 /** Returns the current initialization result. */
305 Result result() { return mResult; }
306
307private:
308
309 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoInitSpan)
310 DECLARE_CLS_NEW_DELETE_NOOP(AutoInitSpan)
311
312 VirtualBoxBase *mObj;
313 Result mResult : 3; // must be at least total number of bits + 1 (sign)
314 bool mOk : 1;
315};
316
317/**
318 * Smart class to enclose the state transition Limited->InInit->Ready.
319 *
320 * The purpose of this span is to protect object re-initialization.
321 *
322 * Instances must be created as a stack-based variable taking |this| pointer
323 * as the argument at the beginning of methods of VirtualBoxBase
324 * subclasses that try to re-initialize the object to bring it to the Ready
325 * state (full functionality) after partial initialization (limited
326 * functionality). When this variable is created, it automatically places
327 * the object to the InInit state.
328 *
329 * When the created variable goes out of scope (i.e. gets destroyed),
330 * depending on the success status of this initialization span, it either
331 * places the object to the Ready state or brings it back to the Limited
332 * state.
333 *
334 * The initial success status of the re-initialization span is |false|. In
335 * order to make it successful, #setSucceeded() must be called before the
336 * instance is destroyed.
337 *
338 * Note that if an instance of this class gets constructed when the object
339 * is in the state other than Limited, #isOk() returns |false| and methods
340 * of this class do nothing: the state transition is not performed.
341 *
342 * A typical usage pattern is:
343 * <code>
344 * HRESULT Component::reinit()
345 * {
346 * AutoReinitSpan autoReinitSpan (this);
347 * AssertReturn (autoReinitSpan.isOk(), E_FAIL);
348 * ...
349 * if (FAILED(rc))
350 * return rc;
351 * ...
352 * if (SUCCEEDED(rc))
353 * autoReinitSpan.setSucceeded();
354 * return rc;
355 * }
356 * </code>
357 *
358 * @note Never create instances of this class outside re-initialization
359 * methods of VirtualBoxBase subclasses and never pass anything other than
360 * |this| as the argument to the constructor!
361 */
362class AutoReinitSpan
363{
364public:
365
366 AutoReinitSpan(VirtualBoxBase *aObj);
367 ~AutoReinitSpan();
368
369 /**
370 * Returns |true| if this instance has been created at the right moment
371 * (when the object was in the Limited state) and |false| otherwise.
372 */
373 bool isOk() const { return mOk; }
374
375 /**
376 * Sets the re-initialization status to Succeeded to indicates
377 * successful re-initialization. The AutoReinitSpan destructor will place
378 * the managed VirtualBoxBase object to the Ready state.
379 */
380 void setSucceeded() { mSucceeded = true; }
381
382private:
383
384 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReinitSpan)
385 DECLARE_CLS_NEW_DELETE_NOOP(AutoReinitSpan)
386
387 VirtualBoxBase *mObj;
388 bool mSucceeded : 1;
389 bool mOk : 1;
390};
391
392/**
393 * Smart class to enclose the state transition Ready->InUninit->NotReady,
394 * InitFailed->InUninit->NotReady.
395 *
396 * The purpose of this span is to protect object uninitialization.
397 *
398 * Instances must be created as a stack-based variable taking |this| pointer
399 * as the argument at the beginning of uninit() methods of VirtualBoxBase
400 * subclasses. When this variable is created it automatically places the
401 * object to the InUninit state, unless it is already in the NotReady state
402 * as indicated by #uninitDone() returning |true|. In the latter case, the
403 * uninit() method must immediately return because there should be nothing
404 * to uninitialize.
405 *
406 * When this variable goes out of scope (i.e. gets destroyed), it places the
407 * object to NotReady state.
408 *
409 * A typical usage pattern is:
410 * <code>
411 * void Component::uninit()
412 * {
413 * AutoUninitSpan autoUninitSpan (this);
414 * if (autoUninitSpan.uninitDone())
415 * return;
416 * ...
417 * }
418 * </code>
419 *
420 * @note The constructor of this class blocks the current thread execution
421 * until the number of callers added to the object using #addCaller()
422 * or AutoCaller drops to zero. For this reason, it is forbidden to
423 * create instances of this class (or call uninit()) within the
424 * AutoCaller or #addCaller() scope because it is a guaranteed
425 * deadlock.
426 *
427 * @note Never create instances of this class outside uninit() methods and
428 * never pass anything other than |this| as the argument to the
429 * constructor!
430 */
431class AutoUninitSpan
432{
433public:
434
435 AutoUninitSpan(VirtualBoxBase *aObj);
436 ~AutoUninitSpan();
437
438 /** |true| when uninit() is called as a result of init() failure */
439 bool initFailed() { return mInitFailed; }
440
441 /** |true| when uninit() has already been called (so the object is NotReady) */
442 bool uninitDone() { return mUninitDone; }
443
444private:
445
446 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoUninitSpan)
447 DECLARE_CLS_NEW_DELETE_NOOP(AutoUninitSpan)
448
449 VirtualBoxBase *mObj;
450 bool mInitFailed : 1;
451 bool mUninitDone : 1;
452};
453
454#endif // !____H_AUTOCALLER
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