summaryrefslogtreecommitdiff
path: root/libs/hwui/thread/WorkQueue.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/thread/WorkQueue.h')
-rw-r--r--libs/hwui/thread/WorkQueue.h145
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