VirtualBox

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

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

misc compiler warning fixes, comment typos and other minor cleanups

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 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 mObj = aObj;
144 add();
145 }
146 }
147
148 /** Verbose equivalent to <tt>attach (NULL)</tt>. */
149 void detach() { attach(NULL); }
150
151private:
152
153 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoCallerBase)
154 DECLARE_CLS_NEW_DELETE_NOOP(AutoCallerBase)
155
156 VirtualBoxBase *mObj;
157 HRESULT mRC;
158 VirtualBoxBase::State mState;
159};
160
161/**
162 * Smart class that automatically increases the number of normal
163 * (non-limited) callers of the given VirtualBoxBase object when an instance
164 * is constructed and decreases it back when the created instance goes out
165 * of scope (i.e. gets destroyed).
166 *
167 * A typical usage pattern to declare a normal method of some object (i.e. a
168 * method that is valid only when the object provides its full
169 * functionality) is:
170 * <code>
171 * STDMETHODIMP Component::Foo()
172 * {
173 * AutoCaller autoCaller(this);
174 * if (FAILED(autoCaller.rc())) return autoCaller.rc();
175 * ...
176 * </code>
177 *
178 * Using this class is equivalent to using the AutoCallerBase template with
179 * the @a aLimited argument set to |false|, but this class is preferred
180 * because provides better self-descriptiveness.
181 *
182 * See AutoCallerBase for more information about auto caller functionality.
183 */
184typedef AutoCallerBase<false> AutoCaller;
185
186/**
187 * Smart class that automatically increases the number of limited callers of
188 * the given VirtualBoxBase object when an instance is constructed and
189 * decreases it back when the created instance goes out of scope (i.e. gets
190 * destroyed).
191 *
192 * A typical usage pattern to declare a limited method of some object (i.e.
193 * a method that is valid even if the object doesn't provide its full
194 * functionality) is:
195 * <code>
196 * STDMETHODIMP Component::Bar()
197 * {
198 * AutoLimitedCaller autoCaller(this);
199 * if (FAILED(autoCaller.rc())) return autoCaller.rc();
200 * ...
201 * </code>
202 *
203 * Using this class is equivalent to using the AutoCallerBase template with
204 * the @a aLimited argument set to |true|, but this class is preferred
205 * because provides better self-descriptiveness.
206 *
207 * See AutoCallerBase for more information about auto caller functionality.
208 */
209typedef AutoCallerBase<true> AutoLimitedCaller;
210
211/**
212 * Smart class to enclose the state transition NotReady->InInit->Ready.
213 *
214 * The purpose of this span is to protect object initialization.
215 *
216 * Instances must be created as a stack-based variable taking |this| pointer
217 * as the argument at the beginning of init() methods of VirtualBoxBase
218 * subclasses. When this variable is created it automatically places the
219 * object to the InInit state.
220 *
221 * When the created variable goes out of scope (i.e. gets destroyed) then,
222 * depending on the result status of this initialization span, it either
223 * places the object to Ready or Limited state or calls the object's
224 * VirtualBoxBase::uninit() method which is supposed to place the object
225 * back to the NotReady state using the AutoUninitSpan class.
226 *
227 * The initial result status of the initialization span is determined by the
228 * @a aResult argument of the AutoInitSpan constructor (Result::Failed by
229 * default). Inside the initialization span, the success status can be set
230 * to Result::Succeeded using #setSucceeded(), to to Result::Limited using
231 * #setLimited() or to Result::Failed using #setFailed(). Please don't
232 * forget to set the correct success status before getting the AutoInitSpan
233 * variable destroyed (for example, by performing an early return from
234 * the init() method)!
235 *
236 * Note that if an instance of this class gets constructed when the object
237 * is in the state other than NotReady, #isOk() returns |false| and methods
238 * of this class do nothing: the state transition is not performed.
239 *
240 * A typical usage pattern is:
241 * <code>
242 * HRESULT Component::init()
243 * {
244 * AutoInitSpan autoInitSpan (this);
245 * AssertReturn (autoInitSpan.isOk(), E_FAIL);
246 * ...
247 * if (FAILED(rc))
248 * return rc;
249 * ...
250 * if (SUCCEEDED(rc))
251 * autoInitSpan.setSucceeded();
252 * return rc;
253 * }
254 * </code>
255 *
256 * @note Never create instances of this class outside init() methods of
257 * VirtualBoxBase subclasses and never pass anything other than |this|
258 * as the argument to the constructor!
259 */
260class AutoInitSpan
261{
262public:
263
264 enum Result { Failed = 0x0, Succeeded = 0x1, Limited = 0x2 };
265
266 AutoInitSpan(VirtualBoxBase *aObj, Result aResult = Failed);
267 ~AutoInitSpan();
268
269 /**
270 * Returns |true| if this instance has been created at the right moment
271 * (when the object was in the NotReady state) and |false| otherwise.
272 */
273 bool isOk() const { return mOk; }
274
275 /**
276 * Sets the initialization status to Succeeded to indicates successful
277 * initialization. The AutoInitSpan destructor will place the managed
278 * VirtualBoxBase object to the Ready state.
279 */
280 void setSucceeded() { mResult = Succeeded; }
281
282 /**
283 * Sets the initialization status to Succeeded to indicate limited
284 * (partly successful) initialization. The AutoInitSpan destructor will
285 * place the managed VirtualBoxBase object to the Limited state.
286 */
287 void setLimited() { mResult = Limited; }
288
289 /**
290 * Sets the initialization status to Failure to indicates failed
291 * initialization. The AutoInitSpan destructor will place the managed
292 * VirtualBoxBase object to the InitFailed state and will automatically
293 * call its uninit() method which is supposed to place the object back
294 * to the NotReady state using AutoUninitSpan.
295 */
296 void setFailed() { mResult = Failed; }
297
298 /** Returns the current initialization result. */
299 Result result() { return mResult; }
300
301private:
302
303 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoInitSpan)
304 DECLARE_CLS_NEW_DELETE_NOOP(AutoInitSpan)
305
306 VirtualBoxBase *mObj;
307 Result mResult : 3; // must be at least total number of bits + 1 (sign)
308 bool mOk : 1;
309};
310
311/**
312 * Smart class to enclose the state transition Limited->InInit->Ready.
313 *
314 * The purpose of this span is to protect object re-initialization.
315 *
316 * Instances must be created as a stack-based variable taking |this| pointer
317 * as the argument at the beginning of methods of VirtualBoxBase
318 * subclasses that try to re-initialize the object to bring it to the Ready
319 * state (full functionality) after partial initialization (limited
320 * functionality). When this variable is created, it automatically places
321 * the object to the InInit state.
322 *
323 * When the created variable goes out of scope (i.e. gets destroyed),
324 * depending on the success status of this initialization span, it either
325 * places the object to the Ready state or brings it back to the Limited
326 * state.
327 *
328 * The initial success status of the re-initialization span is |false|. In
329 * order to make it successful, #setSucceeded() must be called before the
330 * instance is destroyed.
331 *
332 * Note that if an instance of this class gets constructed when the object
333 * is in the state other than Limited, #isOk() returns |false| and methods
334 * of this class do nothing: the state transition is not performed.
335 *
336 * A typical usage pattern is:
337 * <code>
338 * HRESULT Component::reinit()
339 * {
340 * AutoReinitSpan autoReinitSpan (this);
341 * AssertReturn (autoReinitSpan.isOk(), E_FAIL);
342 * ...
343 * if (FAILED(rc))
344 * return rc;
345 * ...
346 * if (SUCCEEDED(rc))
347 * autoReinitSpan.setSucceeded();
348 * return rc;
349 * }
350 * </code>
351 *
352 * @note Never create instances of this class outside re-initialization
353 * methods of VirtualBoxBase subclasses and never pass anything other than
354 * |this| as the argument to the constructor!
355 */
356class AutoReinitSpan
357{
358public:
359
360 AutoReinitSpan(VirtualBoxBase *aObj);
361 ~AutoReinitSpan();
362
363 /**
364 * Returns |true| if this instance has been created at the right moment
365 * (when the object was in the Limited state) and |false| otherwise.
366 */
367 bool isOk() const { return mOk; }
368
369 /**
370 * Sets the re-initialization status to Succeeded to indicates
371 * successful re-initialization. The AutoReinitSpan destructor will place
372 * the managed VirtualBoxBase object to the Ready state.
373 */
374 void setSucceeded() { mSucceeded = true; }
375
376private:
377
378 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReinitSpan)
379 DECLARE_CLS_NEW_DELETE_NOOP(AutoReinitSpan)
380
381 VirtualBoxBase *mObj;
382 bool mSucceeded : 1;
383 bool mOk : 1;
384};
385
386/**
387 * Smart class to enclose the state transition Ready->InUninit->NotReady,
388 * InitFailed->InUninit->NotReady.
389 *
390 * The purpose of this span is to protect object uninitialization.
391 *
392 * Instances must be created as a stack-based variable taking |this| pointer
393 * as the argument at the beginning of uninit() methods of VirtualBoxBase
394 * subclasses. When this variable is created it automatically places the
395 * object to the InUninit state, unless it is already in the NotReady state
396 * as indicated by #uninitDone() returning |true|. In the latter case, the
397 * uninit() method must immediately return because there should be nothing
398 * to uninitialize.
399 *
400 * When this variable goes out of scope (i.e. gets destroyed), it places the
401 * object to NotReady state.
402 *
403 * A typical usage pattern is:
404 * <code>
405 * void Component::uninit()
406 * {
407 * AutoUninitSpan autoUninitSpan (this);
408 * if (autoUninitSpan.uninitDone())
409 * return;
410 * ...
411 * }
412 * </code>
413 *
414 * @note The constructor of this class blocks the current thread execution
415 * until the number of callers added to the object using #addCaller()
416 * or AutoCaller drops to zero. For this reason, it is forbidden to
417 * create instances of this class (or call uninit()) within the
418 * AutoCaller or #addCaller() scope because it is a guaranteed
419 * deadlock.
420 *
421 * @note Never create instances of this class outside uninit() methods and
422 * never pass anything other than |this| as the argument to the
423 * constructor!
424 */
425class AutoUninitSpan
426{
427public:
428
429 AutoUninitSpan(VirtualBoxBase *aObj);
430 ~AutoUninitSpan();
431
432 /** |true| when uninit() is called as a result of init() failure */
433 bool initFailed() { return mInitFailed; }
434
435 /** |true| when uninit() has already been called (so the object is NotReady) */
436 bool uninitDone() { return mUninitDone; }
437
438private:
439
440 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoUninitSpan)
441 DECLARE_CLS_NEW_DELETE_NOOP(AutoUninitSpan)
442
443 VirtualBoxBase *mObj;
444 bool mInitFailed : 1;
445 bool mUninitDone : 1;
446};
447
448#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