#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(); // Platform integration callback for platforms that do not have full // run loop integration or don't want to block at the Mapbox GL Native // loop. It will be called from any thread and is up to the platform // to, after receiving the callback, call RunLoop::runOnce() from the // same thread as the Map object lives. void setPlatformCallback(std::function callback) { platformCallback = std::move(callback); } // 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)); } ::mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } 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(); if (platformCallback) { platformCallback(); } } 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(); } } std::function platformCallback; Queue defaultQueue; Queue highPriorityQueue; std::mutex mutex; std::unique_ptr impl; ::mapbox::base::WeakPtrFactory weakFactory{this}; }; } // namespace util } // namespace mbgl #include