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