• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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