Commit e9befac2 authored by Paul Schütze's avatar Paul Schütze
Browse files

Merge branch 'messaging' into 'master'

Messaging Improvements: Self-Dispatch, UNNAMED_ONLY

Closes #167

See merge request allpix-squared/allpix-squared!576
parents 8630612a 4f58dd90
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -497,12 +497,19 @@ bool filter(std::shared_ptr<Message<Object>> message) const {
}
\end{minted}
\end{enumerate}
It should be noted that the \command{registerFilter} function by default adds the \parameter{IGNORE_NAME} message flag to receive all available messages if called without the message flag parameter:
\begin{minted}[frame=single,framesep=3pt,breaklines=true,tabsize=2,linenos]{c++}
messenger->registerFilter(this, &TestModule::filter);
\end{minted}
This means that a possibly set \parameter{input} parameter of the respective module has no effect.
If this behavior is undesired, the filter should be registered explicitly stating the desired message flags or \parameter{MsgFlags::NONE}.
The available message flags are described in detail in the following section.

\subsection{Message flags}
\label{sec:messageflags}
Flags can be added to the bind and listening methods which enable a particular behavior of the framework.
\begin{itemize}
    \item \textbf{REQUIRED}: Specifies that this message is required during the event processing.
    \item \parameter{REQUIRED}: Specifies that this message is required during the event processing.
    If this particular message is not received before it is time to execute the module's run function, the execution of the method is automatically skipped by the framework for the current event.
    This can be used to ignore modules which cannot perform any action without received messages, for example charge carrier propagation without any deposited charge carriers.
    \item \parameter{ALLOW_OVERWRITE}: By default an exception is automatically raised if a single bound message is overwritten (thus receiving it multiple times instead of once).
@@ -510,6 +517,8 @@ Flags can be added to the bind and listening methods which enable a particular b
    It can only be used for variables bound to a single message.
    \item \parameter{IGNORE_NAME}: If this flag is specified, the name of the dispatched message is not considered.
    Thus, the \parameter{input} parameter is ignored and forced to the value \texttt{*}.
    \item \parameter{UNNAMED_ONLY}: If this flag is specified, the module will only receive messages without explicit name.
    The \parameter{input} parameter is ignored and forced to the value \texttt{?} and all named messages are discarded. It should be noted that \parameter{IGNORE_NAME} takes precedence over this parameter.
\end{itemize}

\subsection{Persistency}
+18 −8
Original line number Diff line number Diff line
@@ -32,12 +32,15 @@ Messenger::~Messenger() {
}
#endif

// Check if the detectors match for the message and the delegate
static bool check_send(BaseMessage* message, BaseDelegate* delegate) {
// Check if the detectors match for the message and the delegate and that we don't have self-dispatch
static bool check_send(Module* source, BaseMessage* message, BaseDelegate* delegate) {
    if(delegate->getDetector() != nullptr &&
       (message->getDetector() == nullptr || delegate->getDetector()->getName() != message->getDetector()->getName())) {
        return false;
    }
    if(delegate->getUniqueName() == source->getUniqueName()) {
        return false;
    }
    return true;
}

@@ -55,25 +58,25 @@ bool Messenger::hasReceiver(Module* source, const std::shared_ptr<BaseMessage>&

    // Check if a normal specific listener exists
    for(auto& delegate : delegates_[type_idx][name]) {
        if(check_send(message.get(), delegate.get())) {
        if(check_send(source, message.get(), delegate.get())) {
            return true;
        }
    }
    // Check if a normal generic listener exists
    for(auto& delegate : delegates_[type_idx]["*"]) {
        if(check_send(message.get(), delegate.get())) {
        if(check_send(source, message.get(), delegate.get())) {
            return true;
        }
    }
    // Check if a base message specific listener exists
    for(auto& delegate : delegates_[typeid(BaseMessage)][name]) {
        if(check_send(message.get(), delegate.get())) {
        if(check_send(source, message.get(), delegate.get())) {
            return true;
        }
    }
    // Check if a base message generic listener exists
    for(auto& delegate : delegates_[typeid(BaseMessage)]["*"]) {
        if(check_send(message.get(), delegate.get())) {
        if(check_send(source, message.get(), delegate.get())) {
            return true;
        }
    }
@@ -95,6 +98,8 @@ void Messenger::add_delegate(const std::type_info& message_type,
    std::string message_name;
    if((delegate->getFlags() & MsgFlags::IGNORE_NAME) != MsgFlags::NONE) {
        message_name = "*";
    } else if((delegate->getFlags() & MsgFlags::UNNAMED_ONLY) != MsgFlags::NONE) {
        message_name = "?";
    } else {
        message_name = module->get_configuration().get<std::string>("input");
    }
@@ -150,6 +155,11 @@ void LocalMessenger::dispatchMessage(Module* source, std::shared_ptr<BaseMessage
    // Send to generic listeners
    send = dispatchMessage(source, message, name, "*") || send;

    // Send to listeners of unnamed messages
    if(name.empty()) {
        send = dispatchMessage(source, message, name, "?") || send;
    }

    // Display a TRACE log message if the message is send to no receiver
    if(!send) {
        const BaseMessage* inst = message.get();
@@ -178,7 +188,7 @@ bool LocalMessenger::dispatchMessage(Module* source,
        if(msg_name_iterator != msg_type_iterator->second.end()) {
            // Send messages only to their specific listeners
            for(const auto& delegate : msg_name_iterator->second) {
                if(check_send(message.get(), delegate.get())) {
                if(check_send(source, message.get(), delegate.get())) {
                    LOG(TRACE) << "Sending message " << allpix::demangle(type_idx.name()) << " from "
                               << source->getUniqueName() << " to " << delegate->getUniqueName();
                    // Construct BaseMessage where message should be stored
@@ -198,7 +208,7 @@ bool LocalMessenger::dispatchMessage(Module* source,
        const auto msg_name_iterator = base_msg_type_iterator->second.find(id);
        if(msg_name_iterator != base_msg_type_iterator->second.end()) {
            for(const auto& delegate : msg_name_iterator->second) {
                if(check_send(message.get(), delegate.get())) {
                if(check_send(source, message.get(), delegate.get())) {
                    LOG(TRACE) << "Sending message " << allpix::demangle(type_idx.name()) << " from "
                               << source->getUniqueName() << " to generic listener " << delegate->getUniqueName();
                    auto& dest = messages_[delegate->getUniqueName()][typeid(BaseMessage)];
+2 −1
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ namespace allpix {
        NONE = 0,                   ///< No enabled flags
        REQUIRED = (1 << 0),        ///< Require a message before running a module
        ALLOW_OVERWRITE = (1 << 1), ///< Allow overwriting a previous message
        IGNORE_NAME = (1 << 2)      ///< Listen to all ignoring message name (equal to * as a input configuration parameter)
        IGNORE_NAME = (1 << 2),     ///< Listen to all ignoring message name (equal to * as a input configuration parameter)
        UNNAMED_ONLY = (1 << 3)     ///< Listen to all messages without explicit name (equal to ? as configuration parameter)
    };
    /**
     * @ingroup Delegates