mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 19:37:03 +00:00
511 lines
12 KiB
C++
511 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2005, Eric Crahen
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is furnished
|
|
* to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#ifndef __ZTGUARD_H__
|
|
#define __ZTGUARD_H__
|
|
|
|
#include "zthread/NonCopyable.h"
|
|
#include "zthread/Exceptions.h"
|
|
|
|
namespace ZThread {
|
|
|
|
//
|
|
// GuardLockingPolicyContract {
|
|
//
|
|
// createScope(lock_type&)
|
|
// bool createScope(lock_type&, unsigned long)
|
|
// destroyScope(lock_type&)
|
|
//
|
|
// }
|
|
//
|
|
|
|
/**
|
|
* @class LockHolder
|
|
* @author Eric Crahen <http://www.code-foo.com>
|
|
* @date <2003-07-16T17:55:42-0400>
|
|
* @version 2.2.0
|
|
*
|
|
* This is a simple base class for Guards class. It allows Guards
|
|
* that have compatible targets to refer to each others targets
|
|
* allowing for the construction of Guards that share the same lock
|
|
* but have different locking policies.
|
|
*/
|
|
template <class LockType>
|
|
class LockHolder {
|
|
|
|
LockType &_lock;
|
|
bool _enabled;
|
|
|
|
public:
|
|
|
|
template <class T>
|
|
LockHolder(T& t) : _lock(extract(t)._lock), _enabled(true) { }
|
|
|
|
LockHolder(LockHolder& holder) : _lock(holder._lock), _enabled(true) { }
|
|
|
|
LockHolder(LockType& lock) : _lock(lock), _enabled(true) { }
|
|
|
|
void disable() {
|
|
_enabled = false;
|
|
}
|
|
|
|
bool isDisabled() {
|
|
return !_enabled;
|
|
}
|
|
|
|
LockType& getLock() {
|
|
return _lock;
|
|
}
|
|
|
|
protected:
|
|
|
|
template <class T>
|
|
static LockHolder& extract(T& t) {
|
|
// Design and Evolution of C++, page 328
|
|
return (LockHolder&)(t);
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* @class CompoundScope
|
|
* @author Eric Crahen <http://www.code-foo.com>
|
|
* @date <2003-07-16T17:55:42-0400>
|
|
* @version 2.2.0
|
|
*
|
|
* Locking policy that aggregates two policies that share a target.
|
|
* It is not appropriate to use with any type of OverlappedScope
|
|
*/
|
|
template <class Scope1, class Scope2>
|
|
class CompoundScope {
|
|
public:
|
|
|
|
template <class LockType>
|
|
static void createScope(LockHolder<LockType>& l) {
|
|
|
|
Scope1::createScope(l);
|
|
Scope2::createScope(l);
|
|
|
|
}
|
|
|
|
template <class LockType>
|
|
static void createScope(LockHolder<LockType>& l, unsigned long ms) {
|
|
|
|
if(Scope1::createScope(l, ms))
|
|
if(!Scope2::createScope(l, ms)) {
|
|
|
|
Scope1::destroyScope(l);
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
template <class LockType>
|
|
static void destroyScope(LockHolder<LockType>& l) {
|
|
|
|
Scope1::destroyScope(l);
|
|
Scope2::destroyScope(l);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* @class LockedScope
|
|
* @author Eric Crahen <http://www.code-foo.com>
|
|
* @date <2003-07-16T17:55:42-0400>
|
|
* @version 2.2.0
|
|
*
|
|
* Locking policy for Lockable objects. This policy acquire()s a Lockable
|
|
* when the protection scope is created, and it release()s a Lockable
|
|
* when the scope is destroyed.
|
|
*/
|
|
class LockedScope {
|
|
public:
|
|
|
|
/**
|
|
* A new protection scope is being created by l2, using an existing scope
|
|
* created by l1.
|
|
*
|
|
* @param lock1 LockType1& is the LockHolder that holds the desired lock
|
|
* @param lock2 LockType1& is the LockHolder that wants to share
|
|
template <class LockType1, class LockType2>
|
|
static void shareScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
|
|
|
|
l2.getLock().acquire();
|
|
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* A new protection scope is being created.
|
|
*
|
|
* @param lock LockType& is a type of LockHolder.
|
|
*/
|
|
template <class LockType>
|
|
static bool createScope(LockHolder<LockType>& l, unsigned long ms) {
|
|
|
|
return l.getLock().tryAcquire(ms);
|
|
|
|
}
|
|
|
|
/**
|
|
* A new protection scope is being created.
|
|
*
|
|
* @param lock LockType& is a type of LockHolder.
|
|
*/
|
|
template <class LockType>
|
|
static void createScope(LockHolder<LockType>& l) {
|
|
|
|
l.getLock().acquire();
|
|
|
|
}
|
|
|
|
/**
|
|
* A protection scope is being destroyed.
|
|
*
|
|
* @param lock LockType& is a type of LockHolder.
|
|
*/
|
|
template <class LockType>
|
|
static void destroyScope(LockHolder<LockType>& l) {
|
|
|
|
l.getLock().release();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* @class UnlockedScope
|
|
* @author Eric Crahen <http://www.code-foo.com>
|
|
* @date <2003-07-16T17:55:42-0400>
|
|
* @version 2.2.0
|
|
*
|
|
* Locking policy for Lockable objects. This policy release()s a Lockable
|
|
* when the protection scope is created, and it acquire()s a Lockable
|
|
* when the scope is destroyed.
|
|
*/
|
|
class UnlockedScope {
|
|
public:
|
|
|
|
/**
|
|
* A new protection scope is being created by l2, using an existing scope
|
|
* created by l1.
|
|
*
|
|
* @param lock1 LockType1& is the LockHolder that holds the desired lock
|
|
* @param lock2 LockType1& is the LockHolder that wants to share
|
|
*/
|
|
template <class LockType1, class LockType2>
|
|
static void shareScope(LockHolder<LockType1>& /*l1*/, LockHolder<LockType2>& l2) {
|
|
|
|
l2.getLock().release();
|
|
|
|
}
|
|
|
|
/**
|
|
* A new protection scope is being created.
|
|
*
|
|
* @param lock LockType& is a type of LockHolder.
|
|
template <class LockType>
|
|
static void createScope(LockHolder<LockType>& l) {
|
|
|
|
l.getLock().release();
|
|
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* A protection scope is being destroyed.
|
|
*
|
|
* @param lock LockType& is a type of LockHolder.
|
|
*/
|
|
template <class LockType>
|
|
static void destroyScope(LockHolder<LockType>& l) {
|
|
|
|
l.getLock().acquire();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* @class TimedLockedScope
|
|
* @author Eric Crahen <http://www.code-foo.com>
|
|
* @date <2003-07-16T17:55:42-0400>
|
|
* @version 2.2.0
|
|
*
|
|
* Locking policy that attempts to enterScope some resource
|
|
* in a certain amount of time using an tryEnterScope-relase protocol.
|
|
*/
|
|
template <int TimeOut>
|
|
class TimedLockedScope {
|
|
public:
|
|
|
|
/**
|
|
* Try to enterScope the given LockHolder.
|
|
*
|
|
* @param lock LockType& is a type of LockHolder.
|
|
*/
|
|
template <class LockType1, class LockType2>
|
|
static void shareScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
|
|
|
|
if(!l2.getLock().tryAcquire(TimeOut))
|
|
throw Timeout_Exception();
|
|
|
|
}
|
|
|
|
template <class LockType>
|
|
static void createScope(LockHolder<LockType>& l) {
|
|
|
|
if(!l.getLock().tryAcquire(TimeOut))
|
|
throw Timeout_Exception();
|
|
|
|
}
|
|
|
|
template <class LockType>
|
|
static void destroyScope(LockHolder<LockType>& l) {
|
|
|
|
l.getLock().release();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* @class OverlappedScope
|
|
* @author Eric Crahen <http://www.code-foo.com>
|
|
* @date <2003-07-16T17:55:42-0400>
|
|
* @version 2.2.0
|
|
*
|
|
* Locking policy allows the effective scope of two locks to overlap
|
|
* by releasing and disabling one lock before its Guard does so.
|
|
*/
|
|
class OverlappedScope {
|
|
public:
|
|
|
|
template <class LockType1, class LockType2>
|
|
static void transferScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
|
|
|
|
l1.getLock().acquire();
|
|
|
|
l2.getLock().release();
|
|
l2.disable();
|
|
|
|
}
|
|
|
|
template <class LockType>
|
|
static void destroyScope(LockHolder<LockType>& l) {
|
|
|
|
l.getLock().release();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* @class Guard
|
|
* @author Eric Crahen <http://www.code-foo.com>
|
|
* @date <2003-07-16T17:55:42-0400>
|
|
* @version 2.2.0
|
|
*
|
|
* Scoped locking utility. This template class can be given a Lockable
|
|
* synchronization object and can 'Guard' or serialize access to
|
|
* that method.
|
|
*
|
|
* For instance, consider a case in which a class or program have a
|
|
* Mutex object associated with it. Access can be serialized with a
|
|
* Guard as shown below.
|
|
*
|
|
* @code
|
|
*
|
|
* Mutex _mtx;
|
|
* void guarded() {
|
|
*
|
|
* Guard<Mutex> g(_mtx);
|
|
*
|
|
* }
|
|
*
|
|
* @endcode
|
|
*
|
|
* The Guard will lock the synchronization object when it is created and
|
|
* automatically unlock it when it goes out of scope. This eliminates
|
|
* common mistakes like forgetting to unlock your mutex.
|
|
*
|
|
* An alternative to the above example would be
|
|
*
|
|
* @code
|
|
*
|
|
* void guarded() {
|
|
*
|
|
* (Guard<Mutex>)(_mtx);
|
|
*
|
|
* }
|
|
*
|
|
* @endcode
|
|
*
|
|
* HOWEVER; using a Guard in this method is dangerous. Depending on your
|
|
* compiler an anonymous variable like this can go out of scope immediately
|
|
* which can result in unexpected behavior. - This is the case with MSVC
|
|
* and was the reason for introducing assertions into the Win32_MutexImpl
|
|
* to track this problem down
|
|
*
|
|
*/
|
|
template <class LockType, class LockingPolicy = LockedScope>
|
|
class Guard : private LockHolder<LockType>, private NonCopyable {
|
|
|
|
friend class LockHolder<LockType>;
|
|
|
|
public:
|
|
|
|
/**
|
|
* Create a Guard that enforces a the effective protection scope
|
|
* throughout the lifetime of the Guard object or until the protection
|
|
* scope is modified by another Guard.
|
|
*
|
|
* @param lock LockType the lock this Guard will use to enforce its
|
|
* protection scope.
|
|
* @post the protection scope may be ended prematurely
|
|
*/
|
|
Guard(LockType& lock) : LockHolder<LockType>(lock) {
|
|
|
|
LockingPolicy::createScope(*this);
|
|
|
|
};
|
|
|
|
/**
|
|
* Create a Guard that enforces a the effective protection scope
|
|
* throughout the lifetime of the Guard object or until the protection
|
|
* scope is modified by another Guard.
|
|
*
|
|
* @param lock LockType the lock this Guard will use to enforce its
|
|
* protection scope.
|
|
* @post the protection scope may be ended prematurely
|
|
*/
|
|
Guard(LockType& lock, unsigned long timeout) : LockHolder<LockType>(lock) {
|
|
|
|
if(!LockingPolicy::createScope(*this, timeout))
|
|
throw Timeout_Exception();
|
|
|
|
};
|
|
|
|
/**
|
|
* Create a Guard that shares the effective protection scope
|
|
* from the given Guard to this Guard.
|
|
*
|
|
* @param g Guard<U, V> guard that is currently enabled
|
|
* @param lock LockType the lock this Guard will use to enforce its
|
|
* protection scope.
|
|
*/
|
|
template <class U, class V>
|
|
Guard(Guard<U, V>& g) : LockHolder<LockType>(g) {
|
|
|
|
LockingPolicy::shareScope(*this, extract(g));
|
|
|
|
}
|
|
|
|
/**
|
|
* Create a Guard that shares the effective protection scope
|
|
* from the given Guard to this Guard.
|
|
*
|
|
* @param g Guard guard that is currently enabled
|
|
* @param lock LockType the lock this Guard will use to enforce its
|
|
* protection scope.
|
|
*/
|
|
Guard(Guard& g) : LockHolder<LockType>(g) {
|
|
|
|
LockingPolicy::shareScope(*this, g);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Create a Guard that transfers the effective protection scope
|
|
* from the given Guard to this Guard.
|
|
*
|
|
* @param g Guard<U, V> guard that is currently enabled
|
|
* @param lock LockType the lock this Guard will use to enforce its
|
|
* protection scope.
|
|
*/
|
|
template <class U, class V>
|
|
Guard(Guard<U, V>& g, LockType& lock) : LockHolder<LockType>(lock) {
|
|
|
|
LockingPolicy::transferScope(*this, extract(g));
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Create a Guard that transfers the effective protection scope
|
|
* from the given Guard to this Guard.
|
|
*
|
|
* @param g Guard guard that is currently enabled
|
|
* @param lock LockType the lock this Guard will use to enforce its
|
|
* protection scope.
|
|
*/
|
|
Guard(Guard& g, LockType& lock) : LockHolder<LockType>(lock) {
|
|
|
|
LockingPolicy::transferScope(*this, g);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Unlock a given Lockable object with the destruction of this Guard
|
|
*/
|
|
~Guard() throw();
|
|
|
|
}; /* Guard */
|
|
|
|
|
|
template <class LockType, class LockingPolicy>
|
|
Guard<LockType, LockingPolicy>::~Guard() throw() {
|
|
|
|
try {
|
|
|
|
if(!this->isDisabled())
|
|
LockingPolicy::destroyScope(*this);
|
|
|
|
} catch (...) { /* ignore */ }
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
#endif // __ZTGUARD_H__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|