- Timestamp:
- Dec 9, 2009 7:50:30 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 55830
- Location:
- trunk/src/VBox/Main
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/AutoLock.cpp
r25282 r25283 26 26 #include <iprt/string.h> 27 27 28 #include <vector> 28 29 29 30 namespace util … … 94 95 //////////////////////////////////////////////////////////////////////////////// 95 96 97 typedef std::vector<LockHandle*> HandlesVector; 98 96 99 struct AutoLockBase::Data 97 100 { 98 Data( LockHandle *argpHandle)99 : pHandle(argpHandle),101 Data(size_t cHandles) 102 : aHandles(cHandles), // size of array 100 103 fIsLocked(false), 101 104 cUnlockedInLeave(0) 102 105 { } 103 106 104 LockHandle *pHandle; 105 bool fIsLocked; 107 HandlesVector aHandles; // array (vector) of LockHandle instances; in the case of AutoWriteLock 108 // and AutoReadLock, there will only be one item on the list; with the 109 // AutoMulti* derivatives, there will be multiple 110 bool fIsLocked; // if true, then all items in aHandles are locked by this AutoLock and 111 // need to be unlocked in the destructor 106 112 uint32_t cUnlockedInLeave; // how many times the handle was unlocked in leave(); otherwise 0 107 113 }; … … 109 115 AutoLockBase::AutoLockBase(LockHandle *pHandle) 110 116 { 111 m = new Data(pHandle); 117 m = new Data(1); 118 m->aHandles[0] = pHandle; 112 119 } 113 120 … … 119 126 /** 120 127 * Requests ownership of all contained lock handles by calling 121 * the pure virtual acquireImpl() function on each of them,128 * the pure virtual callLockImpl() function on each of them, 122 129 * which must be implemented by the descendant class; in the 123 130 * implementation, AutoWriteLock will request a write lock 124 131 * whereas AutoReadLock will request a read lock. 125 */ 126 void AutoLockBase::acquire() 127 { 128 if (m->pHandle) 129 { 130 AssertMsg(!m->fIsLocked, ("m->fIsLocked is true, attempting to lock twice!")); 131 // call virtual function implemented in AutoWriteLock or AutoReadLock 132 this->acquireImpl(*m->pHandle); 133 m->fIsLocked = true; 132 * 133 * Does *not* modify the lock counts in the member variables. 134 */ 135 void AutoLockBase::callLockOnAllHandles() 136 { 137 for (HandlesVector::iterator it = m->aHandles.begin(); 138 it != m->aHandles.end(); 139 ++it) 140 { 141 LockHandle *pHandle = *it; 142 if (pHandle) 143 // call virtual function implemented in AutoWriteLock or AutoReadLock 144 this->callLockImpl(*pHandle); 134 145 } 135 146 } … … 137 148 /** 138 149 * Releases ownership of all contained lock handles by calling 139 * the pure virtual releaseImpl() function on each of them,150 * the pure virtual callUnlockImpl() function on each of them, 140 151 * which must be implemented by the descendant class; in the 141 152 * implementation, AutoWriteLock will release a write lock 142 153 * whereas AutoReadLock will release a read lock. 154 * 155 * Does *not* modify the lock counts in the member variables. 156 */ 157 void AutoLockBase::callUnlockOnAllHandles() 158 { 159 for (HandlesVector::iterator it = m->aHandles.begin(); 160 it != m->aHandles.end(); 161 ++it) 162 { 163 LockHandle *pHandle = *it; 164 if (pHandle) 165 // call virtual function implemented in AutoWriteLock or AutoReadLock 166 this->callUnlockImpl(*pHandle); 167 } 168 } 169 170 /** 171 * Destructor implementation that can also be called explicitly, if required. 172 * Restores the exact state before the AutoLock was created; that is, unlocks 173 * all contained semaphores and might actually lock them again if leave() 174 * was called during the AutoLock's lifetime. 175 */ 176 void AutoLockBase::cleanup() 177 { 178 if (m->cUnlockedInLeave) 179 { 180 // there was a leave() before the destruction: then restore the 181 // lock level that might have been set by locks other than our own 182 if (m->fIsLocked) 183 --m->cUnlockedInLeave; // no lock for our own 184 m->fIsLocked = false; 185 for (; m->cUnlockedInLeave; --m->cUnlockedInLeave) 186 callLockOnAllHandles(); 187 } 188 189 if (m->fIsLocked) 190 callUnlockOnAllHandles(); 191 } 192 193 /** 194 * Requests ownership of all contained semaphores. Public method that can 195 * only be called once and that also gets called by the AutoLock constructors. 196 */ 197 void AutoLockBase::acquire() 198 { 199 AssertMsg(!m->fIsLocked, ("m->fIsLocked is true, attempting to lock twice!")); 200 callLockOnAllHandles(); 201 m->fIsLocked = true; 202 } 203 204 /** 205 * Releases ownership of all contained semaphores. Public method. 143 206 */ 144 207 void AutoLockBase::release() 145 208 { 146 if (m->pHandle) 147 { 148 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot release!")); 149 // call virtual function implemented in AutoWriteLock or AutoReadLock 150 this->releaseImpl(*m->pHandle); 151 m->fIsLocked = false; 152 } 209 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot release!")); 210 callUnlockOnAllHandles(); 211 m->fIsLocked = false; 153 212 } 154 213 … … 158 217 // 159 218 //////////////////////////////////////////////////////////////////////////////// 160 161 void AutoWriteLock::cleanup()162 {163 if (m->pHandle)164 {165 if (m->cUnlockedInLeave)166 {167 // there was a leave() before the destruction: then restore the168 // lock level that might have been set by locks other than our own169 if (m->fIsLocked)170 --m->cUnlockedInLeave; // no lock for our own171 m->fIsLocked = false;172 for (; m->cUnlockedInLeave; --m->cUnlockedInLeave)173 m->pHandle->lockWrite();174 175 // @todo r=dj is this really desirable behavior? maybe leave/enter should go altogether?176 }177 178 if (m->fIsLocked)179 m->pHandle->unlockWrite();180 }181 }182 219 183 220 /** … … 187 224 * the semaphore in write mode. 188 225 */ 189 /*virtual*/ void AutoWriteLock:: acquireImpl(LockHandle &l)226 /*virtual*/ void AutoWriteLock::callLockImpl(LockHandle &l) 190 227 { 191 228 l.lockWrite(); … … 198 235 * the semaphore in write mode. 199 236 */ 200 /*virtual*/ void AutoWriteLock:: releaseImpl(LockHandle &l)237 /*virtual*/ void AutoWriteLock::callUnlockImpl(LockHandle &l) 201 238 { 202 239 l.unlockWrite(); … … 226 263 void AutoWriteLock::leave() 227 264 { 228 if (m->pHandle) 265 LockHandle *pHandle = m->aHandles[0]; 266 267 if (pHandle) 229 268 { 230 269 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot leave()!")); 231 270 AssertMsg(m->cUnlockedInLeave == 0, ("m->cUnlockedInLeave is %d, must be 0! Called leave() twice?", m->cUnlockedInLeave)); 232 271 233 m->cUnlockedInLeave = m->pHandle->writeLockLevel();272 m->cUnlockedInLeave = pHandle->writeLockLevel(); 234 273 AssertMsg(m->cUnlockedInLeave >= 1, ("m->cUnlockedInLeave is %d, must be >=1!", m->cUnlockedInLeave)); 235 274 236 275 for (uint32_t left = m->cUnlockedInLeave; 237 238 239 m->pHandle->unlockWrite();276 left; 277 --left) 278 pHandle->unlockWrite(); 240 279 } 241 280 } … … 249 288 void AutoWriteLock::enter() 250 289 { 251 if (m->pHandle) 290 LockHandle *pHandle = m->aHandles[0]; 291 292 if (pHandle) 252 293 { 253 294 AssertMsg(m->fIsLocked, ("m->fIsLocked is false, cannot enter()!")); … … 255 296 256 297 for (; m->cUnlockedInLeave; --m->cUnlockedInLeave) 257 m->pHandle->lockWrite();298 pHandle->lockWrite(); 258 299 } 259 300 } … … 271 312 void AutoWriteLock::attach(LockHandle *aHandle) 272 313 { 314 LockHandle *pHandle = m->aHandles[0]; 315 273 316 /* detect simple self-reattachment */ 274 if ( m->pHandle != aHandle)317 if (pHandle != aHandle) 275 318 { 276 319 bool fWasLocked = m->fIsLocked; … … 278 321 cleanup(); 279 322 280 m-> pHandle= aHandle;323 m->aHandles[0] = aHandle; 281 324 m->fIsLocked = fWasLocked; 282 325 283 if ( m->pHandle)326 if (aHandle) 284 327 if (fWasLocked) 285 m->pHandle->lockWrite();328 aHandle->lockWrite(); 286 329 } 287 330 } … … 289 332 void AutoWriteLock::attachRaw(LockHandle *ph) 290 333 { 291 m-> pHandle= ph;334 m->aHandles[0] = ph; 292 335 } 293 336 … … 301 344 bool AutoWriteLock::isWriteLockOnCurrentThread() const 302 345 { 303 return m-> pHandle ? m->pHandle->isWriteLockOnCurrentThread() : false;346 return m->aHandles[0] ? m->aHandles[0]->isWriteLockOnCurrentThread() : false; 304 347 } 305 348 … … 317 360 uint32_t AutoWriteLock::writeLockLevel() const 318 361 { 319 return m-> pHandle ? m->pHandle->writeLockLevel() : 0;362 return m->aHandles[0] ? m->aHandles[0]->writeLockLevel() : 0; 320 363 } 321 364 … … 337 380 /*virtual*/ AutoReadLock::~AutoReadLock() 338 381 { 339 if (m->pHandle) 382 LockHandle *pHandle = m->aHandles[0]; 383 384 if (pHandle) 340 385 { 341 386 if (m->fIsLocked) 342 m->pHandle->unlockRead();387 pHandle->unlockRead(); 343 388 } 344 389 } … … 350 395 * the semaphore in read mode. 351 396 */ 352 /*virtual*/ void AutoReadLock:: acquireImpl(LockHandle &l)397 /*virtual*/ void AutoReadLock::callLockImpl(LockHandle &l) 353 398 { 354 399 l.lockRead(); … … 361 406 * the semaphore in read mode. 362 407 */ 363 /*virtual*/ void AutoReadLock:: releaseImpl(LockHandle &l)408 /*virtual*/ void AutoReadLock::callUnlockImpl(LockHandle &l) 364 409 { 365 410 l.unlockRead(); -
trunk/src/VBox/Main/include/AutoLock.h
r25282 r25283 323 323 Data *m; 324 324 325 virtual void acquireImpl(LockHandle &l) = 0; 326 virtual void releaseImpl(LockHandle &l) = 0; 325 virtual void callLockImpl(LockHandle &l) = 0; 326 virtual void callUnlockImpl(LockHandle &l) = 0; 327 328 void callLockOnAllHandles(); 329 void callUnlockOnAllHandles(); 330 331 void cleanup(); 327 332 328 333 public: … … 412 417 } 413 418 414 void cleanup(); 415 416 virtual void acquireImpl(LockHandle &l); 417 virtual void releaseImpl(LockHandle &l); 419 virtual void callLockImpl(LockHandle &l); 420 virtual void callUnlockImpl(LockHandle &l); 418 421 419 422 void leave(); … … 532 535 virtual ~AutoReadLock(); 533 536 534 virtual void acquireImpl(LockHandle &l);535 virtual void releaseImpl(LockHandle &l);537 virtual void callLockImpl(LockHandle &l); 538 virtual void callUnlockImpl(LockHandle &l); 536 539 }; 537 540
Note:
See TracChangeset
for help on using the changeset viewer.