AutoLock.h revision 4b9e6f4eb96b548b326de392cbca2efbb1688e85
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync/** @file
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync *
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Automatic locks, implementation
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync/*
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Copyright (C) 2006-2009 Sun Microsystems, Inc.
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync *
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * available from http://www.virtualbox.org. This file is free software;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * you can redistribute it and/or modify it under the terms of the GNU
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * General Public License (GPL) as published by the Free Software
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync *
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * additional information or have any questions.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#ifndef ____H_AUTOLOCK
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#define ____H_AUTOLOCK
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync#include <iprt/types.h>
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync// macros for automatic lock validation; these will amount to nothing
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync// unless lock validation is enabled for the runtime
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#if defined(RT_LOCK_STRICT)
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#else
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define COMMA_LOCKVAL_SRC_POS
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define LOCKVAL_SRC_POS_DECL
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define COMMA_LOCKVAL_SRC_POS_DECL
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync# define LOCKVAL_SRC_POS_ARGS
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync# define COMMA_LOCKVAL_SRC_POS_ARGS
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#endif
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncnamespace util
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync{
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync////////////////////////////////////////////////////////////////////////////////
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync//
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync// Order classes for lock validation
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync//
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync////////////////////////////////////////////////////////////////////////////////
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync/**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * IPRT now has a sophisticated system of run-time locking classes to validate
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * locking order. Since the Main code is handled by simpler minds, we want
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * compile-time constants for simplicity, and we'll look up the run-time classes
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync * in AutoLock.cpp transparently. These are passed to the constructors of the
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync * LockHandle classes.
9040f019271f91b98e1320c0a8c38a42636e3979vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncenum MainLockValidationClasses
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync{
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync LOCKCLASS_NONE = 0,
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync LOCKCLASS_VIRTUALBOXOBJECT = 1, // highest order: VirtualBox object lock
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync LOCKCLASS_VIRTUALBOXLIST = 2, // lock protecting a list in VirtualBox object
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync // (machines list, hard disk tree, shared folders list, ...)
99be02f9e15a3ca61b6a7c207cc7eb68dbd04817vboxsync LOCKCLASS_OTHERLIST = 3, // lock protecting a list that's elsewhere
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync // (e.g. snapshots list in machine object)
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync LOCKCLASS_OBJECT = 4, // any regular object member variable lock
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync LOCKCLASS_OBJECTSTATE = 5 // object state lock (handled by AutoCaller classes)
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync};
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncvoid InitAutoLockSystem();
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync////////////////////////////////////////////////////////////////////////////////
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync//
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync// LockHandle and friends
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync//
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync////////////////////////////////////////////////////////////////////////////////
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync/**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle).
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Don't use this directly, but this implements lock validation for them.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncclass LockHandle
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync{
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncpublic:
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync LockHandle()
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync {}
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual ~LockHandle()
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync {}
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync /**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Returns @c true if the current thread holds a write lock on this
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * read/write semaphore. Intended for debugging only.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual bool isWriteLockOnCurrentThread() const = 0;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
6c90795355c6e59ba82e8e5a58e10d686a6d6e65vboxsync /**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Returns the current write lock level of this semaphore. The lock level
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * determines the number of nested #lock() calls on the given semaphore
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * handle.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync *
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Note that this call is valid only when the current thread owns a write
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * lock on the given semaphore handle and will assert otherwise.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual uint32_t writeLockLevel() const = 0;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void unlockWrite() = 0;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void lockRead(LOCKVAL_SRC_POS_DECL) = 0;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void unlockRead() = 0;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#ifdef RT_LOCK_STRICT
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual const char* describe() const = 0;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#endif
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncprivate:
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync // prohibit copy + assignment
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync LockHandle(const LockHandle&);
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync LockHandle& operator=(const LockHandle&);
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync};
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync/**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Full-featured read/write semaphore handle implementation.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync *
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * This is an auxiliary base class for classes that need full-featured
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * read/write locking as described in the AutoWriteLock class documentation.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Instances of classes inherited from this class can be passed as arguments to
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * the AutoWriteLock and AutoReadLock constructors.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncclass RWLockHandle : public LockHandle
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync{
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncpublic:
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync RWLockHandle(MainLockValidationClasses lockClass);
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual ~RWLockHandle();
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual bool isWriteLockOnCurrentThread() const;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void unlockWrite();
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void lockRead(LOCKVAL_SRC_POS_DECL);
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void unlockRead();
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual uint32_t writeLockLevel() const;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#ifdef RT_LOCK_STRICT
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual const char* describe() const;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#endif
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncprivate:
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync struct Data;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync Data *m;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync};
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync/**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Write-only semaphore handle implementation.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync *
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * This is an auxiliary base class for classes that need write-only (exclusive)
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync * locking and do not need read (shared) locking. This implementation uses a
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * cheap and fast critical section for both lockWrite() and lockRead() methods
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * which makes a lockRead() call fully equivalent to the lockWrite() call and
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * therefore makes it pointless to use instahces of this class with
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * AutoReadLock instances -- shared locking will not be possible anyway and
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * any call to lock() will block if there are lock owners on other threads.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync *
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Use with care only when absolutely sure that shared locks are not necessary.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncclass WriteLockHandle : public LockHandle
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync{
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncpublic:
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync WriteLockHandle(MainLockValidationClasses lockClass);
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual ~WriteLockHandle();
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual bool isWriteLockOnCurrentThread() const;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void lockWrite(LOCKVAL_SRC_POS_DECL);
88e9d91abf9293ecc1c70e0bf40e42f1c3a0bdcevboxsync virtual void unlockWrite();
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void lockRead(LOCKVAL_SRC_POS_DECL);
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual void unlockRead();
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual uint32_t writeLockLevel() const;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#ifdef RT_LOCK_STRICT
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual const char* describe() const;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync#endif
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncprivate:
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync struct Data;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync Data *m;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync};
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync////////////////////////////////////////////////////////////////////////////////
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync//
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync// Lockable
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync//
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync////////////////////////////////////////////////////////////////////////////////
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync/**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Lockable interface.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync *
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * This is an abstract base for classes that need read/write locking. Unlike
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * RWLockHandle and other classes that makes the read/write semaphore a part of
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * class data, this class allows subclasses to decide which semaphore handle to
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * use.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncclass Lockable
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync{
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsyncpublic:
6831f283dbc5c27bde8a8f8bea179b84a5741697vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync /**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * for locking. Subclasses are allowed to return @c NULL -- in this case,
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * the AutoWriteLock/AutoReadLock object constructed using an instance of
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * such subclass will simply turn into no-op.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync virtual LockHandle *lockHandle() const = 0;
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync /**
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync * Returns @c false if lockHandle() returns @c NULL.
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync */
c1f5ec452b23d55c71e6f07628b84ac5e97cf551vboxsync bool isWriteLockOnCurrentThread()
{
LockHandle *h = lockHandle();
return h ? h->isWriteLockOnCurrentThread() : false;
}
};
////////////////////////////////////////////////////////////////////////////////
//
// AutoLockBase
//
////////////////////////////////////////////////////////////////////////////////
/**
* Abstract base class for all autolocks.
*
* This cannot be used directly. Use AutoReadLock or AutoWriteLock or AutoMultiWriteLock2/3
* which directly and indirectly derive from this.
*
* In the implementation, the instance data contains a list of lock handles.
* The class provides some utility functions to help locking and unlocking
* them.
*/
class AutoLockBase
{
protected:
AutoLockBase(uint32_t cHandles
COMMA_LOCKVAL_SRC_POS_DECL);
AutoLockBase(uint32_t cHandles,
LockHandle *pHandle
COMMA_LOCKVAL_SRC_POS_DECL);
virtual ~AutoLockBase();
struct Data;
Data *m;
virtual void callLockImpl(LockHandle &l) = 0;
virtual void callUnlockImpl(LockHandle &l) = 0;
void callLockOnAllHandles();
void callUnlockOnAllHandles();
void cleanup();
public:
void acquire();
void release();
private:
// prohibit copy + assignment
AutoLockBase(const AutoLockBase&);
AutoLockBase& operator=(const AutoLockBase&);
};
////////////////////////////////////////////////////////////////////////////////
//
// AutoReadLock
//
////////////////////////////////////////////////////////////////////////////////
/**
* Automatic read lock. Use this with a RWLockHandle to request a read/write
* semaphore in read mode. You can also use this with a WriteLockHandle but
* that makes little sense since they treat read mode like write mode.
*
* If constructed with a RWLockHandle or an instance of Lockable (which in
* practice means any VirtualBoxBase derivative), it autoamtically requests
* the lock in read mode and releases the read lock in the destructor.
*/
class AutoReadLock : public AutoLockBase
{
public:
/**
* Constructs a null instance that does not manage any read/write
* semaphore.
*
* Note that all method calls on a null instance are no-ops. This allows to
* have the code where lock protection can be selected (or omitted) at
* runtime.
*/
AutoReadLock(LOCKVAL_SRC_POS_DECL)
: AutoLockBase(1,
NULL
COMMA_LOCKVAL_SRC_POS_ARGS)
{ }
/**
* Constructs a new instance that will start managing the given read/write
* semaphore by requesting a read lock.
*/
AutoReadLock(LockHandle *aHandle
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoLockBase(1,
aHandle
COMMA_LOCKVAL_SRC_POS_ARGS)
{
acquire();
}
/**
* Constructs a new instance that will start managing the given read/write
* semaphore by requesting a read lock.
*/
AutoReadLock(LockHandle &aHandle
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoLockBase(1,
&aHandle
COMMA_LOCKVAL_SRC_POS_ARGS)
{
acquire();
}
/**
* Constructs a new instance that will start managing the given read/write
* semaphore by requesting a read lock.
*/
AutoReadLock(const Lockable &aLockable
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoLockBase(1,
aLockable.lockHandle()
COMMA_LOCKVAL_SRC_POS_ARGS)
{
acquire();
}
/**
* Constructs a new instance that will start managing the given read/write
* semaphore by requesting a read lock.
*/
AutoReadLock(const Lockable *aLockable
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoLockBase(1,
aLockable ? aLockable->lockHandle() : NULL
COMMA_LOCKVAL_SRC_POS_ARGS)
{
acquire();
}
virtual ~AutoReadLock();
virtual void callLockImpl(LockHandle &l);
virtual void callUnlockImpl(LockHandle &l);
};
////////////////////////////////////////////////////////////////////////////////
//
// AutoWriteLockBase
//
////////////////////////////////////////////////////////////////////////////////
/**
* Base class for all auto write locks.
*
* This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3
* which derive from this.
*
* In addition to utility methods for subclasses, this implements the public
* leave/enter/maybeLeave/maybeEnter methods, which are common to all
* write locks.
*/
class AutoWriteLockBase : public AutoLockBase
{
protected:
AutoWriteLockBase(uint32_t cHandles
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoLockBase(cHandles
COMMA_LOCKVAL_SRC_POS_ARGS)
{ }
AutoWriteLockBase(uint32_t cHandles,
LockHandle *pHandle
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoLockBase(cHandles,
pHandle
COMMA_LOCKVAL_SRC_POS_ARGS)
{ }
virtual ~AutoWriteLockBase()
{ }
virtual void callLockImpl(LockHandle &l);
virtual void callUnlockImpl(LockHandle &l);
public:
void leave();
void enter();
void maybeLeave();
void maybeEnter();
};
////////////////////////////////////////////////////////////////////////////////
//
// AutoWriteLock
//
////////////////////////////////////////////////////////////////////////////////
/**
* Automatic write lock. Use this with a RWLockHandle to request a read/write
* semaphore in write mode. There can only ever be one writer of a read/write
* semaphore: while the lock is held in write mode, no other writer or reader
* can request the semaphore and will block.
*
* If constructed with a RWLockHandle or an instance of Lockable (which in
* practice means any VirtualBoxBase derivative), it autoamtically requests
* the lock in write mode and releases the write lock in the destructor.
*
* When used with a WriteLockHandle, it requests the semaphore contained therein
* exclusively.
*/
class AutoWriteLock : public AutoWriteLockBase
{
public:
/**
* Constructs a null instance that does not manage any read/write
* semaphore.
*
* Note that all method calls on a null instance are no-ops. This allows to
* have the code where lock protection can be selected (or omitted) at
* runtime.
*/
AutoWriteLock(LOCKVAL_SRC_POS_DECL)
: AutoWriteLockBase(1,
NULL
COMMA_LOCKVAL_SRC_POS_ARGS)
{ }
/**
* Constructs a new instance that will start managing the given read/write
* semaphore by requesting a write lock.
*/
AutoWriteLock(LockHandle *aHandle
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoWriteLockBase(1,
aHandle
COMMA_LOCKVAL_SRC_POS_ARGS)
{
acquire();
}
/**
* Constructs a new instance that will start managing the given read/write
* semaphore by requesting a write lock.
*/
AutoWriteLock(LockHandle &aHandle
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoWriteLockBase(1,
&aHandle
COMMA_LOCKVAL_SRC_POS_ARGS)
{
acquire();
}
/**
* Constructs a new instance that will start managing the given read/write
* semaphore by requesting a write lock.
*/
AutoWriteLock(const Lockable &aLockable
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoWriteLockBase(1,
aLockable.lockHandle()
COMMA_LOCKVAL_SRC_POS_ARGS)
{
acquire();
}
/**
* Constructs a new instance that will start managing the given read/write
* semaphore by requesting a write lock.
*/
AutoWriteLock(const Lockable *aLockable
COMMA_LOCKVAL_SRC_POS_DECL)
: AutoWriteLockBase(1,
aLockable ? aLockable->lockHandle() : NULL
COMMA_LOCKVAL_SRC_POS_ARGS)
{
acquire();
}
/**
* Release all write locks acquired by this instance through the #lock()
* call and destroys the instance.
*
* Note that if there there are nested #lock() calls without the
* corresponding number of #unlock() calls when the destructor is called, it
* will assert. This is because having an unbalanced number of nested locks
* is a program logic error which must be fixed.
*/
virtual ~AutoWriteLock()
{
cleanup();
}
void attach(LockHandle *aHandle);
/** @see attach (LockHandle *) */
void attach(LockHandle &aHandle)
{
attach(&aHandle);
}
/** @see attach (LockHandle *) */
void attach(const Lockable &aLockable)
{
attach(aLockable.lockHandle());
}
/** @see attach (LockHandle *) */
void attach(const Lockable *aLockable)
{
attach(aLockable ? aLockable->lockHandle() : NULL);
}
bool isWriteLockOnCurrentThread() const;
uint32_t writeLockLevel() const;
};
////////////////////////////////////////////////////////////////////////////////
//
// AutoMultiWriteLock*
//
////////////////////////////////////////////////////////////////////////////////
/**
* A multi-write-lock containing two other write locks.
*
*/
class AutoMultiWriteLock2 : public AutoWriteLockBase
{
public:
AutoMultiWriteLock2(Lockable *pl1,
Lockable *pl2
COMMA_LOCKVAL_SRC_POS_DECL);
AutoMultiWriteLock2(LockHandle *pl1,
LockHandle *pl2
COMMA_LOCKVAL_SRC_POS_DECL);
virtual ~AutoMultiWriteLock2()
{
cleanup();
}
};
/**
* A multi-write-lock containing three other write locks.
*
*/
class AutoMultiWriteLock3 : public AutoWriteLockBase
{
public:
AutoMultiWriteLock3(Lockable *pl1,
Lockable *pl2,
Lockable *pl3
COMMA_LOCKVAL_SRC_POS_DECL);
AutoMultiWriteLock3(LockHandle *pl1,
LockHandle *pl2,
LockHandle *pl3
COMMA_LOCKVAL_SRC_POS_DECL);
virtual ~AutoMultiWriteLock3()
{
cleanup();
}
};
} /* namespace util */
#endif // ____H_AUTOLOCK
/* vi: set tabstop=4 shiftwidth=4 expandtab: */