VirtualBox

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

Last change on this file since 98262 was 98262, checked in by vboxsync, 16 months ago

Main: rc() -> hrc()/vrc(). bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.2 KB
RevLine 
[55401]1/* $Id: AutoCaller.h 98262 2023-01-24 01:42:14Z 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);
[98262]71 * HRESULT hrc = autoCaller.hrc();
[51903]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 /**
[98262]117 * Returns the stored result code returned by ObjectState::addCaller() after
118 * instance creation or after the last #add() call.
119 *
120 * A successful result code means the number of callers was successfully
121 * increased.
122 */
123 HRESULT hrc() const { return mRC; }
124
125 /**
[51903]126 * Returns the stored result code returned by ObjectState::addCaller()
127 * after instance creation or after the last #add() call. A successful
128 * result code means the number of callers was successfully increased.
[98262]129 * @deprecated use hrc()
[1]130 */
[25859]131 HRESULT rc() const { return mRC; }
[1]132
[25859]133 /**
[26186]134 * Returns |true| if |SUCCEEDED(rc())| is |true|, for convenience.
[25859]135 * |true| means the number of callers was successfully increased.
136 */
137 bool isOk() const { return SUCCEEDED(mRC); }
[1]138
139 /**
[94907]140 * Returns |true| if |FAILED(rc())| is |true|, for convenience.
141 * |true| means the number of callers was _not_ successfully increased.
142 */
143 bool isNotOk() const { return FAILED(mRC); }
144
145 /**
[25859]146 * Temporarily decreases the number of callers of the managed object.
147 * May only be called if #isOk() returns |true|. Note that #rc() will
148 * return E_FAIL after this method succeeds.
[1]149 */
[25859]150 void release()
[1]151 {
[25859]152 Assert(SUCCEEDED(mRC));
153 if (SUCCEEDED(mRC))
[1]154 {
[3033]155 if (mObj)
[51903]156 mObj->getObjectState().releaseCaller();
[25859]157 mRC = E_FAIL;
[1]158 }
[25859]159 }
[1]160
161 /**
[25859]162 * Restores the number of callers decreased by #release(). May only be
163 * called after #release().
[1]164 */
[25859]165 void add()
[1]166 {
[25859]167 Assert(!SUCCEEDED(mRC));
168 if (mObj && !SUCCEEDED(mRC))
[51903]169 mRC = mObj->getObjectState().addCaller(mLimited);
[25859]170 }
[1]171
172 /**
[25859]173 * Attaches another object to this caller instance.
174 * The previous object's caller is released before the new one is added.
[1]175 *
[25859]176 * @param aObj New object to attach, may be @c NULL.
[1]177 */
[25859]178 void attach(VirtualBoxBase *aObj)
[1]179 {
[25859]180 /* detect simple self-reattachment */
181 if (mObj != aObj)
182 {
183 if (mObj && SUCCEEDED(mRC))
184 release();
[28205]185 else if (!mObj)
186 {
187 /* Fix up the success state when nothing is attached. Otherwise
188 * there are a couple of assertion which would trigger. */
189 mRC = E_FAIL;
190 }
[25859]191 mObj = aObj;
192 add();
193 }
194 }
[1]195
[51903]196 /** Verbose equivalent to <tt>attach(NULL)</tt>. */
[25859]197 void detach() { attach(NULL); }
[1]198
[51903]199protected:
200 /**
201 * Internal constructor: Increases the number of callers of the given
202 * object (either normal or limited variant) by calling
203 * ObjectState::addCaller() for the corresponding member instance.
204 *
205 * @param aObj Object to add a caller to. If NULL, this
206 * instance is effectively turned to no-op (where
207 * rc() will return S_OK).
208 * @param aLimited If |false|, then it's a regular caller, otherwise a
209 * limited caller.
210 */
211 void init(VirtualBoxBase *aObj, bool aLimited)
212 {
213 mObj = aObj;
[52489]214 mRC = S_OK;
215 mLimited = aLimited;
[51903]216 if (mObj)
217 mRC = mObj->getObjectState().addCaller(mLimited);
218 }
219
[1]220private:
[62636]221 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoCaller);
222 DECLARE_CLS_NEW_DELETE_NOOP(AutoCaller);
[1]223
[25859]224 VirtualBoxBase *mObj;
225 HRESULT mRC;
[51903]226 bool mLimited;
[1]227};
228
229/**
[25859]230 * Smart class that automatically increases the number of limited callers of
231 * the given VirtualBoxBase object when an instance is constructed and
232 * decreases it back when the created instance goes out of scope (i.e. gets
233 * destroyed).
[1]234 *
[25859]235 * A typical usage pattern to declare a limited method of some object (i.e.
236 * a method that is valid even if the object doesn't provide its full
237 * functionality) is:
238 * <code>
239 * STDMETHODIMP Component::Bar()
240 * {
241 * AutoLimitedCaller autoCaller(this);
[98262]242 * HRESULT hrc = autoCaller.hrc();
[39715]243 * if (SUCCEEDED(hrc))
244 * {
245 * ...
246 * }
247 * return hrc;
[25859]248 * </code>
[1]249 *
[51903]250 * See AutoCaller for more information about auto caller functionality.
[1]251 */
[51903]252class AutoLimitedCaller : public AutoCaller
253{
254public:
255 /**
256 * Default constructor. Not terribly useful, but it's valid to create
257 * an instance without associating it with an object. It's a no-op,
258 * like the more useful constructor below when NULL is passed to it.
259 */
260 AutoLimitedCaller()
261 {
262 AutoCaller::init(NULL, true);
263 }
[1]264
[51903]265 /**
266 * Increases the number of callers of the given object by calling
267 * ObjectState::addCaller() for the corresponding member instance.
268 *
269 * @param aObj Object to add a limited caller to. If NULL, this
270 * instance is effectively turned to no-op (where
271 * rc() will return S_OK).
272 */
273 AutoLimitedCaller(VirtualBoxBase *aObj)
274 {
275 AutoCaller::init(aObj, true);
276 }
277
[63147]278private:
279 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoLimitedCaller); /* Shuts up MSC warning C4625. */
[51903]280};
281
[1]282/**
[25859]283 * Smart class to enclose the state transition NotReady->InInit->Ready.
[1]284 *
[25859]285 * The purpose of this span is to protect object initialization.
[1]286 *
[25859]287 * Instances must be created as a stack-based variable taking |this| pointer
288 * as the argument at the beginning of init() methods of VirtualBoxBase
289 * subclasses. When this variable is created it automatically places the
290 * object to the InInit state.
[1]291 *
[25859]292 * When the created variable goes out of scope (i.e. gets destroyed) then,
293 * depending on the result status of this initialization span, it either
294 * places the object to Ready or Limited state or calls the object's
295 * VirtualBoxBase::uninit() method which is supposed to place the object
296 * back to the NotReady state using the AutoUninitSpan class.
[1]297 *
[25859]298 * The initial result status of the initialization span is determined by the
299 * @a aResult argument of the AutoInitSpan constructor (Result::Failed by
300 * default). Inside the initialization span, the success status can be set
301 * to Result::Succeeded using #setSucceeded(), to to Result::Limited using
302 * #setLimited() or to Result::Failed using #setFailed(). Please don't
303 * forget to set the correct success status before getting the AutoInitSpan
304 * variable destroyed (for example, by performing an early return from
305 * the init() method)!
306 *
307 * Note that if an instance of this class gets constructed when the object
308 * is in the state other than NotReady, #isOk() returns |false| and methods
309 * of this class do nothing: the state transition is not performed.
310 *
311 * A typical usage pattern is:
312 * <code>
313 * HRESULT Component::init()
314 * {
[39715]315 * AutoInitSpan autoInitSpan(this);
316 * AssertReturn(autoInitSpan.isOk(), E_FAIL);
[25859]317 * ...
[26186]318 * if (FAILED(rc))
[25859]319 * return rc;
320 * ...
[26186]321 * if (SUCCEEDED(rc))
[25859]322 * autoInitSpan.setSucceeded();
323 * return rc;
324 * }
325 * </code>
326 *
327 * @note Never create instances of this class outside init() methods of
328 * VirtualBoxBase subclasses and never pass anything other than |this|
329 * as the argument to the constructor!
[1]330 */
[25859]331class AutoInitSpan
[1]332{
333public:
334
[25859]335 enum Result { Failed = 0x0, Succeeded = 0x1, Limited = 0x2 };
[1]336
[25859]337 AutoInitSpan(VirtualBoxBase *aObj, Result aResult = Failed);
338 ~AutoInitSpan();
[1]339
340 /**
[25859]341 * Returns |true| if this instance has been created at the right moment
342 * (when the object was in the NotReady state) and |false| otherwise.
[1]343 */
[25859]344 bool isOk() const { return mOk; }
[1]345
346 /**
[25859]347 * Sets the initialization status to Succeeded to indicates successful
348 * initialization. The AutoInitSpan destructor will place the managed
349 * VirtualBoxBase object to the Ready state.
[2672]350 */
[25859]351 void setSucceeded() { mResult = Succeeded; }
[2672]352
353 /**
[25859]354 * Sets the initialization status to Succeeded to indicate limited
355 * (partly successful) initialization. The AutoInitSpan destructor will
356 * place the managed VirtualBoxBase object to the Limited state.
[1]357 */
[25859]358 void setLimited() { mResult = Limited; }
[1]359
360 /**
[85929]361 * Sets the initialization status to Succeeded to indicate limited
362 * (partly successful) initialization but also adds the initialization
363 * error if required for further reporting. The AutoInitSpan destructor
364 * will place the managed VirtualBoxBase object to the Limited state.
365 */
366 void setLimited(HRESULT rc)
367 {
368 mResult = Limited;
369 mFailedRC = rc;
370 mpFailedEI = new ErrorInfo();
371 }
372
373 /**
[25859]374 * Sets the initialization status to Failure to indicates failed
375 * initialization. The AutoInitSpan destructor will place the managed
376 * VirtualBoxBase object to the InitFailed state and will automatically
377 * call its uninit() method which is supposed to place the object back
378 * to the NotReady state using AutoUninitSpan.
[2672]379 */
[59996]380 void setFailed(HRESULT rc = E_ACCESSDENIED)
381 {
382 mResult = Failed;
383 mFailedRC = rc;
384 mpFailedEI = new ErrorInfo();
385 }
[2672]386
[25859]387 /** Returns the current initialization result. */
388 Result result() { return mResult; }
[1]389
[25859]390private:
[2672]391
[62636]392 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoInitSpan);
393 DECLARE_CLS_NEW_DELETE_NOOP(AutoInitSpan);
[357]394
[25859]395 VirtualBoxBase *mObj;
396 Result mResult : 3; // must be at least total number of bits + 1 (sign)
397 bool mOk : 1;
[59996]398 HRESULT mFailedRC;
399 ErrorInfo *mpFailedEI;
[1]400};
401
402/**
[25859]403 * Smart class to enclose the state transition Limited->InInit->Ready.
[1]404 *
[25859]405 * The purpose of this span is to protect object re-initialization.
[6935]406 *
[25859]407 * Instances must be created as a stack-based variable taking |this| pointer
408 * as the argument at the beginning of methods of VirtualBoxBase
409 * subclasses that try to re-initialize the object to bring it to the Ready
410 * state (full functionality) after partial initialization (limited
411 * functionality). When this variable is created, it automatically places
412 * the object to the InInit state.
[6851]413 *
[25859]414 * When the created variable goes out of scope (i.e. gets destroyed),
415 * depending on the success status of this initialization span, it either
416 * places the object to the Ready state or brings it back to the Limited
417 * state.
[6851]418 *
[25859]419 * The initial success status of the re-initialization span is |false|. In
420 * order to make it successful, #setSucceeded() must be called before the
421 * instance is destroyed.
[13729]422 *
[25859]423 * Note that if an instance of this class gets constructed when the object
424 * is in the state other than Limited, #isOk() returns |false| and methods
425 * of this class do nothing: the state transition is not performed.
[6851]426 *
[25859]427 * A typical usage pattern is:
428 * <code>
429 * HRESULT Component::reinit()
430 * {
[51903]431 * AutoReinitSpan autoReinitSpan(this);
432 * AssertReturn(autoReinitSpan.isOk(), E_FAIL);
[25859]433 * ...
[26186]434 * if (FAILED(rc))
[25859]435 * return rc;
436 * ...
[26186]437 * if (SUCCEEDED(rc))
[25859]438 * autoReinitSpan.setSucceeded();
439 * return rc;
440 * }
441 * </code>
[6935]442 *
[25859]443 * @note Never create instances of this class outside re-initialization
444 * methods of VirtualBoxBase subclasses and never pass anything other than
445 * |this| as the argument to the constructor!
[1]446 */
[25859]447class AutoReinitSpan
[1]448{
[6851]449public:
450
[25859]451 AutoReinitSpan(VirtualBoxBase *aObj);
452 ~AutoReinitSpan();
[6851]453
454 /**
[25859]455 * Returns |true| if this instance has been created at the right moment
456 * (when the object was in the Limited state) and |false| otherwise.
[13729]457 */
[25859]458 bool isOk() const { return mOk; }
[13729]459
460 /**
[25859]461 * Sets the re-initialization status to Succeeded to indicates
462 * successful re-initialization. The AutoReinitSpan destructor will place
463 * the managed VirtualBoxBase object to the Ready state.
[6851]464 */
[25859]465 void setSucceeded() { mSucceeded = true; }
[6851]466
[25859]467private:
[13580]468
[62636]469 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReinitSpan);
470 DECLARE_CLS_NEW_DELETE_NOOP(AutoReinitSpan);
[6851]471
[25859]472 VirtualBoxBase *mObj;
473 bool mSucceeded : 1;
474 bool mOk : 1;
[1]475};
476
477/**
[26984]478 * Smart class to enclose the state transition Ready->InUninit->NotReady,
479 * InitFailed->InUninit->NotReady.
[25859]480 *
481 * The purpose of this span is to protect object uninitialization.
482 *
483 * Instances must be created as a stack-based variable taking |this| pointer
484 * as the argument at the beginning of uninit() methods of VirtualBoxBase
485 * subclasses. When this variable is created it automatically places the
486 * object to the InUninit state, unless it is already in the NotReady state
487 * as indicated by #uninitDone() returning |true|. In the latter case, the
488 * uninit() method must immediately return because there should be nothing
489 * to uninitialize.
490 *
491 * When this variable goes out of scope (i.e. gets destroyed), it places the
492 * object to NotReady state.
493 *
494 * A typical usage pattern is:
495 * <code>
496 * void Component::uninit()
497 * {
[51903]498 * AutoUninitSpan autoUninitSpan(this);
[25859]499 * if (autoUninitSpan.uninitDone())
500 * return;
501 * ...
502 * }
503 * </code>
504 *
505 * @note The constructor of this class blocks the current thread execution
[51903]506 * until the number of callers added to the object using
507 * ObjectState::addCaller() or AutoCaller drops to zero. For this reason,
508 * it is forbidden to create instances of this class (or call uninit())
509 * within the AutoCaller or ObjectState::addCaller() scope because it is
510 * a guaranteed deadlock.
[25859]511 *
512 * @note Never create instances of this class outside uninit() methods and
513 * never pass anything other than |this| as the argument to the
514 * constructor!
[1]515 */
[25859]516class AutoUninitSpan
[1]517{
518public:
519
[75660]520 AutoUninitSpan(VirtualBoxBase *aObj, bool fTry = false);
[25859]521 ~AutoUninitSpan();
[1]522
[25859]523 /** |true| when uninit() is called as a result of init() failure */
524 bool initFailed() { return mInitFailed; }
[1]525
[25859]526 /** |true| when uninit() has already been called (so the object is NotReady) */
527 bool uninitDone() { return mUninitDone; }
[1]528
[75660]529 /** |true| when uninit() has failed, relevant only if it was a "try uninit" */
530 bool uninitFailed() { return mUninitFailed; }
531
[52095]532 void setSucceeded();
533
[25859]534private:
[1]535
[62636]536 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoUninitSpan);
537 DECLARE_CLS_NEW_DELETE_NOOP(AutoUninitSpan);
[1]538
[25859]539 VirtualBoxBase *mObj;
540 bool mInitFailed : 1;
541 bool mUninitDone : 1;
[75660]542 bool mUninitFailed : 1;
[1]543};
544
[76562]545#endif /* !MAIN_INCLUDED_AutoCaller_h */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use