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