/* Copyright (c) 2003-2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef BLOCK_MUTEX_HPP #define BLOCK_MUTEX_HPP #include "Callback.hpp" #include "SimulatedBlock.hpp" class Mutex; /** * MutexHandle - A "reference" to a mutex * - Should be used together with Mutex */ class MutexHandle { friend class Mutex; public: MutexHandle(Uint32 id); bool isNull() const; void release(SimulatedBlock::MutexManager & mgr); private: const Uint32 m_mutexId; Uint32 m_activeMutexPtrI; }; /** * MutexHandle2 - A template-based "reference" to a mutex */ template class MutexHandle2 { friend class Mutex; public: MutexHandle2(); bool isNull() const; void release(SimulatedBlock::MutexManager & mgr); private: Uint32 m_activeMutexPtrI; }; /** * A mutex - Used together with a MutexHandle to be put on the stack */ class Mutex { public: Mutex(Signal*, SimulatedBlock::MutexManager & mgr, MutexHandle &); template Mutex(Signal*, SimulatedBlock::MutexManager & mgr, MutexHandle2 &); ~Mutex(); void release(); bool isNull() const ; bool lock(SimulatedBlock::Callback & callback); bool trylock(SimulatedBlock::Callback & callback); void unlock(SimulatedBlock::Callback & callback); void unlock(); // Ignore callback bool create(SimulatedBlock::Callback & callback); bool destroy(SimulatedBlock::Callback & callback); private: Signal* m_signal; SimulatedBlock::MutexManager & m_mgr; const Uint32 m_mutexId; Uint32 & m_srcPtrI; SimulatedBlock::MutexManager::ActiveMutexPtr m_ptr; public: static void release(SimulatedBlock::MutexManager&, Uint32 activePtrI, Uint32 mutexId); }; inline MutexHandle::MutexHandle(Uint32 id) : m_mutexId(id) { m_activeMutexPtrI = RNIL; } inline bool MutexHandle::isNull() const { return m_activeMutexPtrI == RNIL; } inline void MutexHandle::release(SimulatedBlock::MutexManager & mgr){ if(!isNull()){ Mutex::release(mgr, m_activeMutexPtrI, m_mutexId); m_activeMutexPtrI = RNIL; } } template inline MutexHandle2::MutexHandle2() { m_activeMutexPtrI = RNIL; } template inline bool MutexHandle2::isNull() const { return m_activeMutexPtrI == RNIL; } template inline void MutexHandle2::release(SimulatedBlock::MutexManager & mgr){ if(!isNull()){ Mutex::release(mgr, m_activeMutexPtrI, MutexId); m_activeMutexPtrI = RNIL; } } inline Mutex::Mutex(Signal* signal, SimulatedBlock::MutexManager & mgr, MutexHandle & mh) : m_signal(signal), m_mgr(mgr), m_mutexId(mh.m_mutexId), m_srcPtrI(mh.m_activeMutexPtrI){ m_ptr.i = m_srcPtrI; } template inline Mutex::Mutex(Signal* signal, SimulatedBlock::MutexManager & mgr, MutexHandle2 & mh) : m_signal(signal), m_mgr(mgr), m_mutexId(MutexId), m_srcPtrI(mh.m_activeMutexPtrI){ m_ptr.i = m_srcPtrI; } inline Mutex::~Mutex(){ m_srcPtrI = m_ptr.i; } inline void Mutex::release(){ if(!m_ptr.isNull()){ Mutex::release(m_mgr, m_ptr.i, m_mutexId); m_ptr.setNull(); } } inline bool Mutex::isNull() const { return m_ptr.isNull(); } inline bool Mutex::lock(SimulatedBlock::Callback & callback){ if(m_ptr.isNull()){ if(m_mgr.seize(m_ptr)){ m_ptr.p->m_mutexId = m_mutexId; m_ptr.p->m_callback = callback; m_mgr.lock(m_signal, m_ptr); return true; } return false; } ErrorReporter::handleAssert("Mutex::lock mutex alreay inuse", __FILE__, __LINE__); return false; } inline bool Mutex::trylock(SimulatedBlock::Callback & callback){ if(m_ptr.isNull()){ if(m_mgr.seize(m_ptr)){ m_ptr.p->m_mutexId = m_mutexId; m_ptr.p->m_callback = callback; m_mgr.lock(m_signal, m_ptr); return true; } return false; } ErrorReporter::handleAssert("Mutex::trylock mutex alreay inuse", __FILE__, __LINE__); return false; } inline void Mutex::unlock(SimulatedBlock::Callback & callback){ if(!m_ptr.isNull()){ m_mgr.getPtr(m_ptr); if(m_ptr.p->m_mutexId == m_mutexId){ m_ptr.p->m_callback = callback; m_mgr.unlock(m_signal, m_ptr); return; } } ErrorReporter::handleAssert("Mutex::unlock invalid mutex", __FILE__, __LINE__); } inline bool Mutex::create(SimulatedBlock::Callback & callback){ if(m_ptr.isNull()){ if(m_mgr.seize(m_ptr)){ m_ptr.p->m_mutexId = m_mutexId; m_ptr.p->m_callback = callback; m_mgr.create(m_signal, m_ptr); return true; } return false; } ErrorReporter::handleAssert("Mutex::create mutex alreay inuse", __FILE__, __LINE__); return false; } inline bool Mutex::destroy(SimulatedBlock::Callback & callback){ if(m_ptr.isNull()){ if(m_mgr.seize(m_ptr)){ m_ptr.p->m_mutexId = m_mutexId; m_ptr.p->m_callback = callback; m_mgr.destroy(m_signal, m_ptr); return true; } return false; } ErrorReporter::handleAssert("Mutex::destroy mutex alreay inuse", __FILE__, __LINE__); return false; } #endif