#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { namespace util { using LOOP_HANDLE = void *; class RunLoop : public Scheduler, private util::noncopyable { public: enum class Type : uint8_t { Default, New, }; enum class Priority : bool { Default = false, High = true, }; enum class Event : uint8_t { None = 0, Read = 1, Write = 2, ReadWrite = Read | Write, }; RunLoop(Type type = Type::Default); ~RunLoop() override; static RunLoop* Get(); static LOOP_HANDLE getLoopHandle(); void run(); void runOnce(); void stop(); // So far only needed by the libcurl backend. void addWatch(int fd, Event, std::function&& callback); void removeWatch(int fd); // Invoke fn(args...) on this RunLoop. template void invoke(Priority priority, Fn&& fn, Args&&... args) { push(priority, WorkTask::make(std::forward(fn), std::forward(args)...)); } // Invoke fn(args...) on this RunLoop. template void invoke(Fn&& fn, Args&&... args) { invoke(Priority::Default, std::forward(fn), std::forward(args)...); } // Post the cancellable work fn(args...) to this RunLoop. template std::unique_ptr invokeCancellable(Fn&& fn, Args&&... args) { std::shared_ptr task = WorkTask::make(std::forward(fn), std::forward(args)...); push(Priority::Default, task); return std::make_unique(task); } void schedule(std::function fn) override { invoke(std::move(fn)); } class Impl; private: MBGL_STORE_THREAD(tid) using Queue = std::queue>; // Wakes up the RunLoop so that it starts processing items in the queue. void wake(); // Adds a WorkTask to the queue, and wakes it up. void push(Priority priority, std::shared_ptr task) { std::lock_guard lock(mutex); if (priority == Priority::High) { highPriorityQueue.emplace(std::move(task)); } else { defaultQueue.emplace(std::move(task)); } wake(); } void process() { std::shared_ptr task; std::unique_lock lock(mutex); while (true) { if (!highPriorityQueue.empty()) { task = std::move(highPriorityQueue.front()); highPriorityQueue.pop(); } else if (!defaultQueue.empty()) { task = std::move(defaultQueue.front()); defaultQueue.pop(); } else { break; } lock.unlock(); (*task)(); task.reset(); lock.lock(); } } Queue defaultQueue; Queue highPriorityQueue; std::mutex mutex; std::unique_ptr impl; }; } // namespace util } // namespace mbgl #include