From d422c8cac4e436fb2fb1eeafbae5ed5d847e0b00 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 1 Sep 2015 11:09:19 +0300 Subject: [PATCH] [core] Abstract main loop inside RunLoop class --- gyp/platform-android.gypi | 1 + gyp/platform-ios.gypi | 1 + gyp/platform-linux.gypi | 1 + gyp/platform-osx.gypi | 1 + include/mbgl/util/run_loop.hpp | 45 ++++++++--- platform/default/async_task.cpp | 2 +- platform/default/run_loop.cpp | 83 +++++++++++++++++++++ platform/node/src/node_mapbox_gl_native.cpp | 2 +- src/mbgl/storage/default_file_source.cpp | 2 +- src/mbgl/util/run_loop.cpp | 37 --------- src/mbgl/util/thread.hpp | 23 ++---- 11 files changed, 131 insertions(+), 67 deletions(-) create mode 100644 platform/default/run_loop.cpp delete mode 100644 src/mbgl/util/run_loop.cpp diff --git a/gyp/platform-android.gypi b/gyp/platform-android.gypi index dcab0e019..02f46b063 100644 --- a/gyp/platform-android.gypi +++ b/gyp/platform-android.gypi @@ -13,6 +13,7 @@ '../platform/android/log_android.cpp', '../platform/android/asset_root.cpp', '../platform/default/async_task.cpp', + '../platform/default/run_loop.cpp', '../platform/default/thread.cpp', '../platform/default/string_stdlib.cpp', '../platform/default/image.cpp', diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi index 0b23890c4..240fa28e4 100644 --- a/gyp/platform-ios.gypi +++ b/gyp/platform-ios.gypi @@ -11,6 +11,7 @@ 'sources': [ '../platform/default/async_task.cpp', + '../platform/default/run_loop.cpp', '../platform/darwin/log_nslog.mm', '../platform/darwin/string_nsstring.mm', '../platform/darwin/application_root.mm', diff --git a/gyp/platform-linux.gypi b/gyp/platform-linux.gypi index 1ba328c5c..ce2fe3b14 100644 --- a/gyp/platform-linux.gypi +++ b/gyp/platform-linux.gypi @@ -13,6 +13,7 @@ '../platform/default/async_task.cpp', '../platform/default/log_stderr.cpp', '../platform/default/string_stdlib.cpp', + '../platform/default/run_loop.cpp', '../platform/default/application_root.cpp', '../platform/default/asset_root.cpp', '../platform/default/thread.cpp', diff --git a/gyp/platform-osx.gypi b/gyp/platform-osx.gypi index b3941d2e2..a410826b5 100644 --- a/gyp/platform-osx.gypi +++ b/gyp/platform-osx.gypi @@ -11,6 +11,7 @@ 'sources': [ '../platform/default/async_task.cpp', + '../platform/default/run_loop.cpp', '../platform/darwin/log_nslog.mm', '../platform/darwin/string_nsstring.mm', '../platform/darwin/application_root.mm', diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp index 6113ac221..4b9865355 100644 --- a/include/mbgl/util/run_loop.hpp +++ b/include/mbgl/util/run_loop.hpp @@ -1,6 +1,7 @@ #ifndef MBGL_UTIL_RUN_LOOP #define MBGL_UTIL_RUN_LOOP +#include #include #include #include @@ -15,19 +16,26 @@ namespace mbgl { namespace util { +typedef void * LOOP_HANDLE; + class RunLoop : private util::noncopyable { public: - RunLoop(uv_loop_t*); + enum class Type : uint8_t { + Default, + New, + }; + + RunLoop(Type type = Type::Default); ~RunLoop(); static RunLoop* Get() { return current.get(); } - static uv_loop_t* getLoop() { - return current.get()->get(); - } + static LOOP_HANDLE getLoopHandle(); + void run(); + void runOnce(); void stop(); // Invoke fn(args...) on this RunLoop. @@ -39,7 +47,7 @@ public: std::move(tuple)); withMutex([&] { queue.push(task); }); - async.send(); + async->send(); } // Post the cancellable work fn(args...) to this RunLoop. @@ -56,7 +64,7 @@ public: flag); withMutex([&] { queue.push(task); }); - async.send(); + async->send(); return std::make_unique(task); } @@ -90,13 +98,11 @@ public: flag); withMutex([&] { queue.push(task); }); - async.send(); + async->send(); return std::make_unique(task); } - uv_loop_t* get() { return async.get()->loop; } - private: template class Invoker : public WorkTask { @@ -143,12 +149,27 @@ private: using Queue = std::queue>; - void withMutex(std::function&&); - void process(); + void withMutex(std::function&& fn) { + std::lock_guard lock(mutex); + fn(); + } + + void process() { + Queue queue_; + withMutex([&] { queue_.swap(queue); }); + + while (!queue_.empty()) { + (*(queue_.front()))(); + queue_.pop(); + } + } Queue queue; std::mutex mutex; - uv::async async; + std::unique_ptr async; + + class Impl; + std::unique_ptr impl; static uv::tls current; }; diff --git a/platform/default/async_task.cpp b/platform/default/async_task.cpp index 4b4372451..1f2381f71 100644 --- a/platform/default/async_task.cpp +++ b/platform/default/async_task.cpp @@ -12,7 +12,7 @@ namespace util { class AsyncTask::Impl { public: Impl(std::function&& fn) - : async(RunLoop::getLoop(), [this] { runTask(); }) + : async(reinterpret_cast(RunLoop::getLoopHandle()), [this] { runTask(); }) , task(std::move(fn)) { } diff --git a/platform/default/run_loop.cpp b/platform/default/run_loop.cpp new file mode 100644 index 000000000..7c3a74f2c --- /dev/null +++ b/platform/default/run_loop.cpp @@ -0,0 +1,83 @@ +#include + +#include + +namespace mbgl { +namespace util { + +uv::tls RunLoop::current; + +class RunLoop::Impl { +public: + Impl() = default; + + uv_loop_t *loop; + RunLoop::Type type; +}; + +RunLoop::RunLoop(Type type) : impl(std::make_unique()) { + switch (type) { + case Type::New: +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + impl->loop = uv_loop_new(); + if (impl->loop == nullptr) { +#else + impl->loop = new uv_loop_t; + if (uv_loop_init(impl->loop) != 0) { +#endif + throw std::runtime_error("Failed to initialize loop."); + } + break; + case Type::Default: + impl->loop = uv_default_loop(); + break; + } + + impl->type = type; + + current.set(this); + async = std::make_unique(std::bind(&RunLoop::process, this)); +} + +RunLoop::~RunLoop() { + current.set(nullptr); + + if (impl->type == Type::Default) { + return; + } + + // Run the loop again to ensure that async + // close callbacks have been called. Not needed + // for the default main loop because it is only + // closed when the application exits. + async.reset(); + runOnce(); + +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + uv_loop_delete(impl->loop); +#else + if (uv_loop_close(impl->loop) == UV_EBUSY) { + throw std::runtime_error("Failed to close loop."); + } + delete impl->loop; +#endif +} + +LOOP_HANDLE RunLoop::getLoopHandle() { + return current.get()->impl->loop; +} + +void RunLoop::run() { + uv_run(impl->loop, UV_RUN_DEFAULT); +} + +void RunLoop::runOnce() { + uv_run(impl->loop, UV_RUN_ONCE); +} + +void RunLoop::stop() { + invoke([&] { async->unref(); }); +} + +} +} diff --git a/platform/node/src/node_mapbox_gl_native.cpp b/platform/node/src/node_mapbox_gl_native.cpp index 4a86a8d85..e0b094d57 100644 --- a/platform/node/src/node_mapbox_gl_native.cpp +++ b/platform/node/src/node_mapbox_gl_native.cpp @@ -13,7 +13,7 @@ namespace node_mbgl { mbgl::util::RunLoop& NodeRunLoop() { - static mbgl::util::RunLoop nodeRunLoop(uv_default_loop()); + static mbgl::util::RunLoop nodeRunLoop; return nodeRunLoop; } diff --git a/src/mbgl/storage/default_file_source.cpp b/src/mbgl/storage/default_file_source.cpp index 9e2289102..439acd888 100644 --- a/src/mbgl/storage/default_file_source.cpp +++ b/src/mbgl/storage/default_file_source.cpp @@ -78,7 +78,7 @@ void DefaultFileSource::cancel(const Resource& res, FileRequest* req) { // ----- Impl ----- DefaultFileSource::Impl::Impl(FileCache* cache_, const std::string& root) - : loop(util::RunLoop::getLoop()), + : loop(reinterpret_cast(util::RunLoop::getLoopHandle())), cache(cache_), assetRoot(root.empty() ? platform::assetRoot() : root), assetContext(AssetContextBase::createContext(loop)), diff --git a/src/mbgl/util/run_loop.cpp b/src/mbgl/util/run_loop.cpp deleted file mode 100644 index 7f277c988..000000000 --- a/src/mbgl/util/run_loop.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include - -namespace mbgl { -namespace util { - -uv::tls RunLoop::current; - -RunLoop::RunLoop(uv_loop_t* loop) - : async(loop, std::bind(&RunLoop::process, this)) { - current.set(this); -} - -RunLoop::~RunLoop() { - current.set(nullptr); -} - -void RunLoop::withMutex(std::function&& fn) { - std::lock_guard lock(mutex); - fn(); -} - -void RunLoop::process() { - Queue queue_; - withMutex([&] { queue_.swap(queue); }); - - while (!queue_.empty()) { - (*(queue_.front()))(); - queue_.pop(); - } -} - -void RunLoop::stop() { - invoke([&] { async.unref(); }); -} - -} -} diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp index d7611254c..7924d3d4c 100644 --- a/src/mbgl/util/thread.hpp +++ b/src/mbgl/util/thread.hpp @@ -112,26 +112,19 @@ Thread::Thread(const ThreadContext& context, Args&&... args) { template template void Thread::run(ThreadContext context, P&& params, std::index_sequence) { - uv::loop l; - ThreadContext::current.set(&context); - { - RunLoop loop_(l.get()); - loop = &loop_; + RunLoop loop_(RunLoop::Type::New); + loop = &loop_; - Object object_(std::get(std::forward

(params))...); - object = &object_; + Object object_(std::get(std::forward

(params))...); + object = &object_; - running.set_value(); - l.run(); + running.set_value(); + loop_.run(); - loop = nullptr; - object = nullptr; - } - - // Run the loop again to ensure that async close callbacks have been called. - l.run(); + loop = nullptr; + object = nullptr; ThreadContext::current.set(nullptr);