Files
libsst/Include/ZSimulation/ZMessageStream.hpp
2026-04-03 00:22:39 -05:00

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