AutoLock.h revision 537e6c27ec01e6914b4668cc2a70e34b6633ad5f
/** @file
*
* Automatic locks, implementation
*/
/*
* Copyright (C) 2006-2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#ifndef ____H_AUTOLOCK
#define ____H_AUTOLOCK
// macros for automatic lock validation; these will amount to nothing
// unless lock validation is enabled for the runtime
#if defined(RT_LOCK_STRICT) && defined (DEBUG)
#define VBOX_WITH_MAIN_LOCK_VALIDATION
# define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS
# define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL
# define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL
# define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS
# define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS
#else
# define COMMA_LOCKVAL_SRC_POS
# define LOCKVAL_SRC_POS_DECL
# define COMMA_LOCKVAL_SRC_POS_DECL
# define LOCKVAL_SRC_POS_ARGS
# define COMMA_LOCKVAL_SRC_POS_ARGS
#endif
{
////////////////////////////////////////////////////////////////////////////////
//
// Order classes for lock validation
//
////////////////////////////////////////////////////////////////////////////////
/**
* IPRT now has a sophisticated system of run-time locking classes to validate
* locking order. Since the Main code is handled by simpler minds, we want
* compile-time constants for simplicity, and we'll look up the run-time classes
* in AutoLock.cpp transparently. These are passed to the constructors of the
* LockHandle classes.
*/
enum VBoxLockingClass
{
LOCKCLASS_NONE = 0,
// (machines list, hard disk tree, shared folders list, ...)
// (e.g. snapshots list in machine object)
// than both OTHEROBJECT and OTHERLIST since the list
// of snapshots in Machine is OTHERLIST)
// too much @todo r=dj get rid of this!
};
void InitAutoLockSystem();
////////////////////////////////////////////////////////////////////////////////
//
// LockHandle and friends
//
////////////////////////////////////////////////////////////////////////////////
/**
* Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle).
* Don't use this directly, but this implements lock validation for them.
*/
{
{}
{}
/**
* Returns @c true if the current thread holds a write lock on this
*/
virtual bool isWriteLockOnCurrentThread() const = 0;
/**
* Returns the current write lock level of this semaphore. The lock level
* determines the number of nested #lock() calls on the given semaphore
* handle.
*
* Note that this call is valid only when the current thread owns a write
* lock on the given semaphore handle and will assert otherwise.
*/
virtual void unlockWrite() = 0;
virtual void unlockRead() = 0;
#endif
// prohibit copy + assignment
LockHandle(const LockHandle&);
};
/**
*
* This is an auxiliary base class for classes that need full-featured
* Instances of classes inherited from this class can be passed as arguments to
* the AutoWriteLock and AutoReadLock constructors.
*/
{
virtual ~RWLockHandle();
virtual bool isWriteLockOnCurrentThread() const;
virtual void unlockWrite();
virtual void unlockRead();
#endif
struct Data;
Data *m;
};
/**
* Write-only semaphore handle implementation.
*
* This is an auxiliary base class for classes that need write-only (exclusive)
* locking and do not need read (shared) locking. This implementation uses a
* cheap and fast critical section for both lockWrite() and lockRead() methods
* which makes a lockRead() call fully equivalent to the lockWrite() call and
* therefore makes it pointless to use instahces of this class with
* AutoReadLock instances -- shared locking will not be possible anyway and
* any call to lock() will block if there are lock owners on other threads.
*
* Use with care only when absolutely sure that shared locks are not necessary.
*/
{
virtual bool isWriteLockOnCurrentThread() const;
virtual void unlockWrite();
virtual void unlockRead();
#endif
struct Data;
Data *m;
};
////////////////////////////////////////////////////////////////////////////////
//
// Lockable
//
////////////////////////////////////////////////////////////////////////////////
/**
* Lockable interface.
*
* class data, this class allows subclasses to decide which semaphore handle to
* use.
*/
{
/**
* Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock
* for locking. Subclasses are allowed to return @c NULL -- in this case,
* the AutoWriteLock/AutoReadLock object constructed using an instance of
* such subclass will simply turn into no-op.
*/
/**
* Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>.
* Returns @c false if lockHandle() returns @c NULL.
*/
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.
*/
{
virtual ~AutoLockBase();
struct Data;
Data *m;
void callLockOnAllHandles();
void callUnlockOnAllHandles();
void cleanup();
void acquire();
void release();
// prohibit copy + assignment
AutoLockBase(const AutoLockBase&);
};
////////////////////////////////////////////////////////////////////////////////
//
// AutoReadLock
//
////////////////////////////////////////////////////////////////////////////////
/**
* 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.
*/
{
/**
* 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.
*/
: AutoLockBase(1,
{ }
/**
* semaphore by requesting a read lock.
*/
: AutoLockBase(1,
{
acquire();
}
/**
* semaphore by requesting a read lock.
*/
: AutoLockBase(1,
{
acquire();
}
/**
* semaphore by requesting a read lock.
*/
: AutoLockBase(1,
{
acquire();
}
/**
* semaphore by requesting a read lock.
*/
: AutoLockBase(1,
{
acquire();
}
virtual ~AutoReadLock();
};
////////////////////////////////////////////////////////////////////////////////
//
// 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.
*/
{
{ }
{ }
{ }
void leave();
void enter();
void maybeLeave();
void maybeEnter();
};
////////////////////////////////////////////////////////////////////////////////
//
// AutoWriteLock
//
////////////////////////////////////////////////////////////////////////////////
/**
* 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.
*/
{
/**
* 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.
*/
: AutoWriteLockBase(1,
{ }
/**
* semaphore by requesting a write lock.
*/
: AutoWriteLockBase(1,
{
acquire();
}
/**
* semaphore by requesting a write lock.
*/
: AutoWriteLockBase(1,
{
acquire();
}
/**
* semaphore by requesting a write lock.
*/
: AutoWriteLockBase(1,
{
acquire();
}
/**
* semaphore by requesting a write lock.
*/
: AutoWriteLockBase(1,
{
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.
*/
{
cleanup();
}
/** @see attach (LockHandle *) */
{
}
/** @see attach (LockHandle *) */
{
}
/** @see attach (LockHandle *) */
{
}
bool isWriteLockOnCurrentThread() const;
uint32_t writeLockLevel() const;
};
////////////////////////////////////////////////////////////////////////////////
//
// AutoMultiWriteLock*
//
////////////////////////////////////////////////////////////////////////////////
/**
* A multi-write-lock containing two other write locks.
*
*/
{
{
cleanup();
}
};
/**
* A multi-write-lock containing three other write locks.
*
*/
{
{
cleanup();
}
};
} /* namespace util */
#endif // ____H_AUTOLOCK
/* vi: set tabstop=4 shiftwidth=4 expandtab: */