From c260a4a9df40ffc59f27ae13f63a798cba4ea27c Mon Sep 17 00:00:00 2001 From: rachytski Date: Mon, 2 Jan 2012 22:19:37 +0400 Subject: [PATCH] moved FenceManager to base library and added tests for it. --- base/base.pro | 2 + base/base_tests/base_tests.pro | 2 + base/base_tests/fence_manager_test.cpp | 95 ++++++++++++++++++++++++++ base/commands_queue.cpp | 10 +-- base/condition.cpp | 25 +++++++ base/condition.hpp | 11 ++- base/fence_manager.cpp | 90 ++++++++++++++++++++++++ base/fence_manager.hpp | 26 +++++++ yg/fence_manager.cpp | 89 ------------------------ yg/fence_manager.hpp | 29 -------- yg/packets_queue.hpp | 2 +- yg/yg.pro | 2 - 12 files changed, 251 insertions(+), 132 deletions(-) create mode 100644 base/base_tests/fence_manager_test.cpp create mode 100644 base/fence_manager.cpp create mode 100644 base/fence_manager.hpp delete mode 100644 yg/fence_manager.cpp delete mode 100644 yg/fence_manager.hpp diff --git a/base/base.pro b/base/base.pro index 58df037f98..da59a8bca6 100644 --- a/base/base.pro +++ b/base/base.pro @@ -25,6 +25,7 @@ SOURCES += \ exception.cpp \ threaded_container.cpp \ resource_pool.cpp \ + fence_manager.cpp \ HEADERS += \ SRC_FIRST.hpp \ @@ -71,3 +72,4 @@ HEADERS += \ limited_priority_queue.hpp \ threaded_priority_queue.hpp \ std_serialization.hpp \ + fence_manager.hpp \ diff --git a/base/base_tests/base_tests.pro b/base/base_tests/base_tests.pro index 321ccd634e..022ad76c62 100644 --- a/base/base_tests/base_tests.pro +++ b/base/base_tests/base_tests.pro @@ -33,7 +33,9 @@ SOURCES += \ threaded_list_test.cpp \ condition_test.cpp \ containers_test.cpp \ + fence_manager_test.cpp HEADERS += + diff --git a/base/base_tests/fence_manager_test.cpp b/base/base_tests/fence_manager_test.cpp new file mode 100644 index 0000000000..49e8b3a9ef --- /dev/null +++ b/base/base_tests/fence_manager_test.cpp @@ -0,0 +1,95 @@ +#include "../../testing/testing.hpp" +#include "../commands_queue.hpp" +#include "../fence_manager.hpp" +#include "../../std/bind.hpp" + +void add_int(core::CommandsQueue::Environment const & env, + int fenceID, + FenceManager & fenceManager, + int & i, + int a, + int ms) +{ + threads::Sleep(ms); + if (env.isCancelled()) + return; + i += a; + LOG(LINFO, ("add_int result:", i)); + + fenceManager.signalFence(fenceID); +} + +void join_mul_int(core::CommandsQueue::Environment const & env, + int fenceID, + FenceManager & fenceManager, + int & i, + int b, + int ms) +{ + threads::Sleep(ms); + fenceManager.joinFence(fenceID); + i *= b; + LOG(LINFO, ("join_mul_int result: ", i)); +} + +UNIT_TEST(FenceManager_SimpleFence) +{ + FenceManager fenceManager(3); + core::CommandsQueue queue(2); + + int i = 3; + + queue.Start(); + + int fenceID = fenceManager.insertFence(); + + queue.AddCommand(bind(&add_int, _1, fenceID, ref(fenceManager), ref(i), 5, 500)); + queue.AddCommand(bind(&join_mul_int, _1, fenceID, ref(fenceManager), ref(i), 3, 1)); + + queue.Join(); + queue.Cancel(); + + TEST(i == 24, ()); +} + +UNIT_TEST(FenceManager_JoinAlreadySignalled) +{ + FenceManager fenceManager(3); + core::CommandsQueue queue(2); + + int i = 3; + + queue.Start(); + + int fenceID = fenceManager.insertFence(); + + queue.AddCommand(bind(&add_int, _1, fenceID, ref(fenceManager), ref(i), 5, 1)); + queue.AddCommand(bind(&join_mul_int, _1, fenceID, ref(fenceManager), ref(i), 3, 500)); + + queue.Join(); + queue.Cancel(); + + TEST(i == 24, ()); +} + +UNIT_TEST(FenceManager_SignalAlreadySignalled) +{ + FenceManager fenceManager(3); + core::CommandsQueue queue(2); + + int i = 3; + + queue.Start(); + + int fenceID = fenceManager.insertFence(); + + fenceManager.signalFence(fenceID); + + queue.AddCommand(bind(&add_int, _1, fenceID, ref(fenceManager), ref(i), 5, 1)); + queue.AddCommand(bind(&join_mul_int, _1, fenceID, ref(fenceManager), ref(i), 3, 500)); + + queue.Join(); + queue.Cancel(); + + TEST(i == 24, ()) +} diff --git a/base/commands_queue.cpp b/base/commands_queue.cpp index ae3a6f0dfb..ab2925f30b 100644 --- a/base/commands_queue.cpp +++ b/base/commands_queue.cpp @@ -40,7 +40,7 @@ namespace core threads::ConditionGuard g(*m_cond.get()); m_waitCount++; if (!m_isCompleted) - m_cond->Wait(); + g.Wait(); } else LOG(LERROR, ("command isn't waitable")); @@ -54,7 +54,7 @@ namespace core m_isCompleted = true; CHECK(m_waitCount < 2, ("only one thread could wait for the queued command")); if (m_waitCount) - m_cond->Signal(true); + g.Signal(true); } } @@ -215,14 +215,14 @@ namespace core --m_activeCommands; if (m_activeCommands == 0) - m_cond.Signal(); + g.Signal(); } void CommandsQueue::Join() { threads::ConditionGuard g(m_cond); - if (m_activeCommands != 0) - m_cond.Wait(); + while (m_activeCommands != 0) + g.Wait(); } void CommandsQueue::Clear() diff --git a/base/condition.cpp b/base/condition.cpp index c345feab00..7af813e99c 100644 --- a/base/condition.cpp +++ b/base/condition.cpp @@ -7,3 +7,28 @@ #else #include "condition_posix.cpp" #endif + +namespace threads +{ + ConditionGuard::ConditionGuard(Condition & condition) + : m_Condition(condition) + { + m_Condition.Lock(); + } + + ConditionGuard::~ConditionGuard() + { + m_Condition.Unlock(); + } + + void ConditionGuard::Wait() + { + m_Condition.Wait(); + } + + void ConditionGuard::Signal(bool broadcast) + { + m_Condition.Signal(broadcast); + } +} + diff --git a/base/condition.hpp b/base/condition.hpp index 5b30b6bfaf..87d576cc00 100644 --- a/base/condition.hpp +++ b/base/condition.hpp @@ -28,13 +28,12 @@ namespace threads /// ScopeGuard wrapper around mutex class ConditionGuard { - public: - ConditionGuard(Condition & condition) - : m_Condition(condition) { m_Condition.Lock(); } - ~ConditionGuard() { m_Condition.Unlock(); } - void Wait() { m_Condition.Wait(); } - void Signal(bool broadcast = false) { m_Condition.Signal(broadcast); } private: Condition & m_Condition; + public: + ConditionGuard(Condition & condition); + ~ConditionGuard(); + void Wait(); + void Signal(bool broadcast = false); }; } diff --git a/base/fence_manager.cpp b/base/fence_manager.cpp new file mode 100644 index 0000000000..7a4ee1196f --- /dev/null +++ b/base/fence_manager.cpp @@ -0,0 +1,90 @@ +#include "fence_manager.hpp" + +#include "../base/assert.hpp" +#include "../base/logging.hpp" + +FenceManager::FenceManager(int conditionPoolSize) + : m_currentFence(0) +{ + m_conditionPool.resize(conditionPoolSize); + for (unsigned i = 0; i < m_conditionPool.size(); ++i) + m_conditionPool[i] = new threads::Condition(); +} + +FenceManager::~FenceManager() +{ + for (map::const_iterator it = m_activeFences.begin(); + it != m_activeFences.end(); + ++it) + { + it->second->Signal(); + delete it->second; + } + + for (unsigned i = 0; i < m_conditionPool.size(); ++i) + { + delete m_conditionPool[i]; + } +} + +int FenceManager::insertFence() +{ + threads::MutexGuard g(m_mutex); + + if (m_conditionPool.empty()) + return -1; + + threads::Condition * cond = m_conditionPool.back(); + m_conditionPool.pop_back(); + + int id = m_currentFence++; + + m_activeFences[id] = cond; + + return id; +} + +void FenceManager::signalFence(int id) +{ + threads::MutexGuard g(m_mutex); + + map::iterator it = m_activeFences.find(id); + + if (it == m_activeFences.end()) + { + LOG(LWARNING, ("fence with id", id, "has been already signalled or hasn't been installed yet")); + return; + } + + threads::Condition * cond = it->second; + + /// signalling to all waiting fences + cond->Signal(true); + + /// erasing fence from active fences + m_activeFences.erase(it); + + /// returning condition to the pool + m_conditionPool.push_back(cond); +} + +void FenceManager::joinFence(int id) +{ + threads::Condition * cond = 0; + { + threads::MutexGuard g(m_mutex); + + map::iterator it = m_activeFences.find(id); + + if (it == m_activeFences.end()) + { + LOG(LWARNING, ("fence with id", id, "has been already reached in the past or hasn't been installed yet")); + return; + } + + cond = it->second; + } + + threads::ConditionGuard g(*cond); + g.Wait(); +} diff --git a/base/fence_manager.hpp b/base/fence_manager.hpp new file mode 100644 index 0000000000..bd824c4769 --- /dev/null +++ b/base/fence_manager.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "../base/condition.hpp" +#include "../base/mutex.hpp" + +#include "../std/map.hpp" +#include "../std/vector.hpp" + +class FenceManager +{ +private: + + threads::Mutex m_mutex; + vector m_conditionPool; + map m_activeFences; + int m_currentFence; + +public: + + FenceManager(int conditionPoolSize); + ~FenceManager(); + + int insertFence(); + void joinFence(int id); + void signalFence(int id); +}; diff --git a/yg/fence_manager.cpp b/yg/fence_manager.cpp deleted file mode 100644 index 81f15faf01..0000000000 --- a/yg/fence_manager.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "fence_manager.hpp" - -#include "../base/assert.hpp" -#include "../base/logging.hpp" - -namespace yg -{ - FenceManager::FenceManager(int conditionPoolSize) - : m_currentFence(0) - { - m_conditionPool.resize(conditionPoolSize); - for (unsigned i = 0; i < m_conditionPool.size(); ++i) - m_conditionPool[i] = new threads::Condition(); - } - - FenceManager::~FenceManager() - { - for (map::const_iterator it = m_activeFences.begin(); - it != m_activeFences.end(); - ++it) - { - it->second->Signal(true); - delete it->second; - } - - for (unsigned i = 0; i < m_conditionPool.size(); ++i) - { - delete m_conditionPool[i]; - } - } - - int FenceManager::insertFence() - { - threads::MutexGuard g(m_mutex); - - if (m_conditionPool.empty()) - return -1; - - threads::Condition * cond = m_conditionPool.back(); - m_conditionPool.pop_back(); - - int id = m_currentFence++; - - m_activeFences[id] = cond; - - return id; - } - - void FenceManager::signalFence(int id) - { - threads::MutexGuard g(m_mutex); - - map::iterator it = m_activeFences.find(id); - - CHECK(it != m_activeFences.end(), ("using singalFence twice for the same id is error")); - - threads::Condition * cond = it->second; - - /// signalling to all waiting fences - cond->Signal(true); - - /// erasing fence from active fences - m_activeFences.erase(it); - - /// returning condition to the pool - m_conditionPool.push_back(cond); - } - - void FenceManager::joinFence(int id) - { - threads::Condition * cond = 0; - { - threads::MutexGuard g(m_mutex); - - map::iterator it = m_activeFences.find(id); - - if (it == m_activeFences.end()) - { - LOG(LINFO, ("fence has been reached in the past or haven't been installed yet")); - return; - } - - cond = it->second; - } - - threads::ConditionGuard g(*cond); - g.Wait(); - } -} diff --git a/yg/fence_manager.hpp b/yg/fence_manager.hpp deleted file mode 100644 index f8fe31dfce..0000000000 --- a/yg/fence_manager.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "../base/condition.hpp" -#include "../base/mutex.hpp" - -#include "../std/map.hpp" -#include "../std/vector.hpp" - -namespace yg -{ - class FenceManager - { - private: - - threads::Mutex m_mutex; - vector m_conditionPool; - map m_activeFences; - int m_currentFence; - - public: - - FenceManager(int conditionPoolSize); - ~FenceManager(); - - int insertFence(); - void joinFence(int id); - void signalFence(int id); - }; -} diff --git a/yg/packets_queue.hpp b/yg/packets_queue.hpp index 9d687e8411..3598e16b56 100644 --- a/yg/packets_queue.hpp +++ b/yg/packets_queue.hpp @@ -1,6 +1,6 @@ #pragma once -#include "fence_manager.hpp" +#include "../base/fence_manager.hpp" #include "../base/threaded_list.hpp" #include "../base/mutex.hpp" diff --git a/yg/yg.pro b/yg/yg.pro index 5e20a0e731..db043bf017 100644 --- a/yg/yg.pro +++ b/yg/yg.pro @@ -63,7 +63,6 @@ SOURCES += \ glyph_style.cpp \ circle_element.cpp \ packets_queue.cpp \ - fence_manager.cpp HEADERS += \ internal/opengl.hpp \ @@ -120,7 +119,6 @@ HEADERS += \ agg_traits.hpp \ circle_element.hpp \ packets_queue.hpp \ - fence_manager.hpp win32* { SOURCES += internal/opengl_win32.cpp