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 24 namespace ffrt { 25 struct TaskCtx; 26 struct TaskWithNode; 27 using TaskListNode = ListNode; 28 using TaskList = List<TaskWithNode, TaskListNode>; 29 30 struct TaskTimeOutStatus { TaskTimeOutStatusTaskTimeOutStatus31 explicit TaskTimeOutStatus(TaskTimeoutState state) : status(state) 32 { 33 } 34 TaskTimeoutState status; 35 std::mutex lock; 36 }; 37 38 enum class TimeoutState { 39 IDLE, 40 WAITING, 41 TIMEOUTING, 42 DONE, 43 }; 44 45 struct TimeoutStatus { TimeoutStatusTimeoutStatus46 explicit TimeoutStatus(TimeoutState state) : status(state) 47 { 48 } 49 TimeoutState status; 50 mutex lock; 51 }; 52 53 struct TaskWithNode : public TaskListNode { 54 TaskWithNode(); 55 TaskCtx* task = nullptr; 56 std::mutex lk; 57 std::condition_variable cv; 58 }; 59 60 class WaitQueue { 61 public: 62 spin_mutex wqlock; 63 WaitUntilEntry* whead; 64 using TimePoint = std::chrono::steady_clock::time_point; 65 void SuspendAndWait(mutexPrivate* lk); 66 bool SuspendAndWaitUntil(mutexPrivate* lk, const TimePoint& tp) noexcept; 67 bool WeNotifyProc(WaitUntilEntry* we); 68 void NotifyAll() noexcept; 69 void NotifyOne() noexcept; 70 void ThreadWait(WaitUntilEntry* wn, mutexPrivate* lk); 71 bool ThreadWaitUntil(WaitUntilEntry* wn, mutexPrivate* lk, const TimePoint& tp); WaitQueue()72 WaitQueue() 73 { 74 whead = new WaitUntilEntry(); 75 whead->next = whead; 76 whead->prev = whead; 77 } 78 WaitQueue(WaitQueue const&) = delete; 79 void operator=(WaitQueue const&) = delete; 80 ~WaitQueue()81 ~WaitQueue() 82 { 83 wqlock.lock(); 84 while (!empty()) { 85 WaitUntilEntry *wue = pop_front(); 86 (void)WeNotifyProc(wue); 87 } 88 wqlock.unlock(); 89 delete whead; 90 } 91 92 private: empty()93 inline bool empty() const 94 { 95 return (whead->next == whead); 96 } 97 push_back(WaitUntilEntry * we)98 inline void push_back(WaitUntilEntry* we) 99 { 100 we->next = whead; 101 we->prev = whead->prev; 102 whead->prev->next = we; 103 whead->prev = we; 104 } 105 pop_front()106 inline WaitUntilEntry* pop_front() 107 { 108 WaitEntry *we = whead->next; 109 if (we->next == nullptr) { 110 return nullptr; 111 } 112 whead->next = we->next; 113 we->next->prev = whead; 114 we->next = nullptr; 115 we->prev = nullptr; 116 return static_cast<WaitUntilEntry*>(we); 117 } 118 remove(WaitUntilEntry * we)119 inline void remove(WaitUntilEntry* we) 120 { 121 if ((we->next == nullptr) || (we->prev == nullptr)) { 122 return; 123 } 124 we->prev->next = we->next; 125 we->next->prev = we->prev; 126 we->next = nullptr; 127 we->prev = nullptr; 128 return; 129 } 130 }; 131 } // namespace ffrt 132 #endif // _WAITQUEUE_H_ 133