1 /*
2  * Copyright (c) 2023 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 
16 #ifndef HICORO_POLLER_H
17 #define HICORO_POLLER_H
18 #ifndef _MSC_VER
19 #include <sys/epoll.h>
20 #include <sys/eventfd.h>
21 #endif
22 #include <list>
23 #include <map>
24 #include <unordered_map>
25 #include <array>
26 #include "qos.h"
27 #include "sync/sync.h"
28 #include "internal_inc/non_copyable.h"
29 #include "c/executor_task.h"
30 #include "c/timer.h"
31 #include "eu/worker_thread.h"
32 namespace ffrt {
33 enum class PollerRet {
34     RET_NULL,
35     RET_EPOLL,
36     RET_TIMER,
37 };
38 
39 enum class EpollStatus {
40     WAIT,
41     WAKE,
42     TEARDOWN,
43 };
44 
45 enum class TimerStatus {
46     EXECUTING,
47     EXECUTED,
48 };
49 
50 constexpr int EPOLL_EVENT_SIZE = 1024;
51 
52 struct WakeDataWithCb {
WakeDataWithCbWakeDataWithCb53     WakeDataWithCb() {}
WakeDataWithCbWakeDataWithCb54     WakeDataWithCb(int fdVal, void *dataVal, std::function<void(void *, uint32_t)> cbVal, CPUEUTask *taskVal)
55         : fd(fdVal), data(dataVal), cb(cbVal), task(taskVal)
56     {}
57 
58     int fd = 0;
59     void* data = nullptr;
60     std::function<void(void*, uint32_t)> cb = nullptr;
61     CPUEUTask* task = nullptr;
62     uint32_t monitorEvents = 0;
63 };
64 
65 struct TimerDataWithCb {
TimerDataWithCbTimerDataWithCb66     TimerDataWithCb() {}
TimerDataWithCbTimerDataWithCb67     TimerDataWithCb(void *dataVal, void (*cbVal)(void *), CPUEUTask *taskVal, bool repeat, uint64_t timeout)
68         : data(dataVal), cb(cbVal), task(taskVal), repeat(repeat), timeout(timeout)
69     {}
70 
71     void* data = nullptr;
72     void(*cb)(void*) = nullptr;
73     int handle = -1;
74     CPUEUTask* task = nullptr;
75     bool repeat = false;
76     uint64_t timeout = 0;
77 };
78 
79 struct SyncData {
SyncDataSyncData80     SyncData() {}
SyncDataSyncData81     SyncData(void *eventsPtr, int maxEvents, int *nfdsPtr, TimePoint waitTP)
82         : eventsPtr(eventsPtr), maxEvents(maxEvents), nfdsPtr(nfdsPtr), waitTP(waitTP)
83     {}
84 
85     void* eventsPtr = nullptr;
86     int maxEvents = 0;
87     int* nfdsPtr = nullptr;
88     TimePoint waitTP;
89 };
90 
91 using EventVec = typename std::vector<epoll_event>;
92 class Poller : private NonCopyable {
93     using WakeDataList = typename std::list<std::unique_ptr<struct WakeDataWithCb>>;
94 public:
95     Poller() noexcept;
96     ~Poller() noexcept;
97 
98     int AddFdEvent(int op, uint32_t events, int fd, void* data, ffrt_poller_cb cb) noexcept;
99     int DelFdEvent(int fd) noexcept;
100     int WaitFdEvent(struct epoll_event *eventsVec, int maxevents, int timeout) noexcept;
101 
102     PollerRet PollOnce(int timeout = -1) noexcept;
103     void WakeUp() noexcept;
104 
105     int RegisterTimer(uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat = false) noexcept;
106     int UnregisterTimer(int handle) noexcept;
107     ffrt_timer_query_t GetTimerStatus(int handle) noexcept;
108 
109     uint8_t GetPollCount() noexcept;
110 
111     uint64_t GetTaskWaitTime(CPUEUTask* task) noexcept;
112 
113     bool DetermineEmptyMap() noexcept;
114     bool DeterminePollerReady() noexcept;
115 
116     void ClearCachedEvents(CPUEUTask* task) noexcept;
117 
118 private:
119     void ReleaseFdWakeData() noexcept;
120     void WakeSyncTask(std::unordered_map<CPUEUTask*, EventVec>& syncTaskEvents) noexcept;
121     void ProcessWaitedFds(int nfds, std::unordered_map<CPUEUTask*, EventVec>& syncTaskEvents,
122                           std::array<epoll_event, EPOLL_EVENT_SIZE>& waitedEvents) noexcept;
123 
124     void ExecuteTimerCb(TimePoint timer) noexcept;
125     void ProcessTimerDataCb(CPUEUTask* task) noexcept;
126     void RegisterTimerImpl(const TimerDataWithCb& data) noexcept;
127 
128     void CacheEventsAndDoMask(CPUEUTask* task, EventVec& eventVec) noexcept;
129     int FetchCachedEventAndDoUnmask(CPUEUTask* task, struct epoll_event* eventsVec) noexcept;
130     int FetchCachedEventAndDoUnmask(EventVec& cachedEventsVec, struct epoll_event* eventsVec) noexcept;
131 
132     bool IsFdExist() noexcept;
133     bool IsTimerReady() noexcept;
134 
135     int m_epFd;
136     uint8_t pollerCount_ = 0;
137     int timerHandle_ = -1;
138     EpollStatus flag_ = EpollStatus::WAKE;
139     struct WakeDataWithCb m_wakeData;
140     std::unordered_map<int, WakeDataList> m_wakeDataMap;
141     std::unordered_map<int, int> m_delCntMap;
142     std::unordered_map<CPUEUTask*, SyncData> m_waitTaskMap;
143     std::unordered_map<CPUEUTask*, EventVec> m_cachedTaskEvents;
144 
145     std::unordered_map<int, TimerStatus> executedHandle_;
146     std::multimap<TimePoint, TimerDataWithCb> timerMap_;
147     std::atomic_bool fdEmpty_ {true};
148     std::atomic_bool timerEmpty_ {true};
149     mutable spin_mutex m_mapMutex;
150     mutable spin_mutex timerMutex_;
151 };
152 
153 struct PollerProxy {
154 public:
155     static PollerProxy& Instance();
156 
157     Poller& GetPoller(const QoS& qos = QoS(ffrt_qos_default))
158     {
159         return qosPollers[static_cast<size_t>(qos())];
160     }
161 
162 private:
163     std::array<Poller, QoS::MaxNum()> qosPollers;
164 };
165 } // namespace ffrt
166 #endif