瀏覽代碼

cmUVHandlePtr: Add cm::uv_loop_ptr

Kyle Edwards 6 年之前
父節點
當前提交
8cfd25db71
共有 3 個文件被更改,包括 135 次插入9 次删除
  1. 47 7
      Source/cmUVHandlePtr.cxx
  2. 39 1
      Source/cmUVHandlePtr.h
  3. 49 1
      Tests/CMakeLib/testUVRAII.cxx

+ 47 - 7
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);
     }
   }
 };

+ 39 - 1
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.
  *

+ 49 - 1
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;