diff --git a/ethread/MutexRecursive.hpp b/ethread/MutexRecursive.hpp new file mode 100644 index 0000000..8e412b5 --- /dev/null +++ b/ethread/MutexRecursive.hpp @@ -0,0 +1,99 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once +#include + +#ifdef __TARGET_OS__Windows + #include +#else + #include +#endif + +namespace ethread { + /** + * @brief Generic mutex interface (OS independent) + */ + // TODO: Create a single class parametrable for all mutex ... + class MutexRecursive { + private: + #ifdef __TARGET_OS__Windows + CRITICAL_SECTION m_mutex; + #else + pthread_mutex_t m_mutex; + pthread_mutexattr_t m_attribute; + #endif + #ifdef DEBUG + uint32_t m_threadThatHaveLock; + #endif + public: + /** + * @brief Create a new mutex recursive + */ + MutexRecursive(); + /** + * @brief Destroy the mutex. + */ + ~MutexRecursive(); + /** + * @brief Lock the mutex (Wait while the mutex is not lock) + */ + void lock(); + /** + * @brief Try to lock the mutex (exit if mutex is already locked) + * @return true The mutex is locked + * @return false The mutex is already locked. + */ + bool tryLock(); + /** + * @brief Unloc the mutex + */ + void unLock(); + }; + /** + * @brief AutoLock and un-lock when exit fuction. + */ + class RecursiveLock { + private: + // Keep a reference on the mutex + ethread::MutexRecursive &m_protect; + bool m_lock; + public: + /** + * @brief constructor that automaticly lock the mutex. + * @param[in] _protect Mutex to Lock. + * @param[in] _notLock Must be lock after by a tryLock. + */ + RecursiveLock(ethread::MutexRecursive& _protect, bool _notLock = false) : + m_protect(_protect), + m_lock(false) { + if (_notLock == false) { + m_protect.lock(); + m_lock = true; + } + } + /** + * @brief Try to lock the mutex (exit if mutex is already locked) + * @return true The mutex is locked + * @return false The mutex is already locked. + */ + bool tryLock() { + if (m_protect.tryLock() == true) { + m_lock = true; + } + return m_lock; + } + /** + * @brief Destructor that Auto Unlock mutex when remove. + */ + virtual ~RecursiveLock(){ + if (m_lock == true) { + m_protect.unLock(); + m_lock = false; + } + } + }; +} + diff --git a/ethread/MutexRecursive.pthread.cpp b/ethread/MutexRecursive.pthread.cpp new file mode 100644 index 0000000..9261391 --- /dev/null +++ b/ethread/MutexRecursive.pthread.cpp @@ -0,0 +1,89 @@ +/** + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +extern "C" { + #include +} +#include +ETK_DECLARE_TYPE(ethread::MutexRecursive); +ETK_DECLARE_TYPE(ethread::RecursiveLock); +//#include + +ethread::MutexRecursive::MutexRecursive() { + #ifdef DEBUG + m_threadThatHaveLock = 0xFFFFFFFF; + #endif + // create interface mutex : + pthread_mutexattr_init(&m_attribute); + pthread_mutexattr_settype(&m_attribute, PTHREAD_MUTEX_RECURSIVE); + int ret = pthread_mutex_init(&m_mutex, &m_attribute); + //ETHREAD_ASSERT(ret == 0, "Error creating Mutex ..."); +} + + +ethread::MutexRecursive::~MutexRecursive() { + // Remove mutex + int ret = pthread_mutex_destroy(&m_mutex); + //ETHREAD_ASSERT(ret == 0, "Error destroying Mutex ..."); +} + + +void ethread::MutexRecursive::lock() { + pthread_mutex_lock(&m_mutex); + #ifdef DEBUG + m_threadThatHaveLock = ethread::getId(); + #endif +} + + +bool ethread::MutexRecursive::tryLock() { + int ret = pthread_mutex_trylock(&m_mutex); + if (ret == 0) { + return true; + } + if (ret == EINVAL) { + printf("trylock error: EINVAL\n"); + // The mutex was created with the protocol attribute having the value PTHREAD_PRIO_PROTECT and the calling thread's + // priority is higher than the mutex's current priority ceiling. + // The pthread_mutex_trylock() function shall fail if: + } + if (ret == EBUSY) { + printf("trylock error: EBUSY\n"); + // The mutex could not be acquired because it was already locked. + // The pthread_mutex_lock(), pthread_mutex_trylock(), and pthread_mutex_unlock() functions may fail if: + } + if (ret == EINVAL) { + printf("trylock error: EINVAL\n"); + // The value specified by mutex does not refer to an initialized mutex object. + } + if (ret == EAGAIN) { + printf("trylock error: EAGAIN\n"); + // The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded. + // The pthread_mutex_lock() function may fail if: + } + if (ret == EDEADLK) { + printf("trylock error: EDEADLK\n"); + // The current thread already owns the mutex. + // The pthread_mutex_unlock() function may fail if: + } + if (ret == EPERM) { + printf("trylock error: EPERM\n"); + //The current thread does not own the mutex. + } + return false; +} + + +void ethread::MutexRecursive::unLock() { + pthread_mutex_unlock(&m_mutex); + #ifdef DEBUG + m_threadThatHaveLock = 0xFFFFFFFF; + #endif +} +