1 /*
2  * Copyright (c) 2021-2024 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 <atomic>
18 #include <future>
19 #include <map>
20 #include <memory>
21 
22 #include <sys/types.h>
23 
24 #include "defines.h"
25 #include "event.h"
26 #include "event_priority_queue.h"
27 
28 #if defined(__HIVIEW_OHOS__)
29 #include "unique_fd.h"
30 #ifdef USE_POLL
31 #include <poll.h>
32 #endif
33 #elif defined(_WIN32)
34 #include <Windows.h>
35 #include <winnt.h>
36 #endif
37 
38 namespace OHOS {
39 namespace HiviewDFX {
40 constexpr int LOOP_WAKEUP_HANDLE_INDEX = 0;
41 constexpr int MAX_EVENT_SIZE = 16;
42 constexpr int MAX_HANDLE_ARRAY_SIZE = 1;
43 constexpr int MAX_WATCHED_FDS = 64;
44 
45 enum LoopEventType {
46     LOOP_EVENT_TASK,
47     LOOP_PACKAGED_TASK,
48 };
49 struct LoopEvent {
50     bool isRepeat = false;
51     uint8_t taskType = 0;
52     uint64_t seq = 0;
53     uint64_t interval = 0;
54     uint64_t enqueueTime = 0;
55     uint64_t targetTime = 0;
56     std::shared_ptr<Event> event = nullptr;
57     std::shared_ptr<EventHandler> handler = nullptr;
58     Task task = nullptr;
59     std::shared_ptr<std::packaged_task<bool()>> packagedTask = nullptr;
60 
CreateLoopEventLoopEvent61     static LoopEvent CreateLoopEvent(uint64_t now)
62     {
63         LoopEvent event;
64         event.isRepeat = false;
65         event.taskType = LOOP_EVENT_TASK;
66         event.seq = now;
67         event.interval = 0;
68         event.enqueueTime = now;
69         event.targetTime = now;
70         event.event = nullptr;
71         event.handler = nullptr;
72         event.task = nullptr;
73         event.packagedTask = nullptr;
74         return event;
75     }
76 
77     bool operator<(const LoopEvent &obj) const
78     {
79         // as we use std::priority_queue, the event with smaller target time will be in the top of the queue
80         return (this->targetTime > obj.targetTime);
81     }
82 };
83 
84 class FileDescriptorEventCallback {
85 public:
~FileDescriptorEventCallback()86     virtual ~FileDescriptorEventCallback(){};
87 #if defined(__HIVIEW_OHOS__)
88     virtual bool OnFileDescriptorEvent(int fd, int Type) = 0;
89     virtual int32_t GetPollFd() = 0;
90     virtual int32_t GetPollType() = 0;
91 #elif defined(_WIN32)
92     virtual bool OnHandleEvent(std::string fileName, DWORD action) = 0;
93 #endif
94 };
95 class DllExport EventLoop {
96 public:
97     explicit EventLoop(const std::string &name);
98     virtual ~EventLoop();
99     void StartLoop(bool createNewThread = true);
100     void StopLoop();
101 
102     // poll event from file descriptor source
103     // the interfaces may change on windows platform
104     bool AddFileDescriptorEventCallback(const std::string &name, std::shared_ptr<FileDescriptorEventCallback> source);
105     bool RemoveFileDescriptorEventCallback(const std::string &name);
106 
107     // process event immediately
108     uint64_t AddEvent(std::shared_ptr<EventHandler> handler, std::shared_ptr<Event> event, const Task task = nullptr);
109     std::future<bool> AddEventForResult(std::shared_ptr<EventHandler> handler, std::shared_ptr<Event> event);
110 
111     // process delayed event
112     // interval in seconds
113     virtual uint64_t AddTimerEvent(std::shared_ptr<EventHandler> handler, std::shared_ptr<Event> event,
114                                    const Task &task, uint64_t interval, bool repeat);
115     bool RemoveEvent(uint64_t seq);
116 
117     std::string GetRawName() const;
118 
GetName()119     const std::string &GetName() const
120     {
121         return name_;
122     };
123 
IsRunning()124     bool IsRunning() const
125     {
126         return isRunning_;
127     };
128 
129 private:
130     // call from audit module
GetHandlerInfo(const LoopEvent &)131     std::string GetHandlerInfo(const LoopEvent &)
132     {
133         return "";
134     };
135 
136     bool InitEventQueueNotifier();
137     void InitThreadName();
138     void Run();
139     void WakeUp();
140     uint64_t ProcessQueuedEvent();
141     void WaitNextEvent(uint64_t leftTimeMill);
142     bool FetchNextEvent(uint64_t now, uint64_t& leftTimeNanosecond, LoopEvent& event);
143     void ProcessEvent(LoopEvent &event);
144     void ReInsertPeriodicEvent(uint64_t now, LoopEvent &event);
145     void ResetTimerIfNeedLocked();
146     uint64_t NanoSecondSinceSystemStart();
147     volatile bool isWaken_ = false;
148     volatile bool needQuit_ = false;
149     volatile bool isRunning_ = false;
150     std::string name_;
151     EventPriorityQueue<LoopEvent> pendingEvents_;
152     std::unique_ptr<std::thread> thread_;
153     std::mutex queueMutex_;
154 #if defined(__HIVIEW_OHOS__)
155 #ifdef USE_POLL
156     void ModifyFdStatus();
157     void PollNextEvent(uint64_t timeout);
158     volatile bool modifyFdStatus_ = false;
159     int32_t eventQueueFd_[2] = {-1, -1}; // 2:event queue fd size
160     int32_t watchedFdSize_ = 1;
161     struct pollfd watchFds_[MAX_WATCHED_FDS];
162 #else
163     UniqueFd pendingEventQueueFd_;
164     UniqueFd sharedPollingFd_;
165 #endif
166     std::map<int32_t, std::shared_ptr<FileDescriptorEventCallback>> eventSourceMap_;
167     std::map<std::string, int32_t> eventSourceNameMap_;
168 #elif defined(_WIN32)
169     HANDLE watchHandleList_[MAX_HANDLE_ARRAY_SIZE] = {NULL};
170 #endif
171     uint64_t nextWakeupTime_;
172     std::atomic<LoopEvent *> currentProcessingEvent_;
173 };
174 }  // namespace HiviewDFX
175 }  // namespace OHOS
176 #endif  // HIVIEW_BASE_EVENT_LOOP_H