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_TASK_EXECUTOR_H 17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_TASK_EXECUTOR_H 18 19 #include <cstdint> 20 #include <functional> 21 22 #include "base/memory/ace_type.h" 23 #include "base/thread/cancelable_callback.h" 24 #include "base/utils/noncopyable.h" 25 #include "base/log/log.h" 26 27 #ifndef __has_builtin 28 #define __has_builtin(x) 0 29 #endif 30 31 namespace OHOS::Ace { 32 struct Caller final { 33 #if __has_builtin(__builtin_FILE) 34 Caller(std::string file = __builtin_FILE(), int line = __builtin_LINE(), std::string func = __builtin_FUNCTION()) file_final35 : file_(file), line_(line), func_(func) 36 { 37 if (!file_.empty()) { 38 size_t split = file_.find_last_of("/\\"); 39 if (split == std::string::npos) { 40 split = 0; 41 } 42 caller_ = std::string("[" + file_.substr(split + 1) + "(" + func_ + ":" + std::to_string(line_) + ")]"); 43 } 44 } 45 #else 46 Caller() { 47 } 48 #endif 49 50 std::string file_; 51 int32_t line_ = 0; 52 std::string func_; 53 std::string caller_ = "[]"; 54 }; 55 56 class TaskExecutor : public AceType { 57 DECLARE_ACE_TYPE(TaskExecutor, AceType); 58 ACE_DISALLOW_COPY_AND_MOVE(TaskExecutor); 59 60 public: 61 using Task = std::function<void()>; 62 using CancelableTask = CancelableCallback<void()>; 63 64 static constexpr int32_t TASK_TYPE_SIZE = 7; 65 enum class TaskType : uint32_t { 66 PLATFORM = 0, 67 UI, 68 IO, 69 GPU, 70 JS, 71 BACKGROUND, 72 UNKNOWN, 73 }; 74 75 ~TaskExecutor() override = default; 76 77 /** 78 * Post a task to the specified thread. 79 * 80 * @param task Task which need execution. 81 * @param type FrontendType of task, used to specify the thread. 82 * @return Returns 'true' whether task has been post successfully. 83 */ 84 bool PostTask(Task&& task, TaskType type, const Caller& caller = {}) const 85 { 86 return PostDelayedTask(std::move(task), type, 0, caller); 87 } 88 89 /** 90 * Post a task to the specified thread. 91 * 92 * @param task Task which need execution. 93 * @param type FrontendType of task, used to specify the thread. 94 * @return Returns 'true' if task has been posted successfully. 95 */ 96 bool PostTask(const Task& task, TaskType type, const Caller& caller = {}) const 97 { 98 return PostDelayedTask(task, type, 0, caller); 99 } 100 101 /** 102 * Post a task to the specified thread with a trace id. 103 * 104 * @param task Task which need execution. 105 * @param type FrontendType of task, used to specify the thread. 106 * @param id The id to trace the task. 107 * @return Returns 'true' whether task has been post successfully. 108 */ 109 bool PostTaskWithTraceId(Task&& task, TaskType type, int32_t id, const Caller& caller = {}) const 110 { 111 Task wrappedTask = WrapTaskWithTraceId(std::move(task), id); 112 return PostDelayedTask(std::move(wrappedTask), type, 0, caller); 113 } 114 115 /** 116 * Post a task to the specified thread. 117 * 118 * @param task Task which need execution. 119 * @param type FrontendType of task, used to specify the thread. 120 * @param id The id to trace the task. 121 * @return Returns 'true' if task has been posted successfully. 122 */ 123 bool PostTaskWithTraceId(const Task& task, TaskType type, int32_t id, const Caller& caller = {}) const 124 { 125 Task wrappedTask = WrapTaskWithTraceId(Task(task), id); 126 return PostDelayedTask(std::move(wrappedTask), type, 0, caller); 127 } 128 129 /** 130 * Post a delayed task to the specified thread. 131 * Never allow to post a background delayed task. 132 * 133 * @param task Task which need execution. 134 * @param type FrontendType of task, used to specify the thread. 135 * @param delayTime Wait a period of time in milliseconds before execution. 136 * @return Returns 'true' if task has been posted successfully. 137 */ 138 bool PostDelayedTask(Task&& task, TaskType type, uint32_t delayTime, const Caller& caller = {}) const 139 { 140 if (delayTime > 0 && type == TaskType::BACKGROUND) { 141 return false; 142 } 143 return OnPostTask(std::move(task), type, delayTime, caller.caller_); 144 } 145 146 /** 147 * Post a delayed task to the specified thread. 148 * Never allow to post a background delayed task. 149 * 150 * @param task Task which need execution. 151 * @param type FrontendType of task, used to specify the thread. 152 * @param delayTime Wait a period of time in milliseconds before execution. 153 * @return Returns 'true' if task has been posted successfully. 154 */ 155 bool PostDelayedTask(const Task& task, TaskType type, uint32_t delayTime, const Caller& caller = {}) const 156 { 157 return PostDelayedTask(Task(task), type, delayTime, caller); 158 } 159 160 /** 161 * Post a task to the specified thread and wait until finished executing. 162 * Never allow to post a background synchronous task. 163 * 164 * @param task Task which need execution. 165 * @param type FrontendType of task, used to specify the thread. 166 * @return Returns 'true' whether task has been executed. 167 */ 168 bool PostSyncTask(Task&& task, TaskType type, const Caller& caller = {}) const 169 { 170 if (!task || type == TaskType::BACKGROUND) { 171 return false; 172 } else if (WillRunOnCurrentThread(type)) { 173 task(); 174 return true; 175 } 176 return PostTaskAndWait(CancelableTask(std::move(task)), type, 0ms, caller.caller_); 177 } 178 179 /** 180 * Post a task to the specified thread and wait until finished executing. 181 * Never allow to post a background synchronous task. 182 * 183 * @param task Task which need execution. 184 * @param type FrontendType of task, used to specify the thread. 185 * @param timeoutMs Timeout in milliseconds before task execution. 186 * @return Returns 'true' whether task has been executed. 187 */ 188 bool PostSyncTaskTimeout(const Task& task, TaskType type, uint32_t timeoutMs, const Caller& caller = {}) const 189 { 190 if (!task || type == TaskType::BACKGROUND) { 191 return false; 192 } else if (WillRunOnCurrentThread(type)) { 193 task(); 194 return true; 195 } 196 return PostTaskAndWait( 197 CancelableTask(std::move(task)), type, std::chrono::milliseconds(timeoutMs), caller.caller_); 198 } 199 200 /** 201 * Post a task to the specified thread and wait until finished executing. 202 * Never allow to post a background synchronous task. 203 * 204 * @param task Task which need execution. 205 * @param type FrontendType of task, used to specify the thread. 206 * @return Returns 'true' whether task has been executed. 207 */ 208 bool PostSyncTask(const Task& task, TaskType type, const Caller& caller = {}) const 209 { 210 return PostSyncTask(Task(task), type, caller); 211 } 212 213 /** 214 * Post a cancelable task to the specified thread and wait until finished executing. 215 * Never allow to post a background synchronous task. 216 * 217 * @param task Task which need execution. 218 * @param type FrontendType of task, used to specify the thread. 219 * @return Returns 'true' whether task has been executed. 220 */ 221 bool PostSyncTask(CancelableTask&& task, TaskType type, const Caller& caller = {}) const 222 { 223 if (!task || type == TaskType::BACKGROUND) { 224 return false; 225 } else if (WillRunOnCurrentThread(type)) { 226 CancelableTask avatar(task); 227 task(); 228 return avatar.WaitUntilComplete(); 229 } 230 return PostTaskAndWait(std::move(task), type, 0ms, caller.caller_); 231 } 232 233 /** 234 * Post a cancelable task to the specified thread and wait until finished executing. 235 * Never allow to post a background synchronous task. 236 * 237 * @param task Task which need execution. 238 * @param type FrontendType of task, used to specify the thread. 239 * @return Returns 'true' whether task has been executed. 240 */ 241 bool PostSyncTask(const CancelableTask& task, TaskType type, const Caller& caller = {}) const 242 { 243 return PostSyncTask(CancelableTask(task), type, caller); 244 } 245 246 virtual void AddTaskObserver(Task&& callback) = 0; 247 virtual void RemoveTaskObserver() = 0; 248 virtual bool WillRunOnCurrentThread(TaskType type) const = 0; 249 GetTid(TaskType type)250 virtual int32_t GetTid(TaskType type) 251 { 252 return 0; 253 } 254 GetTotalTaskNum(TaskType type)255 virtual uint32_t GetTotalTaskNum(TaskType type) 256 { 257 return 0; 258 } 259 260 protected: 261 TaskExecutor() = default; 262 263 virtual bool OnPostTask(Task&& task, TaskType type, uint32_t delayTime, const std::string& callerInfo) const = 0; 264 virtual Task WrapTaskWithTraceId(Task&& task, int32_t id) const = 0; 265 266 #ifdef ACE_DEBUG OnPreSyncTask(TaskType type)267 virtual bool OnPreSyncTask(TaskType type) const 268 { 269 return true; 270 } OnPostSyncTask()271 virtual void OnPostSyncTask() const {} 272 #endif 273 274 private: 275 bool PostTaskAndWait(CancelableTask&& task, TaskType type, std::chrono::milliseconds timeoutMs = 0ms, 276 const std::string& callerInfo = {}) const 277 { 278 #ifdef ACE_DEBUG 279 bool result = false; 280 if (OnPreSyncTask(type)) { 281 result = OnPostTask(Task(task), type, 0, callerInfo) && task.WaitUntilComplete(timeoutMs); 282 OnPostSyncTask(); 283 } 284 return result; 285 #else 286 return OnPostTask(Task(task), type, 0, callerInfo) && task.WaitUntilComplete(timeoutMs); 287 #endif 288 } 289 }; 290 291 class TaskWrapper { 292 public: 293 virtual bool WillRunOnCurrentThread() = 0; 294 virtual void Call(const TaskExecutor::Task& task) = 0; 295 296 virtual ~TaskWrapper() = default; 297 }; 298 299 class SingleTaskExecutor final { 300 public: 301 using Task = TaskExecutor::Task; 302 using CancelableTask = TaskExecutor::CancelableTask; 303 using TaskType = TaskExecutor::TaskType; 304 SingleTaskExecutor(RefPtr<TaskExecutor> && taskExecutor,TaskType type)305 SingleTaskExecutor(RefPtr<TaskExecutor>&& taskExecutor, TaskType type) 306 : taskExecutor_(std::move(taskExecutor)), type_(type) 307 {} SingleTaskExecutor(const RefPtr<TaskExecutor> & taskExecutor,TaskType type)308 SingleTaskExecutor(const RefPtr<TaskExecutor>& taskExecutor, TaskType type) 309 : taskExecutor_(taskExecutor), type_(type) 310 {} 311 ~SingleTaskExecutor() = default; 312 Make(RefPtr<TaskExecutor> && taskExecutor,TaskType type)313 static SingleTaskExecutor Make(RefPtr<TaskExecutor>&& taskExecutor, TaskType type) 314 { 315 return SingleTaskExecutor(std::move(taskExecutor), type); 316 } 317 Make(const RefPtr<TaskExecutor> & taskExecutor,TaskType type)318 static SingleTaskExecutor Make(const RefPtr<TaskExecutor>& taskExecutor, TaskType type) 319 { 320 return SingleTaskExecutor(taskExecutor, type); 321 } 322 323 /** 324 * Post a task to the specified thread. 325 * 326 * @param task Task which need execution. 327 * @return Returns 'true' whether task has been post successfully. 328 */ 329 bool PostTask(Task&& task, const Caller& caller = {}) const 330 { 331 return taskExecutor_ ? taskExecutor_->PostTask(std::move(task), type_, caller) : false; 332 } 333 334 /** 335 * Post a task to the specified thread. 336 * 337 * @param task Task which need execution. 338 * @return Returns 'true' whether task has been post successfully. 339 */ 340 bool PostTask(const Task& task, const Caller& caller = {}) const 341 { 342 return taskExecutor_ ? taskExecutor_->PostTask(task, type_, caller) : false; 343 } 344 345 /** 346 * Post a delayed task to the specified thread. 347 * Never allow to post a background delayed task. 348 * 349 * @param task Task which need execution. 350 * @param delayTime Wait a period of time in milliseconds before execution. 351 * @return Returns 'true' if task has been posted successfully. 352 */ 353 bool PostDelayedTask(Task&& task, uint32_t delayTime, const Caller& caller = {}) const 354 { 355 return taskExecutor_ ? taskExecutor_->PostDelayedTask(std::move(task), type_, delayTime, caller) : false; 356 } 357 358 /** 359 * Post a delayed task to the specified thread. 360 * Never allow to post a background delayed task. 361 * 362 * @param task Task which need execution. 363 * @param delayTime Wait a period of time in milliseconds before execution. 364 * @return Returns 'true' if task has been posted successfully. 365 */ 366 bool PostDelayedTask(const Task& task, uint32_t delayTime, const Caller& caller = {}) const 367 { 368 return taskExecutor_ ? taskExecutor_->PostDelayedTask(task, type_, delayTime, caller) : false; 369 } 370 371 /** 372 * Post a task to the specified thread and wait until finished executing. 373 * Never allow to post a background synchronous task. 374 * 375 * @param task Task which need execution. 376 * @return Returns 'true' whether task has been executed. 377 */ 378 bool PostSyncTask(Task&& task, const Caller& caller = {}) const 379 { 380 return taskExecutor_ ? taskExecutor_->PostSyncTask(std::move(task), type_, caller) : false; 381 } 382 383 /** 384 * Post a task to the specified thread and wait until finished executing. 385 * Never allow to post a background synchronous task. 386 * 387 * @param task Task which need execution. 388 * @return Returns 'true' whether task has been executed. 389 */ 390 bool PostSyncTask(const Task& task, const Caller& caller = {}) const 391 { 392 return taskExecutor_ ? taskExecutor_->PostSyncTask(task, type_, caller) : false; 393 } 394 395 /** 396 * Post a cancelable task to the specified thread and wait until finished executing. 397 * Never allow to post a background synchronous task. 398 * 399 * @param task Task which need execution. 400 * @return Returns 'true' whether task has been executed. 401 */ 402 bool PostSyncTask(CancelableTask&& task, const Caller& caller = {}) const 403 { 404 return taskExecutor_ ? taskExecutor_->PostSyncTask(std::move(task), type_, caller) : false; 405 } 406 407 /** 408 * Post a cancelable task to the specified thread and wait until finished executing. 409 * Never allow to post a background synchronous task. 410 * 411 * @param task Task which need execution. 412 * @return Returns 'true' whether task has been executed. 413 */ 414 bool PostSyncTask(const CancelableTask& task, const Caller& caller = {}) const 415 { 416 return taskExecutor_ ? taskExecutor_->PostSyncTask(task, type_, caller) : false; 417 } 418 GetTaskExecutor()419 RefPtr<TaskExecutor> GetTaskExecutor() const 420 { 421 return taskExecutor_; 422 } 423 IsRunOnCurrentThread()424 bool IsRunOnCurrentThread() const 425 { 426 return taskExecutor_ ? taskExecutor_->WillRunOnCurrentThread(type_) : false; 427 } 428 429 private: 430 RefPtr<TaskExecutor> taskExecutor_; 431 TaskExecutor::TaskType type_; 432 }; 433 434 } // namespace OHOS::Ace 435 436 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_TASK_EXECUTOR_H 437