VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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