Program Listing for File reactor.cc
↰ Return to documentation for file (lib/reactor.cc)
/*
* Copyright (C) 2019 TU Dresden
* All rights reserved.
*
* Authors:
* Christian Menard
*/
#include "reactor-cpp/reactor.hh"
#include "reactor-cpp/action.hh"
#include "reactor-cpp/assert.hh"
#include "reactor-cpp/environment.hh"
#include "reactor-cpp/logging.hh"
#include "reactor-cpp/port.hh"
#include "reactor-cpp/reaction.hh"
namespace reactor {
ReactorElement::ReactorElement(const std::string& name, ReactorElement::Type type, Reactor* container)
: name_(name)
, container_(container) {
reactor_assert(container != nullptr);
this->environment_ = container->environment(); // NOLINT container can be NULL
reactor_assert(this->environment_ != nullptr);
validate(this->environment_->phase() == Environment::Phase::Construction,
"Reactor elements can only be created during construction phase!");
// We need a reinterpret_cast here as the derived class is not yet created
// when this constructor is executed. dynamic_cast only works for
// completely constructed objects. Technically, the casts here return
// invalid pointers as the objects they point to do not yet
// exists. However, we are good as long as we only store the pointer and do
// not dereference it before construction is completeted.
// It works, but maybe there is some nicer way of doing this...
switch (type) {
case Type::Action:
container->register_action(reinterpret_cast<BaseAction*>(this)); // NOLINT
break;
case Type::Input:
container->register_input(reinterpret_cast<BasePort*>(this)); // NOLINT
break;
case Type::Output:
container->register_output(reinterpret_cast<BasePort*>(this)); // NOLINT
break;
case Type::Reaction:
container->register_reaction(reinterpret_cast<Reaction*>(this)); // NOLINT
break;
case Type::Reactor:
container->register_reactor(reinterpret_cast<Reactor*>(this)); // NOLINT
break;
default:
throw std::runtime_error("unexpected type");
}
std::stringstream string_stream;
string_stream << container_->fqn() << '.' << name;
fqn_ = string_stream.str();
}
ReactorElement::ReactorElement(const std::string& name, ReactorElement::Type type, Environment* environment)
: name_(name)
, fqn_(name)
, environment_(environment) {
reactor_assert(environment != nullptr);
validate(type == Type::Reactor, "Only reactors can be owned by the environment!");
validate(environment_->phase() == Environment::Phase::Construction, "Wrong Phase");
}
Reactor::Reactor(const std::string& name, Reactor* container)
: ReactorElement(name, ReactorElement::Type::Reactor, container) {}
Reactor::Reactor(const std::string& name, Environment* environment)
: ReactorElement(name, ReactorElement::Type::Reactor, environment) {
environment->register_reactor(this);
}
void Reactor::register_action([[maybe_unused]] BaseAction* action) {
reactor_assert(action != nullptr);
reactor::validate(this->environment()->phase() == Environment::Phase::Construction,
"Actions can only be registered during construction phase!");
reactor_assert(actions_.insert(action).second);
}
void Reactor::register_input(BasePort* port) {
reactor_assert(port != nullptr);
reactor::validate(this->environment()->phase() == Environment::Phase::Construction,
"Ports can only be registered during construction phase!");
reactor_assert(inputs_.insert(port).second);
}
void Reactor::register_output(BasePort* port) {
reactor_assert(port != nullptr);
reactor::validate(this->environment()->phase() == Environment::Phase::Construction,
"Ports can only be registered during construction phase!");
reactor_assert(outputs_.insert(port).second);
}
void Reactor::register_reaction([[maybe_unused]] Reaction* reaction) {
reactor_assert(reaction != nullptr);
validate(this->environment()->phase() == Environment::Phase::Construction,
"Reactions can only be registered during construction phase!");
reactor_assert(reactions_.insert(reaction).second);
}
void Reactor::register_reactor([[maybe_unused]] Reactor* reactor) {
reactor_assert(reactor != nullptr);
validate(this->environment()->phase() == Environment::Phase::Construction,
"Reactions can only be registered during construction phase!");
reactor_assert(reactors_.insert(reactor).second);
}
void Reactor::startup() {
reactor_assert(environment()->phase() == Environment::Phase::Startup);
log::Debug() << "Starting up reactor " << fqn();
// call startup on all contained objects
for (auto* base_action : actions_) {
base_action->startup();
}
for (auto* base_port : inputs_) {
base_port->startup();
}
for (auto* base_port : outputs_) {
base_port->startup();
}
for (auto* reaction : reactions_) {
reaction->startup();
}
for (auto* reactor : reactors_) {
reactor->startup();
}
}
void Reactor::shutdown() {
reactor_assert(environment()->phase() == Environment::Phase::Shutdown);
log::Debug() << "Terminating reactor " << fqn();
// call shutdown on all contained objects
for (auto* action : actions_) {
action->shutdown();
}
for (auto* base_port : inputs_) {
base_port->shutdown();
}
for (auto* base_port : outputs_) {
base_port->shutdown();
}
for (auto* reaction : reactions_) {
reaction->shutdown();
}
for (auto* reactor : reactors_) {
reactor->shutdown();
}
}
auto Reactor::get_physical_time() noexcept -> TimePoint { return reactor::get_physical_time(); }
auto Reactor::get_logical_time() const noexcept -> TimePoint {
return environment()->scheduler()->logical_time().time_point();
}
auto Reactor::get_microstep() const noexcept -> mstep_t {
return environment()->scheduler()->logical_time().micro_step();
}
auto Reactor::get_tag() const noexcept -> Tag {
return Tag::from_logical_time(environment()->scheduler()->logical_time());
}
auto Reactor::get_elapsed_logical_time() const noexcept -> Duration {
return get_logical_time() - environment()->start_time();
}
auto Reactor::get_elapsed_physical_time() const noexcept -> Duration {
return get_physical_time() - environment()->start_time();
}
} // namespace reactor