Home | History | Annotate | Download | only in thread
      1 /*
      2  * Copyright (C) 2017 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 HWUI_WORKQUEUE_H
     18 #define HWUI_WORKQUEUE_H
     19 
     20 #include "utils/Macros.h"
     21 
     22 #include <log/log.h>
     23 #include <utils/Timers.h>
     24 
     25 #include <condition_variable>
     26 #include <functional>
     27 #include <future>
     28 #include <mutex>
     29 #include <variant>
     30 #include <vector>
     31 
     32 namespace android::uirenderer {
     33 
     34 struct MonotonicClock {
     35     static nsecs_t now() { return systemTime(CLOCK_MONOTONIC); }
     36 };
     37 
     38 class WorkQueue {
     39     PREVENT_COPY_AND_ASSIGN(WorkQueue);
     40 
     41 public:
     42     using clock = MonotonicClock;
     43 
     44 private:
     45     struct WorkItem {
     46         WorkItem() = delete;
     47         WorkItem(const WorkItem& other) = delete;
     48         WorkItem& operator=(const WorkItem& other) = delete;
     49         WorkItem(WorkItem&& other) = default;
     50         WorkItem& operator=(WorkItem&& other) = default;
     51 
     52         WorkItem(nsecs_t runAt, std::function<void()>&& work)
     53                 : runAt(runAt), work(std::move(work)) {}
     54 
     55         nsecs_t runAt;
     56         std::function<void()> work;
     57     };
     58 
     59 public:
     60     WorkQueue(std::function<void()>&& wakeFunc, std::mutex& lock)
     61             : mWakeFunc(move(wakeFunc)), mLock(lock) {}
     62 
     63     void process() {
     64         auto now = clock::now();
     65         std::vector<WorkItem> toProcess;
     66         {
     67             std::unique_lock _lock{mLock};
     68             if (mWorkQueue.empty()) return;
     69             toProcess = std::move(mWorkQueue);
     70             auto moveBack = find_if(std::begin(toProcess), std::end(toProcess),
     71                                     [&now](WorkItem& item) { return item.runAt > now; });
     72             if (moveBack != std::end(toProcess)) {
     73                 mWorkQueue.reserve(std::distance(moveBack, std::end(toProcess)) + 5);
     74                 std::move(moveBack, std::end(toProcess), std::back_inserter(mWorkQueue));
     75                 toProcess.erase(moveBack, std::end(toProcess));
     76             }
     77         }
     78         for (auto& item : toProcess) {
     79             item.work();
     80         }
     81     }
     82 
     83     template <class F>
     84     void postAt(nsecs_t time, F&& func) {
     85         enqueue(WorkItem{time, std::function<void()>(std::forward<F>(func))});
     86     }
     87 
     88     template <class F>
     89     void postDelayed(nsecs_t delay, F&& func) {
     90         enqueue(WorkItem{clock::now() + delay, std::function<void()>(std::forward<F>(func))});
     91     }
     92 
     93     template <class F>
     94     void post(F&& func) {
     95         postAt(0, std::forward<F>(func));
     96     }
     97 
     98     template <class F>
     99     auto async(F&& func) -> std::future<decltype(func())> {
    100         typedef std::packaged_task<decltype(func())()> task_t;
    101         auto task = std::make_shared<task_t>(std::forward<F>(func));
    102         post([task]() { std::invoke(*task); });
    103         return task->get_future();
    104     }
    105 
    106     template <class F>
    107     auto runSync(F&& func) -> decltype(func()) {
    108         std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
    109         post([&task]() { std::invoke(task); });
    110         return task.get_future().get();
    111     };
    112 
    113     nsecs_t nextWakeup(std::unique_lock<std::mutex>& lock) {
    114         if (mWorkQueue.empty()) {
    115             return std::numeric_limits<nsecs_t>::max();
    116         } else {
    117             return std::begin(mWorkQueue)->runAt;
    118         }
    119     }
    120 
    121 private:
    122     void enqueue(WorkItem&& item) {
    123         bool needsWakeup;
    124         {
    125             std::unique_lock _lock{mLock};
    126             auto insertAt = std::find_if(
    127                     std::begin(mWorkQueue), std::end(mWorkQueue),
    128                     [time = item.runAt](WorkItem & item) { return item.runAt > time; });
    129             needsWakeup = std::begin(mWorkQueue) == insertAt;
    130             mWorkQueue.emplace(insertAt, std::move(item));
    131         }
    132         if (needsWakeup) {
    133             mWakeFunc();
    134         }
    135     }
    136 
    137     std::function<void()> mWakeFunc;
    138 
    139     std::mutex& mLock;
    140     std::vector<WorkItem> mWorkQueue;
    141 };
    142 
    143 }  // namespace android::uirenderer
    144 
    145 #endif  // HWUI_WORKQUEUE_H
    146