blob: 0c025b4f0ee7da78a3d605a64535ea1c6a2f3dc0 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FRAMEWORKS_BASE_COMMONPOOL_H
#define FRAMEWORKS_BASE_COMMONPOOL_H
#include <log/log.h>
#include <condition_variable>
#include <functional>
#include <future>
#include <mutex>
#include <vector>
#include "thread/CommonPoolBase.h"
#include "utils/Macros.h"
namespace android {
namespace uirenderer {
template <class T, int SIZE>
class ArrayQueue {
PREVENT_COPY_AND_ASSIGN(ArrayQueue);
static_assert(SIZE > 0, "Size must be positive");
public:
ArrayQueue() = default;
~ArrayQueue() = default;
constexpr size_t capacity() const { return SIZE; }
constexpr bool hasWork() const { return mHead != mTail; }
constexpr bool hasSpace() const { return ((mHead + 1) % SIZE) != mTail; }
constexpr int size() const {
if (mHead > mTail) {
return mHead - mTail;
} else {
return mTail - mHead + SIZE;
}
}
constexpr void push(T&& t) {
int newHead = (mHead + 1) % SIZE;
LOG_ALWAYS_FATAL_IF(newHead == mTail, "no space");
mBuffer[mHead] = std::move(t);
mHead = newHead;
}
constexpr T pop() {
LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
int index = mTail;
mTail = (mTail + 1) % SIZE;
T ret = std::move(mBuffer[index]);
mBuffer[index] = nullptr;
return ret;
}
private:
T mBuffer[SIZE];
int mHead = 0;
int mTail = 0;
};
class CommonPool : private CommonPoolBase {
PREVENT_COPY_AND_ASSIGN(CommonPool);
public:
using Task = std::function<void()>;
static constexpr auto THREAD_COUNT = 2;
static constexpr auto QUEUE_SIZE = 128;
static void post(Task&& func);
template <class F>
static auto async(F&& func) -> std::future<decltype(func())> {
typedef std::packaged_task<decltype(func())()> task_t;
auto task = std::make_shared<task_t>(std::forward<F>(func));
post([task]() { std::invoke(*task); });
return task->get_future();
}
template <class F>
static auto runSync(F&& func) -> decltype(func()) {
std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
post([&task]() { std::invoke(task); });
return task.get_future().get();
};
static std::vector<int> getThreadIds();
// For testing purposes only, blocks until all worker threads are parked.
static void waitForIdle();
private:
static CommonPool& instance();
CommonPool();
~CommonPool() {
mIsStopping = true;
mCondition.notify_all();
}
void enqueue(Task&&);
void doWaitForIdle();
void workerLoop();
std::vector<int> mWorkerThreadIds;
std::mutex mLock;
std::condition_variable mCondition;
int mWaitingThreads = 0;
ArrayQueue<Task, QUEUE_SIZE> mWorkQueue;
std::atomic_bool mIsStopping = false;
};
} // namespace uirenderer
} // namespace android
#endif // FRAMEWORKS_BASE_COMMONPOOL_H
|