// File: lock.hpp // // Copyright (c) 2002,2003 // Kevin Atkinson // // Permission to use, copy, modify, distribute and sell this software // and its documentation for any purpose is hereby granted without // fee, provided that the above copyright notice appear in all copies // and that both that copyright notice and this permission notice // appear in supporting documentation. Kevin Atkinson makes no // representations about the suitability of this software for any // purpose. It is provided "as is" without express or implied // warranty. #ifndef DISTRIBNET_LOCK__HPP #define DISTRIBNET_LOCK__HPP #include namespace distribnet { // These lock classes serve three functions: // // 1) The ability to aquire a lock and release it when the object // goes out of scope effectvly implemented the "Monitor" concept. // // 2) Avoid the need for recursive locks by careful and efficient // book keeping with the out the use of global thread specific // data. // // 3) Document and enforce guaranteed lock behavior for functions // which take a lock class as a parameter. // // The global lock used to initialize the lock classes. class Mutex; // The scoped lock classes: class LockOnly; // If the lock is not already aquire it will do so // and then release it at the end of the scope. // It will not release it under any other // circumstances. class Lock; // Will aquire the lock if necessary but may also // release it at any time. Do not call a function // with this type of lock while in an inconsistent // state. class UnlockOnly; // If the lock is already aquired it will be // released and then reaquire at the end of the // scope. If will not aquire a lock under any // other circumstances. class Unlock; // If the lock is it will be released it, however // it may reaquire at any time. Do not call a // function with this type of lock if it is // unexceptable to wait for the lock to be // reaquired. // These locks should never be passed by value to functions. // Instead use the following typedef to pass by reference: typedef const LockOnly & WillOnlyLock; typedef const Lock & WillLock; typedef const UnlockOnly & WillOnlyUnlock; typedef const Unlock & WillUnlock; // The following lock "states" are also provided. When a functions // takes one of these lock states as a parameter it may change the // lock state at any time but then again it might not. class MightLockUnlock; // Might aquire or release the lock or both. typedef MightLockUnlock LockState; // alternate name class MightLock; // Might aquire a lock but will not release it // if the lock is already aquired. class MightUnlock; // Might release the lock but will not aquire one // if the lock is already released. // Lock states may be either passed by const refrence or by value. // The various lock and lock states may be converted between each // other as follows. (All relationships are tranasitive). // <== Lock <=> MightLockUnlock <=> Unlock ==> // MightLock <=> LockOnly UnlockOnly <=> MightLock // Never pass any of the locks or the lock states by non const // refrence as that will mess up the automatic conversion between // the lock types. // All Lock classes and states have a public constructor with the // following parms, (Mutex &, bool locked = false). The first // paramter is the global mutex which must be provided. The second // paramter is the state of the mutex which defaults to unlocked. ////////////////////////////////////////////////////////////////////// // // The implementation // static const pthread_mutex_t MUTEX_INIT = PTHREAD_MUTEX_INITIALIZER; class Mutex { pthread_mutex_t l_; public: Mutex() : l_(MUTEX_INIT) {} void lock() {pthread_mutex_lock(&l_);} void unlock() {pthread_mutex_unlock(&l_);} }; class LockBase; class UnlockBase; class MightBase { friend class LockBase; friend class UnlockBase; protected: Mutex & lock_; const bool locked; inline MightBase(const LockBase &); inline MightBase(const UnlockBase &); public: MightBase(Mutex & l, bool lkd) : lock_(l), locked(lkd) {} }; class MightLockUnlock : public MightBase { public: MightLockUnlock(Mutex & l, bool lkd = false) : MightBase(l, lkd) {} inline MightLockUnlock(const Lock & l); inline MightLockUnlock(const Unlock & l); }; class MightLock : public MightBase { public: MightLock(Mutex & l, bool lkd = false) : MightBase(l, lkd) {} MightLock(const MightLockUnlock & l) : MightBase(l) {} inline MightLock(const LockOnly & l); inline MightLock(const Unlock & l); }; class MightUnlock : public MightBase { public: MightUnlock(Mutex & l, bool lkd = false) : MightBase(l, lkd) {} MightUnlock(const MightLockUnlock & l) : MightBase(l) {} inline MightUnlock(const UnlockOnly &); inline MightUnlock(const Lock &); }; class LockBase { friend class MightBase; private: LockBase(const LockBase &); void operator= (const LockBase &); protected: Mutex & lock_; const bool this_scope; LockBase(Mutex & l, bool lkd = false) : lock_(l), this_scope(!lkd) {if (this_scope) lock_.lock();} LockBase(const MightBase & l) : lock_(l.lock_), this_scope(!l.locked) {if (this_scope) lock_.lock();} ~LockBase() {if (this_scope) lock_.unlock();} }; class LockOnly : public LockBase { public: LockOnly(Mutex & l, bool lkd = false) : LockBase(l, lkd) {} LockOnly(const MightLock & l) : LockBase(l) {} LockOnly(const MightLockUnlock & l) : LockBase (l) {} inline LockOnly(const Unlock &); }; class Lock : public LockOnly { friend class UnlockOnly; public: Lock(Mutex & l, bool lkd = false) : LockOnly(l, lkd) {} Lock(const MightLockUnlock & l) : LockOnly(l) {} Lock(const Unlock & l) : LockOnly(l) {} }; class UnlockBase { friend class MightBase; private: UnlockBase(const UnlockBase &); void operator= (const UnlockBase &); protected: Mutex & lock_; const bool this_scope; UnlockBase(Mutex & l, bool lkd = false) : lock_(l), this_scope(lkd) {if (this_scope) lock_.unlock();} UnlockBase(const MightBase & l) : lock_(l.lock_), this_scope(l.locked) {if (this_scope) lock_.unlock();} ~UnlockBase() {if (this_scope) lock_.lock();} }; class UnlockOnly : public UnlockBase { public: UnlockOnly(Mutex & l, bool lkd = false) : UnlockBase(l, lkd) {} UnlockOnly(const MightUnlock & l) : UnlockBase(l) {} UnlockOnly(const MightLockUnlock & l) : UnlockBase (l) {} inline UnlockOnly(const Lock &); }; class Unlock : public UnlockOnly { friend class LockOnly; public: Unlock(Mutex & l, bool lkd = false) : UnlockOnly(l, lkd) {} Unlock(const MightLockUnlock & l) : UnlockOnly(l) {} Unlock(const Lock & l) : UnlockOnly(l) {} }; inline MightBase::MightBase(const LockBase & l) : lock_(l.lock_), locked(true) {} inline MightBase::MightBase(const UnlockBase & l) : lock_(l.lock_), locked(false) {} inline MightLockUnlock::MightLockUnlock(const Lock & l) : MightBase(l) {} inline MightLockUnlock::MightLockUnlock(const Unlock & l) : MightBase(l) {} inline MightLock::MightLock(const LockOnly & l) : MightBase(l) {} inline MightLock::MightLock(const Unlock & l) : MightBase(l) {} inline MightUnlock::MightUnlock(const UnlockOnly & l) : MightBase(l) {} inline MightUnlock::MightUnlock(const Lock & l) : MightBase(l) {} inline LockOnly::LockOnly(const Unlock & l) : LockBase(l.lock_, false) {} inline UnlockOnly::UnlockOnly(const Lock & l) : UnlockBase(l.lock_, true) {} } #endif