diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index f287bcb..fed72ad 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v3 - run: sudo apt update - run: sudo apt install build-essential cmake ninja-build - - run: sudo apt install libjsoncpp-dev libgflags-dev libgoogle-glog-dev libunwind-dev + - run: sudo apt install libjsoncpp-dev libgoogle-glog-dev libunwind-dev - name: Setup Ninja uses: ashutoshvarma/setup-ninja@master @@ -28,12 +28,9 @@ jobs: - name: Configure CMake env: - # glog option: - # -DNDEBUG - # -DDCHECK_ALWAYS_ON # unit test option: # -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined - CXXFLAGS: ${{env.CXXFLAGS}} -DNDEBUG -fPIC -Wall -Wextra -Werror -pedantic-errors -Wswitch-default -Wfloat-equal -Wshadow -Wcast-qual -Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual -Wsign-promo -Wsuggest-override + CXXFLAGS: ${{env.CXXFLAGS}} -Wall -Wextra -Werror -pedantic-errors -Wswitch-default -Wfloat-equal -Wshadow -Wcast-qual -Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual -Wsign-promo -Wsuggest-override -Wextra-semi # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | diff --git a/.gitignore b/.gitignore index 1864913..3135705 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ build/ .vscode launcher/launcher_config.h -test/performance_test_config.h \ No newline at end of file +test/performance_test_config.h +myframe/export.h +myframe/config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 04df54e..7c16e42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,23 @@ cmake_minimum_required(VERSION 3.10) -project(myframe VERSION 0.8.1) - -### gcc version -if (CMAKE_COMPILER_IS_GNUCC) - execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpfullversion -dumpversion - OUTPUT_VARIABLE GCC_VERSION) - string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) - list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) - list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) - set(GCC_VERSION "${GCC_MAJOR}.${GCC_MINOR}") -endif () - -### cpp option -if (GCC_VERSION GREATER "8.0") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra-semi") -endif () +project(myframe VERSION 0.8.2) ### option -option(GENERATE_EXAMPLE "generate example library" ON) -option(GENERATE_TEST "generate test exec" ON) +option(MYFRAME_USE_CV "Using conditional variables for thread communication" OFF) +option(MYFRAME_GENERATE_EXAMPLE "Generate example library" ON) +option(MYFRAME_GENERATE_TEST "Generate test executable program" ON) + +### compile option +set(CMAKE_C_VISIBILITY_PRESET hidden) +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) +if (CMAKE_CXX_STANDARD_REQUIRED) + message(STATUS "Set cxx standard ${CMAKE_CXX_STANDARD}") +else() + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_STANDARD 17) + message(STATUS "Set default cxx standard 17") +endif() ### output path set(MYFRAME_OUTPUT_ROOT "${CMAKE_BINARY_DIR}/output") @@ -27,9 +26,13 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${MYFRAME_OUTPUT_ROOT}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${MYFRAME_OUTPUT_ROOT}/bin) ### install path -# set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/${CMAKE_PROJECT_NAME}") +if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/${CMAKE_PROJECT_NAME}" CACHE PATH "myframe default install prefix" FORCE) + message(STATUS "Set default install prefix $ENV{HOME}/${CMAKE_PROJECT_NAME}") +else() + message(STATUS "Set install prefix ${CMAKE_INSTALL_PREFIX}") +endif() set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -set(MYFRAME_TEST_DIR "test") set(MYFRAME_BIN_DIR "bin") set(MYFRAME_INC_DIR "include") set(MYFRAME_LIB_DIR "lib") @@ -38,20 +41,15 @@ set(MYFRAME_SERVICE_DIR "service") set(MYFRAME_CONF_DIR "conf") ### deps libs +find_package(Threads REQUIRED) find_package(jsoncpp REQUIRED) -find_package(gflags REQUIRED) link_libraries( - pthread dl rt m - glog gflags + Threads::Threads + ${CMAKE_DL_LIBS} + glog jsoncpp - -Wl,-z,defs ) -if (GCC_VERSION LESS "8.0") - link_libraries( - stdc++fs - ) -endif () ### include dir include_directories(.) @@ -59,15 +57,15 @@ include_directories(.) ### sub directory add_subdirectory(myframe) add_subdirectory(launcher) -if (GENERATE_EXAMPLE) +if (MYFRAME_GENERATE_EXAMPLE) add_subdirectory(examples) endif() -if (GENERATE_TEST) +if (MYFRAME_GENERATE_TEST) add_subdirectory(test) endif() ### install file/dir -install(FILES +install(FILES "LICENSE" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ DESTINATION . diff --git a/cpplint.bash b/cpplint.bash index 4f3c610..fa894d8 100755 --- a/cpplint.bash +++ b/cpplint.bash @@ -18,7 +18,8 @@ function main() { -name "*.hxx" -or \ -name "*.cxx" -or \ -name "*.cuh" \ - ')' | xargs python3 ./cpplint.py + ')' -and -not -path "./build/*" \ + | xargs python3 ./cpplint.py } main "$@" diff --git a/doc/development_guide.md b/doc/development_guide.md index bd3a5d3..ed791e8 100644 --- a/doc/development_guide.md +++ b/doc/development_guide.md @@ -71,11 +71,11 @@ make -C build -j "$(nproc)" install ### 运行组件 ```sh cd ${myframe目录}/bin -./launcher -c ${组件名}.json -p app +./launcher -p app ${组件名}.json ``` ### 查看运行日志 ```sh cd ${myframe目录}/log -vi ${日志} +vi app.INFO ``` diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5f2bb28..a125c54 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,5 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.10) +add_compile_definitions(${PROJECT_NAME}_EXPORTS) + ### actor add_library(example_actor_helloworld SHARED example_actor_helloworld.cpp) target_link_libraries(example_actor_helloworld ${PROJECT_NAME}) diff --git a/examples/example_actor_concurrent.cpp b/examples/example_actor_concurrent.cpp index 8757005..cd51c61 100644 --- a/examples/example_actor_concurrent.cpp +++ b/examples/example_actor_concurrent.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -78,7 +78,7 @@ class ExampleActorConcurrentTrigger : public myframe::Actor { std::unordered_map state_; }; -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { if (actor_name == "example_actor_concurrent") { return std::make_shared(); diff --git a/examples/example_actor_helloworld.cpp b/examples/example_actor_helloworld.cpp index 8046a42..07b05aa 100644 --- a/examples/example_actor_helloworld.cpp +++ b/examples/example_actor_helloworld.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include @@ -32,7 +32,7 @@ class ExampleActorHelloWorld : public myframe::Actor { }; /* 创建actor模块实例函数 */ -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { if (actor_name == "example") { return std::make_shared(); diff --git a/examples/example_actor_serial.cpp b/examples/example_actor_serial.cpp index d9891ac..85315d3 100644 --- a/examples/example_actor_serial.cpp +++ b/examples/example_actor_serial.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -81,7 +81,7 @@ class ExampleActorSerial3 : public myframe::Actor { } }; -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { if (actor_name == "example_serial1") { return std::make_shared(); diff --git a/examples/example_actor_subscribe.cpp b/examples/example_actor_subscribe.cpp index 9bd3d64..f0ae8b6 100644 --- a/examples/example_actor_subscribe.cpp +++ b/examples/example_actor_subscribe.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -53,7 +53,7 @@ class ExampleActorSub : public myframe::Actor { } }; -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { if (actor_name == "example_b_pub") { return std::make_shared(); diff --git a/examples/example_actor_timer.cpp b/examples/example_actor_timer.cpp index 6c2c1fa..797b486 100644 --- a/examples/example_actor_timer.cpp +++ b/examples/example_actor_timer.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include @@ -28,7 +28,7 @@ class ExampleActorTimer : public myframe::Actor { } }; -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { if (actor_name == "example_actor_timer") { return std::make_shared(); diff --git a/examples/example_config.cpp b/examples/example_config.cpp index aad3f6d..877d88c 100644 --- a/examples/example_config.cpp +++ b/examples/example_config.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -42,7 +42,7 @@ class ExampleWorkerConfig : public myframe::Worker { }; /* 创建actor实例函数 */ -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { if (actor_name == "example_actor_config") { return std::make_shared(); @@ -51,7 +51,7 @@ extern "C" std::shared_ptr actor_create( } /* 创建worker实例函数 */ -extern "C" std::shared_ptr worker_create( +extern "C" MYFRAME_EXPORT std::shared_ptr worker_create( const std::string& worker_name) { if (worker_name == "example_worker_config") { return std::make_shared(); diff --git a/examples/example_trans_obj.cpp b/examples/example_trans_obj.cpp index 558141b..1b0a5c1 100644 --- a/examples/example_trans_obj.cpp +++ b/examples/example_trans_obj.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -61,7 +61,7 @@ class ExampleWorkerTransObj : public myframe::Worker { }; /* 创建actor实例函数 */ -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { if (actor_name == "example_actor_trans_obj") { return std::make_shared(); @@ -70,7 +70,7 @@ extern "C" std::shared_ptr actor_create( } /* 创建worker实例函数 */ -extern "C" std::shared_ptr worker_create( +extern "C" MYFRAME_EXPORT std::shared_ptr worker_create( const std::string& worker_name) { if (worker_name == "example_worker_trans_obj") { return std::make_shared(); diff --git a/examples/example_worker_actor_interactive.cpp b/examples/example_worker_actor_interactive.cpp index c4ca14d..8284c72 100644 --- a/examples/example_worker_actor_interactive.cpp +++ b/examples/example_worker_actor_interactive.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -44,7 +44,7 @@ class ExampleWorkerInteractive : public myframe::Worker { return; } while (1) { - const auto& msg = mailbox->PopRecv(); + const auto msg = mailbox->PopRecv(); if (msg == nullptr) { break; } @@ -55,7 +55,7 @@ class ExampleWorkerInteractive : public myframe::Worker { }; /* 创建actor实例函数 */ -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { if (actor_name == "example_actor_interactive") { return std::make_shared(); @@ -64,7 +64,7 @@ extern "C" std::shared_ptr actor_create( } /* 创建worker实例函数 */ -extern "C" std::shared_ptr worker_create( +extern "C" MYFRAME_EXPORT std::shared_ptr worker_create( const std::string& worker_name) { if (worker_name == "example_worker_interactive") { return std::make_shared(); diff --git a/examples/example_worker_interactive_with_3rd_frame.cpp b/examples/example_worker_interactive_with_3rd_frame.cpp index ef00211..8ff66dd 100644 --- a/examples/example_worker_interactive_with_3rd_frame.cpp +++ b/examples/example_worker_interactive_with_3rd_frame.cpp @@ -1,10 +1,14 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ +#include "myframe/config.h" +#include "myframe/platform.h" +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) #include +#endif #include #include @@ -18,35 +22,39 @@ Author: likepeng #include "myframe/actor.h" #include "myframe/worker.h" +#if (defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID)) \ + && !defined(MYFRAME_USE_CV) template class MyQueue final { public: - MyQueue() = default; + MyQueue() { + cmd_channel_ = myframe::CmdChannel::Create(nullptr); + } ~MyQueue() = default; - int GetFd0() { return cmd_channel_.GetOwnerHandle(); } - int GetFd1() { return cmd_channel_.GetMainHandle(); } + int GetFd0() { return cmd_channel_->GetOwnerHandle(); } + int GetFd1() { return cmd_channel_->GetMainHandle(); } void Push(std::shared_ptr data) { data_ = data; myframe::CmdChannel::Cmd cmd = myframe::CmdChannel::Cmd::kRun; - cmd_channel_.SendToOwner(cmd); - cmd_channel_.RecvFromOwner(&cmd); + cmd_channel_->SendToOwner(cmd); + cmd_channel_->RecvFromOwner(&cmd); } std::shared_ptr Pop() { std::shared_ptr ret = nullptr; myframe::CmdChannel::Cmd cmd = myframe::CmdChannel::Cmd::kRun; - cmd_channel_.RecvFromMain(&cmd); + cmd_channel_->RecvFromMain(&cmd); ret = data_; data_ = nullptr; - cmd_channel_.SendToMain(myframe::CmdChannel::Cmd::kIdle); + cmd_channel_->SendToMain(myframe::CmdChannel::Cmd::kIdle); return ret; } private: std::shared_ptr data_; - myframe::CmdChannel cmd_channel_; + std::shared_ptr cmd_channel_; }; /** @@ -96,7 +104,7 @@ class ExampleWorkerInteractiveWith3rdFrame : public myframe::Worker { } else if (cmd == myframe::CmdChannel::Cmd::kRunWithMsg) { auto mailbox = GetMailbox(); while (!mailbox->RecvEmpty()) { - const auto& msg = mailbox->PopRecv(); + const auto msg = mailbox->PopRecv(); // 接收到其它组件消息 LOG(INFO) << "get main " << msg->GetData(); } @@ -162,21 +170,34 @@ class ExampleActorInteractiveWith3rdFrame : public myframe::Actor { private: int seq_num_{0}; }; +#endif /* 创建worker实例函数 */ -extern "C" std::shared_ptr worker_create( +extern "C" MYFRAME_EXPORT std::shared_ptr worker_create( const std::string& worker_name) { +#if !(defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID)) \ + || defined(MYFRAME_USE_CV) + (void)worker_name; + LOG(ERROR) << "Unsupport example_worker_interactive_with_3rd_frame"; +#else if (worker_name == "example_worker_interactive_with_3rd_frame") { return std::make_shared(); } +#endif return nullptr; } /* 创建actor实例函数 */ -extern "C" std::shared_ptr actor_create( +extern "C" MYFRAME_EXPORT std::shared_ptr actor_create( const std::string& actor_name) { +#if !(defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID)) \ + || defined(MYFRAME_USE_CV) + (void)actor_name; + LOG(ERROR) << "Unsupport example_actor_interactive_with_3rd_frame"; +#else if (actor_name == "example_actor_interactive_with_3rd_frame") { return std::make_shared(); } +#endif return nullptr; } diff --git a/examples/example_worker_publish.cpp b/examples/example_worker_publish.cpp index d169780..7998089 100644 --- a/examples/example_worker_publish.cpp +++ b/examples/example_worker_publish.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -24,7 +24,7 @@ class ExampleWorkerPublic : public myframe::Worker { } auto mailbox = GetMailbox(); while (!mailbox->RecvEmpty()) { - const auto& msg = mailbox->PopRecv(); + const auto msg = mailbox->PopRecv(); // send msg by udp/tcp/zmq/... LOG(INFO) << "public msg " << msg->GetData() << " ..."; } @@ -32,7 +32,7 @@ class ExampleWorkerPublic : public myframe::Worker { }; /* 创建worker实例函数 */ -extern "C" std::shared_ptr worker_create( +extern "C" MYFRAME_EXPORT std::shared_ptr worker_create( const std::string& worker_name) { if (worker_name == "example_worker_publish") { return std::make_shared(); diff --git a/examples/example_worker_quit.cpp b/examples/example_worker_quit.cpp index 15d38b1..b2e5d13 100644 --- a/examples/example_worker_quit.cpp +++ b/examples/example_worker_quit.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -25,7 +25,7 @@ class ExampleWorkerQuit : public myframe::Worker { }; /* 创建worker实例函数 */ -extern "C" std::shared_ptr worker_create( +extern "C" MYFRAME_EXPORT std::shared_ptr worker_create( const std::string& worker_name) { if (worker_name == "example_worker_quit") { return std::make_shared(); diff --git a/examples/example_worker_talk.cpp b/examples/example_worker_talk.cpp index 7955a17..7a0bb37 100644 --- a/examples/example_worker_talk.cpp +++ b/examples/example_worker_talk.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -30,7 +30,7 @@ class ExampleWorkerTalk : public myframe::Worker { }; /* 创建worker实例函数 */ -extern "C" std::shared_ptr worker_create( +extern "C" MYFRAME_EXPORT std::shared_ptr worker_create( const std::string& worker_name) { if (worker_name == "example_worker_talk") { return std::make_shared(); diff --git a/launcher/cmdline.h b/launcher/cmdline.h new file mode 100644 index 0000000..36625d1 --- /dev/null +++ b/launcher/cmdline.h @@ -0,0 +1,801 @@ +/* + Copyright (c) 2009, Hideyuki Tanaka + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cmdline { + +namespace detail { + +template +class lexical_cast_t { + public: + static Target cast(const Source &arg) { + Target ret; + std::stringstream ss; + if (!(ss << arg && ss >> ret && ss.eof())) + throw std::bad_cast(); + + return ret; + } +}; + +template +class lexical_cast_t{ + public: + static Target cast(const Source &arg) { + return arg; + } +}; + +template +class lexical_cast_t { + public: + static std::string cast(const Source &arg) { + std::ostringstream ss; + ss << arg; + return ss.str(); + } +}; + +template +class lexical_cast_t { + public: + static Target cast(const std::string &arg) { + Target ret; + std::istringstream ss(arg); + if (!(ss >> ret && ss.eof())) + throw std::bad_cast(); + return ret; + } +}; + +template +struct is_same { + static const bool value = false; +}; + +template +struct is_same{ + static const bool value = true; +}; + +template +Target lexical_cast(const Source &arg) { + return lexical_cast_t< + Target, + Source, + detail::is_same::value>::cast(arg); +} + +static inline std::string demangle(const std::string &name) { + int status = 0; + char *p = abi::__cxa_demangle(name.c_str(), 0, 0, &status); + std::string ret(p); + free(p); + return ret; +} + +template +std::string readable_typename() { + return demangle(typeid(T).name()); +} + +template +std::string default_value(T def) { + return detail::lexical_cast(def); +} + +template <> +inline std::string readable_typename() { + return "string"; +} + +} // namespace detail + +//----- + +class cmdline_error : public std::exception { + public: + explicit cmdline_error(const std::string &msg) : msg_(msg) {} + ~cmdline_error() throw() {} + const char *what() const throw() override { return msg_.c_str(); } + private: + std::string msg_; +}; + +template +struct default_reader{ + T operator()(const std::string &str){ + return detail::lexical_cast(str); + } +}; + +template +struct range_reader { + range_reader(const T &low, const T &high): low_(low), high_(high) {} + T operator()(const std::string &s) const { + T ret = default_reader()(s); + if (!(ret >= low_ && ret <= high_)) + throw cmdline::cmdline_error("range_error"); + return ret; + } + private: + T low_, high_; +}; + +template +range_reader range(const T &low, const T &high) { + return range_reader(low, high); +} + +template +struct oneof_reader{ + T operator()(const std::string &s) { + T ret = default_reader()(s); + if (std::find(alt.begin(), alt.end(), ret) == alt.end()) + throw cmdline_error(""); + return ret; + } + void add(const T &v) { alt.push_back(v); } + private: + std::vector alt; +}; + +template +oneof_reader oneof(T a1) { + oneof_reader ret; + ret.add(a1); + return ret; +} + +template +oneof_reader oneof(T a1, T a2) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + return ret; +} + +template +oneof_reader oneof(T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + ret.add(a9); + return ret; +} + +template +oneof_reader oneof( + T a1, T a2, T a3, T a4, T a5, T a6, T a7, T a8, T a9, T a10) { + oneof_reader ret; + ret.add(a1); + ret.add(a2); + ret.add(a3); + ret.add(a4); + ret.add(a5); + ret.add(a6); + ret.add(a7); + ret.add(a8); + ret.add(a9); + ret.add(a10); + return ret; +} + +//----- + +class parser { + public: + parser() { + } + ~parser() { + for (std::map::iterator p = options.begin(); + p != options.end(); p++) + delete p->second; + } + + void add(const std::string &name, + char short_name = 0, + const std::string &desc = "") { + if (options.count(name)) + throw cmdline_error("multiple definition: " + name); + options[name] = new option_without_value(name, short_name, desc); + ordered.push_back(options[name]); + } + + template + void add(const std::string &name, + char short_name = 0, + const std::string &desc = "", + bool need = true, + const T def = T()) { + add(name, short_name, desc, need, def, default_reader()); + } + + template + void add(const std::string &name, + char short_name = 0, + const std::string &desc = "", + bool need = true, + const T def = T(), + F reader = F()) { + if (options.count(name)) + throw cmdline_error("multiple definition: " + name); + options[name] = new option_with_value_with_reader( + name, short_name, need, def, desc, reader); + ordered.push_back(options[name]); + } + + void footer(const std::string &f) { + ftr = f; + } + + void set_program_name(const std::string &name) { + prog_name = name; + } + + bool exist(const std::string &name) const { + if (options.count(name) == 0) + throw cmdline_error("there is no flag: --"+name); + return options.find(name)->second->has_set(); + } + + template + const T &get(const std::string &name) const { + if (options.count(name) == 0) + throw cmdline_error("there is no flag: --" + name); + const option_with_value *p = dynamic_cast*>( + options.find(name)->second); + if (p == NULL) throw cmdline_error("type mismatch flag '" + name + "'"); + return p->get(); + } + + const std::vector &rest() const { + return others; + } + + bool parse(const std::string &arg) { + std::vector args; + + std::string buf; + bool in_quote = false; + for (std::string::size_type i = 0; i < arg.length(); i++) { + if (arg[i] == '\"') { + in_quote = !in_quote; + continue; + } + + if (arg[i] == ' ' && !in_quote) { + args.push_back(buf); + buf = ""; + continue; + } + + if (arg[i] == '\\') { + i++; + if (i >= arg.length()) { + errors.push_back("unexpected occurrence of '\\' at end of string"); + return false; + } + } + + buf += arg[i]; + } + + if (in_quote) { + errors.push_back("quote is not closed"); + return false; + } + + if (buf.length() > 0) + args.push_back(buf); + + for (size_t i = 0; i < args.size(); i++) + std::cout << "\"" << args[i] << "\"" << std::endl; + + return parse(args); + } + + bool parse(const std::vector &args) { + int argc = static_cast(args.size()); + std::vector argv(argc); + + for (int i = 0; i < argc; i++) + argv[i] = args[i].c_str(); + + return parse(argc, &argv[0]); + } + + bool parse(int argc, const char * const argv[]) { + errors.clear(); + others.clear(); + + if (argc < 1) { + errors.push_back("argument number must be longer than 0"); + return false; + } + if (prog_name == "") + prog_name = argv[0]; + + std::map lookup; + for (std::map::iterator p = options.begin(); + p != options.end(); p++) { + if (p->first.length() == 0) continue; + char initial = p->second->short_name(); + if (initial) { + if (lookup.count(initial) > 0) { + lookup[initial] = ""; + errors.push_back( + std::string("short option '") + initial + "' is ambiguous"); + return false; + } else { + lookup[initial] = p->first; + } + } + } + + for (int i = 1; i < argc; i++) { + if (strncmp(argv[i], "--", 2) == 0) { + const char *p = strchr(argv[i] + 2, '='); + if (p) { + std::string name(argv[i] + 2, p); + std::string val(p + 1); + set_option(name, val); + } else { + std::string name(argv[i] + 2); + if (options.count(name) == 0) { + errors.push_back("undefined option: --" + name); + continue; + } + if (options[name]->has_value()) { + if (i + 1 >= argc) { + errors.push_back("option needs value: --" + name); + continue; + } else { + i++; + set_option(name, argv[i]); + } + } else { + set_option(name); + } + } + } else if (strncmp(argv[i], "-", 1) == 0) { + if (!argv[i][1]) continue; + char last = argv[i][1]; + for (int j = 2; argv[i][j]; j++) { + last = argv[i][j]; + if (lookup.count(argv[i][j-1]) == 0) { + errors.push_back( + std::string("undefined short option: -") + argv[i][j-1]); + continue; + } + if (lookup[argv[i][j-1]] == "") { + errors.push_back( + std::string("ambiguous short option: -") + argv[i][j-1]); + continue; + } + set_option(lookup[argv[i][j-1]]); + } + + if (lookup.count(last) == 0) { + errors.push_back(std::string("undefined short option: -") + last); + continue; + } + if (lookup[last] == "") { + errors.push_back(std::string("ambiguous short option: -") + last); + continue; + } + + if (i + 1 < argc && options[lookup[last]]->has_value()) { + set_option(lookup[last], argv[i+1]); + i++; + } else { + set_option(lookup[last]); + } + } else { + others.push_back(argv[i]); + } + } + + for (std::map::iterator p = options.begin(); + p != options.end(); p++) + if (!p->second->valid()) + errors.push_back("need option: --"+std::string(p->first)); + + return errors.size() == 0; + } + + void parse_check(const std::string &arg) { + if (!options.count("help")) + add("help", '?', "print this message"); + check(0, parse(arg)); + } + + void parse_check(const std::vector &args) { + if (!options.count("help")) + add("help", '?', "print this message"); + check(args.size(), parse(args)); + } + + void parse_check(int argc, char *argv[]) { + if (!options.count("help")) + add("help", '?', "print this message"); + check(argc, parse(argc, argv)); + } + + std::string error() const { + return errors.size() > 0 ? errors[0] : ""; + } + + std::string error_full() const { + std::ostringstream oss; + for (size_t i = 0; i < errors.size(); i++) + oss << errors[i] << std::endl; + return oss.str(); + } + + std::string usage() const { + std::ostringstream oss; + oss << "usage: " << prog_name << " "; + for (size_t i = 0; i < ordered.size(); i++) { + if (ordered[i]->must()) + oss << ordered[i]->short_description() << " "; + } + + oss << "[options] ... " << ftr << std::endl; + oss << "options:" << std::endl; + + size_t max_width = 0; + for (size_t i = 0; i < ordered.size(); i++) { + max_width = std::max(max_width, ordered[i]->name().length()); + } + for (size_t i = 0; i < ordered.size(); i++) { + if (ordered[i]->short_name()) { + oss << " -" << ordered[i]->short_name() << ", "; + } else { + oss << " "; + } + + oss << "--" << ordered[i]->name(); + for (size_t j = ordered[i]->name().length(); j < max_width + 4; j++) + oss << ' '; + oss << ordered[i]->description() << std::endl; + } + return oss.str(); + } + + private: + void check(int argc, bool ok) { + if ((argc == 1 && !ok) || exist("help")) { + std::cerr << usage(); + exit(0); + } + + if (!ok) { + std::cerr << error() << std::endl << usage(); + exit(1); + } + } + + void set_option(const std::string &name) { + if (options.count(name) == 0) { + errors.push_back("undefined option: --"+name); + return; + } + if (!options[name]->set()) { + errors.push_back("option needs value: --"+name); + return; + } + } + + void set_option(const std::string &name, const std::string &value) { + if (options.count(name) == 0) { + errors.push_back("undefined option: --"+name); + return; + } + if (!options[name]->set(value)) { + errors.push_back("option value is invalid: --"+name+"="+value); + return; + } + } + + class option_base{ + public: + virtual ~option_base() {} + + virtual bool has_value() const = 0; + virtual bool set() = 0; + virtual bool set(const std::string &value) = 0; + virtual bool has_set() const = 0; + virtual bool valid() const = 0; + virtual bool must() const = 0; + + virtual const std::string &name() const = 0; + virtual char short_name() const = 0; + virtual const std::string &description() const = 0; + virtual std::string short_description() const = 0; + }; + + class option_without_value : public option_base { + public: + option_without_value(const std::string &name, + char short_name, + const std::string &desc) + :nam_(name), snam_(short_name), desc_(desc), has_(false) { + } + ~option_without_value() {} + + bool has_value() const override { return false; } + + bool set() override { + has_ = true; + return true; + } + + bool set(const std::string &) override { + return false; + } + + bool has_set() const override { + return has_; + } + + bool valid() const override { + return true; + } + + bool must() const override { + return false; + } + + const std::string &name() const override { + return nam_; + } + + char short_name() const override { + return snam_; + } + + const std::string &description() const override { + return desc_; + } + + std::string short_description() const override { + return "--"+nam_; + } + + private: + std::string nam_; + char snam_; + std::string desc_; + bool has_; + }; + + template + class option_with_value : public option_base { + public: + option_with_value(const std::string &name, + char short_name, + bool need, + const T &def, + const std::string &desc) + : nam(name), snam(short_name), need_(need), has(false) + , def_(def), actual(def) { + this->desc_ = full_description(desc); + } + ~option_with_value() {} + + const T &get() const { + return actual; + } + + bool has_value() const override { return true; } + + bool set() override { + return false; + } + + bool set(const std::string &value) override { + try { + actual = read(value); + has = true; + } + catch(const std::exception &e) { + return false; + } + return true; + } + + bool has_set() const override { + return has; + } + + bool valid() const override { + if (need_ && !has) return false; + return true; + } + + bool must() const override { + return need_; + } + + const std::string &name() const override { + return nam; + } + + char short_name() const override { + return snam; + } + + const std::string &description() const override { + return desc_; + } + + std::string short_description() const override { + return "--"+nam+"="+detail::readable_typename(); + } + + protected: + std::string full_description(const std::string &desc) { + return + desc+" ("+detail::readable_typename()+ + (need_?"":" [="+detail::default_value(def_)+"]") + +")"; + } + + virtual T read(const std::string &s) = 0; + + std::string nam; + char snam; + bool need_; + std::string desc_; + + bool has; + T def_; + T actual; + }; + + template + class option_with_value_with_reader : public option_with_value { + public: + option_with_value_with_reader(const std::string &name, + char short_name, + bool need, + const T def, + const std::string &desc, + F reader) + : option_with_value(name, short_name, need, def, desc) + , reader_(reader) { + } + + private: + T read(const std::string &s) override { + return reader_(s); + } + + F reader_; + }; + + std::map options; + std::vector ordered; + std::string ftr; + + std::string prog_name; + std::vector others; + + std::vector errors; +}; + +} // namespace cmdline diff --git a/launcher/launcher.cpp b/launcher/launcher.cpp index 3293dc9..950ae12 100644 --- a/launcher/launcher.cpp +++ b/launcher/launcher.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -29,32 +29,26 @@ void OnShutDown(int sig) { int main(int argc, char** argv) { // 命令行参数解析 myframe::ModuleArgument module_args(MYFRAME_CONF_DIR); - auto opt = module_args.ParseArgument(argc, argv); - if (opt == myframe::ModuleArgument::kGetHelpInfo - || opt == myframe::ModuleArgument::kNoArgument - || opt == myframe::ModuleArgument::kInvalidArgument) { - module_args.DisplayUsage(); - return 0; - } + module_args.ParseArgument(argc, argv); // 初始化日志系统 myframe::InitLog(MYFRAME_LOG_DIR, module_args.GetProcessName()); LOG(INFO) << "launch command: " << module_args.GetCmd(); - std::string root_dir = myframe::Common::GetWorkRoot(); + auto root_dir = myframe::Common::GetWorkRoot(); auto lib_dir = myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR); auto service_dir = myframe::Common::GetAbsolutePath(MYFRAME_SERVICE_DIR); auto log_dir = myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR); auto conf_dir = myframe::Common::GetAbsolutePath(MYFRAME_CONF_DIR); - LOG(INFO) << "root dir: " << root_dir; - LOG(INFO) << "default lib dir: " << lib_dir; - LOG(INFO) << "default service dir: " << service_dir; - LOG(INFO) << "default log dir: " << log_dir; - LOG(INFO) << "default conf dir: " << conf_dir; + LOG(INFO) << "root dir: " << root_dir.string(); + LOG(INFO) << "default lib dir: " << lib_dir.string(); + LOG(INFO) << "default service dir: " << service_dir.string(); + LOG(INFO) << "default log dir: " << log_dir.string(); + LOG(INFO) << "default conf dir: " << conf_dir.string(); // 初始化并启动线程 g_app = std::make_shared(); if (false == g_app->Init( - lib_dir, + lib_dir.string(), module_args.GetThreadPoolSize(), module_args.GetConnEventSize(), module_args.GetWarningMsgSize())) { @@ -70,7 +64,7 @@ int main(int argc, char** argv) { if (myframe::Common::IsAbsolutePath(conf)) { abs_conf_file = conf; } else { - abs_conf_file = service_dir + conf; + abs_conf_file = (service_dir / conf).string(); } if (!g_app->LoadServiceFromFile(abs_conf_file)) { LOG(ERROR) << "Load " << abs_conf_file << " failed, exit"; @@ -84,7 +78,7 @@ int main(int argc, char** argv) { if (myframe::Common::IsAbsolutePath(module_args.GetConfDir())) { abs_service_dir = module_args.GetConfDir(); } else { - abs_service_dir = root_dir + "/" + module_args.GetConfDir() + "/"; + abs_service_dir = (root_dir / module_args.GetConfDir()).string(); } } else { abs_service_dir = service_dir; diff --git a/launcher/launcher_config.h.in b/launcher/launcher_config.h.in index eb9b9da..442dc8d 100644 --- a/launcher/launcher_config.h.in +++ b/launcher/launcher_config.h.in @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once diff --git a/launcher/module_argument.cpp b/launcher/module_argument.cpp index c592caf..eeffad0 100644 --- a/launcher/module_argument.cpp +++ b/launcher/module_argument.cpp @@ -1,56 +1,37 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "module_argument.h" -#include #include #include -#include "myframe/common.h" namespace myframe { ModuleArgument::ModuleArgument( const std::string& sys_conf_dir) { sys_conf_dir_ = myframe::Common::GetAbsolutePath(sys_conf_dir); + parser_.add("process_name", 'p', + "The name of this launcher process, " + "and it is also the name of log, " + "default value is launcher_${PID}\n", + false, ""); + parser_.add("sys_conf", 's', + "framework config file", + false, ""); + parser_.add("dir", 'd', + "module config dir", + false, ""); + parser_.footer("module_config_file ..."); } -void ModuleArgument::DisplayUsage() { - std::cout - << "Usage: \n " << binary_name_ << " [OPTION]...\n" - << "Description: \n" - << " -h, --help : help infomation \n" - << " -s, --sys_conf=${CONFIG_FILE} : framework config file \n" - << " -c, --conf=${CONFIG_FILE} : module config file\n" - << " -d, --dir=${CONFIG_DIR} : module config dir\n" - << " -p, --process_name=${PROCESS_NAME}: " - "The name of this launcher process, and it " - "is also the name of log, default value is launcher_${PID}\n" - << "Example:\n" - << " " << binary_name_ << " -h\n" - << " " << binary_name_ << " -c module1.json -c module2.json\n" - << " " << binary_name_ << " -c module1.json -c module2.json " - "-p process_name\n" - << " " << binary_name_ << " -s sys.json -c module1.json " - "-p process_name\n" - << " " << binary_name_ << " -d service_dir -p process_name\n"; -} - -ModuleArgument::OptionReturnType ModuleArgument::ParseArgument( - const int argc, char* const argv[]) { +void ModuleArgument::ParseArgument( + const int argc, char** argv) { const std::string binary_name(argv[0]); binary_name_ = binary_name.substr(binary_name.find_last_of("/") + 1); process_name_ = binary_name_ + "_" + std::to_string(getpid()); - const std::string short_opts = "hc:d:p:s:"; - static const struct option long_opts[] = { - {"help", no_argument, nullptr, 'h'}, - {"conf", required_argument, nullptr, 'c'}, - {"conf_dir", required_argument, nullptr, 'd'}, - {"process_name", required_argument, nullptr, 'p'}, - {"sys_conf", required_argument, nullptr, 's'}, - {NULL, no_argument, nullptr, 0}}; // log command for info std::string cmd(""); @@ -60,45 +41,30 @@ ModuleArgument::OptionReturnType ModuleArgument::ParseArgument( } cmd_ = cmd; - OptionReturnType ret = kNoArgument; - bool parsing_next_opt = true; - int long_index = 0; - do { - int opt = getopt_long( - argc, argv, short_opts.c_str(), long_opts, &long_index); - if (opt == -1) { - break; - } - switch (opt) { - case 's': - if (!ParseSysConf(optarg)) { - parsing_next_opt = false; - ret = kInvalidArgument; - } - break; - case 'c': - conf_list_.emplace_back(optarg); - ret = kOtherParameter; - break; - case 'd': - conf_dir_ = optarg; - ret = kOtherParameter; - break; - case 'p': - process_name_ = optarg; - ret = kOtherParameter; - break; - case 'h': - parsing_next_opt = false; - ret = kGetHelpInfo; - break; - default: - ret = kInvalidArgument; - break; + // check args + parser_.parse_check(argc, argv); + + auto process_name = parser_.get("process_name"); + if (!process_name.empty()) { + process_name_ = process_name; + } + + auto sys_conf = parser_.get("sys_conf"); + if (!sys_conf.empty()) { + if (!ParseSysConf(sys_conf)) { + std::cerr << "parse sys conf failed!!" << std::endl; + exit(-1); } - } while (parsing_next_opt); + } - return ret; + auto dir = parser_.get("dir"); + if (!dir.empty()) { + conf_dir_ = dir; + } + + for (size_t i = 0; i < parser_.rest().size(); i++) { + conf_list_.emplace_back(parser_.rest()[i]); + } } bool ModuleArgument::ParseSysConf(const std::string& sys_conf) { @@ -106,7 +72,7 @@ bool ModuleArgument::ParseSysConf(const std::string& sys_conf) { if (Common::IsAbsolutePath(sys_conf)) { full_sys_conf = sys_conf; } else { - full_sys_conf = sys_conf_dir_ + sys_conf; + full_sys_conf = (sys_conf_dir_ / sys_conf).string(); } auto root = Common::LoadJsonFromFile(full_sys_conf); if (root.isNull() diff --git a/launcher/module_argument.h b/launcher/module_argument.h index 6d96d60..0c7bab7 100644 --- a/launcher/module_argument.h +++ b/launcher/module_argument.h @@ -1,28 +1,23 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include #include +#include "cmdline.h" +#include "myframe/common.h" namespace myframe { class ModuleArgument final { public: - enum OptionReturnType { - kNoArgument, - kGetHelpInfo, - kInvalidArgument, - kOtherParameter, - }; ModuleArgument(const std::string& sys_conf_dir); ~ModuleArgument() = default; - OptionReturnType ParseArgument(const int argc, char* const argv[]); - void DisplayUsage(); + void ParseArgument(const int argc, char** argv); inline std::list GetConfList() const { return conf_list_; } inline std::string GetConfDir() const { return conf_dir_; } inline std::string GetBinaryName() const { return binary_name_; } @@ -38,12 +33,13 @@ class ModuleArgument final { int thread_poll_size_{4}; int conn_event_size_{2}; int warning_msg_size_{10}; - std::string cmd_{""}; - std::string binary_name_{""}; - std::string process_name_{""}; - std::string conf_dir_{""}; - std::string sys_conf_dir_{"conf"}; + std::string cmd_; + std::string binary_name_; + std::string process_name_; + std::string conf_dir_; + stdfs::path sys_conf_dir_; std::list conf_list_; + cmdline::parser parser_; }; } // namespace myframe diff --git a/myframe/CMakeLists.txt b/myframe/CMakeLists.txt index 5bb041c..0b7cd87 100644 --- a/myframe/CMakeLists.txt +++ b/myframe/CMakeLists.txt @@ -1,5 +1,8 @@ cmake_minimum_required(VERSION 3.10) +### config +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h) + ### source aux_source_directory(. __srcs) @@ -11,14 +14,25 @@ target_include_directories(${PROJECT_NAME} $ ) +# export file +include (GenerateExportHeader) +generate_export_header (${PROJECT_NAME} + EXPORT_MACRO_NAME MYFRAME_EXPORT + EXPORT_FILE_NAME "${CMAKE_CURRENT_SOURCE_DIR}/export.h" +) + ### install file(GLOB header_files + config.h + platform.h + export.h macros.h common.h log.h msg.h mailbox.h cmd_channel.h + poller.h actor.h event.h worker.h @@ -31,6 +45,8 @@ install(FILES DESTINATION ${MYFRAME_INC_DIR}/${PROJECT_NAME} ) install(TARGETS ${PROJECT_NAME} - DESTINATION lib EXPORT "${PROJECT_NAME}Targets" + LIBRARY DESTINATION ${MYFRAME_LIB_DIR} + ARCHIVE DESTINATION ${MYFRAME_LIB_DIR} + RUNTIME DESTINATION ${MYFRAME_BIN_DIR} ) diff --git a/myframe/actor.cpp b/myframe/actor.cpp index 4fc934c..b8c4721 100644 --- a/myframe/actor.cpp +++ b/myframe/actor.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/actor.h" diff --git a/myframe/actor.h b/myframe/actor.h index 34443ad..4b14eee 100644 --- a/myframe/actor.h +++ b/myframe/actor.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once @@ -12,6 +12,7 @@ Author: likepeng #include +#include "myframe/export.h" #include "myframe/macros.h" #include "myframe/mailbox.h" @@ -20,7 +21,7 @@ namespace myframe { class Msg; class ActorContext; class App; -class Actor { +class MYFRAME_EXPORT Actor { friend class App; friend class ActorContext; friend class ModLib; @@ -127,6 +128,7 @@ class Actor { } // namespace myframe +template class std::shared_ptr; extern "C" { typedef std::shared_ptr (*actor_create_func_t)( const std::string&); diff --git a/myframe/actor_context.cpp b/myframe/actor_context.cpp index dbaf8c8..ed1362f 100644 --- a/myframe/actor_context.cpp +++ b/myframe/actor_context.cpp @@ -1,14 +1,12 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/actor_context.h" -#include - #include #include diff --git a/myframe/actor_context.h b/myframe/actor_context.h index ec8ace9..339e8f7 100644 --- a/myframe/actor_context.h +++ b/myframe/actor_context.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once diff --git a/myframe/actor_context_manager.cpp b/myframe/actor_context_manager.cpp index dc8fcf4..63d6a57 100644 --- a/myframe/actor_context_manager.cpp +++ b/myframe/actor_context_manager.cpp @@ -1,15 +1,12 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/actor_context_manager.h" -#include -#include - #include #include @@ -79,7 +76,7 @@ bool ActorContextManager::HasActor(const std::string& name) { } void ActorContextManager::PrintWaitQueue() { - DLOG(INFO) << "cur wait queue actor:"; + VLOG(1) << "cur wait queue actor:"; auto it = wait_queue_.begin(); while (it != wait_queue_.end()) { auto ctx = it->lock(); @@ -87,7 +84,7 @@ void ActorContextManager::PrintWaitQueue() { LOG(ERROR) << "context is nullptr"; continue; } - DLOG(INFO) << "---> " << *ctx; + VLOG(1) << "---> " << *ctx; ++it; } } @@ -118,7 +115,7 @@ std::shared_ptr ActorContextManager::GetContextWithMsg() { } } for (std::size_t i = 0; i < in_runing_context.size(); ++i) { - DLOG(INFO) << in_runing_context[i]->GetActor()->GetActorName() + VLOG(1) << in_runing_context[i]->GetActor()->GetActorName() << " is runing, move to wait queue back"; wait_queue_.push_back(in_runing_context[i]); } @@ -127,7 +124,7 @@ std::shared_ptr ActorContextManager::GetContextWithMsg() { void ActorContextManager::PushContext(std::shared_ptr ctx) { if (ctx->IsInWaitQueue()) { - DLOG(INFO) << *ctx << " already in wait queue, return"; + VLOG(1) << *ctx << " already in wait queue, return"; PrintWaitQueue(); return; } diff --git a/myframe/actor_context_manager.h b/myframe/actor_context_manager.h index 174cfae..c7a8ea7 100644 --- a/myframe/actor_context_manager.h +++ b/myframe/actor_context_manager.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once diff --git a/myframe/app.cpp b/myframe/app.cpp index f60d668..87fcf0c 100644 --- a/myframe/app.cpp +++ b/myframe/app.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/app.h" @@ -44,11 +44,11 @@ std::shared_ptr App::GetTimerWorker() { } App::App() - : poller_(new Poller()) - , mods_(new ModManager()) + : mods_(new ModManager()) + , poller_(Poller::Create()) , actor_ctx_mgr_(new ActorContextManager()) , ev_mgr_(new EventManager()) - , ev_conn_mgr_(new EventConnManager(ev_mgr_)) + , ev_conn_mgr_(new EventConnManager(ev_mgr_, poller_)) , worker_ctx_mgr_(new WorkerContextManager(ev_mgr_)) {} @@ -135,8 +135,9 @@ bool App::LoadServiceFromJson(const Json::Value& service) { } lib_name = service["lib"].asString(); auto lib_dir = Common::GetAbsolutePath(lib_dir_); - if (!mods_->LoadMod(lib_dir + lib_name)) { - LOG(ERROR) << "load lib " << (lib_dir + lib_name) << " failed, skip"; + if (!mods_->LoadMod((lib_dir / lib_name).string())) { + LOG(ERROR) << "load lib " + << (lib_dir / lib_name).string() << " failed, skip"; return false; } } @@ -272,7 +273,7 @@ bool App::AddWorker( std::shared_ptr worker, const Json::Value& config) { auto worker_ctx = std::make_shared( - shared_from_this(), worker); + shared_from_this(), worker, poller_); worker->SetContext(worker_ctx); worker->SetInstName(inst_name); worker->SetConfig(config); @@ -426,7 +427,7 @@ void App::DispatchMsg(std::list>* msg_list) { } std::lock_guard lock(dispatch_mtx_); for (auto& msg : (*msg_list)) { - DLOG(INFO) << *msg; + VLOG(1) << *msg; /// 处理框架消息 if (msg->GetDst() == MAIN_ADDR) { ProcessMain(msg); @@ -480,14 +481,14 @@ void App::DispatchMsg(std::shared_ptr context) { if (nullptr == context) { return; } - DLOG(INFO) << context->GetActor()->GetActorName() << " dispatch msg..."; + VLOG(1) << context->GetActor()->GetActorName() << " dispatch msg..."; context->SetRuningFlag(false); auto msg_list = context->GetMailbox()->GetSendList(); DispatchMsg(msg_list); } void App::CheckStopWorkers() { - DLOG(INFO) << "check stop worker"; + VLOG(1) << "check stop worker"; worker_ctx_mgr_->WeakupWorker(); LOG_IF(INFO, worker_ctx_mgr_->IdleWorkerSize() == 0) @@ -496,10 +497,10 @@ void App::CheckStopWorkers() { std::shared_ptr worker_ctx = nullptr; while ((worker_ctx = worker_ctx_mgr_->FrontIdleWorker()) != nullptr) { if (nullptr == (actor_ctx = actor_ctx_mgr_->GetContextWithMsg())) { - DLOG(INFO) << "no actor need process, waiting..."; + VLOG(1) << "no actor need process, waiting..."; break; } - DLOG(INFO) + VLOG(1) << actor_ctx->GetActor()->GetActorName() << " dispatch msg to " << *worker_ctx; @@ -509,9 +510,9 @@ void App::CheckStopWorkers() { msg_list->size() > warning_msg_size_.load()) << actor_ctx->GetActor()->GetActorName() << " recv msg size too many: " << msg_list->size(); - DLOG(INFO) << "run " << actor_ctx->GetActor()->GetActorName(); + VLOG(1) << "run " << actor_ctx->GetActor()->GetActorName(); worker_ctx->GetMailbox()->Recv(msg_list); - DLOG(INFO) << actor_ctx->GetActor()->GetActorName() + VLOG(1) << actor_ctx->GetActor()->GetActorName() << " has " << worker_ctx->GetMailbox()->RecvSize() << " msg need process"; worker_ctx_mgr_->PopFrontIdleWorker(); @@ -569,7 +570,7 @@ void App::GetAllUserModAddr(std::string* info) { void App::ProcessTimerEvent(std::shared_ptr worker_ctx) { // 将定时器线程的发送队列分发完毕 - DLOG(INFO) << *worker_ctx << " dispatch msg..."; + VLOG(1) << *worker_ctx << " dispatch msg..."; DispatchMsg(worker_ctx->GetMailbox()->GetSendList()); CmdChannel::Cmd cmd; @@ -577,7 +578,7 @@ void App::ProcessTimerEvent(std::shared_ptr worker_ctx) { cmd_channel->RecvFromOwner(&cmd); switch (cmd) { case CmdChannel::Cmd::kIdle: // idle - DLOG(INFO) << *worker_ctx << " run again"; + VLOG(1) << *worker_ctx << " run again"; cmd_channel->SendToOwner(CmdChannel::Cmd::kRun); break; case CmdChannel::Cmd::kQuit: // quit @@ -594,7 +595,7 @@ void App::ProcessTimerEvent(std::shared_ptr worker_ctx) { void App::ProcessUserEvent(std::shared_ptr worker_ctx) { // 将用户线程的发送队列分发完毕 - DLOG(INFO) << *worker_ctx << " dispatch msg..."; + VLOG(1) << *worker_ctx << " dispatch msg..."; DispatchMsg(worker_ctx->GetMailbox()->GetSendList()); CmdChannel::Cmd cmd; @@ -602,11 +603,11 @@ void App::ProcessUserEvent(std::shared_ptr worker_ctx) { cmd_channel->RecvFromOwner(&cmd); switch (cmd) { case CmdChannel::Cmd::kIdle: // idle - DLOG(INFO) << *worker_ctx << " run again"; + VLOG(1) << *worker_ctx << " run again"; cmd_channel->SendToOwner(CmdChannel::Cmd::kRun); break; case CmdChannel::Cmd::kWaitForMsg: - DLOG(INFO) << *worker_ctx << " wait for msg..."; + VLOG(1) << *worker_ctx << " wait for msg..."; worker_ctx_mgr_->PushWaitWorker(worker_ctx); break; case CmdChannel::Cmd::kQuit: // quit @@ -624,7 +625,7 @@ void App::ProcessUserEvent(std::shared_ptr worker_ctx) { void App::ProcessWorkerEvent(std::shared_ptr worker_ctx) { // 将actor的发送队列分发完毕 auto worker = worker_ctx->GetWorker(); - DLOG_IF(INFO, worker->GetActorContext() != nullptr) + VLOG_IF(1, worker->GetActorContext() != nullptr) << *worker_ctx << " dispatch " << worker->GetActorContext()->GetActor()->GetActorName() << " msg..."; DispatchMsg(worker->GetActorContext()); @@ -636,7 +637,7 @@ void App::ProcessWorkerEvent(std::shared_ptr worker_ctx) { case CmdChannel::Cmd::kIdle: // idle // 将工作线程中的actor状态设置为全局状态 // 将线程加入空闲队列 - DLOG(INFO) + VLOG(1) << *worker_ctx << " idle, push to idle queue"; worker->Idle(); @@ -677,11 +678,16 @@ void App::ProcessEventConn(std::shared_ptr ev) { } void App::ProcessEvent(const std::vector& evs) { - DLOG_IF(INFO, evs.size() > 0) << "get " << evs.size() << " event"; + VLOG_IF(1, evs.size() > 0) << "get " << evs.size() << " event"; for (size_t i = 0; i < evs.size(); ++i) { auto ev_obj = ev_mgr_->Get(evs[i]); if (ev_obj == nullptr) { - LOG(ERROR) << "can't find ev obj, handle " << evs[i]; + std::stringstream ss; + for (size_t x = 0; x < evs.size(); ++x) { + ss << evs[x] << ", "; + } + LOG(WARNING) << "get evs " << ss.str(); + LOG(WARNING) << "can't find ev obj, handle " << evs[i]; continue; } switch (ev_obj->GetType()) { diff --git a/myframe/app.h b/myframe/app.h index b59a5a2..47fbc0a 100644 --- a/myframe/app.h +++ b/myframe/app.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include @@ -17,6 +17,7 @@ Author: likepeng #include "myframe/macros.h" #include "myframe/event.h" +#include "myframe/export.h" namespace myframe { @@ -35,7 +36,7 @@ class WorkerCommon; class WorkerTimer; class WorkerContextManager; class ModManager; -class App final : public std::enable_shared_from_this { +class MYFRAME_EXPORT App final : public std::enable_shared_from_this { friend class Actor; public: @@ -133,10 +134,11 @@ class App final : public std::enable_shared_from_this { std::unordered_map< std::string, std::list>> cache_msg_; - /// poller - std::unique_ptr poller_; + /// 模块管理对象 std::unique_ptr mods_; + /// poller + std::shared_ptr poller_; /// 句柄管理对象 std::unique_ptr actor_ctx_mgr_; /// 事件管理对象 diff --git a/myframe/cmd_channel.cpp b/myframe/cmd_channel.cpp index a74de0f..2848924 100644 --- a/myframe/cmd_channel.cpp +++ b/myframe/cmd_channel.cpp @@ -1,114 +1,49 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/cmd_channel.h" - -#include -#include - -#include - -#include "myframe/common.h" +#include "myframe/platform.h" + +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) + #ifdef MYFRAME_USE_CV + #include "myframe/platform/cmd_channel_generic.h" + #else + #include "myframe/platform/cmd_channel_linux.h" + #endif +#elif defined(MYFRAME_OS_WINDOWS) + #ifdef MYFRAME_USE_CV + #include "myframe/platform/cmd_channel_generic.h" + #else + #error "Windows support conditional variables only," + " set MYFRAME_USE_CV to enable" + #endif +#else +#error "Unsupported platform" +#endif namespace myframe { -CmdChannel::CmdChannel() { - CreateSockpair(); -} - -CmdChannel::~CmdChannel() { - CloseSockpair(); -} - -ev_handle_t CmdChannel::GetOwnerHandle() const { - return sockpair_[0]; -} - -ev_handle_t CmdChannel::GetMainHandle() const { - return sockpair_[1]; -} - -void CmdChannel::CreateSockpair() { - int res = -1; - res = socketpair(AF_UNIX, SOCK_DGRAM, 0, sockpair_); - if (res) { - LOG(ERROR) << "create sockpair failed"; - return; - } - if (!Common::SetNonblockFd(sockpair_[0], false)) { - LOG(ERROR) << "set sockpair[0] block failed, " << strerror(errno); - return; - } - if (!Common::SetNonblockFd(sockpair_[1], false)) { - LOG(ERROR) << "set sockpair[1] block failed, " << strerror(errno); - return; - } -} - -void CmdChannel::CloseSockpair() { - if (close(sockpair_[0])) { - LOG(ERROR) << "close sockpair[0]: " << strerror(errno); - } - if (close(sockpair_[1])) { - LOG(ERROR) << "close sockpair[1]: " << strerror(errno); - } -} - -int CmdChannel::SendToOwner(const Cmd& cmd) { - char cmd_char = static_cast(cmd); - int ret = write(sockpair_[1], &cmd_char, 1); - if (ret < 0) { - LOG(ERROR) << "write 1 cmd failed, " << strerror(errno); - } - return ret; -} - -int CmdChannel::RecvFromOwner(Cmd* cmd) { - char cmd_char; - int ret = read(sockpair_[1], &cmd_char, 1); - if (ret < 0) { - LOG(ERROR) << "read 1 cmd failed, " << strerror(errno); - return ret; - } - *cmd = static_cast(cmd_char); - return ret; -} - -int CmdChannel::RecvFromMain(Cmd* cmd, int timeout_ms) { - if (timeout_ms < 0) { - // block - if (!Common::IsBlockFd(sockpair_[0])) { - Common::SetNonblockFd(sockpair_[0], false); - } - } else if (timeout_ms == 0) { - // nonblock - if (Common::IsBlockFd(sockpair_[0])) { - Common::SetNonblockFd(sockpair_[0], true); - } - } else { - // timeout - Common::SetSockRecvTimeout(sockpair_[0], timeout_ms); - } - char cmd_char; - int ret = read(sockpair_[0], &cmd_char, 1); - if (ret < 0) { - LOG(ERROR) << "read 0 cmd failed, " << strerror(errno); - return ret; - } - *cmd = static_cast(cmd_char); - return ret; -} - -int CmdChannel::SendToMain(const Cmd& cmd) { - char cmd_char = static_cast(cmd); - int ret = write(sockpair_[0], &cmd_char, 1); - if (ret < 0) { - LOG(ERROR) << "write 0 cmd failed, " << strerror(errno); - } - return ret; +std::shared_ptr CmdChannel::Create( + std::shared_ptr poller) { +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) + #ifdef MYFRAME_USE_CV + return std::make_shared(poller); + #else + return std::make_shared(poller); + #endif +#elif defined(MYFRAME_OS_WINDOWS) + #ifdef MYFRAME_USE_CV + return std::make_shared(poller); + #else + #error "Windows support conditional variables only," + " set MYFRAME_USE_CV to enable" + #endif +#else +#error "Unsupported platform" +#endif } } // namespace myframe diff --git a/myframe/cmd_channel.h b/myframe/cmd_channel.h index bd2e6aa..2e8c19a 100644 --- a/myframe/cmd_channel.h +++ b/myframe/cmd_channel.h @@ -1,16 +1,20 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once +#include + +#include "myframe/export.h" #include "myframe/macros.h" #include "myframe/event.h" +#include "myframe/poller.h" namespace myframe { -class CmdChannel final { +class MYFRAME_EXPORT CmdChannel { public: enum class Cmd : char { kQuit = 'q', ///< 退出 @@ -19,24 +23,25 @@ class CmdChannel final { kRun = 'r', ///< 运行 kRunWithMsg = 'm', ///< 运行(有消息) }; + explicit CmdChannel(std::shared_ptr poller) + : poller_(poller) {} + virtual ~CmdChannel() = default; - CmdChannel(); - virtual ~CmdChannel(); + static std::shared_ptr Create(std::shared_ptr); - ev_handle_t GetOwnerHandle() const; - ev_handle_t GetMainHandle() const; + virtual ev_handle_t GetOwnerHandle() const = 0; + virtual ev_handle_t GetMainHandle() const = 0; - int SendToOwner(const Cmd& cmd); - int RecvFromOwner(Cmd* cmd); + virtual int SendToOwner(const Cmd& cmd) = 0; + virtual int RecvFromOwner(Cmd* cmd) = 0; - int SendToMain(const Cmd& cmd); - int RecvFromMain(Cmd* cmd, int timeout_ms = -1); + virtual int SendToMain(const Cmd& cmd) = 0; + virtual int RecvFromMain(Cmd* cmd, int timeout_ms = -1) = 0; - private: - void CreateSockpair(); - void CloseSockpair(); - ev_handle_t sockpair_[2] {-1, -1}; + protected: + std::shared_ptr poller_{nullptr}; + private: DISALLOW_COPY_AND_ASSIGN(CmdChannel) }; diff --git a/myframe/common.cpp b/myframe/common.cpp index 421b693..33491f4 100644 --- a/myframe/common.cpp +++ b/myframe/common.cpp @@ -1,47 +1,33 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ - #include "myframe/common.h" #include -#include -#include -#include -#include + +#include "myframe/platform.h" +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) #include +#else +#error "Platform not supported" +#endif #include #include namespace myframe { -std::vector Common::SplitMsgName(const std::string& name) { - std::vector name_list; - std::string item; - std::stringstream ss(name); - while (std::getline(ss, item, '.')) { - name_list.push_back(item); - } - return name_list; -} - -std::vector Common::GetDirFiles(const std::string& conf_path) { - std::vector res; - DIR* dir = opendir(conf_path.c_str()); - if (dir == nullptr) { - return res; - } - struct dirent* entry = nullptr; - while (nullptr != (entry = readdir(dir))) { - if (entry->d_type == DT_REG) { - res.emplace_back(conf_path + entry->d_name); +std::vector Common::GetDirFiles(const std::string& conf_path) { + std::vector res; + stdfs::path path(conf_path); + for (auto const& dir_entry : stdfs::directory_iterator{path}) { + if (dir_entry.is_regular_file()) { + res.emplace_back(dir_entry.path()); } } - closedir(dir); return res; } @@ -60,39 +46,8 @@ Json::Value Common::LoadJsonFromFile(const std::string& json_file) { return root; } -uint64_t Common::GetMonoTimeMs() { - uint64_t t; - struct timespec ti; - clock_gettime(CLOCK_MONOTONIC, &ti); - t = static_cast(ti.tv_sec * 1000); - t += ti.tv_nsec / 1000000; - return t; -} - -bool Common::SetSockRecvTimeout(int fd, int timeout_ms) { - struct timeval timeout = {timeout_ms / 1000, (timeout_ms % 1000) * 1000}; - return 0 == setsockopt( - fd, SOL_SOCKET, SO_RCVTIMEO, - reinterpret_cast(&timeout), - sizeof(timeout)); -} - -bool Common::SetNonblockFd(int fd, bool b) { - int flags = fcntl(fd, F_GETFL, 0); - if (b) { - flags |= O_NONBLOCK; - } else { - flags &= ~O_NONBLOCK; - } - return fcntl(fd, F_SETFL, flags) != -1; -} - -bool Common::IsBlockFd(int fd) { - int flags = fcntl(fd, F_GETFL, 0); - return !(flags & O_NONBLOCK); -} - stdfs::path Common::GetWorkRoot() { +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) char path_buf[256]; memset(path_buf, 0, sizeof(path_buf)); int ret = readlink("/proc/self/exe", path_buf, sizeof(path_buf)); @@ -110,20 +65,21 @@ stdfs::path Common::GetWorkRoot() { } } return p; +#else + #error "Platform not supported" +#endif } -std::string Common::GetAbsolutePath(const std::string& flag_path) { +stdfs::path Common::GetAbsolutePath(const std::string& flag_path) { stdfs::path p(flag_path); if (p.is_absolute()) { return flag_path; } - p += "/"; auto root = GetWorkRoot(); if (root.empty()) { return flag_path; } - root += "/"; - root += p; + root /= p; return root; } @@ -135,4 +91,14 @@ bool Common::IsAbsolutePath(const std::string& path) { return false; } +std::vector Common::SplitMsgName(const std::string& name) { + std::vector name_list; + std::string item; + std::stringstream ss(name); + while (std::getline(ss, item, '.')) { + name_list.push_back(item); + } + return name_list; +} + } // namespace myframe diff --git a/myframe/common.h b/myframe/common.h index c9e7d81..88db336 100644 --- a/myframe/common.h +++ b/myframe/common.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once @@ -13,28 +13,24 @@ Author: likepeng #if __has_include() #include namespace stdfs = std::filesystem; -#elif __has_include() -#include -namespace stdfs = std::experimental::filesystem; #else -#error "no filesystem" +#error "no filesystem header" #endif #include +#include "myframe/export.h" namespace myframe { -class Common final { +class MYFRAME_EXPORT Common final { public: - static std::vector GetDirFiles(const std::string& conf_path); + static std::vector GetDirFiles(const std::string& conf_path); static Json::Value LoadJsonFromFile(const std::string& json_file); - static uint64_t GetMonoTimeMs(); - static bool SetSockRecvTimeout(int fd, int timeout_ms); - static bool SetNonblockFd(int fd, bool b); - static bool IsBlockFd(int fd); + static stdfs::path GetWorkRoot(); - static std::string GetAbsolutePath(const std::string& flag_path); + static stdfs::path GetAbsolutePath(const std::string& flag_path); static bool IsAbsolutePath(const std::string& path); + template static void ListAppend( std::list>* dst, diff --git a/myframe/config.h.in b/myframe/config.h.in new file mode 100644 index 0000000..79bbc74 --- /dev/null +++ b/myframe/config.h.in @@ -0,0 +1,9 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#pragma once + +#cmakedefine MYFRAME_USE_CV \ No newline at end of file diff --git a/myframe/event.cpp b/myframe/event.cpp new file mode 100644 index 0000000..5b065ab --- /dev/null +++ b/myframe/event.cpp @@ -0,0 +1,26 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#include "myframe/event.h" + +namespace myframe { + +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) + #ifdef MYFRAME_USE_CV + const ev_handle_t Event::DEFAULT_EV_HANDLE{nullptr}; + #endif +#elif defined(MYFRAME_OS_WINDOWS) + #ifdef MYFRAME_USE_CV + const ev_handle_t Event::DEFAULT_EV_HANDLE{nullptr}; + #else + #error "Windows support conditional variables only," + " set MYFRAME_USE_CV to enable" + #endif +#else +#error "Unsupported platform" +#endif + +} // namespace myframe diff --git a/myframe/event.h b/myframe/event.h index ef7c21c..0711a2c 100644 --- a/myframe/event.h +++ b/myframe/event.h @@ -1,18 +1,37 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include #include +#include "myframe/config.h" +#include "myframe/export.h" +#include "myframe/platform.h" + namespace myframe { -typedef int ev_handle_t; +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) + #ifdef MYFRAME_USE_CV + typedef void* ev_handle_t; + #else + typedef int ev_handle_t; + #endif +#elif defined(MYFRAME_OS_WINDOWS) + #ifdef MYFRAME_USE_CV + typedef void* ev_handle_t; + #else + #error "Windows support conditional variables only," + " set MYFRAME_USE_CV to enable" + #endif +#else +#error "Unsupported platform" +#endif -class Event : public std::enable_shared_from_this { +class MYFRAME_EXPORT Event : public std::enable_shared_from_this { public: enum class Type : int { kWorkerCommon, @@ -22,7 +41,7 @@ class Event : public std::enable_shared_from_this { }; Event() = default; - virtual ~Event() {} + virtual ~Event() = default; /* 事件类型 */ virtual Type GetType() const { return Type::kWorkerUser; } @@ -33,7 +52,22 @@ class Event : public std::enable_shared_from_this { /* 事件名称 */ virtual std::string GetName() const = 0; - static const ev_handle_t DEFAULT_EV_HANDLE{-1}; +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) + #ifdef MYFRAME_USE_CV + static const ev_handle_t DEFAULT_EV_HANDLE; + #else + static const ev_handle_t DEFAULT_EV_HANDLE{-1}; + #endif +#elif defined(MYFRAME_OS_WINDOWS) + #ifdef MYFRAME_USE_CV + static const ev_handle_t DEFAULT_EV_HANDLE; + #else + #error "Windows support conditional variables only," + " set MYFRAME_USE_CV to enable" + #endif +#else +#error "Unsupported platform" +#endif }; } // namespace myframe diff --git a/myframe/event_conn.cpp b/myframe/event_conn.cpp index a59cc67..381b936 100644 --- a/myframe/event_conn.cpp +++ b/myframe/event_conn.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/event_conn.h" @@ -13,8 +13,12 @@ Author: likepeng namespace myframe { +EventConn::EventConn(std::shared_ptr poller) { + cmd_channel_ = CmdChannel::Create(poller); +} + ev_handle_t EventConn::GetHandle() const { - return cmd_channel_.GetMainHandle(); + return cmd_channel_->GetMainHandle(); } Event::Type EventConn::GetType() const { @@ -30,7 +34,7 @@ Mailbox* EventConn::GetMailbox() { } CmdChannel* EventConn::GetCmdChannel() { - return &cmd_channel_; + return cmd_channel_.get(); } int EventConn::Send( @@ -39,9 +43,9 @@ int EventConn::Send( conn_type_ = EventConn::Type::kSend; mailbox_.SendClear(); mailbox_.Send(dst, msg); - cmd_channel_.SendToMain(CmdChannel::Cmd::kRun); + cmd_channel_->SendToMain(CmdChannel::Cmd::kRun); CmdChannel::Cmd cmd; - return cmd_channel_.RecvFromMain(&cmd); + return cmd_channel_->RecvFromMain(&cmd); } const std::shared_ptr EventConn::SendRequest( @@ -50,9 +54,9 @@ const std::shared_ptr EventConn::SendRequest( conn_type_ = EventConn::Type::kSendReq; mailbox_.SendClear(); mailbox_.Send(dst, req); - cmd_channel_.SendToMain(CmdChannel::Cmd::kRunWithMsg); + cmd_channel_->SendToMain(CmdChannel::Cmd::kRunWithMsg); CmdChannel::Cmd cmd; - cmd_channel_.RecvFromMain(&cmd); + cmd_channel_->RecvFromMain(&cmd); if (mailbox_.RecvEmpty()) { return nullptr; } diff --git a/myframe/event_conn.h b/myframe/event_conn.h index c108771..63c3d6c 100644 --- a/myframe/event_conn.h +++ b/myframe/event_conn.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include @@ -12,6 +12,7 @@ Author: likepeng #include "myframe/event.h" #include "myframe/mailbox.h" #include "myframe/cmd_channel.h" +#include "myframe/poller.h" namespace myframe { @@ -27,7 +28,7 @@ class EventConn final : public Event { kSend, }; - EventConn() = default; + explicit EventConn(std::shared_ptr); ev_handle_t GetHandle() const override; Event::Type GetType() const override; @@ -47,7 +48,7 @@ class EventConn final : public Event { Mailbox* GetMailbox(); CmdChannel* GetCmdChannel(); - CmdChannel cmd_channel_; + std::shared_ptr cmd_channel_; Mailbox mailbox_; EventConn::Type conn_type_{ EventConn::Type::kSendReq }; diff --git a/myframe/event_conn_manager.cpp b/myframe/event_conn_manager.cpp index 1110953..ab6e345 100644 --- a/myframe/event_conn_manager.cpp +++ b/myframe/event_conn_manager.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/event_conn_manager.h" @@ -14,8 +14,11 @@ Author: likepeng namespace myframe { -EventConnManager::EventConnManager(std::shared_ptr ev_mgr) +EventConnManager::EventConnManager( + std::shared_ptr ev_mgr, + std::shared_ptr poller) : ev_mgr_(ev_mgr) { + poller_ = poller; LOG(INFO) << "EventConnManager create"; } @@ -32,7 +35,7 @@ bool EventConnManager::Init(int sz) { } void EventConnManager::AddEventConn() { - auto conn = std::make_shared(); + auto conn = std::make_shared(poller_); std::string name = "event.conn." + std::to_string(conn_sz_); conn->GetMailbox()->SetAddr(name); idle_conn_.emplace_back(conn); diff --git a/myframe/event_conn_manager.h b/myframe/event_conn_manager.h index e8be907..ca0b1fc 100644 --- a/myframe/event_conn_manager.h +++ b/myframe/event_conn_manager.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include @@ -17,11 +17,14 @@ Author: likepeng namespace myframe { class Msg; +class Poller; class EventManager; class EventConn; class EventConnManager final { public: - EventConnManager(std::shared_ptr); + EventConnManager( + std::shared_ptr, + std::shared_ptr); virtual ~EventConnManager(); bool Init(int sz = 2); @@ -39,6 +42,7 @@ class EventConnManager final { std::mutex mtx_; std::list> idle_conn_; std::shared_ptr ev_mgr_; + std::shared_ptr poller_; DISALLOW_COPY_AND_ASSIGN(EventConnManager) }; diff --git a/myframe/event_manager.cpp b/myframe/event_manager.cpp index c4adc54..9d8f189 100644 --- a/myframe/event_manager.cpp +++ b/myframe/event_manager.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/event_manager.h" diff --git a/myframe/event_manager.h b/myframe/event_manager.h index 4b97d0c..2db37ed 100644 --- a/myframe/event_manager.h +++ b/myframe/event_manager.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include diff --git a/myframe/list.cpp b/myframe/list.cpp index 22aca24..fb213f6 100644 --- a/myframe/list.cpp +++ b/myframe/list.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/list.h" diff --git a/myframe/list.h b/myframe/list.h index dfb5a58..c2ed650 100644 --- a/myframe/list.h +++ b/myframe/list.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once diff --git a/myframe/log.cpp b/myframe/log.cpp index 1721f0d..46afa29 100644 --- a/myframe/log.cpp +++ b/myframe/log.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/log.h" @@ -30,7 +30,7 @@ void InitLog(const std::string& log_dir, const std::string& bin_name) { FLAGS_stop_logging_if_full_disk = true; auto full_log_dir = Common::GetAbsolutePath(log_dir); - std::string dst_str = full_log_dir + bin_name; + std::string dst_str = (full_log_dir / bin_name).string(); google::SetLogDestination(google::ERROR, ""); google::SetLogDestination(google::WARNING, ""); google::SetLogDestination(google::FATAL, ""); diff --git a/myframe/log.h b/myframe/log.h index a9d8049..e3b83d1 100644 --- a/myframe/log.h +++ b/myframe/log.h @@ -1,16 +1,19 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include +#include "myframe/export.h" namespace myframe { -void InitLog(const std::string& log_dir, const std::string& bin_name); +MYFRAME_EXPORT void InitLog( + const std::string& log_dir, + const std::string& bin_name); -void ShutdownLog(); +MYFRAME_EXPORT void ShutdownLog(); } // namespace myframe diff --git a/myframe/macros.h b/myframe/macros.h index e488dba..9216739 100644 --- a/myframe/macros.h +++ b/myframe/macros.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once diff --git a/myframe/mailbox.cpp b/myframe/mailbox.cpp index 411205c..5dabef3 100644 --- a/myframe/mailbox.cpp +++ b/myframe/mailbox.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/mailbox.h" #include "myframe/common.h" diff --git a/myframe/mailbox.h b/myframe/mailbox.h index 55fcabe..1729293 100644 --- a/myframe/mailbox.h +++ b/myframe/mailbox.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include @@ -10,10 +10,12 @@ Author: likepeng #include #include +#include "myframe/export.h" + namespace myframe { class Msg; -class Mailbox final { +class MYFRAME_EXPORT Mailbox final { friend class ActorContext; friend class WorkerContext; friend class EventConnManager; @@ -56,6 +58,7 @@ class Mailbox final { std::list> send_; }; -std::ostream& operator<<(std::ostream& out, const Mailbox& mailbox); +MYFRAME_EXPORT std::ostream& operator<<( + std::ostream& out, const Mailbox& mailbox); } // namespace myframe diff --git a/myframe/mod_manager.cpp b/myframe/mod_manager.cpp index 901d6fa..7a0d055 100644 --- a/myframe/mod_manager.cpp +++ b/myframe/mod_manager.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/mod_manager.h" @@ -28,10 +28,10 @@ bool ModManager::LoadMod(const std::string& dl_path) { auto dlname = GetLibName(dl_path); std::unique_lock lk(mods_rw_); if (mods_.find(dlname) != mods_.end()) { - DLOG(INFO) << dlname << " has loaded"; + VLOG(1) << dlname << " has loaded"; return true; } - auto lib = std::make_shared(); + auto lib = SharedLibrary::Create(); if (!lib->Load(dl_path, SharedLibrary::Flags::kLocal)) { return false; } @@ -73,7 +73,7 @@ std::shared_ptr ModManager::CreateActorInst( { std::shared_lock lk(mods_rw_); if (mods_.find(mod_or_class_name) != mods_.end()) { - DLOG(INFO) << actor_name << " actor from lib"; + VLOG(1) << actor_name << " actor from lib"; auto lib = mods_[mod_or_class_name]; auto void_func = lib->GetSymbol("actor_create"); auto create = reinterpret_cast(void_func); @@ -98,7 +98,7 @@ std::shared_ptr ModManager::CreateActorInst( std::shared_lock lk(class_actor_rw_); if (mod_or_class_name == "class" && class_actors_.find(actor_name) != class_actors_.end()) { - DLOG(INFO) << actor_name << " actor from reg class"; + VLOG(1) << actor_name << " actor from reg class"; auto actor = class_actors_[actor_name](actor_name); actor->SetModName(mod_or_class_name); actor->SetTypeName(actor_name); diff --git a/myframe/mod_manager.h b/myframe/mod_manager.h index aa75c64..b869be7 100644 --- a/myframe/mod_manager.h +++ b/myframe/mod_manager.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once @@ -13,6 +13,7 @@ Author: likepeng #include #include +#include "myframe/export.h" #include "myframe/macros.h" namespace myframe { @@ -20,7 +21,7 @@ namespace myframe { class Actor; class Worker; class SharedLibrary; -class ModManager final { +class MYFRAME_EXPORT ModManager final { public: ModManager(); virtual ~ModManager(); diff --git a/myframe/msg.cpp b/myframe/msg.cpp index 1ef9943..58bb131 100644 --- a/myframe/msg.cpp +++ b/myframe/msg.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/msg.h" diff --git a/myframe/msg.h b/myframe/msg.h index a2bf7cb..2242aa0 100644 --- a/myframe/msg.h +++ b/myframe/msg.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once @@ -10,6 +10,8 @@ Author: likepeng #include #include +#include "myframe/export.h" + namespace myframe { /* 发送给框架的地址 */ @@ -28,7 +30,7 @@ const char* const MAIN_ADDR = "main"; */ const char* const MAIN_CMD_ALL_USER_MOD_ADDR = "kAllUserModAddr"; -class Msg final { +class MYFRAME_EXPORT Msg final { public: Msg() = default; Msg(const char* data); @@ -87,6 +89,6 @@ class Msg final { std::any any_data_; }; -std::ostream& operator<<(std::ostream& out, const Msg& msg); +MYFRAME_EXPORT std::ostream& operator<<(std::ostream& out, const Msg& msg); } // namespace myframe diff --git a/myframe/platform.h b/myframe/platform.h new file mode 100644 index 0000000..5a83284 --- /dev/null +++ b/myframe/platform.h @@ -0,0 +1,17 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#pragma once + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) + #define MYFRAME_OS_WINDOWS +#elif defined(linux) || defined(__linux) || defined(__linux__) + #define MYFRAME_OS_LINUX +#elif defined(ANDROID) || defined(__ANDROID__) + #define MYFRAME_OS_ANDROID +#else + #error Platform not supported by myframe. +#endif diff --git a/myframe/platform/cmd_channel_generic.h b/myframe/platform/cmd_channel_generic.h new file mode 100644 index 0000000..90b48b1 --- /dev/null +++ b/myframe/platform/cmd_channel_generic.h @@ -0,0 +1,110 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#pragma once +#include +#include +#include +#include +#include + +#include + +#include "myframe/common.h" +#include "myframe/export.h" +#include "myframe/macros.h" +#include "myframe/event.h" +#include "myframe/cmd_channel.h" + +namespace myframe { + +class CmdChannelGeneric final : public CmdChannel { + public: + explicit CmdChannelGeneric(std::shared_ptr); + virtual ~CmdChannelGeneric(); + + ev_handle_t GetOwnerHandle() const override; + ev_handle_t GetMainHandle() const override; + + int SendToOwner(const Cmd& cmd) override; + int RecvFromOwner(Cmd* cmd) override; + + int SendToMain(const Cmd& cmd) override; + int RecvFromMain(Cmd* cmd, int timeout_ms = -1) override; + + private: + std::mutex main_cmd_mtx_; + std::list to_main_cmd_; + + std::mutex mtx_; + std::list to_owner_cmd_; + std::condition_variable cv_; + + DISALLOW_COPY_AND_ASSIGN(CmdChannelGeneric) +}; + +CmdChannelGeneric::CmdChannelGeneric(std::shared_ptr poller) + : CmdChannel(poller) { +} + +CmdChannelGeneric::~CmdChannelGeneric() { + LOG(INFO) << "CmdChannel " << this << " deconstruct"; +} + +ev_handle_t CmdChannelGeneric::GetOwnerHandle() const { + return reinterpret_cast(const_cast(this)); +} + +ev_handle_t CmdChannelGeneric::GetMainHandle() const { + return reinterpret_cast(const_cast(this)); +} + +int CmdChannelGeneric::SendToOwner(const Cmd& cmd) { + std::lock_guard lk(mtx_); + to_owner_cmd_.push_back(cmd); + cv_.notify_one(); + return 0; +} + +int CmdChannelGeneric::RecvFromOwner(Cmd* cmd) { + std::lock_guard lk(main_cmd_mtx_); + *cmd = to_main_cmd_.front(); + to_main_cmd_.pop_front(); + return 0; +} + +int CmdChannelGeneric::RecvFromMain(Cmd* cmd, int timeout_ms) { + std::unique_lock lk(mtx_); + using namespace std::chrono_literals; // NOLINT + if (timeout_ms > 0) { + cv_.wait_for(lk, timeout_ms * 1ms, + [this](){ return !to_owner_cmd_.empty(); }); + } else { + cv_.wait(lk, [this](){ return !to_owner_cmd_.empty(); }); + } + if (to_owner_cmd_.size() > 1) { + std::stringstream ss; + for (Cmd p : to_owner_cmd_) { + ss << static_cast(p) << ", "; + } + LOG(WARNING) << this << " too many cmd " << ss.str(); + } + *cmd = to_owner_cmd_.front(); + to_owner_cmd_.pop_front(); + return 0; +} + +int CmdChannelGeneric::SendToMain(const Cmd& cmd) { + std::lock_guard lk(main_cmd_mtx_); + to_main_cmd_.push_back(cmd); + + poller_->Notify( + reinterpret_cast( + const_cast(this))); + return 0; +} + +} // namespace myframe diff --git a/myframe/platform/cmd_channel_linux.h b/myframe/platform/cmd_channel_linux.h new file mode 100644 index 0000000..741066f --- /dev/null +++ b/myframe/platform/cmd_channel_linux.h @@ -0,0 +1,172 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#pragma once +#include +#include +#include + +#include + +#include + +#include "myframe/common.h" +#include "myframe/export.h" +#include "myframe/macros.h" +#include "myframe/event.h" +#include "myframe/cmd_channel.h" + +namespace myframe { + +class CmdChannelLinux final : public CmdChannel { + public: + explicit CmdChannelLinux(std::shared_ptr); + virtual ~CmdChannelLinux(); + + ev_handle_t GetOwnerHandle() const override; + ev_handle_t GetMainHandle() const override; + + int SendToOwner(const Cmd& cmd) override; + int RecvFromOwner(Cmd* cmd) override; + + int SendToMain(const Cmd& cmd) override; + int RecvFromMain(Cmd* cmd, int timeout_ms = -1) override; + + private: + void CreateSockpair(); + void CloseSockpair(); + + bool SetSockRecvTimeout(int fd, int timeout_ms) const; + bool SetNonblockFd(int fd, bool b) const; + bool IsBlockFd(int fd) const; + + ev_handle_t sockpair_[2] {-1, -1}; + + DISALLOW_COPY_AND_ASSIGN(CmdChannelLinux) +}; + +CmdChannelLinux::CmdChannelLinux(std::shared_ptr poller) + : CmdChannel(poller) { + CreateSockpair(); +} + +CmdChannelLinux::~CmdChannelLinux() { + CloseSockpair(); +} + +ev_handle_t CmdChannelLinux::GetOwnerHandle() const { + return sockpair_[0]; +} + +ev_handle_t CmdChannelLinux::GetMainHandle() const { + return sockpair_[1]; +} + +void CmdChannelLinux::CreateSockpair() { + int res = -1; + res = socketpair(AF_UNIX, SOCK_DGRAM, 0, sockpair_); + if (res) { + LOG(ERROR) << "create sockpair failed"; + return; + } + if (!SetNonblockFd(sockpair_[0], false)) { + LOG(ERROR) << "set sockpair[0] block failed, " << strerror(errno); + return; + } + if (!SetNonblockFd(sockpair_[1], false)) { + LOG(ERROR) << "set sockpair[1] block failed, " << strerror(errno); + return; + } +} + +void CmdChannelLinux::CloseSockpair() { + if (close(sockpair_[0])) { + LOG(ERROR) << "close sockpair[0]: " << strerror(errno); + } + if (close(sockpair_[1])) { + LOG(ERROR) << "close sockpair[1]: " << strerror(errno); + } +} + +int CmdChannelLinux::SendToOwner(const Cmd& cmd) { + char cmd_char = static_cast(cmd); + int ret = write(sockpair_[1], &cmd_char, 1); + if (ret < 0) { + LOG(ERROR) << "write 1 cmd failed, " << strerror(errno); + } + return ret; +} + +int CmdChannelLinux::RecvFromOwner(Cmd* cmd) { + char cmd_char; + int ret = read(sockpair_[1], &cmd_char, 1); + if (ret < 0) { + LOG(ERROR) << "read 1 cmd failed, " << strerror(errno); + return ret; + } + *cmd = static_cast(cmd_char); + return ret; +} + +int CmdChannelLinux::RecvFromMain(Cmd* cmd, int timeout_ms) { + (void)timeout_ms; + if (timeout_ms < 0) { + // block + if (!IsBlockFd(sockpair_[0])) { + SetNonblockFd(sockpair_[0], false); + } + } else if (timeout_ms == 0) { + // nonblock + if (IsBlockFd(sockpair_[0])) { + SetNonblockFd(sockpair_[0], true); + } + } else { + // timeout + SetSockRecvTimeout(sockpair_[0], timeout_ms); + } + char cmd_char; + int ret = read(sockpair_[0], &cmd_char, 1); + if (ret < 0) { + LOG(ERROR) << "read 0 cmd failed, " << strerror(errno); + return ret; + } + *cmd = static_cast(cmd_char); + return ret; +} + +int CmdChannelLinux::SendToMain(const Cmd& cmd) { + char cmd_char = static_cast(cmd); + int ret = write(sockpair_[0], &cmd_char, 1); + if (ret < 0) { + LOG(ERROR) << "write 0 cmd failed, " << strerror(errno); + } + return ret; +} + +bool CmdChannelLinux::SetSockRecvTimeout(int fd, int timeout_ms) const { + struct timeval timeout = {timeout_ms / 1000, (timeout_ms % 1000) * 1000}; + return 0 == setsockopt( + fd, SOL_SOCKET, SO_RCVTIMEO, + reinterpret_cast(&timeout), + sizeof(timeout)); +} + +bool CmdChannelLinux::SetNonblockFd(int fd, bool b) const { + int flags = fcntl(fd, F_GETFL, 0); + if (b) { + flags |= O_NONBLOCK; + } else { + flags &= ~O_NONBLOCK; + } + return fcntl(fd, F_SETFL, flags) != -1; +} + +bool CmdChannelLinux::IsBlockFd(int fd) const { + int flags = fcntl(fd, F_GETFL, 0); + return !(flags & O_NONBLOCK); +} + +} // namespace myframe diff --git a/myframe/platform/poller_generic.h b/myframe/platform/poller_generic.h new file mode 100644 index 0000000..10a7597 --- /dev/null +++ b/myframe/platform/poller_generic.h @@ -0,0 +1,70 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ + +#pragma once +#include +#include +#include +#include +#include + +#include + +#include "myframe/macros.h" +#include "myframe/event.h" +#include "myframe/poller.h" + +namespace myframe { + +class PollerGeneric final : public Poller { + public: + PollerGeneric() = default; + virtual ~PollerGeneric(); + + bool Init() override; + int Wait(std::vector* evs, int timeout_ms = 100) override; + void Notify(ev_handle_t h) override; + + private: + std::vector evs_; + std::mutex mtx_; + std::condition_variable cv_; + + DISALLOW_COPY_AND_ASSIGN(PollerGeneric) +}; + +PollerGeneric::~PollerGeneric() { + LOG(INFO) << "poller deconstruct"; +} + +bool PollerGeneric::Init() { + return true; +} + +int PollerGeneric::Wait(std::vector* evs, int timeout_ms) { + evs->clear(); + using namespace std::chrono_literals; // NOLINT + std::unique_lock lk(mtx_); + if (timeout_ms > 0) { + cv_.wait_for(lk, timeout_ms * 1ms, [this](){ return !evs_.empty(); }); + } else { + cv_.wait(lk, [this](){ return !evs_.empty(); }); + } + for (auto it = evs_.begin(); it != evs_.end(); ++it) { + evs->push_back(*it); + } + evs_.clear(); + return evs->size(); +} + +void PollerGeneric::Notify(ev_handle_t h) { + std::lock_guard lk(mtx_); + evs_.push_back(h); + cv_.notify_one(); +} + +} // namespace myframe diff --git a/myframe/platform/poller_linux.h b/myframe/platform/poller_linux.h new file mode 100644 index 0000000..f044b97 --- /dev/null +++ b/myframe/platform/poller_linux.h @@ -0,0 +1,133 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ + +#pragma once +#include +#include + +#include +#include +#include + +#include + +#include "myframe/macros.h" +#include "myframe/event.h" +#include "myframe/poller.h" + +struct epoll_event; + +namespace myframe { + +class PollerLinux final : public Poller { + public: + PollerLinux() = default; + virtual ~PollerLinux(); + + bool Init() override; + bool Add(const std::shared_ptr&) const override; + bool Del(const std::shared_ptr&) const override; + int Wait(std::vector* evs, int timeout_ms = 100) override; + + private: + std::atomic_bool init_{false}; + int poll_fd_{-1}; + size_t max_ev_count_{64}; + struct epoll_event* evs_{nullptr}; + + DISALLOW_COPY_AND_ASSIGN(PollerLinux) +}; + +PollerLinux::~PollerLinux() { + if (poll_fd_ != -1) { + close(poll_fd_); + poll_fd_ = -1; + } + if (evs_ != nullptr) { + free(evs_); + evs_ = nullptr; + } + init_.store(false); +} + +bool PollerLinux::Init() { + if (init_.load()) { + return true; + } + poll_fd_ = epoll_create(1024); + if (-1 == poll_fd_) { + LOG(ERROR) << "poller create() failed, " << strerror(errno); + return false; + } + LOG(INFO) << "Create epoll fd " << poll_fd_; + auto void_evs = malloc(sizeof(struct epoll_event) * max_ev_count_); + evs_ = reinterpret_cast(void_evs); + init_.store(true); + return true; +} + +bool PollerLinux::Add(const std::shared_ptr& ev) const { + if (!init_.load()) { + return false; + } + struct epoll_event event; + event.data.fd = ev->GetHandle(); + event.events = EPOLLIN; + int res = 0; + // 如果该事件已经注册,就修改事件类型 + res = epoll_ctl(poll_fd_, EPOLL_CTL_MOD, ev->GetHandle(), &event); + if (-1 == res) { + // 没有注册就添加至epoll + res = epoll_ctl(poll_fd_, EPOLL_CTL_ADD, ev->GetHandle(), &event); + if (-1 == res) { + LOG(ERROR) << "epoll_ctl error, " << strerror(errno); + return false; + } + } else { + LOG(WARNING) + << " has already reg ev " << ev->GetHandle() << ": " + << strerror(errno); + return false; + } + return true; +} + +bool PollerLinux::Del(const std::shared_ptr& ev) const { + if (!init_.load()) { + return false; + } + if (-1 == epoll_ctl(poll_fd_, EPOLL_CTL_DEL, ev->GetHandle(), NULL)) { + LOG(ERROR) << "del event " << ev->GetHandle() << ": " << strerror(errno); + return false; + } + return true; +} + +int PollerLinux::Wait(std::vector* evs, int timeout_ms) { + if (!init_.load()) { + return -1; + } + evs->clear(); + int ev_count = epoll_wait(poll_fd_, + evs_, + static_cast(max_ev_count_), + timeout_ms); + if (0 > ev_count) { + LOG(WARNING) << "epoll wait error: " << strerror(errno); + return -1; + } + for (int i = 0; i < ev_count; ++i) { + if (evs_[i].events != EPOLLIN) { + LOG(WARNING) << "epoll event " << evs_[i].events << " continue"; + continue; + } + evs->push_back(evs_[i].data.fd); + } + return ev_count; +} + +} // namespace myframe diff --git a/myframe/platform/shared_library_linux.h b/myframe/platform/shared_library_linux.h new file mode 100644 index 0000000..c6ef406 --- /dev/null +++ b/myframe/platform/shared_library_linux.h @@ -0,0 +1,111 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ + +#pragma once +#include + +#include +#include +#include +#include + +#include + +#include "myframe/macros.h" +#include "myframe/shared_library.h" + +namespace myframe { + +class SharedLibraryLinux final : public SharedLibrary { + public: + SharedLibraryLinux() = default; + virtual ~SharedLibraryLinux(); + + bool Load(const std::string& path) override; + bool Load(const std::string& path, Flags flags) override; + + void Unload() override; + + bool IsLoaded() override; + + bool HasSymbol(const std::string& name) override; + + void* GetSymbol(const std::string& name) override; + + private: + void* handle_{ nullptr }; + std::mutex mutex_; + + DISALLOW_COPY_AND_ASSIGN(SharedLibraryLinux) +}; + +SharedLibraryLinux::~SharedLibraryLinux() { + Unload(); +} + +bool SharedLibraryLinux::Load(const std::string& path) { + return Load(path, Flags::kGlobal); +} + +bool SharedLibraryLinux::Load( + const std::string& path, + Flags flags) { + std::lock_guard lock(mutex_); + if (handle_ != nullptr) { + return false; + } + int real_flag = RTLD_NOW; + if (static_cast(flags) & static_cast(Flags::kLocal)) { + real_flag |= RTLD_LOCAL; + } else { + real_flag |= RTLD_GLOBAL; + } + handle_ = dlopen(path.c_str(), real_flag); + if (handle_ == nullptr) { + LOG(ERROR) << "Open dll " << path << " failed, " << dlerror(); + return false; + } + SetPath(path); + return true; +} + +void SharedLibraryLinux::Unload() { + std::lock_guard lock(mutex_); + if (handle_ == nullptr) { + return; + } + if (dlclose(handle_)) { + LOG(ERROR) << "lib " << GetPath() << " close failed, " << dlerror(); + } + handle_ = nullptr; +} + +bool SharedLibraryLinux::IsLoaded() { + std::lock_guard lock(mutex_); + return handle_ != nullptr; +} + +bool SharedLibraryLinux::HasSymbol(const std::string& name) { + return GetSymbol(name) != nullptr; +} + +void* SharedLibraryLinux::GetSymbol(const std::string& name) { + std::lock_guard lock(mutex_); + if (handle_ == nullptr) { + return nullptr; + } + + void* result = dlsym(handle_, name.c_str()); + if (result == nullptr) { + LOG(ERROR) << "lib " << GetPath() + << " has no symbol " << name << ", " << dlerror(); + return nullptr; + } + return result; +} + +} // namespace myframe diff --git a/myframe/poller.cpp b/myframe/poller.cpp index 500307c..4946d62 100644 --- a/myframe/poller.cpp +++ b/myframe/poller.cpp @@ -1,105 +1,48 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ - #include "myframe/poller.h" - -#include -#include - -#include +#include "myframe/platform.h" + +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) + #ifdef MYFRAME_USE_CV + #include "myframe/platform/poller_generic.h" + #else + #include "myframe/platform/poller_linux.h" + #endif +#elif defined(MYFRAME_OS_WINDOWS) + #ifdef MYFRAME_USE_CV + #include "myframe/platform/poller_generic.h" + #else + #error "Windows support conditional variables only," + " set MYFRAME_USE_CV to enable" + #endif +#else +#error "Unsupported platform" +#endif namespace myframe { -Poller::~Poller() { - if (poll_fd_ != -1) { - close(poll_fd_); - poll_fd_ = -1; - } - if (evs_ != nullptr) { - free(evs_); - evs_ = nullptr; - } - init_.store(false); -} - -bool Poller::Init() { - if (init_.load()) { - return true; - } - poll_fd_ = epoll_create(1024); - if (-1 == poll_fd_) { - LOG(ERROR) << "poller create() failed, " << strerror(errno); - return false; - } - LOG(INFO) << "Create epoll fd " << poll_fd_; - auto void_evs = malloc(sizeof(struct epoll_event) * max_ev_count_); - evs_ = reinterpret_cast(void_evs); - init_.store(true); - return true; -} - -bool Poller::Add(const std::shared_ptr& ev) const { - if (!init_.load()) { - return false; - } - struct epoll_event event; - event.data.fd = ev->GetHandle(); - event.events = EPOLLIN; - int res = 0; - // 如果该事件已经注册,就修改事件类型 - res = epoll_ctl(poll_fd_, EPOLL_CTL_MOD, ev->GetHandle(), &event); - if (-1 == res) { - // 没有注册就添加至epoll - res = epoll_ctl(poll_fd_, EPOLL_CTL_ADD, ev->GetHandle(), &event); - if (-1 == res) { - LOG(ERROR) << "epoll_ctl error, " << strerror(errno); - return false; - } - } else { - LOG(WARNING) - << " has already reg ev " << ev->GetHandle() << ": " - << strerror(errno); - return false; - } - return true; -} - -bool Poller::Del(const std::shared_ptr& ev) const { - if (!init_.load()) { - return false; - } - if (-1 == epoll_ctl(poll_fd_, EPOLL_CTL_DEL, ev->GetHandle(), NULL)) { - LOG(ERROR) << "del event " << ev->GetHandle() << ": " << strerror(errno); - return false; - } - return true; -} - -int Poller::Wait(std::vector* evs, int timeout_ms) { - if (!init_.load()) { - return -1; - } - evs->clear(); - int ev_count = epoll_wait(poll_fd_, - evs_, - static_cast(max_ev_count_), - timeout_ms); - if (0 > ev_count) { - LOG(WARNING) << "epoll wait error: " << strerror(errno); - return -1; - } - for (int i = 0; i < ev_count; ++i) { - if (evs_[i].events != EPOLLIN) { - LOG(WARNING) << "epoll event " << evs_[i].events << " continue"; - continue; - } - evs->push_back(evs_[i].data.fd); - } - return ev_count; +std::shared_ptr Poller::Create() { +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) + #ifdef MYFRAME_USE_CV + return std::make_shared(); + #else + return std::make_shared(); + #endif +#elif defined(MYFRAME_OS_WINDOWS) + #ifdef MYFRAME_USE_CV + return std::make_shared(); + #else + #error "Windows support conditional variables only," + " set MYFRAME_USE_CV to enable" + #endif +#else +#error "Unsupported platform" +#endif } } // namespace myframe diff --git a/myframe/poller.h b/myframe/poller.h index d16dca6..78fc248 100644 --- a/myframe/poller.h +++ b/myframe/poller.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once @@ -10,29 +10,26 @@ Author: likepeng #include #include +#include "myframe/export.h" #include "myframe/macros.h" #include "myframe/event.h" -struct epoll_event; - namespace myframe { -class Poller final { +class MYFRAME_EXPORT Poller { public: - explicit Poller() = default; - ~Poller(); + Poller() = default; + virtual ~Poller() = default; - bool Init(); - bool Add(const std::shared_ptr&) const; - bool Del(const std::shared_ptr&) const; - int Wait(std::vector* evs, int timeout_ms = 100); + static std::shared_ptr Create(); - private: - std::atomic_bool init_{false}; - int poll_fd_{-1}; - size_t max_ev_count_{64}; - struct epoll_event* evs_{nullptr}; + virtual bool Init() = 0; + virtual bool Add(const std::shared_ptr&) const { return true; } + virtual bool Del(const std::shared_ptr&) const { return true; } + virtual int Wait(std::vector* evs, int timeout_ms = 100) = 0; + virtual void Notify(ev_handle_t) {} + private: DISALLOW_COPY_AND_ASSIGN(Poller) }; diff --git a/myframe/shared_library.cpp b/myframe/shared_library.cpp index 661fa7c..58b7ab4 100644 --- a/myframe/shared_library.cpp +++ b/myframe/shared_library.cpp @@ -1,81 +1,26 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ - #include "myframe/shared_library.h" +#include "myframe/platform.h" -#include - -#include +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) +#include "myframe/platform/shared_library_linux.h" +#else +#error "Platform not supported" +#endif namespace myframe { -SharedLibrary::~SharedLibrary() { - Unload(); -} - -bool SharedLibrary::Load(const std::string& path) { - return Load(path, Flags::kGlobal); -} - -bool SharedLibrary::Load( - const std::string& path, - Flags flags) { - std::lock_guard lock(mutex_); - if (handle_ != nullptr) { - return false; - } - int real_flag = RTLD_NOW; - if (static_cast(flags) & static_cast(Flags::kLocal)) { - real_flag |= RTLD_LOCAL; - } else { - real_flag |= RTLD_GLOBAL; - } - handle_ = dlopen(path.c_str(), real_flag); - if (handle_ == nullptr) { - LOG(ERROR) << "Open dll " << path << " failed, " << dlerror(); - return false; - } - path_ = path; - return true; -} - -void SharedLibrary::Unload() { - std::lock_guard lock(mutex_); - if (handle_ == nullptr) { - return; - } - if (dlclose(handle_)) { - LOG(ERROR) << "lib " << path_ << " close failed, " << dlerror(); - } - handle_ = nullptr; -} - -bool SharedLibrary::IsLoaded() { - std::lock_guard lock(mutex_); - return handle_ != nullptr; -} - -bool SharedLibrary::HasSymbol(const std::string& name) { - return GetSymbol(name) != nullptr; -} - -void* SharedLibrary::GetSymbol(const std::string& name) { - std::lock_guard lock(mutex_); - if (handle_ == nullptr) { - return nullptr; - } - - void* result = dlsym(handle_, name.c_str()); - if (result == nullptr) { - LOG(ERROR) << "lib " << path_ - << " has no symbol " << name << ", " << dlerror(); - return nullptr; - } - return result; +std::shared_ptr SharedLibrary::Create() { +#if defined(MYFRAME_OS_LINUX) || defined(MYFRAME_OS_ANDROID) + return std::make_shared(); +#else + return nullptr; +#endif } } // namespace myframe diff --git a/myframe/shared_library.h b/myframe/shared_library.h index f8c646b..7ed1b28 100644 --- a/myframe/shared_library.h +++ b/myframe/shared_library.h @@ -1,15 +1,13 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once -#include -#include -#include #include +#include #include "myframe/macros.h" @@ -32,25 +30,28 @@ class SharedLibrary { }; SharedLibrary() = default; - virtual ~SharedLibrary(); + virtual ~SharedLibrary() = default; - bool Load(const std::string& path); - bool Load(const std::string& path, Flags flags); + static std::shared_ptr Create(); - void Unload(); + virtual bool Load(const std::string& path) = 0; + virtual bool Load(const std::string& path, Flags flags) = 0; - bool IsLoaded(); + virtual void Unload() = 0; - bool HasSymbol(const std::string& name); + virtual bool IsLoaded() = 0; - void* GetSymbol(const std::string& name); + virtual bool HasSymbol(const std::string& name) = 0; + + virtual void* GetSymbol(const std::string& name) = 0; inline const std::string& GetPath() const { return path_; } + protected: + inline void SetPath(const std::string& path) { path_ = path; } + private: - void* handle_{ nullptr }; std::string path_; - std::mutex mutex_; DISALLOW_COPY_AND_ASSIGN(SharedLibrary) }; diff --git a/myframe/worker.cpp b/myframe/worker.cpp index b335f90..2a1e892 100644 --- a/myframe/worker.cpp +++ b/myframe/worker.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/worker.h" @@ -39,9 +39,6 @@ void Worker::Stop() { int Worker::DispatchMsg() { auto channel = GetCmdChannel(); - if (channel == nullptr) { - return -1; - } CmdChannel::Cmd cmd = CmdChannel::Cmd::kIdle; channel->SendToMain(cmd); auto ret = channel->RecvFromMain(&cmd); @@ -55,9 +52,6 @@ int Worker::DispatchMsg() { int Worker::DispatchAndWaitMsg() { auto channel = GetCmdChannel(); - if (channel == nullptr) { - return -1; - } CmdChannel::Cmd cmd = CmdChannel::Cmd::kWaitForMsg; channel->SendToMain(cmd); auto ret = channel->RecvFromMain(&cmd); @@ -79,9 +73,8 @@ Mailbox* Worker::GetMailbox() { CmdChannel* Worker::GetCmdChannel() { auto ctx = ctx_.lock(); - if (ctx == nullptr) { - return nullptr; - } + LOG_IF(FATAL, ctx == nullptr) + << "worker ctx is nullptr"; return ctx->GetCmdChannel(); } diff --git a/myframe/worker.h b/myframe/worker.h index b0e22cb..7fd43df 100644 --- a/myframe/worker.h +++ b/myframe/worker.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once #include @@ -10,6 +10,7 @@ Author: likepeng #include +#include "myframe/export.h" #include "myframe/macros.h" #include "myframe/mailbox.h" #include "myframe/cmd_channel.h" @@ -19,7 +20,7 @@ namespace myframe { class App; class WorkerContext; -class Worker { +class MYFRAME_EXPORT Worker { friend class App; friend class ModLib; friend class ModManager; @@ -127,6 +128,7 @@ class Worker { } // namespace myframe +template class std::shared_ptr; extern "C" { typedef std::shared_ptr (*worker_create_func_t)( const std::string&); diff --git a/myframe/worker_common.cpp b/myframe/worker_common.cpp index 4f46b69..cdd1b5b 100644 --- a/myframe/worker_common.cpp +++ b/myframe/worker_common.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/worker_common.h" diff --git a/myframe/worker_common.h b/myframe/worker_common.h index e0a9af1..9a9558b 100644 --- a/myframe/worker_common.h +++ b/myframe/worker_common.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once diff --git a/myframe/worker_context.cpp b/myframe/worker_context.cpp index 5884829..fbcee29 100644 --- a/myframe/worker_context.cpp +++ b/myframe/worker_context.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/worker_context.h" @@ -19,10 +19,12 @@ namespace myframe { WorkerContext::WorkerContext( std::shared_ptr app, - std::shared_ptr worker) + std::shared_ptr worker, + std::shared_ptr poller) : runing_(false) , worker_(worker) , app_(app) { + cmd_channel_ = CmdChannel::Create(poller); } WorkerContext::~WorkerContext() { @@ -30,7 +32,7 @@ WorkerContext::~WorkerContext() { } ev_handle_t WorkerContext::GetHandle() const { - return cmd_channel_.GetMainHandle(); + return cmd_channel_->GetMainHandle(); } Event::Type WorkerContext::GetType() const { @@ -72,7 +74,7 @@ void WorkerContext::ListenThread() { worker_->Run(); } worker_->Exit(); - cmd_channel_.SendToMain(CmdChannel::Cmd::kQuit); + cmd_channel_->SendToMain(CmdChannel::Cmd::kQuit); } std::size_t WorkerContext::CacheSize() const { @@ -96,7 +98,7 @@ Mailbox* WorkerContext::GetMailbox() { } CmdChannel* WorkerContext::GetCmdChannel() { - return &cmd_channel_; + return cmd_channel_.get(); } std::shared_ptr WorkerContext::GetApp() { diff --git a/myframe/worker_context.h b/myframe/worker_context.h index 26cf928..b6e45fe 100644 --- a/myframe/worker_context.h +++ b/myframe/worker_context.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once @@ -30,7 +30,10 @@ class WorkerContext final : public Event { kWorker, }; - WorkerContext(std::shared_ptr app, std::shared_ptr worker); + WorkerContext( + std::shared_ptr app, + std::shared_ptr worker, + std::shared_ptr poller); virtual ~WorkerContext(); /// thread 相关函数 @@ -96,7 +99,7 @@ class WorkerContext final : public Event { Mailbox mailbox_; /// cmd channel - CmdChannel cmd_channel_; + std::shared_ptr cmd_channel_; /// thread std::thread th_; diff --git a/myframe/worker_context_manager.cpp b/myframe/worker_context_manager.cpp index e36bf7d..7c319d6 100644 --- a/myframe/worker_context_manager.cpp +++ b/myframe/worker_context_manager.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/worker_context_manager.h" @@ -143,7 +143,7 @@ void WorkerContextManager::WeakupWorker() { it = weakup_workers_ctx_.erase(it); worker_ctx->SetCtrlOwnerFlag(WorkerContext::CtrlOwner::kWorker); worker_ctx->SetWaitMsgQueueFlag(false); - DLOG(INFO) << "notify " << *worker_ctx << " process msg"; + VLOG(1) << "notify " << *worker_ctx << " process msg"; worker_ctx->GetCmdChannel()->SendToOwner(CmdChannel::Cmd::kRunWithMsg); } } @@ -169,7 +169,7 @@ void WorkerContextManager::DispatchWorkerMsg(std::shared_ptr msg) { << *worker_ctx << " has " << worker_ctx->CacheSize() << " msg not process!!!"; if (worker_ctx->IsInWaitMsgQueue()) { - DLOG(INFO) << *worker_ctx << " already in wait queue, return"; + VLOG(1) << *worker_ctx << " already in wait queue, return"; return; } worker_ctx->SetWaitMsgQueueFlag(true); diff --git a/myframe/worker_context_manager.h b/myframe/worker_context_manager.h index 9f0d524..56e8361 100644 --- a/myframe/worker_context_manager.h +++ b/myframe/worker_context_manager.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once diff --git a/myframe/worker_timer.cpp b/myframe/worker_timer.cpp index feafad1..16c85d8 100644 --- a/myframe/worker_timer.cpp +++ b/myframe/worker_timer.cpp @@ -1,14 +1,14 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include "myframe/worker_timer.h" -#include -#include +#include +#include #include @@ -18,13 +18,18 @@ Author: likepeng namespace myframe { +uint64_t TimerManager::GetMonoTimeMs() { + auto now = std::chrono::steady_clock::now(); + return now.time_since_epoch().count() / 1e6; +} + TimerManager::TimerManager() { tv_[0] = tv2_; tv_[1] = tv3_; tv_[2] = tv4_; tv_[3] = tv5_; - cur_point_ = Common::GetMonoTimeMs() / 10; + cur_point_ = GetMonoTimeMs() / 10; } TimerManager::~TimerManager() {} @@ -48,8 +53,9 @@ void TimerManager::_AddTimerNode(Timer* node) { } } -int TimerManager::Timeout(const std::string& actor_name, - const std::string& timer_name, int time) { +int TimerManager::Timeout( + const std::string& actor_name, + const std::string& timer_name, int time) { if (time <= 0) return -1; Timer* timer = new Timer(); timer->actor_name_ = actor_name; @@ -138,7 +144,7 @@ void TimerManager::_Updatetime() { mtx_.unlock(); } std::list>* TimerManager::Updatetime() { - uint64_t cp = Common::GetMonoTimeMs() / MY_RESOLUTION_MS; + uint64_t cp = GetMonoTimeMs() / MY_RESOLUTION_MS; if (cp < cur_point_) { LOG(ERROR) << "Future time: " << cp << ":" << cur_point_; cur_point_ = cp; @@ -162,7 +168,7 @@ void WorkerTimer::Run() { DispatchMsg(); cur_us_ = 0; } - usleep(sleep_us_); + std::this_thread::sleep_for(std::chrono::microseconds(sleep_us_)); cur_us_ += sleep_us_; } @@ -178,7 +184,7 @@ int WorkerTimer::SetTimeout( const std::string& actor_name, const std::string& timer_name, int time) { - DLOG(INFO) << actor_name << " set timeout(" << timer_name + VLOG(1) << actor_name << " set timeout(" << timer_name << "): " << (time * 10) << "ms"; return timer_mgr_.Timeout(actor_name, timer_name, time); } diff --git a/myframe/worker_timer.h b/myframe/worker_timer.h index b3a91e8..d6f17e0 100644 --- a/myframe/worker_timer.h +++ b/myframe/worker_timer.h @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once @@ -58,6 +58,7 @@ class TimerManager final { void _MoveList(int level, int idx); void _Shift(); void _Dispath(List* cur); + uint64_t GetMonoTimeMs(); List tv1_[TVR_SIZE]; List tv2_[TVN_SIZE]; diff --git a/templates/CMakeLists.txt b/templates/CMakeLists.txt index 6d40406..738fe95 100644 --- a/templates/CMakeLists.txt +++ b/templates/CMakeLists.txt @@ -1,48 +1,47 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.10) -PROJECT(@template_name@) +cmake_minimum_required(VERSION 3.10) +project(@template_name@) -#### compile setting -SET(CMAKE_CXX_STANDARD 17) -SET(CMAKE_CXX_STANDARD_REQUIRED YES) -SET(CMAKE_CXX_FLAGS "-fPIC -Wall -Wextra -Werror") +#### compile option +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED YES) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) #### path setting -SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") -SET(MYFRAME_INSTALL_SERVICE_DIR ${CMAKE_INSTALL_PREFIX}/service) -SET(MYFRAME_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib) +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +set(MYFRAME_INSTALL_SERVICE_DIR ${CMAKE_INSTALL_PREFIX}/service) +set(MYFRAME_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib) #### dep 3rd lib -FIND_PACKAGE(jsoncpp REQUIRED) -FIND_PACKAGE(gflags REQUIRED) +find_package(Threads REQUIRED) +find_package(jsoncpp REQUIRED) #### include directory -INCLUDE_DIRECTORIES(${CMAKE_INSTALL_PREFIX}/include) +include_directories(${CMAKE_INSTALL_PREFIX}/include) #### deps libs -LINK_LIBRARIES( - dl pthread - glog gflags +link_libraries( + Threads::Threads + glog jsoncpp - -Wl,-z,defs ) -LINK_DIRECTORIES(${MYFRAME_INSTALL_LIB_DIR}) +link_directories(${MYFRAME_INSTALL_LIB_DIR}) #### lib -ADD_LIBRARY(${PROJECT_NAME} SHARED +add_library(${PROJECT_NAME} SHARED ${PROJECT_NAME}.cpp ) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} myframe ) #### install -INSTALL(TARGETS ${PROJECT_NAME} +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${MYFRAME_INSTALL_LIB_DIR} ARCHIVE DESTINATION ${MYFRAME_INSTALL_LIB_DIR} RUNTIME DESTINATION ${MYFRAME_INSTALL_LIB_DIR} ) -FILE(GLOB conf_files "*.json") -INSTALL(FILES +file(GLOB conf_files "*.json") +install(FILES ${conf_files} PERMISSIONS OWNER_READ GROUP_READ WORLD_READ DESTINATION ${MYFRAME_INSTALL_SERVICE_DIR} diff --git a/templates/template.cpp b/templates/template.cpp index c70a627..dd4c977 100644 --- a/templates/template.cpp +++ b/templates/template.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -45,7 +45,7 @@ class @template_name@Worker : public myframe::Worker { std::make_shared("this is template worker req")); DispatchAndWaitMsg(); while (1) { - const auto& msg = mailbox->PopRecv(); + const auto msg = mailbox->PopRecv(); if (msg == nullptr) { break; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a6f4492..a1c3c5e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -4,6 +4,11 @@ cmake_minimum_required(VERSION 3.10) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/performance_test_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/performance_test_config.h @ONLY) ### test bin +add_executable(common_test common_test.cpp) +target_link_libraries(common_test + myframe +) + add_executable(app_send_test app_send_test.cpp) target_link_libraries(app_send_test myframe @@ -36,6 +41,7 @@ target_link_libraries(performance_trans100_fullspeed_test ### install INSTALL(TARGETS + common_test app_send_test performance_trans1_cost_test performance_trans10_cost_test @@ -44,5 +50,5 @@ INSTALL(TARGETS performance_trans100_fullspeed_test LIBRARY DESTINATION ${MYFRAME_LIB_DIR} ARCHIVE DESTINATION ${MYFRAME_LIB_DIR} - RUNTIME DESTINATION ${MYFRAME_TEST_DIR} + RUNTIME DESTINATION ${MYFRAME_BIN_DIR} ) diff --git a/test/app_send_test.cpp b/test/app_send_test.cpp index f6c5bf7..d2dd49d 100644 --- a/test/app_send_test.cpp +++ b/test/app_send_test.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -44,9 +44,9 @@ class EchoActorTest : public myframe::Actor { int main() { auto lib_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR).string(); auto log_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR).string(); myframe::InitLog(log_dir, "app_send_test"); diff --git a/test/common_test.cpp b/test/common_test.cpp new file mode 100644 index 0000000..39412ce --- /dev/null +++ b/test/common_test.cpp @@ -0,0 +1,25 @@ +/**************************************************************************** +Copyright (c) 2019, 李柯鹏 +All rights reserved. + +Author: 李柯鹏 +****************************************************************************/ +#include + +#include "myframe/common.h" +#include "myframe/log.h" + +int main() { + auto root = myframe::Common::GetWorkRoot(); + LOG(INFO) << "work root is " << root.string(); + + auto lib_path = myframe::Common::GetAbsolutePath("lib"); + LOG(INFO) << "lib path is " << lib_path.string(); + + auto root_files = myframe::Common::GetDirFiles(root); + LOG(INFO) << "root dir files:"; + for (size_t i = 0; i < root_files.size(); ++i) { + LOG(INFO) << " " << root_files[i].string(); + } + return 0; +} diff --git a/test/performance_test_config.h.in b/test/performance_test_config.h.in index 5b174eb..5a49dcc 100644 --- a/test/performance_test_config.h.in +++ b/test/performance_test_config.h.in @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #pragma once diff --git a/test/performance_trans100_fullspeed_test.cpp b/test/performance_trans100_fullspeed_test.cpp index 53d9d1a..39060f7 100644 --- a/test/performance_trans100_fullspeed_test.cpp +++ b/test/performance_trans100_fullspeed_test.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -87,9 +87,9 @@ std::atomic_bool FullSpeed100ActorTransTest::is_send_{false}; int main() { auto lib_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR).string(); auto log_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR).string(); myframe::InitLog(log_dir, "performance_trans100_fullspeed_test"); diff --git a/test/performance_trans10_cost_test.cpp b/test/performance_trans10_cost_test.cpp index 516ae9c..b100689 100644 --- a/test/performance_trans10_cost_test.cpp +++ b/test/performance_trans10_cost_test.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -97,9 +97,9 @@ std::vector Trans10ActorCostTest::cost_us_list_; int main() { auto lib_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR).string(); auto log_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR).string(); myframe::InitLog(log_dir, "performance_trans10_cost_test"); diff --git a/test/performance_trans1_cost_test.cpp b/test/performance_trans1_cost_test.cpp index f403ead..8f0734a 100644 --- a/test/performance_trans1_cost_test.cpp +++ b/test/performance_trans1_cost_test.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -75,9 +75,9 @@ class TransMsgCostTest : public myframe::Actor { int main() { auto lib_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR).string(); auto log_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR).string(); myframe::InitLog(log_dir, "performance_trans1_cost_test"); diff --git a/test/performance_trans1_fullspeed_test.cpp b/test/performance_trans1_fullspeed_test.cpp index bc489ee..401b542 100644 --- a/test/performance_trans1_fullspeed_test.cpp +++ b/test/performance_trans1_fullspeed_test.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -81,9 +81,9 @@ class FullSpeedTransTest : public myframe::Actor { int main() { auto lib_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR).string(); auto log_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR).string(); myframe::InitLog(log_dir, "performance_trans1_fullspeed_test"); diff --git a/test/performance_trans20_fullspeed_test.cpp b/test/performance_trans20_fullspeed_test.cpp index f5cf62a..ceaa8b2 100644 --- a/test/performance_trans20_fullspeed_test.cpp +++ b/test/performance_trans20_fullspeed_test.cpp @@ -1,8 +1,8 @@ /**************************************************************************** -Copyright (c) 2018, likepeng +Copyright (c) 2019, 李柯鹏 All rights reserved. -Author: likepeng +Author: 李柯鹏 ****************************************************************************/ #include #include @@ -86,9 +86,9 @@ std::atomic_bool FullSpeed20ActorTransTest::is_send_{false}; int main() { auto lib_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LIB_DIR).string(); auto log_dir = - myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR); + myframe::Common::GetAbsolutePath(MYFRAME_LOG_DIR).string(); myframe::InitLog(log_dir, "performance_trans20_fullspeed_test");