Home | History | Annotate | Download | only in thread
      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 
     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         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();
    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