[core] Abstract main loop inside RunLoop class

This commit is contained in:
Thiago Marcos P. Santos
2015-09-01 11:09:19 +03:00
parent 1d62332204
commit d422c8cac4
11 changed files with 131 additions and 67 deletions

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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',

View File

@@ -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;
};

View File

@@ -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)) {
}

View 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(); });
}
}
}

View File

@@ -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;
}

View File

@@ -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)),

View File

@@ -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(); });
}
}
}

View File

@@ -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);