From 7e8005a90a7deb685987ece3d7809cce5486540a Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 1 Aug 2016 09:18:37 +0200 Subject: [PATCH 1/4] tests + bug fixing --- src/uvw/loop.hpp | 2 +- test/CMakeLists.txt | 9 ++++++++ test/uvw/async.cpp | 19 +++++++++++++++++ test/uvw/check.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++ test/uvw/loop.cpp | 2 +- 5 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 test/uvw/check.cpp diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index e2f9baf0..6edc1ba6 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -125,7 +125,7 @@ public: return (uv_run(loop.get(), UV_RUN_ONCE) == 0); } - bool runWait() noexcept { + bool runNoWait() noexcept { return (uv_run(loop.get(), UV_RUN_NOWAIT) == 0); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d20ada5f..8aa9ec2d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,6 +22,7 @@ set( set(TARGET_MAIN main) set(TARGET_ASYNC async) +set(TARGET_CHECK check) set(TARGET_LOOP loop) set(TARGET_WORK work) @@ -41,6 +42,14 @@ target_include_directories(${TARGET_ASYNC} PRIVATE ${COMMON_INCLUDE_DIRS}) target_link_libraries(${TARGET_ASYNC} PRIVATE ${COMMON_LINK_LIBS}) add_test(NAME ${TARGET_ASYNC} COMMAND ${TARGET_ASYNC}) +# Test TARGET_CHECK + +set(TARGET_CHECK_SOURCES uvw/check.cpp) +add_executable(${TARGET_CHECK} ${TARGET_CHECK_SOURCES}) +target_include_directories(${TARGET_CHECK} PRIVATE ${COMMON_INCLUDE_DIRS}) +target_link_libraries(${TARGET_CHECK} PRIVATE ${COMMON_LINK_LIBS}) +add_test(NAME ${TARGET_CHECK} COMMAND ${TARGET_CHECK}) + # Test TARGET_LOOP set(TARGET_LOOP_SOURCES uvw/loop.cpp) diff --git a/test/uvw/async.cpp b/test/uvw/async.cpp index aa505177..989b3d0f 100644 --- a/test/uvw/async.cpp +++ b/test/uvw/async.cpp @@ -1,6 +1,7 @@ #include #include + TEST(Async, Send) { auto loop = uvw::Loop::getDefault(); auto handle = loop->resource(); @@ -30,3 +31,21 @@ TEST(Async, Send) { ASSERT_FALSE(checkErrorEvent); ASSERT_TRUE(checkAsyncEvent); } + + +TEST(Async, Fake) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + auto l = [](const auto &, auto &){ ASSERT_FALSE(true); }; + handle->on(l); + handle->on(l); + + handle->send(); + handle->close(); + + ASSERT_FALSE(handle->active()); + ASSERT_TRUE(handle->closing()); + + loop->run(); +} diff --git a/test/uvw/check.cpp b/test/uvw/check.cpp new file mode 100644 index 00000000..eed61198 --- /dev/null +++ b/test/uvw/check.cpp @@ -0,0 +1,52 @@ +#include +#include + + +TEST(Check, PartiallyDone) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + bool checkErrorEvent = false; + bool checkCheckEvent = false; + + handle->on([&checkErrorEvent](const uvw::ErrorEvent &, uvw::CheckHandle &){ + ASSERT_FALSE(checkErrorEvent); + checkErrorEvent = true; + }); + + handle->on([&checkCheckEvent](const uvw::CheckEvent &, uvw::CheckHandle &handle){ + ASSERT_FALSE(checkCheckEvent); + checkCheckEvent = true; + handle.stop(); + handle.close(); + ASSERT_TRUE(handle.closing()); + }); + + handle->start(); + + ASSERT_TRUE(handle->active()); + ASSERT_FALSE(handle->closing()); + + loop->runNoWait(); + + ASSERT_FALSE(checkErrorEvent); + ASSERT_TRUE(checkCheckEvent); +} + + +TEST(Check, Fake) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + auto l = [](const auto &, auto &){ ASSERT_FALSE(true); }; + handle->on(l); + handle->on(l); + + handle->start(); + handle->close(); + + ASSERT_FALSE(handle->active()); + ASSERT_TRUE(handle->closing()); + + loop->run(); +} diff --git a/test/uvw/loop.cpp b/test/uvw/loop.cpp index 8cbc5b90..4d47377c 100644 --- a/test/uvw/loop.cpp +++ b/test/uvw/loop.cpp @@ -43,7 +43,7 @@ TEST(Loop, PartiallyDone) { loop->walk([](uvw::BaseHandle &) { ASSERT_TRUE(false); }); ASSERT_NO_THROW(loop->runOnce()); - ASSERT_NO_THROW(loop->runWait()); + ASSERT_NO_THROW(loop->runNoWait()); ASSERT_FALSE(loop->alive()); } From c159f377715ab9e796220743ce5da5e6c9590aa3 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 1 Aug 2016 09:30:59 +0200 Subject: [PATCH 2/4] minor changes --- README.md | 7 ++++++- src/uvw/loop.hpp | 21 ++++++++++++--------- test/uvw/check.cpp | 2 +- test/uvw/loop.cpp | 4 ++-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 281ab550..10d0cf2b 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,12 @@ The first thing to do to use `uvw` is to create a loop. In case the default one auto loop = uvw::Loop::getDefault(); Note that loop objects don't require to be closed explicitly, even if they offer the `close` member method in case an user wants to do that. -Loops can be run using the `run`, `runOnce` and `runWait` member methods. Please refer to the documentation of *libuv* for further details. +Loops can be started using the `run` member method. The two calls below are equivalent: + + loop->run(); + loop->run + +Available modes are: `DEFAULT`, `ONCE`, `NOWAIT`. Please refer to the documentation of *libuv* for further details. In order to create a resource and to bind it to the given loop, just do the following: diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index 6edc1ba6..0109c664 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -22,6 +22,13 @@ enum class UVLoopOption: std::underlying_type_t { }; +enum class UVRunMode: std::underlying_type_t { + DEFAULT = UV_RUN_DEFAULT, + ONCE = UV_RUN_ONCE, + NOWAIT = UV_RUN_NOWAIT +}; + + } @@ -49,6 +56,7 @@ class Loop final: public Emitter, public std::enable_shared_from_this create() { auto ptr = std::unique_ptr{new uv_loop_t, [](uv_loop_t *l){ delete l; }}; @@ -117,16 +125,11 @@ public: if(err) { publish(ErrorEvent{err}); } } + template bool run() noexcept { - return (uv_run(loop.get(), UV_RUN_DEFAULT) == 0); - } - - bool runOnce() noexcept { - return (uv_run(loop.get(), UV_RUN_ONCE) == 0); - } - - bool runNoWait() noexcept { - return (uv_run(loop.get(), UV_RUN_NOWAIT) == 0); + auto utm = static_cast>(mode); + auto uvrm = static_cast(utm); + return (uv_run(loop.get(), uvrm) == 0); } bool alive() const noexcept { diff --git a/test/uvw/check.cpp b/test/uvw/check.cpp index eed61198..f1e0cdd6 100644 --- a/test/uvw/check.cpp +++ b/test/uvw/check.cpp @@ -27,7 +27,7 @@ TEST(Check, PartiallyDone) { ASSERT_TRUE(handle->active()); ASSERT_FALSE(handle->closing()); - loop->runNoWait(); + loop->run(); ASSERT_FALSE(checkErrorEvent); ASSERT_TRUE(checkCheckEvent); diff --git a/test/uvw/loop.cpp b/test/uvw/loop.cpp index 4d47377c..2a774ac7 100644 --- a/test/uvw/loop.cpp +++ b/test/uvw/loop.cpp @@ -42,8 +42,8 @@ TEST(Loop, PartiallyDone) { loop->walk([](uvw::BaseHandle &) { ASSERT_TRUE(false); }); - ASSERT_NO_THROW(loop->runOnce()); - ASSERT_NO_THROW(loop->runNoWait()); + ASSERT_NO_THROW(loop->run()); + ASSERT_NO_THROW(loop->run()); ASSERT_FALSE(loop->alive()); } From 646755c7be0fe50218eae1a8ba9feb6f7dd49d6d Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 1 Aug 2016 10:42:42 +0200 Subject: [PATCH 3/4] more tests --- test/CMakeLists.txt | 27 +++++++++++++++++++++++ test/uvw/async.cpp | 4 ++-- test/uvw/check.cpp | 6 ++--- test/uvw/idle.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++ test/uvw/loop.cpp | 4 ++-- test/uvw/prepare.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++ test/uvw/self.cpp | 23 ++++++++++++++++++++ test/uvw/work.cpp | 8 +++---- 8 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 test/uvw/idle.cpp create mode 100644 test/uvw/prepare.cpp create mode 100644 test/uvw/self.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8aa9ec2d..1e5ee14b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -23,7 +23,10 @@ set( set(TARGET_MAIN main) set(TARGET_ASYNC async) set(TARGET_CHECK check) +set(TARGET_IDLE idle) set(TARGET_LOOP loop) +set(TARGET_PREPARE prepare) +set(TARGET_SELF self) set(TARGET_WORK work) # Test TARGET_MAIN @@ -50,6 +53,14 @@ target_include_directories(${TARGET_CHECK} PRIVATE ${COMMON_INCLUDE_DIRS}) target_link_libraries(${TARGET_CHECK} PRIVATE ${COMMON_LINK_LIBS}) add_test(NAME ${TARGET_CHECK} COMMAND ${TARGET_CHECK}) +# Test TARGET_IDLE + +set(TARGET_IDLE_SOURCES uvw/idle.cpp) +add_executable(${TARGET_IDLE} ${TARGET_IDLE_SOURCES}) +target_include_directories(${TARGET_IDLE} PRIVATE ${COMMON_INCLUDE_DIRS}) +target_link_libraries(${TARGET_IDLE} PRIVATE ${COMMON_LINK_LIBS}) +add_test(NAME ${TARGET_IDLE} COMMAND ${TARGET_IDLE}) + # Test TARGET_LOOP set(TARGET_LOOP_SOURCES uvw/loop.cpp) @@ -58,6 +69,22 @@ target_include_directories(${TARGET_LOOP} PRIVATE ${COMMON_INCLUDE_DIRS}) target_link_libraries(${TARGET_LOOP} PRIVATE ${COMMON_LINK_LIBS}) add_test(NAME ${TARGET_LOOP} COMMAND ${TARGET_LOOP}) +# Test TARGET_PREPARE + +set(TARGET_PREPARE_SOURCES uvw/prepare.cpp) +add_executable(${TARGET_PREPARE} ${TARGET_PREPARE_SOURCES}) +target_include_directories(${TARGET_PREPARE} PRIVATE ${COMMON_INCLUDE_DIRS}) +target_link_libraries(${TARGET_PREPARE} PRIVATE ${COMMON_LINK_LIBS}) +add_test(NAME ${TARGET_PREPARE} COMMAND ${TARGET_PREPARE}) + +# Test TARGET_SELF + +set(TARGET_SELF_SOURCES uvw/self.cpp) +add_executable(${TARGET_SELF} ${TARGET_SELF_SOURCES}) +target_include_directories(${TARGET_SELF} PRIVATE ${COMMON_INCLUDE_DIRS}) +target_link_libraries(${TARGET_SELF} PRIVATE ${COMMON_LINK_LIBS}) +add_test(NAME ${TARGET_SELF} COMMAND ${TARGET_SELF}) + # Test TARGET_WORK set(TARGET_WORK_SOURCES uvw/work.cpp) diff --git a/test/uvw/async.cpp b/test/uvw/async.cpp index 989b3d0f..ad0d1392 100644 --- a/test/uvw/async.cpp +++ b/test/uvw/async.cpp @@ -9,12 +9,12 @@ TEST(Async, Send) { bool checkErrorEvent = false; bool checkAsyncEvent = false; - handle->on([&checkErrorEvent](const uvw::ErrorEvent &, uvw::AsyncHandle &){ + handle->on([&checkErrorEvent](const auto &, auto &){ ASSERT_FALSE(checkErrorEvent); checkErrorEvent = true; }); - handle->on([&checkAsyncEvent](const uvw::AsyncEvent &, uvw::AsyncHandle &handle){ + handle->on([&checkAsyncEvent](const auto &, auto &handle){ ASSERT_FALSE(checkAsyncEvent); checkAsyncEvent = true; handle.close(); diff --git a/test/uvw/check.cpp b/test/uvw/check.cpp index f1e0cdd6..0b89c5d9 100644 --- a/test/uvw/check.cpp +++ b/test/uvw/check.cpp @@ -2,19 +2,19 @@ #include -TEST(Check, PartiallyDone) { +TEST(Check, StartAndStop) { auto loop = uvw::Loop::getDefault(); auto handle = loop->resource(); bool checkErrorEvent = false; bool checkCheckEvent = false; - handle->on([&checkErrorEvent](const uvw::ErrorEvent &, uvw::CheckHandle &){ + handle->on([&checkErrorEvent](const auto &, auto &){ ASSERT_FALSE(checkErrorEvent); checkErrorEvent = true; }); - handle->on([&checkCheckEvent](const uvw::CheckEvent &, uvw::CheckHandle &handle){ + handle->on([&checkCheckEvent](const auto &, auto &handle){ ASSERT_FALSE(checkCheckEvent); checkCheckEvent = true; handle.stop(); diff --git a/test/uvw/idle.cpp b/test/uvw/idle.cpp new file mode 100644 index 00000000..e1c95448 --- /dev/null +++ b/test/uvw/idle.cpp @@ -0,0 +1,52 @@ +#include +#include + + +TEST(Idle, StartAndStop) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + bool checkErrorEvent = false; + bool checkIdleEvent = false; + + handle->on([&checkErrorEvent](const auto &, auto &){ + ASSERT_FALSE(checkErrorEvent); + checkErrorEvent = true; + }); + + handle->on([&checkIdleEvent](const auto &, auto &handle){ + ASSERT_FALSE(checkIdleEvent); + checkIdleEvent = true; + handle.stop(); + handle.close(); + ASSERT_TRUE(handle.closing()); + }); + + handle->start(); + + ASSERT_TRUE(handle->active()); + ASSERT_FALSE(handle->closing()); + + loop->run(); + + ASSERT_FALSE(checkErrorEvent); + ASSERT_TRUE(checkIdleEvent); +} + + +TEST(Idle, Fake) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + auto l = [](const auto &, auto &){ ASSERT_FALSE(true); }; + handle->on(l); + handle->on(l); + + handle->start(); + handle->close(); + + ASSERT_FALSE(handle->active()); + ASSERT_TRUE(handle->closing()); + + loop->run(); +} diff --git a/test/uvw/loop.cpp b/test/uvw/loop.cpp index 2a774ac7..1d2ab667 100644 --- a/test/uvw/loop.cpp +++ b/test/uvw/loop.cpp @@ -15,7 +15,7 @@ TEST(Loop, PartiallyDone) { auto handle = loop->resource(); auto req = loop->resource([](){}); - auto err = [](uvw::ErrorEvent, auto &) { ASSERT_TRUE(false); }; + auto err = [](const auto &, auto &) { ASSERT_TRUE(false); }; loop->on(err); req->on(err); @@ -27,7 +27,7 @@ TEST(Loop, PartiallyDone) { ASSERT_FALSE(loop->alive()); handle->start(); - handle->on([](uvw::PrepareEvent, uvw::PrepareHandle &handle) { + handle->on([](const auto &, auto &handle) { handle.loop().walk([](uvw::BaseHandle &) { static bool trigger = true; ASSERT_TRUE(trigger); diff --git a/test/uvw/prepare.cpp b/test/uvw/prepare.cpp new file mode 100644 index 00000000..e71ae752 --- /dev/null +++ b/test/uvw/prepare.cpp @@ -0,0 +1,52 @@ +#include +#include + + +TEST(Prepare, StartAndStop) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + bool checkErrorEvent = false; + bool checkPrepareEvent = false; + + handle->on([&checkErrorEvent](const auto &, auto &){ + ASSERT_FALSE(checkErrorEvent); + checkErrorEvent = true; + }); + + handle->on([&checkPrepareEvent](const auto &, auto &handle){ + ASSERT_FALSE(checkPrepareEvent); + checkPrepareEvent = true; + handle.stop(); + handle.close(); + ASSERT_TRUE(handle.closing()); + }); + + handle->start(); + + ASSERT_TRUE(handle->active()); + ASSERT_FALSE(handle->closing()); + + loop->run(); + + ASSERT_FALSE(checkErrorEvent); + ASSERT_TRUE(checkPrepareEvent); +} + + +TEST(Prepare, Fake) { + auto loop = uvw::Loop::getDefault(); + auto handle = loop->resource(); + + auto l = [](const auto &, auto &){ ASSERT_FALSE(true); }; + handle->on(l); + handle->on(l); + + handle->start(); + handle->close(); + + ASSERT_FALSE(handle->active()); + ASSERT_TRUE(handle->closing()); + + loop->run(); +} diff --git a/test/uvw/self.cpp b/test/uvw/self.cpp new file mode 100644 index 00000000..1e7c3e24 --- /dev/null +++ b/test/uvw/self.cpp @@ -0,0 +1,23 @@ +#include +#include + + +struct S: uvw::Self { }; + + +TEST(Self, Basics) { + std::shared_ptr self = std::make_shared(); + + ASSERT_TRUE(self.unique()); + ASSERT_FALSE(self->self()); + + self->leak(); + + ASSERT_FALSE(self.unique()); + ASSERT_TRUE(self->self()); + + self->reset(); + + ASSERT_TRUE(self.unique()); + ASSERT_FALSE(self->self()); +} diff --git a/test/uvw/work.cpp b/test/uvw/work.cpp index 7746a6b0..3f95960f 100644 --- a/test/uvw/work.cpp +++ b/test/uvw/work.cpp @@ -14,12 +14,12 @@ TEST(Work, RunTask) { checkTask = true; }); - req->on([&checkWorkEvent](const uvw::WorkEvent &, uvw::WorkReq &){ + req->on([&checkWorkEvent](const auto &, auto &){ ASSERT_FALSE(checkWorkEvent); checkWorkEvent = true; }); - req->on([&checkErrorEvent](const uvw::ErrorEvent &, uvw::WorkReq &){ + req->on([&checkErrorEvent](const auto &, auto &){ ASSERT_FALSE(checkErrorEvent); checkErrorEvent = true; }); @@ -44,12 +44,12 @@ TEST(Work, Cancellation) { checkTask = true; }); - req->on([&checkWorkEvent](const uvw::WorkEvent &, uvw::WorkReq &){ + req->on([&checkWorkEvent](const auto &, auto &){ ASSERT_FALSE(checkWorkEvent); checkWorkEvent = true; }); - req->on([&checkErrorEvent](const uvw::ErrorEvent &, uvw::WorkReq &){ + req->on([&checkErrorEvent](const auto &, auto &){ ASSERT_FALSE(checkErrorEvent); checkErrorEvent = true; }); From cdcdbcfb6d83aa789c2dcbcadae0c91c821e4879 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 1 Aug 2016 11:19:15 +0200 Subject: [PATCH 4/4] updated threads --- src/uvw/thread.hpp | 291 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 272 insertions(+), 19 deletions(-) diff --git a/src/uvw/thread.hpp b/src/uvw/thread.hpp index c3b89bc7..480537bb 100644 --- a/src/uvw/thread.hpp +++ b/src/uvw/thread.hpp @@ -1,6 +1,7 @@ #pragma once +#include #include #include #include @@ -11,6 +12,16 @@ namespace uvw { +class Thread; +class ThreadLocalStorage; +class Once; +class Mutex; +class RWLock; +class Semaphore; +class Condition; +class Barrier; + + class Thread final { using InternalTask = std::function)>; @@ -23,8 +34,7 @@ class Thread final { : pLoop{std::move(ref)}, data{std::move(d)}, thread{}, - task{std::move(t)}, - err{0} + task{std::move(t)} { } public: @@ -44,24 +54,18 @@ public: return !(0 == uv_thread_equal(&tl.thread, &tr.thread)); } - ~Thread() { + ~Thread() noexcept { uv_thread_join(&thread); } bool run() noexcept { - err = uv_thread_create(&thread, &createCallback, this); - return static_cast(*this); + return (0 == uv_thread_create(&thread, &createCallback, this)); } bool join() noexcept { - err = uv_thread_join(&thread); - return static_cast(*this); + return (0 == uv_thread_join(&thread)); } - explicit operator bool() const noexcept { return (0 == err); } - - int error() const noexcept { return err; } - Loop& loop() const noexcept { return *pLoop; } private: @@ -69,17 +73,266 @@ private: std::shared_ptr data; uv_thread_t thread; Task task; - int err; }; -// TODO Thread-local storage -// TODO Once-only initialization -// TODO Mutex locks -// TODO Read-write locks -// TODO Semaphores -// TODO Conditions -// TODO Barriers +class ThreadLocalStorage final { + explicit ThreadLocalStorage(std::shared_ptr ref) noexcept + : pLoop{std::move(ref)} + { + uv_key_create(&key); + } + +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr{new ThreadLocalStorage{std::forward(args)...}}; + } + + ~ThreadLocalStorage() noexcept { + uv_key_delete(&key); + } + + template + T* get() noexcept { + return static_cast(uv_key_get(&key)); + } + + template + void set(T *value) noexcept { + return uv_key_set(&key, value); + } + + Loop& loop() const noexcept { return *pLoop; } + +private: + std::shared_ptr pLoop; + uv_key_t key; +}; + + +class Once final { + explicit Once(std::shared_ptr ref) noexcept + : pLoop{std::move(ref)} + { } + +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr{new Once{std::forward(args)...}}; + } + + template + static void once(F &&f) noexcept { + using CallbackType = void (*)(void); + static_assert(std::is_convertible::value, "!"); + CallbackType cb = f; + uv_once(&guard, cb); + } + + Loop& loop() const noexcept { return *pLoop; } + +private: + std::shared_ptr pLoop; + static uv_once_t guard; +}; + +uv_once_t Once::guard = UV_ONCE_INIT; + + +class Mutex final { + friend class Condition; + + explicit Mutex(std::shared_ptr ref) noexcept + : pLoop{std::move(ref)} + { + uv_mutex_init(&mutex); + } + +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr{new Mutex{std::forward(args)...}}; + } + + ~Mutex() noexcept { + uv_mutex_destroy(&mutex); + } + + void lock() noexcept { + uv_mutex_lock(&mutex); + } + + bool tryLock() noexcept { + return (0 == uv_mutex_trylock(&mutex)); + } + + void unlock() noexcept { + uv_mutex_unlock(&mutex); + } + + Loop& loop() const noexcept { return *pLoop; } + +private: + std::shared_ptr pLoop; + uv_mutex_t mutex; +}; + + +class RWLock final { + explicit RWLock(std::shared_ptr ref) noexcept + : pLoop{std::move(ref)} + { + uv_rwlock_init(&rwlock); + } + +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr{new RWLock{std::forward(args)...}}; + } + + ~RWLock() noexcept { + uv_rwlock_destroy(&rwlock); + } + + void rdLock() noexcept { + uv_rwlock_rdlock(&rwlock); + } + + bool tryRdLock() noexcept { + return (0 == uv_rwlock_tryrdlock(&rwlock)); + } + + void rdUnlock() noexcept { + uv_rwlock_rdunlock(&rwlock); + } + + void wrLock() noexcept { + uv_rwlock_wrlock(&rwlock); + } + + bool tryWrLock() noexcept { + return (0 == uv_rwlock_trywrlock(&rwlock)); + } + + void wrUnlock() noexcept { + uv_rwlock_wrunlock(&rwlock); + } + + Loop& loop() const noexcept { return *pLoop; } + +private: + std::shared_ptr pLoop; + uv_rwlock_t rwlock; +}; + + +class Semaphore final { + explicit Semaphore(std::shared_ptr ref, unsigned int value) noexcept + : pLoop{std::move(ref)} + { + uv_sem_init(&sem, value); + } + +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr{new Semaphore{std::forward(args)...}}; + } + + ~Semaphore() noexcept { + uv_sem_destroy(&sem); + } + + void post() noexcept { + uv_sem_post(&sem); + } + + void wait() noexcept { + uv_sem_wait(&sem); + } + + bool tryWait() noexcept { + return (0 == uv_sem_trywait(&sem)); + } + + Loop& loop() const noexcept { return *pLoop; } + +private: + std::shared_ptr pLoop; + uv_sem_t sem; +}; + + +class Condition final { + explicit Condition(std::shared_ptr ref) noexcept + : pLoop{std::move(ref)} + { + uv_cond_init(&cond); + } + +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr{new Condition{std::forward(args)...}}; + } + + ~Condition() noexcept { + uv_cond_destroy(&cond); + } + + void signal() noexcept { + uv_cond_signal(&cond); + } + + void broadcast() noexcept { + uv_cond_broadcast(&cond); + } + + void wait(Mutex &mutex) noexcept { + uv_cond_wait(&cond, &mutex.mutex); + } + + bool timedWait(Mutex &mutex, uint64_t timeout) noexcept { + return (0 == uv_cond_timedwait(&cond, &mutex.mutex, timeout)); + } + + Loop& loop() const noexcept { return *pLoop; } + +private: + std::shared_ptr pLoop; + uv_cond_t cond; +}; + + +class Barrier final { + explicit Barrier(std::shared_ptr ref, unsigned int count) noexcept + : pLoop{std::move(ref)} + { + uv_barrier_init(&barrier, count); + } + +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr{new Barrier{std::forward(args)...}}; + } + + ~Barrier() noexcept { + uv_barrier_destroy(&barrier); + } + + bool wait() noexcept { + return (0 == uv_barrier_wait(&barrier)); + } + + Loop& loop() const noexcept { return *pLoop; } + +private: + std::shared_ptr pLoop; + uv_barrier_t barrier; +}; }