blob: 7603eeef469284da73048dc0ca446c11584a5240 [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>
28
29namespace android {
30namespace uirenderer {
31
32template <class T, int SIZE>
33class ArrayQueue {
34 PREVENT_COPY_AND_ASSIGN(ArrayQueue);
35 static_assert(SIZE > 0, "Size must be positive");
36
37public:
38 ArrayQueue() = default;
39 ~ArrayQueue() = default;
40
41 constexpr size_t capacity() const { return SIZE; }
42 constexpr bool hasWork() const { return mHead != mTail; }
43 constexpr bool hasSpace() const { return ((mHead + 1) % SIZE) != mTail; }
44 constexpr int size() const {
45 if (mHead > mTail) {
46 return mHead - mTail;
47 } else {
48 return mTail - mHead + SIZE;
49 }
50 }
51
52 constexpr void push(T&& t) {
53 int newHead = (mHead + 1) % SIZE;
54 LOG_ALWAYS_FATAL_IF(newHead == mTail, "no space");
55
56 mBuffer[mHead] = std::move(t);
57 mHead = newHead;
58 }
59
John Reckcfd929d2019-04-08 11:28:15 -070060 constexpr T pop() {
John Reck322b8ab2019-03-14 13:15:28 -070061 LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
62 int index = mTail;
63 mTail = (mTail + 1) % SIZE;
John Reckcfd929d2019-04-08 11:28:15 -070064 T ret = std::move(mBuffer[index]);
65 mBuffer[index] = nullptr;
66 return ret;
John Reck322b8ab2019-03-14 13:15:28 -070067 }
68
69private:
70 T mBuffer[SIZE];
71 int mHead = 0;
72 int mTail = 0;
73};
74
75class CommonPool {
76 PREVENT_COPY_AND_ASSIGN(CommonPool);
77
78public:
79 using Task = std::function<void()>;
80 static constexpr auto THREAD_COUNT = 2;
81 static constexpr auto QUEUE_SIZE = 128;
82
83 static void post(Task&& func);
84
85 template <class F>
86 static auto async(F&& func) -> std::future<decltype(func())> {
87 typedef std::packaged_task<decltype(func())()> task_t;
88 auto task = std::make_shared<task_t>(std::forward<F>(func));
89 post([task]() { std::invoke(*task); });
90 return task->get_future();
91 }
92
93 template <class F>
94 static auto runSync(F&& func) -> decltype(func()) {
95 std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
96 post([&task]() { std::invoke(task); });
97 return task.get_future().get();
98 };
99
John Reckcfd929d2019-04-08 11:28:15 -0700100 // For testing purposes only, blocks until all worker threads are parked.
101 static void waitForIdle();
102
John Reck322b8ab2019-03-14 13:15:28 -0700103private:
John Reckcfd929d2019-04-08 11:28:15 -0700104 static CommonPool& instance();
105
John Reck322b8ab2019-03-14 13:15:28 -0700106 CommonPool();
107 ~CommonPool() {}
108
109 void enqueue(Task&&);
John Reckcfd929d2019-04-08 11:28:15 -0700110 void doWaitForIdle();
John Reck322b8ab2019-03-14 13:15:28 -0700111
112 void workerLoop();
113
114 std::mutex mLock;
115 std::condition_variable mCondition;
116 int mWaitingThreads = 0;
117 ArrayQueue<Task, QUEUE_SIZE> mWorkQueue;
118};
119
120} // namespace uirenderer
121} // namespace android
122
123#endif // FRAMEWORKS_BASE_COMMONPOOL_H