- Timestamp:
- Jul 7, 2014 1:03:49 PM (11 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 12 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/Makefile.kmk
r51476 r51903 346 346 src-all/ProgressImpl.cpp \ 347 347 src-all/SharedFolderImpl.cpp \ 348 src-all/AutoCaller.cpp \ 348 349 src-all/VirtualBoxBase.cpp \ 349 350 src-all/VirtualBoxErrorInfoImpl.cpp \ … … 694 695 src-all/ProgressImpl.cpp \ 695 696 src-all/SharedFolderImpl.cpp \ 697 src-all/AutoCaller.cpp \ 696 698 src-all/VirtualBoxBase.cpp \ 697 699 src-all/VirtualBoxErrorInfoImpl.cpp \ … … 815 817 src-all/EventImpl.cpp \ 816 818 src-all/Global.cpp \ 819 src-all/AutoCaller.cpp \ 817 820 src-all/VirtualBoxBase.cpp \ 818 821 src-all/VirtualBoxErrorInfoImpl.cpp \ -
trunk/src/VBox/Main/include/AutoCaller.h
r44528 r51903 1 1 /** @file 2 2 * 3 * VirtualBox COM base classes definition3 * VirtualBox object caller handling definitions 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-201 2Oracle Corporation7 * Copyright (C) 2006-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 19 19 #define ____H_AUTOCALLER 20 20 21 #include "ObjectState.h" 22 23 #include "VBox/com/AutoLock.h" 24 25 // Forward declaration needed, but nothing more. 26 class VirtualBoxBase; 27 28 21 29 //////////////////////////////////////////////////////////////////////////////// 22 30 // … … 25 33 //////////////////////////////////////////////////////////////////////////////// 26 34 35 27 36 /** 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). 37 * Smart class that automatically increases the number of normal (non-limited) 38 * callers of the given VirtualBoxBase object when an instance is constructed 39 * and decreases it back when the created instance goes out of scope (i.e. gets 40 * destroyed). 31 41 * 32 42 * If #rc() returns a failure after the instance creation, it means that … … 35 45 * failed result code to the upper level. 36 46 * 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 */ 49 template<bool aLimited> 50 class AutoCallerBase 51 { 52 public: 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 153 private: 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). 47 * See ObjectState::addCaller() and ObjectState::releaseCaller() for more 48 * details about object callers. 168 49 * 169 50 * A typical usage pattern to declare a normal method of some object (i.e. a … … 182 63 * } 183 64 * </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 */ 191 typedef AutoCallerBase<false> AutoCaller; 65 */ 66 class AutoCaller 67 { 68 public: 69 /** 70 * Default constructor. Not terribly useful, but it's valid to create 71 * an instance without associating it with an object. It's a no-op, 72 * like the more useful constructor below when NULL is passed to it. 73 */ 74 AutoCaller() 75 { 76 init(NULL, false); 77 } 78 79 /** 80 * Increases the number of callers of the given object by calling 81 * ObjectState::addCaller() for the corresponding member instance. 82 * 83 * @param aObj Object to add a normal caller to. If NULL, this 84 * instance is effectively turned to no-op (where 85 * rc() will return S_OK). 86 */ 87 AutoCaller(VirtualBoxBase *aObj) 88 { 89 init(aObj, false); 90 } 91 92 /** 93 * If the number of callers was successfully increased, decreases it 94 * using ObjectState::releaseCaller(), otherwise does nothing. 95 */ 96 ~AutoCaller() 97 { 98 if (mObj && SUCCEEDED(mRC)) 99 mObj->getObjectState().releaseCaller(); 100 } 101 102 /** 103 * Returns the stored result code returned by ObjectState::addCaller() 104 * after instance creation or after the last #add() call. A successful 105 * result code means the number of callers was successfully increased. 106 */ 107 HRESULT rc() const { return mRC; } 108 109 /** 110 * Returns |true| if |SUCCEEDED(rc())| is |true|, for convenience. 111 * |true| means the number of callers was successfully increased. 112 */ 113 bool isOk() const { return SUCCEEDED(mRC); } 114 115 /** 116 * Temporarily decreases the number of callers of the managed object. 117 * May only be called if #isOk() returns |true|. Note that #rc() will 118 * return E_FAIL after this method succeeds. 119 */ 120 void release() 121 { 122 Assert(SUCCEEDED(mRC)); 123 if (SUCCEEDED(mRC)) 124 { 125 if (mObj) 126 mObj->getObjectState().releaseCaller(); 127 mRC = E_FAIL; 128 } 129 } 130 131 /** 132 * Restores the number of callers decreased by #release(). May only be 133 * called after #release(). 134 */ 135 void add() 136 { 137 Assert(!SUCCEEDED(mRC)); 138 if (mObj && !SUCCEEDED(mRC)) 139 mRC = mObj->getObjectState().addCaller(mLimited); 140 } 141 142 /** 143 * Attaches another object to this caller instance. 144 * The previous object's caller is released before the new one is added. 145 * 146 * @param aObj New object to attach, may be @c NULL. 147 */ 148 void attach(VirtualBoxBase *aObj) 149 { 150 /* detect simple self-reattachment */ 151 if (mObj != aObj) 152 { 153 if (mObj && SUCCEEDED(mRC)) 154 release(); 155 else if (!mObj) 156 { 157 /* Fix up the success state when nothing is attached. Otherwise 158 * there are a couple of assertion which would trigger. */ 159 mRC = E_FAIL; 160 } 161 mObj = aObj; 162 add(); 163 } 164 } 165 166 /** Verbose equivalent to <tt>attach(NULL)</tt>. */ 167 void detach() { attach(NULL); } 168 169 protected: 170 /** 171 * Internal constructor: Increases the number of callers of the given 172 * object (either normal or limited variant) by calling 173 * ObjectState::addCaller() for the corresponding member instance. 174 * 175 * @param aObj Object to add a caller to. If NULL, this 176 * instance is effectively turned to no-op (where 177 * rc() will return S_OK). 178 * @param aLimited If |false|, then it's a regular caller, otherwise a 179 * limited caller. 180 */ 181 void init(VirtualBoxBase *aObj, bool aLimited) 182 { 183 mObj = aObj; 184 mRC = S_OK; 185 mLimited = aLimited; 186 if (mObj) 187 mRC = mObj->getObjectState().addCaller(mLimited); 188 } 189 190 private: 191 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoCaller) 192 DECLARE_CLS_NEW_DELETE_NOOP(AutoCaller) 193 194 VirtualBoxBase *mObj; 195 HRESULT mRC; 196 bool mLimited; 197 }; 192 198 193 199 /** … … 212 218 * </code> 213 219 * 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 */ 220 typedef AutoCallerBase<true> AutoLimitedCaller; 220 * See AutoCaller for more information about auto caller functionality. 221 */ 222 class AutoLimitedCaller : public AutoCaller 223 { 224 public: 225 /** 226 * Default constructor. Not terribly useful, but it's valid to create 227 * an instance without associating it with an object. It's a no-op, 228 * like the more useful constructor below when NULL is passed to it. 229 */ 230 AutoLimitedCaller() 231 { 232 AutoCaller::init(NULL, true); 233 } 234 235 /** 236 * Increases the number of callers of the given object by calling 237 * ObjectState::addCaller() for the corresponding member instance. 238 * 239 * @param aObj Object to add a limited caller to. If NULL, this 240 * instance is effectively turned to no-op (where 241 * rc() will return S_OK). 242 */ 243 AutoLimitedCaller(VirtualBoxBase *aObj) 244 { 245 AutoCaller::init(aObj, true); 246 } 247 248 }; 221 249 222 250 /** … … 349 377 * HRESULT Component::reinit() 350 378 * { 351 * AutoReinitSpan autoReinitSpan 352 * AssertReturn 379 * AutoReinitSpan autoReinitSpan(this); 380 * AssertReturn(autoReinitSpan.isOk(), E_FAIL); 353 381 * ... 354 382 * if (FAILED(rc)) … … 416 444 * void Component::uninit() 417 445 * { 418 * AutoUninitSpan autoUninitSpan 446 * AutoUninitSpan autoUninitSpan(this); 419 447 * if (autoUninitSpan.uninitDone()) 420 448 * return; … … 424 452 * 425 453 * @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 to428 * create instances of this class (or call uninit()) within the429 * AutoCaller or #addCaller() scope because it is a guaranteed430 * deadlock.454 * until the number of callers added to the object using 455 * ObjectState::addCaller() or AutoCaller drops to zero. For this reason, 456 * it is forbidden to create instances of this class (or call uninit()) 457 * within the AutoCaller or ObjectState::addCaller() scope because it is 458 * a guaranteed deadlock. 431 459 * 432 460 * @note Never create instances of this class outside uninit() methods and -
trunk/src/VBox/Main/include/ObjectState.h
r51732 r51903 1 1 /** @file 2 2 * 3 * VirtualBox COM base classes definition3 * VirtualBox object state handling definitions 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2006-201 2Oracle Corporation7 * Copyright (C) 2006-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 #ifndef ____H_AUTOCALLER 19 #define ____H_AUTOCALLER 18 #ifndef ____H_OBJECTSTATE 19 #define ____H_OBJECTSTATE 20 21 #include "VBox/com/defs.h" 22 #include "VBox/com/AutoLock.h" 23 24 // Forward declaration needed, but nothing more. 25 class VirtualBoxBase; 20 26 21 27 //////////////////////////////////////////////////////////////////////////////// 22 28 // 23 // AutoCaller* classes29 // ObjectState 24 30 // 25 31 //////////////////////////////////////////////////////////////////////////////// 26 32 27 33 /** 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). 34 * Thec functionality implemented by this class is the primary object state 35 * (used by VirtualBoxBase and thus part of all API classes) that indicates 36 * if the object is ready to serve the calls, and if not, what stage it is 37 * currently at. Here is the primary state diagram: 31 38 * 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. 39 * +-------------------------------------------------------+ 40 * | | 41 * | (InitFailed) -----------------------+ | 42 * | ^ | | 43 * v | v | 44 * [*] ---> NotReady ----> (InInit) -----> Ready -----> (InUninit) ----+ 45 * ^ | 46 * | v 47 * | Limited 48 * | | 49 * +-------+ 36 50 * 37 * See VirtualBoxBase::addCaller(), VirtualBoxBase::addLimitedCaller() and 38 * VirtualBoxBase::releaseCaller() for more details about object callers. 51 * The object is fully operational only when its state is Ready. The Limited 52 * state means that only some vital part of the object is operational, and it 53 * requires some sort of reinitialization to become fully operational. The 54 * NotReady state means the object is basically dead: it either was not yet 55 * initialized after creation at all, or was uninitialized and is waiting to be 56 * destroyed when the last reference to it is released. All other states are 57 * transitional. 39 58 * 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. 59 * The NotReady->InInit->Ready, NotReady->InInit->Limited and 60 * NotReady->InInit->InitFailed transition is done by the AutoInitSpan smart 61 * class. 44 62 * 45 * @note It is preferable to use the AutoCaller and AutoLimitedCaller 46 * classes than specify the @a aLimited argument, for better 47 * self-descriptiveness. 63 * The Limited->InInit->Ready, Limited->InInit->Limited and 64 * Limited->InInit->InitFailed transition is done by the AutoReinitSpan smart 65 * class. 66 * 67 * The Ready->InUninit->NotReady and InitFailed->InUninit->NotReady 68 * transitions are done by the AutoUninitSpan smart class. 69 * 70 * In order to maintain the primary state integrity and declared functionality 71 * the following rules apply everywhere: 72 * 73 * 1) Use the above Auto*Span classes to perform state transitions. See the 74 * individual class descriptions for details. 75 * 76 * 2) All public methods of subclasses (i.e. all methods that can be called 77 * directly, not only from within other methods of the subclass) must have a 78 * standard prolog as described in the AutoCaller and AutoLimitedCaller 79 * documentation. Alternatively, they must use #addCaller() and 80 * #releaseCaller() directly (and therefore have both the prolog and the 81 * epilog), but this is not recommended because it is easy to forget the 82 * matching release, e.g. returning before reaching the call. 48 83 */ 49 template<bool aLimited> 50 class AutoCallerBase 84 class ObjectState 51 85 { 52 86 public: 87 enum State { NotReady, Ready, InInit, InUninit, InitFailed, Limited }; 53 88 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 } 89 ObjectState(VirtualBoxBase *aObj); 90 ~ObjectState(); 69 91 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 } 92 State getState(); 79 93 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; } 94 HRESULT addCaller(bool aLimited = false); 95 void releaseCaller(); 86 96 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); } 97 bool autoInitSpanConstructor(State aExpectedState); 98 void autoInitSpanDestructor(State aNewState); 99 State autoUninitSpanConstructor(); 100 void autoUninitSpanDestructor(); 152 101 153 102 private: 103 ObjectState(); 154 104 155 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoCallerBase) 156 DECLARE_CLS_NEW_DELETE_NOOP(AutoCallerBase) 105 void setState(State aState); 157 106 107 /** Pointer to the managed object, mostly for error signalling or debugging 108 * purposes, not used much. Guaranteed to be valid during the lifetime of 109 * this object, no need to mess with refcount. */ 158 110 VirtualBoxBase *mObj; 159 HRESULT mRC; 160 VirtualBoxBase::State mState; 111 /** Primary state of this object */ 112 State mState; 113 /** Thread that caused the last state change */ 114 RTTHREAD mStateChangeThread; 115 /** Total number of active calls to this object */ 116 unsigned mCallers; 117 /** Posted when the number of callers drops to zero */ 118 RTSEMEVENT mZeroCallersSem; 119 /** Posted when the object goes from InInit/InUninit to some other state */ 120 RTSEMEVENTMULTI mInitUninitSem; 121 /** Number of threads waiting for mInitUninitDoneSem */ 122 unsigned mInitUninitWaiters; 123 124 /** Protects access to state related data members */ 125 util::RWLockHandle mStateLock; 161 126 }; 162 127 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 */ 191 typedef 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 */ 220 typedef 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 */ 271 class AutoInitSpan 272 { 273 public: 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 312 private: 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 */ 367 class AutoReinitSpan 368 { 369 public: 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 387 private: 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 */ 436 class AutoUninitSpan 437 { 438 public: 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 449 private: 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 128 #endif // !____H_OBJECTSTATE -
trunk/src/VBox/Main/include/VirtualBoxBase.h
r51337 r51903 4 4 5 5 /* 6 * Copyright (C) 2006-201 3Oracle Corporation6 * Copyright (C) 2006-2014 Oracle Corporation 7 7 * 8 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 24 24 #include <map> 25 25 26 #include "ObjectState.h" 27 26 28 #include "VBox/com/AutoLock.h" 27 29 #include "VBox/com/string.h" … … 30 32 #include "VBox/com/VirtualBox.h" 31 33 32 // avoid including VBox/settings.h and VBox/xml.h; 33 // only declare the classes 34 // avoid including VBox/settings.h and VBox/xml.h; only declare the classes 34 35 namespace xml 35 36 { … … 44 45 using namespace com; 45 46 using namespace util; 46 47 class AutoInitSpan;48 class AutoUninitSpan;49 47 50 48 class VirtualBox; … … 665 663 * Declares functionality that should be available in all components. 666 664 * 667 * Among the basic functionality implemented by this class is the primary object 668 * state that indicates if the object is ready to serve the calls, and if not, 669 * what stage it is currently at. Here is the primary state diagram: 670 * 671 * +-------------------------------------------------------+ 672 * | | 673 * | (InitFailed) -----------------------+ | 674 * | ^ | | 675 * v | v | 676 * [*] ---> NotReady ----> (InInit) -----> Ready -----> (InUninit) ----+ 677 * ^ | 678 * | v 679 * | Limited 680 * | | 681 * +-------+ 682 * 683 * The object is fully operational only when its state is Ready. The Limited 684 * state means that only some vital part of the object is operational, and it 685 * requires some sort of reinitialization to become fully operational. The 686 * NotReady state means the object is basically dead: it either was not yet 687 * initialized after creation at all, or was uninitialized and is waiting to be 688 * destroyed when the last reference to it is released. All other states are 689 * transitional. 690 * 691 * The NotReady->InInit->Ready, NotReady->InInit->Limited and 692 * NotReady->InInit->InitFailed transition is done by the AutoInitSpan smart 693 * class. 694 * 695 * The Limited->InInit->Ready, Limited->InInit->Limited and 696 * Limited->InInit->InitFailed transition is done by the AutoReinitSpan smart 697 * class. 698 * 699 * The Ready->InUninit->NotReady and InitFailed->InUninit->NotReady 700 * transitions are done by the AutoUninitSpan smart class. 701 * 702 * In order to maintain the primary state integrity and declared functionality 703 * all subclasses must: 704 * 705 * 1) Use the above Auto*Span classes to perform state transitions. See the 706 * individual class descriptions for details. 707 * 708 * 2) All public methods of subclasses (i.e. all methods that can be called 709 * directly, not only from within other methods of the subclass) must have a 710 * standard prolog as described in the AutoCaller and AutoLimitedCaller 711 * documentation. Alternatively, they must use addCaller()/releaseCaller() 712 * directly (and therefore have both the prolog and the epilog), but this is 713 * not recommended. 665 * The object state logic is documented in ObjectState.h. 714 666 */ 715 667 class ATL_NO_VTABLE VirtualBoxBase … … 744 696 745 697 public: 746 enum State { NotReady, Ready, InInit, InUninit, InitFailed, Limited };747 748 698 VirtualBoxBase(); 749 699 virtual ~VirtualBoxBase(); … … 756 706 * 757 707 * @note Never call this method the AutoCaller scope or after the 758 * #addCaller() call not paired by #releaseCaller() because it is a 759 * guaranteed deadlock. See AutoUninitSpan for details. 708 * ObjectState::addCaller() call not paired by 709 * ObjectState::releaseCaller() because it is a guaranteed deadlock. 710 * See AutoUninitSpan and AutoCaller.h/ObjectState.h for details. 760 711 */ 761 712 virtual void uninit() 762 713 { } 763 714 764 virtual HRESULT addCaller(State *aState = NULL, 765 bool aLimited = false); 766 virtual void releaseCaller(); 767 768 /** 769 * Adds a limited caller. This method is equivalent to doing 770 * <tt>addCaller(aState, true)</tt>, but it is preferred because provides 771 * better self-descriptiveness. See #addCaller() for more info. 772 */ 773 HRESULT addLimitedCaller(State *aState = NULL) 774 { 775 return addCaller(aState, true /* aLimited */); 715 /** 716 */ 717 ObjectState &getObjectState() 718 { 719 return mState; 776 720 } 777 721 … … 805 749 806 750 virtual RWLockHandle *lockHandle() const; 807 808 /**809 * Returns a lock handle used to protect the primary state fields (used by810 * #addCaller(), AutoInitSpan, AutoUninitSpan, etc.). Only intended to be811 * used for similar purposes in subclasses. WARNING: NO any other locks may812 * be requested while holding this lock!813 */814 WriteLockHandle *stateLockHandle() { return &mStateLock; }815 751 816 752 static HRESULT handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL); … … 851 787 852 788 private: 853 854 void setState(State aState) 855 { 856 Assert(mState != aState); 857 mState = aState; 858 mStateChangeThread = RTThreadSelf(); 859 } 860 861 /** Primary state of this object */ 862 State mState; 863 /** Thread that caused the last state change */ 864 RTTHREAD mStateChangeThread; 865 /** Total number of active calls to this object */ 866 unsigned mCallers; 867 /** Posted when the number of callers drops to zero */ 868 RTSEMEVENT mZeroCallersSem; 869 /** Posted when the object goes from InInit/InUninit to some other state */ 870 RTSEMEVENTMULTI mInitUninitSem; 871 /** Number of threads waiting for mInitUninitDoneSem */ 872 unsigned mInitUninitWaiters; 873 874 /** Protects access to state related data members */ 875 WriteLockHandle mStateLock; 789 /** Object for representing object state */ 790 ObjectState mState; 876 791 877 792 /** User-level object lock for subclasses */ 878 793 mutable RWLockHandle *mObjectLock; 879 880 friend class AutoInitSpan;881 friend class AutoReinitSpan;882 friend class AutoUninitSpan;883 794 }; 884 795 -
trunk/src/VBox/Main/src-all/AutoCaller.cpp
r51732 r51903 3 3 /** @file 4 4 * 5 * VirtualBox COM base classesimplementation5 * VirtualBox object state implementation 6 6 */ 7 7 8 8 /* 9 * Copyright (C) 2006-201 2Oracle Corporation9 * Copyright (C) 2006-2014 Oracle Corporation 10 10 * 11 11 * This file is part of VirtualBox Open Source Edition (OSE), as … … 19 19 20 20 #include <iprt/semaphore.h> 21 #include <iprt/asm.h>22 #include <iprt/cpp/exception.h>23 24 #include <typeinfo>25 26 #if !defined (VBOX_WITH_XPCOM)27 #include <windows.h>28 #include <dbghelp.h>29 #else /* !defined (VBOX_WITH_XPCOM) */30 /// @todo remove when VirtualBoxErrorInfo goes away from here31 #include <nsIServiceManager.h>32 #include <nsIExceptionService.h>33 #endif /* !defined (VBOX_WITH_XPCOM) */34 21 35 22 #include "VirtualBoxBase.h" 36 23 #include "AutoCaller.h" 37 #include "VirtualBoxErrorInfoImpl.h"38 24 #include "Logging.h" 39 25 40 #include "VBox/com/ErrorInfo.h"41 #include "VBox/com/MultiResult.h"42 26 43 27 //////////////////////////////////////////////////////////////////////////////// 44 28 // 45 // VirtualBoxBase29 // ObjectState methods 46 30 // 47 31 //////////////////////////////////////////////////////////////////////////////// 48 32 49 VirtualBoxBase::VirtualBoxBase() 50 : mStateLock(LOCKCLASS_OBJECTSTATE) 51 { 33 34 ObjectState::ObjectState() : mStateLock(LOCKCLASS_OBJECTSTATE) 35 { 36 AssertFailed(); 37 } 38 39 ObjectState::ObjectState(VirtualBoxBase *aObj) : 40 mStateLock(LOCKCLASS_OBJECTSTATE), mObj(aObj) 41 { 42 Assert(mObj); 52 43 mState = NotReady; 53 44 mStateChangeThread = NIL_RTTHREAD; … … 56 47 mInitUninitSem = NIL_RTSEMEVENTMULTI; 57 48 mInitUninitWaiters = 0; 58 mObjectLock = NULL; 59 } 60 61 VirtualBoxBase::~VirtualBoxBase() 62 { 63 if (mObjectLock) 64 delete mObjectLock; 49 } 50 51 ObjectState::~ObjectState() 52 { 65 53 Assert(mInitUninitWaiters == 0); 66 54 Assert(mInitUninitSem == NIL_RTSEMEVENTMULTI); 67 55 if (mZeroCallersSem != NIL_RTSEMEVENT) 68 RTSemEventDestroy 56 RTSemEventDestroy(mZeroCallersSem); 69 57 mCallers = 0; 70 58 mStateChangeThread = NIL_RTTHREAD; 71 59 mState = NotReady; 72 } 73 74 /** 75 * This virtual method returns an RWLockHandle that can be used to 76 * protect instance data. This RWLockHandle is generally referred to 77 * as the "object lock"; its locking class (for lock order validation) 78 * must be returned by another virtual method, getLockingClass(), which 79 * by default returns LOCKCLASS_OTHEROBJECT but is overridden by several 80 * subclasses such as VirtualBox, Host, Machine and others. 81 * 82 * On the first call this method lazily creates the RWLockHandle. 83 * 84 * @return 85 */ 86 /* virtual */ 87 RWLockHandle *VirtualBoxBase::lockHandle() const 88 { 89 /* lazy initialization */ 90 if (RT_UNLIKELY(!mObjectLock)) 91 { 92 AssertCompile (sizeof (RWLockHandle *) == sizeof (void *)); 93 94 // getLockingClass() is overridden by many subclasses to return 95 // one of the locking classes listed at the top of AutoLock.h 96 RWLockHandle *objLock = new RWLockHandle(getLockingClass()); 97 if (!ASMAtomicCmpXchgPtr(&mObjectLock, objLock, NULL)) 98 { 99 delete objLock; 100 objLock = ASMAtomicReadPtrT(&mObjectLock, RWLockHandle *); 101 } 102 return objLock; 103 } 104 return mObjectLock; 60 mObj = NULL; 61 } 62 63 ObjectState::State ObjectState::getState() 64 { 65 AutoReadLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); 66 return mState; 105 67 } 106 68 … … 151 113 * and should return the failed result code to its own caller. 152 114 * 153 * @param aState Where to store the current object's state (can be154 * used in overridden methods to determine the cause of155 * the failure).156 115 * @param aLimited |true| to add a limited caller. 157 116 * 158 117 * @return S_OK on success or E_ACCESSDENIED on failure. 159 118 * 160 * @note It is preferable to use the #addLimitedCaller() rather than161 * calling this method with @a aLimited = |true|, for better162 * self-descriptiveness.163 *164 * @sa #addLimitedCaller()165 119 * @sa #releaseCaller() 166 120 */ 167 HRESULT VirtualBoxBase::addCaller(State *aState /* = NULL */, 168 bool aLimited /* = false */) 121 HRESULT ObjectState::addCaller(bool aLimited /* = false */) 169 122 { 170 123 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); … … 175 128 { 176 129 /* if Ready or allows Limited, increase the number of callers */ 177 ++ 130 ++mCallers; 178 131 rc = S_OK; 179 132 } … … 199 152 * uninit() is called. 200 153 */ 201 ++ 154 ++mCallers; 202 155 203 156 /* lazy semaphore creation */ 204 157 if (mInitUninitSem == NIL_RTSEMEVENTMULTI) 205 158 { 206 RTSemEventMultiCreate 159 RTSemEventMultiCreate(&mInitUninitSem); 207 160 Assert(mInitUninitWaiters == 0); 208 161 } 209 162 210 ++ 163 ++mInitUninitWaiters; 211 164 212 165 LogFlowThisFunc(("Waiting for AutoInitSpan/AutoReinitSpan to finish...\n")); 213 166 214 167 stateLock.release(); 215 RTSemEventMultiWait 168 RTSemEventMultiWait(mInitUninitSem, RT_INDEFINITE_WAIT); 216 169 stateLock.acquire(); 217 170 218 if (-- 171 if (--mInitUninitWaiters == 0) 219 172 { 220 173 /* destroy the semaphore since no more necessary */ 221 RTSemEventMultiDestroy 174 RTSemEventMultiDestroy(mInitUninitSem); 222 175 mInitUninitSem = NIL_RTSEMEVENTMULTI; 223 176 } … … 228 181 { 229 182 Assert(mCallers != 0); 230 -- 183 --mCallers; 231 184 if (mCallers == 0 && mState == InUninit) 232 185 { … … 238 191 } 239 192 240 if (aState)241 *aState = mState;242 243 193 if (FAILED(rc)) 244 194 { 245 if (mState == VirtualBoxBase::Limited)246 rc = setError(rc, "The object functionality is limited");195 if (mState == Limited) 196 rc = mObj->setError(rc, "The object functionality is limited"); 247 197 else 248 rc = setError(rc, "The object is not ready");198 rc = mObj->setError(rc, "The object is not ready"); 249 199 } 250 200 … … 255 205 * Decreases the number of calls to this object by one. 256 206 * 257 * Must be called after every #addCaller() or #addLimitedCaller() when258 * protecting the objectfrom uninitialization is no more necessary.259 */ 260 void VirtualBoxBase::releaseCaller()207 * Must be called after every #addCaller() when protecting the object 208 * from uninitialization is no more necessary. 209 */ 210 void ObjectState::releaseCaller() 261 211 { 262 212 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); … … 294 244 } 295 245 296 AssertMsgFailed (("mState = %d!", mState)); 297 } 298 299 /** 300 * Handles unexpected exceptions by turning them into COM errors in release 301 * builds or by hitting a breakpoint in the release builds. 302 * 303 * Usage pattern: 304 * @code 305 try 306 { 307 // ... 308 } 309 catch (LaLalA) 310 { 311 // ... 312 } 313 catch (...) 314 { 315 rc = VirtualBox::handleUnexpectedExceptions(this, RT_SRC_POS); 316 } 317 * @endcode 318 * 319 * @param aThis object where the exception happened 320 * @param RT_SRC_POS_DECL "RT_SRC_POS" macro instantiation. 321 * */ 322 /* static */ 323 HRESULT VirtualBoxBase::handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL) 324 { 325 try 326 { 327 /* re-throw the current exception */ 328 throw; 329 } 330 catch (const RTCError &err) // includes all XML exceptions 331 { 332 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), 333 Utf8StrFmt(tr("%s.\n%s[%d] (%s)"), 334 err.what(), 335 pszFile, iLine, pszFunction).c_str(), 336 false /* aWarning */, 337 true /* aLogIt */); 338 } 339 catch (const std::exception &err) 340 { 341 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), 342 Utf8StrFmt(tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"), 343 err.what(), typeid(err).name(), 344 pszFile, iLine, pszFunction).c_str(), 345 false /* aWarning */, 346 true /* aLogIt */); 347 } 348 catch (...) 349 { 350 return setErrorInternal(E_FAIL, aThis->getClassIID(), aThis->getComponentName(), 351 Utf8StrFmt(tr("Unknown exception\n%s[%d] (%s)"), 352 pszFile, iLine, pszFunction).c_str(), 353 false /* aWarning */, 354 true /* aLogIt */); 355 } 356 357 /* should not get here */ 358 AssertFailed(); 359 return E_FAIL; 360 } 361 362 /** 363 * Sets error info for the current thread. This is an internal function that 364 * gets eventually called by all public variants. If @a aWarning is 365 * @c true, then the highest (31) bit in the @a aResultCode value which 366 * indicates the error severity is reset to zero to make sure the receiver will 367 * recognize that the created error info object represents a warning rather 368 * than an error. 369 */ 370 /* static */ 371 HRESULT VirtualBoxBase::setErrorInternal(HRESULT aResultCode, 372 const GUID &aIID, 373 const char *pcszComponent, 374 Utf8Str aText, 375 bool aWarning, 376 bool aLogIt) 377 { 378 /* whether multi-error mode is turned on */ 379 bool preserve = MultiResult::isMultiEnabled(); 380 381 if (aLogIt) 382 LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%s}, preserve=%RTbool\n", 383 aWarning ? "WARNING" : "ERROR", 384 aResultCode, 385 aResultCode, 386 &aIID, 387 pcszComponent, 388 aText.c_str(), 389 aWarning, 390 preserve)); 391 392 /* these are mandatory, others -- not */ 393 AssertReturn((!aWarning && FAILED(aResultCode)) || 394 (aWarning && aResultCode != S_OK), 395 E_FAIL); 396 397 /* reset the error severity bit if it's a warning */ 398 if (aWarning) 399 aResultCode &= ~0x80000000; 400 401 HRESULT rc = S_OK; 402 403 if (aText.isEmpty()) 404 { 405 /* Some default info */ 406 switch (aResultCode) 407 { 408 case E_INVALIDARG: aText = "A parameter has an invalid value"; break; 409 case E_POINTER: aText = "A parameter is an invalid pointer"; break; 410 case E_UNEXPECTED: aText = "The result of the operation is unexpected"; break; 411 case E_ACCESSDENIED: aText = "The access to an object is not allowed"; break; 412 case E_OUTOFMEMORY: aText = "The allocation of new memory failed"; break; 413 case E_NOTIMPL: aText = "The requested operation is not implemented"; break; 414 case E_NOINTERFACE: aText = "The requested interface is not implemented"; break; 415 case E_FAIL: aText = "A general error occurred"; break; 416 case E_ABORT: aText = "The operation was canceled"; break; 417 case VBOX_E_OBJECT_NOT_FOUND: aText = "Object corresponding to the supplied arguments does not exist"; break; 418 case VBOX_E_INVALID_VM_STATE: aText = "Current virtual machine state prevents the operation"; break; 419 case VBOX_E_VM_ERROR: aText = "Virtual machine error occurred attempting the operation"; break; 420 case VBOX_E_FILE_ERROR: aText = "File not accessible or erroneous file contents"; break; 421 case VBOX_E_IPRT_ERROR: aText = "Runtime subsystem error"; break; 422 case VBOX_E_PDM_ERROR: aText = "Pluggable Device Manager error"; break; 423 case VBOX_E_INVALID_OBJECT_STATE: aText = "Current object state prohibits operation"; break; 424 case VBOX_E_HOST_ERROR: aText = "Host operating system related error"; break; 425 case VBOX_E_NOT_SUPPORTED: aText = "Requested operation is not supported"; break; 426 case VBOX_E_XML_ERROR: aText = "Invalid XML found"; break; 427 case VBOX_E_INVALID_SESSION_STATE: aText = "Current session state prohibits operation"; break; 428 case VBOX_E_OBJECT_IN_USE: aText = "Object being in use prohibits operation"; break; 429 default: aText = "Unknown error"; break; 430 } 431 } 432 433 do 434 { 435 ComObjPtr<VirtualBoxErrorInfo> info; 436 rc = info.createObject(); 437 if (FAILED(rc)) break; 438 439 #if !defined (VBOX_WITH_XPCOM) 440 441 ComPtr<IVirtualBoxErrorInfo> curInfo; 442 if (preserve) 443 { 444 /* get the current error info if any */ 445 ComPtr<IErrorInfo> err; 446 rc = ::GetErrorInfo (0, err.asOutParam()); 447 if (FAILED(rc)) break; 448 rc = err.queryInterfaceTo(curInfo.asOutParam()); 449 if (FAILED(rc)) 450 { 451 /* create a IVirtualBoxErrorInfo wrapper for the native 452 * IErrorInfo object */ 453 ComObjPtr<VirtualBoxErrorInfo> wrapper; 454 rc = wrapper.createObject(); 455 if (SUCCEEDED(rc)) 456 { 457 rc = wrapper->init (err); 458 if (SUCCEEDED(rc)) 459 curInfo = wrapper; 460 } 461 } 462 } 463 /* On failure, curInfo will stay null */ 464 Assert(SUCCEEDED(rc) || curInfo.isNull()); 465 466 /* set the current error info and preserve the previous one if any */ 467 rc = info->init(aResultCode, aIID, pcszComponent, aText, curInfo); 468 if (FAILED(rc)) break; 469 470 ComPtr<IErrorInfo> err; 471 rc = info.queryInterfaceTo(err.asOutParam()); 472 if (SUCCEEDED(rc)) 473 rc = ::SetErrorInfo (0, err); 474 475 #else // !defined (VBOX_WITH_XPCOM) 476 477 nsCOMPtr <nsIExceptionService> es; 478 es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc); 479 if (NS_SUCCEEDED(rc)) 480 { 481 nsCOMPtr <nsIExceptionManager> em; 482 rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); 483 if (FAILED(rc)) break; 484 485 ComPtr<IVirtualBoxErrorInfo> curInfo; 486 if (preserve) 487 { 488 /* get the current error info if any */ 489 ComPtr<nsIException> ex; 490 rc = em->GetCurrentException (ex.asOutParam()); 491 if (FAILED(rc)) break; 492 rc = ex.queryInterfaceTo(curInfo.asOutParam()); 493 if (FAILED(rc)) 494 { 495 /* create a IVirtualBoxErrorInfo wrapper for the native 496 * nsIException object */ 497 ComObjPtr<VirtualBoxErrorInfo> wrapper; 498 rc = wrapper.createObject(); 499 if (SUCCEEDED(rc)) 500 { 501 rc = wrapper->init (ex); 502 if (SUCCEEDED(rc)) 503 curInfo = wrapper; 504 } 505 } 506 } 507 /* On failure, curInfo will stay null */ 508 Assert(SUCCEEDED(rc) || curInfo.isNull()); 509 510 /* set the current error info and preserve the previous one if any */ 511 rc = info->init(aResultCode, aIID, pcszComponent, Bstr(aText), curInfo); 512 if (FAILED(rc)) break; 513 514 ComPtr<nsIException> ex; 515 rc = info.queryInterfaceTo(ex.asOutParam()); 516 if (SUCCEEDED(rc)) 517 rc = em->SetCurrentException (ex); 518 } 519 else if (rc == NS_ERROR_UNEXPECTED) 520 { 521 /* 522 * It is possible that setError() is being called by the object 523 * after the XPCOM shutdown sequence has been initiated 524 * (for example, when XPCOM releases all instances it internally 525 * references, which can cause object's FinalConstruct() and then 526 * uninit()). In this case, do_GetService() above will return 527 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to 528 * set the exception (nobody will be able to read it). 529 */ 530 LogWarningFunc(("Will not set an exception because nsIExceptionService is not available " 531 "(NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n")); 532 rc = NS_OK; 533 } 534 535 #endif // !defined (VBOX_WITH_XPCOM) 536 } 537 while (0); 538 539 AssertComRC (rc); 540 541 return SUCCEEDED(rc) ? aResultCode : rc; 542 } 543 544 /** 545 * Shortcut instance method to calling the static setErrorInternal with the 546 * class interface ID and component name inserted correctly. This uses the 547 * virtual getClassIID() and getComponentName() methods which are automatically 548 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro. 549 * @param aResultCode 550 * @param pcsz 551 * @return 552 */ 553 HRESULT VirtualBoxBase::setError(HRESULT aResultCode) 554 { 555 return setErrorInternal(aResultCode, 556 this->getClassIID(), 557 this->getComponentName(), 558 "", 559 false /* aWarning */, 560 true /* aLogIt */); 561 } 562 563 /** 564 * Shortcut instance method to calling the static setErrorInternal with the 565 * class interface ID and component name inserted correctly. This uses the 566 * virtual getClassIID() and getComponentName() methods which are automatically 567 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro. 568 * @param aResultCode 569 * @return 570 */ 571 HRESULT VirtualBoxBase::setError(HRESULT aResultCode, const char *pcsz, ...) 572 { 573 va_list args; 574 va_start(args, pcsz); 575 HRESULT rc = setErrorInternal(aResultCode, 576 this->getClassIID(), 577 this->getComponentName(), 578 Utf8Str(pcsz, args), 579 false /* aWarning */, 580 true /* aLogIt */); 581 va_end(args); 582 return rc; 583 } 584 585 /** 586 * Shortcut instance method to calling the static setErrorInternal with the 587 * class interface ID and component name inserted correctly. This uses the 588 * virtual getClassIID() and getComponentName() methods which are automatically 589 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro. 590 * @param ei 591 * @return 592 */ 593 HRESULT VirtualBoxBase::setError(const com::ErrorInfo &ei) 594 { 595 /* whether multi-error mode is turned on */ 596 bool preserve = MultiResult::isMultiEnabled(); 597 598 HRESULT rc = S_OK; 599 600 do 601 { 602 ComObjPtr<VirtualBoxErrorInfo> info; 603 rc = info.createObject(); 604 if (FAILED(rc)) break; 605 606 #if !defined (VBOX_WITH_XPCOM) 607 608 ComPtr<IVirtualBoxErrorInfo> curInfo; 609 if (preserve) 610 { 611 /* get the current error info if any */ 612 ComPtr<IErrorInfo> err; 613 rc = ::GetErrorInfo (0, err.asOutParam()); 614 if (FAILED(rc)) break; 615 rc = err.queryInterfaceTo(curInfo.asOutParam()); 616 if (FAILED(rc)) 617 { 618 /* create a IVirtualBoxErrorInfo wrapper for the native 619 * IErrorInfo object */ 620 ComObjPtr<VirtualBoxErrorInfo> wrapper; 621 rc = wrapper.createObject(); 622 if (SUCCEEDED(rc)) 623 { 624 rc = wrapper->init (err); 625 if (SUCCEEDED(rc)) 626 curInfo = wrapper; 627 } 628 } 629 } 630 /* On failure, curInfo will stay null */ 631 Assert(SUCCEEDED(rc) || curInfo.isNull()); 632 633 /* set the current error info and preserve the previous one if any */ 634 rc = info->init(ei, curInfo); 635 if (FAILED(rc)) break; 636 637 ComPtr<IErrorInfo> err; 638 rc = info.queryInterfaceTo(err.asOutParam()); 639 if (SUCCEEDED(rc)) 640 rc = ::SetErrorInfo (0, err); 641 642 #else // !defined (VBOX_WITH_XPCOM) 643 644 nsCOMPtr <nsIExceptionService> es; 645 es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc); 646 if (NS_SUCCEEDED(rc)) 647 { 648 nsCOMPtr <nsIExceptionManager> em; 649 rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); 650 if (FAILED(rc)) break; 651 652 ComPtr<IVirtualBoxErrorInfo> curInfo; 653 if (preserve) 654 { 655 /* get the current error info if any */ 656 ComPtr<nsIException> ex; 657 rc = em->GetCurrentException (ex.asOutParam()); 658 if (FAILED(rc)) break; 659 rc = ex.queryInterfaceTo(curInfo.asOutParam()); 660 if (FAILED(rc)) 661 { 662 /* create a IVirtualBoxErrorInfo wrapper for the native 663 * nsIException object */ 664 ComObjPtr<VirtualBoxErrorInfo> wrapper; 665 rc = wrapper.createObject(); 666 if (SUCCEEDED(rc)) 667 { 668 rc = wrapper->init (ex); 669 if (SUCCEEDED(rc)) 670 curInfo = wrapper; 671 } 672 } 673 } 674 /* On failure, curInfo will stay null */ 675 Assert(SUCCEEDED(rc) || curInfo.isNull()); 676 677 /* set the current error info and preserve the previous one if any */ 678 rc = info->init(ei, curInfo); 679 if (FAILED(rc)) break; 680 681 ComPtr<nsIException> ex; 682 rc = info.queryInterfaceTo(ex.asOutParam()); 683 if (SUCCEEDED(rc)) 684 rc = em->SetCurrentException (ex); 685 } 686 else if (rc == NS_ERROR_UNEXPECTED) 687 { 688 /* 689 * It is possible that setError() is being called by the object 690 * after the XPCOM shutdown sequence has been initiated 691 * (for example, when XPCOM releases all instances it internally 692 * references, which can cause object's FinalConstruct() and then 693 * uninit()). In this case, do_GetService() above will return 694 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to 695 * set the exception (nobody will be able to read it). 696 */ 697 LogWarningFunc(("Will not set an exception because nsIExceptionService is not available " 698 "(NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n")); 699 rc = NS_OK; 700 } 701 702 #endif // !defined (VBOX_WITH_XPCOM) 703 } 704 while (0); 705 706 AssertComRC (rc); 707 708 return SUCCEEDED(rc) ? ei.getResultCode() : rc; 709 } 710 711 /** 712 * Like setError(), but sets the "warning" bit in the call to setErrorInternal(). 713 * @param aResultCode 714 * @param pcsz 715 * @return 716 */ 717 HRESULT VirtualBoxBase::setWarning(HRESULT aResultCode, const char *pcsz, ...) 718 { 719 va_list args; 720 va_start(args, pcsz); 721 HRESULT rc = setErrorInternal(aResultCode, 722 this->getClassIID(), 723 this->getComponentName(), 724 Utf8Str(pcsz, args), 725 true /* aWarning */, 726 true /* aLogIt */); 727 va_end(args); 728 return rc; 729 } 730 731 /** 732 * Like setError(), but disables the "log" flag in the call to setErrorInternal(). 733 * @param aResultCode 734 * @param pcsz 735 * @return 736 */ 737 HRESULT VirtualBoxBase::setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...) 738 { 739 va_list args; 740 va_start(args, pcsz); 741 HRESULT rc = setErrorInternal(aResultCode, 742 this->getClassIID(), 743 this->getComponentName(), 744 Utf8Str(pcsz, args), 745 false /* aWarning */, 746 false /* aLogIt */); 747 va_end(args); 748 return rc; 749 } 750 751 /** 752 * Clear the current error information. 753 */ 754 /*static*/ 755 void VirtualBoxBase::clearError(void) 756 { 757 #if !defined(VBOX_WITH_XPCOM) 758 ::SetErrorInfo (0, NULL); 759 #else 760 HRESULT rc = S_OK; 761 nsCOMPtr <nsIExceptionService> es; 762 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc); 763 if (NS_SUCCEEDED(rc)) 764 { 765 nsCOMPtr <nsIExceptionManager> em; 766 rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); 767 if (SUCCEEDED(rc)) 768 em->SetCurrentException(NULL); 769 } 770 #endif 246 AssertMsgFailed(("mState = %d!", mState)); 247 } 248 249 bool ObjectState::autoInitSpanConstructor(ObjectState::State aExpectedState) 250 { 251 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); 252 253 if (mState == aExpectedState) 254 { 255 setState(InInit); 256 return true; 257 } 258 else 259 return false; 260 } 261 262 void ObjectState::autoInitSpanDestructor(State aNewState) 263 { 264 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); 265 266 Assert(mState == InInit); 267 268 if (mCallers > 0 && mInitUninitWaiters > 0) 269 { 270 /* We have some pending addCaller() calls on other threads (created 271 * during InInit), signal that InInit is finished and they may go on. */ 272 RTSemEventMultiSignal(mInitUninitSem); 273 } 274 275 setState(aNewState); 276 } 277 278 ObjectState::State ObjectState::autoUninitSpanConstructor() 279 { 280 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); 281 282 Assert(mState != InInit); 283 284 if (mState == NotReady) 285 { 286 /* do nothing if already uninitialized */ 287 return mState; 288 } 289 else if (mState == InUninit) 290 { 291 /* Another thread has already started uninitialization, wait for its 292 * completion. This is necessary to make sure that when this method 293 * returns, the object state is well-defined (NotReady). */ 294 295 /* lazy semaphore creation */ 296 if (mInitUninitSem == NIL_RTSEMEVENTMULTI) 297 { 298 RTSemEventMultiCreate(&mInitUninitSem); 299 Assert(mInitUninitWaiters == 0); 300 } 301 ++mInitUninitWaiters; 302 303 LogFlowFunc(("{%p}: Waiting for AutoUninitSpan to finish...\n", mObj)); 304 305 stateLock.release(); 306 RTSemEventMultiWait(mInitUninitSem, RT_INDEFINITE_WAIT); 307 stateLock.acquire(); 308 309 if (--mInitUninitWaiters == 0) 310 { 311 /* destroy the semaphore since no more necessary */ 312 RTSemEventMultiDestroy(mInitUninitSem); 313 mInitUninitSem = NIL_RTSEMEVENTMULTI; 314 } 315 316 /* the other thread set it to NotReady */ 317 return mState; 318 } 319 320 /* go to InUninit to prevent from adding new callers */ 321 setState(InUninit); 322 323 /* wait for already existing callers to drop to zero */ 324 if (mCallers > 0) 325 { 326 /* lazy creation */ 327 Assert(mZeroCallersSem == NIL_RTSEMEVENT); 328 RTSemEventCreate(&mZeroCallersSem); 329 330 /* wait until remaining callers release the object */ 331 LogFlowFunc(("{%p}: Waiting for callers (%d) to drop to zero...\n", 332 mObj, mCallers)); 333 334 stateLock.release(); 335 RTSemEventWait(mZeroCallersSem, RT_INDEFINITE_WAIT); 336 } 337 return mState; 338 } 339 340 void ObjectState::autoUninitSpanDestructor() 341 { 342 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS); 343 344 Assert(mState == InUninit); 345 346 setState(NotReady); 347 } 348 349 350 void ObjectState::setState(ObjectState::State aState) 351 { 352 Assert(mState != aState); 353 mState = aState; 354 mStateChangeThread = RTThreadSelf(); 771 355 } 772 356 … … 794 378 mOk(false) 795 379 { 796 Assert(aObj); 797 798 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS); 799 800 mOk = mObj->mState == VirtualBoxBase::NotReady; 801 AssertReturnVoid (mOk); 802 803 mObj->setState(VirtualBoxBase::InInit); 380 Assert(mObj); 381 mOk = mObj->getObjectState().autoInitSpanConstructor(ObjectState::NotReady); 382 AssertReturnVoid(mOk); 804 383 } 805 384 … … 817 396 return; 818 397 819 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS); 820 821 Assert(mObj->mState == VirtualBoxBase::InInit); 822 823 if (mObj->mCallers > 0) 824 { 825 Assert(mObj->mInitUninitWaiters > 0); 826 827 /* We have some pending addCaller() calls on other threads (created 828 * during InInit), signal that InInit is finished and they may go on. */ 829 RTSemEventMultiSignal(mObj->mInitUninitSem); 830 } 831 398 ObjectState::State newState; 832 399 if (mResult == Succeeded) 833 {834 mObj->setState(VirtualBoxBase::Ready);835 }400 newState = ObjectState::Ready; 401 else if (mResult == Limited) 402 newState = ObjectState::Limited; 836 403 else 837 if (mResult == Limited) 838 { 839 mObj->setState(VirtualBoxBase::Limited); 840 } 841 else 842 { 843 mObj->setState(VirtualBoxBase::InitFailed); 844 /* release the lock to prevent nesting when uninit() is called */ 845 stateLock.release(); 404 newState = ObjectState::InitFailed; 405 mObj->getObjectState().autoInitSpanDestructor(newState); 406 if (newState == ObjectState::InitFailed) 407 { 846 408 /* call uninit() to let the object uninit itself after failed init() */ 847 409 mObj->uninit(); … … 868 430 mOk(false) 869 431 { 870 Assert(aObj); 871 872 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS); 873 874 mOk = mObj->mState == VirtualBoxBase::Limited; 875 AssertReturnVoid (mOk); 876 877 mObj->setState(VirtualBoxBase::InInit); 432 Assert(mObj); 433 mOk = mObj->getObjectState().autoInitSpanConstructor(ObjectState::Limited); 434 AssertReturnVoid(mOk); 878 435 } 879 436 … … 891 448 return; 892 449 893 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS); 894 895 Assert(mObj->mState == VirtualBoxBase::InInit); 896 897 if (mObj->mCallers > 0 && mObj->mInitUninitWaiters > 0) 898 { 899 /* We have some pending addCaller() calls on other threads (created 900 * during InInit), signal that InInit is finished and they may go on. */ 901 RTSemEventMultiSignal(mObj->mInitUninitSem); 902 } 903 450 ObjectState::State newState; 904 451 if (mSucceeded) 905 { 906 mObj->setState(VirtualBoxBase::Ready); 907 } 452 newState = ObjectState::Ready; 908 453 else 909 { 910 mObj->setState(VirtualBoxBase::Limited); 911 } 454 newState = ObjectState::Limited; 455 mObj->getObjectState().autoInitSpanDestructor(newState); 456 /** @todo r=klaus: this is like the initial init() failure, but in this 457 * place uninit() is NOT called. Makes only limited sense. */ 912 458 } 913 459 … … 932 478 mUninitDone(false) 933 479 { 934 Assert(aObj); 935 936 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS); 937 938 Assert(mObj->mState != VirtualBoxBase::InInit); 939 940 /* Set mUninitDone to |true| if this object is already uninitialized 941 * (NotReady) or if another AutoUninitSpan is currently active on some 942 * other thread (InUninit). */ 943 mUninitDone = mObj->mState == VirtualBoxBase::NotReady 944 || mObj->mState == VirtualBoxBase::InUninit; 945 946 if (mObj->mState == VirtualBoxBase::InitFailed) 947 { 948 /* we've been called by init() on failure */ 480 Assert(mObj); 481 ObjectState::State state; 482 state = mObj->getObjectState().autoUninitSpanConstructor(); 483 if (state == ObjectState::InitFailed) 949 484 mInitFailed = true; 950 } 951 else 952 { 953 if (mUninitDone) 954 { 955 /* do nothing if already uninitialized */ 956 if (mObj->mState == VirtualBoxBase::NotReady) 957 return; 958 959 /* otherwise, wait until another thread finishes uninitialization. 960 * This is necessary to make sure that when this method returns, the 961 * object is NotReady and therefore can be deleted (for example). */ 962 963 /* lazy semaphore creation */ 964 if (mObj->mInitUninitSem == NIL_RTSEMEVENTMULTI) 965 { 966 RTSemEventMultiCreate(&mObj->mInitUninitSem); 967 Assert(mObj->mInitUninitWaiters == 0); 968 } 969 ++mObj->mInitUninitWaiters; 970 971 LogFlowFunc(("{%p}: Waiting for AutoUninitSpan to finish...\n", 972 mObj)); 973 974 stateLock.release(); 975 RTSemEventMultiWait(mObj->mInitUninitSem, RT_INDEFINITE_WAIT); 976 stateLock.acquire(); 977 978 if (--mObj->mInitUninitWaiters == 0) 979 { 980 /* destroy the semaphore since no more necessary */ 981 RTSemEventMultiDestroy(mObj->mInitUninitSem); 982 mObj->mInitUninitSem = NIL_RTSEMEVENTMULTI; 983 } 984 985 return; 986 } 987 } 988 989 /* go to InUninit to prevent from adding new callers */ 990 mObj->setState(VirtualBoxBase::InUninit); 991 992 /* wait for already existing callers to drop to zero */ 993 if (mObj->mCallers > 0) 994 { 995 /* lazy creation */ 996 Assert(mObj->mZeroCallersSem == NIL_RTSEMEVENT); 997 RTSemEventCreate(&mObj->mZeroCallersSem); 998 999 /* wait until remaining callers release the object */ 1000 LogFlowFunc(("{%p}: Waiting for callers (%d) to drop to zero...\n", 1001 mObj, mObj->mCallers)); 1002 1003 stateLock.release(); 1004 RTSemEventWait(mObj->mZeroCallersSem, RT_INDEFINITE_WAIT); 1005 } 485 else if (state == ObjectState::NotReady) 486 mUninitDone = true; 1006 487 } 1007 488 … … 1015 496 return; 1016 497 1017 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS); 1018 1019 Assert(mObj->mState == VirtualBoxBase::InUninit); 1020 1021 mObj->setState(VirtualBoxBase::NotReady); 1022 } 1023 1024 //////////////////////////////////////////////////////////////////////////////// 1025 // 1026 // MultiResult methods 1027 // 1028 //////////////////////////////////////////////////////////////////////////////// 1029 1030 RTTLS MultiResult::sCounter = NIL_RTTLS; 1031 1032 /*static*/ 1033 void MultiResult::incCounter() 1034 { 1035 if (sCounter == NIL_RTTLS) 1036 { 1037 sCounter = RTTlsAlloc(); 1038 AssertReturnVoid(sCounter != NIL_RTTLS); 1039 } 1040 1041 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter); 1042 ++counter; 1043 RTTlsSet(sCounter, (void*)counter); 1044 } 1045 1046 /*static*/ 1047 void MultiResult::decCounter() 1048 { 1049 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter); 1050 AssertReturnVoid(counter != 0); 1051 --counter; 1052 RTTlsSet(sCounter, (void*)counter); 1053 } 1054 1055 /*static*/ 1056 bool MultiResult::isMultiEnabled() 1057 { 1058 if (sCounter == NIL_RTTLS) 1059 return false; 1060 1061 return ((uintptr_t)RTTlsGet(MultiResult::sCounter)) > 0; 1062 } 1063 498 mObj->getObjectState().autoUninitSpanDestructor(); 499 } -
trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp
r41214 r51903 7 7 8 8 /* 9 * Copyright (C) 2006-201 2Oracle Corporation9 * Copyright (C) 2006-2014 Oracle Corporation 10 10 * 11 11 * This file is part of VirtualBox Open Source Edition (OSE), as … … 24 24 #include <typeinfo> 25 25 26 #if !defined 26 #if !defined(VBOX_WITH_XPCOM) 27 27 #include <windows.h> 28 28 #include <dbghelp.h> 29 #else /* !defined 29 #else /* !defined(VBOX_WITH_XPCOM) */ 30 30 /// @todo remove when VirtualBoxErrorInfo goes away from here 31 31 #include <nsIServiceManager.h> 32 32 #include <nsIExceptionService.h> 33 #endif /* !defined 33 #endif /* !defined(VBOX_WITH_XPCOM) */ 34 34 35 35 #include "VirtualBoxBase.h" … … 47 47 //////////////////////////////////////////////////////////////////////////////// 48 48 49 VirtualBoxBase::VirtualBoxBase() 50 : mStateLock(LOCKCLASS_OBJECTSTATE) 51 { 52 mState = NotReady; 53 mStateChangeThread = NIL_RTTHREAD; 54 mCallers = 0; 55 mZeroCallersSem = NIL_RTSEMEVENT; 56 mInitUninitSem = NIL_RTSEMEVENTMULTI; 57 mInitUninitWaiters = 0; 49 VirtualBoxBase::VirtualBoxBase() : mState(this) 50 { 58 51 mObjectLock = NULL; 59 52 } … … 63 56 if (mObjectLock) 64 57 delete mObjectLock; 65 Assert(mInitUninitWaiters == 0);66 Assert(mInitUninitSem == NIL_RTSEMEVENTMULTI);67 if (mZeroCallersSem != NIL_RTSEMEVENT)68 RTSemEventDestroy (mZeroCallersSem);69 mCallers = 0;70 mStateChangeThread = NIL_RTTHREAD;71 mState = NotReady;72 58 } 73 59 … … 90 76 if (RT_UNLIKELY(!mObjectLock)) 91 77 { 92 AssertCompile (sizeof (RWLockHandle *) == sizeof(void *));78 AssertCompile(sizeof(RWLockHandle *) == sizeof(void *)); 93 79 94 80 // getLockingClass() is overridden by many subclasses to return … … 103 89 } 104 90 return mObjectLock; 105 }106 107 /**108 * Increments the number of calls to this object by one.109 *110 * After this method succeeds, it is guaranteed that the object will remain111 * in the Ready (or in the Limited) state at least until #releaseCaller() is112 * called.113 *114 * This method is intended to mark the beginning of sections of code within115 * methods of COM objects that depend on the readiness (Ready) state. The116 * Ready state is a primary "ready to serve" state. Usually all code that117 * works with component's data depends on it. On practice, this means that118 * almost every public method, setter or getter of the object should add119 * itself as an object's caller at the very beginning, to protect from an120 * unexpected uninitialization that may happen on a different thread.121 *122 * Besides the Ready state denoting that the object is fully functional,123 * there is a special Limited state. The Limited state means that the object124 * is still functional, but its functionality is limited to some degree, so125 * not all operations are possible. The @a aLimited argument to this method126 * determines whether the caller represents this limited functionality or127 * not.128 *129 * This method succeeds (and increments the number of callers) only if the130 * current object's state is Ready. Otherwise, it will return E_ACCESSDENIED131 * to indicate that the object is not operational. There are two exceptions132 * from this rule:133 * <ol>134 * <li>If the @a aLimited argument is |true|, then this method will also135 * succeed if the object's state is Limited (or Ready, of course).136 * </li>137 * <li>If this method is called from the same thread that placed138 * the object to InInit or InUninit state (i.e. either from within the139 * AutoInitSpan or AutoUninitSpan scope), it will succeed as well (but140 * will not increase the number of callers).141 * </li>142 * </ol>143 *144 * Normally, calling addCaller() never blocks. However, if this method is145 * called by a thread created from within the AutoInitSpan scope and this146 * scope is still active (i.e. the object state is InInit), it will block147 * until the AutoInitSpan destructor signals that it has finished148 * initialization.149 *150 * When this method returns a failure, the caller must not use the object151 * and should return the failed result code to its own caller.152 *153 * @param aState Where to store the current object's state (can be154 * used in overridden methods to determine the cause of155 * the failure).156 * @param aLimited |true| to add a limited caller.157 *158 * @return S_OK on success or E_ACCESSDENIED on failure.159 *160 * @note It is preferable to use the #addLimitedCaller() rather than161 * calling this method with @a aLimited = |true|, for better162 * self-descriptiveness.163 *164 * @sa #addLimitedCaller()165 * @sa #releaseCaller()166 */167 HRESULT VirtualBoxBase::addCaller(State *aState /* = NULL */,168 bool aLimited /* = false */)169 {170 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS);171 172 HRESULT rc = E_ACCESSDENIED;173 174 if (mState == Ready || (aLimited && mState == Limited))175 {176 /* if Ready or allows Limited, increase the number of callers */177 ++ mCallers;178 rc = S_OK;179 }180 else181 if (mState == InInit || mState == InUninit)182 {183 if (mStateChangeThread == RTThreadSelf())184 {185 /* Called from the same thread that is doing AutoInitSpan or186 * AutoUninitSpan, just succeed */187 rc = S_OK;188 }189 else if (mState == InInit)190 {191 /* addCaller() is called by a "child" thread while the "parent"192 * thread is still doing AutoInitSpan/AutoReinitSpan, so wait for193 * the state to become either Ready/Limited or InitFailed (in194 * case of init failure).195 *196 * Note that we increase the number of callers anyway -- to197 * prevent AutoUninitSpan from early completion if we are198 * still not scheduled to pick up the posted semaphore when199 * uninit() is called.200 */201 ++ mCallers;202 203 /* lazy semaphore creation */204 if (mInitUninitSem == NIL_RTSEMEVENTMULTI)205 {206 RTSemEventMultiCreate (&mInitUninitSem);207 Assert(mInitUninitWaiters == 0);208 }209 210 ++ mInitUninitWaiters;211 212 LogFlowThisFunc(("Waiting for AutoInitSpan/AutoReinitSpan to finish...\n"));213 214 stateLock.release();215 RTSemEventMultiWait (mInitUninitSem, RT_INDEFINITE_WAIT);216 stateLock.acquire();217 218 if (-- mInitUninitWaiters == 0)219 {220 /* destroy the semaphore since no more necessary */221 RTSemEventMultiDestroy (mInitUninitSem);222 mInitUninitSem = NIL_RTSEMEVENTMULTI;223 }224 225 if (mState == Ready || (aLimited && mState == Limited))226 rc = S_OK;227 else228 {229 Assert(mCallers != 0);230 -- mCallers;231 if (mCallers == 0 && mState == InUninit)232 {233 /* inform AutoUninitSpan ctor there are no more callers */234 RTSemEventSignal(mZeroCallersSem);235 }236 }237 }238 }239 240 if (aState)241 *aState = mState;242 243 if (FAILED(rc))244 {245 if (mState == VirtualBoxBase::Limited)246 rc = setError(rc, "The object functionality is limited");247 else248 rc = setError(rc, "The object is not ready");249 }250 251 return rc;252 }253 254 /**255 * Decreases the number of calls to this object by one.256 *257 * Must be called after every #addCaller() or #addLimitedCaller() when258 * protecting the object from uninitialization is no more necessary.259 */260 void VirtualBoxBase::releaseCaller()261 {262 AutoWriteLock stateLock(mStateLock COMMA_LOCKVAL_SRC_POS);263 264 if (mState == Ready || mState == Limited)265 {266 /* if Ready or Limited, decrease the number of callers */267 AssertMsgReturn(mCallers != 0, ("mCallers is ZERO!"), (void) 0);268 --mCallers;269 270 return;271 }272 273 if (mState == InInit || mState == InUninit)274 {275 if (mStateChangeThread == RTThreadSelf())276 {277 /* Called from the same thread that is doing AutoInitSpan or278 * AutoUninitSpan: just succeed */279 return;280 }281 282 if (mState == InUninit)283 {284 /* the caller is being released after AutoUninitSpan has begun */285 AssertMsgReturn(mCallers != 0, ("mCallers is ZERO!"), (void) 0);286 --mCallers;287 288 if (mCallers == 0)289 /* inform the Auto*UninitSpan ctor there are no more callers */290 RTSemEventSignal(mZeroCallersSem);291 292 return;293 }294 }295 296 AssertMsgFailed (("mState = %d!", mState));297 91 } 298 92 … … 437 231 if (FAILED(rc)) break; 438 232 439 #if !defined 233 #if !defined(VBOX_WITH_XPCOM) 440 234 441 235 ComPtr<IVirtualBoxErrorInfo> curInfo; … … 444 238 /* get the current error info if any */ 445 239 ComPtr<IErrorInfo> err; 446 rc = ::GetErrorInfo 240 rc = ::GetErrorInfo(0, err.asOutParam()); 447 241 if (FAILED(rc)) break; 448 242 rc = err.queryInterfaceTo(curInfo.asOutParam()); … … 455 249 if (SUCCEEDED(rc)) 456 250 { 457 rc = wrapper->init 251 rc = wrapper->init(err); 458 252 if (SUCCEEDED(rc)) 459 253 curInfo = wrapper; … … 471 265 rc = info.queryInterfaceTo(err.asOutParam()); 472 266 if (SUCCEEDED(rc)) 473 rc = ::SetErrorInfo 474 475 #else // !defined 267 rc = ::SetErrorInfo(0, err); 268 269 #else // !defined(VBOX_WITH_XPCOM) 476 270 477 271 nsCOMPtr <nsIExceptionService> es; 478 es = do_GetService 272 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc); 479 273 if (NS_SUCCEEDED(rc)) 480 274 { 481 275 nsCOMPtr <nsIExceptionManager> em; 482 rc = es->GetCurrentExceptionManager (getter_AddRefs(em));276 rc = es->GetCurrentExceptionManager(getter_AddRefs(em)); 483 277 if (FAILED(rc)) break; 484 278 … … 488 282 /* get the current error info if any */ 489 283 ComPtr<nsIException> ex; 490 rc = em->GetCurrentException 284 rc = em->GetCurrentException(ex.asOutParam()); 491 285 if (FAILED(rc)) break; 492 286 rc = ex.queryInterfaceTo(curInfo.asOutParam()); … … 499 293 if (SUCCEEDED(rc)) 500 294 { 501 rc = wrapper->init 295 rc = wrapper->init(ex); 502 296 if (SUCCEEDED(rc)) 503 297 curInfo = wrapper; … … 515 309 rc = info.queryInterfaceTo(ex.asOutParam()); 516 310 if (SUCCEEDED(rc)) 517 rc = em->SetCurrentException 311 rc = em->SetCurrentException(ex); 518 312 } 519 313 else if (rc == NS_ERROR_UNEXPECTED) … … 533 327 } 534 328 535 #endif // !defined 329 #endif // !defined(VBOX_WITH_XPCOM) 536 330 } 537 331 while (0); 538 332 539 AssertComRC 333 AssertComRC(rc); 540 334 541 335 return SUCCEEDED(rc) ? aResultCode : rc; … … 604 398 if (FAILED(rc)) break; 605 399 606 #if !defined 400 #if !defined(VBOX_WITH_XPCOM) 607 401 608 402 ComPtr<IVirtualBoxErrorInfo> curInfo; … … 611 405 /* get the current error info if any */ 612 406 ComPtr<IErrorInfo> err; 613 rc = ::GetErrorInfo 407 rc = ::GetErrorInfo(0, err.asOutParam()); 614 408 if (FAILED(rc)) break; 615 409 rc = err.queryInterfaceTo(curInfo.asOutParam()); … … 622 416 if (SUCCEEDED(rc)) 623 417 { 624 rc = wrapper->init 418 rc = wrapper->init(err); 625 419 if (SUCCEEDED(rc)) 626 420 curInfo = wrapper; … … 638 432 rc = info.queryInterfaceTo(err.asOutParam()); 639 433 if (SUCCEEDED(rc)) 640 rc = ::SetErrorInfo 641 642 #else // !defined 434 rc = ::SetErrorInfo(0, err); 435 436 #else // !defined(VBOX_WITH_XPCOM) 643 437 644 438 nsCOMPtr <nsIExceptionService> es; 645 es = do_GetService 439 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc); 646 440 if (NS_SUCCEEDED(rc)) 647 441 { 648 442 nsCOMPtr <nsIExceptionManager> em; 649 rc = es->GetCurrentExceptionManager (getter_AddRefs(em));443 rc = es->GetCurrentExceptionManager(getter_AddRefs(em)); 650 444 if (FAILED(rc)) break; 651 445 … … 655 449 /* get the current error info if any */ 656 450 ComPtr<nsIException> ex; 657 rc = em->GetCurrentException 451 rc = em->GetCurrentException(ex.asOutParam()); 658 452 if (FAILED(rc)) break; 659 453 rc = ex.queryInterfaceTo(curInfo.asOutParam()); … … 666 460 if (SUCCEEDED(rc)) 667 461 { 668 rc = wrapper->init 462 rc = wrapper->init(ex); 669 463 if (SUCCEEDED(rc)) 670 464 curInfo = wrapper; … … 682 476 rc = info.queryInterfaceTo(ex.asOutParam()); 683 477 if (SUCCEEDED(rc)) 684 rc = em->SetCurrentException 478 rc = em->SetCurrentException(ex); 685 479 } 686 480 else if (rc == NS_ERROR_UNEXPECTED) … … 700 494 } 701 495 702 #endif // !defined 496 #endif // !defined(VBOX_WITH_XPCOM) 703 497 } 704 498 while (0); 705 499 706 AssertComRC 500 AssertComRC(rc); 707 501 708 502 return SUCCEEDED(rc) ? ei.getResultCode() : rc; … … 756 550 { 757 551 #if !defined(VBOX_WITH_XPCOM) 758 ::SetErrorInfo 552 ::SetErrorInfo(0, NULL); 759 553 #else 760 554 HRESULT rc = S_OK; … … 764 558 { 765 559 nsCOMPtr <nsIExceptionManager> em; 766 rc = es->GetCurrentExceptionManager (getter_AddRefs(em));560 rc = es->GetCurrentExceptionManager(getter_AddRefs(em)); 767 561 if (SUCCEEDED(rc)) 768 562 em->SetCurrentException(NULL); … … 771 565 } 772 566 773 774 ////////////////////////////////////////////////////////////////////////////////775 //776 // AutoInitSpan methods777 //778 ////////////////////////////////////////////////////////////////////////////////779 780 /**781 * Creates a smart initialization span object that places the object to782 * InInit state.783 *784 * Please see the AutoInitSpan class description for more info.785 *786 * @param aObj |this| pointer of the managed VirtualBoxBase object whose787 * init() method is being called.788 * @param aResult Default initialization result.789 */790 AutoInitSpan::AutoInitSpan(VirtualBoxBase *aObj,791 Result aResult /* = Failed */)792 : mObj(aObj),793 mResult(aResult),794 mOk(false)795 {796 Assert(aObj);797 798 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS);799 800 mOk = mObj->mState == VirtualBoxBase::NotReady;801 AssertReturnVoid (mOk);802 803 mObj->setState(VirtualBoxBase::InInit);804 }805 806 /**807 * Places the managed VirtualBoxBase object to Ready/Limited state if the808 * initialization succeeded or partly succeeded, or places it to InitFailed809 * state and calls the object's uninit() method.810 *811 * Please see the AutoInitSpan class description for more info.812 */813 AutoInitSpan::~AutoInitSpan()814 {815 /* if the state was other than NotReady, do nothing */816 if (!mOk)817 return;818 819 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS);820 821 Assert(mObj->mState == VirtualBoxBase::InInit);822 823 if (mObj->mCallers > 0)824 {825 Assert(mObj->mInitUninitWaiters > 0);826 827 /* We have some pending addCaller() calls on other threads (created828 * during InInit), signal that InInit is finished and they may go on. */829 RTSemEventMultiSignal(mObj->mInitUninitSem);830 }831 832 if (mResult == Succeeded)833 {834 mObj->setState(VirtualBoxBase::Ready);835 }836 else837 if (mResult == Limited)838 {839 mObj->setState(VirtualBoxBase::Limited);840 }841 else842 {843 mObj->setState(VirtualBoxBase::InitFailed);844 /* release the lock to prevent nesting when uninit() is called */845 stateLock.release();846 /* call uninit() to let the object uninit itself after failed init() */847 mObj->uninit();848 /* Note: the object may no longer exist here (for example, it can call849 * the destructor in uninit()) */850 }851 }852 853 // AutoReinitSpan methods854 ////////////////////////////////////////////////////////////////////////////////855 856 /**857 * Creates a smart re-initialization span object and places the object to858 * InInit state.859 *860 * Please see the AutoInitSpan class description for more info.861 *862 * @param aObj |this| pointer of the managed VirtualBoxBase object whose863 * re-initialization method is being called.864 */865 AutoReinitSpan::AutoReinitSpan(VirtualBoxBase *aObj)866 : mObj(aObj),867 mSucceeded(false),868 mOk(false)869 {870 Assert(aObj);871 872 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS);873 874 mOk = mObj->mState == VirtualBoxBase::Limited;875 AssertReturnVoid (mOk);876 877 mObj->setState(VirtualBoxBase::InInit);878 }879 880 /**881 * Places the managed VirtualBoxBase object to Ready state if the882 * re-initialization succeeded (i.e. #setSucceeded() has been called) or back to883 * Limited state otherwise.884 *885 * Please see the AutoInitSpan class description for more info.886 */887 AutoReinitSpan::~AutoReinitSpan()888 {889 /* if the state was other than Limited, do nothing */890 if (!mOk)891 return;892 893 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS);894 895 Assert(mObj->mState == VirtualBoxBase::InInit);896 897 if (mObj->mCallers > 0 && mObj->mInitUninitWaiters > 0)898 {899 /* We have some pending addCaller() calls on other threads (created900 * during InInit), signal that InInit is finished and they may go on. */901 RTSemEventMultiSignal(mObj->mInitUninitSem);902 }903 904 if (mSucceeded)905 {906 mObj->setState(VirtualBoxBase::Ready);907 }908 else909 {910 mObj->setState(VirtualBoxBase::Limited);911 }912 }913 914 // AutoUninitSpan methods915 ////////////////////////////////////////////////////////////////////////////////916 917 /**918 * Creates a smart uninitialization span object and places this object to919 * InUninit state.920 *921 * Please see the AutoInitSpan class description for more info.922 *923 * @note This method blocks the current thread execution until the number of924 * callers of the managed VirtualBoxBase object drops to zero!925 *926 * @param aObj |this| pointer of the VirtualBoxBase object whose uninit()927 * method is being called.928 */929 AutoUninitSpan::AutoUninitSpan(VirtualBoxBase *aObj)930 : mObj(aObj),931 mInitFailed(false),932 mUninitDone(false)933 {934 Assert(aObj);935 936 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS);937 938 Assert(mObj->mState != VirtualBoxBase::InInit);939 940 /* Set mUninitDone to |true| if this object is already uninitialized941 * (NotReady) or if another AutoUninitSpan is currently active on some942 * other thread (InUninit). */943 mUninitDone = mObj->mState == VirtualBoxBase::NotReady944 || mObj->mState == VirtualBoxBase::InUninit;945 946 if (mObj->mState == VirtualBoxBase::InitFailed)947 {948 /* we've been called by init() on failure */949 mInitFailed = true;950 }951 else952 {953 if (mUninitDone)954 {955 /* do nothing if already uninitialized */956 if (mObj->mState == VirtualBoxBase::NotReady)957 return;958 959 /* otherwise, wait until another thread finishes uninitialization.960 * This is necessary to make sure that when this method returns, the961 * object is NotReady and therefore can be deleted (for example). */962 963 /* lazy semaphore creation */964 if (mObj->mInitUninitSem == NIL_RTSEMEVENTMULTI)965 {966 RTSemEventMultiCreate(&mObj->mInitUninitSem);967 Assert(mObj->mInitUninitWaiters == 0);968 }969 ++mObj->mInitUninitWaiters;970 971 LogFlowFunc(("{%p}: Waiting for AutoUninitSpan to finish...\n",972 mObj));973 974 stateLock.release();975 RTSemEventMultiWait(mObj->mInitUninitSem, RT_INDEFINITE_WAIT);976 stateLock.acquire();977 978 if (--mObj->mInitUninitWaiters == 0)979 {980 /* destroy the semaphore since no more necessary */981 RTSemEventMultiDestroy(mObj->mInitUninitSem);982 mObj->mInitUninitSem = NIL_RTSEMEVENTMULTI;983 }984 985 return;986 }987 }988 989 /* go to InUninit to prevent from adding new callers */990 mObj->setState(VirtualBoxBase::InUninit);991 992 /* wait for already existing callers to drop to zero */993 if (mObj->mCallers > 0)994 {995 /* lazy creation */996 Assert(mObj->mZeroCallersSem == NIL_RTSEMEVENT);997 RTSemEventCreate(&mObj->mZeroCallersSem);998 999 /* wait until remaining callers release the object */1000 LogFlowFunc(("{%p}: Waiting for callers (%d) to drop to zero...\n",1001 mObj, mObj->mCallers));1002 1003 stateLock.release();1004 RTSemEventWait(mObj->mZeroCallersSem, RT_INDEFINITE_WAIT);1005 }1006 }1007 1008 /**1009 * Places the managed VirtualBoxBase object to the NotReady state.1010 */1011 AutoUninitSpan::~AutoUninitSpan()1012 {1013 /* do nothing if already uninitialized */1014 if (mUninitDone)1015 return;1016 1017 AutoWriteLock stateLock(mObj->mStateLock COMMA_LOCKVAL_SRC_POS);1018 1019 Assert(mObj->mState == VirtualBoxBase::InUninit);1020 1021 mObj->setState(VirtualBoxBase::NotReady);1022 }1023 567 1024 568 //////////////////////////////////////////////////////////////////////////////// -
trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
r51765 r51903 7177 7177 7178 7178 LogRel(("Console::powerDown(): A request to power off the VM has been issued (mMachineState=%s, InUninit=%d)\n", 7179 Global::stringifyMachineState(mMachineState), autoCaller.state() ==InUninit));7179 Global::stringifyMachineState(mMachineState), getObjectState().getState() == ObjectState::InUninit)); 7180 7180 7181 7181 /* Check if we need to power off the VM. In case of mVMPoweredOff=true, the … … 7320 7320 /* If we are called from Console::uninit(), then try to destroy the VM even 7321 7321 * on failure (this will most likely fail too, but what to do?..) */ 7322 if (RT_SUCCESS(vrc) || autoCaller.state() ==InUninit)7322 if (RT_SUCCESS(vrc) || getObjectState().getState() == ObjectState::InUninit) 7323 7323 { 7324 7324 /* If the machine has a USB controller, release all USB devices … … 7518 7518 { 7519 7519 /* sanity check */ 7520 AssertReturn( AutoCaller(this).state() == InInit ||7521 isWriteLockOnCurrentThread(), E_FAIL);7520 AssertReturn( getObjectState().getState() == ObjectState::InInit 7521 || isWriteLockOnCurrentThread(), E_FAIL); 7522 7522 7523 7523 LogFlowThisFunc(("Entering\n")); … … 7863 7863 * 2) VM-(guest-)initiated power off. */ 7864 7864 AssertReturnVoid( autoCaller.isOk() 7865 || autoCaller.state() ==InUninit);7865 || that->getObjectState().getState() == ObjectState::InUninit); 7866 7866 7867 7867 switch (enmState) -
trunk/src/VBox/Main/src-client/SessionImpl.cpp
r51612 r51903 475 475 AutoCaller autoCaller(this); 476 476 477 if ( autoCaller.state() !=Ready)477 if (getObjectState().getState() != ObjectState::Ready) 478 478 { 479 479 /* … … 514 514 HRESULT rc = S_OK; 515 515 516 if ( autoCaller.state() ==Ready)516 if (getObjectState().getState() == ObjectState::Ready) 517 517 { 518 518 /* close() needs write lock */ … … 536 536 rc = unlockMachine(false /* aFinalRelease */, true /* aFromServer */); 537 537 } 538 else if ( autoCaller.state() ==InUninit)538 else if (getObjectState().getState() == ObjectState::InUninit) 539 539 { 540 540 /* -
trunk/src/VBox/Main/src-server/HostImpl.cpp
r51092 r51903 5 5 6 6 /* 7 * Copyright (C) 2004-201 3Oracle Corporation7 * Copyright (C) 2004-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 2972 2972 { 2973 2973 #ifdef VBOX_WITH_HOSTNETIF_API 2974 AssertReturn( AutoCaller(this).state() == InInit ||2975 isWriteLockOnCurrentThread(), E_FAIL);2974 AssertReturn( getObjectState().getState() == ObjectState::InInit 2975 || isWriteLockOnCurrentThread(), E_FAIL); 2976 2976 2977 2977 HostNetworkInterfaceList list, listCopy; -
trunk/src/VBox/Main/src-server/MachineImpl.cpp
r51770 r51903 7436 7436 7437 7437 /* just return false for inaccessible machines */ 7438 if ( autoCaller.state() !=Ready)7438 if (getObjectState().getState() != ObjectState::Ready) 7439 7439 return false; 7440 7440 … … 7469 7469 7470 7470 /* just return false for inaccessible machines */ 7471 if ( autoCaller.state() !=Ready)7471 if (getObjectState().getState() != ObjectState::Ready) 7472 7472 return false; 7473 7473 … … 7599 7599 mData->mUuid.toString().c_str()); 7600 7600 7601 AssertReturn( autoCaller.state() ==Ready, E_FAIL);7601 AssertReturn(getObjectState().getState() == ObjectState::Ready, E_FAIL); 7602 7602 7603 7603 if (mData->mRegistered) … … 7853 7853 AutoCaller autoCaller(this); 7854 7854 AssertComRCReturnRC(autoCaller.rc()); 7855 AssertComRCReturn( autoCaller.state() == InInit ||7856 autoCaller.state() ==Limited, E_FAIL);7855 AssertComRCReturn( getObjectState().getState() == ObjectState::InInit 7856 || getObjectState().getState() == ObjectState::Limited, E_FAIL); 7857 7857 7858 7858 AssertReturn(!mData->mAccessible, E_FAIL); … … 7927 7927 AutoCaller autoCaller(this); 7928 7928 AssertComRCReturnVoid(autoCaller.rc()); 7929 AssertComRCReturnVoid( autoCaller.state() ==InUninit7930 || autoCaller.state() ==Limited);7929 AssertComRCReturnVoid( getObjectState().getState() == ObjectState::InUninit 7930 || getObjectState().getState() == ObjectState::Limited); 7931 7931 7932 7932 /* tell all our other child objects we've been uninitialized */ … … 12716 12716 AutoCaller autoCaller(this); 12717 12717 12718 LogFlowThisFunc(("callerstate=%d\n", autoCaller.state()));12718 LogFlowThisFunc(("callerstate=%d\n", getObjectState().getState())); 12719 12719 /* 12720 12720 * We don't assert below because it might happen that a non-direct session -
trunk/src/VBox/Main/src-server/MediumImpl.cpp
r51888 r51903 5 5 6 6 /* 7 * Copyright (C) 2008-201 3Oracle Corporation7 * Copyright (C) 2008-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 1375 1375 { 1376 1376 /* remove the caller reference we added in setFormat() */ 1377 m->formatObj-> releaseCaller();1377 m->formatObj->getObjectState().releaseCaller(); 1378 1378 m->formatObj.setNull(); 1379 1379 } … … 6004 6004 * no format is known yet */ 6005 6005 AssertReturn( (!m->strFormat.isEmpty() && !m->formatObj.isNull()) 6006 || ( autoCaller.state() ==InInit6006 || ( getObjectState().getState() == ObjectState::InInit 6007 6007 && m->state != MediumState_NotCreated 6008 6008 && m->id.isZero() … … 6177 6177 /* reference the format permanently to prevent its unexpected 6178 6178 * uninitialization */ 6179 HRESULT rc = m->formatObj-> addCaller();6179 HRESULT rc = m->formatObj->getObjectState().addCaller(m->formatObj); 6180 6180 AssertComRCReturnRC(rc); 6181 6181 -
trunk/src/VBox/Main/src-server/SnapshotImpl.cpp
r51498 r51903 1797 1797 AutoCaller autoCaller(this); 1798 1798 1799 LogFlowThisFunc(("state=%d\n", autoCaller.state()));1799 LogFlowThisFunc(("state=%d\n", getObjectState().getState())); 1800 1800 if (!autoCaller.isOk()) 1801 1801 { … … 2338 2338 AutoCaller autoCaller(this); 2339 2339 2340 LogFlowThisFunc(("state=%d\n", autoCaller.state()));2340 LogFlowThisFunc(("state=%d\n", getObjectState().getState())); 2341 2341 if (!autoCaller.isOk()) 2342 2342 { -
trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp
r51888 r51903 2272 2272 if (SUCCEEDED((rc = autoCaller.rc()))) 2273 2273 { 2274 if ( autoCaller.state() !=Ready)2274 if (getObjectState().getState() != ObjectState::Ready) 2275 2275 LogWarningFunc(("VirtualBox has been uninitialized (state=%d), the event is discarded!\n", 2276 autoCaller.state()));2276 getObjectState().getState())); 2277 2277 // return S_OK 2278 2278 else if ( (m->pAsyncEventQ) … … 4128 4128 } 4129 4129 4130 if ( autoCaller.state() !=InInit)4130 if (getObjectState().getState() != ObjectState::InInit) 4131 4131 { 4132 4132 rc = aMachine->i_prepareRegister(); … … 4137 4137 m->allMachines.addChild(aMachine); 4138 4138 4139 if ( autoCaller.state() !=InInit)4139 if (getObjectState().getState() != ObjectState::InInit) 4140 4140 rc = i_saveSettings(); 4141 4141 … … 4519 4519 continue; 4520 4520 /* object is already dead, no point in saving settings */ 4521 if ( autoCaller.state() !=Ready)4521 if (getObjectState().getState() != ObjectState::Ready) 4522 4522 continue; 4523 4523 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS); … … 4699 4699 { 4700 4700 LogWarningFunc(("VirtualBox has been uninitialized (state=%d), the callback event is discarded!\n", 4701 autoCaller.state()));4701 mVirtualBox->getObjectState().getState())); 4702 4702 /* We don't need mVirtualBox any more, so release it */ 4703 4703 mVirtualBox = NULL; -
trunk/src/VBox/Main/testcase/Makefile.kmk
r50613 r51903 242 242 ../src-client/MouseImpl.cpp \ 243 243 ../src-all/EventImpl.cpp \ 244 ../src-all/AutoCaller.cpp \ 244 245 ../src-all/VirtualBoxBase.cpp \ 245 246 ../src-all/VirtualBoxErrorInfoImpl.cpp \
Note:
See TracChangeset
for help on using the changeset viewer.