[core] Abstract main loop inside RunLoop class
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef MBGL_UTIL_RUN_LOOP
|
||||
#define MBGL_UTIL_RUN_LOOP
|
||||
|
||||
#include <mbgl/util/async_task.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/work_task.hpp>
|
||||
#include <mbgl/util/work_request.hpp>
|
||||
@@ -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<WorkRequest>(task);
|
||||
}
|
||||
@@ -90,13 +98,11 @@ public:
|
||||
flag);
|
||||
|
||||
withMutex([&] { queue.push(task); });
|
||||
async.send();
|
||||
async->send();
|
||||
|
||||
return std::make_unique<WorkRequest>(task);
|
||||
}
|
||||
|
||||
uv_loop_t* get() { return async.get()->loop; }
|
||||
|
||||
private:
|
||||
template <class F, class P>
|
||||
class Invoker : public WorkTask {
|
||||
@@ -143,12 +149,27 @@ private:
|
||||
|
||||
using Queue = std::queue<std::shared_ptr<WorkTask>>;
|
||||
|
||||
void withMutex(std::function<void()>&&);
|
||||
void process();
|
||||
void withMutex(std::function<void()>&& fn) {
|
||||
std::lock_guard<std::mutex> 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<AsyncTask> async;
|
||||
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
|
||||
static uv::tls<RunLoop> current;
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace util {
|
||||
class AsyncTask::Impl {
|
||||
public:
|
||||
Impl(std::function<void()>&& fn)
|
||||
: async(RunLoop::getLoop(), [this] { runTask(); })
|
||||
: async(reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle()), [this] { runTask(); })
|
||||
, task(std::move(fn)) {
|
||||
}
|
||||
|
||||
|
||||
83
platform/default/run_loop.cpp
Normal file
83
platform/default/run_loop.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
namespace mbgl {
|
||||
namespace util {
|
||||
|
||||
uv::tls<RunLoop> RunLoop::current;
|
||||
|
||||
class RunLoop::Impl {
|
||||
public:
|
||||
Impl() = default;
|
||||
|
||||
uv_loop_t *loop;
|
||||
RunLoop::Type type;
|
||||
};
|
||||
|
||||
RunLoop::RunLoop(Type type) : impl(std::make_unique<Impl>()) {
|
||||
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<AsyncTask>(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(); });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<uv_loop_t*>(util::RunLoop::getLoopHandle())),
|
||||
cache(cache_),
|
||||
assetRoot(root.empty() ? platform::assetRoot() : root),
|
||||
assetContext(AssetContextBase::createContext(loop)),
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace util {
|
||||
|
||||
uv::tls<RunLoop> 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<void()>&& fn) {
|
||||
std::lock_guard<std::mutex> 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(); });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -112,26 +112,19 @@ Thread<Object>::Thread(const ThreadContext& context, Args&&... args) {
|
||||
template <class Object>
|
||||
template <typename P, std::size_t... I>
|
||||
void Thread<Object>::run(ThreadContext context, P&& params, std::index_sequence<I...>) {
|
||||
uv::loop l;
|
||||
|
||||
ThreadContext::current.set(&context);
|
||||
|
||||
{
|
||||
RunLoop loop_(l.get());
|
||||
loop = &loop_;
|
||||
RunLoop loop_(RunLoop::Type::New);
|
||||
loop = &loop_;
|
||||
|
||||
Object object_(std::get<I>(std::forward<P>(params))...);
|
||||
object = &object_;
|
||||
Object object_(std::get<I>(std::forward<P>(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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user