refactor: add a wrapper for wrangling uv handles. (#25332)

* refactor: add a wrapper for wrangling uv handles.

Part 1 of a fix for #25248, #22069.

Place the uv_asyncs owned by NodeBindings, ElectronBindings inside a new
UvHandle wrapper class which manages uv_handles' need for their closed()
callback to be invoked before the handles' memory can be freed.

* chore: make lint happy

* refactor: use DCHECK_EQ() instead of DCHECK()

* refactor: fix oops
This commit is contained in:
Charles Kerr 2020-09-13 19:53:50 -05:00 committed by GitHub
parent a3389d017f
commit 70e3aa0182
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 28 deletions

View file

@ -5,6 +5,8 @@
#ifndef SHELL_COMMON_NODE_BINDINGS_H_
#define SHELL_COMMON_NODE_BINDINGS_H_
#include <type_traits>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@ -24,6 +26,54 @@ class IsolateData;
namespace electron {
// A helper class to manage uv_handle_t types, e.g. uv_async_t.
//
// As per the uv docs: "uv_close() MUST be called on each handle before
// memory is released. Moreover, the memory can only be released in
// close_cb or after it has returned." This class encapsulates the work
// needed to follow those requirements.
template <typename T,
typename std::enable_if<
// these are the C-style 'subclasses' of uv_handle_t
std::is_same<T, uv_async_t>::value ||
std::is_same<T, uv_check_t>::value ||
std::is_same<T, uv_fs_event_t>::value ||
std::is_same<T, uv_fs_poll_t>::value ||
std::is_same<T, uv_idle_t>::value ||
std::is_same<T, uv_pipe_t>::value ||
std::is_same<T, uv_poll_t>::value ||
std::is_same<T, uv_prepare_t>::value ||
std::is_same<T, uv_process_t>::value ||
std::is_same<T, uv_signal_t>::value ||
std::is_same<T, uv_stream_t>::value ||
std::is_same<T, uv_tcp_t>::value ||
std::is_same<T, uv_timer_t>::value ||
std::is_same<T, uv_tty_t>::value ||
std::is_same<T, uv_udp_t>::value>::type* = nullptr>
class UvHandle {
public:
UvHandle() : t_(new T) {}
~UvHandle() { reset(); }
T* get() { return t_; }
uv_handle_t* handle() { return reinterpret_cast<uv_handle_t*>(t_); }
void reset() {
auto* h = handle();
if (h != nullptr) {
DCHECK_EQ(0, uv_is_closing(h));
uv_close(h, OnClosed);
t_ = nullptr;
}
}
private:
static void OnClosed(uv_handle_t* handle) {
delete reinterpret_cast<T*>(handle);
}
T* t_ = {};
};
class NodeBindings {
public:
enum class BrowserEnvironment { BROWSER, RENDERER, WORKER };
@ -95,7 +145,7 @@ class NodeBindings {
uv_loop_t worker_loop_;
// Dummy handle to make uv's loop not quit.
uv_async_t dummy_uv_handle_;
UvHandle<uv_async_t> dummy_uv_handle_;
// Thread for polling events.
uv_thread_t embed_thread_;