diff options
Diffstat (limited to 'src/mbgl/util/uv_detail.hpp')
-rw-r--r-- | src/mbgl/util/uv_detail.hpp | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/mbgl/util/uv_detail.hpp b/src/mbgl/util/uv_detail.hpp new file mode 100644 index 0000000000..99f5edc145 --- /dev/null +++ b/src/mbgl/util/uv_detail.hpp @@ -0,0 +1,177 @@ +#ifndef MBGL_UTIL_UV_DETAIL +#define MBGL_UTIL_UV_DETAIL + +#include <mbgl/util/uv-worker.h> +#include <mbgl/util/noncopyable.hpp> + +#include <uv.h> + +#include <functional> +#include <cassert> +#include <memory> +#include <string> + +namespace uv { + +template <class T> +void close(std::unique_ptr<T> ptr) { + uv_close(reinterpret_cast<uv_handle_t*>(ptr.release()), [](uv_handle_t* handle) { + delete reinterpret_cast<T*>(handle); + }); +} + +class loop : public mbgl::util::noncopyable { +public: + inline loop() { +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + l = uv_loop_new(); + if (l == nullptr) { +#else + l = new uv_loop_t; + if (uv_loop_init(l) != 0) { +#endif + throw std::runtime_error("failed to initialize loop"); + } + } + + inline ~loop() { +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + uv_loop_delete(l); +#else + uv_loop_close(l); + delete l; +#endif + + } + + inline uv_loop_t *operator*() { return l; } + +private: + uv_loop_t *l = nullptr; +}; + +class async : public mbgl::util::noncopyable { +public: + inline async(uv_loop_t* loop, std::function<void ()> fn_) + : a(new uv_async_t) + , fn(fn_) + { + a->data = this; + if (uv_async_init(loop, a.get(), async_cb) != 0) { + throw std::runtime_error("failed to initialize async"); + } + } + + inline ~async() { + close(std::move(a)); + } + + inline void send() { + if (uv_async_send(a.get()) != 0) { + throw std::runtime_error("failed to async send"); + } + } + +private: +#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10 + static void async_cb(uv_async_t* a, int) { +#else + static void async_cb(uv_async_t* a) { +#endif + reinterpret_cast<async*>(a->data)->fn(); + } + + std::unique_ptr<uv_async_t> a; + std::function<void ()> fn; +}; + +class rwlock : public mbgl::util::noncopyable { +public: + inline rwlock() { + if (uv_rwlock_init(&mtx) != 0) { + throw std::runtime_error("failed to initialize read-write lock"); + } + } + inline ~rwlock() { uv_rwlock_destroy(&mtx); } + inline void rdlock() { uv_rwlock_rdlock(&mtx); } + inline void wrlock() { uv_rwlock_wrlock(&mtx); } + inline void rdunlock() { uv_rwlock_rdunlock(&mtx); } + inline void wrunlock() { uv_rwlock_wrunlock(&mtx); } + +private: + uv_rwlock_t mtx; +}; + +class readlock : public mbgl::util::noncopyable { +public: + inline readlock(rwlock &mtx_) : mtx(mtx_) { mtx.rdlock(); } + inline readlock(const std::unique_ptr<rwlock> &mtx_) : mtx(*mtx_) { mtx.rdlock(); } + inline ~readlock() { mtx.rdunlock(); } + +private: + rwlock &mtx; +}; + +class writelock : public mbgl::util::noncopyable { +public: + inline writelock(rwlock &mtx_) : mtx(mtx_) { mtx.wrlock(); } + inline writelock(const std::unique_ptr<rwlock> &mtx_) : mtx(*mtx_) { mtx.wrlock(); } + inline ~writelock() { mtx.wrunlock(); } + +private: + rwlock &mtx; +}; + +class worker : public mbgl::util::noncopyable { +public: + inline worker(uv_loop_t *loop, unsigned int count, const char *name = nullptr) : w(new uv_worker_t) { + uv_worker_init(w, loop, count, name); + } + inline ~worker() { + uv_worker_close(w, [](uv_worker_t *worker_) { + delete worker_; + }); + } + inline void add(void *data, uv_worker_cb work_cb, uv_worker_after_cb after_work_cb) { + uv_worker_send(w, data, work_cb, after_work_cb); + } + +private: + uv_worker_t *w; +}; + +template <typename T> +class work : public mbgl::util::noncopyable { +public: + typedef std::function<void (T&)> work_callback; + typedef std::function<void (T&)> after_work_callback; + + template<typename... Args> + work(worker &worker, work_callback work_cb_, after_work_callback after_work_cb_, Args&&... args) + : data(std::forward<Args>(args)...), + work_cb(work_cb_), + after_work_cb(after_work_cb_) { + worker.add(this, do_work, after_work); + } + +private: + static void do_work(void *data) { + work<T> *w = reinterpret_cast<work<T> *>(data); + w->work_cb(w->data); + } + + static void after_work(void *data) { + work<T> *w = reinterpret_cast<work<T> *>(data); + w->after_work_cb(w->data); + delete w; + } + +private: + T data; + work_callback work_cb; + after_work_callback after_work_cb; +}; + +} + +#endif |