diff --git a/tai_mux/README.md b/tai_mux/README.md index cb75e45..5366499 100644 --- a/tai_mux/README.md +++ b/tai_mux/README.md @@ -16,7 +16,9 @@ modules and decides which `libtai.so` to use for detected modules. platform adapter. User can choose which platform adapter to use by passing an environment variable `TAI_MUX_PLATFORM_ADAPTER`. -Currently, only `static` platform adapter is supported. +Currently, `static` platform adapter and `exec` platform adapter is supported. + +By default, `TAI_MUX_PLATFORM_ADAPTER` is set to `static`. #### static platform adapter @@ -48,6 +50,24 @@ is 5,6,7,8. An environment variable `TAI_MUX_STATIC_CONFIG_FILE` is used to let the static platform adapter know the location of the configuration file. +#### exec platform adapter + +exec platform adapter is a platform adapter which executes a prespecified script. + +User can choose what script to execute by using an environment variable `TAI_MUX_EXEC_SCRIPT`. + +By default, `TAI_MUX_EXEC_SCRIPT` is set to `/etc/tai/mux/exec.sh`. + +exec platform adapter executes this script in two ways. + +The first way is to get the list of modules during the initialization phase. +In this case, exec platform adapter passes 'list' as the first argument. +The script must return the list of modules which is separated by a newline, or "\n". + +The second way is to get the actual TAI library to use for a module when TAI adapter host tries to create a module. +In this case, exec platform adapter passes the module location as the first argument. +The script must return the TAI library name. If the module doesn't exist in the specified location, the script must exit with non-zero value. + ### HOW TO BUILD ``` diff --git a/tai_mux/custom_attrs/mux_module.h b/tai_mux/custom_attrs/mux_module.h index ab35b65..2e8c90f 100644 --- a/tai_mux/custom_attrs/mux_module.h +++ b/tai_mux/custom_attrs/mux_module.h @@ -7,6 +7,7 @@ typedef enum _tai_mux_platform_adapter_type_t { TAI_MUX_PLATFORM_ADAPTER_TYPE_UNKNOWN, TAI_MUX_PLATFORM_ADAPTER_TYPE_STATIC, + TAI_MUX_PLATFORM_ADAPTER_TYPE_EXEC, TAI_MUX_PLATFORM_ADAPTER_TYPE_MAX, } tai_mux_platform_adapter_type_t; diff --git a/tai_mux/exec_platform_adapter.cpp b/tai_mux/exec_platform_adapter.cpp new file mode 100644 index 0000000..9ff671a --- /dev/null +++ b/tai_mux/exec_platform_adapter.cpp @@ -0,0 +1,92 @@ +#include "exec_platform_adapter.hpp" +#include +#include +#include + +namespace tai::mux { + + // trim from end (in place) + static inline void rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { + return std::isgraph(ch); + }).base(), s.end()); + } + + static int exec(const std::string& cmd, std::string& output) { + FILE* pipe = popen(cmd.c_str(), "r"); + if (!pipe) return -1; + char buffer[128] = {}; + while (!feof(pipe)) { + if (fgets(buffer, 128, pipe) != NULL) + output += buffer; + } + return WEXITSTATUS(pclose(pipe)); + } + + static int exec_script(const std::string& arg, std::string& output) { + std::stringstream ss; + std::string script = TAI_MUX_EXEC_DEFAULT_SCRIPT; + auto e = std::getenv(TAI_MUX_EXEC_SCRIPT.c_str()); + if ( e != nullptr ) { + script = e; + } + ss << script; + ss << " "; + ss << arg; + auto ret = exec(ss.str(), output); + if ( ret != 0 ) { + TAI_ERROR("failed to execute %s: ret: %d", script.c_str(), ret); + return ret; + } + rtrim(output); + return 0; + } + + ExecPlatformAdapter::ExecPlatformAdapter(uint64_t flags, const tai_service_method_table_t* services) : m_flags(flags) { + + m_services.module_presence = nullptr; + if ( services != nullptr ) { + m_services.get_module_io_handler = services->get_module_io_handler; + } + + if ( services != nullptr && services->module_presence != nullptr ) { + std::string output; + auto ret = exec_script("list", output); + if ( ret != 0 ) { + throw Exception(TAI_STATUS_FAILURE); + } + TAI_DEBUG("result of list: %s", output.c_str()); + std::stringstream ss(output); + std::string location; + while(getline(ss, location)) { + services->module_presence(true, const_cast(location.c_str())); + } + } + } + + ExecPlatformAdapter::~ExecPlatformAdapter() { + for ( auto& m : m_ma_map ) { + m.second->tai_api_uninitialize(); + } + } + + S_ModuleAdapter ExecPlatformAdapter::get_module_adapter(const std::string& location) { + std::string lib; + auto ret = exec_script(location, lib); + if ( ret != 0 ) { + TAI_ERROR("script failed: %d", ret); + return nullptr; + } + auto dl = ModuleAdapter::dl_address(lib); + S_ModuleAdapter ma; + if ( dl == 0 ) { + ma = std::make_shared(lib, m_flags, &m_services); + dl = ModuleAdapter::dl_address(lib); + m_lib_map[dl] = ma; + } else { + ma = m_lib_map[dl]; + } + m_ma_map[location] = ma; + return ma; + } +} diff --git a/tai_mux/exec_platform_adapter.hpp b/tai_mux/exec_platform_adapter.hpp new file mode 100644 index 0000000..13ff0f6 --- /dev/null +++ b/tai_mux/exec_platform_adapter.hpp @@ -0,0 +1,48 @@ +#ifndef __EXEC_PLATFORM_ADAPTER_HPP__ +#define __EXEC_PLATFORM_ADAPTER_HPP__ + +#include +#include +#include +#include +#include + +#include "platform_adapter.hpp" +#include "module_adapter.hpp" +#include "tai.h" +#include "json.hpp" + +namespace tai::mux { + + using json = nlohmann::json; + + const std::string TAI_MUX_EXEC_SCRIPT = "TAI_MUX_EXEC_SCRIPT"; + const std::string TAI_MUX_EXEC_DEFAULT_SCRIPT = "/etc/tai/mux/exec.sh"; + + class ExecPlatformAdapter : public PlatformAdapter { + public: + ExecPlatformAdapter(uint64_t flags, const tai_service_method_table_t* services); + ~ExecPlatformAdapter(); + S_ModuleAdapter get_module_adapter(const std::string& location); + const std::unordered_set list_module_adapters() { + std::unordered_set set; + for ( auto m : m_ma_map ) { + set.emplace(m.second); + } + return set; + }; + + virtual tai_mux_platform_adapter_type_t type() const { + return TAI_MUX_PLATFORM_ADAPTER_TYPE_EXEC; + } + private: + std::map m_lib_map; + std::map m_ma_map; + std::thread m_th; + tai_service_method_table_t m_services; + const uint64_t m_flags; + }; + +}; + +#endif diff --git a/tai_mux/module_adapter.cpp b/tai_mux/module_adapter.cpp index b12fc8a..da22c58 100644 --- a/tai_mux/module_adapter.cpp +++ b/tai_mux/module_adapter.cpp @@ -14,6 +14,7 @@ namespace tai::mux { ModuleAdapter::ModuleAdapter(const std::string& name, uint64_t flags, const tai_service_method_table_t* services) : m_name(name) { m_dl = dlopen(name.c_str(), RTLD_NOW | RTLD_DEEPBIND); if ( m_dl == nullptr ) { + TAI_ERROR("dlerror: %s", dlerror()); throw std::runtime_error(dlerror()); } LOAD_TAI_API(tai_api_initialize) diff --git a/tai_mux/mux.cpp b/tai_mux/mux.cpp index a292732..564f785 100644 --- a/tai_mux/mux.cpp +++ b/tai_mux/mux.cpp @@ -1,6 +1,8 @@ #include "mux.hpp" #include #include "taimetadata.h" +#include "static_platform_adapter.hpp" +#include "exec_platform_adapter.hpp" namespace tai::mux { @@ -35,11 +37,16 @@ namespace tai::mux { tai_mux_platform_adapter_type_t pa_type; if ( pa_name == "static" ) { pa_type = TAI_MUX_PLATFORM_ADAPTER_TYPE_STATIC; + } else if ( pa_name == "exec" ) { + pa_type = TAI_MUX_PLATFORM_ADAPTER_TYPE_EXEC; } switch ( pa_type ) { case TAI_MUX_PLATFORM_ADAPTER_TYPE_STATIC: m_pa = std::make_shared(0, services); break; + case TAI_MUX_PLATFORM_ADAPTER_TYPE_EXEC: + m_pa = std::make_shared(0, services); + break; default: TAI_ERROR("unsupported platform_adapter: %s", pa_name.c_str()); throw Exception(TAI_STATUS_NOT_SUPPORTED); @@ -162,6 +169,10 @@ namespace tai::mux { } tai_status_t Platform::set_log(tai_api_t api, tai_log_level_t level, tai_log_fn log_fn) { + auto ret = tai::Logger::get_instance().set_log(api, level, log_fn); + if ( ret != TAI_STATUS_SUCCESS ) { + return ret; + } auto set = m_pa->list_module_adapters(); for ( const auto& a : set ) { auto ret = a->tai_log_set(api, level, log_fn); diff --git a/tai_mux/mux.hpp b/tai_mux/mux.hpp index 81b1c44..34620e1 100644 --- a/tai_mux/mux.hpp +++ b/tai_mux/mux.hpp @@ -3,7 +3,6 @@ #include #include "platform_adapter.hpp" -#include "static_platform_adapter.hpp" #include "module_adapter.hpp" #include "tai.h" #include