1 /*
2 * Copyright (C) 2024 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "C2BqPoolInvalidator"
19 #include <utils/Log.h>
20 #include <utils/SystemClock.h>
21
22 #include <C2BqBufferPriv.h>
23 #include <C2BqPoolInvalidator.h>
24
25 namespace android {
26
27 namespace {
28 static constexpr int64_t kBqPoolInvalidateDelayMs = 1000;
29 } // anonymous namespace
30
C2BqPoolInvalidateItem(std::list<std::shared_ptr<C2BufferQueueBlockPool>> && pools)31 C2BqPoolInvalidateItem::C2BqPoolInvalidateItem(
32 std::list<std::shared_ptr<C2BufferQueueBlockPool>> &&pools) : mPools(std::move(pools)) {
33 if (!mPools.empty()) {
34 mNeedsInvalidate = true;
35 } else {
36 mNeedsInvalidate = false;
37 }
38 }
39
invalidate()40 void C2BqPoolInvalidateItem::invalidate() {
41 std::list<std::shared_ptr<C2BufferQueueBlockPool>> pools;
42 {
43 std::unique_lock<std::mutex> l(mLock);
44 if (!mNeedsInvalidate) {
45 return;
46 }
47 pools = std::move(mPools);
48 mNeedsInvalidate = false;
49 }
50 for(auto it = pools.begin(); it != pools.end(); ++it) {
51 (*it)->invalidate();
52 }
53 }
54
skip()55 void C2BqPoolInvalidateItem::skip() {
56 std::unique_lock<std::mutex> l(mLock);
57 mNeedsInvalidate = false;
58 mPools.clear();
59 }
60
needsInvalidate()61 bool C2BqPoolInvalidateItem::needsInvalidate() {
62 std::unique_lock<std::mutex> l(mLock);
63 return mNeedsInvalidate;
64 }
65
getInstance()66 C2BqPoolInvalidator &C2BqPoolInvalidator::getInstance() {
67 static android::base::NoDestructor<C2BqPoolInvalidator> sInvalidator;
68 return *sInvalidator;
69 }
70
C2BqPoolInvalidator()71 C2BqPoolInvalidator::C2BqPoolInvalidator() : mDone(false) {
72 mThread = std::thread(&C2BqPoolInvalidator::run, this);
73 }
74
~C2BqPoolInvalidator()75 C2BqPoolInvalidator::~C2BqPoolInvalidator() {
76 {
77 std::unique_lock<std::mutex> l(mMutex);
78 mDone = true;
79 mCv.notify_one();
80 }
81 if (mThread.joinable()) {
82 mThread.join();
83 }
84 }
85
queue(std::shared_ptr<C2BqPoolInvalidateItem> & item)86 void C2BqPoolInvalidator::queue(std::shared_ptr<C2BqPoolInvalidateItem> &item) {
87 std::unique_lock<std::mutex> l(mMutex);
88 std::pair<int64_t, std::shared_ptr<C2BqPoolInvalidateItem>> p =
89 std::make_pair(::android::elapsedRealtime() + kBqPoolInvalidateDelayMs, item);
90 mItems.push_back(p);
91 mCv.notify_one();
92 }
93
run()94 void C2BqPoolInvalidator::run() {
95 while(true) {
96 int64_t nowMs = ::android::elapsedRealtime();
97 std::unique_lock<std::mutex> l(mMutex);
98 if (mDone) {
99 break;
100 }
101 std::list<std::shared_ptr<C2BqPoolInvalidateItem>> items;
102 while (!mItems.empty()) {
103 if (mItems.front().first <= nowMs) {
104 items.push_back(mItems.front().second);
105 mItems.pop_front();
106 } else {
107 break;
108 }
109 }
110 if (items.empty()) {
111 if (mItems.empty()) {
112 mCv.wait(l);
113 } else {
114 int64_t nextMs = mItems.front().first;
115 if (nextMs > nowMs) {
116 mCv.wait_for(l, std::chrono::milliseconds(nextMs - nowMs));
117 }
118 }
119 } else {
120 l.unlock();
121 int invalidated = 0;
122 for (auto it = items.begin(); it != items.end(); ++it, ++invalidated) {
123 (*it)->invalidate();
124 }
125 ALOGD("invalidated %d bqpool items", invalidated);
126 }
127 }
128 }
129
130 } // android
131