154 lines
4.1 KiB
C++
154 lines
4.1 KiB
C++
/*
|
|
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
|
|
|