1 /*
2  * Copyright (C) 2024 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 "skia_task_executor.h"
17 #include "utils/log.h"
18 
19 #ifdef SKIA_PRIO_SCHED_ENABLE
20 #include "qos.h"
21 #endif
22 
23 namespace OHOS {
24 namespace Rosen {
25 
TaskPoolExecutor()26 TaskPoolExecutor::TaskPoolExecutor()
27 {
28     InitThreadPool();
29 }
30 
GetInstance()31 TaskPoolExecutor& TaskPoolExecutor::GetInstance()
32 {
33     static TaskPoolExecutor pool;
34     return pool;
35 }
36 
PostTask(Task && task)37 void TaskPoolExecutor::PostTask(Task&& task)
38 {
39     GetInstance().EnqueueTask(std::move(task));
40 }
41 
InitThreadPool()42 void TaskPoolExecutor::InitThreadPool()
43 {
44     TaskPoolExecutor* pool = this;
45     // 3 threads are created by default.
46     for (uint32_t i = 0; i < DEFAULT_THREAD_COUNT; i++) {
47         std::thread thread([pool, i] {
48             {
49                 std::string name{"SkiaExecutor-"};
50                 name.append(std::to_string(i));
51 #if defined(MAC_PLATFORM) || defined(IOS_PLATFORM)
52                 pthread_setname_np(name.c_str());
53 #else
54                 pthread_setname_np(pthread_self(), name.c_str());
55 #endif
56             }
57             pool->ThreadLoop();
58         });
59         thread.detach();
60     }
61 }
62 
EnqueueTask(Task && task)63 void TaskPoolExecutor::EnqueueTask(Task&& task)
64 {
65     std::unique_lock lock(mutex_);
66     while (!taskQueue_.HasSpace()) {
67         lock.unlock();
68         usleep(WAIT_SLEEP_TIME);
69         lock.lock();
70     }
71     taskQueue_.Push(std::move(task));
72     if (waitingThread_ == DEFAULT_THREAD_COUNT || (waitingThread_ > 0 && taskQueue_.Size() > 1)) {
73         condition_.notify_one();
74     }
75 }
76 
77 #ifdef RES_SCHED_ENABLE
PromoteThreadPriority()78 void TaskPoolExecutor::PromoteThreadPriority()
79 {
80     if (RsFrameReport::GetInstance().GetEnable()) {
81         RsFrameReport::GetInstance().SetFrameParam(REQUEST_THREAD_PRIORITY_ID, REQUEST_THREAD_PRIORITY_LOAD,
82             REQUEST_THREAD_PRIORITY_NUM, gettid());
83     }
84 }
85 #endif
86 
ThreadLoop()87 void TaskPoolExecutor::ThreadLoop()
88 {
89 #ifdef RES_SCHED_ENABLE
90     PromoteThreadPriority();
91 #endif
92 
93 #ifdef SKIA_PRIO_SCHED_ENABLE
94     auto ret = OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_USER_INTERACTIVE);
95     LOGI("SkiaExecutor: SetThreadQos retcode = %{public}d", ret);
96 #endif
97     std::unique_lock lock(mutex_);
98     while (running_) {
99         if (!taskQueue_.HasTask()) {
100             waitingThread_++;
101             condition_.wait(lock);
102             waitingThread_--;
103         }
104         while (taskQueue_.HasTask()) {
105             auto task = taskQueue_.Pop();
106             lock.unlock();
107             if (task != nullptr) {
108                 task();
109             }
110             lock.lock();
111         }
112     }
113 }
114 } // namespace Rosen
115 } // namespace OHOS