1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "CommonPool.h"
18 
19 #undef LOG_TAG
20 #define LOG_TAG "RenderEngine"
21 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
22 
23 #include <sys/resource.h>
24 #include <utils/Trace.h>
25 
26 #include <system/thread_defs.h>
27 #include <array>
28 
29 namespace android {
30 namespace renderengine {
31 namespace skia {
32 
CommonPool()33 CommonPool::CommonPool() {
34     ATRACE_CALL();
35 
36     CommonPool* pool = this;
37     // Create 2 workers
38     for (int i = 0; i < THREAD_COUNT; i++) {
39         std::thread worker([pool, i] {
40             {
41                 std::array<char, 20> name{"reTask"};
42                 snprintf(name.data(), name.size(), "reTask%d", i);
43                 auto self = pthread_self();
44                 pthread_setname_np(self, name.data());
45                 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_FOREGROUND);
46             }
47             pool->workerLoop();
48         });
49         worker.detach();
50     }
51 }
52 
instance()53 CommonPool& CommonPool::instance() {
54     static CommonPool pool;
55     return pool;
56 }
57 
post(Task && task)58 void CommonPool::post(Task&& task) {
59     instance().enqueue(std::move(task));
60 }
61 
enqueue(Task && task)62 void CommonPool::enqueue(Task&& task) {
63     std::unique_lock lock(mLock);
64     while (mWorkQueue.size() > QUEUE_SIZE) {
65         lock.unlock();
66         ALOGW("Queue is full: %d, waiting before adding more tasks.", QUEUE_SIZE);
67         usleep(100);
68         lock.lock();
69     }
70     mWorkQueue.push(std::move(task));
71     if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
72         mCondition.notify_one();
73     }
74 }
75 
workerLoop()76 void CommonPool::workerLoop() {
77     std::unique_lock lock(mLock);
78     while (true) {
79         if (mWorkQueue.size() == 0) {
80             mWaitingThreads++;
81             mCondition.wait(lock);
82             mWaitingThreads--;
83         }
84         // Need to double-check that work is still available now that we have the lock
85         // It may have already been grabbed by a different thread
86         while (mWorkQueue.size() > 0) {
87             auto work = mWorkQueue.front();
88             mWorkQueue.pop();
89             lock.unlock();
90             work();
91             lock.lock();
92         }
93     }
94 }
95 
96 } // namespace skia
97 } // namespace renderengine
98 } // namespace android