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