VirtualBox

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

Last change on this file since 40084 was 39715, checked in by vboxsync, 13 years ago

nits.

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