VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.9 KB
RevLine 
[55401]1/* $Id: AutoCaller.h 98103 2023-01-17 14:15:46Z vboxsync $ */
[1]2/** @file
3 *
[51903]4 * VirtualBox object caller handling definitions
[1]5 */
6
7/*
[98103]8 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]9 *
[96407]10 * This file is part of VirtualBox base platform packages, as
11 * available from https://www.virtualbox.org.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation, in version 3 of the
16 * License.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <https://www.gnu.org/licenses>.
25 *
26 * SPDX-License-Identifier: GPL-3.0-only
[1]27 */
28
[76562]29#ifndef MAIN_INCLUDED_AutoCaller_h
30#define MAIN_INCLUDED_AutoCaller_h
[76487]31#ifndef RT_WITHOUT_PRAGMA_ONCE
32# pragma once
33#endif
[1]34
[51903]35#include "ObjectState.h"
36
37#include "VBox/com/AutoLock.h"
38
39// Forward declaration needed, but nothing more.
40class VirtualBoxBase;
41
42
[1]43////////////////////////////////////////////////////////////////////////////////
[25859]44//
45// AutoCaller* classes
46//
[14588]47////////////////////////////////////////////////////////////////////////////////
[6076]48
[51903]49
[14588]50/**
[51903]51 * Smart class that automatically increases the number of normal (non-limited)
52 * callers of the given VirtualBoxBase object when an instance is constructed
53 * and decreases it back when the created instance goes out of scope (i.e. gets
54 * destroyed).
[1]55 *
[25859]56 * If #rc() returns a failure after the instance creation, it means that
57 * the managed VirtualBoxBase object is not Ready, or in any other invalid
58 * state, so that the caller must not use the object and can return this
59 * failed result code to the upper level.
[1]60 *
[51903]61 * See ObjectState::addCaller() and ObjectState::releaseCaller() for more
62 * details about object callers.
[13580]63 *
[51903]64 * A typical usage pattern to declare a normal method of some object (i.e. a
65 * method that is valid only when the object provides its full
66 * functionality) is:
67 * <code>
68 * STDMETHODIMP Component::Foo()
69 * {
70 * AutoCaller autoCaller(this);
71 * HRESULT hrc = autoCaller.rc();
72 * if (SUCCEEDED(hrc))
73 * {
74 * ...
75 * }
76 * return hrc;
77 * }
78 * </code>
[13580]79 */
[51903]80class AutoCaller
[1]81{
82public:
[51903]83 /**
84 * Default constructor. Not terribly useful, but it's valid to create
85 * an instance without associating it with an object. It's a no-op,
86 * like the more useful constructor below when NULL is passed to it.
87 */
88 AutoCaller()
89 {
90 init(NULL, false);
91 }
[1]92
93 /**
[25859]94 * Increases the number of callers of the given object by calling
[51903]95 * ObjectState::addCaller() for the corresponding member instance.
[25859]96 *
[51903]97 * @param aObj Object to add a normal caller to. If NULL, this
[25859]98 * instance is effectively turned to no-op (where
[51903]99 * rc() will return S_OK).
[25834]100 */
[51903]101 AutoCaller(VirtualBoxBase *aObj)
[25834]102 {
[51903]103 init(aObj, false);
[25834]104 }
105
106 /**
[25859]107 * If the number of callers was successfully increased, decreases it
[51903]108 * using ObjectState::releaseCaller(), otherwise does nothing.
[25834]109 */
[51903]110 ~AutoCaller()
[25834]111 {
[25859]112 if (mObj && SUCCEEDED(mRC))
[51903]113 mObj->getObjectState().releaseCaller();
[25834]114 }
115
116 /**
[51903]117 * Returns the stored result code returned by ObjectState::addCaller()
118 * after instance creation or after the last #add() call. A successful
119 * result code means the number of callers was successfully increased.
[1]120 */
[25859]121 HRESULT rc() const { return mRC; }
[1]122
[25859]123 /**
[26186]124 * Returns |true| if |SUCCEEDED(rc())| is |true|, for convenience.
[25859]125 * |true| means the number of callers was successfully increased.
126 */
127 bool isOk() const { return SUCCEEDED(mRC); }
[1]128
129 /**
[94907]130 * Returns |true| if |FAILED(rc())| is |true|, for convenience.
131 * |true| means the number of callers was _not_ successfully increased.
132 */
133 bool isNotOk() const { return FAILED(mRC); }
134
135 /**
[25859]136 * Temporarily decreases the number of callers of the managed object.
137 * May only be called if #isOk() returns |true|. Note that #rc() will
138 * return E_FAIL after this method succeeds.
[1]139 */
[25859]140 void release()
[1]141 {
[25859]142 Assert(SUCCEEDED(mRC));
143 if (SUCCEEDED(mRC))
[1]144 {
[3033]145 if (mObj)
[51903]146 mObj->getObjectState().releaseCaller();
[25859]147 mRC = E_FAIL;
[1]148 }
[25859]149 }
[1]150
151 /**
[25859]152 * Restores the number of callers decreased by #release(). May only be
153 * called after #release().
[1]154 */
[25859]155 void add()
[1]156 {
[25859]157 Assert(!SUCCEEDED(mRC));
158 if (mObj && !SUCCEEDED(mRC))
[51903]159 mRC = mObj->getObjectState().addCaller(mLimited);
[25859]160 }
[1]161
162 /**
[25859]163 * Attaches another object to this caller instance.
164 * The previous object's caller is released before the new one is added.
[1]165 *
[25859]166 * @param aObj New object to attach, may be @c NULL.
[1]167 */
[25859]168 void attach(VirtualBoxBase *aObj)
[1]169 {
[25859]170 /* detect simple self-reattachment */
171 if (mObj != aObj)
172 {
173 if (mObj && SUCCEEDED(mRC))
174 release();
[28205]175 else if (!mObj)
176 {
177 /* Fix up the success state when nothing is attached. Otherwise
178 * there are a couple of assertion which would trigger. */
179 mRC = E_FAIL;
180 }
[25859]181 mObj = aObj;
182 add();
183 }
184 }
[1]185
[51903]186 /** Verbose equivalent to <tt>attach(NULL)</tt>. */
[25859]187 void detach() { attach(NULL); }
[1]188
[51903]189protected:
190 /**
191 * Internal constructor: Increases the number of callers of the given
192 * object (either normal or limited variant) by calling
193 * ObjectState::addCaller() for the corresponding member instance.
194 *
195 * @param aObj Object to add a caller to. If NULL, this
196 * instance is effectively turned to no-op (where
197 * rc() will return S_OK).
198 * @param aLimited If |false|, then it's a regular caller, otherwise a
199 * limited caller.
200 */
201 void init(VirtualBoxBase *aObj, bool aLimited)
202 {
203 mObj = aObj;
[52489]204 mRC = S_OK;
205 mLimited = aLimited;
[51903]206 if (mObj)
207 mRC = mObj->getObjectState().addCaller(mLimited);
208 }
209
[1]210private:
[62636]211 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoCaller);
212 DECLARE_CLS_NEW_DELETE_NOOP(AutoCaller);
[1]213
[25859]214 VirtualBoxBase *mObj;
215 HRESULT mRC;
[51903]216 bool mLimited;
[1]217};
218
219/**
[25859]220 * Smart class that automatically increases the number of limited callers of
221 * the given VirtualBoxBase object when an instance is constructed and
222 * decreases it back when the created instance goes out of scope (i.e. gets
223 * destroyed).
[1]224 *
[25859]225 * A typical usage pattern to declare a limited method of some object (i.e.
226 * a method that is valid even if the object doesn't provide its full
227 * functionality) is:
228 * <code>
229 * STDMETHODIMP Component::Bar()
230 * {
231 * AutoLimitedCaller autoCaller(this);
[39715]232 * HRESULT hrc = autoCaller.rc();
233 * if (SUCCEEDED(hrc))
234 * {
235 * ...
236 * }
237 * return hrc;
[25859]238 * </code>
[1]239 *
[51903]240 * See AutoCaller for more information about auto caller functionality.
[1]241 */
[51903]242class AutoLimitedCaller : public AutoCaller
243{
244public:
245 /**
246 * Default constructor. Not terribly useful, but it's valid to create
247 * an instance without associating it with an object. It's a no-op,
248 * like the more useful constructor below when NULL is passed to it.
249 */
250 AutoLimitedCaller()
251 {
252 AutoCaller::init(NULL, true);
253 }
[1]254
[51903]255 /**
256 * Increases the number of callers of the given object by calling
257 * ObjectState::addCaller() for the corresponding member instance.
258 *
259 * @param aObj Object to add a limited caller to. If NULL, this
260 * instance is effectively turned to no-op (where
261 * rc() will return S_OK).
262 */
263 AutoLimitedCaller(VirtualBoxBase *aObj)
264 {
265 AutoCaller::init(aObj, true);
266 }
267
[63147]268private:
269 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoLimitedCaller); /* Shuts up MSC warning C4625. */
[51903]270};
271
[1]272/**
[25859]273 * Smart class to enclose the state transition NotReady->InInit->Ready.
[1]274 *
[25859]275 * The purpose of this span is to protect object initialization.
[1]276 *
[25859]277 * Instances must be created as a stack-based variable taking |this| pointer
278 * as the argument at the beginning of init() methods of VirtualBoxBase
279 * subclasses. When this variable is created it automatically places the
280 * object to the InInit state.
[1]281 *
[25859]282 * When the created variable goes out of scope (i.e. gets destroyed) then,
283 * depending on the result status of this initialization span, it either
284 * places the object to Ready or Limited state or calls the object's
285 * VirtualBoxBase::uninit() method which is supposed to place the object
286 * back to the NotReady state using the AutoUninitSpan class.
[1]287 *
[25859]288 * The initial result status of the initialization span is determined by the
289 * @a aResult argument of the AutoInitSpan constructor (Result::Failed by
290 * default). Inside the initialization span, the success status can be set
291 * to Result::Succeeded using #setSucceeded(), to to Result::Limited using
292 * #setLimited() or to Result::Failed using #setFailed(). Please don't
293 * forget to set the correct success status before getting the AutoInitSpan
294 * variable destroyed (for example, by performing an early return from
295 * the init() method)!
296 *
297 * Note that if an instance of this class gets constructed when the object
298 * is in the state other than NotReady, #isOk() returns |false| and methods
299 * of this class do nothing: the state transition is not performed.
300 *
301 * A typical usage pattern is:
302 * <code>
303 * HRESULT Component::init()
304 * {
[39715]305 * AutoInitSpan autoInitSpan(this);
306 * AssertReturn(autoInitSpan.isOk(), E_FAIL);
[25859]307 * ...
[26186]308 * if (FAILED(rc))
[25859]309 * return rc;
310 * ...
[26186]311 * if (SUCCEEDED(rc))
[25859]312 * autoInitSpan.setSucceeded();
313 * return rc;
314 * }
315 * </code>
316 *
317 * @note Never create instances of this class outside init() methods of
318 * VirtualBoxBase subclasses and never pass anything other than |this|
319 * as the argument to the constructor!
[1]320 */
[25859]321class AutoInitSpan
[1]322{
323public:
324
[25859]325 enum Result { Failed = 0x0, Succeeded = 0x1, Limited = 0x2 };
[1]326
[25859]327 AutoInitSpan(VirtualBoxBase *aObj, Result aResult = Failed);
328 ~AutoInitSpan();
[1]329
330 /**
[25859]331 * Returns |true| if this instance has been created at the right moment
332 * (when the object was in the NotReady state) and |false| otherwise.
[1]333 */
[25859]334 bool isOk() const { return mOk; }
[1]335
336 /**
[25859]337 * Sets the initialization status to Succeeded to indicates successful
338 * initialization. The AutoInitSpan destructor will place the managed
339 * VirtualBoxBase object to the Ready state.
[2672]340 */
[25859]341 void setSucceeded() { mResult = Succeeded; }
[2672]342
343 /**
[25859]344 * Sets the initialization status to Succeeded to indicate limited
345 * (partly successful) initialization. The AutoInitSpan destructor will
346 * place the managed VirtualBoxBase object to the Limited state.
[1]347 */
[25859]348 void setLimited() { mResult = Limited; }
[1]349
350 /**
[85929]351 * Sets the initialization status to Succeeded to indicate limited
352 * (partly successful) initialization but also adds the initialization
353 * error if required for further reporting. The AutoInitSpan destructor
354 * will place the managed VirtualBoxBase object to the Limited state.
355 */
356 void setLimited(HRESULT rc)
357 {
358 mResult = Limited;
359 mFailedRC = rc;
360 mpFailedEI = new ErrorInfo();
361 }
362
363 /**
[25859]364 * Sets the initialization status to Failure to indicates failed
365 * initialization. The AutoInitSpan destructor will place the managed
366 * VirtualBoxBase object to the InitFailed state and will automatically
367 * call its uninit() method which is supposed to place the object back
368 * to the NotReady state using AutoUninitSpan.
[2672]369 */
[59996]370 void setFailed(HRESULT rc = E_ACCESSDENIED)
371 {
372 mResult = Failed;
373 mFailedRC = rc;
374 mpFailedEI = new ErrorInfo();
375 }
[2672]376
[25859]377 /** Returns the current initialization result. */
378 Result result() { return mResult; }
[1]379
[25859]380private:
[2672]381
[62636]382 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoInitSpan);
383 DECLARE_CLS_NEW_DELETE_NOOP(AutoInitSpan);
[357]384
[25859]385 VirtualBoxBase *mObj;
386 Result mResult : 3; // must be at least total number of bits + 1 (sign)
387 bool mOk : 1;
[59996]388 HRESULT mFailedRC;
389 ErrorInfo *mpFailedEI;
[1]390};
391
392/**
[25859]393 * Smart class to enclose the state transition Limited->InInit->Ready.
[1]394 *
[25859]395 * The purpose of this span is to protect object re-initialization.
[6935]396 *
[25859]397 * Instances must be created as a stack-based variable taking |this| pointer
398 * as the argument at the beginning of methods of VirtualBoxBase
399 * subclasses that try to re-initialize the object to bring it to the Ready
400 * state (full functionality) after partial initialization (limited
401 * functionality). When this variable is created, it automatically places
402 * the object to the InInit state.
[6851]403 *
[25859]404 * When the created variable goes out of scope (i.e. gets destroyed),
405 * depending on the success status of this initialization span, it either
406 * places the object to the Ready state or brings it back to the Limited
407 * state.
[6851]408 *
[25859]409 * The initial success status of the re-initialization span is |false|. In
410 * order to make it successful, #setSucceeded() must be called before the
411 * instance is destroyed.
[13729]412 *
[25859]413 * Note that if an instance of this class gets constructed when the object
414 * is in the state other than Limited, #isOk() returns |false| and methods
415 * of this class do nothing: the state transition is not performed.
[6851]416 *
[25859]417 * A typical usage pattern is:
418 * <code>
419 * HRESULT Component::reinit()
420 * {
[51903]421 * AutoReinitSpan autoReinitSpan(this);
422 * AssertReturn(autoReinitSpan.isOk(), E_FAIL);
[25859]423 * ...
[26186]424 * if (FAILED(rc))
[25859]425 * return rc;
426 * ...
[26186]427 * if (SUCCEEDED(rc))
[25859]428 * autoReinitSpan.setSucceeded();
429 * return rc;
430 * }
431 * </code>
[6935]432 *
[25859]433 * @note Never create instances of this class outside re-initialization
434 * methods of VirtualBoxBase subclasses and never pass anything other than
435 * |this| as the argument to the constructor!
[1]436 */
[25859]437class AutoReinitSpan
[1]438{
[6851]439public:
440
[25859]441 AutoReinitSpan(VirtualBoxBase *aObj);
442 ~AutoReinitSpan();
[6851]443
444 /**
[25859]445 * Returns |true| if this instance has been created at the right moment
446 * (when the object was in the Limited state) and |false| otherwise.
[13729]447 */
[25859]448 bool isOk() const { return mOk; }
[13729]449
450 /**
[25859]451 * Sets the re-initialization status to Succeeded to indicates
452 * successful re-initialization. The AutoReinitSpan destructor will place
453 * the managed VirtualBoxBase object to the Ready state.
[6851]454 */
[25859]455 void setSucceeded() { mSucceeded = true; }
[6851]456
[25859]457private:
[13580]458
[62636]459 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReinitSpan);
460 DECLARE_CLS_NEW_DELETE_NOOP(AutoReinitSpan);
[6851]461
[25859]462 VirtualBoxBase *mObj;
463 bool mSucceeded : 1;
464 bool mOk : 1;
[1]465};
466
467/**
[26984]468 * Smart class to enclose the state transition Ready->InUninit->NotReady,
469 * InitFailed->InUninit->NotReady.
[25859]470 *
471 * The purpose of this span is to protect object uninitialization.
472 *
473 * Instances must be created as a stack-based variable taking |this| pointer
474 * as the argument at the beginning of uninit() methods of VirtualBoxBase
475 * subclasses. When this variable is created it automatically places the
476 * object to the InUninit state, unless it is already in the NotReady state
477 * as indicated by #uninitDone() returning |true|. In the latter case, the
478 * uninit() method must immediately return because there should be nothing
479 * to uninitialize.
480 *
481 * When this variable goes out of scope (i.e. gets destroyed), it places the
482 * object to NotReady state.
483 *
484 * A typical usage pattern is:
485 * <code>
486 * void Component::uninit()
487 * {
[51903]488 * AutoUninitSpan autoUninitSpan(this);
[25859]489 * if (autoUninitSpan.uninitDone())
490 * return;
491 * ...
492 * }
493 * </code>
494 *
495 * @note The constructor of this class blocks the current thread execution
[51903]496 * until the number of callers added to the object using
497 * ObjectState::addCaller() or AutoCaller drops to zero. For this reason,
498 * it is forbidden to create instances of this class (or call uninit())
499 * within the AutoCaller or ObjectState::addCaller() scope because it is
500 * a guaranteed deadlock.
[25859]501 *
502 * @note Never create instances of this class outside uninit() methods and
503 * never pass anything other than |this| as the argument to the
504 * constructor!
[1]505 */
[25859]506class AutoUninitSpan
[1]507{
508public:
509
[75660]510 AutoUninitSpan(VirtualBoxBase *aObj, bool fTry = false);
[25859]511 ~AutoUninitSpan();
[1]512
[25859]513 /** |true| when uninit() is called as a result of init() failure */
514 bool initFailed() { return mInitFailed; }
[1]515
[25859]516 /** |true| when uninit() has already been called (so the object is NotReady) */
517 bool uninitDone() { return mUninitDone; }
[1]518
[75660]519 /** |true| when uninit() has failed, relevant only if it was a "try uninit" */
520 bool uninitFailed() { return mUninitFailed; }
521
[52095]522 void setSucceeded();
523
[25859]524private:
[1]525
[62636]526 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoUninitSpan);
527 DECLARE_CLS_NEW_DELETE_NOOP(AutoUninitSpan);
[1]528
[25859]529 VirtualBoxBase *mObj;
530 bool mInitFailed : 1;
531 bool mUninitDone : 1;
[75660]532 bool mUninitFailed : 1;
[1]533};
534
[76562]535#endif /* !MAIN_INCLUDED_AutoCaller_h */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use