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