|
@@ -1,32 +1,78 @@
|
|
|
#include "sophiar_pool.h"
|
|
#include "sophiar_pool.h"
|
|
|
#include "core/basic_obj_types.hpp"
|
|
#include "core/basic_obj_types.hpp"
|
|
|
|
|
+#include "core/global_defs.h"
|
|
|
#include "utility/config_utility.hpp"
|
|
#include "utility/config_utility.hpp"
|
|
|
#include "utility/named_vector.hpp"
|
|
#include "utility/named_vector.hpp"
|
|
|
#include "utility/string_map.hpp"
|
|
#include "utility/string_map.hpp"
|
|
|
#include "utility/versatile_buffer2.hpp"
|
|
#include "utility/versatile_buffer2.hpp"
|
|
|
|
|
|
|
|
|
|
+#include <boost/asio/co_spawn.hpp>
|
|
|
|
|
+#include <boost/asio/post.hpp>
|
|
|
|
|
+
|
|
|
|
|
+#include <list>
|
|
|
#include <vector>
|
|
#include <vector>
|
|
|
#include <unordered_map>
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
|
|
+using boost::asio::co_spawn;
|
|
|
|
|
+using boost::asio::post;
|
|
|
|
|
+
|
|
|
namespace sophiar {
|
|
namespace sophiar {
|
|
|
|
|
|
|
|
struct sophiar_pool::impl {
|
|
struct sophiar_pool::impl {
|
|
|
|
|
|
|
|
|
|
+ struct variable_info_impl;
|
|
|
|
|
+ struct callback_info;
|
|
|
|
|
+
|
|
|
|
|
+ using callback_queue_type = std::list<callback_info *>;
|
|
|
|
|
+ using callback_queue_iter_type = callback_queue_type::iterator;
|
|
|
|
|
+
|
|
|
|
|
+ struct attach_info {
|
|
|
|
|
+ variable_info_impl *var_info = nullptr;
|
|
|
|
|
+ callback_info *callback = nullptr;
|
|
|
|
|
+ void *callback_list_iter = nullptr; // callback_list_iter_type
|
|
|
|
|
+ void *attach_iter = nullptr; // attach_iter_type
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ using attach_list_type = std::list<attach_info>;
|
|
|
|
|
+ using attach_iter_type = attach_list_type::iterator;
|
|
|
|
|
+ static_assert(sizeof(attach_iter_type) == sizeof(void *));
|
|
|
|
|
+ static_assert(sizeof(attach_iter_type) == sizeof(attach_token_type));
|
|
|
|
|
+
|
|
|
|
|
+ struct callback_info {
|
|
|
|
|
+ enum status_type {
|
|
|
|
|
+ IDLE, PENDING, RUNNING
|
|
|
|
|
+ } status = IDLE;
|
|
|
|
|
+
|
|
|
|
|
+ using callback_store_type = std::variant<function_callback_type, coroutine_callback_type>;
|
|
|
|
|
+ callback_store_type func_store;
|
|
|
|
|
+ attach_list_type attach_list;
|
|
|
|
|
+ callback_queue_iter_type queue_iter;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ using callback_pool_type = std::list<callback_info>;
|
|
|
|
|
+ using callback_iter_type = callback_pool_type::iterator;
|
|
|
|
|
+ static_assert(sizeof(callback_iter_type) == sizeof(callback_token_type));
|
|
|
|
|
+
|
|
|
|
|
+ using callback_list_type = std::list<callback_info *>;
|
|
|
|
|
+ using callback_list_iter_type = callback_list_type::iterator;
|
|
|
|
|
+ static_assert(sizeof(callback_list_iter_type) == sizeof(void *));
|
|
|
|
|
+
|
|
|
struct variable_type_info {
|
|
struct variable_type_info {
|
|
|
std::type_index type = typeid(void);
|
|
std::type_index type = typeid(void);
|
|
|
- variable_type_index_type type_index;
|
|
|
|
|
|
|
+ variable_type_index_type type_index = -1;
|
|
|
std::string type_name;
|
|
std::string type_name;
|
|
|
|
|
|
|
|
// function list
|
|
// function list
|
|
|
using creator_func_type = void *(*)(const nlohmann::json &);
|
|
using creator_func_type = void *(*)(const nlohmann::json &);
|
|
|
- creator_func_type creator_func;
|
|
|
|
|
|
|
+ creator_func_type creator_func = nullptr;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
struct variable_info_impl {
|
|
struct variable_info_impl {
|
|
|
- void *placeholder;
|
|
|
|
|
- coro_signal2 *update_signal;
|
|
|
|
|
- const variable_type_info *type_info;
|
|
|
|
|
- timestamp_type last_update_ts;
|
|
|
|
|
|
|
+ void *placeholder = nullptr;
|
|
|
|
|
+ coro_signal2 *update_signal = nullptr;
|
|
|
|
|
+ const variable_type_info *type_info = nullptr;
|
|
|
|
|
+ timestamp_type last_update_ts = 0;
|
|
|
|
|
+ callback_list_type callback_list;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
string_map<variable_type_index_type> variable_type_name_index_map; // typename -> index
|
|
string_map<variable_type_index_type> variable_type_name_index_map; // typename -> index
|
|
@@ -34,6 +80,9 @@ namespace sophiar {
|
|
|
std::vector<variable_type_info> variable_type_info_pool;
|
|
std::vector<variable_type_info> variable_type_info_pool;
|
|
|
|
|
|
|
|
named_vector<variable_index_type, variable_info_impl> variable_pool;
|
|
named_vector<variable_index_type, variable_info_impl> variable_pool;
|
|
|
|
|
+ callback_pool_type callback_pool;
|
|
|
|
|
+ callback_queue_type callback_queue;
|
|
|
|
|
+ bool is_callback_handler_active = false;
|
|
|
|
|
|
|
|
template<typename SmallObjType>
|
|
template<typename SmallObjType>
|
|
|
static void *create_variable_pointer(const nlohmann::json &config) {
|
|
static void *create_variable_pointer(const nlohmann::json &config) {
|
|
@@ -108,6 +157,76 @@ namespace sophiar {
|
|
|
info.last_update_ts = 0;
|
|
info.last_update_ts = 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ callback_token_type register_callback(callback_info::callback_store_type &&callback) {
|
|
|
|
|
+ auto &item = callback_pool.emplace_front();
|
|
|
|
|
+ item.func_store = std::move(callback);
|
|
|
|
|
+ return std::bit_cast<callback_token_type>(callback_pool.begin());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void unregister_callback(callback_iter_type callback) {
|
|
|
|
|
+ while (!callback->attach_list.empty()) {
|
|
|
|
|
+ detach_callback(callback->attach_list.begin());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (callback->status == callback_info::PENDING) {
|
|
|
|
|
+ callback_queue.erase(callback->queue_iter);
|
|
|
|
|
+ }
|
|
|
|
|
+ callback_pool.erase(callback);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ attach_token_type attach_callback(variable_index_type var_index, callback_iter_type callback) {
|
|
|
|
|
+ auto &var_info = variable_pool[var_index];
|
|
|
|
|
+ var_info.callback_list.push_front(&(*callback));
|
|
|
|
|
+
|
|
|
|
|
+ auto &attach_item = callback->attach_list.emplace_front();
|
|
|
|
|
+ attach_item.var_info = &var_info;
|
|
|
|
|
+ attach_item.callback = &(*callback);
|
|
|
|
|
+ attach_item.callback_list_iter = std::bit_cast<void *>(var_info.callback_list.begin());
|
|
|
|
|
+ attach_item.attach_iter = std::bit_cast<void *>(callback->attach_list.begin());
|
|
|
|
|
+ return std::bit_cast<attach_token_type>(callback->attach_list.begin());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ static void detach_callback(attach_iter_type iter) {
|
|
|
|
|
+ auto callback_iter = std::bit_cast<callback_list_iter_type>(iter->callback_list_iter);
|
|
|
|
|
+ auto attach_iter = std::bit_cast<attach_iter_type>(iter->attach_iter);
|
|
|
|
|
+ iter->var_info->callback_list.erase(callback_iter);
|
|
|
|
|
+ iter->callback->attach_list.erase(attach_iter);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void handle_callback_func() {
|
|
|
|
|
+ while (!callback_queue.empty()) {
|
|
|
|
|
+ auto callback = callback_queue.back();
|
|
|
|
|
+ callback_queue.pop_back();
|
|
|
|
|
+ callback->status = callback_info::RUNNING;
|
|
|
|
|
+ callback->queue_iter = {};
|
|
|
|
|
+ if (callback->func_store.index() == 0) {
|
|
|
|
|
+ std::get<0>(callback->func_store)();
|
|
|
|
|
+ callback->status = callback_info::IDLE;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ assert(callback->func_store.index() == 1);
|
|
|
|
|
+ co_spawn(*global_context, std::get<1>(callback->func_store)(), [=](std::exception_ptr eptr) {
|
|
|
|
|
+ assert(eptr == nullptr);
|
|
|
|
|
+ callback->status = callback_info::IDLE;
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ is_callback_handler_active = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void trigger_callback(variable_info_impl *var_info) {
|
|
|
|
|
+ if (var_info->callback_list.empty()) return;
|
|
|
|
|
+ bool has_callback = false;
|
|
|
|
|
+ for (auto &callback: var_info->callback_list) {
|
|
|
|
|
+ if (callback->status != callback_info::IDLE) continue;
|
|
|
|
|
+ callback_queue.push_front(callback);
|
|
|
|
|
+ callback->status = callback_info::PENDING;
|
|
|
|
|
+ callback->queue_iter = callback_queue.begin();
|
|
|
|
|
+ has_callback = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!has_callback || is_callback_handler_active) return;
|
|
|
|
|
+ post(*global_context, [this]() { handle_callback_func(); });
|
|
|
|
|
+ is_callback_handler_active = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
void load_config(const nlohmann::json &config) {
|
|
void load_config(const nlohmann::json &config) {
|
|
|
|
|
|
|
|
#ifdef SOPHIAR_TEST
|
|
#ifdef SOPHIAR_TEST
|
|
@@ -186,12 +305,34 @@ namespace sophiar {
|
|
|
assert(ts > info.last_update_ts);
|
|
assert(ts > info.last_update_ts);
|
|
|
info.last_update_ts = ts;
|
|
info.last_update_ts = ts;
|
|
|
info.update_signal->try_notify_all(ts);
|
|
info.update_signal->try_notify_all(ts);
|
|
|
|
|
+ pimpl->trigger_callback(&info);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void sophiar_pool::load_config(const nlohmann::json &config) {
|
|
void sophiar_pool::load_config(const nlohmann::json &config) {
|
|
|
pimpl->load_config(config);
|
|
pimpl->load_config(config);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ sophiar_pool::callback_token_type sophiar_pool::register_callback(function_callback_type &&callback) {
|
|
|
|
|
+ return pimpl->register_callback(std::move(callback));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sophiar_pool::callback_token_type sophiar_pool::register_coro_callback(coroutine_callback_type &&callback) {
|
|
|
|
|
+ return pimpl->register_callback(std::move(callback));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void sophiar_pool::unregister_callback(callback_token_type token) {
|
|
|
|
|
+ return pimpl->unregister_callback(std::bit_cast<impl::callback_iter_type>(token));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sophiar_pool::attach_token_type sophiar_pool::attach_callback(variable_index_type var_index,
|
|
|
|
|
+ callback_token_type token) {
|
|
|
|
|
+ return pimpl->attach_callback(var_index, std::bit_cast<impl::callback_iter_type>(token));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void sophiar_pool::detach_callback(attach_token_type token) {
|
|
|
|
|
+ return pimpl->detach_callback(std::bit_cast<impl::attach_iter_type>(token));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
sophiar_pool::~sophiar_pool() = default;
|
|
sophiar_pool::~sophiar_pool() = default;
|
|
|
|
|
|
|
|
#ifdef SOPHIAR_TEST
|
|
#ifdef SOPHIAR_TEST
|