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 namespace OHOS::Ace { 28 29 // 1. Must be consistent with AppExecFwk::EventQueue::Priority. 30 // 2. Do not use this ability arbitrarily. 31 enum class PriorityType : int32_t { 32 // The highest priority queue, should be distributed until the tasks in the queue are completed. 33 VIP = 0, 34 // Event that should be distributed at once if possible. 35 IMMEDIATE, 36 // High priority event, sorted by handle time, should be distributed before low priority event. 37 HIGH, 38 // Normal event, sorted by handle time. 39 LOW, 40 // Event that should be distributed only if no other event right now. 41 IDLE, 42 }; 43 44 class TaskExecutor : public AceType { 45 DECLARE_ACE_TYPE(TaskExecutor, AceType); 46 ACE_DISALLOW_COPY_AND_MOVE(TaskExecutor); 47 48 public: 49 using Task = std::function<void()>; 50 using CancelableTask = CancelableCallback<void()>; 51 52 static constexpr int32_t TASK_TYPE_SIZE = 7; 53 enum class TaskType : uint32_t { 54 PLATFORM = 0, 55 UI, 56 IO, 57 GPU, 58 JS, 59 BACKGROUND, 60 UNKNOWN, 61 }; 62 63 ~TaskExecutor() override = default; 64 65 /** 66 * Post a task to the specified thread. 67 * 68 * @param task Task which need execution. 69 * @param type FrontendType of task, used to specify the thread. 70 * @param name Name of the task. 71 * @return Returns 'true' whether task has been post successfully. 72 */ 73 bool PostTask( 74 Task&& task, TaskType type, const std::string& name, PriorityType priorityType = PriorityType::LOW) const 75 { 76 return PostDelayedTask(std::move(task), type, 0, name, priorityType); 77 } 78 79 /** 80 * Post a task to the specified thread. 81 * 82 * @param task Task which need execution. 83 * @param type FrontendType of task, used to specify the thread. 84 * @param name Name of the task. 85 * @return Returns 'true' if task has been posted successfully. 86 */ 87 bool PostTask(const Task& task, TaskType type, const std::string& name, 88 PriorityType priorityType = PriorityType::LOW) const 89 { 90 return PostDelayedTask(task, type, 0, name, priorityType); 91 } 92 93 /** 94 * Post a task to the specified thread with a trace id. 95 * 96 * @param task Task which need execution. 97 * @param type FrontendType of task, used to specify the thread. 98 * @param id The id to trace the task. 99 * @param name Name of the task. 100 * @return Returns 'true' whether task has been post successfully. 101 */ PostTaskWithTraceId(Task && task,TaskType type,int32_t id,const std::string & name)102 bool PostTaskWithTraceId(Task&& task, TaskType type, int32_t id, const std::string& name) const 103 { 104 Task wrappedTask = WrapTaskWithTraceId(std::move(task), id); 105 return PostDelayedTask(std::move(wrappedTask), type, 0, name); 106 } 107 108 /** 109 * Post a task to the specified thread. 110 * 111 * @param task Task which need execution. 112 * @param type FrontendType of task, used to specify the thread. 113 * @param id The id to trace the task. 114 * @param name Name of the task. 115 * @return Returns 'true' if task has been posted successfully. 116 */ PostTaskWithTraceId(const Task & task,TaskType type,int32_t id,const std::string & name)117 bool PostTaskWithTraceId(const Task& task, TaskType type, int32_t id, const std::string& name) const 118 { 119 Task wrappedTask = WrapTaskWithTraceId(Task(task), id); 120 return PostDelayedTask(std::move(wrappedTask), type, 0, name); 121 } 122 123 /** 124 * Post a delayed task to the specified thread. 125 * Never allow to post a background delayed task. 126 * 127 * @param task Task which need execution. 128 * @param type FrontendType of task, used to specify the thread. 129 * @param delayTime Wait a period of time in milliseconds before execution. 130 * @param name Name of the task. 131 * @return Returns 'true' if task has been posted successfully. 132 */ 133 bool PostDelayedTask(Task&& task, TaskType type, uint32_t delayTime, const std::string& name, 134 PriorityType priorityType = PriorityType::LOW) const 135 { 136 if (delayTime > 0 && type == TaskType::BACKGROUND) { 137 return false; 138 } 139 return OnPostTask(std::move(task), type, delayTime, name, priorityType); 140 } 141 142 /** 143 * Post a delayed task to the specified thread. 144 * Never allow to post a background delayed task. 145 * 146 * @param task Task which need execution. 147 * @param type FrontendType of task, used to specify the thread. 148 * @param delayTime Wait a period of time in milliseconds before execution. 149 * @param name Name of the task. 150 * @return Returns 'true' if task has been posted successfully. 151 */ 152 bool PostDelayedTask(const Task& task, TaskType type, uint32_t delayTime, const std::string& name, 153 PriorityType priorityType = PriorityType::LOW) const 154 { 155 return PostDelayedTask(Task(task), type, delayTime, name, priorityType); 156 } 157 158 /** 159 * Post a task to the specified thread and wait until finished executing. 160 * Never allow to post a background synchronous task. 161 * 162 * @param task Task which need execution. 163 * @param type FrontendType of task, used to specify the thread. 164 * @param name Name of the task. 165 * @return Returns 'true' whether task has been executed. 166 */ 167 bool PostSyncTask( 168 Task&& task, TaskType type, const std::string& name, PriorityType priorityType = PriorityType::IMMEDIATE) 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, name, 0ms, priorityType); 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 * @param name Name of the task. 187 * @return Returns 'true' whether task has been executed. 188 */ PostSyncTaskTimeout(const Task & task,TaskType type,uint32_t timeoutMs,const std::string & name)189 bool PostSyncTaskTimeout(const Task& task, TaskType type, uint32_t timeoutMs, const std::string& name) const 190 { 191 if (!task || type == TaskType::BACKGROUND) { 192 return false; 193 } else if (WillRunOnCurrentThread(type)) { 194 task(); 195 return true; 196 } 197 return PostTaskAndWait( 198 CancelableTask(std::move(task)), type, name, std::chrono::milliseconds(timeoutMs)); 199 } 200 201 /** 202 * Post a task to the specified thread and wait until finished executing. 203 * Never allow to post a background synchronous task. 204 * 205 * @param task Task which need execution. 206 * @param type FrontendType of task, used to specify the thread. 207 * @param name Name of the task. 208 * @return Returns 'true' whether task has been executed. 209 */ PostSyncTask(const Task & task,TaskType type,const std::string & name)210 bool PostSyncTask(const Task& task, TaskType type, const std::string& name) const 211 { 212 return PostSyncTask(Task(task), type, name); 213 } 214 215 /** 216 * Post a cancelable task to the specified thread and wait until finished executing. 217 * Never allow to post a background synchronous task. 218 * 219 * @param task Task which need execution. 220 * @param type FrontendType of task, used to specify the thread. 221 * @param name Name of the task. 222 * @return Returns 'true' whether task has been executed. 223 */ PostSyncTask(CancelableTask && task,TaskType type,const std::string & name)224 bool PostSyncTask(CancelableTask&& task, TaskType type, const std::string& name) const 225 { 226 if (!task || type == TaskType::BACKGROUND) { 227 return false; 228 } else if (WillRunOnCurrentThread(type)) { 229 CancelableTask avatar(task); 230 task(); 231 return avatar.WaitUntilComplete(); 232 } 233 return PostTaskAndWait(std::move(task), type, name, 0ms); 234 } 235 236 /** 237 * Post a cancelable task to the specified thread and wait until finished executing. 238 * Never allow to post a background synchronous task. 239 * 240 * @param task Task which need execution. 241 * @param type FrontendType of task, used to specify the thread. 242 * @param name Name of the task. 243 * @return Returns 'true' whether task has been executed. 244 */ PostSyncTask(const CancelableTask & task,TaskType type,const std::string & name)245 bool PostSyncTask(const CancelableTask& task, TaskType type, const std::string& name) const 246 { 247 return PostSyncTask(CancelableTask(task), type, name); 248 } 249 250 /** 251 * The task use PostDelayedTask will new an object TraceId, when use 252 * RemoveTask will cause memory overflow. 253 * Post a delayed task without traceId to the specified thread. 254 * Never allow to post a background delayed task. 255 * 256 * @param task Task which need execution. 257 * @param type FrontendType of task, used to specify the thread. 258 * @param delayTime Wait a period of time in milliseconds before execution. 259 * @param name Name of the task. 260 * @return Returns 'true' if task has been posted successfully. 261 */ 262 bool PostDelayedTaskWithoutTraceId(Task&& task, TaskType type, uint32_t delayTime, const std::string& name, 263 PriorityType priorityType = PriorityType::LOW) const 264 { 265 if (delayTime > 0 && type == TaskType::BACKGROUND) { 266 return false; 267 } 268 return OnPostTaskWithoutTraceId(std::move(task), type, delayTime, name, priorityType); 269 } 270 271 virtual void AddTaskObserver(Task&& callback) = 0; 272 virtual void RemoveTaskObserver() = 0; 273 virtual bool WillRunOnCurrentThread(TaskType type) const = 0; 274 virtual void RemoveTask(TaskType type, const std::string &name) = 0; 275 GetTid(TaskType type)276 virtual int32_t GetTid(TaskType type) 277 { 278 return 0; 279 } 280 GetTotalTaskNum(TaskType type)281 virtual uint32_t GetTotalTaskNum(TaskType type) 282 { 283 return 0; 284 } 285 286 protected: 287 TaskExecutor() = default; 288 289 virtual bool OnPostTask(Task&& task, TaskType type, uint32_t delayTime, const std::string& name, 290 PriorityType priorityType = PriorityType::LOW) const = 0; 291 virtual Task WrapTaskWithTraceId(Task&& task, int32_t id) const = 0; 292 virtual bool OnPostTaskWithoutTraceId(Task&& task, TaskType type, uint32_t delayTime, const std::string& name, 293 PriorityType priorityType = PriorityType::LOW) const = 0; 294 295 #ifdef ACE_DEBUG OnPreSyncTask(TaskType type)296 virtual bool OnPreSyncTask(TaskType type) const 297 { 298 return true; 299 } OnPostSyncTask()300 virtual void OnPostSyncTask() const {} 301 #endif 302 303 private: 304 bool PostTaskAndWait(CancelableTask&& task, TaskType type, const std::string& name, 305 std::chrono::milliseconds timeoutMs = 0ms, PriorityType priorityType = PriorityType::IMMEDIATE) const 306 { 307 #ifdef ACE_DEBUG 308 bool result = false; 309 if (OnPreSyncTask(type)) { 310 result = OnPostTask(Task(task), type, 0, name, priorityType) && task.WaitUntilComplete(timeoutMs); 311 OnPostSyncTask(); 312 } 313 return result; 314 #else 315 return OnPostTask(Task(task), type, 0, name, priorityType) && task.WaitUntilComplete(timeoutMs); 316 #endif 317 } 318 }; 319 320 class TaskWrapper { 321 public: 322 virtual bool WillRunOnCurrentThread() = 0; 323 virtual void Call(const TaskExecutor::Task& task) = 0; 324 325 virtual ~TaskWrapper() = default; 326 }; 327 328 class SingleTaskExecutor final { 329 public: 330 using Task = TaskExecutor::Task; 331 using CancelableTask = TaskExecutor::CancelableTask; 332 using TaskType = TaskExecutor::TaskType; 333 SingleTaskExecutor(RefPtr<TaskExecutor> && taskExecutor,TaskType type)334 SingleTaskExecutor(RefPtr<TaskExecutor>&& taskExecutor, TaskType type) 335 : taskExecutor_(std::move(taskExecutor)), type_(type) 336 {} SingleTaskExecutor(const RefPtr<TaskExecutor> & taskExecutor,TaskType type)337 SingleTaskExecutor(const RefPtr<TaskExecutor>& taskExecutor, TaskType type) 338 : taskExecutor_(taskExecutor), type_(type) 339 {} 340 ~SingleTaskExecutor() = default; 341 Make(RefPtr<TaskExecutor> && taskExecutor,TaskType type)342 static SingleTaskExecutor Make(RefPtr<TaskExecutor>&& taskExecutor, TaskType type) 343 { 344 return SingleTaskExecutor(std::move(taskExecutor), type); 345 } 346 Make(const RefPtr<TaskExecutor> & taskExecutor,TaskType type)347 static SingleTaskExecutor Make(const RefPtr<TaskExecutor>& taskExecutor, TaskType type) 348 { 349 return SingleTaskExecutor(taskExecutor, type); 350 } 351 352 /** 353 * Post a task to the specified thread. 354 * 355 * @param task Task which need execution. 356 * @param name Name of the task. 357 * @return Returns 'true' whether task has been post successfully. 358 */ PostTask(Task && task,const std::string & name)359 bool PostTask(Task&& task, const std::string& name) const 360 { 361 return taskExecutor_ ? taskExecutor_->PostTask(std::move(task), type_, name) : false; 362 } 363 364 /** 365 * Post a task to the specified thread. 366 * 367 * @param task Task which need execution. 368 * @param name Name of the task. 369 * @return Returns 'true' whether task has been post successfully. 370 */ PostTask(const Task & task,const std::string & name)371 bool PostTask(const Task& task, const std::string& name) const 372 { 373 return taskExecutor_ ? taskExecutor_->PostTask(task, type_, name) : false; 374 } 375 376 /** 377 * Post a delayed task to the specified thread. 378 * Never allow to post a background delayed task. 379 * 380 * @param task Task which need execution. 381 * @param delayTime Wait a period of time in milliseconds before execution. 382 * @param name Name of the task. 383 * @return Returns 'true' if task has been posted successfully. 384 */ PostDelayedTask(Task && task,uint32_t delayTime,const std::string & name)385 bool PostDelayedTask(Task&& task, uint32_t delayTime, const std::string& name) const 386 { 387 return taskExecutor_ ? taskExecutor_->PostDelayedTask(std::move(task), type_, delayTime, name) : false; 388 } 389 390 /** 391 * Post a delayed task to the specified thread. 392 * Never allow to post a background delayed task. 393 * 394 * @param task Task which need execution. 395 * @param delayTime Wait a period of time in milliseconds before execution. 396 * @param name Name of the task. 397 * @return Returns 'true' if task has been posted successfully. 398 */ PostDelayedTask(const Task & task,uint32_t delayTime,const std::string & name)399 bool PostDelayedTask(const Task& task, uint32_t delayTime, const std::string& name) const 400 { 401 return taskExecutor_ ? taskExecutor_->PostDelayedTask(task, type_, delayTime, name) : false; 402 } 403 404 /** 405 * Post a task to the specified thread and wait until finished executing. 406 * Never allow to post a background synchronous task. 407 * 408 * @param task Task which need execution. 409 * @param name Name of the task. 410 * @return Returns 'true' whether task has been executed. 411 */ PostSyncTask(Task && task,const std::string & name)412 bool PostSyncTask(Task&& task, const std::string& name) const 413 { 414 return taskExecutor_ ? taskExecutor_->PostSyncTask(std::move(task), type_, name) : false; 415 } 416 417 /** 418 * Post a task to the specified thread and wait until finished executing. 419 * Never allow to post a background synchronous task. 420 * 421 * @param task Task which need execution. 422 * @param name Name of the task. 423 * @return Returns 'true' whether task has been executed. 424 */ PostSyncTask(const Task & task,const std::string & name)425 bool PostSyncTask(const Task& task, const std::string& name) const 426 { 427 return taskExecutor_ ? taskExecutor_->PostSyncTask(task, type_, name) : false; 428 } 429 430 /** 431 * Post a cancelable task to the specified thread and wait until finished executing. 432 * Never allow to post a background synchronous task. 433 * 434 * @param task Task which need execution. 435 * @param name Name of the task. 436 * @return Returns 'true' whether task has been executed. 437 */ PostSyncTask(CancelableTask && task,const std::string & name)438 bool PostSyncTask(CancelableTask&& task, const std::string& name) const 439 { 440 return taskExecutor_ ? taskExecutor_->PostSyncTask(std::move(task), type_, name) : false; 441 } 442 443 /** 444 * Post a cancelable task to the specified thread and wait until finished executing. 445 * Never allow to post a background synchronous task. 446 * 447 * @param task Task which need execution. 448 * @param name Name of the task. 449 * @return Returns 'true' whether task has been executed. 450 */ PostSyncTask(const CancelableTask & task,const std::string & name)451 bool PostSyncTask(const CancelableTask& task, const std::string& name) const 452 { 453 return taskExecutor_ ? taskExecutor_->PostSyncTask(task, type_, name) : false; 454 } 455 GetTaskExecutor()456 RefPtr<TaskExecutor> GetTaskExecutor() const 457 { 458 return taskExecutor_; 459 } 460 IsRunOnCurrentThread()461 bool IsRunOnCurrentThread() const 462 { 463 return taskExecutor_ ? taskExecutor_->WillRunOnCurrentThread(type_) : false; 464 } 465 466 private: 467 RefPtr<TaskExecutor> taskExecutor_; 468 TaskExecutor::TaskType type_; 469 }; 470 471 } // namespace OHOS::Ace 472 473 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_THREAD_TASK_EXECUTOR_H 474