diff --git a/mindspore/core/CMakeLists.txt b/mindspore/core/CMakeLists.txt index c91a98648e..02be915eea 100644 --- a/mindspore/core/CMakeLists.txt +++ b/mindspore/core/CMakeLists.txt @@ -2,6 +2,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_BINARY_DIR}) include_directories(${CMAKE_SOURCE_DIR}/mindspore/core) add_subdirectory(gvar) +if(NOT(CMAKE_SYSTEM_NAME MATCHES "Windows")) + add_subdirectory(mindrt) +endif() message("************ build core ***************") @@ -18,7 +21,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "Windows") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -DHAVE_SNPRINTF") add_compile_definitions(BUILDING_DLL) elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wuser-defined-warnings -Winconsistent-missing-override -Wno-delete-non-abstract-non-virtual-dtor") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \ + -Wuser-defined-warnings -Winconsistent-missing-override -Wno-delete-non-abstract-non-virtual-dtor") endif() set_property(SOURCE ${CORE_SRC_LIST} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_CORE) diff --git a/mindspore/core/mindrt/CMakeLists.txt b/mindspore/core/mindrt/CMakeLists.txt new file mode 100644 index 0000000000..789f68bf21 --- /dev/null +++ b/mindspore/core/mindrt/CMakeLists.txt @@ -0,0 +1,16 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/) + +file(GLOB MINDRT_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/actor/*.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/async/*.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/evloop/*.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/timer/*.cc + ) + + +add_library(mindrt_mid OBJECT ${MINDRT_SRC}) + + diff --git a/mindspore/core/mindrt/include/actor/actor.h b/mindspore/core/mindrt/include/actor/actor.h new file mode 100644 index 0000000000..c5011aeaf3 --- /dev/null +++ b/mindspore/core/mindrt/include/actor/actor.h @@ -0,0 +1,214 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_ACTOR_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_ACTOR_H + +#include +#include +#include +#include +#include +#include + +#include "actor/msg.h" + +namespace mindspore { + +class ActorBase; +class ActorMgr; +class ActorPolicy; + +using ActorReference = std::shared_ptr; + +// should be at least greater than 1 +constexpr uint32_t MAX_ACTOR_RECORD_SIZE = 3; + +class ActorBase { + public: + inline const AID &GetAID() const { return id; } + + inline void AddMsgRecord(const std::string &msgName) { + recordNextPoint++; + uint32_t startPoint = recordNextPoint % MAX_ACTOR_RECORD_SIZE; + msgRecords[startPoint] = msgName; + } + + inline void PrintMsgRecord() { + uint32_t startPoint = recordNextPoint % MAX_ACTOR_RECORD_SIZE; + for (uint32_t i = 0; i < MAX_ACTOR_RECORD_SIZE; i++) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "Actor message dumps:%s", + "actor:%s,msg:%s", id.Name().c_str(), msgRecords[startPoint].c_str()); + startPoint = (startPoint + MAX_ACTOR_RECORD_SIZE - 1) % MAX_ACTOR_RECORD_SIZE; + } + } + + explicit ActorBase(const std::string &name); + virtual ~ActorBase(); + + // send MessageBase message to the actor. + int Send(const AID &to, std::unique_ptr msg); + + // send string message to the actor + int Send(const AID &to, std::string &&name, std::string &&msg, bool remoteLink = false, + bool isExactNotRemote = false); + + // get output buffer size for flow control + uint64_t GetOutBufSize(const AID &to); + + // get input buffer size for flow control + uint64_t GetInBufSize(const AID &to); + + // set record send/receive message package size + int AddRuleUdp(const std::string &peer, int recordNum); + + // delete the send/receive message package size + void DelRuleUdp(const std::string &peer, bool outputLog); + + protected: + using ActorFunction = std::function &msg)>; + + // install KMSG handler . This method will be called before the actor start to run. + virtual void Init() {} + + // This method will be called before the actor start to terminate. + virtual void Finalize() {} + + // KHTTPMsg handler + virtual void HandleHttp(std::unique_ptr msg) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, + "ACTOR (%s) HandleHttp() is not implemented", "a=%s", id.Name().c_str()); + } + + // KLOCALMsg handler + virtual void HandleLocalMsg(std::unique_ptr msg) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, + "ACTOR (%s) HandleLocalMsg() is not implemented.", "a=%s", id.Name().c_str()); + } + + // The link is closed. + virtual void Exited(const AID &actor) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, + "ACTOR (%s) Exited() is not implemented. ", "a=%s", id.Name().c_str()); + } + + // Filter the KMSG + virtual bool Filter(const std::unique_ptr &msg) { return false; } + + // register the message handle + void Receive(const std::string &msgName, ActorFunction &&func); + + // register the message handle. It will be discarded. + template + void Receive(const std::string &msgName, void (T::*method)(mindspore::AID, std::string &&, std::string &&)) { + ActorFunction func = std::bind(&BehaviorBase1, static_cast(this), method, std::placeholders::_1); + Receive(msgName, std::move(func)); + } + + // register the message handle + template + void Receive(const std::string &msgName, void (T::*method)(const mindspore::AID &, std::string &&, std::string &&)) { + ActorFunction func = std::bind(&BehaviorBase, static_cast(this), method, std::placeholders::_1); + Receive(msgName, std::move(func)); + return; + } + + // register the message handle, for kmsg-udp message + template + void ReceiveUdp(const std::string &msgName, + void (T::*method)(const mindspore::AID &, std::string &&, std::string &&)) { + ActorFunction func = std::bind(&BehaviorBaseForUdp, static_cast(this), method, std::placeholders::_1); + Receive(msgName, std::move(func)); + return; + } + + // Link the remote actor + int Link(const AID &to); + + // Unlink the remote actor + int UnLink(const AID &to); + + // Reconnect to the remote actor + int Reconnect(const AID &to); + + void Terminate(); + void Await(); + + private: + friend class ActorMgr; + friend class ActorThread; + + // KMSG Msg Handler + virtual void HandlekMsg(std::unique_ptr &msg); + + template + static void BehaviorBase(T *t, void (T::*method)(const mindspore::AID &, std::string &&, std::string &&), + std::unique_ptr &msg) { + if (msg->type != MessageBase::Type::KMSG) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "Drop non-tcp message: %s", + "from:%s,to:%s,name:%s", std::string(msg->from).c_str(), std::string(msg->to).c_str(), + msg->name.c_str()); + return; + } + (t->*method)(msg->from, std::move(msg->name), std::move(msg->body)); + } + + // register the message handle. It will be discarded. + template + static void BehaviorBase1(T *t, void (T::*method)(mindspore::AID, std::string &&, std::string &&), + std::unique_ptr &msg) { + if (msg->type != MessageBase::Type::KMSG) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "Drop non-tcp message: %s", + "from:%s,to:%s,name:%s", std::string(msg->from).c_str(), std::string(msg->to).c_str(), + msg->name.c_str()); + return; + } + (t->*method)(msg->from, std::move(msg->name), std::move(msg->body)); + } + + // register the udp message handle. Use this closure function to drop non-udp messages + template + static void BehaviorBaseForUdp(T *t, void (T::*method)(const mindspore::AID &, std::string &&, std::string &&), + std::unique_ptr &msg) { + if (msg->type != MessageBase::Type::KUDP) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "Drop non-udp message: %s", + "from:%s,to:%s,name:%s", std::string(msg->from).c_str(), std::string(msg->to).c_str(), + msg->name.c_str()); + return; + } + (t->*method)(msg->from, std::move(msg->name), std::move(msg->body)); + } + + void Run(); + void Quit(); + int EnqueMessage(std::unique_ptr msg); + + void Spawn(std::shared_ptr &actor, std::unique_ptr actorThread); + void SetRunningStatus(bool start); + + std::unique_ptr actorThread; + + AID id; + std::map actionFunctions; + std::mutex waiterLock; + + std::string msgRecords[MAX_ACTOR_RECORD_SIZE]; + uint32_t recordNextPoint = 0; +}; + +}; // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/actor/actorapp.h b/mindspore/core/mindrt/include/actor/actorapp.h new file mode 100644 index 0000000000..6c23b288cb --- /dev/null +++ b/mindspore/core/mindrt/include/actor/actorapp.h @@ -0,0 +1,88 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_ACTORAPP_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_ACTORAPP_H + +#include "actor/actor.h" + +namespace mindspore { + +class MessageLocal : public MessageBase { + public: + MessageLocal(const AID &from, const AID &to, const std::string &name, void *aPtr) + : MessageBase(from, to, name, "LocalMsg", Type::KLOCAL), ptr(aPtr) {} + ~MessageLocal() {} + void *ptr; +}; + +class AppActor : public ActorBase { + public: + typedef std::function)> APPBehavior; + + AppActor(const std::string &name) : ActorBase(name) {} + ~AppActor() {} + + inline int Send(const AID &to, std::unique_ptr msg) { return ActorBase::Send(to, std::move(msg)); } + // send T message to the actor + template + int Send(const std::string &to, const std::string &msgName, std::unique_ptr msg) { + std::unique_ptr localMsg(new (std::nothrow) MessageLocal(GetAID(), to, msgName, msg.release())); + BUS_OOM_EXIT(localMsg); + return Send(to, std::move(localMsg)); + } + + // register the message handle + template + void Receive(const std::string &msgName, void (T::*method)(const AID &, std::unique_ptr)) { + APPBehavior behavior = std::bind(&BehaviorBase, static_cast(this), method, std::placeholders::_1); + + if (appBehaviors.find(msgName) != appBehaviors.end()) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "ACTOR msgName conflict:%s", + "a=%s,msg=%s", GetAID().Name().c_str(), msgName.c_str()); + BUS_EXIT("msgName conflicts."); + return; + } + + appBehaviors.emplace(msgName, behavior); + return; + } + + template + static void BehaviorBase(T *t, void (T::*method)(const AID &, std::unique_ptr), std::unique_ptr msg) { + (t->*method)(msg->From(), std::move(std::unique_ptr((M *)static_cast(msg.get())->ptr))); + return; + } + + protected: + // KLOCALMsg handler + virtual void HandleLocalMsg(std::unique_ptr msg) { + auto it = appBehaviors.find(msg->Name()); + if (it != appBehaviors.end()) { + it->second(std::move(msg)); + } else { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "ACTOR can not finds handler:%s", + "a=%s,msg=%s,hdlno=%zd", GetAID().Name().c_str(), msg->Name().c_str(), appBehaviors.size()); + } + } + + private: + std::map appBehaviors; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/actor/aid.h b/mindspore/core/mindrt/include/actor/aid.h new file mode 100644 index 0000000000..de5d50ab3f --- /dev/null +++ b/mindspore/core/mindrt/include/actor/aid.h @@ -0,0 +1,113 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_AID_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_AID_H + +#include + +#include "actor/buslog.h" + +namespace mindspore { + +constexpr auto BUS_TCP = "tcp"; +constexpr auto BUS_UDP = "udp"; + +class AID { + public: + AID() : name(), url() {} + + ~AID() {} + + AID(const char *name); + AID(const std::string &name); + + AID(const std::string &tmpName, const std::string &sUrl) : name(tmpName), url(sUrl) { SetUnfixUrl(); } + + AID(const AID &id) : name(id.name), url(id.url) { SetUnfixUrl(); } + + // Overloading of Assignment Operator + AID &operator=(const AID &id); + + inline void SetUrl(const std::string &tmpUrl) { + url = tmpUrl; + SetUnfixUrl(); + } + + inline void SetName(const std::string &tmpName) { name = tmpName; } + + inline const std::string &Name() const { return name; } + + inline const std::string &Url() const { return url; } + + void SetProtocol(const std::string &protocol); + bool OK() const; + + std::string GetProtocol() const; + std::string GetIp() const; + uint16_t GetPort() const; + inline std::string UnfixUrl() const { return GetIp() + ":" + std::to_string(GetPort()); } + inline operator std::string() const { return name + "@" + url; } + + inline std::string HashString() const { return name + "@" + UnfixUrl(); } + + private: + void SetUnfixUrl(); + + friend class Actor; + + // actor's name + std::string name; + + /** + tcp://ip:port + udp://ip:port + ip:port (tcp) + **/ + std::string url; +}; + +inline std::ostream &operator<<(std::ostream &os, const AID &aid) { + os << aid.Name() << "@" << aid.Url(); + return os; +} + +inline bool operator==(const AID &aid1, const AID &aid2) { + if (aid1.GetProtocol() == BUS_TCP && aid2.GetProtocol() == BUS_TCP) { + // NOTE : By default, http has no protocol filed, so we use 'UnfixUrl' to compare aids here + return ((aid1.Name() == aid2.Name()) && (aid1.UnfixUrl() == aid2.UnfixUrl())); + } else { + return ((aid1.Name() == aid2.Name()) && (aid1.Url() == aid2.Url())); + } +} +inline bool operator!=(const AID &aid1, const AID &aid2) { return !(aid1 == aid2); } + +inline bool operator>(const AID &aid1, const AID &aid2) { return aid1.HashString() > aid2.HashString(); } +inline bool operator<(const AID &aid1, const AID &aid2) { return aid1.HashString() < aid2.HashString(); } + +}; // namespace mindspore + +// custom specialization of std::hash can be injected in namespace std +namespace std { +template <> +struct hash { + typedef mindspore::AID argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const &s) const noexcept { return (std::hash{}(s.HashString())); } +}; +} // namespace std + +#endif diff --git a/mindspore/core/mindrt/include/actor/buserrcode.h b/mindspore/core/mindrt/include/actor/buserrcode.h new file mode 100644 index 0000000000..433f4763c8 --- /dev/null +++ b/mindspore/core/mindrt/include/actor/buserrcode.h @@ -0,0 +1,43 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_BUSERRCODE_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_BUSERRCODE_H + +// common err code -1 ~ -100 +constexpr int BUS_ERROR = -1; +constexpr int BUS_OK = 0; +constexpr int COMM_NULL_PTR = -1; +constexpr int ERRORCODE_SUCCESS = 1; + +// actor module err code -101 ~ -200 +constexpr int ACTOR_PARAMER_ERR = -101; +constexpr int ACTOR_NOT_FIND = -102; +constexpr int IO_NOT_FIND = -103; + +// TCP module err code -301 ~ -400 +// Null +// UDP IO err code -401 ~ -500 +constexpr int UDP_MSG_TOO_BIG = -401; +constexpr int UDP_MSG_WRITE_ERR = -402; +constexpr int UDP_MSG_SEND_ERR = -403; +constexpr int UDP_MSG_ADDR_ERR = -404; +constexpr int UDP_MSG_SEND_SUCCESS = 1; + +// Protocol module err code -501 ~ -600 +constexpr int PB_MSG_NO_NAME = -501; + +#endif diff --git a/mindspore/core/mindrt/include/actor/buslog.h b/mindspore/core/mindrt/include/actor/buslog.h new file mode 100644 index 0000000000..91b011fb71 --- /dev/null +++ b/mindspore/core/mindrt/include/actor/buslog.h @@ -0,0 +1,149 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_BUSLOG_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_BUSLOG_H + +#include +#include + +#include +#include +#include + +#include "actor/buserrcode.h" + +namespace mindspore { + +#define BUS_LOG(severity) // LOG(severity) +#define BUS_DLOG(verboselevel) // VLOG(verboselevel) + +#define HARES_LOG_PID int // GetLogPID(); +#define PID_LITEBUS_LOG + +#define ICTSBASE_LOG_COMMON_CODE +#define HLOG_LEVEL_INFO +#define PID_LITEBUS_LOG +//#define BUS_OOM_EXIT +#define HLOG_LEVEL_DEBUG 1 +#define ICTSBASE_LOG0(logig, level, pid, format) +#define ICTSBASE_LOG1(logig, level, pid, format, para) +#define ICTSBASE_LOG2(logig, level, pid, format, para1, para2) +#define ICTSBASE_LOG3(logig, level, pid, format, para1, para2, para3) +#define ICTSBASE_LOG4(logig, level, pid, format, para1, para2, para3, para4) +#define ICTSBASE_LOG_STRING(logig, level, pid, preformat, format...) +#define FlushHLogCache() +// Kill the process for safe exiting. +inline void KillProcess(const std::string &ret) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "BUS Exit Tip: %s", "%s", + ret.c_str()); + // flush the log in cache to disk before exiting. + FlushHLogCache(); +} + +} // namespace mindspore + +constexpr int DLEVEL4 = 1000; +constexpr int DLEVEL3 = 3; +constexpr int DLEVEL2 = 2; +constexpr int DLEVEL1 = 1; +constexpr int DLEVEL0 = 0; + +#define BUS_ASSERT(expression) \ + do { \ + if (!(expression)) { \ + std::stringstream ss; \ + ss << "Assertion failed: " << #expression << ", file: " << __FILE__ << ", line: " << __LINE__; \ + mindspore::KillProcess(ss.str()); \ + } \ + } while (0) + +#define BUS_EXIT(ret) \ + do { \ + std::stringstream ss; \ + ss << (ret) << " ( file: " << __FILE__ << ", line: " << __LINE__ << " )."; \ + mindspore::KillProcess(ss.str()); \ + } while (0) + +#define BUS_OOM_EXIT(ptr) \ + { \ + if (ptr == nullptr) { \ + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "new failed, will exit"); \ + BUS_EXIT("Exit for OOM."); \ + } \ + } + +constexpr int LOG_CHECK_EVERY_FIRSTNUM = 10; +constexpr int LOG_CHECK_EVERY_NUM1 = 10; +constexpr int LOG_CHECK_EVERY_NUM2 = 100; +constexpr int LOG_CHECK_EVERY_NUM3 = 1000; +constexpr int LOG_CHECK_EVERY_NUM4 = 10000; + +#define LOG_CHECK_ID_CONCAT(word1, word2) word1##word2 + +#define LOG_CHECK_ID LOG_CHECK_ID_CONCAT(__FUNCTION__, __LINE__) + +#define LOG_CHECK_FIRST_N \ + [](uint32_t firstNum) { \ + static uint32_t LOG_CHECK_ID = 0; \ + ++LOG_CHECK_ID; \ + return (LOG_CHECK_ID <= firstNum); \ + } + +#define LOG_CHECK_EVERY_N1 \ + [](uint32_t firstNum, uint32_t num) { \ + static uint32_t LOG_CHECK_ID = 0; \ + ++LOG_CHECK_ID; \ + return ((LOG_CHECK_ID <= firstNum) || (LOG_CHECK_ID % num == 0)); \ + } + +#define LOG_CHECK_EVERY_N2 \ + [](uint32_t firstNum, uint32_t num1, uint32_t num2) { \ + static uint32_t LOG_CHECK_ID = 0; \ + ++LOG_CHECK_ID; \ + return ((LOG_CHECK_ID <= firstNum) || (LOG_CHECK_ID < num2 && LOG_CHECK_ID % num1 == 0) || \ + (LOG_CHECK_ID % num2 == 0)); \ + } + +#define LOG_CHECK_EVERY_N3 \ + [](uint32_t firstNum, uint32_t num1, uint32_t num2, uint32_t num3) { \ + static uint32_t LOG_CHECK_ID = 0; \ + ++LOG_CHECK_ID; \ + return ((LOG_CHECK_ID <= firstNum) || (LOG_CHECK_ID < num2 && LOG_CHECK_ID % num1 == 0) || \ + (LOG_CHECK_ID < num3 && LOG_CHECK_ID % num2 == 0) || (LOG_CHECK_ID % num3 == 0)); \ + } + +#define LOG_CHECK_EVERY_N4 \ + [](uint32_t firstNum, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4) { \ + static uint32_t LOG_CHECK_ID = 0; \ + ++LOG_CHECK_ID; \ + return ((LOG_CHECK_ID <= firstNum) || (LOG_CHECK_ID < num2 && LOG_CHECK_ID % num1 == 0) || \ + (LOG_CHECK_ID < num3 && LOG_CHECK_ID % num2 == 0) || (LOG_CHECK_ID < num4 && LOG_CHECK_ID % num3 == 0) || \ + (LOG_CHECK_ID % num4 == 0)); \ + } + +#define LOG_CHECK_EVERY_N \ + []() { \ + static uint32_t LOG_CHECK_ID = 0; \ + ++LOG_CHECK_ID; \ + return ((LOG_CHECK_ID <= LOG_CHECK_EVERY_FIRSTNUM) || \ + (LOG_CHECK_ID < LOG_CHECK_EVERY_NUM2 && LOG_CHECK_ID % LOG_CHECK_EVERY_NUM1 == 0) || \ + (LOG_CHECK_ID < LOG_CHECK_EVERY_NUM3 && LOG_CHECK_ID % LOG_CHECK_EVERY_NUM2 == 0) || \ + (LOG_CHECK_ID < LOG_CHECK_EVERY_NUM4 && LOG_CHECK_ID % LOG_CHECK_EVERY_NUM3 == 0) || \ + (LOG_CHECK_ID % LOG_CHECK_EVERY_NUM4 == 0)); \ + } + +#endif diff --git a/mindspore/core/mindrt/include/actor/msg.h b/mindspore/core/mindrt/include/actor/msg.h new file mode 100644 index 0000000000..e4764941be --- /dev/null +++ b/mindspore/core/mindrt/include/actor/msg.h @@ -0,0 +1,83 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_MSG_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_MSG_H + +#include "actor/aid.h" + +namespace mindspore { +class ActorBase; +class MessageBase { + public: + enum class Type : char { + KMSG = 1, + KUDP, + KHTTP, + KASYNC, + KLOCAL, + KEXIT, + KTERMINATE, + }; + + MessageBase(Type eType = Type::KMSG) : from(), name(), type(eType) {} + + explicit MessageBase(const std::string &sName, Type eType = Type::KMSG) : from(), name(sName), type(eType) {} + + explicit MessageBase(const AID &aFrom, const AID &aTo, Type eType = Type::KMSG) + : from(aFrom), to(aTo), name(), body(), type(eType) {} + + explicit MessageBase(const AID &aFrom, const AID &aTo, const std::string &sName, Type eType = Type::KMSG) + : from(aFrom), to(aTo), name(sName), body(), type(eType) {} + + explicit MessageBase(const AID &aFrom, const AID &aTo, const std::string &sName, std::string &&sBody, + Type eType = Type::KMSG) + : from(aFrom), to(aTo), name(sName), body(std::move(sBody)), type(eType) {} + + virtual ~MessageBase() {} + + inline std::string &Name() { return name; } + + inline void SetName(const std::string &aName) { this->name = aName; } + + inline AID &From() { return from; } + + inline std::string &Body() { return body; } + + inline void SetFrom(const AID &aFrom) { from = aFrom; } + + inline AID &To() { return to; } + + inline void SetTo(const AID &aTo) { to = aTo; } + + inline const Type GetType() const { return type; } + + inline void SetType(Type eType) { type = eType; } + + virtual void Run(ActorBase *actor) {} + + friend class ActorBase; + friend class TCPMgr; + AID from; + AID to; + std::string name; + std::string body; + Type type; +}; + +} // namespace mindspore + +#endif // __LITEBUS_MESSAGE_HPP__ diff --git a/mindspore/core/mindrt/include/actor/naught.h b/mindspore/core/mindrt/include/actor/naught.h new file mode 100644 index 0000000000..6e321f07dd --- /dev/null +++ b/mindspore/core/mindrt/include/actor/naught.h @@ -0,0 +1,39 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_NAUGHT_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ACTOR_NAUGHT_H + +#include + +namespace mindspore { + +class Naught; +class ActorBase; + +typedef std::shared_ptr UniqueNaught; +typedef std::shared_ptr SharedNaught; +typedef std::string BusString; + +// Lite , start from Naught +class Naught { + public: + virtual ~Naught() {} +}; + +}; // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/apply.h b/mindspore/core/mindrt/include/async/apply.h new file mode 100644 index 0000000000..444374c9d6 --- /dev/null +++ b/mindspore/core/mindrt/include/async/apply.h @@ -0,0 +1,81 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_APPLY_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_APPLY_H + +namespace mindspore { + +template +struct IntegerSequenceBase { + static constexpr std::size_t Size() noexcept { return sizeof...(Ints); } +}; + +namespace internal { + +template +struct IntegerSequence : public IntegerSequence {}; + +template +struct IntegerSequence { + using type = IntegerSequenceBase; +}; + +} // namespace internal + +template +using make_integer_sequence = typename internal::IntegerSequence::type; + +template +using index_sequence = IntegerSequenceBase; + +template +using make_index_sequence = make_integer_sequence; + +template +using index_sequence_for = make_index_sequence; + +template +auto ApplyHelper(Func &&func, Tuple &&tuple, index_sequence) + -> decltype(func(std::get(std::forward(tuple))...)) { + return func(std::get(std::forward(tuple))...); +} + +template +auto ApplyHelper(T *ptr, Func &&func, Tuple &&tuple, index_sequence) + -> decltype((ptr->*func)(std::get(std::forward(tuple))...)) { + return (ptr->*func)(std::get(std::forward(tuple))...); +} + +template +auto Apply(Func &&func, Tuple &&tuple) + -> decltype(ApplyHelper(std::forward(func), std::forward(tuple), + make_index_sequence::type>::value>{})) { + return ApplyHelper(std::forward(func), std::forward(tuple), + make_index_sequence::type>::value>{}); +} + +template +auto Apply(T *ptr, Func &&func, Tuple &&tuple) + -> decltype(ApplyHelper(ptr, std::forward(func), std::forward(tuple), + make_index_sequence::type>::value>{})) { + return ApplyHelper(ptr, std::forward(func), std::forward(tuple), + make_index_sequence::type>::value>{}); +} + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/async.h b/mindspore/core/mindrt/include/async/async.h new file mode 100644 index 0000000000..99ba1f537e --- /dev/null +++ b/mindspore/core/mindrt/include/async/async.h @@ -0,0 +1,271 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_ASYNC_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_ASYNC_H + +#include "actor/actor.h" +#include "actor/buslog.h" + +#include "async/apply.h" +#include "async/future.h" + +namespace mindspore { + +using MessageHandler = std::function; + +void Async(const AID &aid, std::unique_ptr handler); + +namespace internal { + +template +struct AsyncHelper; + +// for defer +template <> +struct AsyncHelper { + template + void operator()(const AID &aid, F &&f) { + std::unique_ptr> handler( + new (std::nothrow) std::function([=](ActorBase *) { f(); })); + BUS_OOM_EXIT(handler); + Async(aid, std::move(handler)); + } +}; + +template +struct AsyncHelper> { + template + Future operator()(const AID &aid, F &&f) { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::unique_ptr> handler( + new (std::nothrow) std::function([=](ActorBase *) { promise->Associate(f()); })); + BUS_OOM_EXIT(handler); + Async(aid, std::move(handler)); + return future; + } +}; + +template +struct AsyncHelper { + template + Future operator()(const AID &aid, F &&f) { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::unique_ptr> handler( + new (std::nothrow) std::function([=](ActorBase *) { promise->SetValue(f()); })); + BUS_OOM_EXIT(handler); + Async(aid, std::move(handler)); + return future; + } +}; + +} // namespace internal + +// return void +template +void Async(const AID &aid, void (T::*method)()) { + std::unique_ptr> handler( + new (std::nothrow) std::function([method](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + (t->*method)(); + })); + BUS_OOM_EXIT(handler); + Async(aid, std::move(handler)); +} + +template +void Async(const AID &aid, void (T::*method)(Arg0), Arg1 &&arg) { + std::unique_ptr> handler( + new (std::nothrow) std::function([method, arg](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + (t->*method)(arg); + })); + BUS_OOM_EXIT(handler); + Async(aid, std::move(handler)); +} + +template +void Async(const AID &aid, void (T::*method)(Args0...), std::tuple &&tuple) { + std::unique_ptr> handler( + new (std::nothrow) std::function([method, tuple](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + Apply(t, method, tuple); + })); + BUS_OOM_EXIT(handler); + Async(aid, std::move(handler)); +} + +template +void Async(const AID &aid, void (T::*method)(Args0...), Args1 &&... args) { + auto tuple = std::make_tuple(std::forward(args)...); + Async(aid, method, std::move(tuple)); +} + +// return future +template +Future Async(const AID &aid, Future (T::*method)()) { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::unique_ptr> handler( + new (std::nothrow) std::function([promise, method](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + promise->Associate((t->*method)()); + })); + BUS_OOM_EXIT(handler); + + Async(aid, std::move(handler)); + return future; +} + +template +Future Async(const AID &aid, Future (T::*method)(Arg0), Arg1 &&arg) { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::unique_ptr> handler( + new (std::nothrow) std::function([promise, method, arg](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + promise->Associate((t->*method)(arg)); + })); + BUS_OOM_EXIT(handler); + + Async(aid, std::move(handler)); + return future; +} + +template +Future Async(const AID &aid, Future (T::*method)(Args0...), std::tuple &&tuple) { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::unique_ptr> handler( + new (std::nothrow) std::function([promise, method, tuple](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + promise->Associate(Apply(t, method, tuple)); + })); + BUS_OOM_EXIT(handler); + + Async(aid, std::move(handler)); + return future; +} + +template +Future Async(const AID &aid, Future (T::*method)(Args0...), Args1 &&... args) { + auto tuple = std::make_tuple(std::forward(args)...); + return Async(aid, method, std::move(tuple)); +} + +// return R +template ::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0, typename T> +Future Async(const AID &aid, R (T::*method)()) { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::unique_ptr> handler( + new (std::nothrow) std::function([promise, method](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + promise->SetValue((t->*method)()); + })); + BUS_OOM_EXIT(handler); + + Async(aid, std::move(handler)); + return future; +} + +template ::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0, typename T, typename Arg0, + typename Arg1> +Future Async(const AID &aid, R (T::*method)(Arg0), Arg1 &&arg) { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::unique_ptr> handler( + new (std::nothrow) std::function([promise, method, arg](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + promise->SetValue((t->*method)(arg)); + })); + BUS_OOM_EXIT(handler); + + Async(aid, std::move(handler)); + return future; +} + +template ::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0, typename T, typename... Args0, + typename... Args1> +Future Async(const AID &aid, R (T::*method)(Args0...), std::tuple &&tuple) { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::unique_ptr> handler( + new (std::nothrow) std::function([promise, method, tuple](ActorBase *actor) { + BUS_ASSERT(actor != nullptr); + T *t = static_cast(actor); + BUS_ASSERT(t != nullptr); + promise->SetValue(Apply(t, method, tuple)); + })); + BUS_OOM_EXIT(handler); + + Async(aid, std::move(handler)); + return future; +} + +template ::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0, typename T, typename... Args0, + typename... Args1> +Future Async(const AID &aid, R (T::*method)(Args0...), Args1 &&... args) { + auto tuple = std::make_tuple(std::forward(args)...); + return Async(aid, method, std::move(tuple)); +} + +template ::type> +auto Async(const AID &aid, F &&f) -> decltype(internal::AsyncHelper()(aid, std::forward(f))) { + return internal::AsyncHelper()(aid, std::forward(f)); +} + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/asyncafter.h b/mindspore/core/mindrt/include/async/asyncafter.h new file mode 100644 index 0000000000..a038eb2e12 --- /dev/null +++ b/mindspore/core/mindrt/include/async/asyncafter.h @@ -0,0 +1,49 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_ASYNCAFTER_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_ASYNCAFTER_H + +#include "async/async.h" + +#include "timer/timertools.h" + +constexpr mindspore::Duration MILLISECONDS = 1; +constexpr mindspore::Duration SECONDS = 1000; + +namespace mindspore { +template +Timer AsyncAfter(const Duration &duration, const AID &aid, void (T::*method)()) { + return TimerTools::AddTimer(duration, aid, [=]() { Async(aid, method); }); +} + +template +Timer AsyncAfter(const Duration &duration, const AID &aid, void (T::*method)(Arg0), Arg1 &&arg) { + return TimerTools::AddTimer(duration, aid, [=]() { Async(aid, method, arg); }); +} + +template +Timer AsyncAfter(const Duration &duration, const AID &aid, void (T::*method)(Args0...), Args1 &&... args) { + std::function f([=](Args0... args0) { Async(aid, method, args0...); }); + + auto handler = std::bind(f, args...); + + return TimerTools::AddTimer(duration, aid, [=]() { Async(aid, std::move(handler)); }); +} + +}; // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/collect.h b/mindspore/core/mindrt/include/async/collect.h new file mode 100644 index 0000000000..51cb67c8c1 --- /dev/null +++ b/mindspore/core/mindrt/include/async/collect.h @@ -0,0 +1,123 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_COLLECT_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_COLLECT_H + +#include +#include +#include + +#include "async/common.h" +#include "async/future.h" +#include "async/spinlock.h" + +#include "actor/actor.h" + +#include "litebus.hpp" + +namespace mindspore { + +template +class Future; + +template +class Promise; + +template +class Collected; + +template +class Collected { + public: + Collected(const std::list> &f, Promise> *p) : futures(f), promise(p), ready(0) {} + + virtual ~Collected() { + delete promise; + promise = nullptr; + } + + Collected(const Collected &) = delete; + Collected(Collected &&) = default; + + Collected &operator=(const Collected &) = delete; + Collected &operator=(Collected &&) = default; + + public: + void Discarded() { + auto iter = futures.begin(); + for (; iter != futures.end(); ++iter) { + iter->SetFailed(Status::KERROR); + } + } + + void Waited(const Future &future) { + if (future.IsError()) { + promise->SetFailed(future.GetErrorCode()); + } else if (future.IsOK()) { + ready.fetch_add(1); + if (ready.load() == futures.size()) { + std::list values; + auto iter = futures.begin(); + for (; iter != futures.end(); ++iter) { + values.push_back(iter->Get()); + } + promise->SetValue(values); + } + } + } + + private: + const std::list> futures; + Promise> *promise; + std::atomic_ulong ready; +}; + +template +inline Future> Collect(const std::list> &futures) { + if (futures.empty()) { + return std::list(); + } + + Promise> *promise = new (std::nothrow) Promise>(); + BUS_OOM_EXIT(promise); + using CollectType = Collected; + std::shared_ptr collect = std::make_shared(futures, promise); + + // + auto iter = futures.begin(); + for (; iter != futures.end(); ++iter) { + iter->OnComplete(Defer(collect, &CollectType::Waited, std::placeholders::_1)); + } + + Future> future = promise->GetFuture(); + future.OnComplete(Defer(collect, &Collected::Discarded)); + + return future; +} + +template +Future> Collect(const Future &... futures) { + std::list> wrappers = {futures.Then([]() { return Nothing(); })...}; + + auto f = [](const Future &... futures) { return std::make_tuple(futures.Get()...); }; + + return Collect(wrappers).Then(std::bind(f, futures...)); +} + +}; // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/common.h b/mindspore/core/mindrt/include/async/common.h new file mode 100644 index 0000000000..0ecbb37b83 --- /dev/null +++ b/mindspore/core/mindrt/include/async/common.h @@ -0,0 +1,26 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_COMMON_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_COMMON_H + +namespace mindspore { + +struct Nothing {}; + +} // namespace mindspore + +#endif /* COMMON_HPP__ */ diff --git a/mindspore/core/mindrt/include/async/defer.h b/mindspore/core/mindrt/include/async/defer.h new file mode 100644 index 0000000000..7d919faf48 --- /dev/null +++ b/mindspore/core/mindrt/include/async/defer.h @@ -0,0 +1,316 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_DEFER_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_DEFER_H + +#include + +#include "async/async.h" +#include "async/option.h" + +namespace mindspore { + +template +class Deferred : public std::function { + public: + virtual ~Deferred() {} + + private: + template + friend class internal::DeferredHelper; + + template + friend Deferred Defer(const AID &aid, void (T::*method)()); + + template + friend Deferred()> Defer(const AID &aid, Future (T::*method)()); + + template + friend Deferred()> Defer(const AID &aid, R (T::*method)()); + + Deferred(const std::function &f) : std::function(f) {} +}; + +namespace internal { + +template +class DeferredHelper { + public: + DeferredHelper(const AID &id, F &&function) : aid(id), f(std::forward(function)) {} + + DeferredHelper(F &&function) : f(std::forward(function)) {} + + ~DeferredHelper() {} + + operator Deferred() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=]() { Async(optionAid.Get(), function); }); + } + + operator std::function() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=]() { Async(optionAid.Get(), function); }); + } + + template + operator Deferred() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=]() { return Async(optionAid.Get(), function); }); + } + + template + operator std::function() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=]() { return Async(optionAid.Get(), function); }); + } + + template + operator Deferred() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=](Arg arg) { + std::function handler([=]() { function(arg); }); + Async(optionAid.Get(), handler); + }); + } + + template + operator std::function() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=](Arg arg) { + std::function handler([=]() { function(arg); }); + Async(optionAid.Get(), handler); + }); + } + + template + operator Deferred() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=](Args... args) { + auto tuple = std::make_tuple(std::forward(args)...); + std::function handler([=]() { Apply(function, tuple); }); + Async(optionAid.Get(), handler); + }); + } + + template + operator std::function() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=](Args... args) { + auto tuple = std::make_tuple(std::forward(args)...); + std::function handler([=]() { Apply(function, tuple); }); + Async(optionAid.Get(), handler); + }); + } + + template ::value, int>::type = 0, typename Arg> + operator Deferred() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=](Arg arg) { + std::function handler([=]() { return function(arg); }); + return Async(optionAid.Get(), handler); + }); + } + + template ::value, int>::type = 0, typename Arg> + operator std::function() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=](Arg arg) { + std::function handler([=]() { return function(arg); }); + return Async(optionAid.Get(), handler); + }); + } + + template ::value, int>::type = 0, typename... Args> + operator Deferred() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=](Args... args) { + auto tuple = std::make_tuple(std::forward(args)...); + std::function handler([=]() { return Apply(function, tuple); }); + return Async(optionAid.Get(), handler); + }); + } + + template ::value, int>::type = 0, typename... Args> + operator std::function() && { + if (aid.IsNone()) { + return std::function(std::forward(f)); + } + + Option optionAid = aid; + F &&function = std::forward(f); + + return std::function([=](Args... args) { + auto tuple = std::make_tuple(std::forward(args)...); + std::function handler([=]() { return Apply(function, tuple); }); + return Async(optionAid.Get(), handler); + }); + } + + private: + template + friend DeferredHelper Defer(const AID &aid, G &&g); + + Option aid; + F f; +}; + +} // namespace internal + +template +internal::DeferredHelper Defer(const AID &aid, F &&f) { + return internal::DeferredHelper(aid, std::forward(f)); +} + +template +Deferred Defer(const AID &aid, void (T::*method)()) { + return Deferred([=]() { Async(aid, method); }); +} + +template +Deferred()> Defer(const AID &aid, Future (T::*method)()) { + return Deferred()>([=]() { return Async(aid, method); }); +} + +template +Deferred()> Defer(const AID &aid, R (T::*method)()) { + return Deferred()>([=]() { return Async(aid, method); }); +} + +template +auto Defer(T *t, void (T::*method)(Args0...), Args1 &&... args) + -> internal::DeferredHelper::operator(), + std::function(), std::forward(args)...))> { + std::function f([=](Args0... args0) { + if (t != nullptr) { + (t->*method)(args0...); + } + }); + + return std::bind(&std::function::operator(), std::move(f), std::forward(args)...); +} + +template +auto Defer(std::shared_ptr t, void (T::*method)(Args0...), Args1 &&... args) + -> internal::DeferredHelper::operator(), + std::function(), std::forward(args)...))> { + std::function f([=](Args0... args0) { + if (t != nullptr) { + (t.get()->*method)(args0...); + } + }); + + return std::bind(&std::function::operator(), std::move(f), std::forward(args)...); +} + +template +auto Defer(const AID &aid, void (T::*method)(Args0...), Args1 &&... args) + -> internal::DeferredHelper::operator(), + std::function(), std::forward(args)...))> { + std::function f([=](Args0... args0) { Async(aid, method, args0...); }); + + return std::bind(&std::function::operator(), std::move(f), std::forward(args)...); +} + +template +auto Defer(const AID &aid, Future (T::*method)(Args0...), Args1 &&... args) + -> internal::DeferredHelper(Args0...)>::operator(), + std::function(Args0...)>(), std::forward(args)...))> { + std::function(Args0...)> f([=](Args0... args0) { return Async(aid, method, args0...); }); + + return std::bind(&std::function(Args0...)>::operator(), std::move(f), std::forward(args)...); +} + +template ::value, int>::type = 0, + typename std::enable_if::value, int>::type = 0, typename T, typename... Args0, + typename... Args1> +auto Defer(const AID &aid, R (T::*method)(Args0...), Args1 &&... args) + -> internal::DeferredHelper(Args0...)>::operator(), + std::function(Args0...)>(), std::forward(args)...))> { + std::function(Args0...)> f([=](Args0... args0) { return Async(aid, method, args0...); }); + + return std::bind(&std::function(Args0...)>::operator(), std::move(f), std::forward(args)...); +} + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/failure.h b/mindspore/core/mindrt/include/async/failure.h new file mode 100644 index 0000000000..7e1f4b8451 --- /dev/null +++ b/mindspore/core/mindrt/include/async/failure.h @@ -0,0 +1,40 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_FAILURE_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_FAILURE_H + +#include "async/status.h" + +namespace mindspore { + +class Failure : public Status { + public: + Failure() : Status(Status::KOK), errorCode(Status::KOK) {} + + Failure(int32_t code) : Status(code), errorCode(code) {} + + ~Failure() {} + + const int32_t GetErrorCode() const { return errorCode; } + + private: + Status::Code errorCode; +}; + +} // namespace mindspore + +#endif /* __FAILURE_HPP__ */ diff --git a/mindspore/core/mindrt/include/async/future.h b/mindspore/core/mindrt/include/async/future.h new file mode 100644 index 0000000000..e786da2024 --- /dev/null +++ b/mindspore/core/mindrt/include/async/future.h @@ -0,0 +1,511 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_FUTURE_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_FUTURE_H + +#include +#include +#include + +#include "actor/actor.h" +#include "actor/buslog.h" + +#include "async/spinlock.h" +#include "async/status.h" +#include "async/uuid_generator.h" + +#include "litebus.hpp" + +#include "future_base.h" + +namespace mindspore { + +template +class Promise; + +template +class Option; + +template +class Future : public FutureBase { + public: + typedef Status WaitForStatus; + typedef typename FutureData::CompleteCallback CompleteCallback; + typedef typename FutureData::AbandonedCallback AbandonedCallback; + typedef FutureData Data; + Future() : data(new (std::nothrow) Data()) { + BUS_OOM_EXIT(data); + data->abandoned = true; + } + + Future(const Future &f) : FutureBase(f), data(f.data) {} + + Future(Future &&f) : data(std::move(f.data)) {} + + Future(const T &t) : data(new (std::nothrow) Data()) { + BUS_OOM_EXIT(data); + SetValue(std::move(t)); + } + + template + Future(const V &value) : data(new (std::nothrow) Data()) { + BUS_OOM_EXIT(data); + SetValue(value); + } + + Future(const Status &s) : data(new (std::nothrow) Data()) { + BUS_OOM_EXIT(data); + SetFailed(s.GetCode()); + } + + ~Future() override {} + + Future &operator=(const Future &f) { + if (&f != this) { + data = f.data; + } + return *this; + } + + bool operator==(const Future &f) const { return data == f.data; } + + bool operator!=(const Future &f) const { return !(*this == f); } + + const T &Get() const { + if (data->status.IsError()) { + ICTSBASE_LOG1(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_WARNING, PID_LITEBUS_LOG, + "Future::Get() but status == Error: %d", GetErrorCode()); + return data->t; + } + + if (data->gotten) { + return data->t; + } + + // try { + data->t = data->future.get(); + data->gotten = true; + // } catch (std::future_error const &e) { + // ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "Future error: %s", + // "%s", + // e.what()); + // } catch (std::exception const &e) { + // ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "Standard exception: + // %s", + // "%s", e.what()); + // } catch (...) { + // ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "Unknown exception."); + // } + + return data->t; + } + + Option Get(uint64_t timeMs) const { + if (data->gotten) { + return Option(data->t); + } + + if (WaitFor(timeMs).IsError()) { + return Option(); + } + + if (data->status.IsError()) { + return Option(); + } + + return Option(Get()); + } + + bool Valid() const noexcept { return data->future.valid(); } + + bool IsInit() const { return data->status.IsInit(); } + + bool IsOK() const { return data->status.IsOK(); } + + bool IsError() const { return data->status.IsError(); } + + Status GetStatus() const { return data->status; } + + int32_t GetErrorCode() const { + const Status &status_ = data->status; + if (status_.IsError()) { + return status_.GetCode(); + } + + return 0; + } + + void Wait() const { + if (!data->status.IsInit()) { + return; + } + + data->future.wait(); + } + + WaitForStatus WaitFor(uint64_t timeMs) const { + if (!data->status.IsInit()) { + return Status::KOK; + } + + AID aid = mindspore::Spawn(std::make_shared( + internal::WAIT_ACTOR_NAME + std::to_string(mindspore::localid_generator::GenLocalActorId()))); + + mindspore::Timer timer = TimerTools::AddTimer(timeMs, aid, std::bind(&internal::Waitf, aid)); + + OnComplete(std::bind(&internal::Wait, aid, timer)); + + // block + mindspore::Await(aid); + + data->lock.Lock(); + bool ret = data->status.IsInit(); + data->lock.Unlock(); + + if (!ret) { + return Status::KOK; + } + + return Status::KERROR; + } + + template + const Future &OnComplete(internal::DeferredHelper &&deferred) const { + return OnComplete(std::move(deferred).operator std::function &)>()); + } + + template + const Future &OnAbandoned(internal::DeferredHelper &&deferred) const { + return OnAbandoned(std::move(deferred).operator std::function &)>()); + } + + const Future &OnComplete(CompleteCallback &&callback) const { + bool call = false; + + data->lock.Lock(); + if (data->status.IsInit()) { + // using move to make callback execute once + data->onCompleteCallbacks.push_back(std::move(callback)); + } else { + call = true; + } + data->lock.Unlock(); + + if (call) { + std::move(callback)(*this); + } + + return *this; + } + + const Future &OnAbandoned(AbandonedCallback &&callback) const { + bool call = false; + + data->lock.Lock(); + if (data->abandoned) { + call = true; + } else if (data->status.IsInit()) { + // using move to make callback execute once + data->onAbandonedCallbacks.push_back(std::move(callback)); + } + data->lock.Unlock(); + + if (call) { + std::move(callback)(*this); + } + + return *this; + } + + void SetValue(T &&t) const { return Set(std::move(t)); } + + void SetValue(const T &t) const { return Set(t); } + + void SetOK() const { + bool call = false; + + data->lock.Lock(); + if (data->status.IsInit()) { + data->status.SetOK(); + data->promise.set_value(T()); + call = true; + } + data->lock.Unlock(); + + if (call) { + RunCallbacks(); + } + } + + void SetFailed(int32_t errCode) const { + BUS_ASSERT(errCode != Status::KINIT && errCode != Status::KOK); + + bool call = false; + + data->lock.Lock(); + if (data->status.IsInit()) { + data->status.SetCode(errCode); + data->promise.set_value(T()); + call = true; + } + data->lock.Unlock(); + + if (call) { + RunCallbacks(); + } + } + + // remove all callbacks + void Clear() const { data->Clear(); } + + void Abandon(bool abandon = false) const { + bool call = false; + + std::list callbacks; + data->lock.Lock(); + if (!data->abandoned && data->status.IsInit() && (!data->associated || abandon)) { + call = data->abandoned = true; + callbacks.swap(data->onAbandonedCallbacks); + } + data->lock.Unlock(); + + if (call) { + internal::Run(std::move(callbacks), *this); + } + } + + template + Future Then(const std::function(const T &)> &f) const { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::function &)> handler = + std::bind(&internal::Thenf, f, promise, std::placeholders::_1); + + OnComplete(std::move(handler)); + + return future; + } + + template + Future Then(const std::function &f) const { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + std::function &)> handler = + std::bind(&internal::Then, f, promise, std::placeholders::_1); + + OnComplete(std::move(handler)); + + return future; + } + + template + Future Then(const std::function()> &f) const { + return Then(std::function(const T &)>(std::bind(f))); + } + + template + Future Then(const std::function &f) const { + return Then(std::function(std::bind(f))); + } + + template + auto Then(F &&f) const -> decltype(this->Then(std::forward(f), FutureBase())) { + return Then(std::forward(f), FutureBase()); + } + + template + const Future &OnComplete(F &&f) const { + return OnComplete(std::forward(f), FutureBase()); + } + + template + const Future &OnAbandoned(F &&f) const { + return OnAbandoned(std::forward(f), FutureBase()); + } + + Future After(const Duration &timeMs, const std::function(const Future &)> &f) const { + std::shared_ptr> promise(new (std::nothrow) Promise()); + BUS_OOM_EXIT(promise); + Future future = promise->GetFuture(); + + mindspore::Timer timer = + TimerTools::AddTimer(timeMs, "__After__", std::bind(&internal::Afterf, f, promise, *this)); + + OnComplete(std::bind(&internal::After, promise, timer, std::placeholders::_1)); + + return future; + } + + private: + template ::type>::type> + Future Then(internal::DeferredHelper &&f, FutureBase) const { + return Then(std::move(f).operator std::function(const T &)>()); + } + + template ::type>::value, F>::type()>::type>::type> + Future Then(internal::DeferredHelper &&f, LessFuture) const { + return Then(std::move(f).operator std::function()>()); + } + + template ::type>::type> + Future Then(F &&f, FutureBase) const { + return Then(std::function(const T &)>(f)); + } + + template ::type>::value, F>::type()>::type>::type> + Future Then(F &&f, LessFuture) const { + return Then(std::function()>(std::forward(f))); + } + + template &)>::type> + const Future &OnComplete(F &&f, FutureBase) const { + return OnComplete( + std::function &)>([=](const Future &future) mutable { std::forward(f)(future); })); + } + + template ::type>::value, F>::type()>::type> + const Future &OnComplete(F &&f, LessFuture) const { + return OnComplete(std::function &)>([=](const Future &) mutable { std::forward(f)(); })); + } + + template &)>::type> + const Future &OnAbandoned(F &&f, FutureBase) const { + return OnAbandoned( + std::function &)>([=](const Future &future) mutable { std::forward(f)(future); })); + } + + template ::type>::value, F>::type()>::type> + const Future &OnAbandoned(F &&f, LessFuture) const { + return OnAbandoned( + std::function &)>([=](const Future &) mutable { std::forward(f)(); })); + } + + void RunCallbacks() const { + std::shared_ptr::Data> copy = data; + internal::Run(std::move(copy->onCompleteCallbacks), Future(copy)); + copy->Clear(); + } + + void Run() const { + auto iter = data->onCompleteCallbacks.begin(); + for (; iter != data->onCompleteCallbacks.end(); ++iter) { + (*iter)(*this); + } + } + + template + void Set(V &&value) const { + bool call = false; + + data->lock.Lock(); + if (data->status.IsInit()) { + data->status.SetOK(); + data->promise.set_value(std::forward(value)); + call = true; + } + data->lock.Unlock(); + + if (call) { + RunCallbacks(); + } + } + + template + friend class Future; + friend class Promise; + + Future(const std::shared_ptr &t) : data(t) {} + + std::shared_ptr data; +}; + +template +class Promise { + public: + Promise() : future() { future.data->abandoned = false; } + + explicit Promise(const T &t) : future(t) {} + + virtual ~Promise() { + // try { + if (future.data) { + future.Abandon(); + } + // } catch (...) { + // } + } + + void SetValue(const T &value) const { Set(value); } + + void SetValue(T &&value) const { Set(std::move(value)); } + + void SetValue(const Future &tFuture) const { Associate(tFuture); } + + void SetFailed(int32_t code) const { + if (!future.data->associated) { + future.SetFailed(code); + } + } + + Future GetFuture() const { return future; } + + void Associate(const Future &f) const { + bool associated = false; + + future.data->lock.Lock(); + if (future.IsInit() && !future.data->associated) { + associated = (future.data->associated = true); + } + future.data->lock.Unlock(); + + if (associated) { + f.OnComplete(std::bind(&internal::Complete, future, std::placeholders::_1)) + .OnAbandoned(std::bind(&internal::Abandon, future, true)); + } + } + + private: + template + void Set(V &&value) const { + if (future.IsInit() && !future.data->associated) { + future.SetValue(std::forward(value)); + } + } + + template + friend class Future; + + Future future; +}; + +template <> +class Promise; + +template +class Promise; + +}; // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/future_base.h b/mindspore/core/mindrt/include/async/future_base.h new file mode 100644 index 0000000000..0960e7ad72 --- /dev/null +++ b/mindspore/core/mindrt/include/async/future_base.h @@ -0,0 +1,203 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_FUTURE_BASE_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_FUTURE_BASE_H + +#include +#include +#include + +#include "actor/actor.h" +#include "actor/buslog.h" +#include "async/spinlock.h" +#include "async/status.h" + +#include "timer/timertools.h" + +namespace mindspore { + +template +class Future; + +template +class Promise; + +class LessFuture { + public: + LessFuture() {} + LessFuture(const LessFuture &obj) {} + LessFuture &operator=(const LessFuture &) = delete; + virtual ~LessFuture() {} +}; + +class FutureBase : public LessFuture { + public: + FutureBase() {} + FutureBase(const FutureBase &obj) : LessFuture(obj) {} + FutureBase &operator=(const FutureBase &) = delete; + ~FutureBase() override {} +}; + +template +struct FutureData { + public: + typedef std::function &)> CompleteCallback; + typedef std::function &)> AbandonedCallback; + + FutureData() + : status(Status::KINIT), + associated(false), + abandoned(false), + gotten(false), + promise(), + future(promise.get_future()), + t() {} + + ~FutureData() { + // try { + Clear(); + // } catch (...) { + // } + } + + // remove all callbacks + void Clear() { + onCompleteCallbacks.clear(); + onAbandonedCallbacks.clear(); + } + + // status of future + SpinLock lock; + Status status; + + bool associated; + bool abandoned; + bool gotten; + + std::promise promise; + + // get from promise + std::future future; + + // complete callback + std::list onCompleteCallbacks; + + // abandoned callback + std::list onAbandonedCallbacks; + + T t; +}; + +namespace internal { + +const std::string WAIT_ACTOR_NAME = "WACTOR_"; + +class WaitActor : public ActorBase { + public: + explicit WaitActor(const std::string &name) : mindspore::ActorBase(name) {} + + ~WaitActor() override {} +}; + +template +class DeferredHelper; + +template +struct Wrap { + typedef Future type; +}; + +template +struct Wrap> { + typedef Future type; +}; + +template +struct Unwrap { + typedef T type; +}; + +template +struct Unwrap> { + typedef T type; +}; + +template +struct IsFuture : public std::integral_constant::value> {}; + +template +static void Run(std::list &&handlers, Args &&... args) { + for (auto iter = handlers.begin(); iter != handlers.end(); ++iter) { + std::move (*iter)(std::forward(args)...); + } +} + +template +static void Complete(const Future &future, const Future &f) { + if (f.IsError()) { + future.SetFailed(f.GetErrorCode()); + } else if (f.IsOK()) { + future.SetValue(f.Get()); + } +} + +template +static void Abandon(const Future &future, bool abandon) { + future.Abandon(abandon); +} + +template +static void Thenf(const std::function(const T &)> &function, const std::shared_ptr> &promise, + const Future &f) { + if (f.IsError()) { + promise->SetFailed(f.GetErrorCode()); + } else if (f.IsOK()) { + promise->Associate(function(f.Get())); + } +} + +template +static void Then(const std::function &function, const std::shared_ptr> &promise, + const Future &f) { + if (f.IsError()) { + promise->SetFailed(f.GetErrorCode()); + } else if (f.IsOK()) { + promise->SetValue(function(f.Get())); + } +} + +template +static void Afterf(const std::function(const Future &)> &f, const std::shared_ptr> &promise, + const Future &future) { + promise->Associate(f(future)); +} + +template +static void After(const std::shared_ptr> &promise, const mindspore::Timer &timer, const Future &future) { + (void)mindspore::TimerTools::Cancel(timer); + promise->Associate(future); +} + +void Waitf(const AID &aid); + +void Wait(const AID &aid, const mindspore::Timer &timer); + +} // namespace internal + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/option.h b/mindspore/core/mindrt/include/async/option.h new file mode 100644 index 0000000000..f34bb60856 --- /dev/null +++ b/mindspore/core/mindrt/include/async/option.h @@ -0,0 +1,111 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_OPTION_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_OPTION_H + +#include +#include + +#include "actor/buslog.h" + +namespace mindspore { + +template +struct InnerSome { + InnerSome(const T &t) : _t(std::move(t)) {} + T _t; +}; + +template +InnerSome::type> Some(T &&t) { + return InnerSome::type>(std::forward(t)); +} + +struct None {}; + +template +class Option { + public: + Option() : data(), state(NONE) {} + + Option(const T &t) : data(t), state(SOME) {} + + Option(T &&t) : data(std::move(t)), state(SOME) {} + + Option(const InnerSome &some) : data(some._t), state(SOME) {} + + Option(const None &none) : data(), state(NONE) {} + + Option(const Option &that) : data(), state(that.state) { + if (that.IsSome()) { + data = that.data; + } + } + + virtual ~Option() {} + + bool IsNone() const { return state == NONE; } + + bool IsSome() const { return state == SOME; } + + const T &Get() const & { + BUS_ASSERT(IsSome()); + return data; + } + + T &&Get() && { + BUS_ASSERT(IsSome()); + return std::move(data); + } + + const T &&Get() const && { + BUS_ASSERT(IsSome()); + return std::move(data); + } + + // oprerator override + Option &operator=(const Option &that) { + if (&that != this) { + state = that.state; + if (that.IsSome()) { + data = that.data; + } + } + + return *this; + } + + bool operator==(const Option &that) const { + return (IsNone() && that.IsNone()) || (IsSome() && that.IsSome() && data == that.data); + } + + bool operator!=(const Option &that) const { return !(*this == that); } + + bool operator==(const T &that) const { return IsSome() && data == that; } + + bool operator!=(const T &that) const { return !(*this == that); } + + private: + enum State { NONE = 0, SOME = 1 }; + + T data; + State state; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/result.h b/mindspore/core/mindrt/include/async/result.h new file mode 100644 index 0000000000..6eab1d3745 --- /dev/null +++ b/mindspore/core/mindrt/include/async/result.h @@ -0,0 +1,72 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_RESULT_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_RESULT_H + +#include + +#include "option.h" +#include "status.h" + +namespace mindspore { + +template +class Result { + public: + Result() : status(Status::KINIT) {} + + Result(Types... types, const Status &s) : tuple(Option(types)...), status(s) {} + + ~Result() {} + + template + bool IsSome() { + return (std::get(tuple)).IsSome(); + } + + template + bool IsNone() { + return std::get(tuple).IsNone(); + } + + bool IsOK() { return status.IsOK(); } + + bool IsError() { return status.IsError(); } + + void SetStatus(Status::Code code) { status.SetCode(code); } + + const Status &GetStatus() const { return status; } + + template + typename std::tuple_element...>>::type Get() const { + return GetOption().Get(); + } + + private: + template + typename std::tuple_element...>>::type GetOption() const { + return std::get(tuple); + } + + private: + std::tuple...> tuple; + Status status; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/spinlock.h b/mindspore/core/mindrt/include/async/spinlock.h new file mode 100644 index 0000000000..ad19c71212 --- /dev/null +++ b/mindspore/core/mindrt/include/async/spinlock.h @@ -0,0 +1,39 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_SPINLOCK_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_SPINLOCK_H + +#include + +namespace mindspore { + +class SpinLock { + public: + void Lock() { + while (locked.test_and_set(std::memory_order_acquire)) + ; + } + + void Unlock() { locked.clear(std::memory_order_release); } + + private: + std::atomic_flag locked = ATOMIC_FLAG_INIT; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/status.h b/mindspore/core/mindrt/include/async/status.h new file mode 100644 index 0000000000..5c5701b4d4 --- /dev/null +++ b/mindspore/core/mindrt/include/async/status.h @@ -0,0 +1,69 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_STATUS_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_STATUS_H + +namespace mindspore { + +class Status { + public: + typedef int32_t Code; + + static const Code KINIT = 1; + static const Code KOK = 0; + static const Code KERROR = -1; + + // Create a success status. + Status(int32_t c) : code(c) {} + + Status() : code(KINIT) {} + + virtual ~Status() {} + + // Returns true iff the status indicates success. + bool IsInit() const { return (code == KINIT); } + + bool IsOK() const { return (code == KOK); } + + bool IsError() const { return (code != KINIT && code != KOK); } + + // Return a success status. + Status OK() const { return Status(KOK); } + + Status Error() const { return Status(KERROR); } + + void SetError() { + code = KERROR; + return; + } + + void SetOK() { + code = KOK; + return; + } + + Code GetCode() const { return code; } + + void SetCode(Code c) { code = c; } + + private: + Code code; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/try.h b/mindspore/core/mindrt/include/async/try.h new file mode 100644 index 0000000000..f00af5f930 --- /dev/null +++ b/mindspore/core/mindrt/include/async/try.h @@ -0,0 +1,55 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_TRY_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_TRY_H + +#include "async/failure.h" +#include "async/option.h" +#include "async/status.h" + +namespace mindspore { + +template +class Try { + public: + Try() : errorCode(Status::KOK) {} + + Try(const T &t) { + data = Some(t); + errorCode = Status::KOK; + } + + Try(const F &errCode) { errorCode = errCode; } + + virtual ~Try() {} + + bool IsOK() { return !IsError(); } + + bool IsError() { return data.IsNone(); } + + const T &Get() const { return data.Get(); } + + const int GetErrorCode() const { return errorCode.GetErrorCode(); } + + private: + Option data; + Failure errorCode; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/async/uuid_base.h b/mindspore/core/mindrt/include/async/uuid_base.h new file mode 100644 index 0000000000..5833f041e8 --- /dev/null +++ b/mindspore/core/mindrt/include/async/uuid_base.h @@ -0,0 +1,104 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_UUID_BASE_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_UUID_BASE_H + +#include +#include +#include +#include +#include +#include "async/option.h" + +namespace mindspore { +namespace uuids { + +const std::size_t UUID_SIZE = 16; + +struct uuid { + public: + static std::size_t Size(); + + static std::string ToBytes(const uuid &u); + + static Option FromBytes(const std::string &s); + + static Option GetValue(char c); + + static Option FromString(const std::string &s); + + // To check whether uuid looks like 0000000-000-000-000-000000000000000 + bool IsNilUUID() const; + + const uint8_t *Get() const; + + private: + const uint8_t *BeginAddress() const; + + const uint8_t *EndAddress() const; + + uint8_t *BeginAddress(); + + uint8_t *EndAddress(); + + friend class RandomBasedGenerator; + friend bool operator==(uuid const &left, uuid const &right); + friend bool operator!=(uuid const &left, uuid const &right); + template + friend std::basic_ostream &operator<<(std::basic_ostream &s, const struct uuid &outputUuid); + uint8_t uuidData[UUID_SIZE]; +}; + +class RandomBasedGenerator { + public: + static uuid GenerateRandomUuid(); +}; + +// operator override +inline bool operator==(uuid const &left, uuid const &right) { + return std::equal(left.BeginAddress(), left.EndAddress(), right.BeginAddress()); +} + +// operator override +inline bool operator!=(uuid const &left, uuid const &right) { return !(left == right); } + +// operator override +template +std::basic_ostream &operator<<(std::basic_ostream &s, const struct uuid &outputUuid) { + const int FIRST_DELIM_OFFSET = 3; + const int SECOND_DELIM_OFFSET = 5; + const int THIRD_DELIM_OFFSET = 7; + const int FOURTH_DELIM_OFFSET = 9; + const int UUID_WIDTH = 2; + s << std::hex << std::setfill(static_cast('0')); + + int i = 0; + for (const uint8_t *ptr = outputUuid.BeginAddress(); ptr < outputUuid.EndAddress(); ++ptr, ++i) { + s << std::setw(UUID_WIDTH) << (int)(*ptr); + if (i == FIRST_DELIM_OFFSET || i == SECOND_DELIM_OFFSET || i == THIRD_DELIM_OFFSET || i == FOURTH_DELIM_OFFSET) { + s << '-'; + } + } + + s << std::setfill(static_cast(' ')) << std::dec; + return s; +} + +} // namespace uuids +} // namespace mindspore + +#endif /* UUID_BASE_HPP_ */ diff --git a/mindspore/core/mindrt/include/async/uuid_generator.h b/mindspore/core/mindrt/include/async/uuid_generator.h new file mode 100644 index 0000000000..3827386b6a --- /dev/null +++ b/mindspore/core/mindrt/include/async/uuid_generator.h @@ -0,0 +1,44 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_UUID_GENERATOR_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_ASYNC_UUID_GENERATOR_H + +#include "uuid_base.h" + +namespace mindspore { + +namespace uuid_generator { +struct UUID : public mindspore::uuids::uuid { + public: + explicit UUID(const mindspore::uuids::uuid &inputUUID) : mindspore::uuids::uuid(inputUUID) {} + static UUID GetRandomUUID(); + std::string ToString(); +}; +} // namespace uuid_generator + +namespace localid_generator { +int GenLocalActorId(); + +#ifdef HTTP_ENABLED +int GenHttpClientConnId(); +int GenHttpServerConnId(); +#endif + +} // namespace localid_generator + +} // namespace mindspore +#endif diff --git a/mindspore/core/mindrt/include/litebus.h b/mindspore/core/mindrt/include/litebus.h new file mode 100644 index 0000000000..25b47cb2d1 --- /dev/null +++ b/mindspore/core/mindrt/include/litebus.h @@ -0,0 +1,45 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_LITEBUS_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_LITEBUS_H + +#ifdef __cplusplus +#include + +extern "C" { +#endif + +#define LITEBUS_URL_MAX_LEN 138 + +struct LitebusConfig { + char tcpUrl[LITEBUS_URL_MAX_LEN]; + char tcpUrlAdv[LITEBUS_URL_MAX_LEN]; + char udpUrl[LITEBUS_URL_MAX_LEN]; + char udpUrlAdv[LITEBUS_URL_MAX_LEN]; + int threadCount; + int httpKmsgFlag; +}; + +int LitebusInitializeC(const struct LitebusConfig *config); + +void LitebusFinalizeC(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mindspore/core/mindrt/include/litebus.hpp b/mindspore/core/mindrt/include/litebus.hpp new file mode 100755 index 0000000000..aa36185317 --- /dev/null +++ b/mindspore/core/mindrt/include/litebus.hpp @@ -0,0 +1,76 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_INCLUDE_LITEBUS_HPP_H +#define MINDSPORE_CORE_MINDRT_INCLUDE_LITEBUS_HPP_H + +#include +#include "mindrt/include/actor/actor.h" + +// brief provide an asynchronous programming framework as Actor model +namespace mindspore { + +struct LitebusAddress { + std::string scheme; + std::string ip; + uint16_t port; +}; + +// brief initialize the library +int Initialize(const std::string &tcpUrl, const std::string &tcpUrlAdv = "", const std::string &udpUrl = "", + const std::string &udpUrlAdv = "", int threadCount = 0); + +// brief spawn a process to run an actor +AID Spawn(ActorReference actor, bool sharedThread = true, bool start = true); + +// brief wait for the actor process to exit . It will be discarded +void Await(const ActorReference &actor); + +// brief get actor with aid +ActorReference GetActor(const AID &actor); + +// brief wait for the actor process to exit +void Await(const AID &actor); + +// brief Terminate the actor to exit +void Terminate(const AID &actor); + +// brief set the actor's running status +void SetActorStatus(const AID &actor, bool start); + +// brief Terminate all actors +void TerminateAll(); + +// brief terminate the process. It will be discarded +void Finalize(); + +// brief set the delegate of restful +void SetDelegate(const std::string &delegate); + +// set log pid of the process use litebus +void SetLogPID(HARES_LOG_PID pid); + +// get global litebus address +const LitebusAddress &GetLitebusAddress(); + +// get flag of http message format +int GetHttpKmsgFlag(); + +// brief set flag of http message format +void SetHttpKmsgFlag(int flag); + +} // namespace mindspore +#endif diff --git a/mindspore/core/mindrt/include/timer/duration.h b/mindspore/core/mindrt/include/timer/duration.h new file mode 100755 index 0000000000..d99a975a96 --- /dev/null +++ b/mindspore/core/mindrt/include/timer/duration.h @@ -0,0 +1,32 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LITEBUS_DURATION_HPP__ +#define __LITEBUS_DURATION_HPP__ + +#include +#include +#include +#include +#include +#include + +#include "async/spinlock.h" + +namespace mindspore { +using Duration = uint64_t; +} +#endif diff --git a/mindspore/core/mindrt/include/timer/timer.h b/mindspore/core/mindrt/include/timer/timer.h new file mode 100644 index 0000000000..ca3285d8b9 --- /dev/null +++ b/mindspore/core/mindrt/include/timer/timer.h @@ -0,0 +1,48 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LITEBUS_TIMER_HPP__ +#define __LITEBUS_TIMER_HPP__ + +#include "actor/aid.h" +#include "timer/timewatch.h" + +namespace mindspore { +class Timer { + public: + Timer(); + ~Timer(); + bool operator==(const Timer &that) const; + // run this timer's thunk. + void operator()() const; + TimeWatch GetTimeWatch() const; + AID GetTimerAID() const; + uint64_t GetTimerID() const; + + private: + friend class TimerTools; + + Timer(uint64_t timerId, const TimeWatch &timeWatch, const AID &timeAid, const std::function &handler); + + uint64_t id; + TimeWatch t; + AID aid; + std::function thunk; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/timer/timertools.h b/mindspore/core/mindrt/include/timer/timertools.h new file mode 100644 index 0000000000..0b19a51e9a --- /dev/null +++ b/mindspore/core/mindrt/include/timer/timertools.h @@ -0,0 +1,39 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LITEBUS_TIMETOOLS_HPP__ +#define __LITEBUS_TIMETOOLS_HPP__ + +#include +#include +#include +#include + +#include "timer/duration.h" +#include "timer/timer.h" + +namespace mindspore { +class TimerTools { + public: + static bool Initialize(); + static void Finalize(); + static Timer AddTimer(const Duration &duration, const AID &aid, const std::function &thunk); + static bool Cancel(const Timer &timer); + static std::atomic_bool g_initStatus; +}; +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/include/timer/timewatch.h b/mindspore/core/mindrt/include/timer/timewatch.h new file mode 100644 index 0000000000..87da4d39a4 --- /dev/null +++ b/mindspore/core/mindrt/include/timer/timewatch.h @@ -0,0 +1,65 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LITEBUS_TIMEWATCH_HPP__ +#define __LITEBUS_TIMEWATCH_HPP__ + +#include "timer/duration.h" +namespace mindspore { +constexpr Duration MICRTONANO = 1000; +constexpr Duration MILLITOMICR = 1000; +constexpr Duration SECTOMILLI = 1000; + +class TimeWatch { + public: + TimeWatch(); + + TimeWatch(const Duration &duration); + + TimeWatch(const TimeWatch &that); + ~TimeWatch(); + + // Constructs a Time instance that is the 'duration' from now. + static TimeWatch In(const Duration &duration); + + static Duration Now(); + + TimeWatch &operator=(const TimeWatch &that); + + TimeWatch &operator=(const Duration &duration); + + bool operator==(const TimeWatch &that) const; + + bool operator<(const TimeWatch &that) const; + + bool operator<=(const TimeWatch &that) const; + + // Returns the value of the timewatch as a Duration object. + Duration Time() const; + + // Returns the amount of time remaining. + Duration Remaining() const; + + // return true if the time expired. + bool Expired() const; + + private: + Duration duration; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/src/CMakeLists.txt b/mindspore/core/mindrt/src/CMakeLists.txt new file mode 100644 index 0000000000..c2a23c3fd5 --- /dev/null +++ b/mindspore/core/mindrt/src/CMakeLists.txt @@ -0,0 +1,131 @@ +# include DIRECTIVES FOR LITEBUS LIBRARY (generates, e.g., -I/path/to/thing on Linux). +###################################################################################### +if(${HTTP_ENABLED} STREQUAL "on") + set(LITEBUS_INCLUDE_DIR ${LITEBUS_INCLUDE_DIR} ${HTTP_PARSER_INCLUDE_DIR}) +endif() + +if(${SSL_ENABLED} STREQUAL "on") + set(LITEBUS_INCLUDE_DIR ${LITEBUS_INCLUDE_DIR} + ${LITEBUS_OSSCRYPTO_INCLUDE_DIR} + ${LITEBUS_HARESCRYPTO_INCLUDE_DIR} + ) +endif() + +link_directories(${SECUREC_LIB_DIR}) +link_directories(${GLOG_LIB_DIR}) +link_directories(${HARES_LOG_LIB_DIR}) +link_directories(${PROTOBUF_C_LIB_DIR}) + +if(${HTTP_ENABLED} STREQUAL "on") + link_directories(${HTTP_PARSER_LIB_DIR}) +endif() + +# LINK libgcov.a +####################################################################### +if(${CODE_COVERAGE} STREQUAL "on") + set(LINK_LIBS ${LINK_LIBS} gcov) +endif() + +# add object lib to avoid duplicate compile for a single source file +####################################################################### +add_library(litebus_obj OBJECT litebus.cc) +target_include_directories(litebus_obj PUBLIC ${LITEBUS_INCLUDE_DIR} ${3RDPARTY_LITEBUS_INCLUDE_DIRS}) +#add_library(decrypt_obj OBJECT) + +# THE LITEBUS LIBRARY (generates, e.g., liblitebus.so, etc., on Linux). +####################################################################### +if(${STATIC_LIB} STREQUAL "on") + +####################################################################### +add_library(${LITEBUS_TARGET}_static STATIC $) +target_link_libraries(${LITEBUS_TARGET}_static ${LINK_LIBS} ${LITEBUS_HARES_DECRYPT_SLIB} +${OPENSSL_SSL_LIB_A} ${OPENSSL_CRYPTO_LIB_A}) +set_target_properties(${LITEBUS_TARGET}_static PROPERTIES OUTPUT_NAME ${LITEBUS_TARGET}) + +if(DEFINED DEPEND_PATH) + add_custom_command(TARGET ${LITEBUS_TARGET}_static POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink lib${LITEBUS_TARGET}.a liblitebus.a + ) +endif() + +####################################################################### +endif() + + set(LINK_LIBS ${LINK_LIBS}) + +if(${HTTP_ENABLED} STREQUAL "on") + set(LINK_LIBS ${LINK_LIBS} ${HTTP_PARSER_DFLAG}) +endif() + +add_library(litebus_shared SHARED $) +target_link_libraries(litebus_shared ${LINK_LIBS}) +target_include_directories(litebus_shared PUBLIC ${LITEBUS_INCLUDE_DIR} ${3RDPARTY_LITEBUS_INCLUDE_DIRS}) + +set_target_properties( + litebus_shared PROPERTIES + OUTPUT_NAME litebus + VERSION ${LITEBUS_PACKAGE_VERSION} + SOVERSION ${LITEBUS_PACKAGE_VERSION} + LINK_FLAGS -s +) + +#copy lib to depend path (internal use) +#set(DEPEND_PATH "${PROJECT_SOURCE_DIR}/output1") +if(DEFINED DEPEND_PATH) + set(DEPEND_LIB_PATH ${DEPEND_PATH}/LITEBUS/lib) + set(DEPEND_INCLUDE_PATH ${DEPEND_PATH}/LITEBUS/include) + + add_custom_target(litebus_all ALL COMMENT "================= litebus_all =====================") + if(${STATIC_LIB} STREQUAL "on") + add_dependencies(litebus_all litebus_shared ${LITEBUS_TARGET}_static) + endif() + add_dependencies(litebus_all litebus_shared) + add_custom_command(TARGET litebus_all POST_BUILD + COMMAND ${CMAKE_COMMAND} -P ${PROJECT_SOURCE_DIR}/cmake/MakeDirectory.cmake + ${DEPEND_LIB_PATH} ${DEPEND_INCLUDE_PATH} + COMMAND ${CMAKE_COMMAND} -DLITEBUS_COPYTO="${DEPEND_LIB_PATH}" -P + ${PROJECT_SOURCE_DIR}/cmake/CopyLibToPath.cmake + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/litebus.hpp + ${DEPEND_INCLUDE_PATH} + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/litebus.h + ${DEPEND_INCLUDE_PATH} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/include/actor + ${DEPEND_INCLUDE_PATH}/actor + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/include/async + ${DEPEND_INCLUDE_PATH}/async + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/include/timer + ${DEPEND_INCLUDE_PATH}/timer + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/include/exec + ${DEPEND_INCLUDE_PATH}/exec + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/include/utils + ${DEPEND_INCLUDE_PATH}/utils) + if(${HTTP_ENABLED} STREQUAL "on") + add_custom_command(TARGET litebus_all POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${PROJECT_SOURCE_DIR}/include/httpd ${DEPEND_INCLUDE_PATH}/httpd) + endif() + if(${SSL_ENABLED} STREQUAL "on") + add_custom_command(TARGET litebus_all POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${PROJECT_SOURCE_DIR}/include/ssl ${DEPEND_INCLUDE_PATH}/ssl) + endif() + +endif() + +#install lib to package path +if("${PROJECT_HARES}" STREQUAL "cloudcore") + install(TARGETS litebus_shared LIBRARY DESTINATION HARES_LS_Master/lib PERMISSIONS OWNER_READ) + install(TARGETS litebus_shared LIBRARY DESTINATION HARES_LS_Slave/lib PERMISSIONS OWNER_READ) + install(TARGETS litebus_shared LIBRARY DESTINATION HARES_HASEN_Common/lib PERMISSIONS OWNER_READ) +elseif("${PROJECT_HARES}" STREQUAL "hasen_cloudcore_csp") + install(TARGETS litebus_shared LIBRARY DESTINATION HARES_Common/lib PERMISSIONS OWNER_READ) +else() + install(TARGETS litebus_shared LIBRARY DESTINATION HARES_Common/lib PERMISSIONS OWNER_READ) + install(TARGETS litebus_shared LIBRARY DESTINATION HARES_Slave/lib PERMISSIONS OWNER_READ) +endif() + +# Build pbjson.so. +add_subdirectory(actor) +add_subdirectory(async) +add_subdirectory(evloop) +add_subdirectory(timer) \ No newline at end of file diff --git a/mindspore/core/mindrt/src/actor/CMakeLists.txt b/mindspore/core/mindrt/src/actor/CMakeLists.txt new file mode 100644 index 0000000000..5118685fc6 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(litebus_obj PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/actor.cc + ${CMAKE_CURRENT_SOURCE_DIR}/actormgr.cc + ${CMAKE_CURRENT_SOURCE_DIR}/actorthread.cc + ${CMAKE_CURRENT_SOURCE_DIR}/actorpolicy.cc + ${CMAKE_CURRENT_SOURCE_DIR}/aid.cc + ${CMAKE_CURRENT_SOURCE_DIR}/sysmgr_actor.cc +) diff --git a/mindspore/core/mindrt/src/actor/actor.cc b/mindspore/core/mindrt/src/actor/actor.cc new file mode 100644 index 0000000000..f9d85117c9 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/actor.cc @@ -0,0 +1,221 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "actor/actor.h" +#include "actor/actormgr.h" +#include "actor/actorpolicyinterface.h" +#include "actor/iomgr.h" +#include "utils/log_adapter.h" + +namespace mindspore { + +ActorBase::ActorBase(const std::string &name) + : actorThread(nullptr), id(name, ActorMgr::GetActorMgrRef()->GetUrl()), actionFunctions() {} + +ActorBase::~ActorBase() {} + +void ActorBase::Spawn(std::shared_ptr &actor, std::unique_ptr thread) { + // lock here or await(). and unlock at Quit() or at aweit. + waiterLock.lock(); + + actorThread = std::move(thread); +} +void ActorBase::SetRunningStatus(bool start) { actorThread->SetRunningStatus(start); } + +void ActorBase::Await() { + std::string actorName = id.Name(); + // lock here or at spawn(). and unlock here or at worker(). wait for the worker to finish. + MS_LOG(DEBUG) << "ACTOR is waiting for terminate to finish. a=" << actorName.c_str(); + + waiterLock.lock(); + waiterLock.unlock(); + MS_LOG(DEBUG) << "ACTOR succeeded in waiting. a=" << actorName.c_str(); +} +void ActorBase::Terminate() { + std::unique_ptr msg(new (std::nothrow) MessageBase("Terminate", MessageBase::Type::KTERMINATE)); + BUS_OOM_EXIT(msg); + (void)EnqueMessage(std::move(msg)); +} + +void ActorBase::HandlekMsg(std::unique_ptr &msg) { + auto it = actionFunctions.find(msg->Name()); + if (it != actionFunctions.end()) { + ActorFunction &func = it->second; + func(msg); + } else { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_WARNING, PID_LITEBUS_LOG, + "ACTOR can not find function for message (%s)", "a=%s,m=%s", id.Name().c_str(), + msg->Name().c_str()); + MS_LOG(WARNING) << "ACTOR can not find function for message, a=" << id.Name().c_str() + << ",m=" << msg->Name().c_str(); + } +} +int ActorBase::EnqueMessage(std::unique_ptr msg) { return actorThread->EnqueMessage(msg); } + +void ActorBase::Quit() { + Finalize(); + actorThread->Terminate(this); + // lock at spawn(), unlock here. + waiterLock.unlock(); +} + +void ActorBase::Run() { + for (;;) { + auto msgs = actorThread->GetMsgs(); + if (msgs == nullptr) { + return; + } + for (auto it = msgs->begin(); it != msgs->end(); ++it) { + std::unique_ptr &msg = *it; + if (msg == nullptr) { + continue; + } + // std::cout << "dequeue message]actor=" << id.Name() << ",msg=" << msg->Name() << std::endl; + AddMsgRecord(msg->Name()); + switch (msg->GetType()) { + case MessageBase::Type::KMSG: + case MessageBase::Type::KUDP: { + if (Filter(msg)) { + continue; + } + this->HandlekMsg(msg); + break; + } + case MessageBase::Type::KHTTP: { + this->HandleHttp(std::move(msg)); + break; + } + case MessageBase::Type::KASYNC: { + msg->Run(this); + break; + } + case MessageBase::Type::KLOCAL: { + this->HandleLocalMsg(std::move(msg)); + break; + } + case MessageBase::Type::KTERMINATE: { + this->Quit(); + return; + } + case MessageBase::Type::KEXIT: { + this->Exited(msg->From()); + break; + } + } + } + msgs->clear(); + } +} + +int ActorBase::Send(const AID &to, std::unique_ptr msg) { + msg->SetFrom(id); + return ActorMgr::GetActorMgrRef()->Send(to, std::move(msg)); +} +int ActorBase::Send(const AID &to, std::string &&name, std::string &&strMsg, bool remoteLink, bool isExactNotRemote) { + std::unique_ptr msg( + new (std::nothrow) MessageBase(this->id, to, std::move(name), std::move(strMsg), MessageBase::Type::KMSG)); + BUS_OOM_EXIT(msg); + return ActorMgr::GetActorMgrRef()->Send(to, std::move(msg), remoteLink, isExactNotRemote); +} + +// register the message handle +void ActorBase::Receive(const std::string &msgName, ActorFunction &&func) { + if (actionFunctions.find(msgName) != actionFunctions.end()) { + MS_LOG(ERROR) << "ACTOR function's name conflicts, a=%s" << id.Name().c_str() << ",f=%s" << msgName.c_str(); + BUS_EXIT("function's name conflicts"); + return; + } + actionFunctions.emplace(msgName, std::move(func)); + return; +} + +int ActorBase::Link(const AID &to) { + auto io = ActorMgr::GetIOMgrRef(to); + if (io != nullptr) { + if (to.OK()) { + io->Link(this->GetAID(), to); + return ERRORCODE_SUCCESS; + } else { + return ACTOR_PARAMER_ERR; + } + } else { + return IO_NOT_FIND; + } +} +int ActorBase::UnLink(const AID &to) { + auto io = ActorMgr::GetIOMgrRef(to); + if (io != nullptr) { + if (to.OK()) { + io->UnLink(to); + return ERRORCODE_SUCCESS; + } else { + return ACTOR_PARAMER_ERR; + } + } else { + return IO_NOT_FIND; + } +} + +int ActorBase::Reconnect(const AID &to) { + auto io = ActorMgr::GetIOMgrRef(to); + if (io != nullptr) { + if (to.OK()) { + io->Reconnect(this->GetAID(), to); + return ERRORCODE_SUCCESS; + } else { + return ACTOR_PARAMER_ERR; + } + } else { + return IO_NOT_FIND; + } +} + +uint64_t ActorBase::GetOutBufSize(const AID &to) { + auto io = ActorMgr::GetIOMgrRef(to); + if (io != nullptr) { + return io->GetOutBufSize(); + } else { + return 0; + } +} + +uint64_t ActorBase::GetInBufSize(const AID &to) { + auto io = ActorMgr::GetIOMgrRef(to); + if (io != nullptr) { + return io->GetInBufSize(); + } else { + return 0; + } +} + +int ActorBase::AddRuleUdp(const std::string &peer, int recordNum) { + const std::string udp = BUS_UDP; + auto io = ActorMgr::GetIOMgrRef(udp); + if (io != nullptr) { + return io->AddRuleUdp(peer, recordNum); + } else { + return 0; + } +} + +void ActorBase::DelRuleUdp(const std::string &peer, bool outputLog) { + const std::string udp = BUS_UDP; + auto io = ActorMgr::GetIOMgrRef(udp); + if (io != nullptr) { + io->DelRuleUdp(peer, outputLog); + } +} +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/actor/actormgr.cc b/mindspore/core/mindrt/src/actor/actormgr.cc new file mode 100644 index 0000000000..82a29862f5 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/actormgr.cc @@ -0,0 +1,223 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "actor/actormgr.h" +#include "actor/actorpolicy.h" +#include "actor/iomgr.h" +#include "utils/log_adapter.h" + +namespace mindspore { + +std::shared_ptr ActorMgr::actorMgr = std::make_shared(); +std::map> ActorMgr::ioMgrs; + +std::shared_ptr &ActorMgr::GetIOMgrRef(const std::string &protocol) { + auto it = ioMgrs.find(protocol); + if (it != ioMgrs.end()) { + return it->second; + } else { + MS_LOG(DEBUG) << "Can't find IOMgr of protocol " << protocol.c_str(); + static std::shared_ptr nullIOMgr; + return nullIOMgr; + } +} +ActorMgr::ActorMgr() : actors(), procotols(), urls() { + actors.clear(); + procotols.clear(); + urls.clear(); +} + +ActorMgr::~ActorMgr() {} + +const std::string ActorMgr::GetUrl(const std::string &protocol) { + auto it = procotols.find(protocol); + if (it != procotols.end()) { + return it->second; + } else if (procotols.size() > 0) { + return procotols.begin()->second; + } else { + return ""; + } +} + +void ActorMgr::AddUrl(const std::string &protocol, const std::string &url) { + procotols[protocol] = url; + AID id("a@" + url); + (void)urls.insert(id.GetIp() + ":" + std::to_string(id.GetPort())); + (void)urls.insert(id.GetProtocol() + "://" + id.GetIp() + ":" + std::to_string(id.GetPort())); + (void)urls.insert(std::string("127.0.0.1:") + std::to_string(id.GetPort())); + (void)urls.insert(protocol + "://127.0.0.1:" + std::to_string(id.GetPort())); +} + +void ActorMgr::AddIOMgr(const std::string &protocol, const std::shared_ptr &ioMgr) { ioMgrs[protocol] = ioMgr; } + +void ActorMgr::RemoveActor(const std::string &name) { + MS_LOG(DEBUG) << "ACTOR was terminated with aid= " << name.c_str(); + actorsMutex.lock(); + (void)actors.erase(name); + actorsMutex.unlock(); +} + +void ActorMgr::TerminateAll() { + // copy all the actors + std::list actorsWaiting; + actorsMutex.lock(); + for (auto actorIt = actors.begin(); actorIt != actors.end(); ++actorIt) { + actorsWaiting.push_back(actorIt->second); + } + actorsMutex.unlock(); + + // send terminal msg to all actors. + for (auto actorIt = actorsWaiting.begin(); actorIt != actorsWaiting.end(); ++actorIt) { + std::unique_ptr msg(new (std::nothrow) MessageBase("Terminate", MessageBase::Type::KTERMINATE)); + BUS_OOM_EXIT(msg); + (void)(*actorIt)->EnqueMessage(std::move(msg)); + (*actorIt)->SetRunningStatus(true); + } + + // wait actor's thread to finish. + for (auto actorIt = actorsWaiting.begin(); actorIt != actorsWaiting.end(); ++actorIt) { + (*actorIt)->Await(); + } +} + +void ActorMgr::Initialize(int threadCount) { threadPool.AddThread(threadCount); } + +void ActorMgr::Finalize() { + this->TerminateAll(); + MS_LOG(INFO) << "litebus Actors finish exiting."; + + // stop all actor threads; + threadPool.Finalize(); + MS_LOG(INFO) << "litebus Threads finish exiting."; + + // stop iomgr thread + for (auto mgrIt = ioMgrs.begin(); mgrIt != ioMgrs.end(); ++mgrIt) { + MS_LOG(INFO) << "finalize IOMgr=" << mgrIt->first.c_str(); + mgrIt->second->Finish(); + } + + MS_LOG(INFO) << "litebus IOMGRS finish exiting."; +} + +ActorReference ActorMgr::GetActor(const AID &id) { + ActorReference result; + actorsMutex.lock(); + auto actorIt = actors.find(id.Name()); + if (actorIt != actors.end()) { + result = actorIt->second; + } else { + MS_LOG(DEBUG) << "can't find ACTOR with name=" << id.Name().c_str(); + result = nullptr; + } + // find the + actorsMutex.unlock(); + return result; +} +int ActorMgr::Send(const AID &to, std::unique_ptr msg, bool remoteLink, bool isExactNotRemote) { + // The destination is local + if (IsLocalAddres(to)) { + auto actor = GetActor(to); + if (actor != nullptr) { + if (to.GetProtocol() == BUS_UDP && msg->GetType() == MessageBase::Type::KMSG) { + msg->type = MessageBase::Type::KUDP; + } + return actor->EnqueMessage(std::move(msg)); + } else { + return ACTOR_NOT_FIND; + } + + } else { + // send to remote actor + if (msg->GetType() != MessageBase::Type::KMSG) { + MS_LOG(ERROR) << "The msg is not KMSG,it can't send to remote=" << std::string(to).c_str(); + return ACTOR_PARAMER_ERR; + } else { + // null + } + msg->SetTo(to); + auto io = ActorMgr::GetIOMgrRef(to); + if (io != nullptr) { + return io->Send(std::move(msg), remoteLink, isExactNotRemote); + } else { + MS_LOG(ERROR) << "The protocol is not supported:" + << "p=" << to.GetProtocol().c_str() << ",f=" << msg->From().Name().c_str() + << ",t=" << to.Name().c_str() << ",m=" << msg->Name().c_str(); + return IO_NOT_FIND; + } + } +} + +AID ActorMgr::Spawn(ActorReference &actor, bool shareThread, bool start) { + actorsMutex.lock(); + if (actors.find(actor->GetAID().Name()) != actors.end()) { + actorsMutex.unlock(); + MS_LOG(ERROR) << "The actor's name conflicts,name:" << actor->GetAID().Name().c_str(); + BUS_EXIT("Actor name conflicts."); + } + + MS_LOG(DEBUG) << "ACTOR was spawned,a=" << actor->GetAID().Name().c_str(); + + std::unique_ptr threadPolicy; + + if (shareThread) { + threadPolicy.reset(new (std::nothrow) ShardedThread(actor)); + BUS_OOM_EXIT(threadPolicy); + actor->Spawn(actor, std::move(threadPolicy)); + + } else { + threadPolicy.reset(new (std::nothrow) SingleThread()); + BUS_OOM_EXIT(threadPolicy); + actor->Spawn(actor, std::move(threadPolicy)); + ActorMgr::GetActorMgrRef()->SetActorReady(actor); + } + + (void)this->actors.emplace(actor->GetAID().Name(), actor); + actorsMutex.unlock(); + + // long time + actor->Init(); + + actor->SetRunningStatus(start); + + return actor->GetAID(); +} + +void ActorMgr::Terminate(const AID &id) { + auto actor = GetActor(id); + if (actor != nullptr) { + std::unique_ptr msg(new (std::nothrow) MessageBase("Terminate", MessageBase::Type::KTERMINATE)); + BUS_OOM_EXIT(msg); + (void)actor->EnqueMessage(std::move(msg)); + actor->SetRunningStatus(true); + } +} + +void ActorMgr::SetActorStatus(const AID &pid, bool start) { + auto actor = GetActor(pid); + if (actor != nullptr) { + actor->SetRunningStatus(start); + } +} + +void ActorMgr::Wait(const AID &id) { + auto actor = GetActor(id); + if (actor != nullptr) { + actor->Await(); + } +} + +}; // end of namespace mindspore diff --git a/mindspore/core/mindrt/src/actor/actormgr.h b/mindspore/core/mindrt/src/actor/actormgr.h new file mode 100644 index 0000000000..40d0a12742 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/actormgr.h @@ -0,0 +1,85 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_SRC_ACTOR_ACTORMGR_H +#define MINDSPORE_CORE_MINDRT_SRC_ACTOR_ACTORMGR_H + +#include +#include "actor/actorthread.h" + +namespace mindspore { + +class ActorBase; +class IOMgr; + +class ActorMgr { + public: + static inline std::shared_ptr &GetActorMgrRef() { return actorMgr; } + + static std::shared_ptr &GetIOMgrRef(const std::string &protocol = "tcp"); + + static inline std::shared_ptr &GetIOMgrRef(const AID &to) { return GetIOMgrRef(to.GetProtocol()); } + + static void Receive(std::unique_ptr &&msg) { + auto to = msg->To().Name(); + (void)ActorMgr::GetActorMgrRef()->Send(to, std::move(msg)); + } + + ActorMgr(); + ~ActorMgr(); + + void Finalize(); + void Initialize(int threadCount); + void RemoveActor(const std::string &name); + ActorReference GetActor(const AID &id); + const std::string GetUrl(const std::string &protocol = "tcp"); + void AddUrl(const std::string &protocol, const std::string &url); + void AddIOMgr(const std::string &protocol, const std::shared_ptr &ioMgr); + int Send(const AID &to, std::unique_ptr msg, bool remoteLink = false, bool isExactNotRemote = false); + AID Spawn(ActorReference &actor, bool shareThread = true, bool start = true); + void Terminate(const AID &id); + void TerminateAll(); + void Wait(const AID &pid); + inline const std::string &GetDelegate() const { return delegate; } + + inline void SetDelegate(const std::string &d) { delegate = d; } + inline void SetActorReady(const std::shared_ptr &actor) { threadPool.EnqueReadyActor(actor); } + void SetActorStatus(const AID &pid, bool start); + + private: + inline bool IsLocalAddres(const AID &id) { + if (id.Url() == "" || id.Url().empty() || urls.find(id.Url()) != urls.end()) { + return true; + } else { + return false; + } + } + // Map of all local spawned and running processes. + std::map actors; + std::mutex actorsMutex; + + ActorThread threadPool; + + std::map procotols; + std::set urls; + std::string delegate; + static std::shared_ptr actorMgr; + static std::map > ioMgrs; + +}; // end of class ActorMgr + +}; // end of namespace mindspore +#endif diff --git a/mindspore/core/mindrt/src/actor/actorpolicy.cc b/mindspore/core/mindrt/src/actor/actorpolicy.cc new file mode 100644 index 0000000000..9ebfd5b830 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/actorpolicy.cc @@ -0,0 +1,128 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "actor/actor.h" +#include "actor/actormgr.h" +#include "actor/actorpolicy.h" +#include "utils/log_adapter.h" + +namespace mindspore { + +void ActorPolicy::SetRunningStatus(bool startRun) { + std::lock_guard lock(mailboxLock); + this->start = startRun; + Notify(); +} + +SingleThread::SingleThread() {} +SingleThread::~SingleThread() {} + +void SingleThread::Terminate(const ActorBase *actor) { + std::string actorName = actor->GetAID().Name(); + MS_LOG(DEBUG) << "ACTOR SingleThread received terminate message, v=" << actorName.c_str(); + // remove actor from actorMgr + ActorMgr::GetActorMgrRef()->RemoveActor(actorName); +} + +int SingleThread::EnqueMessage(std::unique_ptr &msg) { + int result; + { + std::lock_guard lock(mailboxLock); + enqueMailbox->push_back(std::move(msg)); + result = ++msgCount; + } + + // Notify when the count of message is from empty to one. + if (start && result == 1) { + conditionVar.notify_one(); + } + + return result; +} +void SingleThread::Notify() { + if (start && msgCount > 0) { + conditionVar.notify_one(); + } +} + +std::list> *SingleThread::GetMsgs() { + std::list> *result; + std::unique_lock lock(mailboxLock); + conditionVar.wait(lock, [this] { return (!this->enqueMailbox->empty()); }); + SwapMailbox(); + + // REF_PRIVATE_MEMBER + result = dequeMailbox; + + return result; +} + +ShardedThread::ShardedThread(const std::shared_ptr &aActor) + : ready(false), terminated(false), actor(aActor) {} +ShardedThread::~ShardedThread() {} + +void ShardedThread::Terminate(const ActorBase *aActor) { + std::string actorName = aActor->GetAID().Name(); + MS_LOG(DEBUG) << "ACTOR ShardedThread received terminate message,v=" << actorName.c_str(); + // remove actor from actorMgr + ActorMgr::GetActorMgrRef()->RemoveActor(actorName); + + mailboxLock.lock(); + terminated = true; + this->actor = nullptr; + mailboxLock.unlock(); +} + +int ShardedThread::EnqueMessage(std::unique_ptr &msg) { + int result; + mailboxLock.lock(); + enqueMailbox->push_back(std::move(msg)); + // true : The actor is running. else the actor will be ready to run. + if (start && ready == false && terminated == false) { + ActorMgr::GetActorMgrRef()->SetActorReady(actor); + ready = true; + } + result = ++msgCount; + mailboxLock.unlock(); + return result; +} + +void ShardedThread::Notify() { + if (start && ready == false && terminated == false && msgCount > 0) { + ActorMgr::GetActorMgrRef()->SetActorReady(actor); + ready = true; + } +} + +std::list> *ShardedThread::GetMsgs() { + std::list> *result; + mailboxLock.lock(); + + if (enqueMailbox->empty()) { + ready = false; + result = nullptr; + } else { + ready = true; + SwapMailbox(); + result = dequeMailbox; + } + + mailboxLock.unlock(); + + return result; +} + +}; // end of namespace mindspore diff --git a/mindspore/core/mindrt/src/actor/actorpolicy.h b/mindspore/core/mindrt/src/actor/actorpolicy.h new file mode 100644 index 0000000000..16fcccef67 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/actorpolicy.h @@ -0,0 +1,56 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_SRC_ACTOR_ACTORPOLICY_H +#define MINDSPORE_CORE_MINDRT_SRC_ACTOR_ACTORPOLICY_H +#include "actor/actorpolicyinterface.h" + +namespace mindspore { + +class ShardedThread : public ActorPolicy { + public: + ShardedThread(const std::shared_ptr &actor); + virtual ~ShardedThread(); + + protected: + virtual void Terminate(const ActorBase *actor); + virtual int EnqueMessage(std::unique_ptr &msg); + virtual std::list> *GetMsgs(); + virtual void Notify(); + + private: + bool ready; + bool terminated; + std::shared_ptr actor; +}; + +class SingleThread : public ActorPolicy { + public: + SingleThread(); + virtual ~SingleThread(); + + protected: + virtual void Terminate(const ActorBase *actor); + virtual int EnqueMessage(std::unique_ptr &msg); + virtual std::list> *GetMsgs(); + virtual void Notify(); + + private: + std::condition_variable conditionVar; +}; + +}; // end of namespace mindspore +#endif diff --git a/mindspore/core/mindrt/src/actor/actorpolicyinterface.h b/mindspore/core/mindrt/src/actor/actorpolicyinterface.h new file mode 100644 index 0000000000..132ec46406 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/actorpolicyinterface.h @@ -0,0 +1,61 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_SRC_ACTOR_ACTORPOLICYINTERFACE_H +#define MINDSPORE_CORE_MINDRT_SRC_ACTOR_ACTORPOLICYINTERFACE_H + +namespace mindspore { + +class ActorPolicy { + public: + ActorPolicy() : mailbox1(), mailbox2() { + enqueMailbox = &mailbox1; + dequeMailbox = &mailbox2; + msgCount = 0; + start = false; + }; + virtual ~ActorPolicy(){}; + inline void SwapMailbox() { + std::list> *temp; + temp = enqueMailbox; + enqueMailbox = dequeMailbox; + dequeMailbox = temp; + msgCount = 0; + } + + protected: + void SetRunningStatus(bool startRun); + virtual void Terminate(const ActorBase *actor) = 0; + virtual int EnqueMessage(std::unique_ptr &msg) = 0; + virtual std::list> *GetMsgs() = 0; + virtual void Notify() = 0; + + std::list> *enqueMailbox; + std::list> *dequeMailbox; + + int msgCount; + bool start; + std::mutex mailboxLock; + + private: + friend class ActorBase; + + std::list> mailbox1; + std::list> mailbox2; +}; + +}; // end of namespace mindspore +#endif diff --git a/mindspore/core/mindrt/src/actor/actorthread.cc b/mindspore/core/mindrt/src/actor/actorthread.cc new file mode 100644 index 0000000000..fa40729f13 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/actorthread.cc @@ -0,0 +1,104 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "actor/actorthread.h" +#include +#include "utils/log_adapter.h" + +namespace mindspore { +constexpr int MAXTHREADNAMELEN = 12; +ActorThread::ActorThread() : readyActors(), workers() { + readyActors.clear(); + workers.clear(); + + char *envThreadName = getenv("LITEBUS_THREAD_NAME"); + if (envThreadName != nullptr) { + threadName = envThreadName; + if (threadName.size() > MAXTHREADNAMELEN) { + threadName.resize(MAXTHREADNAMELEN); + } + } else { + threadName = "HARES_LB_ACT"; + } +} + +ActorThread::~ActorThread() {} +void ActorThread::AddThread(int threadCount) { + for (int i = 0; i < threadCount; ++i) { + std::unique_ptr worker(new (std::nothrow) std::thread(&ActorThread::Run, this)); + BUS_OOM_EXIT(worker); + workers.push_back(std::move(worker)); + } +} +void ActorThread::Finalize() { + MS_LOG(INFO) << "Actor's threads are exiting."; + // terminate all thread; enqueue nullptr actor to terminate; + std::shared_ptr exitActor(nullptr); + for (auto it = workers.begin(); it != workers.end(); ++it) { + EnqueReadyActor(exitActor); + } + // wait all thread to exit + for (auto it = workers.begin(); it != workers.end(); ++it) { + std::unique_ptr &worker = *it; + if (worker->joinable()) { + worker->join(); + } + } + workers.clear(); + MS_LOG(INFO) << "Actor's threads finish exiting."; +} + +void ActorThread::DequeReadyActor(std::shared_ptr &actor) { + std::unique_lock lock(readyActorMutex); + conditionVar.wait(lock, [this] { return (this->readyActors.size() > 0); }); + actor = readyActors.front(); + readyActors.pop_front(); +} + +void ActorThread::EnqueReadyActor(const std::shared_ptr &actor) { + { + std::lock_guard lock(readyActorMutex); + readyActors.push_back(actor); + } + conditionVar.notify_one(); +} + +void ActorThread::Run() { +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 12 + static std::atomic actorCount(1); + int ret = pthread_setname_np(pthread_self(), (threadName + std::to_string(actorCount.fetch_add(1))).c_str()); + if (0 != ret) { + MS_LOG(INFO) << "set pthread name fail]ret:" << ret; + } else { + MS_LOG(INFO) << "set pthread name success]threadID:" << pthread_self(); + } +#endif + + bool terminate = false; + do { + std::shared_ptr actor; + DequeReadyActor(actor); + if (actor != nullptr) { + actor->Run(); + } else { + terminate = true; + MS_LOG(DEBUG) << "Actor this Threads have finished exiting."; + } + + } while (!terminate); +} + +}; // end of namespace mindspore diff --git a/mindspore/core/mindrt/src/actor/actorthread.h b/mindspore/core/mindrt/src/actor/actorthread.h new file mode 100644 index 0000000000..2c54a2c667 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/actorthread.h @@ -0,0 +1,49 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_SRC_ACTOR_ACTORTHREAD_H +#define MINDSPORE_CORE_MINDRT_SRC_ACTOR_ACTORTHREAD_H + +#include +#include +#include + +#include "actor/actor.h" + +namespace mindspore { + +class ActorThread { + public: + ActorThread(); + ~ActorThread(); + void Finalize(); + void AddThread(int threadCount); + void EnqueReadyActor(const std::shared_ptr &actor); + + private: + void Run(); + void DequeReadyActor(std::shared_ptr &actor); + + std::list> readyActors; + std::mutex readyActorMutex; + std::condition_variable conditionVar; + + std::list> workers; + std::string threadName; +}; + +}; // end of namespace mindspore +#endif diff --git a/mindspore/core/mindrt/src/actor/aid.cc b/mindspore/core/mindrt/src/actor/aid.cc new file mode 100644 index 0000000000..a5bab35bbc --- /dev/null +++ b/mindspore/core/mindrt/src/actor/aid.cc @@ -0,0 +1,127 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "actor/aid.h" +#include "utils/log_adapter.h" + +namespace mindspore { + +constexpr int PORTMINNUMBER = 0; +constexpr int PORTMAXNUMBER = 65535; +constexpr int PROCOLLEN = 3; // strlen("://"); + +void AID::SetUnfixUrl() { + size_t index = url.find("://"); + if (index != std::string::npos) { + if (url.substr(0, index) == BUS_TCP) { + url = url.substr(index + PROCOLLEN); + } + } +} + +AID::AID(const char *tmpName) { + std::string sName = tmpName; + size_t index = sName.find("@"); + if (index == std::string::npos) { + name = sName; + url = ""; + } else { + name = sName.substr(0, index); + url = sName.substr(index + 1); + SetUnfixUrl(); + } +} + +AID::AID(const std::string &tmpName) { + size_t index = tmpName.find("@"); + if (index == std::string::npos) { + name = tmpName; + url = ""; + } else { + name = tmpName.substr(0, index); + url = tmpName.substr(index + 1); + SetUnfixUrl(); + } +} + +bool AID::OK() const { + std::string proto = GetProtocol(); +#ifdef UDP_ENABLED + bool protoOK = (proto == BUS_TCP) || (proto == BUS_UDP); +#else + bool protoOK = (proto == BUS_TCP); +#endif + int port = GetPort(); + bool portOK = port > PORTMINNUMBER && port < PORTMAXNUMBER; + return protoOK && portOK && name != ""; +} +AID &AID::operator=(const AID &id) { + if (&id != this) { + name = id.name; + url = id.url; + } + return *this; +} + +void AID::SetProtocol(const std::string &protocol) { + size_t index = url.find("://"); + if (index != std::string::npos) { + if (protocol == BUS_TCP) { + url = url.substr(index + PROCOLLEN); + } else { + url = protocol + url.substr(index); + } + + } else { + if (protocol == BUS_TCP) { + // url = url; + } else { + url = protocol + "://" + url; + } + } +} + +std::string AID::GetProtocol() const { + size_t index = url.find("://"); + if (index != std::string::npos) { + return url.substr(0, index); + } else { + return "tcp"; + } +} + +std::string AID::GetIp() const { + size_t index1 = url.find("://"); + if (index1 == std::string::npos) { + index1 = 0; + } else { + index1 = index1 + PROCOLLEN; + } + size_t index2 = url.rfind(':'); + if ((index2 == std::string::npos) || (index2 < index1)) { + MS_LOG(INFO) << "wrong url:%s,u=" << url.c_str(); + return url; + } else { + return url.substr(index1, index2 - index1); + } +} + +uint16_t AID::GetPort() const { + size_t index = url.rfind(':'); + return (uint16_t)std::stoul(url.substr(index + 1)); +} + +}; // end of namespace mindspore diff --git a/mindspore/core/mindrt/src/actor/iomgr.h b/mindspore/core/mindrt/src/actor/iomgr.h new file mode 100644 index 0000000000..1d14dc6fa2 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/iomgr.h @@ -0,0 +1,90 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_SRC_ACTOR_IOMGR_H +#define MINDSPORE_CORE_MINDRT_SRC_ACTOR_IOMGR_H +#include +#include "actor/aid.h" + +#include "actor/msg.h" + +namespace mindspore { + +class AID; +class MessageBase; + +// Server socket listen backlog. +static const int SOCKET_LISTEN_BACKLOG = 2048; + +static const int SOCKET_KEEPALIVE = 1; + +// Send first probe after `interval' seconds. +static const int SOCKET_KEEPIDLE = 600; + +// Send next probes after the specified interval. +static const int SOCKET_KEEPINTERVAL = 5; + +// Consider the socket in error state after we send three ACK +// probes without getting a reply. +static const int SOCKET_KEEPCOUNT = 3; + +static const std::string BUS_MAGICID = "BUS0"; + +static const std::string URL_PROTOCOL_IP_SEPARATOR = "://"; + +static const std::string URL_IP_PORT_SEPARATOR = ":"; + +static const std::string UDP_EVLOOP_THREADNAME = "HARES_LB_Udp"; + +static const std::string TCP_RECV_EVLOOP_THREADNAME = "HARES_LB_TcpR"; +static const std::string TCP_SEND_EVLOOP_THREADNAME = "HARES_LB_TcpS"; + +static const std::string HTTP_CLIENT_EVLOOP_THREADNAME = "HARES_LB_Htp"; + +class IOMgr { + public: + using MsgHandler = void (*)(std::unique_ptr &&msg); + /** + * remoteLink and isExactNotRemote are flags to tell us which link should be used. There are several cases: + * 1. remoteLink is false and isExactNotRemote is false : callers can reuse remote link when threr are no links + * created before. + * 2. remoteLink is true and isExactNotRemote is false : callers can only use remote link + * 3. remoteLink is true and isExactNotRemote is true : as the same as case 2 + * 4. remoteLink is false and isExactNotRemote is true : callers can't reuse remote link. if no link, + * we will create a new one for callers. + */ + virtual int Send(std::unique_ptr &&msg, bool remoteLink = false, bool isExactNotRemote = false) = 0; + virtual void Link(const AID &sAid, const AID &dAid) = 0; + // close the socket,and send exitedEvent to all linkers. + virtual void UnLink(const AID &dAid) = 0; + virtual void Reconnect(const AID &sAid, const AID &dAid) = 0; + virtual void RegisterMsgHandle(MsgHandler handle) = 0; + virtual bool Init() = 0; // once + virtual void Finish() = 0; // once + virtual bool StartIOServer(const std::string &url, const std::string &advertiseUrl) = 0; // multicalledable + virtual uint64_t GetOutBufSize() = 0; + virtual uint64_t GetInBufSize() = 0; + virtual void CollectMetrics() = 0; + virtual int AddRuleUdp(std::string peer, int recordNum) = 0; + virtual void DelRuleUdp(std::string peer, bool outputLog) = 0; + virtual void LinkRecycleCheck(int recyclePeroid) = 0; + IOMgr() {} + virtual ~IOMgr() {} +}; + +}; // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/src/actor/sysmgr_actor.cc b/mindspore/core/mindrt/src/actor/sysmgr_actor.cc new file mode 100644 index 0000000000..62a6a3c6c4 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/sysmgr_actor.cc @@ -0,0 +1,85 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "actor/actormgr.h" +#include "actor/iomgr.h" +#include "utils/log_adapter.h" + +namespace mindspore { + +Duration SysMgrActor::linkRecycleDuration = 10000; + +void MetricsMessage::PrintMetrics() { + // print sendMetrics by default, in the future we can add more metrics format + std::ostringstream out; + + while (!intTypeMetrics.empty()) { + out << intTypeMetrics.front() << "-"; + intTypeMetrics.pop(); + } + + out << "|"; + + while (!stringTypeMetrics.empty()) { + std::string stringMetric = stringTypeMetrics.front(); + if (stringMetric.empty()) { + out << "null" + << "-"; + } else { + out << stringMetric << "-"; + } + + stringTypeMetrics.pop(); + } + + MS_LOG(INFO) << "[format:fd-err-sum-size|to-okmsg-failmsg], value:" << out.str().c_str(); +} + +void SysMgrActor::SendMetricsDurationCallback() { + std::string protocol = "tcp"; + std::shared_ptr ioMgrRef = ActorMgr::GetIOMgrRef(protocol); + if (ioMgrRef == nullptr) { + MS_LOG(INFO) << "tcp protocol is not exist."; + } else { + ioMgrRef->CollectMetrics(); + } + + (void)AsyncAfter(printSendMetricsDuration, GetAID(), &SysMgrActor::SendMetricsDurationCallback); +} + +void SysMgrActor::HandleSendMetricsCallback(const AID &from, std::unique_ptr message) { + if (message == nullptr) { + MS_LOG(WARNING) << "Can't transform to MetricsMessage."; + return; + } + message->PrintMetrics(); + return; +} + +void SysMgrActor::LinkRecycleDurationCallback() { + std::string protocol = "tcp"; + std::shared_ptr ioMgrRef = ActorMgr::GetIOMgrRef(protocol); + if (ioMgrRef == nullptr) { + MS_LOG(INFO) << "tcp protocol is not exist."; + } else { + ioMgrRef->LinkRecycleCheck(linkRecyclePeriod); + } + + (void)AsyncAfter(linkRecycleDuration, GetAID(), &SysMgrActor::LinkRecycleDurationCallback); +} + +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/actor/sysmgr_actor.h b/mindspore/core/mindrt/src/actor/sysmgr_actor.h new file mode 100644 index 0000000000..36191c5e61 --- /dev/null +++ b/mindspore/core/mindrt/src/actor/sysmgr_actor.h @@ -0,0 +1,93 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_CORE_MINDRT_SRC_ACTOR_SYSMGR_ACTOR_H +#define MINDSPORE_CORE_MINDRT_SRC_ACTOR_SYSMGR_ACTOR_H + +#include + +#include "async/async.h" +#include "async/asyncafter.h" +#include "actor/actorapp.h" +#include "utils/log_adapter.h" + +namespace mindspore { + +const std::string SYSMGR_ACTOR_NAME = "SysMgrActor"; +const std::string METRICS_SEND_MSGNAME = "SendMetrics"; +const int LINK_RECYCLE_PERIOD_MIN = 20; +const int LINK_RECYCLE_PERIOD_MAX = 360; + +using IntTypeMetrics = std::queue; +using StringTypeMetrics = std::queue; + +class MetricsMessage : public MessageBase { + public: + explicit MetricsMessage(const std::string &tfrom, const std::string &tTo, const std::string &tName, + const IntTypeMetrics &tInts = IntTypeMetrics(), + const StringTypeMetrics &tStrings = StringTypeMetrics()) + : MessageBase(tfrom, tTo, tName), intTypeMetrics(tInts), stringTypeMetrics(tStrings) {} + + ~MetricsMessage() override {} + + void PrintMetrics(); + + private: + IntTypeMetrics intTypeMetrics; + StringTypeMetrics stringTypeMetrics; +}; + +class SysMgrActor : public mindspore::AppActor { + public: + explicit SysMgrActor(const std::string &name, const Duration &duration) + : mindspore::AppActor(name), printSendMetricsDuration(duration) { + linkRecyclePeriod = 0; + } + + ~SysMgrActor() override {} + + protected: + virtual void Init() override { + MS_LOG(INFO) << "Initiaize SysMgrActor"; + // register receive handle + Receive("SendMetrics", &SysMgrActor::HandleSendMetricsCallback); + + // start sys manager timers + (void)AsyncAfter(printSendMetricsDuration, GetAID(), &SysMgrActor::SendMetricsDurationCallback); + + char *linkRecycleEnv = getenv("LITEBUS_LINK_RECYCLE_PERIOD"); + if (linkRecycleEnv != nullptr) { + int period = 0; + period = std::stoi(linkRecycleEnv); + if (period >= LINK_RECYCLE_PERIOD_MIN && period <= LINK_RECYCLE_PERIOD_MAX) { + MS_LOG(INFO) << "link recycle set:" << period; + linkRecyclePeriod = period; + (void)AsyncAfter(linkRecycleDuration, GetAID(), &SysMgrActor::LinkRecycleDurationCallback); + } + } + } + + private: + void SendMetricsDurationCallback(); + void HandleSendMetricsCallback(const AID &from, std::unique_ptr message); + void LinkRecycleDurationCallback(); + Duration printSendMetricsDuration; + static Duration linkRecycleDuration; + int linkRecyclePeriod; +}; + +} // namespace mindspore +#endif diff --git a/mindspore/core/mindrt/src/async/CMakeLists.txt b/mindspore/core/mindrt/src/async/CMakeLists.txt new file mode 100644 index 0000000000..d95e6ac5a9 --- /dev/null +++ b/mindspore/core/mindrt/src/async/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(litebus_obj PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/async.cc + ${CMAKE_CURRENT_SOURCE_DIR}/future.cc + ${CMAKE_CURRENT_SOURCE_DIR}/uuid_base.cc + ${CMAKE_CURRENT_SOURCE_DIR}/uuid_generator.cc +# ${CMAKE_CURRENT_SOURCE_DIR}/flag_parser_impl.cpp +) diff --git a/mindspore/core/mindrt/src/async/async.cc b/mindspore/core/mindrt/src/async/async.cc new file mode 100644 index 0000000000..92e1f179c2 --- /dev/null +++ b/mindspore/core/mindrt/src/async/async.cc @@ -0,0 +1,41 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "async/async.h" +#include "actor/actormgr.h" + +namespace mindspore { + +class MessageAsync : public MessageBase { + public: + explicit MessageAsync(std::unique_ptr h) + : MessageBase("Async", Type::KASYNC), handler(std::move(h)) {} + + ~MessageAsync() override {} + + void Run(ActorBase *actor) override { (*handler)(actor); } + + private: + std::unique_ptr handler; +}; + +void Async(const AID &aid, std::unique_ptr> handler) { + std::unique_ptr msg(new (std::nothrow) MessageAsync(std::move(handler))); + BUS_OOM_EXIT(msg); + (void)ActorMgr::GetActorMgrRef()->Send(aid, std::move(msg)); +} + +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/async/future.cc b/mindspore/core/mindrt/src/async/future.cc new file mode 100644 index 0000000000..b7ace76722 --- /dev/null +++ b/mindspore/core/mindrt/src/async/future.cc @@ -0,0 +1,34 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "async/future.h" +#include "utils/log_adapter.h" + +namespace mindspore { +namespace internal { + +void Waitf(const AID &aid) { + mindspore::Terminate(aid); + MS_LOG(WARNING) << "WaitFor is timeout."; +} + +void Wait(const AID &aid, const mindspore::Timer &timer) { + mindspore::TimerTools::Cancel(timer); + mindspore::Terminate(aid); +} + +} // namespace internal +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/async/uuid_base.cc b/mindspore/core/mindrt/src/async/uuid_base.cc new file mode 100644 index 0000000000..1fec8aa19b --- /dev/null +++ b/mindspore/core/mindrt/src/async/uuid_base.cc @@ -0,0 +1,180 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "async/uuid_base.h" +#include +#include "utils/log_adapter.h" + +namespace mindspore { +namespace uuids { + +constexpr int DASH_POS0 = 4; +constexpr int DASH_POS1 = 6; +constexpr int DASH_POS2 = 8; +constexpr int DASH_POS3 = 10; +constexpr int SHIFT_BIT = 4; + +const uint8_t *uuid::BeginAddress() const { return uuidData; } + +const uint8_t *uuid::EndAddress() const { return uuidData + UUID_SIZE; } + +std::size_t uuid::Size() { return UUID_SIZE; } + +std::string uuid::ToBytes(const uuid &u) { + BUS_ASSERT(sizeof(u) == UUID_SIZE); + return std::string(reinterpret_cast(u.uuidData), sizeof(u.uuidData)); +} + +Option uuid::FromBytes(const std::string &s) { + if (s.size() != UUID_SIZE) { + return None(); + } + uuid u; + memcpy(&u.uuidData, s.data(), s.size()); + + return u; +} + +Option uuid::GetValue(char c) { + static char const digitsBegin[] = "0123456789abcdefABCDEF"; + static const size_t digitsLen = (sizeof(digitsBegin) / sizeof(char)) - 1; + static const char *const digitsEnd = digitsBegin + digitsLen; + static unsigned char const values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15}; + size_t pos = std::find(digitsBegin, digitsEnd, c) - digitsBegin; + if (pos >= digitsLen) { + MS_LOG(ERROR) << "invalid char"; + return None(); + } + return values[pos]; +} + +Option uuid::FromString(const std::string &s) { + auto sBegin = s.begin(); + if (sBegin == s.end()) { + return None(); + } + auto c = *sBegin; + bool hasOpenBrace = (c == '{'); + bool hasDashes = false; + if (hasOpenBrace) { + ++sBegin; + } + uuid u; + for (size_t i = 0; sBegin != s.end(); ++i) { + c = *(sBegin++); + if ((i == DASH_POS0) && (c == '-')) { + hasDashes = true; + c = *(sBegin++); + } else if ((i == DASH_POS1 || i == DASH_POS2 || i == DASH_POS3) && (hasDashes == true)) { + if (c == '-' && sBegin != s.end()) { + c = *(sBegin++); + } else { + MS_LOG(ERROR) << "str invalid"; + return None(); + } + } + Option oc1 = GetValue(c); + if (oc1.IsNone()) { + return None(); + } + u.uuidData[i] = oc1.Get(); + if (sBegin != s.end()) { + c = *(sBegin++); + } + u.uuidData[i] <<= SHIFT_BIT; + Option oc2 = GetValue(c); + if (oc2.IsNone()) { + return None(); + } + u.uuidData[i] |= oc2.Get(); + } + if ((hasOpenBrace && (c != '}')) || (sBegin != s.end())) { + MS_LOG(ERROR) << "No } end or leng invalid"; + return None(); + } + return u; +} + +// To check whether uuid looks like 0000000-000-000-000-000000000000000 +bool uuid::IsNilUUID() const { + for (std::size_t i = 0; i < Size(); i++) { + if (uuidData[i]) { + return false; + } + } + + return true; +} + +const uint8_t *uuid::Get() const { return uuidData; } + +uint8_t *uuid::BeginAddress() { return uuidData; } + +uint8_t *uuid::EndAddress() { return uuidData + UUID_SIZE; } + +uuid RandomBasedGenerator::GenerateRandomUuid() { + const int VARIANT_BIT_OFFSET = 8; + const int VERSION_BIT_OFFSET = 6; + const int RIGHT_SHIFT_BITS = 8; + uuid tmpUUID; + + // This is used to generate a random number as a random seed + std::random_device rd; + + // Mersenne Twister algorithm, as a generator engine, + // which is used to generate a random number + std::mt19937 gen(rd()); + + // We use uniform distribution + std::uniform_int_distribution distribution((std::numeric_limits::min)(), + (std::numeric_limits::max)()); + + unsigned long randomValue = distribution(gen); + + unsigned int i = 0; + for (uint8_t *it = tmpUUID.BeginAddress(); it != tmpUUID.EndAddress(); ++it, ++i) { + if (i == sizeof(unsigned long)) { + randomValue = distribution(gen); + i = 0; + } + + *it = static_cast((randomValue >> (i * RIGHT_SHIFT_BITS)) & 0xFF); + } + + // use atomic ++ to replace random + static std::atomic ul(1); + unsigned long lCount = ul.fetch_add(1); + unsigned long offSet = distribution(gen) % RIGHT_SHIFT_BITS; + auto ret = memcpy(tmpUUID.BeginAddress() + offSet, &lCount, sizeof(lCount)); + if (ret != 0) { + MS_LOG(ERROR) << "memcpy_s error."; + BUS_OOM_EXIT(tmpUUID.BeginAddress()); + } + + // set the variant + *(tmpUUID.BeginAddress() + VARIANT_BIT_OFFSET) &= 0xBF; + *(tmpUUID.BeginAddress() + VARIANT_BIT_OFFSET) |= 0x80; + + // set the uuid generation version + *(tmpUUID.BeginAddress() + VERSION_BIT_OFFSET) &= 0x4F; + *(tmpUUID.BeginAddress() + VERSION_BIT_OFFSET) |= 0x40; + + return tmpUUID; +} + +} // namespace uuids +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/async/uuid_generator.cc b/mindspore/core/mindrt/src/async/uuid_generator.cc new file mode 100644 index 0000000000..9f7d376976 --- /dev/null +++ b/mindspore/core/mindrt/src/async/uuid_generator.cc @@ -0,0 +1,61 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "async/uuid_generator.h" +#include +#include + +namespace mindspore { + +namespace uuid_generator { +UUID UUID::GetRandomUUID() { return UUID(mindspore::uuids::RandomBasedGenerator::GenerateRandomUuid()); } + +std::string UUID::ToString() { + std::ostringstream ret; + ret << *this; + return ret.str(); +} +} // namespace uuid_generator + +namespace localid_generator { +int GenLocalActorId() { + static std::atomic localActorId(0); + return localActorId.fetch_add(1); +} + +#ifdef HTTP_ENABLED +// not support muti-thread +int GenHttpClientConnId() { + static int httpClientConnId = 1; + if (httpClientConnId == INT_MAX) { + httpClientConnId = 1; + } + return httpClientConnId++; +} + +// not support muti-thread +int GenHttpServerConnId() { + static int httpServerConnId = 1; + if (httpServerConnId == INT_MAX) { + httpServerConnId = 1; + } + return httpServerConnId++; +} +#endif + +} // namespace localid_generator + +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/evloop/CMakeLists.txt b/mindspore/core/mindrt/src/evloop/CMakeLists.txt new file mode 100644 index 0000000000..67a456f7c4 --- /dev/null +++ b/mindspore/core/mindrt/src/evloop/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(litebus_obj PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/evloop.cc +) \ No newline at end of file diff --git a/mindspore/core/mindrt/src/evloop/evloop.cc b/mindspore/core/mindrt/src/evloop/evloop.cc new file mode 100644 index 0000000000..d98ec17e6d --- /dev/null +++ b/mindspore/core/mindrt/src/evloop/evloop.cc @@ -0,0 +1,387 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "actor/buslog.h" +#include "evloop/evloop.h" +#include "utils/log_adapter.h" + +namespace mindspore { + +int EventLoopRun(EvLoop *evloop, int timeout) { + int nevent = 0; + struct epoll_event *events = nullptr; + + (void)sem_post(&evloop->semId); + + size_t size = 1; + events = (struct epoll_event *)malloc(size); + if (events == nullptr) { + MS_LOG(ERROR) << "malloc events fail"; + return BUS_ERROR; + } + // 1. dest is valid 2. destsz equals to count and both are valid. + // memset_s will always executes successfully. + (void)memset(events, 0, size); + + while (!evloop->stopLoop) { + /* free deleted event handlers */ + evloop->EventFreeDelEvents(); + + MS_LOG(DEBUG) << "timeout:" << timeout << ",epoll_fd:" << evloop->efd; + MS_LOG(DEBUG) << "nevent:" << nevent << ",epoll_fd:" << evloop->efd; + if (nevent < 0) { + if (errno != EINTR) { + MS_LOG(ERROR) << "epoll_wait failed]epoll_fd:" << evloop->efd << ",errno:" << errno; + free(events); + return BUS_ERROR; + } else { + continue; + } + } else if (nevent > 0) { + /* save the epoll modify in "stop" while dispatching handlers */ + evloop->HandleEvent(events, nevent); + } else { + MS_LOG(ERROR) << "epoll_wait failed]epoll_fd:" << evloop->efd << ",ret:0,errno:" << errno; + evloop->stopLoop = 1; + } + + if (evloop->stopLoop) { + /* free deleted event handlers */ + evloop->EventFreeDelEvents(); + } + } + evloop->stopLoop = 0; + MS_LOG(INFO) << "event epoll loop run end"; + free(events); + return BUS_OK; +} + +void *EvloopRun(void *arg) { + if (arg == nullptr) { + MS_LOG(ERROR) << "arg is null"; + } else { + (void)EventLoopRun((EvLoop *)arg, -1); + } + return nullptr; +} + +void QueueReadyCallback(int fd, uint32_t events, void *arg) { + EvLoop *evloop = (EvLoop *)arg; + if (evloop == nullptr) { + MS_LOG(ERROR) << "evloop is null]fd:" << fd << ",events:" << events; + return; + } + + uint64_t count; + if (read(evloop->queueEventfd, &count, sizeof(count)) == sizeof(count)) { + // take out functions from the queue + std::queue> q; + + evloop->queueMutex.lock(); + evloop->queue.swap(q); + evloop->queueMutex.unlock(); + + // invoke functions in the queue + while (!q.empty()) { + q.front()(); + q.pop(); + } + } +} + +void EvLoop::CleanUp() { + if (queueEventfd != -1) { + close(queueEventfd); + queueEventfd = -1; + } + + if (efd != -1) { + close(efd); + efd = -1; + } +} + +int EvLoop::AddFuncToEvLoop(std::function &&func) { + // put func to the queue + queueMutex.lock(); + queue.emplace(std::move(func)); + // return the queque size to send's caller. + int result = queue.size(); + queueMutex.unlock(); + + if (result == 1) { + // wakeup event loop + uint64_t one = 1; + if (write(queueEventfd, &one, sizeof(one)) != sizeof(one)) { + MS_LOG(WARNING) << "fail to write queueEventfd]fd:" << queueEventfd << ",errno:" << errno; + } + } + + return result; +} + +bool EvLoop::Init(const std::string &threadName) { + int retval = EventLoopCreate(); + if (retval != BUS_OK) { + return false; + } + (void)sem_init(&semId, 0, 0); + + if (pthread_create(&loopThread, nullptr, EvloopRun, (void *)this) != 0) { + MS_LOG(ERROR) << "pthread_create fail"; + Finish(); + return false; + } + // wait EvloopRun + (void)sem_wait(&semId); +#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 12 + std::string name = threadName; + if (name.empty()) { + name = "EventLoopThread"; + } + retval = pthread_setname_np(loopThread, name.c_str()); + if (retval != 0) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "set pthread name fail]%s", + "name:%s,retval:%d", name.c_str(), retval); + } else { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "set pthread name success]%s", + "name:%s,loopThread:%lu", name.c_str(), loopThread); + } +#endif + + return true; +} + +void EvLoop::Finish() { + if (loopThread) { + void *threadResult = nullptr; + StopEventLoop(); + int ret = pthread_join(loopThread, &threadResult); + if (ret != 0) { + MS_LOG(INFO) << "pthread_join loopThread fail"; + } + loopThread = 0; + } + EventLoopDestroy(); + + MS_LOG(INFO) << "stop loop succ"; +} + +EvLoop::~EvLoop() { Finish(); } + +void EvLoop::DeleteEvent(int fd) { + auto iter = events.find(fd); + if (iter == events.end()) { + MS_LOG(DEBUG) << "not found event]fd:" << fd; + return; + } + MS_LOG(DEBUG) << "erase event]fd:%d" << fd; + EventData *eventData = iter->second; + if (eventData != nullptr) { + delete eventData; + } + events.erase(fd); +} + +EventData *EvLoop::FindEvent(int fd) { + auto iter = events.find(fd); + if (iter == events.end()) { + return nullptr; + } + + return iter->second; +} +void EvLoop::AddEvent(EventData *eventData) { + if (!eventData) { + return; + } + DeleteEvent(eventData->fd); + events.emplace(eventData->fd, eventData); +} + +int EvLoop::EventLoopCreate(void) { return BUS_OK; } + +int EvLoop::AddFdEvent(int fd, uint32_t tEvents, EventHandler handler, void *data) { return BUS_OK; } + +int EvLoop::DelFdEvent(int fd) { + EventData *tev = nullptr; + + eventsLock.lock(); + tev = FindEvent(fd); + if (tev == nullptr) { + eventsLock.unlock(); + MS_LOG(DEBUG) << "event search fail]fd:" << fd << ",epollfd:" << efd; + return BUS_ERROR; + } + events.erase(tev->fd); + + // Don't delete tev immediately, let's push it into deletedEvents, before next epoll_wait,we will free + // all events in deletedEvents. + AddDeletedEvents(tev); + + eventsLock.unlock(); + + return BUS_OK; +} + +int EvLoop::ModifyFdEvent(int fd, uint32_t tEvents) { + struct epoll_event ev; + EventData *tev = nullptr; + + tev = FindEvent(fd); + if (tev == nullptr) { + MS_LOG(ERROR) << "event lookup fail]fd:" << fd << ",events:" << tEvents; + return BUS_ERROR; + } + + // 1. dest is valid 2. destsz equals to count and both are valid. + // memset_s will always executes successfully. + (void)memset(&ev, 0, sizeof(ev)); + + ev.events = tEvents; + ev.data.ptr = tev; + + return BUS_OK; +} + +void EvLoop::AddDeletedEvents(EventData *eventData) { + // caller need check eventData is not nullptr + std::list deleteEventList; + + // if fd not found, push eventData into deletedEvents[fd] + std::map>::iterator fdIter = deletedEvents.find(eventData->fd); + if (fdIter == deletedEvents.end()) { + deletedEvents[eventData->fd].push_back(eventData); + return; + } + + // if fd found, check if same eventData ptr exists + deleteEventList = fdIter->second; + std::list::iterator eventIter = deleteEventList.begin(); + bool found = false; + while (eventIter != deleteEventList.end()) { + if (*eventIter == eventData) { + MS_LOG(WARNING) << "fd has been deleted before]fd:" << eventData->fd << ",efd:" << efd; + found = true; + break; + } + ++eventIter; + } + + // if found same eventData ptr, do nothing + if (found) { + return; + } + + deletedEvents[eventData->fd].push_back(eventData); + + return; +} + +void EvLoop::EventFreeDelEvents() { + std::map>::iterator fdIter = deletedEvents.begin(); + while (fdIter != deletedEvents.end()) { + std::list deleteEventList = fdIter->second; + std::list::iterator eventIter = deleteEventList.begin(); + while (eventIter != deleteEventList.end()) { + EventData *deleteEv = *eventIter; + delete deleteEv; + deleteEv = nullptr; + ++eventIter; + } + deletedEvents.erase(fdIter++); + } + deletedEvents.clear(); +} + +int EvLoop::FindDeletedEvent(const EventData *tev) { + std::map>::iterator fdIter = deletedEvents.find(tev->fd); + if (fdIter == deletedEvents.end()) { + return 0; + } + + std::list deleteEventList = fdIter->second; + std::list::iterator eventIter = deleteEventList.begin(); + while (eventIter != deleteEventList.end()) { + if (*eventIter == tev) { + return 1; + } + ++eventIter; + } + return 0; +} + +void EvLoop::HandleEvent(const struct epoll_event *tEvents, int nevent) { + int i; + int found; + EventData *tev = nullptr; + + for (i = 0; i < nevent; i++) { + tev = reinterpret_cast(tEvents[i].data.ptr); + if (tev != nullptr) { + found = FindDeletedEvent(tev); + if (found) { + MS_LOG(WARNING) << "fd has been deleted from epoll]fd:" << tev->fd << ",efd:" << efd; + continue; + } + + tev->handler(tev->fd, tEvents[i].events, tev->data); + } + } +} + +void EvLoop::StopEventLoop() { + if (stopLoop == 1) { + return; + } + + stopLoop = 1; + + uint64_t one = 1; + if (write(queueEventfd, &one, sizeof(one)) != sizeof(one)) { + MS_LOG(WARNING) << "fail to write queueEventfd]fd:" << queueEventfd << ",errno:" << errno; + } + return; +} + +void EvLoop::EventLoopDestroy() { + /* free deleted event handlers */ + EventFreeDelEvents(); + if (efd > 0) { + if (queueEventfd > 0) { + (void)DelFdEvent(queueEventfd); + close(queueEventfd); + queueEventfd = -1; + } + + close(efd); + efd = -1; + } +} + +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/evloop/evloop.h b/mindspore/core/mindrt/src/evloop/evloop.h new file mode 100644 index 0000000000..2b8b06465a --- /dev/null +++ b/mindspore/core/mindrt/src/evloop/evloop.h @@ -0,0 +1,109 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LITEBUS_EVLOOP_H__ +#define __LITEBUS_EVLOOP_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "timer/duration.h" + +namespace mindspore { + +/* + * max epoll set size + */ +constexpr auto EPOLL_SIZE = 4096; + +/* + * epoll event max size + */ +constexpr auto EPOLL_EVENTS_SIZE = 64; + +typedef void (*EventHandler)(int fd, uint32_t events, void *data); + +typedef struct EventData { + EventHandler handler; + void *data; + int fd; + +} EventData; + +class EvLoop { + public: + EvLoop() { + efd = -1; + stopLoop = 0; + queueEventfd = -1; + loopThread = 0; + }; + EvLoop(const EvLoop &) = delete; + EvLoop &operator=(const EvLoop &) = delete; + + bool Init(const std::string &threadName); + + int AddFuncToEvLoop(std::function &&func); + + int AddFdEvent(int fd, uint32_t events, EventHandler handler, void *data); + int ModifyFdEvent(int fd, uint32_t events); + int DelFdEvent(int fd); + void Finish(); + + ~EvLoop(); + + int EventLoopCreate(void); + void StopEventLoop(); + + void EventLoopDestroy(); + + void EventFreeDelEvents(); + void AddDeletedEvents(EventData *eventData); + int FindDeletedEvent(const EventData *tev); + + void HandleEvent(const struct epoll_event *events, int nevent); + + void DeleteEvent(int fd); + EventData *FindEvent(int fd); + void AddEvent(EventData *eventData); + void CleanUp(); + + int efd; + int stopLoop; + std::mutex loopMutex; + sem_t semId; + pthread_t loopThread; + int queueEventfd; + std::mutex queueMutex; + std::queue> queue; + + std::mutex eventsLock; + // fd,EventData + std::map events; + + // Just to be safe, let's use a list to preserve deleted events rather than a map. Because the caller may + // delete events on the same fd twice in once epoll_wait + std::map> deletedEvents; +}; + +} // namespace mindspore + +#endif diff --git a/mindspore/core/mindrt/src/litebus.cc b/mindspore/core/mindrt/src/litebus.cc new file mode 100644 index 0000000000..280489e8ee --- /dev/null +++ b/mindspore/core/mindrt/src/litebus.cc @@ -0,0 +1,232 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "mindrt/src/actor/sysmgr_actor.h" +#include "mindrt/src/actor/actormgr.h" +#include "mindrt/src/actor/iomgr.h" + +//#include "utils/os_utils.hpp" + +#include "litebus.hpp" +#include "timer/timertools.h" +#include "litebus.h" + +extern "C" { +int LitebusInitializeC(const struct LitebusConfig *config) { + if (config == nullptr) { + return -1; + } + + if (config->threadCount == 0) { + return -1; + } + + if (config->httpKmsgFlag != 0 && config->httpKmsgFlag != 1) { + return -1; + } + mindspore::SetHttpKmsgFlag(config->httpKmsgFlag); + + return mindspore::Initialize(std::string(config->tcpUrl), std::string(config->tcpUrlAdv), std::string(config->udpUrl), + std::string(config->udpUrlAdv), config->threadCount); +} + +void LitebusFinalizeC() { mindspore::Finalize(); } +} + +constexpr auto LITEBUSTHREADMIN = 3; +constexpr auto LITEBUSTHREADMAX = 100; +constexpr auto LITEBUSTHREADS = 10; + +constexpr auto SYSMGR_TIMER_DURATION = 600000; + +namespace mindspore { + +namespace local { + +static LitebusAddress *g_litebusAddress = new (std::nothrow) LitebusAddress(); +static std::atomic_bool g_finalizeLitebusStatus(false); + +} // namespace local + +const LitebusAddress &GetLitebusAddress() { + BUS_OOM_EXIT(local::g_litebusAddress); + return *local::g_litebusAddress; +} + +bool SetServerIo(std::shared_ptr &io, std::string &advertiseUrl, const std::string &protocol, + const std::string &url) { +#if 0 + if (protocol == "tcp") { + size_t index = advertiseUrl.find("://"); + if (index != std::string::npos) { + advertiseUrl = advertiseUrl.substr(index + URL_PROTOCOL_IP_SEPARATOR.size()); + } + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "create tcp iomgr. (%s)", + "Url=%s,advertiseUrl=%s", url.c_str(), advertiseUrl.c_str()); + if (local::g_litebusAddress == nullptr) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, + "Couldn't allocate memory for LitebusAddress"); + return false; + } + local::g_litebusAddress->scheme = protocol; + local::g_litebusAddress->ip = AID("test@" + advertiseUrl).GetIp(); + local::g_litebusAddress->port = AID("test@" + advertiseUrl).GetPort(); + +#ifdef HTTP_ENABLED + mindspore::HttpIOMgr::EnableHttp(); +#endif + io.reset(new (std::nothrow) mindspore::TCPMgr()); + if (io == nullptr) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, + "Couldn't allocate memory for TCPMgr"); + return false; + } + } +#ifdef UDP_ENABLED + else if (protocol == "udp") { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "create udp iomgr. (%s)", + "Url=%s,advertiseUrl=%s", url.c_str(), advertiseUrl.c_str()); + + io.reset(new (std::nothrow) mindspore::UDPMgr()); + if (io == nullptr) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, + "Couldn't allocate memory for UDPMgr"); + return false; + } + } +#endif + else { + + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "unsupported protocol. (%s)", + "%s", protocol.c_str()); + return false; + } +#endif + return true; +} + +void SetThreadCount(int threadCount) { + int tmpThreadCount = LITEBUSTHREADS; + ActorMgr::GetActorMgrRef()->Initialize(tmpThreadCount); +} + +class LiteBusExit { + public: + LiteBusExit() { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "trace: enter LiteBusExit()---------"); + } + ~LiteBusExit() { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "trace: enter ~LiteBusExit()---------"); + mindspore::Finalize(); + } +}; + +int InitializeImp(const std::string &tcpUrl, const std::string &tcpUrlAdv, const std::string &udpUrl, + const std::string &udpUrlAdv, int threadCount) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "litebus starts ......"); + signal(SIGPIPE, SIG_IGN); + + if (!TimerTools::Initialize()) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "Failed to initialize timer tools"); + return BUS_ERROR; + } + + // start actor's thread + SetThreadCount(threadCount); + + mindspore::Spawn(std::make_shared(SYSMGR_ACTOR_NAME, SYSMGR_TIMER_DURATION)); + + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "litebus has started."); + return BUS_OK; +} + +int Initialize(const std::string &tcpUrl, const std::string &tcpUrlAdv, const std::string &udpUrl, + const std::string &udpUrlAdv, int threadCount) { + static std::atomic_bool initLitebusStatus(false); + bool inite = false; + if (initLitebusStatus.compare_exchange_strong(inite, true) == false) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "litebus has been initialized"); + return BUS_OK; + } + + int result = BUS_OK; + result = InitializeImp(tcpUrl, tcpUrlAdv, udpUrl, udpUrlAdv, threadCount); + static LiteBusExit busExit; + + return result; +} + +AID Spawn(ActorReference actor, bool sharedThread, bool start) { + if (actor == nullptr) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "Actor is nullptr."); + BUS_EXIT("Actor is nullptr."); + } + + if (local::g_finalizeLitebusStatus.load() == true) { + return actor->GetAID(); + } else { + return ActorMgr::GetActorMgrRef()->Spawn(actor, sharedThread, start); + } +} +void SetActorStatus(const AID &actor, bool start) { ActorMgr::GetActorMgrRef()->SetActorStatus(actor, start); } + +void Await(const ActorReference &actor) { ActorMgr::GetActorMgrRef()->Wait(actor->GetAID()); } + +void Await(const AID &actor) { ActorMgr::GetActorMgrRef()->Wait(actor); } + +// brief get actor with aid +ActorReference GetActor(const AID &actor) { return ActorMgr::GetActorMgrRef()->GetActor(actor); } + +void Terminate(const AID &actor) { ActorMgr::GetActorMgrRef()->Terminate(actor); } + +void TerminateAll() { mindspore::ActorMgr::GetActorMgrRef()->TerminateAll(); } + +void Finalize() { + bool inite = false; + if (local::g_finalizeLitebusStatus.compare_exchange_strong(inite, true) == false) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "litebus has been Finalized."); + return; + } + + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "litebus starts to finalize."); + mindspore::ActorMgr::GetActorMgrRef()->Finalize(); + TimerTools::Finalize(); + + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "litebus has been finalized."); + // flush the log in cache to disk before exiting. + FlushHLogCache(); +} + +void SetDelegate(const std::string &delegate) { mindspore::ActorMgr::GetActorMgrRef()->SetDelegate(delegate); } + +static HARES_LOG_PID g_busLogPid = 1; +void SetLogPID(HARES_LOG_PID pid) { + ICTSBASE_LOG1(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, pid, "Set LiteBus log PID: %u", pid); + g_busLogPid = pid; +} +HARES_LOG_PID GetLogPID() { return g_busLogPid; } + +static int g_httpKmsgEnable = -1; +void SetHttpKmsgFlag(int flag) { + ICTSBASE_LOG1(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "Set LiteBus http message format:%d", flag); + g_httpKmsgEnable = flag; +} + +int GetHttpKmsgFlag() { return g_httpKmsgEnable; } + +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/timer/CMakeLists.txt b/mindspore/core/mindrt/src/timer/CMakeLists.txt new file mode 100644 index 0000000000..1489d44e0f --- /dev/null +++ b/mindspore/core/mindrt/src/timer/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(litebus_obj PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/timer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/timertools.cc + ${CMAKE_CURRENT_SOURCE_DIR}/timewatch.cc +) \ No newline at end of file diff --git a/mindspore/core/mindrt/src/timer/timer.cc b/mindspore/core/mindrt/src/timer/timer.cc new file mode 100644 index 0000000000..c61d482f49 --- /dev/null +++ b/mindspore/core/mindrt/src/timer/timer.cc @@ -0,0 +1,38 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "timer/timer.h" + +namespace mindspore { + +Timer::Timer() : id(0), t(TimeWatch()), aid(AID()), thunk(&abort) {} + +Timer::~Timer() {} + +bool Timer::operator==(const Timer &that) const { return id == that.id; } + +void Timer::operator()() const { thunk(); } + +TimeWatch Timer::GetTimeWatch() const { return t; } + +AID Timer::GetTimerAID() const { return aid; } + +uint64_t Timer::GetTimerID() const { return id; } + +Timer::Timer(uint64_t timerId, const TimeWatch &timeWatch, const AID &timeAid, const std::function &handler) + : id(timerId), t(timeWatch), aid(timeAid), thunk(handler) {} + +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/timer/timertools.cc b/mindspore/core/mindrt/src/timer/timertools.cc new file mode 100644 index 0000000000..8bdacbc9ea --- /dev/null +++ b/mindspore/core/mindrt/src/timer/timertools.cc @@ -0,0 +1,347 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "timer/timertools.h" +#include +#include +#include +#include +#include "evloop/evloop.h" + +namespace mindspore { +using TimerPoolType = std::map>; +static std::unique_ptr g_timerPool; +static std::unique_ptr g_timerEvLoop; +static Duration g_ticks(0); +static int g_runTimerFD(-1); +static int g_watchTimerFD(-1); +static SpinLock g_timersLock; +std::atomic_bool TimerTools::g_initStatus(false); +constexpr Duration SCAN_TIMERPOOL_DELAY = 30; +constexpr Duration WATCH_INTERVAL = 20; +constexpr unsigned int TIMER_LOG_INTERVAL = 6; +const static std::string TIMER_EVLOOP_THREADNAME = "HARES_LB_TMer"; + +namespace timer { +void ScanTimerPool(int fd, uint32_t events, void *data); +Duration NextTick(const std::map> &timerPool) { + if (!timerPool.empty()) { + Duration first = timerPool.begin()->first; + return first; + } + return 0; +} + +void ExecTimers(const std::list &timers) { + for (const auto &timer : timers) { + timer(); + } +} + +void CreateTimerToLoop(const Duration &delay, const Duration &nextTick) { + if (g_runTimerFD == -1) { + g_runTimerFD = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if (g_runTimerFD >= 0) { + int retval = g_timerEvLoop->AddFdEvent(g_runTimerFD, EPOLLIN, ScanTimerPool, nullptr); + if (retval != BUS_OK) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "add run timer event fail]%s", + "ID:%d", g_runTimerFD); + close(g_runTimerFD); + g_runTimerFD = -1; + return; + } + } else { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "create run timer fd fail]%s", + "ID:%d", g_runTimerFD); + g_runTimerFD = -1; + return; + } + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "create run timer fd success]%s", + "ID:%d", g_runTimerFD); + } + + struct itimerspec it; + it.it_interval.tv_sec = 0; + it.it_interval.tv_nsec = 0; + it.it_value.tv_sec = delay / SECTOMILLI; + it.it_value.tv_nsec = (delay % SECTOMILLI) * MILLITOMICR * MICRTONANO; + if (timerfd_settime(g_runTimerFD, 0, &it, nullptr) == -1) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "start run timer fail]%s", "ID:%d", + g_runTimerFD); + close(g_runTimerFD); + g_runTimerFD = -1; + return; + } +} + +void ScheduleTick(const std::map> &timerPool) { + Duration nextTick = NextTick(timerPool); + + if (nextTick != 0) { + // 'tick' scheduled for an earlier time, not schedule current 'tick' + if ((g_ticks == 0) || (nextTick < g_ticks)) { + Duration nowTime = TimeWatch::Now(); + Duration delay = 0; + + if (nextTick > nowTime) { + delay = nextTick - nowTime; + g_ticks = nextTick; + CreateTimerToLoop(delay, nextTick); + } else { + delay = SCAN_TIMERPOOL_DELAY; + g_ticks = delay + nowTime; + CreateTimerToLoop(delay, nextTick); + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_DEBUG, PID_LITEBUS_LOG, + "run timer immediately {nextTick, now time}= %s ", "{%" PRIu64 ", %" PRIu64 "}", nextTick, + nowTime); + } + } + } +} + +// select timeout timers +void ScanTimerPool(int fd, uint32_t events, void *data) { + std::list outTimer; + uint64_t count; + + if ((g_runTimerFD != fd) || !(events & EPOLLIN)) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, + "run timer fd or events err {g_runTimerFD, fd, events}= %s ", "{%d, %d, %u}", g_runTimerFD, fd, + events); + return; + } + + if (read(fd, &count, sizeof(uint64_t)) < 0) { + return; + } + g_timersLock.Lock(); + Duration now = TimeWatch::Now(); + auto it = g_timerPool->begin(); + while (it != g_timerPool->end()) { + if (it->first > now) { + break; + } + outTimer.splice(outTimer.end(), (*g_timerPool)[it->first]); + ++it; + } + // delete timed out timer + (void)g_timerPool->erase(g_timerPool->begin(), g_timerPool->upper_bound(now)); + g_ticks = 0; + ScheduleTick(*g_timerPool); + g_timersLock.Unlock(); + + ExecTimers(outTimer); + outTimer.clear(); +} + +void CheckPassedTimer(int fd, uint32_t events, void *data) { + std::list passTimer; + static unsigned long watchTimes = 0; + uint64_t count; + + if ((g_watchTimerFD != fd) || !(events & EPOLLIN)) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, + "check timer fd or events err {g_watchTimerFD, fd, events}= %s ", "{%d, %d, %u}", + g_watchTimerFD, fd, events); + return; + } + if (read(fd, &count, sizeof(uint64_t)) < 0) { + return; + } + g_timersLock.Lock(); + Duration now = TimeWatch::Now(); + ++watchTimes; + + for (auto it = g_timerPool->begin(); it != g_timerPool->end(); ++it) { + if (it->first > now) { + break; + } + passTimer.splice(passTimer.end(), (*g_timerPool)[it->first]); + } + // delete passed timer + if (passTimer.size() > 0) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_DEBUG, PID_LITEBUS_LOG, + "fire pass timer {pass size, now, g_ticks}= %s ", "{%zd, %" PRIu64 ", %" PRIu64 "}", + passTimer.size(), now, g_ticks); + } + (void)g_timerPool->erase(g_timerPool->begin(), g_timerPool->upper_bound(now)); + if (g_ticks <= now) { + g_ticks = 0; + } + + if (g_timerPool->size() > 0) { + if ((watchTimes % TIMER_LOG_INTERVAL == 0) && (passTimer.size() > 0) && + (now - g_timerPool->begin()->first > SECTOMILLI)) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, + "timer info {pool size, pass size, now, g_ticks, poolTick, watchTimes}= %s ", + "{%zd, %zd, %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %lu}", g_timerPool->size(), + passTimer.size(), now, g_ticks, g_timerPool->begin()->first, watchTimes); + } + } + + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_DEBUG, PID_LITEBUS_LOG, + "timer info {pool size, pass size, now, g_ticks, poolTick, watchTimes}= %s ", + "{%zd, %zd, %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %lu}", g_timerPool->size(), passTimer.size(), + now, g_ticks, g_timerPool->begin()->first, watchTimes); + + ScheduleTick(*g_timerPool); + g_timersLock.Unlock(); + + ExecTimers(passTimer); + passTimer.clear(); +} + +bool StartWatchTimer() { + // create watch timer + g_watchTimerFD = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if (g_watchTimerFD >= 0) { + int retval = g_timerEvLoop->AddFdEvent(g_watchTimerFD, EPOLLIN, CheckPassedTimer, nullptr); + if (retval != BUS_OK) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "add watch timer event fail]%s", + "ID:%d", g_watchTimerFD); + close(g_watchTimerFD); + g_watchTimerFD = -1; + return false; + } + } else { + g_watchTimerFD = -1; + return false; + } + + // start watch timer + struct itimerspec it; + it.it_interval.tv_sec = WATCH_INTERVAL; + it.it_interval.tv_nsec = 0; + it.it_value.tv_sec = WATCH_INTERVAL; + it.it_value.tv_nsec = 0; + if (timerfd_settime(g_watchTimerFD, 0, &it, nullptr) == -1) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "start watch timer fail]%s", + "ID:%d", g_watchTimerFD); + close(g_watchTimerFD); + g_watchTimerFD = -1; + return false; + } + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, + "start watch timer success, {id}= %s ", "{%d}", g_watchTimerFD); + return true; +} +} // namespace timer + +bool TimerTools::Initialize() { + bool ret = true; + g_timersLock.Lock(); + + g_timerPool.reset(new (std::nothrow) TimerPoolType()); + if (g_timerPool == nullptr) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "timer pool new failed."); + g_timersLock.Unlock(); + return false; + } + + g_timerEvLoop.reset(new (std::nothrow) EvLoop()); + if (g_timerEvLoop == nullptr) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "ev new failed."); + g_timersLock.Unlock(); + return false; + } + bool ok = g_timerEvLoop->Init(TIMER_EVLOOP_THREADNAME); + if (!ok) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, "ev init failed."); + g_timerEvLoop = nullptr; + g_timersLock.Unlock(); + return false; + } + ret = timer::StartWatchTimer(); + g_timersLock.Unlock(); + g_initStatus.store(true); + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "Timer init succ."); + return ret; +} + +void TimerTools::Finalize() { + if (g_initStatus.load() == false) { + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "no need for Timer Finalize."); + return; + } + g_initStatus.store(false); + + ICTSBASE_LOG0(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "Timer Finalize."); + g_timersLock.Lock(); + if (g_runTimerFD >= 0) { + close(g_runTimerFD); + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "run timer close {ID}=%s", "{%d}", + g_runTimerFD); + g_runTimerFD = -1; + } + if (g_watchTimerFD >= 0) { + close(g_watchTimerFD); + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_INFO, PID_LITEBUS_LOG, "watch timer close {ID}=%s", "{%d}", + g_watchTimerFD); + g_watchTimerFD = -1; + } + g_timersLock.Unlock(); +} + +Timer TimerTools::AddTimer(const Duration &duration, const AID &aid, const std::function &thunk) { + if (g_initStatus.load() == false) { + return Timer(); + } + if (duration == 0) { + thunk(); + return Timer(); + } + static std::atomic id(1); + TimeWatch timeWatch = TimeWatch::In(duration); + Timer timer(id.fetch_add(1), timeWatch, aid, thunk); + + // Add the timer to timerpoll and Schedule it + g_timersLock.Lock(); + + if (g_timerPool->size() == 0 || timer.GetTimeWatch().Time() < g_timerPool->begin()->first) { + (*g_timerPool)[timer.GetTimeWatch().Time()].push_back(timer); + timer::ScheduleTick(*g_timerPool); + } else { + if (!(g_timerPool->size() >= 1)) { + ICTSBASE_LOG_STRING(ICTSBASE_LOG_COMMON_CODE, HLOG_LEVEL_ERROR, PID_LITEBUS_LOG, + "g_timerPool size invalid {size}=%s", "{%zd}", g_timerPool->size()); + } + (*g_timerPool)[timer.GetTimeWatch().Time()].push_back(timer); + } + g_timersLock.Unlock(); + + return timer; +} + +bool TimerTools::Cancel(const Timer &timer) { + if (g_initStatus.load() == false) { + return false; + } + + bool canceled = false; + g_timersLock.Lock(); + Duration duration = timer.GetTimeWatch().Time(); + if (g_timerPool->count(duration) > 0) { + canceled = true; + (*g_timerPool)[duration].remove(timer); + if ((*g_timerPool)[duration].empty()) { + (void)(g_timerPool->erase(duration)); + } + } + g_timersLock.Unlock(); + + return canceled; +} +} // namespace mindspore diff --git a/mindspore/core/mindrt/src/timer/timewatch.cc b/mindspore/core/mindrt/src/timer/timewatch.cc new file mode 100644 index 0000000000..5f8c12f6eb --- /dev/null +++ b/mindspore/core/mindrt/src/timer/timewatch.cc @@ -0,0 +1,66 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "timer/timewatch.h" + +namespace mindspore { + +TimeWatch::TimeWatch() : duration(Now()) {} + +TimeWatch::TimeWatch(const Duration &d) : duration(d) {} + +TimeWatch::TimeWatch(const TimeWatch &that) : duration(that.duration) {} + +TimeWatch::~TimeWatch() {} + +Duration TimeWatch::Now() { + struct timespec ts = {0, 0}; + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + Duration duration = ts.tv_sec * SECTOMILLI + (ts.tv_nsec / MICRTONANO) / MILLITOMICR; + return duration; +} + +TimeWatch TimeWatch::In(const Duration &duration) { return TimeWatch(Now() + duration); } + +TimeWatch &TimeWatch::operator=(const TimeWatch &that) { + if (&that != this) { + duration = that.duration; + } + + return *this; +} + +TimeWatch &TimeWatch::operator=(const Duration &d) { + duration = Now() + d; + return *this; +} + +bool TimeWatch::operator==(const TimeWatch &that) const { return duration == that.duration; } + +bool TimeWatch::operator<(const TimeWatch &that) const { return duration < that.duration; } + +bool TimeWatch::operator<=(const TimeWatch &that) const { return duration <= that.duration; } + +Duration TimeWatch::Time() const { return duration; } + +Duration TimeWatch::Remaining() const { + Duration nowTime = Now(); + return duration > nowTime ? (duration - nowTime) : 0; +} + +bool TimeWatch::Expired() const { return duration <= Now(); } + +} // namespace mindspore