• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #include "core/common/task_executor_impl.h"
17 
18 #if !defined(PREVIEW)
19 #ifdef OHOS_STANDARD_SYSTEM
20 #include <sys/prctl.h>
21 #endif
22 #include <sys/resource.h>
23 #endif
24 #include <unistd.h>
25 #include "base/log/trace_id.h"
26 #include "base/thread/background_task_executor.h"
27 #include "core/common/container.h"
28 #include "core/common/task_runner_adapter_factory.h"
29 
30 namespace OHOS::Ace {
31 namespace {
32 constexpr int32_t GPU_THREAD_PRIORITY = -10;
33 constexpr int32_t UI_THREAD_PRIORITY = -15;
34 
GenJsThreadName()35 inline std::string GenJsThreadName()
36 {
37     static std::atomic<uint32_t> instanceCount { 1 };
38     return std::string("jsThread-") + std::to_string(instanceCount.fetch_add(1, std::memory_order_relaxed));
39 }
40 } // namespace
41 
WrapTaskWithContainer(TaskExecutor::Task && task,int32_t id,std::function<void ()> && traceIdFunc) const42 TaskExecutor::Task TaskExecutorImpl::WrapTaskWithContainer(
43     TaskExecutor::Task&& task, int32_t id, std::function<void()>&& traceIdFunc) const
44 {
45     auto wrappedTask = [originTask = std::move(task), id, traceId = TraceId::CreateTraceId(),
46                            traceIdFunc = std::move(traceIdFunc)]() {
47         ContainerScope scope(id);
48         std::unique_ptr<TraceId> traceIdPtr(traceId);
49         if (originTask && traceIdPtr) {
50             traceIdPtr->SetTraceId();
51             originTask();
52             traceIdPtr->ClearTraceId();
53         } else {
54             LOGW("WrapTaskWithContainer: originTask or traceIdPtr is null.");
55         }
56         if (traceIdFunc) {
57             traceIdFunc();
58         }
59     };
60     return wrappedTask;
61 }
62 
WrapTaskWithCustomWrapper(TaskExecutor::Task && task,int32_t id,std::function<void ()> && traceIdFunc) const63 TaskExecutor::Task TaskExecutorImpl::WrapTaskWithCustomWrapper(
64     TaskExecutor::Task&& task, int32_t id, std::function<void()>&& traceIdFunc) const
65 {
66     auto wrappedTask = [taskWrapper = taskWrapper_, originTask = std::move(task), id,
67                            traceId = TraceId::CreateTraceId(), traceIdFunc = std::move(traceIdFunc)]() {
68         ContainerScope scope(id);
69         std::unique_ptr<TraceId> traceIdPtr(traceId);
70         if (originTask && traceIdPtr) {
71             traceIdPtr->SetTraceId();
72             taskWrapper->Call(originTask);
73             traceIdPtr->ClearTraceId();
74         } else {
75             LOGW("WrapTaskWithContainer: originTask or traceIdPtr is null.");
76         }
77         if (traceIdFunc) {
78             traceIdFunc();
79         }
80     };
81     return wrappedTask;
82 }
83 
PostTaskToTaskRunner(const RefPtr<TaskRunnerAdapter> & taskRunner,TaskExecutor::Task && task,uint32_t delayTime,const std::string & name,PriorityType priorityType) const84 bool TaskExecutorImpl::PostTaskToTaskRunner(const RefPtr<TaskRunnerAdapter>& taskRunner, TaskExecutor::Task&& task,
85     uint32_t delayTime, const std::string& name, PriorityType priorityType) const
86 {
87     CHECK_NULL_RETURN(taskRunner, false);
88     CHECK_NULL_RETURN(task, false);
89 
90     if (delayTime > 0) {
91         taskRunner->PostDelayedTask(std::move(task), delayTime, name, priorityType);
92     } else {
93         taskRunner->PostTask(std::move(task), name, priorityType);
94     }
95     return true;
96 }
97 
SetThreadPriority(int32_t priority) const98 void TaskExecutorImpl::SetThreadPriority(int32_t priority) const
99 {
100 #if !defined(PREVIEW) and !defined(IOS_PLATFORM)
101     if (setpriority(PRIO_PROCESS, gettid(), priority) < 0) {
102         LOGW("Failed to set thread priority, errno = %{private}d", errno);
103     }
104 #endif
105 }
106 
TaskExecutorImpl(const RefPtr<TaskExecutorImpl> & taskExecutor)107 TaskExecutorImpl::TaskExecutorImpl(const RefPtr<TaskExecutorImpl>& taskExecutor)
108 {
109     jsRunner_ = TaskRunnerAdapterFactory::Create(false, GenJsThreadName());
110     platformRunner_ = taskExecutor->platformRunner_;
111     uiRunner_ = taskExecutor->uiRunner_;
112     ioRunner_ = taskExecutor->ioRunner_;
113     gpuRunner_ = taskExecutor->gpuRunner_;
114 }
115 
TaskExecutorImpl(const OHOS::Ace::TaskRunners & taskRunners)116 TaskExecutorImpl::TaskExecutorImpl(const OHOS::Ace::TaskRunners& taskRunners)
117 {
118     jsRunner_ = TaskRunnerAdapterFactory::Create(false, GenJsThreadName());
119 
120     platformRunner_ = taskRunners.GetPlatformTaskRunner();
121     uiRunner_ = taskRunners.GetUITaskRunner();
122     ioRunner_ = taskRunners.GetIOTaskRunner();
123     gpuRunner_ = taskRunners.GetGPUTaskRunner();
124 }
125 
InitPlatformThread(bool useCurrentEventRunner,bool isStageModel)126 void TaskExecutorImpl::InitPlatformThread(bool useCurrentEventRunner, bool isStageModel)
127 {
128     platformRunner_ = TaskRunnerAdapterFactory::Create(useCurrentEventRunner, "");
129     FillTaskTypeTable(TaskType::PLATFORM);
130 }
131 
InitJsThread(bool newThread)132 void TaskExecutorImpl::InitJsThread(bool newThread)
133 {
134     if (newThread) {
135         jsRunner_ = TaskRunnerAdapterFactory::Create(false, GenJsThreadName());
136     } else {
137         jsRunner_ = uiRunner_;
138     }
139 
140     PostTaskToTaskRunner(
141         jsRunner_, [weak = AceType::WeakClaim(this)] { FillTaskTypeTable(weak, TaskType::JS); }, 0,
142         "ArkUIFillTaskTypeTable");
143 }
144 
InitOtherThreads(ThreadModelImpl * threadModel)145 void TaskExecutorImpl::InitOtherThreads(ThreadModelImpl* threadModel)
146 {
147     if (threadModel) {
148         InitOtherThreads(threadModel->GetTaskRunners());
149     }
150 }
151 
InitOtherThreads(const OHOS::Ace::TaskRunners & taskRunners)152 void TaskExecutorImpl::InitOtherThreads(const OHOS::Ace::TaskRunners& taskRunners)
153 {
154     uiRunner_ = taskRunners.GetUITaskRunner();
155     ioRunner_ = taskRunners.GetIOTaskRunner();
156     gpuRunner_ = taskRunners.GetGPUTaskRunner();
157 
158     PostTaskToTaskRunner(
159         uiRunner_, [this] { SetThreadPriority(UI_THREAD_PRIORITY); }, 0, "ArkUISetThreadPriority");
160     PostTaskToTaskRunner(
161         gpuRunner_, [this] { SetThreadPriority(GPU_THREAD_PRIORITY); }, 0, "ArkUISetThreadPriority");
162 
163     PostTaskToTaskRunner(
164         uiRunner_, [weak = AceType::WeakClaim(this)] { FillTaskTypeTable(weak, TaskType::UI); }, 0,
165         "ArkUIFillTaskTypeTable");
166     PostTaskToTaskRunner(
167         ioRunner_, [weak = AceType::WeakClaim(this)] { FillTaskTypeTable(weak, TaskType::IO); }, 0,
168         "ArkUIFillTaskTypeTable");
169     PostTaskToTaskRunner(
170         gpuRunner_, [weak = AceType::WeakClaim(this)] { FillTaskTypeTable(weak, TaskType::GPU); }, 0,
171         "ArkUIFillTaskTypeTable");
172 }
173 
OnPostTask(Task && task,TaskType type,uint32_t delayTime,const std::string & name,PriorityType priorityType) const174 bool TaskExecutorImpl::OnPostTask(
175     Task&& task, TaskType type, uint32_t delayTime, const std::string& name, PriorityType priorityType) const
176 {
177     int32_t currentId = Container::CurrentId();
178     auto traceIdFunc = [weak = WeakClaim(const_cast<TaskExecutorImpl*>(this)), type]() {
179         auto sp = weak.Upgrade();
180         if (sp) {
181             sp->taskIdTable_[static_cast<uint32_t>(type)]++;
182         }
183     };
184 
185     if (taskWrapper_ != nullptr && (type == TaskType::PLATFORM || type == TaskType::UI || type == TaskType::JS)) {
186         TaskExecutor::Task wrappedTask = WrapTaskWithCustomWrapper(std::move(task), currentId, std::move(traceIdFunc));
187         taskWrapper_->Call(std::move(wrappedTask));
188         return true;
189     }
190 
191     TaskExecutor::Task wrappedTask =
192         currentId >= 0 ? WrapTaskWithContainer(std::move(task), currentId, std::move(traceIdFunc)) : std::move(task);
193 
194     switch (type) {
195         case TaskType::PLATFORM:
196             return PostTaskToTaskRunner(platformRunner_, std::move(wrappedTask), delayTime, name);
197         case TaskType::UI:
198             return PostTaskToTaskRunner(uiRunner_, std::move(wrappedTask), delayTime, name, priorityType);
199         case TaskType::IO:
200             return PostTaskToTaskRunner(ioRunner_, std::move(wrappedTask), delayTime, name);
201         case TaskType::GPU:
202             return PostTaskToTaskRunner(gpuRunner_, std::move(wrappedTask), delayTime, name);
203         case TaskType::JS:
204             return PostTaskToTaskRunner(jsRunner_, std::move(wrappedTask), delayTime, name);
205         case TaskType::BACKGROUND:
206             // Ignore delay time
207             return BackgroundTaskExecutor::GetInstance().PostTask(std::move(wrappedTask));
208         default:
209             return false;
210     }
211 }
212 
WrapTaskWithTraceId(Task && task,int32_t id) const213 TaskExecutor::Task TaskExecutorImpl::WrapTaskWithTraceId(Task&& task, int32_t id) const
214 {
215     return WrapTaskWithContainer(std::move(task), id);
216 }
217 
WillRunOnCurrentThread(TaskType type) const218 bool TaskExecutorImpl::WillRunOnCurrentThread(TaskType type) const
219 {
220     switch (type) {
221         case TaskType::PLATFORM:
222             return platformRunner_ ? (taskWrapper_ != nullptr ? taskWrapper_->WillRunOnCurrentThread()
223                                                               : platformRunner_->RunsTasksOnCurrentThread())
224                                    : false;
225         case TaskType::UI:
226             return uiRunner_ ? (taskWrapper_ != nullptr ? taskWrapper_->WillRunOnCurrentThread()
227                                                         : uiRunner_->RunsTasksOnCurrentThread())
228                              : false;
229         case TaskType::IO:
230             return ioRunner_ ? ioRunner_->RunsTasksOnCurrentThread() : false;
231         case TaskType::GPU:
232             return gpuRunner_ ? gpuRunner_->RunsTasksOnCurrentThread() : false;
233         case TaskType::JS:
234             return jsRunner_ ? (taskWrapper_ != nullptr ? taskWrapper_->WillRunOnCurrentThread()
235                                                         : jsRunner_->RunsTasksOnCurrentThread())
236                              : false;
237         case TaskType::BACKGROUND:
238             // Always return false for background tasks.
239             return false;
240         default:
241             return false;
242     }
243 }
244 
245 thread_local TaskExecutor::TaskType TaskExecutorImpl::localTaskType = TaskExecutor::TaskType::UNKNOWN;
246 
247 #ifdef ACE_DEBUG
TaskTypeToString(TaskExecutor::TaskType type)248 static const char* TaskTypeToString(TaskExecutor::TaskType type)
249 {
250     switch (type) {
251         case TaskExecutor::TaskType::PLATFORM:
252             return "PLATFORM";
253         case TaskExecutor::TaskType::UI:
254             return "UI";
255         case TaskExecutor::TaskType::IO:
256             return "IO";
257         case TaskExecutor::TaskType::GPU:
258             return "GPU";
259         case TaskExecutor::TaskType::JS:
260             return "JS";
261         case TaskExecutor::TaskType::BACKGROUND:
262             return "BACKGROUND";
263         case TaskExecutor::TaskType::UNKNOWN:
264         default:
265             return "UNKNOWN";
266     }
267 }
268 
OnPreSyncTask(TaskType type) const269 bool TaskExecutorImpl::OnPreSyncTask(TaskType type) const
270 {
271     std::lock_guard<std::mutex> lock(tableMutex_);
272     auto it = taskTypeTable_.find(type);
273     // when task type not filled, just skip
274     if (it == taskTypeTable_.end()) {
275         return true;
276     }
277 
278     auto itSync = syncTaskTable_.find(it->second.threadId);
279     while (itSync != syncTaskTable_.end()) {
280         if (itSync->second == std::this_thread::get_id()) {
281             DumpDeadSyncTask(localTaskType, type);
282             ACE_DCHECK(itSync->second != std::this_thread::get_id() && "DEAD LOCK HAPPENED !!!");
283             return false;
284         }
285 
286         itSync = syncTaskTable_.find(itSync->second);
287     }
288 
289     syncTaskTable_.emplace(std::this_thread::get_id(), it->second.threadId);
290     return true;
291 }
292 
OnPostSyncTask() const293 void TaskExecutorImpl::OnPostSyncTask() const
294 {
295     std::lock_guard<std::mutex> lock(tableMutex_);
296     syncTaskTable_.erase(std::this_thread::get_id());
297 }
298 
DumpDeadSyncTask(TaskType from,TaskType to) const299 void TaskExecutorImpl::DumpDeadSyncTask(TaskType from, TaskType to) const
300 {
301     auto itFrom = taskTypeTable_.find(from);
302     auto itTo = taskTypeTable_.find(to);
303 
304     ACE_DCHECK(itFrom != taskTypeTable_.end());
305     ACE_DCHECK(itTo != taskTypeTable_.end());
306 
307     LOGE("DEAD LOCK HAPPEN: %{public}s(%{public}d, %{public}s) -> %{public}s(%{public}d, %{public}s)",
308         TaskTypeToString(from), itFrom->second.tid, itFrom->second.threadName.c_str(), TaskTypeToString(to),
309         itTo->second.tid, itTo->second.threadName.c_str());
310 }
311 #endif
312 
FillTaskTypeTable(TaskType type)313 void TaskExecutorImpl::FillTaskTypeTable(TaskType type)
314 {
315     constexpr size_t MAX_THREAD_NAME_SIZE = 32;
316     char threadNameBuf[MAX_THREAD_NAME_SIZE] = { 0 };
317     const char* threadName = threadNameBuf;
318 #if !defined(PREVIEW) and !defined(IOS_PLATFORM)
319 #ifdef OHOS_STANDARD_SYSTEM
320     if (prctl(PR_GET_NAME, threadNameBuf) < 0) {
321         threadName = "unknown";
322     }
323 #else
324     if (pthread_getname_np(pthread_self(), threadNameBuf, sizeof(threadNameBuf)) != 0) {
325         threadName = "unknown";
326     }
327 #endif
328 #endif
329 
330     localTaskType = type;
331     ThreadInfo info = {
332         .threadId = std::this_thread::get_id(),
333 #if !defined(PREVIEW) and !defined(IOS_PLATFORM)
334         .tid = gettid(),
335 #endif
336         .threadName = threadName,
337     };
338 
339     std::lock_guard<std::mutex> lock(tableMutex_);
340     taskTypeTable_.emplace(type, info);
341 }
342 
FillTaskTypeTable(const WeakPtr<TaskExecutorImpl> & weak,TaskType type)343 void TaskExecutorImpl::FillTaskTypeTable(const WeakPtr<TaskExecutorImpl>& weak, TaskType type)
344 {
345     auto taskExecutor = weak.Upgrade();
346     if (taskExecutor) {
347         taskExecutor->FillTaskTypeTable(type);
348     }
349 }
350 
OnPostTaskWithoutTraceId(Task && task,TaskType type,uint32_t delayTime,const std::string & name,PriorityType priorityType) const351 bool TaskExecutorImpl::OnPostTaskWithoutTraceId(
352     Task&& task, TaskType type, uint32_t delayTime, const std::string& name, PriorityType priorityType) const
353 {
354     TaskExecutor::Task wrappedTask = std::move(task);
355 
356     switch (type) {
357         case TaskType::PLATFORM:
358             return PostTaskToTaskRunner(platformRunner_, std::move(wrappedTask), delayTime, name);
359         case TaskType::UI:
360             return PostTaskToTaskRunner(uiRunner_, std::move(wrappedTask), delayTime, name, priorityType);
361         case TaskType::IO:
362             return PostTaskToTaskRunner(ioRunner_, std::move(wrappedTask), delayTime, name);
363         case TaskType::GPU:
364             return PostTaskToTaskRunner(gpuRunner_, std::move(wrappedTask), delayTime, name);
365         case TaskType::JS:
366             return PostTaskToTaskRunner(jsRunner_, std::move(wrappedTask), delayTime, name);
367         case TaskType::BACKGROUND:
368             // Ignore delay time
369             return BackgroundTaskExecutor::GetInstance().PostTask(std::move(wrappedTask));
370         default:
371             return false;
372     }
373 }
374 
RemoveTask(TaskType type,const std::string & name)375 void TaskExecutorImpl::RemoveTask(TaskType type, const std::string &name)
376 {
377     switch (type) {
378         case TaskType::PLATFORM:
379             RemoveTaskFromTaskRunner(platformRunner_, name);
380             break;
381         case TaskType::UI:
382             RemoveTaskFromTaskRunner(uiRunner_, name);
383             break;
384         case TaskType::IO:
385             RemoveTaskFromTaskRunner(ioRunner_, name);
386             break;
387         case TaskType::GPU:
388             RemoveTaskFromTaskRunner(gpuRunner_, name);
389             break;
390         case TaskType::JS:
391             RemoveTaskFromTaskRunner(jsRunner_, name);
392             break;
393         case TaskType::BACKGROUND:
394             // background task cannot remove,use ffrt not eventhander
395             break;
396         default:
397             break;
398     }
399 }
400 
RemoveTaskFromTaskRunner(const RefPtr<TaskRunnerAdapter> & taskRunner,const std::string & name)401 void TaskExecutorImpl::RemoveTaskFromTaskRunner(const RefPtr<TaskRunnerAdapter>& taskRunner, const std::string& name)
402 {
403     CHECK_NULL_VOID(taskRunner);
404     taskRunner->RemoveTask(name);
405 }
406 } // namespace OHOS::Ace
407