1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #ifndef HIVIEW_BASE_EVENT_LOOP_H 16 #define HIVIEW_BASE_EVENT_LOOP_H 17 #include <algorithm> 18 #include <atomic> 19 #include <future> 20 #include <map> 21 #include <memory> 22 #include <queue> 23 #include <utility> 24 25 #include <sys/types.h> 26 27 #include "defines.h" 28 #include "event.h" 29 30 #if defined(__HIVIEW_OHOS__) 31 #include "unique_fd.h" 32 #ifdef USE_POLL 33 #include <poll.h> 34 #endif 35 #elif defined(_WIN32) 36 #include <Windows.h> 37 #include <winnt.h> 38 #endif 39 40 namespace OHOS { 41 namespace HiviewDFX { 42 constexpr int LOOP_WAKEUP_HANDLE_INDEX = 0; 43 constexpr int MAX_EVENT_SIZE = 16; 44 constexpr int MAX_HANDLE_ARRAY_SIZE = 1; 45 constexpr int MAX_WATCHED_FDS = 64; 46 constexpr uint64_t SECOND_TO_MICROSECOND = 1000000; 47 constexpr uint64_t SECOND_TO_NANOSECOND = 1000000000; 48 constexpr uint64_t NANOSECOND_TO_MILLSECOND = 1000000; 49 constexpr uint64_t MICROSECOND_TO_MILLSECOND = 1000; 50 constexpr uint64_t MICROSECOND_TO_NANOSECOND = 1000; 51 using Task = std::function<void()>; 52 enum LoopEventType { 53 LOOP_EVENT_TASK, 54 LOOP_PACKAGED_TASK, 55 }; 56 struct LoopEvent { 57 bool isRepeat = false; 58 uint8_t taskType = 0; 59 uint64_t seq = 0; 60 uint64_t interval = 0; 61 uint64_t enqueueTime = 0; 62 uint64_t targetTime = 0; 63 std::shared_ptr<Event> event = nullptr; 64 std::shared_ptr<EventHandler> handler = nullptr; 65 Task task = nullptr; 66 std::shared_ptr<std::packaged_task<bool()>> packagedTask = nullptr; 67 CreateLoopEventLoopEvent68 static LoopEvent CreateLoopEvent(uint64_t now) 69 { 70 LoopEvent event; 71 event.isRepeat = false; 72 event.taskType = LOOP_EVENT_TASK; 73 event.seq = now; 74 event.interval = 0; 75 event.enqueueTime = now; 76 event.targetTime = now; 77 event.event = nullptr; 78 event.handler = nullptr; 79 event.task = nullptr; 80 event.packagedTask = nullptr; 81 return event; 82 } 83 84 bool operator<(const LoopEvent &obj) const 85 { 86 // as we use std::priority_queue, the event with smaller target time will be in the top of the queue 87 return (this->targetTime > obj.targetTime); 88 } 89 }; 90 91 class EventLoopPriorityQueue : public std::priority_queue<LoopEvent, std::vector<LoopEvent>> { 92 public: remove(uint64_t seq)93 bool remove(uint64_t seq) 94 { 95 auto it = std::find_if(this->c.begin(), this->c.end(), [seq](LoopEvent event) { 96 return event.seq == seq; 97 }); 98 99 if (it != this->c.end()) { 100 this->c.erase(it); 101 std::make_heap(this->c.begin(), this->c.end(), this->comp); 102 return true; 103 } else { 104 return false; 105 }; 106 }; 107 }; 108 109 class FileDescriptorEventCallback { 110 public: ~FileDescriptorEventCallback()111 virtual ~FileDescriptorEventCallback(){}; 112 #if defined(__HIVIEW_OHOS__) 113 virtual bool OnFileDescriptorEvent(int fd, int Type) = 0; 114 virtual int32_t GetPollFd() = 0; 115 virtual int32_t GetPollType() = 0; 116 #elif defined(_WIN32) 117 virtual bool OnHandleEvent(std::string fileName, DWORD action) = 0; 118 #endif 119 }; 120 class DllExport EventLoop { 121 public: 122 explicit EventLoop(const std::string &name); 123 virtual ~EventLoop(); 124 void StartLoop(bool createNewThread = true); 125 void StopLoop(); 126 127 // poll event from file descriptor source 128 // the interfaces may change on windows platform 129 bool AddFileDescriptorEventCallback(const std::string &name, std::shared_ptr<FileDescriptorEventCallback> source); 130 bool RemoveFileDescriptorEventCallback(const std::string &name); 131 132 // process event immediately 133 uint64_t AddEvent(std::shared_ptr<EventHandler> handler, std::shared_ptr<Event> event, const Task task = nullptr); 134 std::future<bool> AddEventForResult(std::shared_ptr<EventHandler> handler, std::shared_ptr<Event> event); 135 136 // process delayed event 137 // interval in seconds 138 uint64_t AddTimerEvent(std::shared_ptr<EventHandler> handler, std::shared_ptr<Event> event, const Task &task, 139 uint64_t interval, bool repeat); 140 bool RemoveEvent(uint64_t seq); 141 GetName()142 const std::string &GetName() const 143 { 144 return name_; 145 }; 146 IsRunning()147 bool IsRunning() const 148 { 149 return isRunning_; 150 }; 151 152 private: 153 // call from audit module GetHandlerInfo(const LoopEvent &)154 std::string GetHandlerInfo(const LoopEvent &) 155 { 156 return ""; 157 }; 158 159 bool InitEventQueueNotifier(); 160 void Run(); 161 void WakeUp(); 162 uint64_t ProcessQueuedEvent(); 163 void WaitNextEvent(uint64_t leftTimeMill); 164 bool FetchNextEvent(uint64_t now, uint64_t& leftTimeNanosecond, LoopEvent& event); 165 void ProcessEvent(LoopEvent &event); 166 void ReInsertPeriodicEvent(uint64_t now, LoopEvent &event); 167 void ResetTimerIfNeedLocked(); 168 uint64_t NanoSecondSinceSystemStart(); 169 volatile bool isWaken_ = false; 170 volatile bool needQuit_ = false; 171 volatile bool isRunning_ = false; 172 std::string name_; 173 EventLoopPriorityQueue pendingEvents_; 174 std::unique_ptr<std::thread> thread_; 175 std::mutex queueMutex_; 176 #if defined(__HIVIEW_OHOS__) 177 #ifdef USE_POLL 178 void ModifyFdStatus(); 179 void PollNextEvent(uint64_t timeout); 180 volatile bool modifyFdStatus_ = false; 181 int32_t eventQueueFd_[2] = {-1, -1}; // 2:event queue fd size 182 int32_t watchedFdSize_ = 1; 183 struct pollfd watchFds_[MAX_WATCHED_FDS]; 184 #else 185 UniqueFd pendingEventQueueFd_; 186 UniqueFd sharedPollingFd_; 187 #endif 188 std::map<int32_t, std::shared_ptr<FileDescriptorEventCallback>> eventSourceMap_; 189 std::map<std::string, int32_t> eventSourceNameMap_; 190 #elif defined(_WIN32) 191 HANDLE watchHandleList_[MAX_HANDLE_ARRAY_SIZE] = {NULL}; 192 #endif 193 uint64_t nextWakeupTime_; 194 std::atomic<LoopEvent *> currentProcessingEvent_; 195 }; 196 } // namespace HiviewDFX 197 } // namespace OHOS 198 #endif // HIVIEW_BASE_EVENT_LOOP_H