Last active
August 29, 2015 14:10
-
-
Save jmorrill/8e2fed9bdce19cc9379e to your computer and use it in GitHub Desktop.
libuv c++ wrapper impl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "details/_uv_async.hpp" | |
#include "details/_uv_loop.hpp" | |
#include "details/_utilities.hpp" | |
#include "details/_uv_work.hpp" | |
namespace uvxx { namespace details | |
{ | |
_uv_loop::_uv_loop(bool use_default /*= false*/) : | |
__uv_loop_(use_default ? uv_default_loop() : uv_loop_new()), | |
/* uv_async_init */ | |
_methods_to_invoke_async(this, std::bind(&_uv_loop::on_process_invokes, this)), | |
_method_to_invoke_async_unsafe(this, std::bind(&_uv_loop::on_process_invokes_unsafe, this)), | |
_work_methods_to_invoke_async(this, std::bind(&_uv_loop::on_process_invokes, this)), | |
_thread_id(std::this_thread::get_id()) | |
{ | |
__uv_loop_->data = this; | |
} | |
_uv_loop::~_uv_loop() | |
{ | |
if (__uv_loop_) | |
{ | |
if (!_begin_invoke_callbacks.empty()) | |
{ | |
on_process_invokes(); | |
} | |
_methods_to_invoke_async.close(); | |
/*while (uv_loop_alive(_uv_loop) != 0) | |
{ | |
run_once(); | |
}*/ | |
uv_loop_delete(__uv_loop_); | |
__uv_loop_ = nullptr; | |
} | |
} | |
/* processes the 'unsafe' that avoids locking.*/ | |
/* this callback happens off the loop when | |
* _method_to_invoke_async_unsafe.send() has been flagged */ | |
void _uv_loop::on_process_invokes_unsafe() | |
{ | |
if (_method_to_invoke_unsafe == nullptr) | |
{ | |
return; | |
} | |
auto unsafe_method = std::move(_method_to_invoke_unsafe); | |
unsafe_method(); | |
} | |
/* processes all work queued for this loop to execute. this includes | |
* queued thread pool operations (aka work) | |
/* this callback happens off the loop when | |
* _methods_to_invoke_async/_work_methods_to_invoke_async.send() has been flagged */ | |
void _uv_loop::on_process_invokes() | |
{ | |
/* quit if there is nothing to do - should not happen */ | |
if (_begin_invoke_callbacks.empty() && | |
_work_callbacks.empty()) | |
{ | |
return; | |
} | |
/* temporary vectors */ | |
std::vector<std::function<void()>> async_list; | |
std::vector<std::function<void()>> work_list; | |
{ | |
std::lock_guard<std::mutex> lock(_mutex); | |
/* move the invoke methods to a local vector, | |
* to avoid any rentrancy issues */ | |
std::swap(_begin_invoke_callbacks, async_list); | |
std::swap(_work_callbacks, work_list); | |
} | |
/* process threadpool invokes */ | |
for (auto& fun : work_list) | |
{ | |
/* queue the work on thread pool (uv_queue_work) | |
* 'new' here cleans it self up */ | |
new _uv_work(this, std::move(fun)); | |
} | |
/* process queued methods invokes */ | |
for (auto& fun : async_list) | |
{ | |
fun(); | |
} | |
} | |
/* queues thread pool work to happen via this loop */ | |
void _uv_loop::queue_work(std::function<void()> work_function) | |
{ | |
{ | |
std::lock_guard<std::mutex> lock(_mutex); | |
_work_callbacks.emplace_back(std::move(work_function)); | |
} | |
/* uv_async_send + uv_async_t - these libuv methods are thread-safe | |
/* flags loop to look for threadpool invokes on next loop iteration*/ | |
_work_methods_to_invoke_async.send(); | |
} | |
/* queues work to happen on this loop. this method is thread safe */ | |
void _uv_loop::begin_invoke(std::function<void()> operation) | |
{ | |
{ | |
/* lock our vector<function<void()> of work */ | |
std::lock_guard<std::mutex> lock(_mutex); | |
/* add the work to our list of callbacks for this loop to execute */ | |
_begin_invoke_callbacks.emplace_back(std::move(operation)); | |
} | |
/* uv_async_send + uv_async_t - these libuv methods are thread-safe | |
* this flags the async callback to happen on the next run of the loop */ | |
_methods_to_invoke_async.send(); | |
} | |
/* non-thread safe impl of begin_invoke for when an event | |
* loop needs to queue work on it's own thread, | |
* avoiding any lock overhead */ | |
void _uv_loop::begin_invoke_unsafe(std::function<void()> operation) | |
{ | |
/* store this unsafe callback in a place separate from other queued work */ | |
_method_to_invoke_unsafe = std::move(operation); | |
/* uv_async_send + uv_async_t - these libuv methods are thread-safe | |
* this flags the async callback to happen on the next run of the loop */ | |
_method_to_invoke_async_unsafe.send(); | |
} | |
bool _uv_loop::run() | |
{ | |
return uv_run(__uv_loop_, UV_RUN_DEFAULT) == 0; | |
} | |
bool _uv_loop::run_once() | |
{ | |
return uv_run(__uv_loop_, UV_RUN_ONCE) == 0; | |
} | |
bool _uv_loop::run_nowait() | |
{ | |
return uv_run(__uv_loop_, UV_RUN_NOWAIT) == 0; | |
} | |
}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment