Skip to content

Commit

Permalink
wip: Refactor in order to add probe command
Browse files Browse the repository at this point in the history
  • Loading branch information
cassava committed Jun 25, 2024
1 parent f8935a2 commit 63c7e34
Show file tree
Hide file tree
Showing 50 changed files with 3,163 additions and 1,959 deletions.
33 changes: 31 additions & 2 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,36 @@ add_library(cloe-enginelib STATIC
src/simulation.hpp
src/simulation_context.cpp
src/simulation_context.hpp
src/simulation_actions.hpp
src/simulation_events.hpp
src/simulation_outcome.hpp
src/simulation_result.hpp
src/simulation_probe.hpp
src/simulation_statistics.hpp
src/simulation_sync.hpp
src/simulation_progress.hpp
src/simulation_machine.hpp
src/simulation_state_abort.cpp
src/simulation_state_connect.cpp
src/simulation_state_disconnect.cpp
src/simulation_state_fail.cpp
src/simulation_state_keep_alive.cpp
src/simulation_state_pause.cpp
src/simulation_state_probe.cpp
src/simulation_state_reset.cpp
src/simulation_state_resume.cpp
src/simulation_state_start.cpp
src/simulation_state_step_begin.cpp
src/simulation_state_step_controllers.cpp
src/simulation_state_step_end.cpp
src/simulation_state_step_simulators.cpp
src/simulation_state_stop.cpp
src/simulation_state_success.cpp
src/utility/command.cpp
src/utility/command.hpp
src/utility/defer.hpp
src/utility/progress.hpp
src/utility/state_machine.hpp
src/utility/time_event.hpp
)
add_library(cloe::enginelib ALIAS cloe-enginelib)
set_target_properties(cloe-enginelib PROPERTIES
Expand Down Expand Up @@ -172,6 +195,10 @@ if(BUILD_TESTING)
src/lua_stack_test.cpp
src/lua_setup_test.cpp
)
target_compile_definitions(test-enginelib
PRIVATE
CLOE_LUA_PATH="${CMAKE_CURRENT_SOURCE_DIR}/lua"
)
set_target_properties(test-enginelib PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
Expand All @@ -193,11 +220,13 @@ add_subdirectory(vendor/linenoise)
add_executable(cloe-engine
src/main.cpp
src/main_commands.hpp
src/main_commands.cpp
src/main_check.cpp
src/main_dump.cpp
src/main_probe.cpp
src/main_run.cpp
src/main_usage.cpp
src/main_shell.cpp
src/main_usage.cpp
src/main_version.cpp
)
set_target_properties(cloe-engine PROPERTIES
Expand Down
18 changes: 18 additions & 0 deletions engine/src/coordinator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,24 @@ std::shared_ptr<cloe::TriggerRegistrar> Coordinator::trigger_registrar(Source s)
return std::make_shared<TriggerRegistrar>(*this, s);
}

[[nodiscard]] std::vector<std::string> Coordinator::trigger_action_names() const {
std::vector<std::string> results;
results.reserve(actions_.size());
for (const auto& [key, _] : actions_) {
results.emplace_back(key);
}
return results;
}

[[nodiscard]] std::vector<std::string> Coordinator::trigger_event_names() const {
std::vector<std::string> results;
results.reserve(events_.size());
for (const auto& [key, _] : events_) {
results.emplace_back(key);
}
return results;
}

void Coordinator::enroll(Registrar& r) {
// clang-format off
r.register_api_handler("/triggers/actions", HandlerType::STATIC,
Expand Down
32 changes: 21 additions & 11 deletions engine/src/coordinator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ class TriggerUnknownAction : public cloe::TriggerInvalid {
public:
TriggerUnknownAction(const std::string& key, const cloe::Conf& c)
: TriggerInvalid(c, "unknown action: " + key), key_(key) {}
virtual ~TriggerUnknownAction() noexcept = default;
~TriggerUnknownAction() noexcept override = default;

/**
* Return key that is unknown.
*/
const char* key() const { return key_.c_str(); }
[[nodiscard]] const char* key() const { return key_.c_str(); }

private:
std::string key_;
Expand All @@ -73,7 +73,7 @@ class TriggerUnknownEvent : public cloe::TriggerInvalid {
/**
* Return key that is unknown.
*/
const char* key() const { return key_.c_str(); }
[[nodiscard]] const char* key() const { return key_.c_str(); }

private:
std::string key_;
Expand Down Expand Up @@ -107,15 +107,25 @@ class Coordinator {
void register_event(const std::string& key, cloe::EventFactoryPtr&& ef,
std::shared_ptr<cloe::Callback> storage);

sol::table register_lua_table(const std::string& field);
[[nodiscard]] sol::table register_lua_table(const std::string& field);

cloe::DataBroker* data_broker() const { return db_; }
[[nodiscard]] cloe::DataBroker* data_broker() const { return db_; }

std::shared_ptr<cloe::TriggerRegistrar> trigger_registrar(cloe::Source s);

void enroll(cloe::Registrar& r);

cloe::Logger logger() const { return cloe::logger::get("cloe"); }
[[nodiscard]] cloe::Logger logger() const { return cloe::logger::get("cloe"); }

/**
* Return a list of names of all available actions that have been enrolled.
*/
[[nodiscard]] std::vector<std::string> trigger_action_names() const;

/**
* Return a list of names of all available events that have been enrolled.
*/
[[nodiscard]] std::vector<std::string> trigger_event_names() const;

/**
* Process any incoming triggers, clear the buffer, and trigger time-based
Expand All @@ -130,11 +140,11 @@ class Coordinator {
void execute_action_from_lua(const cloe::Sync& sync, const sol::object& obj);

protected:
cloe::ActionPtr make_action(const sol::object& lua) const;
cloe::ActionPtr make_action(const cloe::Conf& c) const;
cloe::EventPtr make_event(const cloe::Conf& c) const;
cloe::TriggerPtr make_trigger(cloe::Source s, const cloe::Conf& c) const;
cloe::TriggerPtr make_trigger(const sol::table& tbl) const;
[[nodiscard]] cloe::ActionPtr make_action(const sol::object& lua) const;
[[nodiscard]] cloe::ActionPtr make_action(const cloe::Conf& c) const;
[[nodiscard]] cloe::EventPtr make_event(const cloe::Conf& c) const;
[[nodiscard]] cloe::TriggerPtr make_trigger(cloe::Source s, const cloe::Conf& c) const;
[[nodiscard]] cloe::TriggerPtr make_trigger(const sol::table& tbl) const;
void queue_trigger(cloe::Source s, const cloe::Conf& c) { queue_trigger(make_trigger(s, c)); }
void queue_trigger(cloe::TriggerPtr&& tp);
void store_trigger(cloe::TriggerPtr&& tp, const cloe::Sync& sync);
Expand Down
11 changes: 9 additions & 2 deletions engine/src/lua_setup_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,24 @@
#include "stack.hpp" // for Stack
using namespace cloe; // NOLINT(build/namespaces)

#ifndef CLOE_LUA_PATH
#error "require CLOE_LUA_PATH to be defined in order to find lua directory"
#endif

class cloe_lua_setup : public testing::Test {
std::vector<std::filesystem::path> defer_deletion_;

protected:
sol::state lua_state;
sol::state_view lua;
LuaOptions opt;
Stack stack;

std::vector<std::filesystem::path> defer_deletion_;

cloe_lua_setup() : lua(lua_state.lua_state()) {
opt.environment = std::make_unique<fable::Environment>();
#ifdef CLOE_LUA_PATH
opt.lua_paths.emplace_back(CLOE_LUA_PATH);
#endif
}

std::filesystem::path WriteTempLuaFile(std::string_view content) {
Expand Down
2 changes: 2 additions & 0 deletions engine/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ int main(int argc, char** argv) {
return engine::dump(with_global_options(dump_options), dump_files);
} else if (*check) {
return engine::check(with_global_options(check_options), check_files);
} else if (*probe) {
return engine::probe(with_global_options(probe_options), probe_files);
} else if (*run) {
return engine::run(with_global_options(run_options), run_files);
} else if (*shell) {
Expand Down
135 changes: 135 additions & 0 deletions engine/src/main_commands.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Copyright 2024 Robert Bosch GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* \file main_commands.cpp
*/

#include "main_commands.hpp"

#include <csignal> // for signal
#include <cstdlib> // for getenv
#include <iostream> // for cerr
#include <tuple> // for tuple

// NOTE: Unfortunately, <boost/uuid/uuid_generators.hpp> includes Boost headers
// that make use of deprecated headers. This is fixed in Boost 1.70.0, but
// we still need to support earlier versions of Boost.
#define BOOST_ALLOW_DEPRECATED_HEADERS

#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp> // for lexical_cast
#include <boost/uuid/uuid_generators.hpp> // for random_generator
#include <boost/uuid/uuid_io.hpp>

#include <cloe/core.hpp> // for logger::get
#include <fable/utility.hpp> // for read_conf

#include "error_handler.hpp" // for conclude_error
#include "simulation.hpp" // for Simulation
#include "stack.hpp" // for Stack

namespace engine {

// We need a global instance so that our signal handler has access to it.
Simulation* GLOBAL_SIMULATION_INSTANCE{nullptr}; // NOLINT

void handle_signal(int sig) {
static size_t interrupts = 0;
switch (sig) {
case SIGSEGV:
case SIGABRT:
abort();
break;
case SIGINT:
default:
std::cerr << "\n" << std::flush; // print newline so that ^C is on its own line
if (++interrupts == 3) {
std::ignore = std::signal(sig, SIG_DFL); // third time goes to the default handler
}
if (GLOBAL_SIMULATION_INSTANCE != nullptr) {
GLOBAL_SIMULATION_INSTANCE->signal_abort();
}
break;
}
}

// Set the UUID of the simulation:
template <typename Options>
std::string handle_uuid_impl(const Options& opt) {
std::string uuid;
if (!opt.uuid.empty()) {
uuid = opt.uuid;
} else if (std::getenv(CLOE_SIMULATION_UUID_VAR) != nullptr) {
uuid = std::getenv(CLOE_SIMULATION_UUID_VAR);
} else {
uuid = boost::lexical_cast<std::string>(boost::uuids::random_generator()());
}
opt.stack_options.environment->set(CLOE_SIMULATION_UUID_VAR, uuid);
return uuid;
}

std::string handle_uuid(const RunOptions& opt) { return handle_uuid_impl(opt); }

std::string handle_uuid(const ProbeOptions& opt) { return handle_uuid_impl(opt); }

template <typename Options>
std::tuple<cloe::Stack, sol::state> handle_config_impl(const Options& opt,
const std::vector<std::string>& filepaths) {
assert(opt.output != nullptr && opt.error != nullptr);
auto log = cloe::logger::get("cloe");
cloe::logger::get("cloe")->info("Cloe {}", CLOE_ENGINE_VERSION);

// Load the stack file:
sol::state lua_state;
sol::state_view lua_view(lua_state.lua_state());
cloe::Stack stack = cloe::new_stack(opt.stack_options);
cloe::setup_lua(lua_view, opt.lua_options, stack);
#if CLOE_ENGINE_WITH_LRDB
if (opt.debug_lua) {
log->info("Lua debugger listening at port: {}", opt.debug_lua_port);
cloe::start_lua_debugger(lua_view, opt.debug_lua_port);
}
#else
if (opt.debug_lua) {
log->error("Lua debugger feature not available.");
}
#endif
cloe::conclude_error(*opt.stack_options.error, [&]() {
for (const auto& file : filepaths) {
if (boost::algorithm::ends_with(file, ".lua")) {
cloe::merge_lua(lua_view, file);
} else {
cloe::merge_stack(opt.stack_options, stack, file);
}
}
});

return {std::move(stack), std::move(lua_state)};
}

std::tuple<cloe::Stack, sol::state> handle_config(
const RunOptions& opt, const std::vector<std::string>& filepaths) {
return handle_config_impl(opt, filepaths);
}

std::tuple<cloe::Stack, sol::state> handle_config(
const ProbeOptions& opt, const std::vector<std::string>& filepaths) {
return handle_config_impl(opt, filepaths);
}

} // namespace engine
30 changes: 29 additions & 1 deletion engine/src/main_commands.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,14 @@ struct ProbeOptions {
std::ostream* output = &std::cout;
std::ostream* error = &std::cerr;

// Options
std::string uuid; // Not currently used.

// Flags:
int json_indent = 2;

bool debug_lua = false; // Not currently used.
int debug_lua_port = CLOE_LUA_DEBUGGER_PORT; // Not currently used.
};

int probe(const ProbeOptions& opt, const std::vector<std::string>& filepaths);
Expand All @@ -89,7 +95,6 @@ struct RunOptions {
bool write_output = true;
bool require_success = false;
bool report_progress = true;
bool probe_simulation = false;

bool debug_lua = false;
int debug_lua_port = CLOE_LUA_DEBUGGER_PORT;
Expand Down Expand Up @@ -140,4 +145,27 @@ struct VersionOptions {

int version(const VersionOptions& opt);

// ------------------------------------------------------------------------- //

class Simulation;

extern Simulation* GLOBAL_SIMULATION_INSTANCE; // NOLINT

/**
* Handle interrupt signals sent by the operating system.
*
* When this function is called, it cannot call any other functions that
* might have set any locks, because it might not get the lock, and then the
* program hangs instead of gracefully exiting. It's a bit sad, true, but
* that's the way it is.
*
* That is why you cannot make use of the logging in this function. You also
* cannot make use of triggers, because they also have a lock.
*
* The function immediately resets the signal handler to the default provided
* by the standard library, so that in the case that we do hang for some
* reasons, the user can force abort by sending the signal a third time.
*/
void handle_signal(int sig);

} // namespace engine
Loading

0 comments on commit 63c7e34

Please sign in to comment.