1 /*
2  * Copyright (c) 2021 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 FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_CANCELABEL_CALLBACK_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_CANCELABEL_CALLBACK_H
18 
19 #include <atomic>
20 #include <functional>
21 #include <future>
22 
23 #include "base/memory/referenced.h"
24 #include "base/utils/macros.h"
25 
26 namespace OHOS::Ace {
27 
28 using std::chrono_literals::operator""s;
29 using std::chrono_literals::operator""ms;
30 
31 using TaskThread = uint32_t;
32 constexpr TaskThread PLATFORM_TASK = 0;
33 constexpr TaskThread MAIN_TASK = 1;
34 constexpr TaskThread BACKGROUND_TASK = 1 << 1;
35 constexpr TaskThread UNDEFINED_TASK = 1 << 2;
36 
37 template<class>
38 class CancelableCallback;
39 
40 template<class... V>
41 class CancelableCallback<void(V...)> final {
42 public:
43     using FunctionType = std::function<void(V...)>;
44 
45     CancelableCallback() = default;
CancelableCallback(const FunctionType & callback)46     explicit CancelableCallback(const FunctionType& callback)
47         : impl_(callback ? Referenced::MakeRefPtr<Callback>(callback) : nullptr)
48     {}
CancelableCallback(FunctionType && callback)49     explicit CancelableCallback(FunctionType&& callback)
50         : impl_(callback ? Referenced::MakeRefPtr<Callback>(std::move(callback)) : nullptr)
51     {}
CancelableCallback(const FunctionType & callback,TaskThread taskThread)52     CancelableCallback(const FunctionType& callback, TaskThread taskThread)
53         : impl_(callback ? Referenced::MakeRefPtr<Callback>(callback) : nullptr), taskThread_(taskThread)
54     {}
CancelableCallback(FunctionType && callback,TaskThread taskThread)55     CancelableCallback(FunctionType&& callback, TaskThread taskThread)
56         : impl_(callback ? Referenced::MakeRefPtr<Callback>(std::move(callback)) : nullptr), taskThread_(taskThread)
57     {}
58     ~CancelableCallback() = default;
59 
SetTaskThreadType(TaskThread taskThread)60     void SetTaskThreadType(TaskThread taskThread) {}
61 
GetTaskThreadType()62     TaskThread GetTaskThreadType() const
63     {
64         return MAIN_TASK;
65     }
66 
67     void Reset(const FunctionType& callback, bool needCancel = true, bool waitUntilCompleted = false);
68     void Reset(FunctionType&& callback, bool needCancel = true, bool waitUntilCompleted = false);
69     bool WaitUntilComplete(std::chrono::milliseconds timeoutMs = 0ms);
70     bool Cancel(bool waitUntilCompleted = false);
71     void operator()(V&&... values) const;
72     operator bool() const
73     {
74         return impl_ && impl_->callback_;
75     }
76 
77 private:
78     enum : int32_t {
79         READY,
80         CANCELED,
81         RUNNING,
82         COMPLETED,
83     };
84 
85     struct Callback final : public Referenced {
Callbackfinal86         explicit Callback(const FunctionType& callback) : callback_(callback) {}
Callbackfinal87         explicit Callback(FunctionType&& callback) : callback_(std::move(callback)) {}
~Callbackfinal88         ~Callback() override
89         {
90             int32_t status = status_.load(std::memory_order_relaxed);
91             ACE_DCHECK(status != RUNNING);
92             if (status == READY) {
93                 promise_.set_value(CANCELED);
94             }
95         }
96 
97         FunctionType callback_;
98         std::atomic<int32_t> status_ { READY };
99         std::promise<int32_t> promise_;
100         std::shared_future<int32_t> future_ { promise_.get_future() };
101     };
102 
103     RefPtr<Callback> impl_;
104     TaskThread taskThread_ = MAIN_TASK;
105 };
106 
107 template<class... V>
Reset(const CancelableCallback<void (V...)>::FunctionType & callback,bool needCancel,bool waitUntilCompleted)108 void CancelableCallback<void(V...)>::Reset(
109     const CancelableCallback<void(V...)>::FunctionType& callback, bool needCancel, bool waitUntilCompleted)
110 {
111     if (needCancel) {
112         Cancel(waitUntilCompleted);
113     }
114     impl_ = callback ? Referenced::MakeRefPtr<Callback>(callback) : nullptr;
115 }
116 
117 template<class... V>
Reset(CancelableCallback<void (V...)>::FunctionType && callback,bool needCancel,bool waitUntilCompleted)118 void CancelableCallback<void(V...)>::Reset(
119     CancelableCallback<void(V...)>::FunctionType&& callback, bool needCancel, bool waitUntilCompleted)
120 {
121     if (needCancel) {
122         Cancel(waitUntilCompleted);
123     }
124     impl_ = callback ? Referenced::MakeRefPtr<Callback>(std::move(callback)) : nullptr;
125 }
126 
127 template<class... V>
WaitUntilComplete(std::chrono::milliseconds timeoutMs)128 bool CancelableCallback<void(V...)>::WaitUntilComplete(std::chrono::milliseconds timeoutMs)
129 {
130     RefPtr<Callback> impl(std::move(impl_));
131     if (!impl) {
132         return false;
133     }
134 
135     switch (impl->status_.load(std::memory_order_relaxed)) {
136         case READY:
137         case RUNNING: {
138             std::shared_future<int32_t> future(impl->future_);
139             if (timeoutMs != 0ms && std::future_status::timeout == future.wait_for(timeoutMs)) {
140                 CancelableCallback avatar(*this);
141                 avatar.impl_ = impl;
142                 avatar.Cancel(true);
143             }
144             impl.Reset();
145             return future.get() == COMPLETED;
146         }
147         case COMPLETED:
148             return true;
149         case CANCELED:
150         default:
151             return false;
152     }
153 }
154 
155 template<class... V>
Cancel(bool waitUntilCompleted)156 bool CancelableCallback<void(V...)>::Cancel(bool waitUntilCompleted)
157 {
158     RefPtr<Callback> impl(std::move(impl_));
159     if (!impl) {
160         return true;
161     }
162 
163     int32_t status = READY;
164     if (impl->status_.compare_exchange_strong(status, CANCELED, std::memory_order_relaxed)) {
165         impl->promise_.set_value(CANCELED);
166         return true;
167     } else if (status == CANCELED) {
168         return true;
169     }
170 
171     if (waitUntilCompleted && status == RUNNING) {
172         std::shared_future<int32_t> future(impl->future_);
173         impl.Reset();
174         status = future.get();
175         ACE_DCHECK(status == COMPLETED);
176     }
177     return false;
178 }
179 
180 template<class... V>
operator()181 void CancelableCallback<void(V...)>::operator()(V&&... values) const
182 {
183     RefPtr<Callback> impl(std::move(impl_));
184     if (!impl) {
185         return;
186     }
187 
188     int32_t status = READY;
189     if (impl->status_.compare_exchange_strong(status, RUNNING, std::memory_order_relaxed)) {
190         impl->callback_(std::forward<V>(values)...);
191         impl->status_.store(COMPLETED);
192         impl->promise_.set_value(COMPLETED);
193     }
194 }
195 
196 } // namespace OHOS::Ace
197 
198 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_CANCELABEL_CALLBACK_H
199