blob: 74f852bd1413748a8e78b1168b1ad7073c93f3aa [file] [log] [blame]
John Reck322b8ab2019-03-14 13:15:28 -07001/*
2 * Copyright (C) 2019 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#ifndef FRAMEWORKS_BASE_COMMONPOOL_H
18#define FRAMEWORKS_BASE_COMMONPOOL_H
19
20#include "utils/Macros.h"
21
22#include <log/log.h>
23
24#include <condition_variable>
25#include <functional>
26#include <future>
27#include <mutex>
Bo Liu027b2182021-03-18 16:50:38 -040028#include <vector>
John Reck322b8ab2019-03-14 13:15:28 -070029
30namespace android {
31namespace uirenderer {
32
33template <class T, int SIZE>
34class ArrayQueue {
35 PREVENT_COPY_AND_ASSIGN(ArrayQueue);
36 static_assert(SIZE > 0, "Size must be positive");
37
38public:
39 ArrayQueue() = default;
40 ~ArrayQueue() = default;
41
42 constexpr size_t capacity() const { return SIZE; }
43 constexpr bool hasWork() const { return mHead != mTail; }
44 constexpr bool hasSpace() const { return ((mHead + 1) % SIZE) != mTail; }
45 constexpr int size() const {
46 if (mHead > mTail) {
47 return mHead - mTail;
48 } else {
49 return mTail - mHead + SIZE;
50 }
51 }
52
53 constexpr void push(T&& t) {
54 int newHead = (mHead + 1) % SIZE;
55 LOG_ALWAYS_FATAL_IF(newHead == mTail, "no space");
56
57 mBuffer[mHead] = std::move(t);
58 mHead = newHead;
59 }
60
John Reckcfd929d2019-04-08 11:28:15 -070061 constexpr T pop() {
John Reck322b8ab2019-03-14 13:15:28 -070062 LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
63 int index = mTail;
64 mTail = (mTail + 1) % SIZE;
John Reckcfd929d2019-04-08 11:28:15 -070065 T ret = std::move(mBuffer[index]);
66 mBuffer[index] = nullptr;
67 return ret;
John Reck322b8ab2019-03-14 13:15:28 -070068 }
69
70private:
71 T mBuffer[SIZE];
72 int mHead = 0;
73 int mTail = 0;
74};
75
76class CommonPool {
77 PREVENT_COPY_AND_ASSIGN(CommonPool);
78
79public:
80 using Task = std::function<void()>;
81 static constexpr auto THREAD_COUNT = 2;
82 static constexpr auto QUEUE_SIZE = 128;
83
84 static void post(Task&& func);
85
86 template <class F>
87 static auto async(F&& func) -> std::future<decltype(func())> {
88 typedef std::packaged_task<decltype(func())()> task_t;
89 auto task = std::make_shared<task_t>(std::forward<F>(func));
90 post([task]() { std::invoke(*task); });
91 return task->get_future();
92 }
93
94 template <class F>
95 static auto runSync(F&& func) -> decltype(func()) {
96 std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
97 post([&task]() { std::invoke(task); });
98 return task.get_future().get();
99 };
100
Bo Liu027b2182021-03-18 16:50:38 -0400101 static std::vector<int> getThreadIds();
102
John Reckcfd929d2019-04-08 11:28:15 -0700103 // For testing purposes only, blocks until all worker threads are parked.
104 static void waitForIdle();
105
John Reck322b8ab2019-03-14 13:15:28 -0700106private:
John Reckcfd929d2019-04-08 11:28:15 -0700107 static CommonPool& instance();
108
John Reck322b8ab2019-03-14 13:15:28 -0700109 CommonPool();
110 ~CommonPool() {}
111
112 void enqueue(Task&&);
John Reckcfd929d2019-04-08 11:28:15 -0700113 void doWaitForIdle();
John Reck322b8ab2019-03-14 13:15:28 -0700114
115 void workerLoop();
116
Bo Liu027b2182021-03-18 16:50:38 -0400117 std::vector<int> mWorkerThreadIds;
118
John Reck322b8ab2019-03-14 13:15:28 -0700119 std::mutex mLock;
120 std::condition_variable mCondition;
121 int mWaitingThreads = 0;
122 ArrayQueue<Task, QUEUE_SIZE> mWorkQueue;
123};
124
125} // namespace uirenderer
126} // namespace android
127
128#endif // FRAMEWORKS_BASE_COMMONPOOL_H