Initial commit
This commit is contained in:
153
Include/ZSimulation/ZMessageStream.hpp
Normal file
153
Include/ZSimulation/ZMessageStream.hpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
ZMessageStream.hpp
|
||||
Author: James Russell <jcrussell@762studios.com>
|
||||
Created: 2/4/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Messaging stream class, which acts as an event loop for the entire simulation. Processes both
|
||||
untargeted (or 'simulation' targeted) messages and messages that are intended for a specific entity.
|
||||
Handles organization and sorting so that the messages can be processed in a thread safe fashion at
|
||||
a later time.
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZMESSAGESTREAM_HPP
|
||||
#define _ZMESSAGESTREAM_HPP
|
||||
|
||||
#include <ZUtil/ZConcurrency.hpp>
|
||||
#include <ZUtil/ZSlabAllocator.hpp>
|
||||
|
||||
#include "ZSimulationDefs.hpp"
|
||||
|
||||
//Forward Declarations
|
||||
class ZSimulation;
|
||||
|
||||
/*
|
||||
Message structure. Messages are in the form of a POD struct of a set size
|
||||
payload. Message layout definitions (see ZSimulationDefs.hpp for examples)
|
||||
can be used to interpret the data.
|
||||
*/
|
||||
struct ZMessage {
|
||||
mID Type; // type of the message
|
||||
eID Sender; // the entity who sent the message (ZSIM_EID_SYSTEM means system or simulation)
|
||||
eID Target; // the target of the message (ZSIM_EID_SYSTEM calls the default handler)
|
||||
|
||||
char Payload[ZSIM_MESSAGE_SIZE]; // the message payload, which can be interpreted via layout definitions
|
||||
};
|
||||
|
||||
/*
|
||||
Message handler function profile.
|
||||
*/
|
||||
typedef void (*ZMessageHandler)(eID _sender, eID _target, void* _payload, ZSimulation& _sim);
|
||||
|
||||
/*
|
||||
Message streaming class, used to send messages from one entity to another or to the simulation.
|
||||
*/
|
||||
class ZMessageStream
|
||||
{
|
||||
public:
|
||||
// c'tor
|
||||
ZMessageStream();
|
||||
|
||||
// d'tor
|
||||
~ZMessageStream();
|
||||
|
||||
// message 'Send' method, which will copy data from a struct into the message (MT must be a POD type)
|
||||
template <typename MT>
|
||||
void Send(mID _type, eID _sender, eID _target, MT _payload)
|
||||
{
|
||||
ZMessage* msg;
|
||||
|
||||
#if SST_COMPILER == SST_COMPILER_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127)
|
||||
#endif
|
||||
|
||||
ZASSERT(sizeof(MT) <= ZSIM_MESSAGE_SIZE, "Message sent with payload too large!");
|
||||
|
||||
#if SST_COMPILER == SST_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// Synchronized Section
|
||||
{
|
||||
ZLock lock(AllocatorMutex);
|
||||
|
||||
msg = MessageAllocator.Allocate();
|
||||
}
|
||||
|
||||
ZASSERT(msg != NULL, "Unable to allocate message!");
|
||||
|
||||
msg->Type = _type;
|
||||
msg->Sender = _sender;
|
||||
msg->Target = _target;
|
||||
|
||||
MemCopy(uint8_t, msg->Payload, &_payload, sizeof(MT));
|
||||
|
||||
// Synchronized Section
|
||||
{
|
||||
ZLock lock(BufferMutex);
|
||||
|
||||
MessageBuffers[CurrentBufferIndex].PushBack(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Pumps the message queue, processing the messages that have been sent since last time this method was
|
||||
called. Returns true if additional messages were generated during the processing of the current set
|
||||
of messages.
|
||||
|
||||
Messages that are targeted at a specific entity will be delivered to that entity. If that entity cannot
|
||||
be found, the message is dropped. Messages that target the reserved eID of '0' will be handled by the
|
||||
message stream handlers.
|
||||
|
||||
Only one thread should ever be calling this method. Multiple threads calling this method will result
|
||||
in that thread waiting until the previous has finished.
|
||||
|
||||
Returns true if messages are still available for processing, false if the current queue is empty.
|
||||
*/
|
||||
bool ProcessMessages(ZSimulation& _sim);
|
||||
|
||||
/*
|
||||
External message handlers. Used to return an entity targeted message or process a targeted
|
||||
message that had no installed handler.
|
||||
*/
|
||||
void HandleMessage(ZMessage* _msg, ZSimulation& _sim);
|
||||
void ReturnMessage(ZMessage* _msg);
|
||||
|
||||
/*
|
||||
Push and Pop Methods for Handlers.
|
||||
*/
|
||||
void PushHandler(mID _type, ZMessageHandler _handler);
|
||||
ZMessageHandler PopHandler(mID _type);
|
||||
|
||||
protected:
|
||||
|
||||
ZMutex AllocatorMutex; // lock for allocators
|
||||
ZMutex BufferMutex; // lock for buffers
|
||||
ZMutex HandlerMutex; // lock for handlers
|
||||
ZMutex ProcessingMutex; // lock for processing
|
||||
|
||||
int CurrentBufferIndex; // index to our current message buffer
|
||||
|
||||
ZRingBuffer<ZMessage*> MessageBuffers[2]; // the current set of messages (one receives messages while the other is processed)
|
||||
ZHashMap<mID,
|
||||
ZArray<ZMessageHandler>> MessageHandlers; // set of handler functions
|
||||
|
||||
ZSlabAllocator<ZMessage,
|
||||
ZSIM_MESSAGE_ALLOC> MessageAllocator; // slab allocator for messages
|
||||
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN(ZMessageStream);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user