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
Line 
1/* $Id: AutoCaller.h 98262 2023-01-24 01:42:14Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox object caller handling definitions
5 */
6
7/*
8 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
9 *
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
27 */
28
29#ifndef MAIN_INCLUDED_AutoCaller_h
30#define MAIN_INCLUDED_AutoCaller_h
31#ifndef RT_WITHOUT_PRAGMA_ONCE
32# pragma once
33#endif
34
35#include "ObjectState.h"
36
37#include "VBox/com/AutoLock.h"
38
39// Forward declaration needed, but nothing more.
40class VirtualBoxBase;
41
42
43////////////////////////////////////////////////////////////////////////////////
44//
45// AutoCaller* classes
46//
47////////////////////////////////////////////////////////////////////////////////
48
49
50/**
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).
55 *
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.
60 *
61 * See ObjectState::addCaller() and ObjectState::releaseCaller() for more
62 * details about object callers.
63 *
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.hrc();
72 * if (SUCCEEDED(hrc))
73 * {
74 * ...
75 * }
76 * return hrc;
77 * }
78 * </code>
79 */
80class AutoCaller
81{
82public:
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 }
92
93 /**
94 * Increases the number of callers of the given object by calling
95 * ObjectState::addCaller() for the corresponding member instance.
96 *
97 * @param aObj Object to add a normal caller to. If NULL, this
98 * instance is effectively turned to no-op (where
99 * rc() will return S_OK).
100 */
101 AutoCaller(VirtualBoxBase *aObj)
102 {
103 init(aObj, false);
104 }
105
106 /**
107 * If the number of callers was successfully increased, decreases it
108 * using ObjectState::releaseCaller(), otherwise does nothing.
109 */
110 ~AutoCaller()
111 {
112 if (mObj && SUCCEEDED(mRC))
113 mObj->getObjectState().releaseCaller();
114 }
115
116 /**
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 /**
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.
129 * @deprecated use hrc()
130 */
131 HRESULT rc() const { return mRC; }
132
133 /**
134 * Returns |true| if |SUCCEEDED(rc())| is |true|, for convenience.
135 * |true| means the number of callers was successfully increased.
136 */
137 bool isOk() const { return SUCCEEDED(mRC); }
138
139 /**
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 /**
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.
149 */
150 void release()
151 {
152 Assert(SUCCEEDED(mRC));
153 if (SUCCEEDED(mRC))
154 {
155 if (mObj)
156 mObj->getObjectState().releaseCaller();
157 mRC = E_FAIL;
158 }
159 }
160
161 /**
162 * Restores the number of callers decreased by #release(). May only be
163 * called after #release().
164 */
165 void add()
166 {
167 Assert(!SUCCEEDED(mRC));
168 if (mObj && !SUCCEEDED(mRC))
169 mRC = mObj->getObjectState().addCaller(mLimited);
170 }
171
172 /**
173 * Attaches another object to this caller instance.
174 * The previous object's caller is released before the new one is added.
175 *
176 * @param aObj New object to attach, may be @c NULL.
177 */
178 void attach(VirtualBoxBase *aObj)
179 {
180 /* detect simple self-reattachment */
181 if (mObj != aObj)
182 {
183 if (mObj && SUCCEEDED(mRC))
184 release();
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 }
191 mObj = aObj;
192 add();
193 }
194 }
195
196 /** Verbose equivalent to <tt>attach(NULL)</tt>. */
197 void detach() { attach(NULL); }
198
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;
214 mRC = S_OK;
215 mLimited = aLimited;
216 if (mObj)
217 mRC = mObj->getObjectState().addCaller(mLimited);
218 }
219
220private:
221 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoCaller);
222 DECLARE_CLS_NEW_DELETE_NOOP(AutoCaller);
223
224 VirtualBoxBase *mObj;
225 HRESULT mRC;
226 bool mLimited;
227};
228
229/**
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).
234 *
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);
242 * HRESULT hrc = autoCaller.hrc();
243 * if (SUCCEEDED(hrc))
244 * {
245 * ...
246 * }
247 * return hrc;
248 * </code>
249 *
250 * See AutoCaller for more information about auto caller functionality.
251 */
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 }
264
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
278private:
279 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoLimitedCaller); /* Shuts up MSC warning C4625. */
280};
281
282/**
283 * Smart class to enclose the state transition NotReady->InInit->Ready.
284 *
285 * The purpose of this span is to protect object initialization.
286 *
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.
291 *
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.
297 *
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 * {
315 * AutoInitSpan autoInitSpan(this);
316 * AssertReturn(autoInitSpan.isOk(), E_FAIL);
317 * ...
318 * if (FAILED(rc))
319 * return rc;
320 * ...
321 * if (SUCCEEDED(rc))
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!
330 */
331class AutoInitSpan
332{
333public:
334
335 enum Result { Failed = 0x0, Succeeded = 0x1, Limited = 0x2 };
336
337 AutoInitSpan(VirtualBoxBase *aObj, Result aResult = Failed);
338 ~AutoInitSpan();
339
340 /**
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.
343 */
344 bool isOk() const { return mOk; }
345
346 /**
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.
350 */
351 void setSucceeded() { mResult = Succeeded; }
352
353 /**
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.
357 */
358 void setLimited() { mResult = Limited; }
359
360 /**
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 /**
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.
379 */
380 void setFailed(HRESULT rc = E_ACCESSDENIED)
381 {
382 mResult = Failed;
383 mFailedRC = rc;
384 mpFailedEI = new ErrorInfo();
385 }
386
387 /** Returns the current initialization result. */
388 Result result() { return mResult; }
389
390private:
391
392 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoInitSpan);
393 DECLARE_CLS_NEW_DELETE_NOOP(AutoInitSpan);
394
395 VirtualBoxBase *mObj;
396 Result mResult : 3; // must be at least total number of bits + 1 (sign)
397 bool mOk : 1;
398 HRESULT mFailedRC;
399 ErrorInfo *mpFailedEI;
400};
401
402/**
403 * Smart class to enclose the state transition Limited->InInit->Ready.
404 *
405 * The purpose of this span is to protect object re-initialization.
406 *
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.
413 *
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.
418 *
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.
422 *
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.
426 *
427 * A typical usage pattern is:
428 * <code>
429 * HRESULT Component::reinit()
430 * {
431 * AutoReinitSpan autoReinitSpan(this);
432 * AssertReturn(autoReinitSpan.isOk(), E_FAIL);
433 * ...
434 * if (FAILED(rc))
435 * return rc;
436 * ...
437 * if (SUCCEEDED(rc))
438 * autoReinitSpan.setSucceeded();
439 * return rc;
440 * }
441 * </code>
442 *
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!
446 */
447class AutoReinitSpan
448{
449public:
450
451 AutoReinitSpan(VirtualBoxBase *aObj);
452 ~AutoReinitSpan();
453
454 /**
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.
457 */
458 bool isOk() const { return mOk; }
459
460 /**
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.
464 */
465 void setSucceeded() { mSucceeded = true; }
466
467private:
468
469 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReinitSpan);
470 DECLARE_CLS_NEW_DELETE_NOOP(AutoReinitSpan);
471
472 VirtualBoxBase *mObj;
473 bool mSucceeded : 1;
474 bool mOk : 1;
475};
476
477/**
478 * Smart class to enclose the state transition Ready->InUninit->NotReady,
479 * InitFailed->InUninit->NotReady.
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 * {
498 * AutoUninitSpan autoUninitSpan(this);
499 * if (autoUninitSpan.uninitDone())
500 * return;
501 * ...
502 * }
503 * </code>
504 *
505 * @note The constructor of this class blocks the current thread execution
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.
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!
515 */
516class AutoUninitSpan
517{
518public:
519
520 AutoUninitSpan(VirtualBoxBase *aObj, bool fTry = false);
521 ~AutoUninitSpan();
522
523 /** |true| when uninit() is called as a result of init() failure */
524 bool initFailed() { return mInitFailed; }
525
526 /** |true| when uninit() has already been called (so the object is NotReady) */
527 bool uninitDone() { return mUninitDone; }
528
529 /** |true| when uninit() has failed, relevant only if it was a "try uninit" */
530 bool uninitFailed() { return mUninitFailed; }
531
532 void setSucceeded();
533
534private:
535
536 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoUninitSpan);
537 DECLARE_CLS_NEW_DELETE_NOOP(AutoUninitSpan);
538
539 VirtualBoxBase *mObj;
540 bool mInitFailed : 1;
541 bool mUninitDone : 1;
542 bool mUninitFailed : 1;
543};
544
545#endif /* !MAIN_INCLUDED_AutoCaller_h */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use