[1] | 1 | /** @file
|
---|
[58110] | 2 | * MS COM / XPCOM Abstraction Layer - Automatic locks, implementation.
|
---|
[1] | 3 | */
|
---|
| 4 |
|
---|
| 5 | /*
|
---|
[98103] | 6 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[1] | 7 | *
|
---|
[96407] | 8 | * This file is part of VirtualBox base platform packages, as
|
---|
| 9 | * available from https://www.virtualbox.org.
|
---|
[8155] | 10 | *
|
---|
[96407] | 11 | * This program is free software; you can redistribute it and/or
|
---|
| 12 | * modify it under the terms of the GNU General Public License
|
---|
| 13 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 14 | * License.
|
---|
| 15 | *
|
---|
| 16 | * This program is distributed in the hope that it will be useful, but
|
---|
| 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 19 | * General Public License for more details.
|
---|
| 20 | *
|
---|
| 21 | * You should have received a copy of the GNU General Public License
|
---|
| 22 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 23 | *
|
---|
[25885] | 24 | * The contents of this file may alternatively be used under the terms
|
---|
| 25 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 26 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 27 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[25885] | 28 | * CDDL are applicable instead of those of the GPL.
|
---|
| 29 | *
|
---|
| 30 | * You may elect to license modified versions of this file under the
|
---|
| 31 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 32 | *
|
---|
| 33 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[1] | 34 | */
|
---|
| 35 |
|
---|
[76558] | 36 | #ifndef VBOX_INCLUDED_com_AutoLock_h
|
---|
| 37 | #define VBOX_INCLUDED_com_AutoLock_h
|
---|
[76507] | 38 | #ifndef RT_WITHOUT_PRAGMA_ONCE
|
---|
| 39 | # pragma once
|
---|
| 40 | #endif
|
---|
[1] | 41 |
|
---|
| 42 | #include <iprt/types.h>
|
---|
| 43 |
|
---|
[58110] | 44 |
|
---|
| 45 | /** @defgroup grp_com_autolock Automatic Locks
|
---|
| 46 | * @ingroup grp_com
|
---|
| 47 | * @{
|
---|
| 48 | */
|
---|
| 49 |
|
---|
[25809] | 50 | // macros for automatic lock validation; these will amount to nothing
|
---|
| 51 | // unless lock validation is enabled for the runtime
|
---|
[26746] | 52 | #if defined(RT_LOCK_STRICT)
|
---|
| 53 | # define VBOX_WITH_MAIN_LOCK_VALIDATION
|
---|
[25310] | 54 | # define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS
|
---|
| 55 | # define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL
|
---|
| 56 | # define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL
|
---|
| 57 | # define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS
|
---|
| 58 | # define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS
|
---|
| 59 | #else
|
---|
| 60 | # define COMMA_LOCKVAL_SRC_POS
|
---|
| 61 | # define LOCKVAL_SRC_POS_DECL
|
---|
| 62 | # define COMMA_LOCKVAL_SRC_POS_DECL
|
---|
| 63 | # define LOCKVAL_SRC_POS_ARGS
|
---|
| 64 | # define COMMA_LOCKVAL_SRC_POS_ARGS
|
---|
| 65 | #endif
|
---|
| 66 |
|
---|
[1] | 67 | namespace util
|
---|
| 68 | {
|
---|
| 69 |
|
---|
[25279] | 70 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 71 | //
|
---|
[25809] | 72 | // Order classes for lock validation
|
---|
| 73 | //
|
---|
| 74 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 75 |
|
---|
| 76 | /**
|
---|
| 77 | * IPRT now has a sophisticated system of run-time locking classes to validate
|
---|
| 78 | * locking order. Since the Main code is handled by simpler minds, we want
|
---|
| 79 | * compile-time constants for simplicity, and we'll look up the run-time classes
|
---|
| 80 | * in AutoLock.cpp transparently. These are passed to the constructors of the
|
---|
| 81 | * LockHandle classes.
|
---|
| 82 | */
|
---|
[25834] | 83 | enum VBoxLockingClass
|
---|
[25809] | 84 | {
|
---|
| 85 | LOCKCLASS_NONE = 0,
|
---|
[30501] | 86 | LOCKCLASS_WEBSERVICE = 1, // highest order: webservice locks
|
---|
| 87 | LOCKCLASS_VIRTUALBOXOBJECT = 2, // highest order within Main itself: VirtualBox object lock
|
---|
| 88 | LOCKCLASS_HOSTOBJECT = 3, // Host object lock
|
---|
| 89 | LOCKCLASS_LISTOFMACHINES = 4, // list of machines in VirtualBox object
|
---|
| 90 | LOCKCLASS_MACHINEOBJECT = 5, // Machine object lock
|
---|
| 91 | LOCKCLASS_SNAPSHOTOBJECT = 6, // snapshot object locks
|
---|
[25930] | 92 | // (the snapshots tree, including the child pointers in Snapshot,
|
---|
| 93 | // is protected by the normal Machine object lock)
|
---|
[41528] | 94 | LOCKCLASS_MEDIUMQUERY = 7, // lock used to protect Machine::queryInfo
|
---|
| 95 | LOCKCLASS_LISTOFMEDIA = 8, // list of media (hard disks, DVDs, floppies) in VirtualBox object
|
---|
| 96 | LOCKCLASS_LISTOFOTHEROBJECTS = 9, // any other list of objects
|
---|
[38717] | 97 | LOCKCLASS_OTHEROBJECT = 10, // any regular object member variable lock
|
---|
[41528] | 98 | LOCKCLASS_PROGRESSLIST = 11, // list of progress objects in VirtualBox; no other object lock
|
---|
[25842] | 99 | // may be held after this!
|
---|
[90828] | 100 | LOCKCLASS_OBJECTSTATE = 12, // object state lock (handled by AutoCaller classes)
|
---|
| 101 | LOCKCLASS_TRANSLATOR = 13 // translator internal lock
|
---|
[25809] | 102 | };
|
---|
| 103 |
|
---|
| 104 | void InitAutoLockSystem();
|
---|
| 105 |
|
---|
[28270] | 106 | /**
|
---|
| 107 | * Check whether the current thread holds any locks in the given class
|
---|
| 108 | *
|
---|
| 109 | * @return true if any such locks are held, false otherwise. If the lock
|
---|
| 110 | * validator is not compiled in, always returns false.
|
---|
| 111 | * @param lockClass Which lock class to check.
|
---|
| 112 | */
|
---|
| 113 | bool AutoLockHoldsLocksInClass(VBoxLockingClass lockClass);
|
---|
| 114 |
|
---|
[25809] | 115 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 116 | //
|
---|
[25279] | 117 | // LockHandle and friends
|
---|
| 118 | //
|
---|
| 119 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 120 |
|
---|
[7992] | 121 | /**
|
---|
[25310] | 122 | * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle).
|
---|
[25408] | 123 | * Don't use this directly, but this implements lock validation for them.
|
---|
[7992] | 124 | */
|
---|
[25287] | 125 | class LockHandle
|
---|
[7992] | 126 | {
|
---|
| 127 | public:
|
---|
[25809] | 128 | LockHandle()
|
---|
| 129 | {}
|
---|
[1] | 130 |
|
---|
[25809] | 131 | virtual ~LockHandle()
|
---|
| 132 | {}
|
---|
| 133 |
|
---|
[1] | 134 | /**
|
---|
[7992] | 135 | * Returns @c true if the current thread holds a write lock on this
|
---|
| 136 | * read/write semaphore. Intended for debugging only.
|
---|
[1] | 137 | */
|
---|
[8083] | 138 | virtual bool isWriteLockOnCurrentThread() const = 0;
|
---|
[7992] | 139 |
|
---|
| 140 | /**
|
---|
[67721] | 141 | * Returns @c true if the current thread holds a read lock on this
|
---|
| 142 | * read/write semaphore. Intended for debugging only as it isn't always
|
---|
| 143 | * accurate given @a fWannaHear.
|
---|
| 144 | */
|
---|
| 145 | virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const = 0;
|
---|
| 146 |
|
---|
| 147 | /**
|
---|
[7992] | 148 | * Returns the current write lock level of this semaphore. The lock level
|
---|
[58106] | 149 | * determines the number of nested #lockWrite() calls on the given
|
---|
| 150 | * semaphore handle.
|
---|
[7992] | 151 | *
|
---|
| 152 | * Note that this call is valid only when the current thread owns a write
|
---|
| 153 | * lock on the given semaphore handle and will assert otherwise.
|
---|
| 154 | */
|
---|
| 155 | virtual uint32_t writeLockLevel() const = 0;
|
---|
| 156 |
|
---|
[25408] | 157 | virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0;
|
---|
| 158 | virtual void unlockWrite() = 0;
|
---|
| 159 | virtual void lockRead(LOCKVAL_SRC_POS_DECL) = 0;
|
---|
| 160 | virtual void unlockRead() = 0;
|
---|
| 161 |
|
---|
[25834] | 162 | #ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
|
---|
[25408] | 163 | virtual const char* describe() const = 0;
|
---|
[25310] | 164 | #endif
|
---|
| 165 |
|
---|
[7992] | 166 | private:
|
---|
[25287] | 167 | // prohibit copy + assignment
|
---|
| 168 | LockHandle(const LockHandle&);
|
---|
| 169 | LockHandle& operator=(const LockHandle&);
|
---|
[7992] | 170 | };
|
---|
| 171 |
|
---|
| 172 | /**
|
---|
| 173 | * Full-featured read/write semaphore handle implementation.
|
---|
| 174 | *
|
---|
| 175 | * This is an auxiliary base class for classes that need full-featured
|
---|
[8083] | 176 | * read/write locking as described in the AutoWriteLock class documentation.
|
---|
[7992] | 177 | * Instances of classes inherited from this class can be passed as arguments to
|
---|
[8083] | 178 | * the AutoWriteLock and AutoReadLock constructors.
|
---|
[7992] | 179 | */
|
---|
| 180 | class RWLockHandle : public LockHandle
|
---|
| 181 | {
|
---|
| 182 | public:
|
---|
[25834] | 183 | RWLockHandle(VBoxLockingClass lockClass);
|
---|
[7992] | 184 | virtual ~RWLockHandle();
|
---|
| 185 |
|
---|
[25287] | 186 | virtual bool isWriteLockOnCurrentThread() const;
|
---|
[67721] | 187 | virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const;
|
---|
[7992] | 188 |
|
---|
[25310] | 189 | virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
|
---|
[25287] | 190 | virtual void unlockWrite();
|
---|
[25310] | 191 | virtual void lockRead(LOCKVAL_SRC_POS_DECL);
|
---|
[25287] | 192 | virtual void unlockRead();
|
---|
[7992] | 193 |
|
---|
[25287] | 194 | virtual uint32_t writeLockLevel() const;
|
---|
[7992] | 195 |
|
---|
[25834] | 196 | #ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
|
---|
[25408] | 197 | virtual const char* describe() const;
|
---|
| 198 | #endif
|
---|
| 199 |
|
---|
[25287] | 200 | private:
|
---|
[25288] | 201 | struct Data;
|
---|
| 202 | Data *m;
|
---|
[63147] | 203 |
|
---|
| 204 | DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(RWLockHandle); /* Shuts up MSC warning C4625. */
|
---|
[7992] | 205 | };
|
---|
| 206 |
|
---|
| 207 | /**
|
---|
| 208 | * Write-only semaphore handle implementation.
|
---|
| 209 | *
|
---|
| 210 | * This is an auxiliary base class for classes that need write-only (exclusive)
|
---|
| 211 | * locking and do not need read (shared) locking. This implementation uses a
|
---|
| 212 | * cheap and fast critical section for both lockWrite() and lockRead() methods
|
---|
| 213 | * which makes a lockRead() call fully equivalent to the lockWrite() call and
|
---|
| 214 | * therefore makes it pointless to use instahces of this class with
|
---|
[8083] | 215 | * AutoReadLock instances -- shared locking will not be possible anyway and
|
---|
[7992] | 216 | * any call to lock() will block if there are lock owners on other threads.
|
---|
| 217 | *
|
---|
| 218 | * Use with care only when absolutely sure that shared locks are not necessary.
|
---|
| 219 | */
|
---|
| 220 | class WriteLockHandle : public LockHandle
|
---|
| 221 | {
|
---|
| 222 | public:
|
---|
[25834] | 223 | WriteLockHandle(VBoxLockingClass lockClass);
|
---|
[25287] | 224 | virtual ~WriteLockHandle();
|
---|
| 225 | virtual bool isWriteLockOnCurrentThread() const;
|
---|
[67721] | 226 | virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const;
|
---|
[7992] | 227 |
|
---|
[25310] | 228 | virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
|
---|
[25287] | 229 | virtual void unlockWrite();
|
---|
[25310] | 230 | virtual void lockRead(LOCKVAL_SRC_POS_DECL);
|
---|
[25287] | 231 | virtual void unlockRead();
|
---|
| 232 | virtual uint32_t writeLockLevel() const;
|
---|
[1] | 233 |
|
---|
[25834] | 234 | #ifdef VBOX_WITH_MAIN_LOCK_VALIDATION
|
---|
[25408] | 235 | virtual const char* describe() const;
|
---|
| 236 | #endif
|
---|
| 237 |
|
---|
[7992] | 238 | private:
|
---|
[25288] | 239 | struct Data;
|
---|
| 240 | Data *m;
|
---|
[63147] | 241 |
|
---|
| 242 | DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(WriteLockHandle); /* Shuts up MSC warning C4625. */
|
---|
[7992] | 243 | };
|
---|
[1] | 244 |
|
---|
[25279] | 245 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 246 | //
|
---|
| 247 | // Lockable
|
---|
| 248 | //
|
---|
| 249 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 250 |
|
---|
[7992] | 251 | /**
|
---|
| 252 | * Lockable interface.
|
---|
| 253 | *
|
---|
| 254 | * This is an abstract base for classes that need read/write locking. Unlike
|
---|
| 255 | * RWLockHandle and other classes that makes the read/write semaphore a part of
|
---|
| 256 | * class data, this class allows subclasses to decide which semaphore handle to
|
---|
| 257 | * use.
|
---|
| 258 | */
|
---|
| 259 | class Lockable
|
---|
| 260 | {
|
---|
| 261 | public:
|
---|
[84342] | 262 | virtual ~Lockable() { } /* To make VC++ 2019 happy. */
|
---|
[7992] | 263 |
|
---|
| 264 | /**
|
---|
[8083] | 265 | * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock
|
---|
| 266 | * for locking. Subclasses are allowed to return @c NULL -- in this case,
|
---|
| 267 | * the AutoWriteLock/AutoReadLock object constructed using an instance of
|
---|
[7992] | 268 | * such subclass will simply turn into no-op.
|
---|
| 269 | */
|
---|
| 270 | virtual LockHandle *lockHandle() const = 0;
|
---|
| 271 |
|
---|
| 272 | /**
|
---|
[8083] | 273 | * Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>.
|
---|
[7992] | 274 | * Returns @c false if lockHandle() returns @c NULL.
|
---|
| 275 | */
|
---|
[8083] | 276 | bool isWriteLockOnCurrentThread()
|
---|
[7992] | 277 | {
|
---|
| 278 | LockHandle *h = lockHandle();
|
---|
[8083] | 279 | return h ? h->isWriteLockOnCurrentThread() : false;
|
---|
[7992] | 280 | }
|
---|
[67721] | 281 |
|
---|
| 282 | /**
|
---|
| 283 | * Equivalent to <tt>#lockHandle()->isReadLockedOnCurrentThread()</tt>.
|
---|
| 284 | * Returns @c false if lockHandle() returns @c NULL.
|
---|
| 285 | * @note Use with care, simple debug assertions and similar only.
|
---|
| 286 | */
|
---|
[67722] | 287 | bool isReadLockedOnCurrentThread(bool fWannaHear = true) const
|
---|
[67721] | 288 | {
|
---|
| 289 | LockHandle *h = lockHandle();
|
---|
| 290 | return h ? h->isReadLockedOnCurrentThread(fWannaHear) : false;
|
---|
| 291 | }
|
---|
[7992] | 292 | };
|
---|
| 293 |
|
---|
[25279] | 294 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 295 | //
|
---|
| 296 | // AutoLockBase
|
---|
| 297 | //
|
---|
| 298 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 299 |
|
---|
[25287] | 300 | /**
|
---|
| 301 | * Abstract base class for all autolocks.
|
---|
| 302 | *
|
---|
| 303 | * This cannot be used directly. Use AutoReadLock or AutoWriteLock or AutoMultiWriteLock2/3
|
---|
| 304 | * which directly and indirectly derive from this.
|
---|
| 305 | *
|
---|
| 306 | * In the implementation, the instance data contains a list of lock handles.
|
---|
| 307 | * The class provides some utility functions to help locking and unlocking
|
---|
| 308 | * them.
|
---|
| 309 | */
|
---|
| 310 |
|
---|
[25279] | 311 | class AutoLockBase
|
---|
[7992] | 312 | {
|
---|
[25279] | 313 | protected:
|
---|
[25310] | 314 | AutoLockBase(uint32_t cHandles
|
---|
| 315 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
| 316 | AutoLockBase(uint32_t cHandles,
|
---|
| 317 | LockHandle *pHandle
|
---|
| 318 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
[25281] | 319 | virtual ~AutoLockBase();
|
---|
[25279] | 320 |
|
---|
[25281] | 321 | struct Data;
|
---|
| 322 | Data *m;
|
---|
| 323 |
|
---|
[25283] | 324 | virtual void callLockImpl(LockHandle &l) = 0;
|
---|
| 325 | virtual void callUnlockImpl(LockHandle &l) = 0;
|
---|
[25282] | 326 |
|
---|
[25283] | 327 | void callLockOnAllHandles();
|
---|
| 328 | void callUnlockOnAllHandles();
|
---|
| 329 |
|
---|
| 330 | void cleanup();
|
---|
| 331 |
|
---|
[25282] | 332 | public:
|
---|
| 333 | void acquire();
|
---|
| 334 | void release();
|
---|
| 335 |
|
---|
[25281] | 336 | private:
|
---|
| 337 | // prohibit copy + assignment
|
---|
| 338 | AutoLockBase(const AutoLockBase&);
|
---|
[25287] | 339 | AutoLockBase& operator=(const AutoLockBase&);
|
---|
[25279] | 340 | };
|
---|
| 341 |
|
---|
| 342 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 343 | //
|
---|
[25284] | 344 | // AutoReadLock
|
---|
[25279] | 345 | //
|
---|
| 346 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 347 |
|
---|
[25287] | 348 | /**
|
---|
| 349 | * Automatic read lock. Use this with a RWLockHandle to request a read/write
|
---|
| 350 | * semaphore in read mode. You can also use this with a WriteLockHandle but
|
---|
[25408] | 351 | * that makes little sense since they treat read mode like write mode.
|
---|
[25287] | 352 | *
|
---|
| 353 | * If constructed with a RWLockHandle or an instance of Lockable (which in
|
---|
| 354 | * practice means any VirtualBoxBase derivative), it autoamtically requests
|
---|
| 355 | * the lock in read mode and releases the read lock in the destructor.
|
---|
| 356 | */
|
---|
[25284] | 357 | class AutoReadLock : public AutoLockBase
|
---|
[25279] | 358 | {
|
---|
[7992] | 359 | public:
|
---|
| 360 |
|
---|
| 361 | /**
|
---|
| 362 | * Constructs a null instance that does not manage any read/write
|
---|
| 363 | * semaphore.
|
---|
| 364 | *
|
---|
| 365 | * Note that all method calls on a null instance are no-ops. This allows to
|
---|
| 366 | * have the code where lock protection can be selected (or omitted) at
|
---|
| 367 | * runtime.
|
---|
| 368 | */
|
---|
[25310] | 369 | AutoReadLock(LOCKVAL_SRC_POS_DECL)
|
---|
| 370 | : AutoLockBase(1,
|
---|
| 371 | NULL
|
---|
| 372 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 373 | { }
|
---|
[7992] | 374 |
|
---|
| 375 | /**
|
---|
| 376 | * Constructs a new instance that will start managing the given read/write
|
---|
[25284] | 377 | * semaphore by requesting a read lock.
|
---|
[7992] | 378 | */
|
---|
[25310] | 379 | AutoReadLock(LockHandle *aHandle
|
---|
| 380 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 381 | : AutoLockBase(1,
|
---|
| 382 | aHandle
|
---|
| 383 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 384 | {
|
---|
| 385 | acquire();
|
---|
| 386 | }
|
---|
[7992] | 387 |
|
---|
| 388 | /**
|
---|
| 389 | * Constructs a new instance that will start managing the given read/write
|
---|
[25284] | 390 | * semaphore by requesting a read lock.
|
---|
[7992] | 391 | */
|
---|
[25310] | 392 | AutoReadLock(LockHandle &aHandle
|
---|
| 393 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 394 | : AutoLockBase(1,
|
---|
| 395 | &aHandle
|
---|
| 396 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 397 | {
|
---|
| 398 | acquire();
|
---|
| 399 | }
|
---|
[7992] | 400 |
|
---|
| 401 | /**
|
---|
| 402 | * Constructs a new instance that will start managing the given read/write
|
---|
[25284] | 403 | * semaphore by requesting a read lock.
|
---|
[7992] | 404 | */
|
---|
[25310] | 405 | AutoReadLock(const Lockable &aLockable
|
---|
| 406 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 407 | : AutoLockBase(1,
|
---|
| 408 | aLockable.lockHandle()
|
---|
| 409 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 410 | {
|
---|
| 411 | acquire();
|
---|
| 412 | }
|
---|
[1] | 413 |
|
---|
[7992] | 414 | /**
|
---|
| 415 | * Constructs a new instance that will start managing the given read/write
|
---|
[25284] | 416 | * semaphore by requesting a read lock.
|
---|
[7992] | 417 | */
|
---|
[25310] | 418 | AutoReadLock(const Lockable *aLockable
|
---|
| 419 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 420 | : AutoLockBase(1,
|
---|
| 421 | aLockable ? aLockable->lockHandle() : NULL
|
---|
| 422 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 423 | {
|
---|
| 424 | acquire();
|
---|
| 425 | }
|
---|
[1] | 426 |
|
---|
[25284] | 427 | virtual ~AutoReadLock();
|
---|
[25280] | 428 |
|
---|
[25283] | 429 | virtual void callLockImpl(LockHandle &l);
|
---|
| 430 | virtual void callUnlockImpl(LockHandle &l);
|
---|
[63147] | 431 |
|
---|
| 432 | private:
|
---|
| 433 | DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReadLock); /* Shuts up MSC warning C4625. */
|
---|
[25284] | 434 | };
|
---|
[25280] | 435 |
|
---|
[25284] | 436 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 437 | //
|
---|
| 438 | // AutoWriteLockBase
|
---|
| 439 | //
|
---|
| 440 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 441 |
|
---|
[25287] | 442 | /**
|
---|
| 443 | * Base class for all auto write locks.
|
---|
| 444 | *
|
---|
| 445 | * This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3
|
---|
[25408] | 446 | * which derive from this.
|
---|
[25287] | 447 | *
|
---|
[40257] | 448 | * It has some utility methods for subclasses.
|
---|
[25287] | 449 | */
|
---|
[25284] | 450 | class AutoWriteLockBase : public AutoLockBase
|
---|
| 451 | {
|
---|
| 452 | protected:
|
---|
[25310] | 453 | AutoWriteLockBase(uint32_t cHandles
|
---|
| 454 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 455 | : AutoLockBase(cHandles
|
---|
| 456 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25284] | 457 | { }
|
---|
| 458 |
|
---|
[25310] | 459 | AutoWriteLockBase(uint32_t cHandles,
|
---|
| 460 | LockHandle *pHandle
|
---|
| 461 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 462 | : AutoLockBase(cHandles,
|
---|
| 463 | pHandle
|
---|
| 464 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25285] | 465 | { }
|
---|
| 466 |
|
---|
[25284] | 467 | virtual ~AutoWriteLockBase()
|
---|
| 468 | { }
|
---|
| 469 |
|
---|
| 470 | virtual void callLockImpl(LockHandle &l);
|
---|
| 471 | virtual void callUnlockImpl(LockHandle &l);
|
---|
[63147] | 472 |
|
---|
| 473 | private:
|
---|
| 474 | DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoWriteLockBase); /* Shuts up MSC warning C4625. */
|
---|
[7992] | 475 | };
|
---|
| 476 |
|
---|
| 477 | ////////////////////////////////////////////////////////////////////////////////
|
---|
[25279] | 478 | //
|
---|
[25284] | 479 | // AutoWriteLock
|
---|
[25279] | 480 | //
|
---|
| 481 | ////////////////////////////////////////////////////////////////////////////////
|
---|
[7992] | 482 |
|
---|
[25287] | 483 | /**
|
---|
| 484 | * Automatic write lock. Use this with a RWLockHandle to request a read/write
|
---|
| 485 | * semaphore in write mode. There can only ever be one writer of a read/write
|
---|
| 486 | * semaphore: while the lock is held in write mode, no other writer or reader
|
---|
| 487 | * can request the semaphore and will block.
|
---|
| 488 | *
|
---|
| 489 | * If constructed with a RWLockHandle or an instance of Lockable (which in
|
---|
| 490 | * practice means any VirtualBoxBase derivative), it autoamtically requests
|
---|
| 491 | * the lock in write mode and releases the write lock in the destructor.
|
---|
| 492 | *
|
---|
| 493 | * When used with a WriteLockHandle, it requests the semaphore contained therein
|
---|
| 494 | * exclusively.
|
---|
| 495 | */
|
---|
[25284] | 496 | class AutoWriteLock : public AutoWriteLockBase
|
---|
[7992] | 497 | {
|
---|
| 498 | public:
|
---|
| 499 |
|
---|
[3329] | 500 | /**
|
---|
[7992] | 501 | * Constructs a null instance that does not manage any read/write
|
---|
| 502 | * semaphore.
|
---|
| 503 | *
|
---|
| 504 | * Note that all method calls on a null instance are no-ops. This allows to
|
---|
| 505 | * have the code where lock protection can be selected (or omitted) at
|
---|
| 506 | * runtime.
|
---|
[3329] | 507 | */
|
---|
[25310] | 508 | AutoWriteLock(LOCKVAL_SRC_POS_DECL)
|
---|
| 509 | : AutoWriteLockBase(1,
|
---|
| 510 | NULL
|
---|
| 511 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 512 | { }
|
---|
[3329] | 513 |
|
---|
| 514 | /**
|
---|
[7992] | 515 | * Constructs a new instance that will start managing the given read/write
|
---|
[25284] | 516 | * semaphore by requesting a write lock.
|
---|
[3329] | 517 | */
|
---|
[25310] | 518 | AutoWriteLock(LockHandle *aHandle
|
---|
| 519 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 520 | : AutoWriteLockBase(1,
|
---|
| 521 | aHandle
|
---|
| 522 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 523 | {
|
---|
| 524 | acquire();
|
---|
| 525 | }
|
---|
[3329] | 526 |
|
---|
[7992] | 527 | /**
|
---|
| 528 | * Constructs a new instance that will start managing the given read/write
|
---|
[25284] | 529 | * semaphore by requesting a write lock.
|
---|
[7992] | 530 | */
|
---|
[25310] | 531 | AutoWriteLock(LockHandle &aHandle
|
---|
| 532 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 533 | : AutoWriteLockBase(1,
|
---|
| 534 | &aHandle
|
---|
| 535 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 536 | {
|
---|
| 537 | acquire();
|
---|
| 538 | }
|
---|
[1] | 539 |
|
---|
[7992] | 540 | /**
|
---|
| 541 | * Constructs a new instance that will start managing the given read/write
|
---|
[25284] | 542 | * semaphore by requesting a write lock.
|
---|
[7992] | 543 | */
|
---|
[25310] | 544 | AutoWriteLock(const Lockable &aLockable
|
---|
| 545 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 546 | : AutoWriteLockBase(1,
|
---|
| 547 | aLockable.lockHandle()
|
---|
| 548 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 549 | {
|
---|
| 550 | acquire();
|
---|
| 551 | }
|
---|
[1] | 552 |
|
---|
[7992] | 553 | /**
|
---|
| 554 | * Constructs a new instance that will start managing the given read/write
|
---|
[25284] | 555 | * semaphore by requesting a write lock.
|
---|
[7992] | 556 | */
|
---|
[25310] | 557 | AutoWriteLock(const Lockable *aLockable
|
---|
| 558 | COMMA_LOCKVAL_SRC_POS_DECL)
|
---|
| 559 | : AutoWriteLockBase(1,
|
---|
| 560 | aLockable ? aLockable->lockHandle() : NULL
|
---|
| 561 | COMMA_LOCKVAL_SRC_POS_ARGS)
|
---|
[25279] | 562 | {
|
---|
| 563 | acquire();
|
---|
| 564 | }
|
---|
[7992] | 565 |
|
---|
[25284] | 566 | /**
|
---|
[38773] | 567 | * Constructs a new instance that will start managing the given read/write
|
---|
| 568 | * semaphore by requesting a write lock.
|
---|
| 569 | */
|
---|
| 570 | AutoWriteLock(uint32_t cHandles,
|
---|
| 571 | LockHandle** pHandles
|
---|
| 572 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
| 573 |
|
---|
| 574 | /**
|
---|
[58106] | 575 | * Release all write locks acquired by this instance through the #acquire()
|
---|
[25284] | 576 | * call and destroys the instance.
|
---|
| 577 | *
|
---|
[58106] | 578 | * Note that if there there are nested #acquire() calls without the
|
---|
| 579 | * corresponding number of #release() calls when the destructor is called, it
|
---|
[25284] | 580 | * will assert. This is because having an unbalanced number of nested locks
|
---|
| 581 | * is a program logic error which must be fixed.
|
---|
| 582 | */
|
---|
| 583 | virtual ~AutoWriteLock()
|
---|
| 584 | {
|
---|
| 585 | cleanup();
|
---|
| 586 | }
|
---|
[1] | 587 |
|
---|
[25284] | 588 | void attach(LockHandle *aHandle);
|
---|
| 589 |
|
---|
| 590 | /** @see attach (LockHandle *) */
|
---|
| 591 | void attach(LockHandle &aHandle)
|
---|
| 592 | {
|
---|
| 593 | attach(&aHandle);
|
---|
| 594 | }
|
---|
| 595 |
|
---|
| 596 | /** @see attach (LockHandle *) */
|
---|
| 597 | void attach(const Lockable &aLockable)
|
---|
| 598 | {
|
---|
| 599 | attach(aLockable.lockHandle());
|
---|
| 600 | }
|
---|
| 601 |
|
---|
| 602 | /** @see attach (LockHandle *) */
|
---|
| 603 | void attach(const Lockable *aLockable)
|
---|
| 604 | {
|
---|
| 605 | attach(aLockable ? aLockable->lockHandle() : NULL);
|
---|
| 606 | }
|
---|
| 607 |
|
---|
[25285] | 608 | bool isWriteLockOnCurrentThread() const;
|
---|
| 609 | uint32_t writeLockLevel() const;
|
---|
[63147] | 610 |
|
---|
[67721] | 611 | bool isReadLockedOnCurrentThread(bool fWannaHear = true) const;
|
---|
| 612 |
|
---|
[63147] | 613 | private:
|
---|
| 614 | DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoWriteLock); /* Shuts up MSC warning C4625. */
|
---|
[1] | 615 | };
|
---|
| 616 |
|
---|
[7992] | 617 | ////////////////////////////////////////////////////////////////////////////////
|
---|
[25279] | 618 | //
|
---|
[25285] | 619 | // AutoMultiWriteLock*
|
---|
| 620 | //
|
---|
| 621 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 622 |
|
---|
[25287] | 623 | /**
|
---|
| 624 | * A multi-write-lock containing two other write locks.
|
---|
| 625 | *
|
---|
| 626 | */
|
---|
[25285] | 627 | class AutoMultiWriteLock2 : public AutoWriteLockBase
|
---|
| 628 | {
|
---|
| 629 | public:
|
---|
[25310] | 630 | AutoMultiWriteLock2(Lockable *pl1,
|
---|
| 631 | Lockable *pl2
|
---|
| 632 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
| 633 | AutoMultiWriteLock2(LockHandle *pl1,
|
---|
| 634 | LockHandle *pl2
|
---|
| 635 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
[25285] | 636 |
|
---|
| 637 | virtual ~AutoMultiWriteLock2()
|
---|
| 638 | {
|
---|
| 639 | cleanup();
|
---|
| 640 | }
|
---|
[63147] | 641 |
|
---|
| 642 | private:
|
---|
| 643 | DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock2); /* Shuts up MSC warning C4625. */
|
---|
[25285] | 644 | };
|
---|
| 645 |
|
---|
[25287] | 646 | /**
|
---|
| 647 | * A multi-write-lock containing three other write locks.
|
---|
| 648 | *
|
---|
| 649 | */
|
---|
[25285] | 650 | class AutoMultiWriteLock3 : public AutoWriteLockBase
|
---|
| 651 | {
|
---|
| 652 | public:
|
---|
[25310] | 653 | AutoMultiWriteLock3(Lockable *pl1,
|
---|
| 654 | Lockable *pl2,
|
---|
| 655 | Lockable *pl3
|
---|
| 656 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
| 657 | AutoMultiWriteLock3(LockHandle *pl1,
|
---|
| 658 | LockHandle *pl2,
|
---|
| 659 | LockHandle *pl3
|
---|
| 660 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
[25285] | 661 |
|
---|
| 662 | virtual ~AutoMultiWriteLock3()
|
---|
| 663 | {
|
---|
| 664 | cleanup();
|
---|
| 665 | }
|
---|
[63147] | 666 |
|
---|
| 667 | private:
|
---|
| 668 | DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock3); /* Shuts up MSC warning C4625. */
|
---|
[25285] | 669 | };
|
---|
| 670 |
|
---|
[38743] | 671 | /**
|
---|
| 672 | * A multi-write-lock containing four other write locks.
|
---|
| 673 | *
|
---|
| 674 | */
|
---|
| 675 | class AutoMultiWriteLock4 : public AutoWriteLockBase
|
---|
| 676 | {
|
---|
| 677 | public:
|
---|
| 678 | AutoMultiWriteLock4(Lockable *pl1,
|
---|
| 679 | Lockable *pl2,
|
---|
| 680 | Lockable *pl3,
|
---|
| 681 | Lockable *pl4
|
---|
| 682 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
| 683 | AutoMultiWriteLock4(LockHandle *pl1,
|
---|
| 684 | LockHandle *pl2,
|
---|
| 685 | LockHandle *pl3,
|
---|
| 686 | LockHandle *pl4
|
---|
| 687 | COMMA_LOCKVAL_SRC_POS_DECL);
|
---|
| 688 |
|
---|
| 689 | virtual ~AutoMultiWriteLock4()
|
---|
| 690 | {
|
---|
| 691 | cleanup();
|
---|
| 692 | }
|
---|
[63147] | 693 |
|
---|
| 694 | private:
|
---|
| 695 | DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock4); /* Shuts up MSC warning C4625. */
|
---|
[38743] | 696 | };
|
---|
| 697 |
|
---|
[5658] | 698 | } /* namespace util */
|
---|
[1] | 699 |
|
---|
[58110] | 700 | /** @} */
|
---|
| 701 |
|
---|
[76585] | 702 | #endif /* !VBOX_INCLUDED_com_AutoLock_h */
|
---|
[1] | 703 |
|
---|
[14949] | 704 | /* vi: set tabstop=4 shiftwidth=4 expandtab: */
|
---|