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