• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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