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 __WAITQUEUE_H__ 17 #define __WAITQUEUE_H__ 18 #include "sync.h" 19 #include "cpp/mutex.h" 20 #include "sched/execute_ctx.h" 21 #include "util/IntrusiveList.h" 22 #include "sync/mutex_private.h" 23 #include "dfx/log/ffrt_log_api.h" 24 25 namespace ffrt { 26 class CPUEUTask; 27 struct TaskWithNode; 28 using TaskListNode = ListNode; 29 using TaskList = List<TaskWithNode, TaskListNode>; 30 31 struct TaskTimeOutStatus { TaskTimeOutStatusTaskTimeOutStatus32 explicit TaskTimeOutStatus(TaskTimeoutState state) : status(state) 33 { 34 } 35 TaskTimeoutState status; 36 std::mutex lock; 37 }; 38 39 enum class TimeoutState { 40 IDLE, 41 WAITING, 42 TIMEOUTING, 43 DONE, 44 }; 45 46 struct TimeoutStatus { TimeoutStatusTimeoutStatus47 explicit TimeoutStatus(TimeoutState state) : status(state) 48 { 49 } 50 TimeoutState status; 51 mutex lock; 52 }; 53 54 struct TaskWithNode : public TaskListNode { 55 TaskWithNode(); 56 CPUEUTask* task = nullptr; 57 std::mutex lk; 58 std::condition_variable cv; 59 }; 60 61 class WaitQueue { 62 public: 63 using TimePoint = std::chrono::steady_clock::time_point; 64 void SuspendAndWait(mutexPrivate* lk); 65 bool SuspendAndWaitUntil(mutexPrivate* lk, const TimePoint& tp) noexcept; NotifyAll()66 void NotifyAll() noexcept { Notify(false); } NotifyOne()67 void NotifyOne() noexcept { Notify(true); } 68 WaitQueue()69 WaitQueue() 70 { 71 whead = new WaitUntilEntry(); 72 whead->next = whead; 73 whead->prev = whead; 74 } 75 WaitQueue(WaitQueue const&) = delete; 76 void operator=(WaitQueue const&) = delete; 77 ~WaitQueue()78 ~WaitQueue() 79 { 80 wqlock.lock(); 81 ReleaseAll(); 82 delete whead; 83 whead = nullptr; 84 wqlock.unlock(); 85 } 86 87 private: 88 spin_mutex wqlock; 89 WaitUntilEntry* whead; 90 91 private: 92 bool WeNotifyProc(WaitUntilEntry* we); 93 void ThreadWait(WaitUntilEntry* wn, mutexPrivate* lk, bool legacyMode, CPUEUTask* task); 94 bool ThreadWaitUntil(WaitUntilEntry* wn, mutexPrivate* lk, const TimePoint& tp, bool legacyMode, CPUEUTask* task); 95 void Notify(bool one) noexcept; 96 empty()97 inline bool empty() const 98 { 99 if (whead == nullptr) { 100 return true; 101 } 102 return (whead->next == whead); 103 } 104 ReleaseAll()105 void ReleaseAll() 106 { 107 while (!empty()) { 108 FFRT_LOGE("There are still tasks in cv that have not been awakened"); 109 WaitUntilEntry *wue = pop_front(); 110 (void)WeNotifyProc(wue); 111 } 112 } 113 push_back(WaitUntilEntry * we)114 inline void push_back(WaitUntilEntry* we) 115 { 116 if ((we == nullptr) || (whead == nullptr) || (whead->prev == nullptr)) { 117 FFRT_LOGE("we or whead or whead->prev is nullptr"); 118 return; 119 } 120 we->next = whead; 121 we->prev = whead->prev; 122 whead->prev->next = we; 123 whead->prev = we; 124 } 125 pop_front()126 inline WaitUntilEntry* pop_front() 127 { 128 if ((whead->next == nullptr) || (whead->next->next == nullptr)) { 129 FFRT_LOGE("whead->next or whead->next->next is nullptr"); 130 return nullptr; 131 } 132 WaitEntry *we = whead->next; 133 whead->next = we->next; 134 we->next->prev = whead; 135 we->next = nullptr; 136 we->prev = nullptr; 137 return static_cast<WaitUntilEntry*>(we); 138 } 139 remove(WaitUntilEntry * we)140 inline void remove(WaitUntilEntry* we) 141 { 142 if ((we->next == nullptr) || (we->prev == nullptr)) { 143 return; 144 } 145 we->prev->next = we->next; 146 we->next->prev = we->prev; 147 we->next = nullptr; 148 we->prev = nullptr; 149 return; 150 } 151 friend bool WeTimeoutProc(WaitQueue* wq, WaitUntilEntry* wue); 152 }; 153 } // namespace ffrt 154 #endif // _WAITQUEUE_H_ 155