21EventService *EventService::instance =
nullptr;
27 impl_.reset(
new Impl(
this));
34 impl_.reset(
new Impl(
this));
38EventService::~EventService()
47 iface,
this, EventService::Impl::MTI_VALUE_EVENT,
48 EventService::Impl::MTI_MASK_EVENT));
50 iface,
this, EventService::Impl::MTI_VALUE_GLOBAL,
51 EventService::Impl::MTI_MASK_GLOBAL));
53 iface,
this, EventService::Impl::MTI_VALUE_ADDRESSED_ALL,
54 EventService::Impl::MTI_MASK_ADDRESSED_ALL));
57EventService::Impl::Impl(
EventService *service) : callerFlow_(service)
66EventService::Impl::~Impl()
76 return call_immediately(
STATE(call_done));
79 (c->registry_entry->
handler->*(c->fn))(*c->registry_entry, c->rep, &n_);
80 return wait_and_call(
STATE(call_done));
85 return release_and_exit();
88EventIteratorFlow::EventIteratorFlow(If *async_if, EventService *event_service,
89 unsigned mti_value,
unsigned mti_mask)
90 : IncomingMessageStateFlow(async_if)
91 , eventService_(event_service)
92 , iterator_(event_service->impl()->registry->create_iterator())
93#ifdef DEBUG_EVENT_PERFORMANCE
94 , mtiValue_(mti_value)
97 iface()->dispatcher()->register_handler(
this, mti_value, mti_mask);
100EventIteratorFlow::~EventIteratorFlow()
111 if (!f->is_waiting())
119 uint64_t e = r->
event;
122 r->
mask = (e ^ (e + 1)) >> 1;
126 r->
mask = (e ^ (e - 1)) >> 1;
128 r->
event &= ~r->mask;
135#ifdef DEBUG_EVENT_PERFORMANCE
143 if (
nmsg()->payload.size() != 8)
145 LOG(
INFO,
"Invalid input event message, payload length %d",
146 (
unsigned)
nmsg()->payload.size());
147 return release_and_exit();
157 rep->
mask = 0xFFFFFFFFFFFFFFFFULL;
162 case Defs::MTI_EVENT_REPORT:
173 rep->
state = EventState::UNKNOWN;
177 rep->
state = EventState::VALID;
181 rep->
state = EventState::INVALID;
185 rep->
state = EventState::RESERVED;
196 rep->
state = EventState::UNKNOWN;
200 rep->
state = EventState::VALID;
204 rep->
state = EventState::INVALID;
208 rep->
state = EventState::RESERVED;
214 LOG(
INFO,
"Invalid addressed identify all message, destination "
216 return release_and_exit();
227 DIE(
"Unexpected message arrived at the global event handler.");
235 return yield_and_call(
STATE(iterate_next));
258#ifdef DEBUG_EVENT_PERFORMANCE
275 return dispatch_event(
entry);
293InlineEventIteratorFlow::dispatch_event(
const EventRegistryEntry *entry)
299 return call_immediately(
STATE(iterate_next));
308 return call_immediately(
STATE(iterate_next));
313 return wait_and_call(
STATE(iterate_next));
#define STATE(_fn)
Turns a function name into an argument to be supplied to functions expecting a state.
BarrierNotifiable * reset(Notifiable *done)
Resets the barrier. Returns &*this. Asserts that is_done().
BarrierNotifiable * new_child()
Call this for each child task.
bool abort_if_almost_done()
Checks if there is exactly one outstanding notification left in the barrier.
void set_done(BarrierNotifiable *done)
Specifies that a given BarrierNotifiable must be called when the Buffer is deallocated (unreffed to z...
Base class for all QMember types that hold data in an expandable format.
T * data()
get a pointer to the start of the data.
void unregister_handler_all(HandlerType *handler)
Removes all instances of a handler from this dispatcher.
This class implements an execution of tasks pulled off an input queue.
virtual void notify()=0
Generic callback.
void alloc(Buffer< BufferType > **result, Executable *flow=NULL)
Get a free item out of the pool.
Collection of related state machines that pend on incoming messages.
static EventRegistry * instance()
Return type for a state flow callback.
void release() OVERRIDE
Unrefs the current buffer.
void send(MessageType *msg, unsigned priority=UINT_MAX) OVERRIDE
Sends a message to the state flow for processing.
virtual Action entry() OVERRIDE
Entry into the StateFlow activity.
virtual void handle_identify_global(const EventRegistryEntry ®istry_entry, EventReport *event, BarrierNotifiable *done)=0
Called on the need of sending out identification messages.
virtual void handle_consumer_range_identified(const EventRegistryEntry ®istry_entry, EventReport *event, BarrierNotifiable *done)
Called on another node sending ConsumerRangeIdentified.
virtual void handle_producer_range_identified(const EventRegistryEntry ®istry_entry, EventReport *event, BarrierNotifiable *done)
Called on another node sending ProducerRangeIdentified for this event.
virtual void handle_event_report(const EventRegistryEntry ®istry_entry, EventReport *event, BarrierNotifiable *done)=0
Called on incoming EventReport messages.
virtual void handle_identify_consumer(const EventRegistryEntry ®istry_entry, EventReport *event, BarrierNotifiable *done)=0
Called on another node sending IdentifyConsumer.
virtual void handle_producer_identified(const EventRegistryEntry ®istry_entry, EventReport *event, BarrierNotifiable *done)
Called on another node sending ProducerIdentified for this event.
virtual void handle_consumer_identified(const EventRegistryEntry ®istry_entry, EventReport *event, BarrierNotifiable *done)
Called on another node sending ConsumerIdentified for this event.
virtual void handle_identify_producer(const EventRegistryEntry ®istry_entry, EventReport *event, BarrierNotifiable *done)=0
Called on another node sending IdentifyProducer.
Flow to receive incoming messages of event protocol, and dispatch them to the registered event handle...
unsigned eventRegistryEpoch_
The epoch of the event registry at the start of the iteration.
uint8_t countEvents_
How many events' cost are accumulated so far.
long long numProcessNsec_
Accumulator of how many msec processingthe events took.
EventIterator * iterator_
Iterator for generating the event handlers from the registry.
Action entry() OVERRIDE
Entry into the StateFlow activity.
long long currentProcessStart_
When the processing of the current event started.
Notifiable * incomingDone_
This done notifiable holds a reference to the incoming message buffer.
EventReport eventReport_
Statically allocated structure for calling the event handlers from the main event queue.
virtual EventRegistryEntry * next_entry()=0
Steps the iteration.
virtual void clear_iteration()=0
Stops iteration and resets iteration variables.
virtual void init_iteration(EventReport *event)=0
Starts the iteration.
EventHandler * handler
Pointer to the handler.
PImpl class for the EventService.
std::unique_ptr< EventRegistry > registry
The implementation of the event registry.
std::vector< std::unique_ptr< StateFlowWithQueue > > ownedFlows_
Flows that we own.
EventCallerFlow callerFlow_
This flow will serialize calls to NMRAnetEventHandler objects.
bool event_processing_pending()
Returns true if there are outstanding events that are not yet handled.
EventService(ExecutorBase *e)
Creates a global event service with no interfaces registered.
void register_interface(If *iface)
Registers this global event handler with an interface.
Abstract class representing an OpenLCB Interface.
MessageDispatchFlow * dispatcher()
GenMessage * nmsg()
Returns the NMRAnet message we received.
Flow to receive incoming messages of event protocol, and dispatch them to the registered event handle...
const EventRegistryEntry * currentEntry_
The handler we need to call.
EventRegistry implementation that keeps event handlers in a SortedListMap and filters the event handl...
EventRegistry implementation that keeps all event handlers in a vector and forwards every single call...
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
static const int INFO
Loglevel that is printed by default, reporting some status information.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
#define DIE(MSG)
Unconditionally terminates the current process with a message.
uint64_t NetworkToEventID(const void *data)
Takes 8 bytes (big-endian) from *data, and returns the event id they represent.
long long os_get_time_monotonic(void)
Get the monotonic time since the system started.
@ MTI_CONSUMER_IDENTIFIED_INVALID
consumer broadcast, invalid state
@ MTI_PRODUCER_IDENTIFY
query about producers
@ MTI_EVENT_MASK
event number present mask
@ MTI_EVENTS_IDENTIFY_GLOBAL
request identify all of every node's events
@ MTI_CONSUMER_IDENTIFIED_RESERVED
reserved for future use
@ MTI_PRODUCER_IDENTIFIED_RANGE
producer broadcast about a range of producers
@ MTI_PRODUCER_IDENTIFIED_RESERVED
reserved for future use
@ MTI_CONSUMER_IDENTIFIED_UNKNOWN
consumer broadcast, validity unknown
@ MTI_PRODUCER_IDENTIFIED_VALID
producer broadcast, valid state
@ MTI_CONSUMER_IDENTIFY
query about consumers
@ MTI_EVENTS_IDENTIFY_ADDRESSED
request identify all of a node's events
@ MTI_PRODUCER_IDENTIFIED_INVALID
producer broadcast, invalid state
@ MTI_PRODUCER_IDENTIFIED_UNKNOWN
producer broadcast, validity unknown
@ MTI_CONSUMER_IDENTIFIED_VALID
consumer broadcast, valid state
@ MTI_CONSUMER_IDENTIFIED_RANGE
consumer broadcast about a range of consumers
Arguments structure for the EventCallerFlow.
Shared notification structure that is assembled for each incoming event-related message,...
EventId mask
Specifies the mask in case the request is for an event range.
EventState state
For producer/consumer identified messages, specifies the state of the producer/consumer as the sender...
NodeHandle src_node
Information about the sender of the incoming event-related OpenLCB message.
EventId event
The event ID from the incoming message.
Node * dst_node
nullptr for global messages; points to the specific virtual node for addressed events identify messag...
Node * dstNode
If the destination node is local, this value is non-NULL.
NodeHandle src
Source node.