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 <log/log.h> 21 22 #include <condition_variable> 23 #include <functional> 24 #include <future> 25 #include <mutex> 26 #include <vector> 27 28 #include "thread/CommonPoolBase.h" 29 #include "utils/Macros.h" 30 31 namespace android { 32 namespace uirenderer { 33 34 template <class T, int SIZE> 35 class ArrayQueue { 36 PREVENT_COPY_AND_ASSIGN(ArrayQueue); 37 static_assert(SIZE > 0, "Size must be positive"); 38 39 public: 40 ArrayQueue() = default; 41 ~ArrayQueue() = default; 42 capacity()43 constexpr size_t capacity() const { return SIZE; } hasWork()44 constexpr bool hasWork() const { return mHead != mTail; } hasSpace()45 constexpr bool hasSpace() const { return ((mHead + 1) % SIZE) != mTail; } size()46 constexpr int size() const { 47 if (mHead > mTail) { 48 return mHead - mTail; 49 } else { 50 return mTail - mHead + SIZE; 51 } 52 } 53 push(T && t)54 constexpr void push(T&& t) { 55 int newHead = (mHead + 1) % SIZE; 56 LOG_ALWAYS_FATAL_IF(newHead == mTail, "no space"); 57 58 mBuffer[mHead] = std::move(t); 59 mHead = newHead; 60 } 61 pop()62 constexpr T pop() { 63 LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty"); 64 int index = mTail; 65 mTail = (mTail + 1) % SIZE; 66 T ret = std::move(mBuffer[index]); 67 mBuffer[index] = nullptr; 68 return ret; 69 } 70 71 private: 72 T mBuffer[SIZE]; 73 int mHead = 0; 74 int mTail = 0; 75 }; 76 77 class CommonPool : private CommonPoolBase { 78 PREVENT_COPY_AND_ASSIGN(CommonPool); 79 80 public: 81 using Task = std::function<void()>; 82 static constexpr auto THREAD_COUNT = 2; 83 static constexpr auto QUEUE_SIZE = 128; 84 85 static void post(Task&& func); 86 87 template <class F> 88 static auto async(F&& func) -> std::future<decltype(func())> { 89 typedef std::packaged_task<decltype(func())()> task_t; 90 auto task = std::make_shared<task_t>(std::forward<F>(func)); 91 post([task]() { std::invoke(*task); }); 92 return task->get_future(); 93 } 94 95 template <class F> 96 static auto runSync(F&& func) -> decltype(func()) { 97 std::packaged_task<decltype(func())()> task{std::forward<F>(func)}; 98 post([&task]() { std::invoke(task); }); 99 return task.get_future().get(); 100 }; 101 102 static std::vector<int> getThreadIds(); 103 104 // For testing purposes only, blocks until all worker threads are parked. 105 static void waitForIdle(); 106 107 private: 108 static CommonPool& instance(); 109 110 CommonPool(); ~CommonPool()111 ~CommonPool() { 112 mIsStopping = true; 113 mCondition.notify_all(); 114 } 115 116 void enqueue(Task&&); 117 void doWaitForIdle(); 118 119 void workerLoop(); 120 121 std::vector<int> mWorkerThreadIds; 122 123 std::mutex mLock; 124 std::condition_variable mCondition; 125 int mWaitingThreads = 0; 126 ArrayQueue<Task, QUEUE_SIZE> mWorkQueue; 127 std::atomic_bool mIsStopping = false; 128 }; 129 130 } // namespace uirenderer 131 } // namespace android 132 133 #endif // FRAMEWORKS_BASE_COMMONPOOL_H 134