1 /* 2 * Copyright (c) 2024-2025 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 LIBPANDABASE_TASKMANAGER_UTILS_WAIT_LIST_H 17 #define LIBPANDABASE_TASKMANAGER_UTILS_WAIT_LIST_H 18 19 #include "libpandabase/utils/time.h" 20 #include <algorithm> 21 #include "libpandabase/os/mutex.h" 22 #include <atomic> 23 #include <functional> 24 #include <optional> 25 #include <list> 26 #include <limits> 27 28 namespace ark::taskmanager { 29 30 using WaiterId = size_t; 31 inline constexpr WaiterId INVALID_WAITER_ID = 0U; 32 33 template <class T> 34 class WaitList { 35 class WaitValue { 36 public: WaitValue(T && value,uint64_t targetTime,size_t id)37 WaitValue(T &&value, uint64_t targetTime, size_t id) 38 : value_(std::move(value)), targetTime_(targetTime), id_(id) 39 { 40 } 41 DEFAULT_MOVE_SEMANTIC(WaitValue); 42 NO_COPY_SEMANTIC(WaitValue); 43 ~WaitValue() = default; 44 GetValue()45 T &&GetValue() 46 { 47 return std::move(value_); 48 } 49 GetValue()50 const T &GetValue() const 51 { 52 return value_; 53 } 54 GetTargetTime()55 uint64_t GetTargetTime() const 56 { 57 return targetTime_; 58 } 59 SetTargetTime(uint64_t newTargetTime)60 void SetTargetTime(uint64_t newTargetTime) 61 { 62 targetTime_ = newTargetTime; 63 } 64 GetId()65 WaiterId GetId() const 66 { 67 return id_; 68 } 69 70 private: 71 T value_; 72 uint64_t targetTime_; 73 WaiterId id_; 74 }; 75 76 public: 77 /** 78 * @returns value with targetTime less than or equal to current time. If such a value doesn't exist returns 79 * std::nullopt. 80 */ GetReadyValue()81 std::optional<T> GetReadyValue() 82 { 83 os::memory::WriteLockHolder wlh(lock_); 84 auto currentTime = time::GetCurrentTimeInMillis(true); 85 for (auto iter = waitList_.begin(); iter != waitList_.end(); iter = next(iter)) { 86 if (currentTime >= iter->GetTargetTime()) { 87 T value = iter->GetValue(); 88 waitList_.erase(iter); 89 return value; 90 } 91 } 92 return std::nullopt; 93 } 94 95 template <class Callback> ProcessWaitList(Callback callback)96 size_t ProcessWaitList(Callback callback) 97 { 98 static constexpr size_t BUFFER_MAX_SIZE = 128U; 99 std::array<T, BUFFER_MAX_SIZE> bufferOfElems {}; 100 size_t sizeOfBuffer = 0; 101 { 102 os::memory::WriteLockHolder wlh(lock_); 103 auto currentTime = time::GetCurrentTimeInMillis(true); 104 auto iter = waitList_.begin(); 105 while (iter != waitList_.end() && sizeOfBuffer < BUFFER_MAX_SIZE) { 106 if (currentTime >= iter->GetTargetTime()) { 107 bufferOfElems[sizeOfBuffer++] = iter->GetValue(); 108 iter = waitList_.erase(iter); 109 } else { 110 iter = next(iter); 111 } 112 } 113 } 114 for (size_t i = 0; i < sizeOfBuffer; i++) { 115 callback(std::move(bufferOfElems[i])); 116 } 117 return sizeOfBuffer; 118 } 119 120 /// @returns true if there is a value with a targetTime less or equal to current time. Otherwise false. HaveReadyValue()121 bool HaveReadyValue() const 122 { 123 os::memory::ReadLockHolder rlh(lock_); 124 auto currentTime = time::GetCurrentTimeInMillis(true); 125 for (auto iter = waitList_.begin(); iter != waitList_.end(); iter = next(iter)) { 126 if (currentTime >= iter->GetTargetTime()) { 127 return true; 128 } 129 } 130 return false; 131 } 132 133 /// @brief adds value in waitQueues_ with timeToWait if it's setted. 134 WaiterId AddValueToWait(T value, uint64_t timeToWait = std::numeric_limits<uint64_t>().max()) 135 { 136 os::memory::WriteLockHolder wlh(lock_); 137 addCounter_++; 138 uint64_t currentTime = time::GetCurrentTimeInMillis(true); 139 uint64_t targetTime = 0; 140 141 // Check if we need to set max possible time 142 if (std::numeric_limits<uint64_t>().max() - timeToWait < currentTime) { 143 targetTime = std::numeric_limits<uint64_t>().max(); 144 } else { 145 targetTime = currentTime + timeToWait; 146 } 147 148 waitList_.emplace_back(std::move(value), targetTime, addCounter_); 149 return waitList_.back().GetId(); 150 } 151 152 /// @returns value with specified WaiterId. It it doesn't exists returns std::nullopt. GetValueById(WaiterId id)153 std::optional<T> GetValueById(WaiterId id) 154 { 155 os::memory::WriteLockHolder wlh(lock_); 156 auto waitValue = 157 std::find_if(waitList_.begin(), waitList_.end(), [id](const auto &value) { return value.GetId() == id; }); 158 if (waitValue == waitList_.end()) { 159 return std::nullopt; 160 } 161 auto val = waitValue->GetValue(); 162 waitList_.erase(waitValue); 163 return val; 164 } 165 166 private: 167 std::list<WaitValue> waitList_; 168 size_t addCounter_ = 0U; 169 os::memory::RWLock mutable lock_; 170 }; 171 172 } // namespace ark::taskmanager 173 174 #endif // LIBPANDABASE_TASKMANAGER_UTILS_WAIT_LIST_H 175