/* * Copyright (c) 2023 Huawei Device 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 HICORO_POLLER_H #define HICORO_POLLER_H #ifndef _MSC_VER #include #include #endif #include #include #include #include #include "qos.h" #include "sync/sync.h" #include "internal_inc/non_copyable.h" #include "c/executor_task.h" #include "c/timer.h" #include "eu/worker_thread.h" namespace ffrt { enum class PollerRet { RET_NULL, RET_EPOLL, RET_TIMER, }; enum class EpollStatus { WAIT, WAKE, TEARDOWN, }; enum class TimerStatus { EXECUTING, EXECUTED, }; constexpr int EPOLL_EVENT_SIZE = 1024; struct WakeDataWithCb { WakeDataWithCb() {} WakeDataWithCb(int fdVal, void *dataVal, std::function cbVal, CPUEUTask *taskVal) : fd(fdVal), data(dataVal), cb(cbVal), task(taskVal) {} int fd = 0; void* data = nullptr; std::function cb = nullptr; CPUEUTask* task = nullptr; uint32_t monitorEvents = 0; }; struct TimerDataWithCb { TimerDataWithCb() {} TimerDataWithCb(void *dataVal, void (*cbVal)(void *), CPUEUTask *taskVal, bool repeat, uint64_t timeout) : data(dataVal), cb(cbVal), task(taskVal), repeat(repeat), timeout(timeout) {} void* data = nullptr; void(*cb)(void*) = nullptr; int handle = -1; CPUEUTask* task = nullptr; bool repeat = false; uint64_t timeout = 0; }; struct SyncData { SyncData() {} SyncData(void *eventsPtr, int maxEvents, int *nfdsPtr, TimePoint waitTP) : eventsPtr(eventsPtr), maxEvents(maxEvents), nfdsPtr(nfdsPtr), waitTP(waitTP) {} void* eventsPtr = nullptr; int maxEvents = 0; int* nfdsPtr = nullptr; TimePoint waitTP; int timerHandle = -1; }; using EventVec = typename std::vector; class Poller : private NonCopyable { using WakeDataList = typename std::list>; public: Poller() noexcept; ~Poller() noexcept; int AddFdEvent(int op, uint32_t events, int fd, void* data, ffrt_poller_cb cb) noexcept; int DelFdEvent(int fd) noexcept; int WaitFdEvent(struct epoll_event *eventsVec, int maxevents, int timeout) noexcept; PollerRet PollOnce(int timeout = -1) noexcept; void WakeUp() noexcept; int RegisterTimer(uint64_t timeout, void* data, ffrt_timer_cb cb, bool repeat = false) noexcept; int UnregisterTimer(int handle) noexcept; ffrt_timer_query_t GetTimerStatus(int handle) noexcept; uint64_t GetPollCount() noexcept; uint64_t GetTaskWaitTime(CPUEUTask* task) noexcept; bool DetermineEmptyMap() noexcept; bool DeterminePollerReady() noexcept; void ClearCachedEvents(CPUEUTask* task) noexcept; private: void ReleaseFdWakeData() noexcept; void WakeSyncTask(std::unordered_map& syncTaskEvents) noexcept; void ProcessWaitedFds(int nfds, std::unordered_map& syncTaskEvents, std::array& waitedEvents) noexcept; void ExecuteTimerCb(TimePoint timer) noexcept; void ProcessTimerDataCb(CPUEUTask* task) noexcept; void RegisterTimerImpl(const TimerDataWithCb& data) noexcept; void CacheEventsAndDoMask(CPUEUTask* task, EventVec& eventVec) noexcept; int FetchCachedEventAndDoUnmask(CPUEUTask* task, struct epoll_event* eventsVec) noexcept; int FetchCachedEventAndDoUnmask(EventVec& cachedEventsVec, struct epoll_event* eventsVec) noexcept; inline void CacheDelFd(int fd, CPUEUTask *task) noexcept { m_delFdCacheMap.emplace(fd, task); } inline void CacheMaskWakeData(CPUEUTask* task, std::unique_ptr& maskWakeData) noexcept { m_maskWakeDataWithCbMap[task].emplace_back(std::move(maskWakeData)); } void CacheMaskFdAndEpollDel(int fd, CPUEUTask *task) noexcept; int ClearMaskWakeDataWithCbCache(CPUEUTask *task) noexcept; int ClearMaskWakeDataWithCbCache(CPUEUTask *task, int fd) noexcept; int ClearDelFdCache(int fd) noexcept; bool IsFdExist() noexcept; bool IsTimerReady() noexcept; int m_epFd; std::atomic pollerCount_ = 0; int timerHandle_ = -1; std::atomic flag_ = EpollStatus::WAKE; struct WakeDataWithCb m_wakeData; std::unordered_map m_wakeDataMap; std::unordered_map m_delCntMap; std::unordered_map m_waitTaskMap; std::unordered_map m_cachedTaskEvents; std::unordered_map m_delFdCacheMap; std::unordered_map m_maskWakeDataWithCbMap; std::unordered_map executedHandle_; std::multimap timerMap_; std::atomic_bool fdEmpty_ {true}; std::atomic_bool timerEmpty_ {true}; mutable spin_mutex m_mapMutex; mutable spin_mutex timerMutex_; }; struct PollerProxy { public: static PollerProxy& Instance(); Poller& GetPoller(const QoS& qos = QoS(ffrt_qos_default)) { return qosPollers[static_cast(qos())]; } private: std::array qosPollers; }; } // namespace ffrt #endif