[drape] cross-thread communication channel

This commit is contained in:
ExMix 2013-11-20 11:57:38 +03:00 committed by Alex Zolotarev
parent dee5053a23
commit d5eaaf4e01
8 changed files with 233 additions and 0 deletions

View file

@ -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;
}
}

View file

@ -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;
};
}

View file

@ -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;
}
}

View file

@ -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;
};
}

View file

@ -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();
}
}

View file

@ -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<Message *> m_messages;
};
}

View file

@ -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);
}
}

View file

@ -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<ThreadName, MessageAcceptor *> acceptors_map_t;
acceptors_map_t m_acceptors;
};
}