diff options
Diffstat (limited to 'libs/hwui/thread/WorkQueue.h')
-rw-r--r-- | libs/hwui/thread/WorkQueue.h | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/libs/hwui/thread/WorkQueue.h b/libs/hwui/thread/WorkQueue.h new file mode 100644 index 000000000000..7a6e638e0568 --- /dev/null +++ b/libs/hwui/thread/WorkQueue.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HWUI_WORKQUEUE_H +#define HWUI_WORKQUEUE_H + +#include "utils/Macros.h" + +#include <log/log.h> +#include <utils/Timers.h> + +#include <condition_variable> +#include <functional> +#include <future> +#include <mutex> +#include <variant> +#include <vector> + +namespace android::uirenderer { + +struct MonotonicClock { + static nsecs_t now() { return systemTime(CLOCK_MONOTONIC); } +}; + +class WorkQueue { + PREVENT_COPY_AND_ASSIGN(WorkQueue); + +public: + using clock = MonotonicClock; + +private: + struct WorkItem { + WorkItem() = delete; + WorkItem(const WorkItem& other) = delete; + WorkItem& operator=(const WorkItem& other) = delete; + WorkItem(WorkItem&& other) = default; + WorkItem& operator=(WorkItem&& other) = default; + + WorkItem(nsecs_t runAt, std::function<void()>&& work) + : runAt(runAt), work(std::move(work)) {} + + nsecs_t runAt; + std::function<void()> work; + }; + +public: + WorkQueue(std::function<void()>&& wakeFunc, std::mutex& lock) + : mWakeFunc(move(wakeFunc)), mLock(lock) {} + + void process() { + auto now = clock::now(); + std::vector<WorkItem> toProcess; + { + std::unique_lock _lock{mLock}; + if (mWorkQueue.empty()) return; + toProcess = std::move(mWorkQueue); + auto moveBack = find_if(std::begin(toProcess), std::end(toProcess), + [&now](WorkItem& item) { return item.runAt > now; }); + if (moveBack != std::end(toProcess)) { + mWorkQueue.reserve(std::distance(moveBack, std::end(toProcess)) + 5); + std::move(moveBack, std::end(toProcess), std::back_inserter(mWorkQueue)); + toProcess.erase(moveBack, std::end(toProcess)); + } + } + for (auto& item : toProcess) { + item.work(); + } + } + + template <class F> + void postAt(nsecs_t time, F&& func) { + enqueue(WorkItem{time, std::function<void()>(std::forward<F>(func))}); + } + + template <class F> + void postDelayed(nsecs_t delay, F&& func) { + enqueue(WorkItem{clock::now() + delay, std::function<void()>(std::forward<F>(func))}); + } + + template <class F> + void post(F&& func) { + postAt(0, std::forward<F>(func)); + } + + template <class F> + auto async(F&& func) -> std::future<decltype(func())> { + typedef std::packaged_task<decltype(func())()> task_t; + auto task = std::make_shared<task_t>(std::forward<F>(func)); + post([task]() { std::invoke(*task); }); + return task->get_future(); + } + + template <class F> + auto runSync(F&& func) -> decltype(func()) { + std::packaged_task<decltype(func())()> task{std::forward<F>(func)}; + post([&task]() { std::invoke(task); }); + return task.get_future().get(); + }; + + nsecs_t nextWakeup(std::unique_lock<std::mutex>& lock) { + if (mWorkQueue.empty()) { + return std::numeric_limits<nsecs_t>::max(); + } else { + return std::begin(mWorkQueue)->runAt; + } + } + +private: + void enqueue(WorkItem&& item) { + bool needsWakeup; + { + std::unique_lock _lock{mLock}; + auto insertAt = std::find_if( + std::begin(mWorkQueue), std::end(mWorkQueue), + [time = item.runAt](WorkItem & item) { return item.runAt > time; }); + needsWakeup = std::begin(mWorkQueue) == insertAt; + mWorkQueue.emplace(insertAt, std::move(item)); + } + if (needsWakeup) { + mWakeFunc(); + } + } + + std::function<void()> mWakeFunc; + + std::mutex& mLock; + std::vector<WorkItem> mWorkQueue; +}; + +} // namespace android::uirenderer + +#endif // HWUI_WORKQUEUE_H |