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