| @@ -2,6 +2,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) | |||||
| include_directories(${CMAKE_BINARY_DIR}) | include_directories(${CMAKE_BINARY_DIR}) | ||||
| include_directories(${CMAKE_SOURCE_DIR}/mindspore/core) | include_directories(${CMAKE_SOURCE_DIR}/mindspore/core) | ||||
| add_subdirectory(gvar) | add_subdirectory(gvar) | ||||
| if(NOT(CMAKE_SYSTEM_NAME MATCHES "Windows")) | |||||
| add_subdirectory(mindrt) | |||||
| endif() | |||||
| message("************ build core ***************") | message("************ build core ***************") | ||||
| @@ -18,7 +21,8 @@ if(CMAKE_SYSTEM_NAME MATCHES "Windows") | |||||
| set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -DHAVE_SNPRINTF") | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes -DHAVE_SNPRINTF") | ||||
| add_compile_definitions(BUILDING_DLL) | add_compile_definitions(BUILDING_DLL) | ||||
| elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") | 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() | endif() | ||||
| set_property(SOURCE ${CORE_SRC_LIST} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_CORE) | set_property(SOURCE ${CORE_SRC_LIST} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_CORE) | ||||
| @@ -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}) | |||||
| @@ -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 <functional> | |||||
| #include <map> | |||||
| #include <memory> | |||||
| #include <mutex> | |||||
| #include <string> | |||||
| #include <utility> | |||||
| #include "actor/msg.h" | |||||
| namespace mindspore { | |||||
| class ActorBase; | |||||
| class ActorMgr; | |||||
| class ActorPolicy; | |||||
| using ActorReference = std::shared_ptr<ActorBase>; | |||||
| // 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<MessageBase> 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<void(std::unique_ptr<MessageBase> &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<MessageBase> 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<MessageBase> 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<MessageBase> &msg) { return false; } | |||||
| // register the message handle | |||||
| void Receive(const std::string &msgName, ActorFunction &&func); | |||||
| // register the message handle. It will be discarded. | |||||
| template <typename T> | |||||
| void Receive(const std::string &msgName, void (T::*method)(mindspore::AID, std::string &&, std::string &&)) { | |||||
| ActorFunction func = std::bind(&BehaviorBase1<T>, static_cast<T *>(this), method, std::placeholders::_1); | |||||
| Receive(msgName, std::move(func)); | |||||
| } | |||||
| // register the message handle | |||||
| template <typename T> | |||||
| void Receive(const std::string &msgName, void (T::*method)(const mindspore::AID &, std::string &&, std::string &&)) { | |||||
| ActorFunction func = std::bind(&BehaviorBase<T>, static_cast<T *>(this), method, std::placeholders::_1); | |||||
| Receive(msgName, std::move(func)); | |||||
| return; | |||||
| } | |||||
| // register the message handle, for kmsg-udp message | |||||
| template <typename T> | |||||
| void ReceiveUdp(const std::string &msgName, | |||||
| void (T::*method)(const mindspore::AID &, std::string &&, std::string &&)) { | |||||
| ActorFunction func = std::bind(&BehaviorBaseForUdp<T>, static_cast<T *>(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<MessageBase> &msg); | |||||
| template <typename T> | |||||
| static void BehaviorBase(T *t, void (T::*method)(const mindspore::AID &, std::string &&, std::string &&), | |||||
| std::unique_ptr<MessageBase> &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 <typename T> | |||||
| static void BehaviorBase1(T *t, void (T::*method)(mindspore::AID, std::string &&, std::string &&), | |||||
| std::unique_ptr<MessageBase> &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 <typename T> | |||||
| static void BehaviorBaseForUdp(T *t, void (T::*method)(const mindspore::AID &, std::string &&, std::string &&), | |||||
| std::unique_ptr<MessageBase> &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<MessageBase> msg); | |||||
| void Spawn(std::shared_ptr<ActorBase> &actor, std::unique_ptr<ActorPolicy> actorThread); | |||||
| void SetRunningStatus(bool start); | |||||
| std::unique_ptr<ActorPolicy> actorThread; | |||||
| AID id; | |||||
| std::map<std::string, ActorFunction> actionFunctions; | |||||
| std::mutex waiterLock; | |||||
| std::string msgRecords[MAX_ACTOR_RECORD_SIZE]; | |||||
| uint32_t recordNextPoint = 0; | |||||
| }; | |||||
| }; // namespace mindspore | |||||
| #endif | |||||
| @@ -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<void(std::unique_ptr<MessageBase>)> APPBehavior; | |||||
| AppActor(const std::string &name) : ActorBase(name) {} | |||||
| ~AppActor() {} | |||||
| inline int Send(const AID &to, std::unique_ptr<MessageBase> msg) { return ActorBase::Send(to, std::move(msg)); } | |||||
| // send T message to the actor | |||||
| template <typename M> | |||||
| int Send(const std::string &to, const std::string &msgName, std::unique_ptr<M> msg) { | |||||
| std::unique_ptr<MessageLocal> 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 <typename T, typename M> | |||||
| void Receive(const std::string &msgName, void (T::*method)(const AID &, std::unique_ptr<M>)) { | |||||
| APPBehavior behavior = std::bind(&BehaviorBase<T, M>, static_cast<T *>(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 <typename T, typename M> | |||||
| static void BehaviorBase(T *t, void (T::*method)(const AID &, std::unique_ptr<M>), std::unique_ptr<MessageBase> msg) { | |||||
| (t->*method)(msg->From(), std::move(std::unique_ptr<M>((M *)static_cast<MessageLocal *>(msg.get())->ptr))); | |||||
| return; | |||||
| } | |||||
| protected: | |||||
| // KLOCALMsg handler | |||||
| virtual void HandleLocalMsg(std::unique_ptr<MessageBase> 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<std::string, APPBehavior> appBehaviors; | |||||
| }; | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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 <string> | |||||
| #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<mindspore::AID> { | |||||
| typedef mindspore::AID argument_type; | |||||
| typedef std::size_t result_type; | |||||
| result_type operator()(argument_type const &s) const noexcept { return (std::hash<std::string>{}(s.HashString())); } | |||||
| }; | |||||
| } // namespace std | |||||
| #endif | |||||
| @@ -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 | |||||
| @@ -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 <signal.h> | |||||
| #include <iostream> | |||||
| #include <sstream> | |||||
| #include <string> | |||||
| #include <string.h> | |||||
| #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 | |||||
| @@ -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__ | |||||
| @@ -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 <memory> | |||||
| namespace mindspore { | |||||
| class Naught; | |||||
| class ActorBase; | |||||
| typedef std::shared_ptr<Naught> UniqueNaught; | |||||
| typedef std::shared_ptr<Naught> SharedNaught; | |||||
| typedef std::string BusString; | |||||
| // Lite , start from Naught | |||||
| class Naught { | |||||
| public: | |||||
| virtual ~Naught() {} | |||||
| }; | |||||
| }; // namespace mindspore | |||||
| #endif | |||||
| @@ -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 <typename T, T... Ints> | |||||
| struct IntegerSequenceBase { | |||||
| static constexpr std::size_t Size() noexcept { return sizeof...(Ints); } | |||||
| }; | |||||
| namespace internal { | |||||
| template <typename T, std::size_t N, std::size_t... Ints> | |||||
| struct IntegerSequence : public IntegerSequence<T, N - 1, N - 1, Ints...> {}; | |||||
| template <typename T, std::size_t... Ints> | |||||
| struct IntegerSequence<T, 0, Ints...> { | |||||
| using type = IntegerSequenceBase<T, Ints...>; | |||||
| }; | |||||
| } // namespace internal | |||||
| template <typename T, std::size_t N> | |||||
| using make_integer_sequence = typename internal::IntegerSequence<T, N>::type; | |||||
| template <std::size_t... Ints> | |||||
| using index_sequence = IntegerSequenceBase<std::size_t, Ints...>; | |||||
| template <std::size_t N> | |||||
| using make_index_sequence = make_integer_sequence<std::size_t, N>; | |||||
| template <class... T> | |||||
| using index_sequence_for = make_index_sequence<sizeof...(T)>; | |||||
| template <typename Func, typename Tuple, std::size_t... Ints> | |||||
| auto ApplyHelper(Func &&func, Tuple &&tuple, index_sequence<Ints...>) | |||||
| -> decltype(func(std::get<Ints>(std::forward<Tuple>(tuple))...)) { | |||||
| return func(std::get<Ints>(std::forward<Tuple>(tuple))...); | |||||
| } | |||||
| template <typename T, typename Func, typename Tuple, std::size_t... Ints> | |||||
| auto ApplyHelper(T *ptr, Func &&func, Tuple &&tuple, index_sequence<Ints...>) | |||||
| -> decltype((ptr->*func)(std::get<Ints>(std::forward<Tuple>(tuple))...)) { | |||||
| return (ptr->*func)(std::get<Ints>(std::forward<Tuple>(tuple))...); | |||||
| } | |||||
| template <typename Func, typename Tuple> | |||||
| auto Apply(Func &&func, Tuple &&tuple) | |||||
| -> decltype(ApplyHelper(std::forward<Func>(func), std::forward<Tuple>(tuple), | |||||
| make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{})) { | |||||
| return ApplyHelper(std::forward<Func>(func), std::forward<Tuple>(tuple), | |||||
| make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{}); | |||||
| } | |||||
| template <typename T, typename Func, typename Tuple> | |||||
| auto Apply(T *ptr, Func &&func, Tuple &&tuple) | |||||
| -> decltype(ApplyHelper(ptr, std::forward<Func>(func), std::forward<Tuple>(tuple), | |||||
| make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{})) { | |||||
| return ApplyHelper(ptr, std::forward<Func>(func), std::forward<Tuple>(tuple), | |||||
| make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{}); | |||||
| } | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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(ActorBase *)>; | |||||
| void Async(const AID &aid, std::unique_ptr<MessageHandler> handler); | |||||
| namespace internal { | |||||
| template <typename R> | |||||
| struct AsyncHelper; | |||||
| // for defer | |||||
| template <> | |||||
| struct AsyncHelper<void> { | |||||
| template <typename F> | |||||
| void operator()(const AID &aid, F &&f) { | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([=](ActorBase *) { f(); })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| } | |||||
| }; | |||||
| template <typename R> | |||||
| struct AsyncHelper<Future<R>> { | |||||
| template <typename F> | |||||
| Future<R> operator()(const AID &aid, F &&f) { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([=](ActorBase *) { promise->Associate(f()); })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| }; | |||||
| template <typename R> | |||||
| struct AsyncHelper { | |||||
| template <typename F> | |||||
| Future<R> operator()(const AID &aid, F &&f) { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([=](ActorBase *) { promise->SetValue(f()); })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| }; | |||||
| } // namespace internal | |||||
| // return void | |||||
| template <typename T> | |||||
| void Async(const AID &aid, void (T::*method)()) { | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([method](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| (t->*method)(); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| } | |||||
| template <typename T, typename Arg0, typename Arg1> | |||||
| void Async(const AID &aid, void (T::*method)(Arg0), Arg1 &&arg) { | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([method, arg](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| (t->*method)(arg); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| } | |||||
| template <typename T, typename... Args0, typename... Args1> | |||||
| void Async(const AID &aid, void (T::*method)(Args0...), std::tuple<Args1...> &&tuple) { | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([method, tuple](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| Apply(t, method, tuple); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| } | |||||
| template <typename T, typename... Args0, typename... Args1> | |||||
| void Async(const AID &aid, void (T::*method)(Args0...), Args1 &&... args) { | |||||
| auto tuple = std::make_tuple(std::forward<Args1>(args)...); | |||||
| Async(aid, method, std::move(tuple)); | |||||
| } | |||||
| // return future | |||||
| template <typename R, typename T> | |||||
| Future<R> Async(const AID &aid, Future<R> (T::*method)()) { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([promise, method](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| promise->Associate((t->*method)()); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| template <typename R, typename T, typename Arg0, typename Arg1> | |||||
| Future<R> Async(const AID &aid, Future<R> (T::*method)(Arg0), Arg1 &&arg) { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([promise, method, arg](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| promise->Associate((t->*method)(arg)); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| template <typename R, typename T, typename... Args0, typename... Args1> | |||||
| Future<R> Async(const AID &aid, Future<R> (T::*method)(Args0...), std::tuple<Args1...> &&tuple) { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([promise, method, tuple](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| promise->Associate(Apply(t, method, tuple)); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| template <typename R, typename T, typename... Args0, typename... Args1> | |||||
| Future<R> Async(const AID &aid, Future<R> (T::*method)(Args0...), Args1 &&... args) { | |||||
| auto tuple = std::make_tuple(std::forward<Args1>(args)...); | |||||
| return Async(aid, method, std::move(tuple)); | |||||
| } | |||||
| // return R | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, | |||||
| typename std::enable_if<!internal::IsFuture<R>::value, int>::type = 0, typename T> | |||||
| Future<R> Async(const AID &aid, R (T::*method)()) { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([promise, method](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| promise->SetValue((t->*method)()); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, | |||||
| typename std::enable_if<!internal::IsFuture<R>::value, int>::type = 0, typename T, typename Arg0, | |||||
| typename Arg1> | |||||
| Future<R> Async(const AID &aid, R (T::*method)(Arg0), Arg1 &&arg) { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([promise, method, arg](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| promise->SetValue((t->*method)(arg)); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, | |||||
| typename std::enable_if<!internal::IsFuture<R>::value, int>::type = 0, typename T, typename... Args0, | |||||
| typename... Args1> | |||||
| Future<R> Async(const AID &aid, R (T::*method)(Args0...), std::tuple<Args1...> &&tuple) { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::unique_ptr<std::function<void(ActorBase *)>> handler( | |||||
| new (std::nothrow) std::function<void(ActorBase *)>([promise, method, tuple](ActorBase *actor) { | |||||
| BUS_ASSERT(actor != nullptr); | |||||
| T *t = static_cast<T *>(actor); | |||||
| BUS_ASSERT(t != nullptr); | |||||
| promise->SetValue(Apply(t, method, tuple)); | |||||
| })); | |||||
| BUS_OOM_EXIT(handler); | |||||
| Async(aid, std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, | |||||
| typename std::enable_if<!internal::IsFuture<R>::value, int>::type = 0, typename T, typename... Args0, | |||||
| typename... Args1> | |||||
| Future<R> Async(const AID &aid, R (T::*method)(Args0...), Args1 &&... args) { | |||||
| auto tuple = std::make_tuple(std::forward<Args1>(args)...); | |||||
| return Async(aid, method, std::move(tuple)); | |||||
| } | |||||
| template <typename F, typename R = typename std::result_of<F()>::type> | |||||
| auto Async(const AID &aid, F &&f) -> decltype(internal::AsyncHelper<R>()(aid, std::forward<F>(f))) { | |||||
| return internal::AsyncHelper<R>()(aid, std::forward<F>(f)); | |||||
| } | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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 <typename T> | |||||
| Timer AsyncAfter(const Duration &duration, const AID &aid, void (T::*method)()) { | |||||
| return TimerTools::AddTimer(duration, aid, [=]() { Async(aid, method); }); | |||||
| } | |||||
| template <typename T, typename Arg0, typename Arg1> | |||||
| Timer AsyncAfter(const Duration &duration, const AID &aid, void (T::*method)(Arg0), Arg1 &&arg) { | |||||
| return TimerTools::AddTimer(duration, aid, [=]() { Async(aid, method, arg); }); | |||||
| } | |||||
| template <typename T, typename... Args0, typename... Args1> | |||||
| Timer AsyncAfter(const Duration &duration, const AID &aid, void (T::*method)(Args0...), Args1 &&... args) { | |||||
| std::function<void(Args0...)> 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 | |||||
| @@ -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 <future> | |||||
| #include <iostream> | |||||
| #include <list> | |||||
| #include "async/common.h" | |||||
| #include "async/future.h" | |||||
| #include "async/spinlock.h" | |||||
| #include "actor/actor.h" | |||||
| #include "litebus.hpp" | |||||
| namespace mindspore { | |||||
| template <typename T> | |||||
| class Future; | |||||
| template <typename T> | |||||
| class Promise; | |||||
| template <typename T> | |||||
| class Collected; | |||||
| template <typename T> | |||||
| class Collected { | |||||
| public: | |||||
| Collected(const std::list<Future<T>> &f, Promise<std::list<T>> *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<T> &future) { | |||||
| if (future.IsError()) { | |||||
| promise->SetFailed(future.GetErrorCode()); | |||||
| } else if (future.IsOK()) { | |||||
| ready.fetch_add(1); | |||||
| if (ready.load() == futures.size()) { | |||||
| std::list<T> values; | |||||
| auto iter = futures.begin(); | |||||
| for (; iter != futures.end(); ++iter) { | |||||
| values.push_back(iter->Get()); | |||||
| } | |||||
| promise->SetValue(values); | |||||
| } | |||||
| } | |||||
| } | |||||
| private: | |||||
| const std::list<Future<T>> futures; | |||||
| Promise<std::list<T>> *promise; | |||||
| std::atomic_ulong ready; | |||||
| }; | |||||
| template <typename T> | |||||
| inline Future<std::list<T>> Collect(const std::list<Future<T>> &futures) { | |||||
| if (futures.empty()) { | |||||
| return std::list<T>(); | |||||
| } | |||||
| Promise<std::list<T>> *promise = new (std::nothrow) Promise<std::list<T>>(); | |||||
| BUS_OOM_EXIT(promise); | |||||
| using CollectType = Collected<T>; | |||||
| std::shared_ptr<CollectType> collect = std::make_shared<CollectType>(futures, promise); | |||||
| // | |||||
| auto iter = futures.begin(); | |||||
| for (; iter != futures.end(); ++iter) { | |||||
| iter->OnComplete(Defer(collect, &CollectType::Waited, std::placeholders::_1)); | |||||
| } | |||||
| Future<std::list<T>> future = promise->GetFuture(); | |||||
| future.OnComplete(Defer(collect, &Collected<T>::Discarded)); | |||||
| return future; | |||||
| } | |||||
| template <typename... Ts> | |||||
| Future<std::tuple<Ts...>> Collect(const Future<Ts> &... futures) { | |||||
| std::list<Future<Nothing>> wrappers = {futures.Then([]() { return Nothing(); })...}; | |||||
| auto f = [](const Future<Ts> &... futures) { return std::make_tuple(futures.Get()...); }; | |||||
| return Collect(wrappers).Then(std::bind(f, futures...)); | |||||
| } | |||||
| }; // namespace mindspore | |||||
| #endif | |||||
| @@ -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__ */ | |||||
| @@ -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 <functional> | |||||
| #include "async/async.h" | |||||
| #include "async/option.h" | |||||
| namespace mindspore { | |||||
| template <typename F> | |||||
| class Deferred : public std::function<F> { | |||||
| public: | |||||
| virtual ~Deferred() {} | |||||
| private: | |||||
| template <typename G> | |||||
| friend class internal::DeferredHelper; | |||||
| template <typename T> | |||||
| friend Deferred<void()> Defer(const AID &aid, void (T::*method)()); | |||||
| template <typename R, typename T> | |||||
| friend Deferred<Future<R>()> Defer(const AID &aid, Future<R> (T::*method)()); | |||||
| template <typename R, typename T> | |||||
| friend Deferred<Future<R>()> Defer(const AID &aid, R (T::*method)()); | |||||
| Deferred(const std::function<F> &f) : std::function<F>(f) {} | |||||
| }; | |||||
| namespace internal { | |||||
| template <typename F> | |||||
| class DeferredHelper { | |||||
| public: | |||||
| DeferredHelper(const AID &id, F &&function) : aid(id), f(std::forward<F>(function)) {} | |||||
| DeferredHelper(F &&function) : f(std::forward<F>(function)) {} | |||||
| ~DeferredHelper() {} | |||||
| operator Deferred<void()>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<void()>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<void()>([=]() { Async(optionAid.Get(), function); }); | |||||
| } | |||||
| operator std::function<void()>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<void()>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<void()>([=]() { Async(optionAid.Get(), function); }); | |||||
| } | |||||
| template <typename R> | |||||
| operator Deferred<R()>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<R()>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<R()>([=]() { return Async(optionAid.Get(), function); }); | |||||
| } | |||||
| template <typename R> | |||||
| operator std::function<R()>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<R()>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<R()>([=]() { return Async(optionAid.Get(), function); }); | |||||
| } | |||||
| template <typename Arg> | |||||
| operator Deferred<void(Arg)>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<void(Arg)>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<void(Arg)>([=](Arg arg) { | |||||
| std::function<void()> handler([=]() { function(arg); }); | |||||
| Async(optionAid.Get(), handler); | |||||
| }); | |||||
| } | |||||
| template <typename Arg> | |||||
| operator std::function<void(Arg)>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<void(Arg)>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<void(Arg)>([=](Arg arg) { | |||||
| std::function<void()> handler([=]() { function(arg); }); | |||||
| Async(optionAid.Get(), handler); | |||||
| }); | |||||
| } | |||||
| template <typename... Args> | |||||
| operator Deferred<void(Args...)>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<void(Args...)>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<void(Args...)>([=](Args... args) { | |||||
| auto tuple = std::make_tuple(std::forward<Args>(args)...); | |||||
| std::function<void()> handler([=]() { Apply(function, tuple); }); | |||||
| Async(optionAid.Get(), handler); | |||||
| }); | |||||
| } | |||||
| template <typename... Args> | |||||
| operator std::function<void(Args...)>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<void(Args...)>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<void(Args...)>([=](Args... args) { | |||||
| auto tuple = std::make_tuple(std::forward<Args>(args)...); | |||||
| std::function<void()> handler([=]() { Apply(function, tuple); }); | |||||
| Async(optionAid.Get(), handler); | |||||
| }); | |||||
| } | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, typename Arg> | |||||
| operator Deferred<R(Arg)>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<R(Arg)>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<R(Arg)>([=](Arg arg) { | |||||
| std::function<R()> handler([=]() { return function(arg); }); | |||||
| return Async(optionAid.Get(), handler); | |||||
| }); | |||||
| } | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, typename Arg> | |||||
| operator std::function<R(Arg)>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<R(Arg)>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<R(Arg)>([=](Arg arg) { | |||||
| std::function<R()> handler([=]() { return function(arg); }); | |||||
| return Async(optionAid.Get(), handler); | |||||
| }); | |||||
| } | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, typename... Args> | |||||
| operator Deferred<R(Args...)>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<R(Args...)>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<R(Args...)>([=](Args... args) { | |||||
| auto tuple = std::make_tuple(std::forward<Args>(args)...); | |||||
| std::function<R()> handler([=]() { return Apply(function, tuple); }); | |||||
| return Async(optionAid.Get(), handler); | |||||
| }); | |||||
| } | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, typename... Args> | |||||
| operator std::function<R(Args...)>() && { | |||||
| if (aid.IsNone()) { | |||||
| return std::function<R(Args...)>(std::forward<F>(f)); | |||||
| } | |||||
| Option<AID> optionAid = aid; | |||||
| F &&function = std::forward<F>(f); | |||||
| return std::function<R(Args...)>([=](Args... args) { | |||||
| auto tuple = std::make_tuple(std::forward<Args>(args)...); | |||||
| std::function<R()> handler([=]() { return Apply(function, tuple); }); | |||||
| return Async(optionAid.Get(), handler); | |||||
| }); | |||||
| } | |||||
| private: | |||||
| template <typename G> | |||||
| friend DeferredHelper<G> Defer(const AID &aid, G &&g); | |||||
| Option<AID> aid; | |||||
| F f; | |||||
| }; | |||||
| } // namespace internal | |||||
| template <typename F> | |||||
| internal::DeferredHelper<F> Defer(const AID &aid, F &&f) { | |||||
| return internal::DeferredHelper<F>(aid, std::forward<F>(f)); | |||||
| } | |||||
| template <typename T> | |||||
| Deferred<void()> Defer(const AID &aid, void (T::*method)()) { | |||||
| return Deferred<void()>([=]() { Async(aid, method); }); | |||||
| } | |||||
| template <typename R, typename T> | |||||
| Deferred<Future<R>()> Defer(const AID &aid, Future<R> (T::*method)()) { | |||||
| return Deferred<Future<R>()>([=]() { return Async(aid, method); }); | |||||
| } | |||||
| template <typename R, typename T> | |||||
| Deferred<Future<R>()> Defer(const AID &aid, R (T::*method)()) { | |||||
| return Deferred<Future<R>()>([=]() { return Async(aid, method); }); | |||||
| } | |||||
| template <typename T, typename... Args0, typename... Args1> | |||||
| auto Defer(T *t, void (T::*method)(Args0...), Args1 &&... args) | |||||
| -> internal::DeferredHelper<decltype(std::bind(&std::function<void(Args0...)>::operator(), | |||||
| std::function<void(Args0...)>(), std::forward<Args1>(args)...))> { | |||||
| std::function<void(Args0...)> f([=](Args0... args0) { | |||||
| if (t != nullptr) { | |||||
| (t->*method)(args0...); | |||||
| } | |||||
| }); | |||||
| return std::bind(&std::function<void(Args0...)>::operator(), std::move(f), std::forward<Args1>(args)...); | |||||
| } | |||||
| template <typename T, typename... Args0, typename... Args1> | |||||
| auto Defer(std::shared_ptr<T> t, void (T::*method)(Args0...), Args1 &&... args) | |||||
| -> internal::DeferredHelper<decltype(std::bind(&std::function<void(Args0...)>::operator(), | |||||
| std::function<void(Args0...)>(), std::forward<Args1>(args)...))> { | |||||
| std::function<void(Args0...)> f([=](Args0... args0) { | |||||
| if (t != nullptr) { | |||||
| (t.get()->*method)(args0...); | |||||
| } | |||||
| }); | |||||
| return std::bind(&std::function<void(Args0...)>::operator(), std::move(f), std::forward<Args1>(args)...); | |||||
| } | |||||
| template <typename T, typename... Args0, typename... Args1> | |||||
| auto Defer(const AID &aid, void (T::*method)(Args0...), Args1 &&... args) | |||||
| -> internal::DeferredHelper<decltype(std::bind(&std::function<void(Args0...)>::operator(), | |||||
| std::function<void(Args0...)>(), std::forward<Args1>(args)...))> { | |||||
| std::function<void(Args0...)> f([=](Args0... args0) { Async(aid, method, args0...); }); | |||||
| return std::bind(&std::function<void(Args0...)>::operator(), std::move(f), std::forward<Args1>(args)...); | |||||
| } | |||||
| template <typename R, typename T, typename... Args0, typename... Args1> | |||||
| auto Defer(const AID &aid, Future<R> (T::*method)(Args0...), Args1 &&... args) | |||||
| -> internal::DeferredHelper<decltype(std::bind(&std::function<Future<R>(Args0...)>::operator(), | |||||
| std::function<Future<R>(Args0...)>(), std::forward<Args1>(args)...))> { | |||||
| std::function<Future<R>(Args0...)> f([=](Args0... args0) { return Async(aid, method, args0...); }); | |||||
| return std::bind(&std::function<Future<R>(Args0...)>::operator(), std::move(f), std::forward<Args1>(args)...); | |||||
| } | |||||
| template <typename R, typename std::enable_if<!std::is_same<R, void>::value, int>::type = 0, | |||||
| typename std::enable_if<!internal::IsFuture<R>::value, int>::type = 0, typename T, typename... Args0, | |||||
| typename... Args1> | |||||
| auto Defer(const AID &aid, R (T::*method)(Args0...), Args1 &&... args) | |||||
| -> internal::DeferredHelper<decltype(std::bind(&std::function<Future<R>(Args0...)>::operator(), | |||||
| std::function<Future<R>(Args0...)>(), std::forward<Args1>(args)...))> { | |||||
| std::function<Future<R>(Args0...)> f([=](Args0... args0) { return Async(aid, method, args0...); }); | |||||
| return std::bind(&std::function<Future<R>(Args0...)>::operator(), std::move(f), std::forward<Args1>(args)...); | |||||
| } | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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__ */ | |||||
| @@ -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 <future> | |||||
| #include <iostream> | |||||
| #include <list> | |||||
| #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 <typename T> | |||||
| class Promise; | |||||
| template <typename T> | |||||
| class Option; | |||||
| template <typename T> | |||||
| class Future : public FutureBase { | |||||
| public: | |||||
| typedef Status WaitForStatus; | |||||
| typedef typename FutureData<T>::CompleteCallback CompleteCallback; | |||||
| typedef typename FutureData<T>::AbandonedCallback AbandonedCallback; | |||||
| typedef FutureData<T> Data; | |||||
| Future() : data(new (std::nothrow) Data()) { | |||||
| BUS_OOM_EXIT(data); | |||||
| data->abandoned = true; | |||||
| } | |||||
| Future(const Future<T> &f) : FutureBase(f), data(f.data) {} | |||||
| Future(Future<T> &&f) : data(std::move(f.data)) {} | |||||
| Future(const T &t) : data(new (std::nothrow) Data()) { | |||||
| BUS_OOM_EXIT(data); | |||||
| SetValue(std::move(t)); | |||||
| } | |||||
| template <typename V> | |||||
| 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<T> &operator=(const Future<T> &f) { | |||||
| if (&f != this) { | |||||
| data = f.data; | |||||
| } | |||||
| return *this; | |||||
| } | |||||
| bool operator==(const Future<T> &f) const { return data == f.data; } | |||||
| bool operator!=(const Future<T> &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<T> Get(uint64_t timeMs) const { | |||||
| if (data->gotten) { | |||||
| return Option<T>(data->t); | |||||
| } | |||||
| if (WaitFor(timeMs).IsError()) { | |||||
| return Option<T>(); | |||||
| } | |||||
| if (data->status.IsError()) { | |||||
| return Option<T>(); | |||||
| } | |||||
| return Option<T>(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::WaitActor>( | |||||
| 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 <typename F> | |||||
| const Future<T> &OnComplete(internal::DeferredHelper<F> &&deferred) const { | |||||
| return OnComplete(std::move(deferred).operator std::function<void(const Future<T> &)>()); | |||||
| } | |||||
| template <typename F> | |||||
| const Future<T> &OnAbandoned(internal::DeferredHelper<F> &&deferred) const { | |||||
| return OnAbandoned(std::move(deferred).operator std::function<void(const Future<T> &)>()); | |||||
| } | |||||
| const Future<T> &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<T> &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<AbandonedCallback> 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 <typename R> | |||||
| Future<R> Then(const std::function<Future<R>(const T &)> &f) const { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::function<void(const Future<T> &)> handler = | |||||
| std::bind(&internal::Thenf<T, R>, f, promise, std::placeholders::_1); | |||||
| OnComplete(std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| template <typename R> | |||||
| Future<R> Then(const std::function<R(const T &)> &f) const { | |||||
| std::shared_ptr<Promise<R>> promise(new (std::nothrow) Promise<R>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<R> future = promise->GetFuture(); | |||||
| std::function<void(const Future<T> &)> handler = | |||||
| std::bind(&internal::Then<T, R>, f, promise, std::placeholders::_1); | |||||
| OnComplete(std::move(handler)); | |||||
| return future; | |||||
| } | |||||
| template <typename R> | |||||
| Future<R> Then(const std::function<Future<R>()> &f) const { | |||||
| return Then(std::function<Future<R>(const T &)>(std::bind(f))); | |||||
| } | |||||
| template <typename R> | |||||
| Future<R> Then(const std::function<R()> &f) const { | |||||
| return Then(std::function<R(const T &)>(std::bind(f))); | |||||
| } | |||||
| template <typename F> | |||||
| auto Then(F &&f) const -> decltype(this->Then(std::forward<F>(f), FutureBase())) { | |||||
| return Then(std::forward<F>(f), FutureBase()); | |||||
| } | |||||
| template <typename F> | |||||
| const Future<T> &OnComplete(F &&f) const { | |||||
| return OnComplete(std::forward<F>(f), FutureBase()); | |||||
| } | |||||
| template <typename F> | |||||
| const Future<T> &OnAbandoned(F &&f) const { | |||||
| return OnAbandoned(std::forward<F>(f), FutureBase()); | |||||
| } | |||||
| Future<T> After(const Duration &timeMs, const std::function<Future<T>(const Future<T> &)> &f) const { | |||||
| std::shared_ptr<Promise<T>> promise(new (std::nothrow) Promise<T>()); | |||||
| BUS_OOM_EXIT(promise); | |||||
| Future<T> future = promise->GetFuture(); | |||||
| mindspore::Timer timer = | |||||
| TimerTools::AddTimer(timeMs, "__After__", std::bind(&internal::Afterf<T>, f, promise, *this)); | |||||
| OnComplete(std::bind(&internal::After<T>, promise, timer, std::placeholders::_1)); | |||||
| return future; | |||||
| } | |||||
| private: | |||||
| template <typename F, typename R = typename internal::Unwrap<typename std::result_of<F(const T &)>::type>::type> | |||||
| Future<R> Then(internal::DeferredHelper<F> &&f, FutureBase) const { | |||||
| return Then<R>(std::move(f).operator std::function<Future<R>(const T &)>()); | |||||
| } | |||||
| template <typename F, typename R = typename internal::Unwrap<typename std::result_of<typename std::enable_if< | |||||
| !std::is_bind_expression<typename std::decay<F>::type>::value, F>::type()>::type>::type> | |||||
| Future<R> Then(internal::DeferredHelper<F> &&f, LessFuture) const { | |||||
| return Then<R>(std::move(f).operator std::function<Future<R>()>()); | |||||
| } | |||||
| template <typename F, typename R = typename internal::Unwrap<typename std::result_of<F(const T &)>::type>::type> | |||||
| Future<R> Then(F &&f, FutureBase) const { | |||||
| return Then<R>(std::function<Future<R>(const T &)>(f)); | |||||
| } | |||||
| template <typename F, typename R = typename internal::Unwrap<typename std::result_of<typename std::enable_if< | |||||
| !std::is_bind_expression<typename std::decay<F>::type>::value, F>::type()>::type>::type> | |||||
| Future<R> Then(F &&f, LessFuture) const { | |||||
| return Then<R>(std::function<Future<R>()>(std::forward<F>(f))); | |||||
| } | |||||
| template <typename F, typename = typename std::result_of<F(const Future<T> &)>::type> | |||||
| const Future<T> &OnComplete(F &&f, FutureBase) const { | |||||
| return OnComplete( | |||||
| std::function<void(const Future<T> &)>([=](const Future<T> &future) mutable { std::forward<F>(f)(future); })); | |||||
| } | |||||
| template <typename F, typename = typename std::result_of<typename std::enable_if< | |||||
| !std::is_bind_expression<typename std::decay<F>::type>::value, F>::type()>::type> | |||||
| const Future<T> &OnComplete(F &&f, LessFuture) const { | |||||
| return OnComplete(std::function<void(const Future<T> &)>([=](const Future<T> &) mutable { std::forward<F>(f)(); })); | |||||
| } | |||||
| template <typename F, typename = typename std::result_of<F(const Future<T> &)>::type> | |||||
| const Future<T> &OnAbandoned(F &&f, FutureBase) const { | |||||
| return OnAbandoned( | |||||
| std::function<void(const Future<T> &)>([=](const Future<T> &future) mutable { std::forward<F>(f)(future); })); | |||||
| } | |||||
| template <typename F, typename = typename std::result_of<typename std::enable_if< | |||||
| !std::is_bind_expression<typename std::decay<F>::type>::value, F>::type()>::type> | |||||
| const Future<T> &OnAbandoned(F &&f, LessFuture) const { | |||||
| return OnAbandoned( | |||||
| std::function<void(const Future<T> &)>([=](const Future<T> &) mutable { std::forward<F>(f)(); })); | |||||
| } | |||||
| void RunCallbacks() const { | |||||
| std::shared_ptr<typename Future<T>::Data> copy = data; | |||||
| internal::Run(std::move(copy->onCompleteCallbacks), Future<T>(copy)); | |||||
| copy->Clear(); | |||||
| } | |||||
| void Run() const { | |||||
| auto iter = data->onCompleteCallbacks.begin(); | |||||
| for (; iter != data->onCompleteCallbacks.end(); ++iter) { | |||||
| (*iter)(*this); | |||||
| } | |||||
| } | |||||
| template <typename V> | |||||
| void Set(V &&value) const { | |||||
| bool call = false; | |||||
| data->lock.Lock(); | |||||
| if (data->status.IsInit()) { | |||||
| data->status.SetOK(); | |||||
| data->promise.set_value(std::forward<V>(value)); | |||||
| call = true; | |||||
| } | |||||
| data->lock.Unlock(); | |||||
| if (call) { | |||||
| RunCallbacks(); | |||||
| } | |||||
| } | |||||
| template <typename V> | |||||
| friend class Future; | |||||
| friend class Promise<T>; | |||||
| Future(const std::shared_ptr<Data> &t) : data(t) {} | |||||
| std::shared_ptr<Data> data; | |||||
| }; | |||||
| template <typename T> | |||||
| 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<T> &tFuture) const { Associate(tFuture); } | |||||
| void SetFailed(int32_t code) const { | |||||
| if (!future.data->associated) { | |||||
| future.SetFailed(code); | |||||
| } | |||||
| } | |||||
| Future<T> GetFuture() const { return future; } | |||||
| void Associate(const Future<T> &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<T>, future, std::placeholders::_1)) | |||||
| .OnAbandoned(std::bind(&internal::Abandon<T>, future, true)); | |||||
| } | |||||
| } | |||||
| private: | |||||
| template <typename V> | |||||
| void Set(V &&value) const { | |||||
| if (future.IsInit() && !future.data->associated) { | |||||
| future.SetValue(std::forward<V>(value)); | |||||
| } | |||||
| } | |||||
| template <typename V> | |||||
| friend class Future; | |||||
| Future<T> future; | |||||
| }; | |||||
| template <> | |||||
| class Promise<void>; | |||||
| template <typename T> | |||||
| class Promise<T &>; | |||||
| }; // namespace mindspore | |||||
| #endif | |||||
| @@ -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 <future> | |||||
| #include <iostream> | |||||
| #include <list> | |||||
| #include "actor/actor.h" | |||||
| #include "actor/buslog.h" | |||||
| #include "async/spinlock.h" | |||||
| #include "async/status.h" | |||||
| #include "timer/timertools.h" | |||||
| namespace mindspore { | |||||
| template <typename T> | |||||
| class Future; | |||||
| template <typename T> | |||||
| 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 <typename T> | |||||
| struct FutureData { | |||||
| public: | |||||
| typedef std::function<void(const Future<T> &)> CompleteCallback; | |||||
| typedef std::function<void(const Future<T> &)> 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<T> promise; | |||||
| // get from promise | |||||
| std::future<T> future; | |||||
| // complete callback | |||||
| std::list<CompleteCallback> onCompleteCallbacks; | |||||
| // abandoned callback | |||||
| std::list<AbandonedCallback> 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 <typename T> | |||||
| class DeferredHelper; | |||||
| template <typename T> | |||||
| struct Wrap { | |||||
| typedef Future<T> type; | |||||
| }; | |||||
| template <typename T> | |||||
| struct Wrap<Future<T>> { | |||||
| typedef Future<T> type; | |||||
| }; | |||||
| template <typename T> | |||||
| struct Unwrap { | |||||
| typedef T type; | |||||
| }; | |||||
| template <typename T> | |||||
| struct Unwrap<Future<T>> { | |||||
| typedef T type; | |||||
| }; | |||||
| template <typename T> | |||||
| struct IsFuture : public std::integral_constant<bool, std::is_base_of<FutureBase, T>::value> {}; | |||||
| template <typename H, typename... Args> | |||||
| static void Run(std::list<H> &&handlers, Args &&... args) { | |||||
| for (auto iter = handlers.begin(); iter != handlers.end(); ++iter) { | |||||
| std::move (*iter)(std::forward<Args>(args)...); | |||||
| } | |||||
| } | |||||
| template <typename T> | |||||
| static void Complete(const Future<T> &future, const Future<T> &f) { | |||||
| if (f.IsError()) { | |||||
| future.SetFailed(f.GetErrorCode()); | |||||
| } else if (f.IsOK()) { | |||||
| future.SetValue(f.Get()); | |||||
| } | |||||
| } | |||||
| template <typename T> | |||||
| static void Abandon(const Future<T> &future, bool abandon) { | |||||
| future.Abandon(abandon); | |||||
| } | |||||
| template <typename T, typename R> | |||||
| static void Thenf(const std::function<Future<R>(const T &)> &function, const std::shared_ptr<Promise<R>> &promise, | |||||
| const Future<T> &f) { | |||||
| if (f.IsError()) { | |||||
| promise->SetFailed(f.GetErrorCode()); | |||||
| } else if (f.IsOK()) { | |||||
| promise->Associate(function(f.Get())); | |||||
| } | |||||
| } | |||||
| template <typename T, typename R> | |||||
| static void Then(const std::function<R(const T &)> &function, const std::shared_ptr<Promise<R>> &promise, | |||||
| const Future<T> &f) { | |||||
| if (f.IsError()) { | |||||
| promise->SetFailed(f.GetErrorCode()); | |||||
| } else if (f.IsOK()) { | |||||
| promise->SetValue(function(f.Get())); | |||||
| } | |||||
| } | |||||
| template <typename T> | |||||
| static void Afterf(const std::function<Future<T>(const Future<T> &)> &f, const std::shared_ptr<Promise<T>> &promise, | |||||
| const Future<T> &future) { | |||||
| promise->Associate(f(future)); | |||||
| } | |||||
| template <typename T> | |||||
| static void After(const std::shared_ptr<Promise<T>> &promise, const mindspore::Timer &timer, const Future<T> &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 | |||||
| @@ -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 <type_traits> | |||||
| #include <utility> | |||||
| #include "actor/buslog.h" | |||||
| namespace mindspore { | |||||
| template <typename T> | |||||
| struct InnerSome { | |||||
| InnerSome(const T &t) : _t(std::move(t)) {} | |||||
| T _t; | |||||
| }; | |||||
| template <typename T> | |||||
| InnerSome<typename std::decay<T>::type> Some(T &&t) { | |||||
| return InnerSome<typename std::decay<T>::type>(std::forward<T>(t)); | |||||
| } | |||||
| struct None {}; | |||||
| template <typename T> | |||||
| 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<T> &some) : data(some._t), state(SOME) {} | |||||
| Option(const None &none) : data(), state(NONE) {} | |||||
| Option(const Option<T> &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<T> &operator=(const Option<T> &that) { | |||||
| if (&that != this) { | |||||
| state = that.state; | |||||
| if (that.IsSome()) { | |||||
| data = that.data; | |||||
| } | |||||
| } | |||||
| return *this; | |||||
| } | |||||
| bool operator==(const Option<T> &that) const { | |||||
| return (IsNone() && that.IsNone()) || (IsSome() && that.IsSome() && data == that.data); | |||||
| } | |||||
| bool operator!=(const Option<T> &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 | |||||
| @@ -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 <tuple> | |||||
| #include "option.h" | |||||
| #include "status.h" | |||||
| namespace mindspore { | |||||
| template <typename... Types> | |||||
| class Result { | |||||
| public: | |||||
| Result() : status(Status::KINIT) {} | |||||
| Result(Types... types, const Status &s) : tuple(Option<Types>(types)...), status(s) {} | |||||
| ~Result() {} | |||||
| template <std::size_t I> | |||||
| bool IsSome() { | |||||
| return (std::get<I>(tuple)).IsSome(); | |||||
| } | |||||
| template <std::size_t I> | |||||
| bool IsNone() { | |||||
| return std::get<I>(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 <std::size_t I> | |||||
| typename std::tuple_element<I, std::tuple<Option<Types>...>>::type Get() const { | |||||
| return GetOption<I>().Get(); | |||||
| } | |||||
| private: | |||||
| template <std::size_t I> | |||||
| typename std::tuple_element<I, std::tuple<Option<Types>...>>::type GetOption() const { | |||||
| return std::get<I>(tuple); | |||||
| } | |||||
| private: | |||||
| std::tuple<Option<Types>...> tuple; | |||||
| Status status; | |||||
| }; | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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 <atomic> | |||||
| 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 | |||||
| @@ -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 | |||||
| @@ -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 <typename T, typename F = Failure> | |||||
| 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<T> data; | |||||
| Failure errorCode; | |||||
| }; | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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 <stdint.h> | |||||
| #include <algorithm> | |||||
| #include <sstream> | |||||
| #include <iostream> | |||||
| #include <iomanip> | |||||
| #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<uuid> FromBytes(const std::string &s); | |||||
| static Option<unsigned char> GetValue(char c); | |||||
| static Option<uuid> 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 <typename T, typename F> | |||||
| friend std::basic_ostream<T, F> &operator<<(std::basic_ostream<T, F> &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 <typename T, typename F> | |||||
| std::basic_ostream<T, F> &operator<<(std::basic_ostream<T, F> &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<T>('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<T>(' ')) << std::dec; | |||||
| return s; | |||||
| } | |||||
| } // namespace uuids | |||||
| } // namespace mindspore | |||||
| #endif /* UUID_BASE_HPP_ */ | |||||
| @@ -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 | |||||
| @@ -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 <string> | |||||
| 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 | |||||
| @@ -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 <string> | |||||
| #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 | |||||
| @@ -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 <deque> | |||||
| #include <functional> | |||||
| #include <list> | |||||
| #include <map> | |||||
| #include <string> | |||||
| #include <thread> | |||||
| #include "async/spinlock.h" | |||||
| namespace mindspore { | |||||
| using Duration = uint64_t; | |||||
| } | |||||
| #endif | |||||
| @@ -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<void()> &handler); | |||||
| uint64_t id; | |||||
| TimeWatch t; | |||||
| AID aid; | |||||
| std::function<void()> thunk; | |||||
| }; | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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 <atomic> | |||||
| #include <list> | |||||
| #include <map> | |||||
| #include <set> | |||||
| #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<void()> &thunk); | |||||
| static bool Cancel(const Timer &timer); | |||||
| static std::atomic_bool g_initStatus; | |||||
| }; | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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 | |||||
| @@ -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_OBJECTS:litebus_obj>) | |||||
| 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_OBJECTS:litebus_obj>) | |||||
| 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) | |||||
| @@ -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 | |||||
| ) | |||||
| @@ -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<ActorBase> &actor, std::unique_ptr<ActorPolicy> 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<MessageBase> msg(new (std::nothrow) MessageBase("Terminate", MessageBase::Type::KTERMINATE)); | |||||
| BUS_OOM_EXIT(msg); | |||||
| (void)EnqueMessage(std::move(msg)); | |||||
| } | |||||
| void ActorBase::HandlekMsg(std::unique_ptr<MessageBase> &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<MessageBase> 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<MessageBase> &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<MessageBase> 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<MessageBase> 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 | |||||
| @@ -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::actorMgr = std::make_shared<ActorMgr>(); | |||||
| std::map<std::string, std::shared_ptr<IOMgr>> ActorMgr::ioMgrs; | |||||
| std::shared_ptr<IOMgr> &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<IOMgr> 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> &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<ActorReference> 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<MessageBase> 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<MessageBase> 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<ActorPolicy> 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<MessageBase> 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 | |||||
| @@ -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 <set> | |||||
| #include "actor/actorthread.h" | |||||
| namespace mindspore { | |||||
| class ActorBase; | |||||
| class IOMgr; | |||||
| class ActorMgr { | |||||
| public: | |||||
| static inline std::shared_ptr<ActorMgr> &GetActorMgrRef() { return actorMgr; } | |||||
| static std::shared_ptr<IOMgr> &GetIOMgrRef(const std::string &protocol = "tcp"); | |||||
| static inline std::shared_ptr<IOMgr> &GetIOMgrRef(const AID &to) { return GetIOMgrRef(to.GetProtocol()); } | |||||
| static void Receive(std::unique_ptr<MessageBase> &&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> &ioMgr); | |||||
| int Send(const AID &to, std::unique_ptr<MessageBase> 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<ActorBase> &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<std::string, ActorReference> actors; | |||||
| std::mutex actorsMutex; | |||||
| ActorThread threadPool; | |||||
| std::map<std::string, std::string> procotols; | |||||
| std::set<std::string> urls; | |||||
| std::string delegate; | |||||
| static std::shared_ptr<ActorMgr> actorMgr; | |||||
| static std::map<std::string, std::shared_ptr<IOMgr> > ioMgrs; | |||||
| }; // end of class ActorMgr | |||||
| }; // end of namespace mindspore | |||||
| #endif | |||||
| @@ -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<std::mutex> 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<MessageBase> &msg) { | |||||
| int result; | |||||
| { | |||||
| std::lock_guard<std::mutex> 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<std::unique_ptr<MessageBase>> *SingleThread::GetMsgs() { | |||||
| std::list<std::unique_ptr<MessageBase>> *result; | |||||
| std::unique_lock<std::mutex> lock(mailboxLock); | |||||
| conditionVar.wait(lock, [this] { return (!this->enqueMailbox->empty()); }); | |||||
| SwapMailbox(); | |||||
| // REF_PRIVATE_MEMBER | |||||
| result = dequeMailbox; | |||||
| return result; | |||||
| } | |||||
| ShardedThread::ShardedThread(const std::shared_ptr<ActorBase> &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<MessageBase> &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<std::unique_ptr<MessageBase>> *ShardedThread::GetMsgs() { | |||||
| std::list<std::unique_ptr<MessageBase>> *result; | |||||
| mailboxLock.lock(); | |||||
| if (enqueMailbox->empty()) { | |||||
| ready = false; | |||||
| result = nullptr; | |||||
| } else { | |||||
| ready = true; | |||||
| SwapMailbox(); | |||||
| result = dequeMailbox; | |||||
| } | |||||
| mailboxLock.unlock(); | |||||
| return result; | |||||
| } | |||||
| }; // end of namespace mindspore | |||||
| @@ -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<ActorBase> &actor); | |||||
| virtual ~ShardedThread(); | |||||
| protected: | |||||
| virtual void Terminate(const ActorBase *actor); | |||||
| virtual int EnqueMessage(std::unique_ptr<MessageBase> &msg); | |||||
| virtual std::list<std::unique_ptr<MessageBase>> *GetMsgs(); | |||||
| virtual void Notify(); | |||||
| private: | |||||
| bool ready; | |||||
| bool terminated; | |||||
| std::shared_ptr<ActorBase> actor; | |||||
| }; | |||||
| class SingleThread : public ActorPolicy { | |||||
| public: | |||||
| SingleThread(); | |||||
| virtual ~SingleThread(); | |||||
| protected: | |||||
| virtual void Terminate(const ActorBase *actor); | |||||
| virtual int EnqueMessage(std::unique_ptr<MessageBase> &msg); | |||||
| virtual std::list<std::unique_ptr<MessageBase>> *GetMsgs(); | |||||
| virtual void Notify(); | |||||
| private: | |||||
| std::condition_variable conditionVar; | |||||
| }; | |||||
| }; // end of namespace mindspore | |||||
| #endif | |||||
| @@ -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<std::unique_ptr<MessageBase>> *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<MessageBase> &msg) = 0; | |||||
| virtual std::list<std::unique_ptr<MessageBase>> *GetMsgs() = 0; | |||||
| virtual void Notify() = 0; | |||||
| std::list<std::unique_ptr<MessageBase>> *enqueMailbox; | |||||
| std::list<std::unique_ptr<MessageBase>> *dequeMailbox; | |||||
| int msgCount; | |||||
| bool start; | |||||
| std::mutex mailboxLock; | |||||
| private: | |||||
| friend class ActorBase; | |||||
| std::list<std::unique_ptr<MessageBase>> mailbox1; | |||||
| std::list<std::unique_ptr<MessageBase>> mailbox2; | |||||
| }; | |||||
| }; // end of namespace mindspore | |||||
| #endif | |||||
| @@ -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 <atomic> | |||||
| #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<std::thread> 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<ActorBase> 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<std::thread> &worker = *it; | |||||
| if (worker->joinable()) { | |||||
| worker->join(); | |||||
| } | |||||
| } | |||||
| workers.clear(); | |||||
| MS_LOG(INFO) << "Actor's threads finish exiting."; | |||||
| } | |||||
| void ActorThread::DequeReadyActor(std::shared_ptr<ActorBase> &actor) { | |||||
| std::unique_lock<std::mutex> lock(readyActorMutex); | |||||
| conditionVar.wait(lock, [this] { return (this->readyActors.size() > 0); }); | |||||
| actor = readyActors.front(); | |||||
| readyActors.pop_front(); | |||||
| } | |||||
| void ActorThread::EnqueReadyActor(const std::shared_ptr<ActorBase> &actor) { | |||||
| { | |||||
| std::lock_guard<std::mutex> lock(readyActorMutex); | |||||
| readyActors.push_back(actor); | |||||
| } | |||||
| conditionVar.notify_one(); | |||||
| } | |||||
| void ActorThread::Run() { | |||||
| #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 12 | |||||
| static std::atomic<int> 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<ActorBase> 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 | |||||
| @@ -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 <condition_variable> | |||||
| #include <list> | |||||
| #include <thread> | |||||
| #include "actor/actor.h" | |||||
| namespace mindspore { | |||||
| class ActorThread { | |||||
| public: | |||||
| ActorThread(); | |||||
| ~ActorThread(); | |||||
| void Finalize(); | |||||
| void AddThread(int threadCount); | |||||
| void EnqueReadyActor(const std::shared_ptr<ActorBase> &actor); | |||||
| private: | |||||
| void Run(); | |||||
| void DequeReadyActor(std::shared_ptr<ActorBase> &actor); | |||||
| std::list<std::shared_ptr<ActorBase>> readyActors; | |||||
| std::mutex readyActorMutex; | |||||
| std::condition_variable conditionVar; | |||||
| std::list<std::unique_ptr<std::thread>> workers; | |||||
| std::string threadName; | |||||
| }; | |||||
| }; // end of namespace mindspore | |||||
| #endif | |||||
| @@ -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 | |||||
| @@ -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 <memory> | |||||
| #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<MessageBase> &&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<MessageBase> &&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 | |||||
| @@ -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 <actor/sysmgr_actor.h> | |||||
| #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<mindspore::IOMgr> 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<MetricsMessage> 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<mindspore::IOMgr> 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 | |||||
| @@ -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 <queue> | |||||
| #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<int>; | |||||
| using StringTypeMetrics = std::queue<std::string>; | |||||
| 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<MetricsMessage> message); | |||||
| void LinkRecycleDurationCallback(); | |||||
| Duration printSendMetricsDuration; | |||||
| static Duration linkRecycleDuration; | |||||
| int linkRecyclePeriod; | |||||
| }; | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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 | |||||
| ) | |||||
| @@ -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<MessageHandler> h) | |||||
| : MessageBase("Async", Type::KASYNC), handler(std::move(h)) {} | |||||
| ~MessageAsync() override {} | |||||
| void Run(ActorBase *actor) override { (*handler)(actor); } | |||||
| private: | |||||
| std::unique_ptr<MessageHandler> handler; | |||||
| }; | |||||
| void Async(const AID &aid, std::unique_ptr<std::function<void(ActorBase *)>> handler) { | |||||
| std::unique_ptr<MessageAsync> msg(new (std::nothrow) MessageAsync(std::move(handler))); | |||||
| BUS_OOM_EXIT(msg); | |||||
| (void)ActorMgr::GetActorMgrRef()->Send(aid, std::move(msg)); | |||||
| } | |||||
| } // namespace mindspore | |||||
| @@ -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 | |||||
| @@ -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 <random> | |||||
| #include "async/uuid_base.h" | |||||
| #include <atomic> | |||||
| #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<const char *>(u.uuidData), sizeof(u.uuidData)); | |||||
| } | |||||
| Option<uuid> 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<unsigned char> 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> 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<unsigned char> 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<unsigned char> 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<unsigned long> distribution((std::numeric_limits<unsigned long>::min)(), | |||||
| (std::numeric_limits<unsigned long>::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<uint8_t>((randomValue >> (i * RIGHT_SHIFT_BITS)) & 0xFF); | |||||
| } | |||||
| // use atomic ++ to replace random | |||||
| static std::atomic<unsigned long> 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 | |||||
| @@ -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 <atomic> | |||||
| #include <climits> | |||||
| 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<int> 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 | |||||
| @@ -0,0 +1,3 @@ | |||||
| target_sources(litebus_obj PRIVATE | |||||
| ${CMAKE_CURRENT_SOURCE_DIR}/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 <atomic> | |||||
| #include <string> | |||||
| #include <thread> | |||||
| #include <netinet/in.h> | |||||
| #include <netinet/tcp.h> | |||||
| #include <sys/eventfd.h> | |||||
| #include <sys/socket.h> | |||||
| #include <csignal> | |||||
| #include <unistd.h> | |||||
| #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<std::function<void()>> 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<void()> &&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<EventData *> deleteEventList; | |||||
| // if fd not found, push eventData into deletedEvents[fd] | |||||
| std::map<int, std::list<EventData *>>::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<EventData *>::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<int, std::list<EventData *>>::iterator fdIter = deletedEvents.begin(); | |||||
| while (fdIter != deletedEvents.end()) { | |||||
| std::list<EventData *> deleteEventList = fdIter->second; | |||||
| std::list<EventData *>::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<int, std::list<EventData *>>::iterator fdIter = deletedEvents.find(tev->fd); | |||||
| if (fdIter == deletedEvents.end()) { | |||||
| return 0; | |||||
| } | |||||
| std::list<EventData *> deleteEventList = fdIter->second; | |||||
| std::list<EventData *>::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<EventData *>(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 | |||||
| @@ -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 <sys/epoll.h> | |||||
| #include <sys/ioctl.h> | |||||
| #include <functional> | |||||
| #include <list> | |||||
| #include <mutex> | |||||
| #include <queue> | |||||
| #include <sys/eventfd.h> | |||||
| #include <semaphore.h> | |||||
| #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<void()> &&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<std::function<void()>> queue; | |||||
| std::mutex eventsLock; | |||||
| // fd,EventData | |||||
| std::map<int, EventData *> 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<int, std::list<EventData *>> deletedEvents; | |||||
| }; | |||||
| } // namespace mindspore | |||||
| #endif | |||||
| @@ -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 <cstdlib> | |||||
| #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<mindspore::IOMgr> &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<SysMgrActor>(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 | |||||
| @@ -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 | |||||
| ) | |||||
| @@ -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<void()> &handler) | |||||
| : id(timerId), t(timeWatch), aid(timeAid), thunk(handler) {} | |||||
| } // namespace mindspore | |||||
| @@ -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 <csignal> | |||||
| #include <ctime> | |||||
| #include <unistd.h> | |||||
| #include <sys/timerfd.h> | |||||
| #include "evloop/evloop.h" | |||||
| namespace mindspore { | |||||
| using TimerPoolType = std::map<Duration, std::list<Timer>>; | |||||
| static std::unique_ptr<TimerPoolType> g_timerPool; | |||||
| static std::unique_ptr<EvLoop> 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<Duration, std::list<Timer>> &timerPool) { | |||||
| if (!timerPool.empty()) { | |||||
| Duration first = timerPool.begin()->first; | |||||
| return first; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| void ExecTimers(const std::list<Timer> &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<Duration, std::list<Timer>> &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<Timer> 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<Timer> 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<void()> &thunk) { | |||||
| if (g_initStatus.load() == false) { | |||||
| return Timer(); | |||||
| } | |||||
| if (duration == 0) { | |||||
| thunk(); | |||||
| return Timer(); | |||||
| } | |||||
| static std::atomic<uint64_t> 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 | |||||
| @@ -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 | |||||