diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2019-04-23 17:37:26 (GMT) |
---|---|---|
committer | Kyle Edwards <kyle.edwards@kitware.com> | 2019-04-25 16:03:08 (GMT) |
commit | 8cfd25db711c22f9478e565a496145577df24d77 (patch) | |
tree | 4903ef06ec74137f44c375bbdd23fbbce9a99676 | |
parent | c0e6b22d0a81c0e0dc1ee87366790882a3d54667 (diff) | |
download | CMake-8cfd25db711c22f9478e565a496145577df24d77.zip CMake-8cfd25db711c22f9478e565a496145577df24d77.tar.gz CMake-8cfd25db711c22f9478e565a496145577df24d77.tar.bz2 |
cmUVHandlePtr: Add cm::uv_loop_ptr
-rw-r--r-- | Source/cmUVHandlePtr.cxx | 54 | ||||
-rw-r--r-- | Source/cmUVHandlePtr.h | 40 | ||||
-rw-r--r-- | Tests/CMakeLib/testUVRAII.cxx | 50 |
3 files changed, 135 insertions, 9 deletions
diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx index fd07d2d..27069ee 100644 --- a/Source/cmUVHandlePtr.cxx +++ b/Source/cmUVHandlePtr.cxx @@ -11,19 +11,59 @@ namespace cm { -static void close_delete(uv_handle_t* h) +struct uv_loop_deleter { - free(h); + void operator()(uv_loop_t* loop) const; +}; + +void uv_loop_deleter::operator()(uv_loop_t* loop) const +{ + uv_run(loop, UV_RUN_DEFAULT); + int result = uv_loop_close(loop); + (void)result; + assert(result >= 0); + free(loop); +} + +int uv_loop_ptr::init(void* data) +{ + this->reset(); + + this->loop.reset(static_cast<uv_loop_t*>(calloc(1, sizeof(uv_loop_t))), + uv_loop_deleter()); + this->loop->data = data; + + return uv_loop_init(this->loop.get()); +} + +void uv_loop_ptr::reset() +{ + this->loop.reset(); +} + +uv_loop_ptr::operator uv_loop_t*() +{ + return this->loop.get(); +} + +uv_loop_t* uv_loop_ptr::operator->() const noexcept +{ + return this->loop.get(); +} + +uv_loop_t* uv_loop_ptr::get() const +{ + return this->loop.get(); } template <typename T> -static void default_delete(T* type_handle) +static void handle_default_delete(T* type_handle) { auto handle = reinterpret_cast<uv_handle_t*>(type_handle); if (handle) { assert(!uv_is_closing(handle)); if (!uv_is_closing(handle)) { - uv_close(handle, &close_delete); + uv_close(handle, [](uv_handle_t* h) { free(h); }); } } } @@ -34,7 +74,7 @@ static void default_delete(T* type_handle) template <typename T> struct uv_handle_deleter { - void operator()(T* type_handle) const { default_delete(type_handle); } + void operator()(T* type_handle) const { handle_default_delete(type_handle); } }; template <typename T> @@ -107,7 +147,7 @@ struct uv_handle_deleter<uv_async_t> void operator()(uv_async_t* handle) { std::lock_guard<std::mutex> lock(*handleMutex); - default_delete(handle); + handle_default_delete(handle); } }; @@ -136,7 +176,7 @@ struct uv_handle_deleter<uv_signal_t> { if (handle) { uv_signal_stop(handle); - default_delete(handle); + handle_default_delete(handle); } } }; diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h index 992c429..c09e4bf 100644 --- a/Source/cmUVHandlePtr.h +++ b/Source/cmUVHandlePtr.h @@ -30,7 +30,45 @@ namespace cm { /*** - * RAII class to simplify and insure the safe usage of uv_*_t types. This + * RAII class to simplify and ensure the safe usage of uv_loop_t. This includes + * making sure resources are properly freed. + */ +class uv_loop_ptr +{ +protected: + std::shared_ptr<uv_loop_t> loop; + +public: + uv_loop_ptr(uv_loop_ptr const&) = delete; + uv_loop_ptr& operator=(uv_loop_ptr const&) = delete; + uv_loop_ptr(uv_loop_ptr&&) noexcept; + uv_loop_ptr& operator=(uv_loop_ptr&&) noexcept; + + // Dtor and ctor need to be inline defined like this for default ctors and + // dtors to work. Some compilers do not like '= default' here. + uv_loop_ptr() {} // NOLINT(modernize-use-equals-default) + uv_loop_ptr(std::nullptr_t) {} + ~uv_loop_ptr() { this->reset(); } + + int init(void* data = nullptr); + + /** + * Properly close the handle if needed and sets the inner handle to nullptr + */ + void reset(); + + /** + * Allow less verbose calling of uv_loop_* functions + * @return reinterpreted handle + */ + operator uv_loop_t*(); + + uv_loop_t* get() const; + uv_loop_t* operator->() const noexcept; +}; + +/*** + * RAII class to simplify and ensure the safe usage of uv_*_t types. This * includes making sure resources are properly freed and contains casting * operators which allow for passing into relevant uv_* functions. * diff --git a/Tests/CMakeLib/testUVRAII.cxx b/Tests/CMakeLib/testUVRAII.cxx index 1c1da76..2aeaf2c 100644 --- a/Tests/CMakeLib/testUVRAII.cxx +++ b/Tests/CMakeLib/testUVRAII.cxx @@ -171,11 +171,59 @@ static bool testAllMoves() return true; }; +static bool testLoopReset() +{ + bool closed = false; + cm::uv_loop_ptr loop; + loop.init(); + + uv_timer_t timer; + uv_timer_init(loop, &timer); + timer.data = &closed; + uv_close(reinterpret_cast<uv_handle_t*>(&timer), [](uv_handle_t* handle) { + auto closedPtr = static_cast<bool*>(handle->data); + *closedPtr = true; + }); + + loop.reset(); + if (!closed) { + std::cerr << "uv_loop_ptr did not finish" << std::endl; + return false; + } + + return true; +}; + +static bool testLoopDestructor() +{ + bool closed = false; + + uv_timer_t timer; + { + cm::uv_loop_ptr loop; + loop.init(); + + uv_timer_init(loop, &timer); + timer.data = &closed; + uv_close(reinterpret_cast<uv_handle_t*>(&timer), [](uv_handle_t* handle) { + auto closedPtr = static_cast<bool*>(handle->data); + *closedPtr = true; + }); + } + + if (!closed) { + std::cerr << "uv_loop_ptr did not finish" << std::endl; + return false; + } + + return true; +}; + int testUVRAII(int, char** const) { if ((testAsyncShutdown() && testAsyncDtor() & testAsyncMove() & testCrossAssignment() & - testAllMoves()) == 0) { + testAllMoves() & testLoopReset() & testLoopDestructor()) == 0) { return -1; } return 0; |