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