2 #ifndef UVCC_HANDLE_BASE__HPP 3 #define UVCC_HANDLE_BASE__HPP 5 #include "uvcc/debug.hpp" 6 #include "uvcc/utility.hpp" 7 #include "uvcc/loop.hpp" 18 #include <type_traits> 22 #define HACK_UV_INTERFACE_PTR 1
41 using uv_t = ::uv_handle_t;
42 using on_destroy_t = std::function<
void(
void *_data) >;
53 constexpr static const std::size_t MAX_PROPERTY_SIZE = 136 +
sizeof(::
uv_buf_t) +
sizeof(::
uv_fs_t);
54 constexpr static const std::size_t MAX_PROPERTY_ALIGN = 8;
58 template<
class _Handle_ >
59 static typename _Handle_::uv_interface& instance()
61 static typename _Handle_::uv_interface instance;
65 virtual ~uv_interface() =
default;
67 virtual void close(
void*)
noexcept = 0;
68 virtual ::uv_handle_type type(
void*)
const noexcept = 0;
69 virtual ::uv_loop_t* loop(
void*)
const noexcept = 0;
70 virtual void*& data(
void*)
noexcept = 0;
71 virtual int fileno(
void*, ::uv_os_fd_t&)
const noexcept = 0;
72 virtual int is_active(
void*)
const noexcept = 0;
73 virtual int is_closing(
void*)
const noexcept = 0;
74 virtual void ref(
void*)
const noexcept = 0;
75 virtual void unref(
void*)
const noexcept = 0;
76 virtual int has_ref(
void*)
const noexcept = 0;
78 struct uv_handle_interface;
79 struct uv_fs_interface;
81 template<
class _Handle_ >
class instance
85 template<
typename _T_,
typename = std::size_t >
struct substitute {
using type =
void; };
86 template<
typename _T_ >
struct substitute< _T_,
decltype(
sizeof(
typename _T_::uv_t)) > {
using type =
typename _T_::uv_t; };
87 template<
typename _T_ >
struct substitute< _T_, std::enable_if_t< std::is_same<
typename _T_::uv_t,
void >::value, std::size_t > >
90 ::uv_any_handle uv_handle_data;
94 using type =
typename substitute< _Handle_ >::type;
98 mutable int uv_error = 0;
101 aligned_storage< MAX_PROPERTY_SIZE, MAX_PROPERTY_ALIGN > property_storage;
103 handle::uv_interface *uv_interface_ptr =
nullptr;
105 typename _Handle_::uv_interface *uv_interface_ptr =
nullptr;
107 loop::instance *loop_instance_ptr =
nullptr;
109 alignas(greatest(
alignof(::uv_any_handle),
alignof(::uv_fs_t)))
typename uv_t::type uv_handle_struct = { 0,};
114 property_storage.reset<
typename _Handle_::properties >();
115 uv_interface_ptr = &uv_interface::instance< _Handle_ >();
116 uvcc_debug_function_return(
"instance [0x%08tX] for handle [0x%08tX]", (ptrdiff_t)
this, (ptrdiff_t)&uv_handle_struct);
118 template<
typename... _Args_ > instance(_Args_&&... _args)
120 property_storage.reset<
typename _Handle_::properties >(std::forward< _Args_ >(_args)...);
121 uv_interface_ptr = &uv_interface::instance< _Handle_ >();
122 uvcc_debug_function_return(
"instance [0x%08tX] for handle [0x%08tX]", (ptrdiff_t)
this, (ptrdiff_t)&uv_handle_struct);
128 uvcc_debug_function_enter(
"instance [0x%08tX] for handle [0x%08tX]", (ptrdiff_t)
this, (ptrdiff_t)&uv_handle_struct);
132 instance(
const instance&) =
delete;
133 instance& operator =(
const instance&) =
delete;
135 instance(instance&&) =
delete;
136 instance& operator =(instance&&) =
delete;
139 static void* create() {
return &(
new instance)->uv_handle_struct; }
140 template<
typename... _Args_ >
static void* create(_Args_&&... _args)
142 return &(
new instance(std::forward< _Args_ >(_args)...))->uv_handle_struct;
145 constexpr static instance* from(
void *_uv_handle)
noexcept 147 static_assert(std::is_standard_layout< instance >::value,
"not a standard layout type");
148 return reinterpret_cast< instance* >(
static_cast<
char* >(_uv_handle) - offsetof(instance, uv_handle_struct));
151 typename _Handle_::properties& properties()
noexcept 152 {
return property_storage.get<
typename _Handle_::properties >(); }
154 typename _Handle_::uv_interface* uv_interface()
const noexcept 156 {
return dynamic_cast<
typename _Handle_::uv_interface* >(uv_interface_ptr); }
163 {
return uv_interface_ptr; }
168 uvcc_debug_function_enter(
"handle [0x%08tX]", (ptrdiff_t)&uv_handle_struct);
173 uvcc_debug_function_enter(
"handle [0x%08tX]", (ptrdiff_t)&uv_handle_struct);
174 auto nrefs = refs.dec();
175 uvcc_debug_condition(nrefs == 0,
"handle [0x%08tX] (nrefs=%li)", (ptrdiff_t)&uv_handle_struct, nrefs);
176 if (nrefs == 0) uv_interface_ptr->close(&uv_handle_struct);
181 uvcc_debug_function_enter(
182 "handle [0x%08tX], loop [0x%08tX]", (ptrdiff_t)&uv_handle_struct, (ptrdiff_t)uv_interface_ptr->loop(&uv_handle_struct)
185 loop_instance_ptr = loop::instance::from(uv_interface_ptr->loop(&uv_handle_struct));
186 loop_instance_ptr->ref();
190 uvcc_debug_do_if(loop_instance_ptr,
191 uvcc_debug_function_enter(
"handle [0x%08tX], loop [0x%08tX]", (ptrdiff_t)&uv_handle_struct, (ptrdiff_t)&loop_instance_ptr->uv_loop_struct)
193 if (loop_instance_ptr)
195 loop_instance_ptr->unref();
196 loop_instance_ptr =
nullptr;
201 template<
class _Handle_ >
friend typename _Handle_::instance* debug::instance(_Handle_&)
noexcept;
214 handle()
noexcept : uv_handle(
nullptr) {}
216 explicit handle(uv_t *_uv_handle)
218 if (_uv_handle) instance< handle >::from(_uv_handle)->ref();
219 uv_handle = _uv_handle;
224 ~handle() {
if (uv_handle) instance< handle >::from(uv_handle)->unref(); }
226 handle(
const handle &_that) :
handle(
static_cast< uv_t* >(_that.uv_handle)) {}
231 if (_that.uv_handle) instance< handle >::from(_that.uv_handle)->ref();
233 uv_handle = _that.uv_handle;
234 if (t) instance< handle >::from(t)->unref();
239 handle(
handle &&_that)
noexcept : uv_handle(_that.uv_handle) { _that.uv_handle =
nullptr; }
245 uv_handle = _that.uv_handle;
246 _that.uv_handle =
nullptr;
247 if (t) instance< handle >::from(t)->unref();
254 int uv_status(
int _value)
const noexcept 256 instance< handle >::from(uv_handle)->uv_error = _value;
262 void swap(
handle &_that)
noexcept { std::swap(uv_handle, _that.uv_handle); }
265 std::uintptr_t
id()
const noexcept 267 return reinterpret_cast< std::uintptr_t >(
268 uv_handle ? instance< handle >::from(uv_handle) : 0
273 long nrefs()
const noexcept {
return instance< handle >::from(uv_handle)->refs.get_value(); }
276 int uv_status()
const noexcept {
return instance< handle >::from(uv_handle)->uv_error; }
278 on_destroy_t& on_destroy()
const noexcept {
return instance< handle >::from(uv_handle)->destroy_cb_storage.value(); }
281 ::uv_handle_type
type()
const noexcept {
return instance< handle >::from(uv_handle)->uv_interface()->type(uv_handle); }
289 case UV_UNKNOWN_HANDLE: ret =
"UNKNOWN";
break;
290 #define XX(X, x) case UV_##X: ret = #x; break; 291 UV_HANDLE_TYPE_MAP(XX)
293 case UV_FILE: ret =
"file";
break;
294 default: ret =
"<UNDEFINED>";
break;
303 uv::
loop loop()
const noexcept {
return uv::loop(instance< handle >::from(uv_handle)->uv_interface()->loop(uv_handle)); }
313 void attached(
bool _state)
const noexcept 316 ::uv_ref(
static_cast< uv_t* >(uv_handle));
318 ::uv_unref(
static_cast< uv_t* >(uv_handle));
320 bool attached()
const noexcept 322 return instance< handle >::from(uv_handle)->uv_interface()->has_ref(uv_handle);
327 void*& data()
const noexcept {
return instance< handle >::from(uv_handle)->uv_interface()->data(uv_handle); }
331 int is_active()
const noexcept 332 {
return uv_status(instance< handle >::from(uv_handle)->uv_interface()->is_active(uv_handle)); }
335 int is_closing()
const noexcept 336 {
return uv_status(instance< handle >::from(uv_handle)->uv_interface()->is_closing(uv_handle)); }
366 ::uv_os_fd_t fileno()
const noexcept 369 uv_status(instance< handle >::from(uv_handle)->uv_interface()->fileno(uv_handle, h));
374 explicit operator
const uv_t*()
const noexcept {
return instance< handle >::from(uv_handle)->uv_interface()->type(uv_handle) == UV_FILE ?
nullptr :
static_cast<
const uv_t* >(uv_handle); }
375 explicit operator uv_t*()
noexcept {
return instance< handle >::from(uv_handle)->uv_interface()->type(uv_handle) == UV_FILE ?
nullptr :
static_cast< uv_t* >(uv_handle); }
378 explicit operator
bool()
const noexcept {
return (uv_handle
and uv_status() >= 0); }
385 struct handle::uv_handle_interface :
virtual uv_interface
387 template<
typename =
void >
static void close_cb(::uv_handle_t*);
389 void close(
void *_uv_handle)
noexcept override 391 auto uv_handle =
static_cast< ::uv_handle_t* >(_uv_handle);
392 uvcc_debug_function_enter(
"%s handle [0x%08tX]", debug::handle_type_name(uv_handle), (ptrdiff_t)uv_handle);
414 uvcc_debug_log_if(
true,
"handle [0x%08tX]: call close callback synchronously", (ptrdiff_t)uv_handle);
416 uvcc_debug_log_if(uv_handle->type == 0,
"handle [0x%08tX]: don't call ::uv_close() for handle not having been initialized by libuv", (ptrdiff_t)uv_handle);
417 if (uv_handle->type != 0) ::uv_close(uv_handle,
nullptr);
423 ::uv_handle_type type(
void *_uv_handle)
const noexcept override {
return static_cast< ::uv_handle_t* >(_uv_handle)->type; }
424 ::uv_loop_t* loop(
void *_uv_handle)
const noexcept override {
return static_cast< ::uv_handle_t* >(_uv_handle)->loop; }
425 void*& data(
void *_uv_handle)
noexcept override {
return static_cast< ::uv_handle_t* >(_uv_handle)->data; }
427 int fileno(
void *_uv_handle, ::uv_os_fd_t &_h)
const noexcept override 430 _h = INVALID_HANDLE_VALUE;
434 return ::uv_fileno(
static_cast< ::uv_handle_t* >(_uv_handle), &_h);
437 int is_active(
void *_uv_handle)
const noexcept override {
return ::uv_is_active(
static_cast< ::uv_handle_t* >(_uv_handle)); }
438 int is_closing(
void *_uv_handle)
const noexcept override {
return ::uv_is_closing(
static_cast< ::uv_handle_t* >(_uv_handle)); }
440 void ref(
void *_uv_handle)
const noexcept override { ::uv_ref(
static_cast< ::uv_handle_t* >(_uv_handle)); }
441 void unref(
void *_uv_handle)
const noexcept override { ::uv_unref(
static_cast< ::uv_handle_t* >(_uv_handle)); }
442 int has_ref(
void *_uv_handle)
const noexcept override {
return ::uv_has_ref(
static_cast< ::uv_handle_t* >(_uv_handle)); }
448 void handle::uv_handle_interface::close_cb(::uv_handle_t *_uv_handle)
450 uvcc_debug_function_enter(
"%s handle [0x%08tX]", debug::handle_type_name(_uv_handle), (ptrdiff_t)_uv_handle);
452 auto instance_ptr = handle::instance< handle >::from(_uv_handle);
454 auto &destroy_cb = instance_ptr->destroy_cb_storage.value();
455 if (destroy_cb) destroy_cb(_uv_handle->data);
464 struct handle::uv_fs_interface :
virtual uv_interface
466 void close(
void *_uv_fs)
noexcept override 468 uvcc_debug_function_enter(
"fs handle [0x%08tX]", (ptrdiff_t)_uv_fs);
470 auto instance_ptr = handle::instance< handle >::from(_uv_fs);
471 auto uv_fs =
static_cast< ::uv_fs_t* >(_uv_fs);
472 auto fd =
static_cast< ::uv_file >(uv_fs->result);
477 ::uv_fs_close(
nullptr, &req_close, fd,
nullptr);
478 ::uv_fs_req_cleanup(&req_close);
481 auto &destroy_cb = instance_ptr->destroy_cb_storage.value();
482 if (destroy_cb) destroy_cb(uv_fs->data);
484 ::uv_fs_req_cleanup(uv_fs);
488 ::uv_handle_type type(
void *_uv_fs)
const noexcept override {
return UV_FILE; }
489 ::uv_loop_t* loop(
void *_uv_fs)
const noexcept override {
return static_cast< ::uv_fs_t* >(_uv_fs)->loop; }
490 void*& data(
void *_uv_fs)
noexcept override {
return static_cast< ::uv_fs_t* >(_uv_fs)->data; }
492 int fileno(
void *_uv_fs, ::uv_os_fd_t &_h)
const noexcept override 494 auto fd =
static_cast< ::uv_file >(
static_cast< ::uv_fs_t* >(_uv_fs)->result);
498 _h = fd >= 0 ? (HANDLE)::_get_osfhandle(fd) : INVALID_HANDLE_VALUE;
499 return _h == INVALID_HANDLE_VALUE ? UV_EBADF : 0;
501 _h =
static_cast< ::uv_os_fd_t >(fd);
502 return _h == -1 ? UV_EBADF : 0;
506 int is_active(
void *_uv_fs)
const noexcept override {
return 0; }
508 void ref(
void *_uv_fs)
const noexcept override {}
509 void unref(
void *_uv_fs)
const noexcept override {}
510 int has_ref(
void *_uv_fs)
const noexcept override {
return 0; }
523 template<>
inline void swap(
uv::
handle &_this,
uv::
handle &_that)
noexcept { _this.swap(_that); }
Namespace for all uvcc definitions.
A wrapper providing the feature of being a standard layout type for the given type _T_...
::uv_handle_type type() const noexcept
The tag indicating the libuv type of the handle.
int uv_status() const noexcept
The status value returned by the last executed libuv API function on this handle. ...
The base class for the libuv handles.
std::uintptr_t id() const noexcept
The unique ID of the instance managed by this handle variable or 0 if the handle is void...
long nrefs() const noexcept
The current number of existing references to the same object as this handle variable refers to...
The I/O event loop class.
A reference counter with atomic increment/decrement.
const char * type_name() const noexcept
A string containing the name of the handle type.
#define HACK_UV_INTERFACE_PTR