1 /* 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 #include <vector> 29 30 namespace android { 31 namespace uirenderer { 32 33 template <class T, int SIZE> 34 class ArrayQueue { 35 PREVENT_COPY_AND_ASSIGN(ArrayQueue); 36 static_assert(SIZE > 0, "Size must be positive"); 37 38 public: 39 ArrayQueue() = default; 40 ~ArrayQueue() = default; 41 capacity()42 constexpr size_t capacity() const { return SIZE; } hasWork()43 constexpr bool hasWork() const { return mHead != mTail; } hasSpace()44 constexpr bool hasSpace() const { return ((mHead + 1) % SIZE) != mTail; } size()45 constexpr int size() const { 46 if (mHead > mTail) { 47 return mHead - mTail; 48 } else { 49 return mTail - mHead + SIZE; 50 } 51 } 52 push(T && t)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 pop()61 constexpr T pop() { 62 LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty"); 63 int index = mTail; 64 mTail = (mTail + 1) % SIZE; 65 T ret = std::move(mBuffer[index]); 66 mBuffer[index] = nullptr; 67 return ret; 68 } 69 70 private: 71 T mBuffer[SIZE]; 72 int mHead = 0; 73 int mTail = 0; 74 }; 75 76 class CommonPool { 77 PREVENT_COPY_AND_ASSIGN(CommonPool); 78 79 public: 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 101 static std::vector<int> getThreadIds(); 102 103 // For testing purposes only, blocks until all worker threads are parked. 104 static void waitForIdle(); 105 106 private: 107 static CommonPool& instance(); 108 109 CommonPool(); ~CommonPool()110 ~CommonPool() {} 111 112 void enqueue(Task&&); 113 void doWaitForIdle(); 114 115 void workerLoop(); 116 117 std::vector<int> mWorkerThreadIds; 118 119 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 129