blob: aef2990d63434d1f91a51523cd92269c50d53026 [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
60 constexpr T&& pop() {
61 LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
62 int index = mTail;
63 mTail = (mTail + 1) % SIZE;
64 return std::move(mBuffer[index]);
65 }
66
67private:
68 T mBuffer[SIZE];
69 int mHead = 0;
70 int mTail = 0;
71};
72
73class CommonPool {
74 PREVENT_COPY_AND_ASSIGN(CommonPool);
75
76public:
77 using Task = std::function<void()>;
78 static constexpr auto THREAD_COUNT = 2;
79 static constexpr auto QUEUE_SIZE = 128;
80
81 static void post(Task&& func);
82
83 template <class F>
84 static auto async(F&& func) -> std::future<decltype(func())> {
85 typedef std::packaged_task<decltype(func())()> task_t;
86 auto task = std::make_shared<task_t>(std::forward<F>(func));
87 post([task]() { std::invoke(*task); });
88 return task->get_future();
89 }
90
91 template <class F>
92 static auto runSync(F&& func) -> decltype(func()) {
93 std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
94 post([&task]() { std::invoke(task); });
95 return task.get_future().get();
96 };
97
98private:
99 CommonPool();
100 ~CommonPool() {}
101
102 void enqueue(Task&&);
103
104 void workerLoop();
105
106 std::mutex mLock;
107 std::condition_variable mCondition;
108 int mWaitingThreads = 0;
109 ArrayQueue<Task, QUEUE_SIZE> mWorkQueue;
110};
111
112} // namespace uirenderer
113} // namespace android
114
115#endif // FRAMEWORKS_BASE_COMMONPOOL_H