From d5eaaf4e01a91a96f4e647eeebd3613db439f810 Mon Sep 17 00:00:00 2001 From: ExMix Date: Wed, 20 Nov 2013 11:57:38 +0300 Subject: [PATCH] [drape] cross-thread communication channel --- drape_frontend/message.cpp | 20 ++++++++++++ drape_frontend/message.hpp | 30 ++++++++++++++++++ drape_frontend/message_acceptor.cpp | 34 ++++++++++++++++++++ drape_frontend/message_acceptor.hpp | 27 ++++++++++++++++ drape_frontend/message_queue.cpp | 45 +++++++++++++++++++++++++++ drape_frontend/message_queue.hpp | 28 +++++++++++++++++ drape_frontend/threads_commutator.cpp | 23 ++++++++++++++ drape_frontend/threads_commutator.hpp | 26 ++++++++++++++++ 8 files changed, 233 insertions(+) create mode 100644 drape_frontend/message.cpp create mode 100644 drape_frontend/message.hpp create mode 100644 drape_frontend/message_acceptor.cpp create mode 100644 drape_frontend/message_acceptor.hpp create mode 100644 drape_frontend/message_queue.cpp create mode 100644 drape_frontend/message_queue.hpp create mode 100644 drape_frontend/threads_commutator.cpp create mode 100644 drape_frontend/threads_commutator.hpp diff --git a/drape_frontend/message.cpp b/drape_frontend/message.cpp new file mode 100644 index 0000000000..e0f6db0bb0 --- /dev/null +++ b/drape_frontend/message.cpp @@ -0,0 +1,20 @@ +#include "message.hpp" + +#include "../base/assert.hpp" + +namespace df +{ + Message::Message() + : m_type(Unknown) {} + + Message::Type Message::GetType() const + { + ASSERT(m_type != Unknown, ()); + return m_type; + } + + void Message::SetType(Type t) + { + m_type = t; + } +} diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp new file mode 100644 index 0000000000..5119b4b10a --- /dev/null +++ b/drape_frontend/message.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace df +{ + class Message + { + public: + enum Type + { + // in perfect world GetType never return this type + // for this you need call SetType on subclass constructor + Unknown, + DropTile, + DropCoverage, + UpdateCoverage, + Resize, + TaskFinish + }; + + Message(); + virtual ~Message() {} + Type GetType() const; + + protected: + void SetType(Type t); + + private: + Type m_type; + }; +} diff --git a/drape_frontend/message_acceptor.cpp b/drape_frontend/message_acceptor.cpp new file mode 100644 index 0000000000..20cca88fcf --- /dev/null +++ b/drape_frontend/message_acceptor.cpp @@ -0,0 +1,34 @@ +#include "message_acceptor.hpp" + +#include "message.hpp" + +namespace df +{ + void MessageAcceptor::ProcessSingleMessage(bool waitMessage) + { + Message * message = m_messageQueue.PopMessage(waitMessage); + if (message == NULL) + return; + + AcceptMessage(message); + delete message; + } + + void MessageAcceptor::PostMessage(Message * message) + { + m_messageQueue.PushMessage(message); + } + + void MessageAcceptor::CloseQueue() + { + m_messageQueue.CancelWait(); + ClearQueue(); + } + + void MessageAcceptor::ClearQueue() + { + Message * message; + while ((message = m_messageQueue.PopMessage(false)) != NULL) + delete message; + } +} diff --git a/drape_frontend/message_acceptor.hpp b/drape_frontend/message_acceptor.hpp new file mode 100644 index 0000000000..1b03094271 --- /dev/null +++ b/drape_frontend/message_acceptor.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "message_queue.hpp" + +namespace df +{ + class Message; + + class MessageAcceptor + { + protected: + virtual void AcceptMessage(Message * message) = 0; + + /// Must be called by subclass on message target thread + void ProcessSingleMessage(bool waitMessage); + void CloseQueue(); + + private: + friend class ThreadsCommutator; + + void PostMessage(Message * message); + void ClearQueue(); + + private: + MessageQueue m_messageQueue; + }; +} diff --git a/drape_frontend/message_queue.cpp b/drape_frontend/message_queue.cpp new file mode 100644 index 0000000000..5a968a8434 --- /dev/null +++ b/drape_frontend/message_queue.cpp @@ -0,0 +1,45 @@ +#include "message_queue.hpp" + +#include "../base/assert.hpp" + +namespace df +{ + Message * MessageQueue::PopMessage(bool waitMessage) + { + threads::ConditionGuard guard(m_condition); + + if (waitMessage) + WaitMessage(); + + /// even waitNonEmpty == true m_messages can be empty after WaitMessage call + /// if application preparing to close and CancelWait been called + if (m_messages.empty()) + return NULL; + + Message * msg = m_messages.front(); + m_messages.pop_front(); + return msg; + } + + void MessageQueue::PushMessage(Message * message) + { + threads::ConditionGuard guard(m_condition); + + bool wasEmpty = m_messages.empty(); + m_messages.push_back(message); + + if (wasEmpty) + guard.Signal(); + } + + void MessageQueue::WaitMessage() + { + if (m_messages.empty()) + m_condition.Wait(); + } + + void MessageQueue::CancelWait() + { + m_condition.Signal(); + } +} diff --git a/drape_frontend/message_queue.hpp b/drape_frontend/message_queue.hpp new file mode 100644 index 0000000000..f1ae520532 --- /dev/null +++ b/drape_frontend/message_queue.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "message.hpp" + +#include "../base/condition.hpp" + +#include "../std/list.hpp" + +namespace df +{ + class MessageQueue + { + public: + MessageQueue(); + + /// if queue is empty than return NULL + Message * PopMessage(bool waitMessage); + void PushMessage(Message * message); + void CancelWait(); + + private: + void WaitMessage(); + + private: + threads::Condition m_condition; + list m_messages; + }; +} diff --git a/drape_frontend/threads_commutator.cpp b/drape_frontend/threads_commutator.cpp new file mode 100644 index 0000000000..8b352fc2e5 --- /dev/null +++ b/drape_frontend/threads_commutator.cpp @@ -0,0 +1,23 @@ +#include "threads_commutator.hpp" + +#include "message_acceptor.hpp" + +#include "../base/assert.hpp" + +namespace df +{ + void ThreadsCommutator::RegisterThread(ThreadName name, MessageAcceptor * acceptor) + { + ASSERT(m_acceptors.find(name) == m_acceptors.end(), ()); + m_acceptors[name] = acceptor; + } + + void ThreadsCommutator::PostMessage(ThreadName name, Message * message) + { + acceptors_map_t::iterator it = m_acceptors.find(name); + ASSERT(it != m_acceptors.end(), ()); + if (it != m_acceptors.end()) + it->second->AcceptMessage(message); + } +} + diff --git a/drape_frontend/threads_commutator.hpp b/drape_frontend/threads_commutator.hpp new file mode 100644 index 0000000000..766b93768a --- /dev/null +++ b/drape_frontend/threads_commutator.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "../std/map.hpp" + +namespace df +{ + class Message; + class MessageAcceptor; + + class ThreadsCommutator + { + public: + enum ThreadName + { + RenderThread, + ResourceUploadThread + }; + + void RegisterThread(ThreadName name, MessageAcceptor * acceptor); + void PostMessage(ThreadName name, Message * message); + + private: + typedef map acceptors_map_t; + acceptors_map_t m_acceptors; + }; +}