From 6587d76305601ff4e9d2f50fbd49ea979af9b8c9 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 21:55:01 +0200 Subject: [PATCH 01/10] added self.hpp + refactoring --- src/uvw.hpp | 1 + src/uvw/handle.hpp | 31 ++++++++++--------------------- src/uvw/self.hpp | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 src/uvw/self.hpp diff --git a/src/uvw.hpp b/src/uvw.hpp index 8870260f..52900628 100644 --- a/src/uvw.hpp +++ b/src/uvw.hpp @@ -7,6 +7,7 @@ #include "uvw/loop.hpp" #include "uvw/prepare.hpp" #include "uvw/request.hpp" +#include "uvw/self.hpp" #include "uvw/signal.hpp" #include "uvw/stream.hpp" #include "uvw/tcp.hpp" diff --git a/src/uvw/handle.hpp b/src/uvw/handle.hpp index 7d5c6925..f3fcb6c7 100644 --- a/src/uvw/handle.hpp +++ b/src/uvw/handle.hpp @@ -5,6 +5,7 @@ #include #include #include "emitter.hpp" +#include "self.hpp" #include "loop.hpp" @@ -25,11 +26,7 @@ template<> struct HandleType { }; template -class Handle - : public BaseHandle, - public Emitter, - public std::enable_shared_from_this -{ +class Handle: public BaseHandle, public Emitter, public Self { struct BaseWrapper { virtual ~BaseWrapper() = default; virtual void * get() const noexcept = 0; @@ -45,20 +42,18 @@ class Handle static void closeCallback(uv_handle_t *handle) { Handle &ref = *(static_cast(handle->data)); - ref.initialized = false; ref.publish(CloseEvent{}); - ref.leak.reset(); + ref.reset(); } protected: template explicit Handle(HandleType, std::shared_ptr ref) - : Emitter{}, - std::enable_shared_from_this{}, + : BaseHandle{}, + Emitter{}, + Self{}, wrapper{std::make_unique>()}, - pLoop{std::move(ref)}, - leak{nullptr}, - initialized{false} + pLoop{std::move(ref)} { this->template get()->data = static_cast(this); } @@ -70,21 +65,17 @@ protected: template bool initialize(F &&f, Args&&... args) { - bool ret = true; - - if(!initialized) { + if(!this->self()) { auto err = std::forward(f)(parent(), get(), std::forward(args)...); if(err) { this->publish(ErrorEvent{err}); - ret = false; } else { - leak = this->shared_from_this(); - initialized = true; + this->leak(); } } - return ret; + return this->self(); } template @@ -117,8 +108,6 @@ public: private: std::unique_ptr wrapper; std::shared_ptr pLoop; - std::shared_ptr leak; - bool initialized; }; diff --git a/src/uvw/self.hpp b/src/uvw/self.hpp new file mode 100644 index 00000000..aff2e3d1 --- /dev/null +++ b/src/uvw/self.hpp @@ -0,0 +1,21 @@ +#pragma once + + +#include + + +namespace uvw { + + +template +struct Self: std::enable_shared_from_this { + void leak() noexcept { ptr = this->shared_from_this(); } + void reset() noexcept { ptr.reset(); } + bool self() const noexcept { return static_cast(ptr); } + +private: + std::shared_ptr ptr{nullptr}; +}; + + +} From 29c8d22a6fa665dcef11a1244368e65628348206 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 22:19:54 +0200 Subject: [PATCH 02/10] refinement --- src/uvw/handle.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/uvw/handle.hpp b/src/uvw/handle.hpp index f3fcb6c7..ef59b779 100644 --- a/src/uvw/handle.hpp +++ b/src/uvw/handle.hpp @@ -42,8 +42,9 @@ class Handle: public BaseHandle, public Emitter, public Self { static void closeCallback(uv_handle_t *handle) { Handle &ref = *(static_cast(handle->data)); + auto ptr = ref.shared_from_this(); + ptr->reset(); ref.publish(CloseEvent{}); - ref.reset(); } protected: From a3b75c174570813ca0bc640598d6424d8917da01 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 22:36:20 +0200 Subject: [PATCH 03/10] added common base class Resource for Request and Handle --- src/uvw.hpp | 1 + src/uvw/async.hpp | 2 +- src/uvw/check.hpp | 2 +- src/uvw/handle.hpp | 86 ++++++++++++-------------------------------- src/uvw/idle.hpp | 2 +- src/uvw/loop.hpp | 2 +- src/uvw/prepare.hpp | 2 +- src/uvw/request.hpp | 24 +++++-------- src/uvw/resource.hpp | 79 ++++++++++++++++++++++++++++++++++++++++ src/uvw/signal.hpp | 2 +- src/uvw/stream.hpp | 5 ++- src/uvw/tcp.hpp | 2 +- src/uvw/timer.hpp | 2 +- src/uvw/tty.hpp | 2 +- 14 files changed, 122 insertions(+), 91 deletions(-) create mode 100644 src/uvw/resource.hpp diff --git a/src/uvw.hpp b/src/uvw.hpp index 52900628..b672220a 100644 --- a/src/uvw.hpp +++ b/src/uvw.hpp @@ -7,6 +7,7 @@ #include "uvw/loop.hpp" #include "uvw/prepare.hpp" #include "uvw/request.hpp" +#include "uvw/resource.hpp" #include "uvw/self.hpp" #include "uvw/signal.hpp" #include "uvw/stream.hpp" diff --git a/src/uvw/async.hpp b/src/uvw/async.hpp index 23f4a5e6..ab9c521a 100644 --- a/src/uvw/async.hpp +++ b/src/uvw/async.hpp @@ -19,7 +19,7 @@ class Async final: public Handle { } explicit Async(std::shared_ptr ref) - : Handle{HandleType{}, std::move(ref)} + : Handle{ResourceType{}, std::move(ref)} { } public: diff --git a/src/uvw/check.hpp b/src/uvw/check.hpp index fc6a2f06..920e802c 100644 --- a/src/uvw/check.hpp +++ b/src/uvw/check.hpp @@ -19,7 +19,7 @@ class Check final: public Handle { } explicit Check(std::shared_ptr ref) - : Handle{HandleType{}, std::move(ref)} + : Handle{ResourceType{}, std::move(ref)} { } public: diff --git a/src/uvw/handle.hpp b/src/uvw/handle.hpp index ef59b779..7f105d51 100644 --- a/src/uvw/handle.hpp +++ b/src/uvw/handle.hpp @@ -4,42 +4,14 @@ #include #include #include -#include "emitter.hpp" -#include "self.hpp" -#include "loop.hpp" +#include "resource.hpp" namespace uvw { -template -struct HandleType; - -template<> struct HandleType { }; -template<> struct HandleType { }; -template<> struct HandleType { }; -template<> struct HandleType { }; -template<> struct HandleType { }; -template<> struct HandleType { }; -template<> struct HandleType { }; -template<> struct HandleType { }; - - template -class Handle: public BaseHandle, public Emitter, public Self { - struct BaseWrapper { - virtual ~BaseWrapper() = default; - virtual void * get() const noexcept = 0; - }; - - template - struct Wrapper: BaseWrapper { - Wrapper(): handle{std::make_unique()} { } - void * get() const noexcept override { return handle.get(); } - private: - std::unique_ptr handle; - }; - +class Handle: public BaseHandle, public Resource { static void closeCallback(uv_handle_t *handle) { Handle &ref = *(static_cast(handle->data)); auto ptr = ref.shared_from_this(); @@ -49,25 +21,15 @@ class Handle: public BaseHandle, public Emitter, public Self { protected: template - explicit Handle(HandleType, std::shared_ptr ref) + explicit Handle(ResourceType rt, std::shared_ptr ref) : BaseHandle{}, - Emitter{}, - Self{}, - wrapper{std::make_unique>()}, - pLoop{std::move(ref)} - { - this->template get()->data = static_cast(this); - } - - uv_loop_t* parent() const noexcept { return pLoop->loop.get(); } - - template - U* get() const noexcept { return reinterpret_cast(wrapper->get()); } + Resource{std::move(rt), std::move(ref)} + { } template bool initialize(F &&f, Args&&... args) { if(!this->self()) { - auto err = std::forward(f)(parent(), get(), std::forward(args)...); + auto err = std::forward(f)(this->parent(), this->template get(), std::forward(args)...); if(err) { this->publish(ErrorEvent{err}); @@ -79,36 +41,32 @@ protected: return this->self(); } - template - auto invoke(F &&f, Args&&... args) { - auto err = std::forward(f)(std::forward(args)...); - if(err) { Emitter::publish(ErrorEvent{err}); } - return err; - } - public: - virtual ~Handle() { - static_assert(std::is_base_of, T>::value, "!"); + bool active() const noexcept override { + return !(uv_is_active(this->template get()) == 0); } - Loop& loop() const noexcept { return *pLoop; } + bool closing() const noexcept override { + return !(uv_is_closing(this->template get()) == 0); + } - bool active() const noexcept override { return !(uv_is_active(get()) == 0); } - bool closing() const noexcept override { return !(uv_is_closing(get()) == 0); } + void reference() noexcept override { + uv_ref(this->template get()); + } - void reference() noexcept override { uv_ref(get()); } - void unreference() noexcept override { uv_unref(get()); } - bool referenced() const noexcept override { return !(uv_has_ref(get()) == 0); } + void unreference() noexcept override { + uv_unref(this->template get()); + } + + bool referenced() const noexcept override { + return !(uv_has_ref(this->template get()) == 0); + } void close() noexcept override { if(!closing()) { - uv_close(get(), &Handle::closeCallback); + uv_close(this->template get(), &Handle::closeCallback); } } - -private: - std::unique_ptr wrapper; - std::shared_ptr pLoop; }; diff --git a/src/uvw/idle.hpp b/src/uvw/idle.hpp index 8374bb57..2d175f79 100644 --- a/src/uvw/idle.hpp +++ b/src/uvw/idle.hpp @@ -19,7 +19,7 @@ class Idle final: public Handle { } explicit Idle(std::shared_ptr ref) - : Handle{HandleType{}, std::move(ref)} + : Handle{ResourceType{}, std::move(ref)} { } public: diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index b01095dd..95f4b08f 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -26,7 +26,7 @@ public: class Loop final: public Emitter, public std::enable_shared_from_this { template - friend class Handle; + friend class Resource; using Deleter = std::function; diff --git a/src/uvw/prepare.hpp b/src/uvw/prepare.hpp index 0929dee2..c5948494 100644 --- a/src/uvw/prepare.hpp +++ b/src/uvw/prepare.hpp @@ -19,7 +19,7 @@ class Prepare final: public Handle { } explicit Prepare(std::shared_ptr ref) - : Handle{HandleType{}, std::move(ref)} + : Handle{ResourceType{}, std::move(ref)} { } public: diff --git a/src/uvw/request.hpp b/src/uvw/request.hpp index a50a8da6..3a37a723 100644 --- a/src/uvw/request.hpp +++ b/src/uvw/request.hpp @@ -1,28 +1,22 @@ #pragma once +#include +#include #include +#include "resource.hpp" namespace uvw { -template -struct RequestType; - -template<> struct RequestType { }; -template<> struct RequestType { }; -template<> struct RequestType { }; -template<> struct RequestType { }; -template<> struct RequestType { }; -template<> struct RequestType { }; -template<> struct RequestType { }; -template<> struct RequestType { }; - - template -struct Request: T { - // TODO room for a pointer to a memory pool and a better memory management +class Request: public Resource { +protected: + template + explicit Request(ResourceType rt, std::shared_ptr ref) + : Resource{std::move(rt), std::move(ref)} + { } }; diff --git a/src/uvw/resource.hpp b/src/uvw/resource.hpp new file mode 100644 index 00000000..d09e892e --- /dev/null +++ b/src/uvw/resource.hpp @@ -0,0 +1,79 @@ +#pragma once + + +#include +#include +#include +#include "emitter.hpp" +#include "self.hpp" +#include "loop.hpp" + + +namespace uvw { + + +template +struct ResourceType; + +template<> struct ResourceType { }; +template<> struct ResourceType { }; +template<> struct ResourceType { }; +template<> struct ResourceType { }; +template<> struct ResourceType { }; +template<> struct ResourceType { }; +template<> struct ResourceType { }; +template<> struct ResourceType { }; + + +template +class Resource: public Emitter, public Self { + struct BaseWrapper { + virtual ~BaseWrapper() = default; + virtual void * get() const noexcept = 0; + }; + + template + struct Wrapper: BaseWrapper { + Wrapper(): resource{std::make_unique()} { } + void * get() const noexcept override { return resource.get(); } + private: + std::unique_ptr resource; + }; + +protected: + template + explicit Resource(ResourceType, std::shared_ptr ref) + : Emitter{}, + Self{}, + wrapper{std::make_unique>()}, + pLoop{std::move(ref)} + { + this->template get()->data = static_cast(this); + } + + uv_loop_t* parent() const noexcept { return pLoop->loop.get(); } + + template + U* get() const noexcept { return reinterpret_cast(wrapper->get()); } + + template + auto invoke(F &&f, Args&&... args) { + auto err = std::forward(f)(std::forward(args)...); + if(err) { Emitter::publish(ErrorEvent{err}); } + return err; + } + +public: + virtual ~Resource() { + static_assert(std::is_base_of, T>::value, "!"); + } + + Loop& loop() const noexcept { return *pLoop; } + +private: + std::unique_ptr wrapper; + std::shared_ptr pLoop; +}; + + +} diff --git a/src/uvw/signal.hpp b/src/uvw/signal.hpp index 66747061..5a7a20e2 100644 --- a/src/uvw/signal.hpp +++ b/src/uvw/signal.hpp @@ -19,7 +19,7 @@ class Signal final: public Handle { } explicit Signal(std::shared_ptr ref) - : Handle{HandleType{}, std::move(ref)} + : Handle{ResourceType{}, std::move(ref)} { } public: diff --git a/src/uvw/stream.hpp b/src/uvw/stream.hpp index 3c0adf01..20947f73 100644 --- a/src/uvw/stream.hpp +++ b/src/uvw/stream.hpp @@ -57,9 +57,8 @@ class Stream: public Handle { protected: template - Stream(HandleType rt, std::shared_ptr ref) - : Handle{std::move(rt), - std::move(ref)}, + Stream(ResourceType rt, std::shared_ptr ref) + : Handle{std::move(rt), std::move(ref)}, sdown{std::make_unique()} { } diff --git a/src/uvw/tcp.hpp b/src/uvw/tcp.hpp index ec31b91c..969db4ab 100644 --- a/src/uvw/tcp.hpp +++ b/src/uvw/tcp.hpp @@ -22,7 +22,7 @@ class Tcp final: public Stream { } explicit Tcp(std::shared_ptr ref) - : Stream{HandleType{}, std::move(ref)}, + : Stream{ResourceType{}, std::move(ref)}, conn{std::make_unique()} { } diff --git a/src/uvw/timer.hpp b/src/uvw/timer.hpp index c321af80..37747755 100644 --- a/src/uvw/timer.hpp +++ b/src/uvw/timer.hpp @@ -20,7 +20,7 @@ class Timer final: public Handle { } explicit Timer(std::shared_ptr ref) - : Handle{HandleType{}, std::move(ref)} + : Handle{ResourceType{}, std::move(ref)} { } public: diff --git a/src/uvw/tty.hpp b/src/uvw/tty.hpp index 2a7ecc24..243fd949 100644 --- a/src/uvw/tty.hpp +++ b/src/uvw/tty.hpp @@ -31,7 +31,7 @@ class TTY final: public Stream { explicit TTY(std::shared_ptr ref, details::FileDescriptor, bool readable) - : Stream{HandleType{}, std::move(ref)}, + : Stream{ResourceType{}, std::move(ref)}, fd{FD}, rw{readable ? 1 : 0} { } From 5f481737555d27a805d327ea1e8f8052fd131ef0 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 22:47:05 +0200 Subject: [PATCH 04/10] minor changes --- src/uvw/handle.hpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/uvw/handle.hpp b/src/uvw/handle.hpp index 7f105d51..6e87ac6c 100644 --- a/src/uvw/handle.hpp +++ b/src/uvw/handle.hpp @@ -1,6 +1,7 @@ #pragma once +#include #include #include #include @@ -50,6 +51,12 @@ public: return !(uv_is_closing(this->template get()) == 0); } + void close() noexcept override { + if(!closing()) { + uv_close(this->template get(), &Handle::closeCallback); + } + } + void reference() noexcept override { uv_ref(this->template get()); } @@ -62,10 +69,8 @@ public: return !(uv_has_ref(this->template get()) == 0); } - void close() noexcept override { - if(!closing()) { - uv_close(this->template get(), &Handle::closeCallback); - } + std::size_t size() const noexcept { + return uv_handle_size(this->template get()->type); } }; From 78e6de086f9a066c67fdf2d4454038502d5726ac Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 22:47:28 +0200 Subject: [PATCH 05/10] added Request::cancel --- src/uvw/request.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/uvw/request.hpp b/src/uvw/request.hpp index 3a37a723..25f8a306 100644 --- a/src/uvw/request.hpp +++ b/src/uvw/request.hpp @@ -17,6 +17,15 @@ protected: explicit Request(ResourceType rt, std::shared_ptr ref) : Resource{std::move(rt), std::move(ref)} { } + +public: + void cancel() noexcept { + invoke(&uv_cancel, this->template get()); + } + + std::size_t size() const noexcept { + return uv_req_size(this->template get()->type); + } }; From becef55848c4e81db7f9efc006a67f66c4595d4a Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 22:50:17 +0200 Subject: [PATCH 06/10] added a couple of TODO --- src/uvw/stream.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/uvw/stream.hpp b/src/uvw/stream.hpp index 20947f73..61101ca7 100644 --- a/src/uvw/stream.hpp +++ b/src/uvw/stream.hpp @@ -37,6 +37,7 @@ class Stream: public Handle { } static void writeCallback(uv_write_t *req, int status) { + // TODO migrate to Request (see request.hpp for further details) T &ref = *(static_cast(req->handle->data)); if(status) { ref.publish(ErrorEvent{status}); } else { ref.publish(WriteEvent{}); } @@ -85,6 +86,7 @@ public: void write(char *data, ssize_t length) { uv_buf_t bufs[] = { uv_buf_init(data, length) }; + // TODO migrate to Request (see request.hpp for further details) uv_write_t *req = new uv_write_t; auto err = uv_write(req, this->template get(), bufs, 1, &Stream::writeCallback); From 80fabe239743c231e30d248a72b554e95ec5a8df Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 22:53:02 +0200 Subject: [PATCH 07/10] clean up --- src/uvw.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/uvw.hpp b/src/uvw.hpp index b672220a..ac7578e5 100644 --- a/src/uvw.hpp +++ b/src/uvw.hpp @@ -1,16 +1,10 @@ #include "uvw/async.hpp" #include "uvw/check.hpp" -#include "uvw/emitter.hpp" #include "uvw/event.hpp" -#include "uvw/handle.hpp" #include "uvw/idle.hpp" #include "uvw/loop.hpp" #include "uvw/prepare.hpp" -#include "uvw/request.hpp" -#include "uvw/resource.hpp" -#include "uvw/self.hpp" #include "uvw/signal.hpp" -#include "uvw/stream.hpp" #include "uvw/tcp.hpp" #include "uvw/timer.hpp" #include "uvw/tty.hpp" From d2a52b1693e3a10b0bb10fb89e5a8d76c7aa8bfb Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 23:12:22 +0200 Subject: [PATCH 08/10] updated API + updated documentation --- README.md | 22 +++++++++++----------- src/uvw/handle.hpp | 6 +----- src/uvw/loop.hpp | 9 ++++++++- src/uvw/request.hpp | 5 +---- test/main.cpp | 6 +++--- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 018cd530..0a03cb43 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ **Please, note that `uvw` is still a work in progress**. `uvw` is a header-only, event based, tiny and easy to use C++ wrapper for *libuv*. -The basic idea is to hide completely the *C-ish* interace of *libuv* behind a graceful C++ API. Currently, no `uv_*_t` data structure is actually exposed by the library. -Note that `uvw` stays true to the API of *libuv* and it doesn't add anything to its interface. For the same reason, users of the library must follow the same rules who are used to follow with *libuv*. +The basic idea is to hide completely the *C-ish* interface of *libuv* behind a graceful C++ API. Currently, no `uv_*_t` data structure is actually exposed by the library. +Note that `uvw` stays true to the API of *libuv* and it doesn't add anything to its interface. For the same reasons, users of the library must follow the same rules who are used to follow with *libuv*. As an example, a *handle* should be initialized before any other operation and closed once it is no longer in use. ## Code Example @@ -14,10 +14,10 @@ As an example, a *handle* should be initialized before any other operation and c #include void listen(uvw::Loop &loop) { - std::shared_ptr tcp = loop.handle(); + std::shared_ptr tcp = loop.resource(); tcp->once([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutable { - std::shared_ptr client = srv.loop().handle(); + std::shared_ptr client = srv.loop().resource(); client->on([ptr = srv.shared_from_this()](const uvw::CloseEvent &, uvw::Tcp &) mutable { ptr->close(); }); client->on([](const uvw::EndEvent &, uvw::Tcp &client) { client.close(); }); @@ -31,7 +31,7 @@ void listen(uvw::Loop &loop) { } void conn(uvw::Loop &loop) { - auto tcp = loop.handle(); + auto tcp = loop.resource(); tcp->on([](const uvw::ErrorEvent &, uvw::Tcp &) { /* handle errors */ }); @@ -90,7 +90,7 @@ To navigate it with your favorite browser: There is only one rule when using `uvw`: always initialize the handles and close them. Handles keep themselves alive until one closes them. Because of that, leaks are possible if users simply forget about a handle. -To be honest, initialization is performed under the hood and can be even passed over, as far as resources are created using the `Loop::handle` member method. +To be honest, initialization is performed under the hood and can be even passed over, as far as resources are created using the `Loop::resource` member method. Thus the rule quickly becomes *always close your handles*. It's simple as calling the `close` member method on them. The first thing to do to use `uvw` is to create a loop. In case the default one is enough, it's easy as doing this: @@ -102,9 +102,9 @@ Loops can be run using the `run`, `runOnce` and `runWait` member methods. Please In order to create a handle and to bind it to the given loop, just do the following: - auto tcp = loop.handle(); + auto tcp = loop.resource(); -A tcp handle will be created and initialized, thus a shared pointer to that handle will be returned. +A tcp handle will be created and initialized, thus a shared pointer to the handle will be returned. Users should check if pointers have been correctly initialized: in case of errors, they won't be. Another way to create a handle is: @@ -113,7 +113,7 @@ Another way to create a handle is: Pretty annoying indeed. Using a loop is the recommended approach. -Once a handle has been created, it will keep itself alive until one invoke the `close` member method on it. +Once a handle has been created, it will keep itself alive until one invokes the `close` member method on it. To know what are the handles that are still alive and bound to a given loop, just do the following: loop.walk([](uvw::BaseHandle &){ /* application code here */ }); @@ -151,12 +151,12 @@ The code below shows how to create a simple tcp server using `uvw`: ``` auto loop = uvw::Loop::getDefault(); -auto tcp = loop.handle(); +auto tcp = loop.resource(); tcp->on([](const uvw::ErrorEvent &, uvw::Tcp &srv) { /* something went wrong */ }); tcp->on([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutable { - std::shared_ptr client = srv.loop().handle(); + std::shared_ptr client = srv.loop().resource(); client->once([](const uvw::EndEvent &, uvw::Tcp &client) { client.close(); }); client->on([](const uvw::DataEvent &, uvw::Tcp &) { /* data received */ }); srv.accept(*client); diff --git a/src/uvw/handle.hpp b/src/uvw/handle.hpp index 6e87ac6c..f20cc338 100644 --- a/src/uvw/handle.hpp +++ b/src/uvw/handle.hpp @@ -21,11 +21,7 @@ class Handle: public BaseHandle, public Resource { } protected: - template - explicit Handle(ResourceType rt, std::shared_ptr ref) - : BaseHandle{}, - Resource{std::move(rt), std::move(ref)} - { } + using Resource::Resource; template bool initialize(F &&f, Args&&... args) { diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index 95f4b08f..27daa66e 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -76,12 +76,19 @@ public: } template - std::shared_ptr handle(Args&&... args) { + std::enable_if_t::value, std::shared_ptr> + resource(Args&&... args) { auto ptr = R::create(shared_from_this(), std::forward(args)...); ptr = ptr->init() ? ptr : nullptr; return ptr; } + template + std::enable_if_t::value, std::shared_ptr> + resource(Args&&... args) { + return R::create(shared_from_this(), std::forward(args)...); + } + void close() noexcept { auto err = uv_loop_close(loop.get()); if(err) { publish(ErrorEvent{err}); } diff --git a/src/uvw/request.hpp b/src/uvw/request.hpp index 25f8a306..ec3603f3 100644 --- a/src/uvw/request.hpp +++ b/src/uvw/request.hpp @@ -13,10 +13,7 @@ namespace uvw { template class Request: public Resource { protected: - template - explicit Request(ResourceType rt, std::shared_ptr ref) - : Resource{std::move(rt), std::move(ref)} - { } + using Resource::Resource; public: void cancel() noexcept { diff --git a/test/main.cpp b/test/main.cpp index b085f446..1f87e951 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -6,7 +6,7 @@ void listen(uvw::Loop &loop) { - std::shared_ptr tcp = loop.handle(); + std::shared_ptr tcp = loop.resource(); tcp->on([](const uvw::ErrorEvent &, uvw::Tcp &) { std::cout << "error " << std::endl; @@ -15,7 +15,7 @@ void listen(uvw::Loop &loop) { tcp->once([](const uvw::ListenEvent &event, uvw::Tcp &srv) mutable { std::cout << "listen" << std::endl; - std::shared_ptr client = srv.loop().handle(); + std::shared_ptr client = srv.loop().resource(); client->on([](const uvw::ErrorEvent &, uvw::Tcp &) { std::cout << "error " << std::endl; @@ -62,7 +62,7 @@ void listen(uvw::Loop &loop) { void conn(uvw::Loop &loop) { - auto tcp = loop.handle(); + auto tcp = loop.resource(); tcp->on([](const uvw::ErrorEvent &, uvw::Tcp &) { std::cout << "error " << std::endl; From 001a95c8e472d3f8e067971cfa2518544c7ceaaa Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 23:37:36 +0200 Subject: [PATCH 09/10] added a couple of TODO --- src/uvw/stream.hpp | 3 +++ src/uvw/tcp.hpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/uvw/stream.hpp b/src/uvw/stream.hpp index 61101ca7..c38aebd8 100644 --- a/src/uvw/stream.hpp +++ b/src/uvw/stream.hpp @@ -45,6 +45,7 @@ class Stream: public Handle { } static void shutdownCallback(uv_shutdown_t *req, int status) { + // TODO migrate to Request (see request.hpp for further details) T &ref = *(static_cast(req->handle->data)); if(status) { ref.publish(ErrorEvent{status}); } else { ref.publish(ShutdownEvent{}); } @@ -60,6 +61,7 @@ protected: template Stream(ResourceType rt, std::shared_ptr ref) : Handle{std::move(rt), std::move(ref)}, + // TODO migrate to Request (see request.hpp for further details) sdown{std::make_unique()} { } @@ -126,6 +128,7 @@ public: } private: + // TODO migrate to Request (see request.hpp for further details) std::unique_ptr sdown; }; diff --git a/src/uvw/tcp.hpp b/src/uvw/tcp.hpp index 969db4ab..e3b47c3e 100644 --- a/src/uvw/tcp.hpp +++ b/src/uvw/tcp.hpp @@ -16,12 +16,14 @@ namespace uvw { class Tcp final: public Stream { static void connectCallback(uv_connect_t *req, int status) { + // TODO migrate to Request (see request.hpp for further details) Tcp &tcp = *(static_cast(req->handle->data)); if(status) { tcp.publish(ErrorEvent{status}); } else { tcp.publish(ConnectEvent{}); } } explicit Tcp(std::shared_ptr ref) + // TODO migrate to Request (see request.hpp for further details) : Stream{ResourceType{}, std::move(ref)}, conn{std::make_unique()} { } @@ -112,6 +114,7 @@ public: } private: + // TODO migrate to Request (see request.hpp for further details) std::unique_ptr conn; }; From a8917f5ba6d77f1a3aa150f442c2536b50080951 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Thu, 14 Jul 2016 23:38:04 +0200 Subject: [PATCH 10/10] added Work request --- src/uvw.hpp | 1 + src/uvw/event.hpp | 2 ++ src/uvw/resource.hpp | 1 + src/uvw/work.hpp | 47 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 src/uvw/work.hpp diff --git a/src/uvw.hpp b/src/uvw.hpp index ac7578e5..b676d082 100644 --- a/src/uvw.hpp +++ b/src/uvw.hpp @@ -9,3 +9,4 @@ #include "uvw/timer.hpp" #include "uvw/tty.hpp" #include "uvw/util.hpp" +#include "uvw/work.hpp" diff --git a/src/uvw/event.hpp b/src/uvw/event.hpp index fb11693d..a96cb0d0 100644 --- a/src/uvw/event.hpp +++ b/src/uvw/event.hpp @@ -30,6 +30,7 @@ struct Event: BaseEvent { }; +struct AfterWorkEvent: Event { }; struct AsyncEvent: Event { }; struct CheckEvent: Event { }; struct CloseEvent: Event { }; @@ -82,6 +83,7 @@ private: struct TimerEvent: Event { }; struct UninitializedEvent: Event { }; +struct WorkEvent: Event { }; struct WriteEvent: Event { }; diff --git a/src/uvw/resource.hpp b/src/uvw/resource.hpp index d09e892e..808cbe65 100644 --- a/src/uvw/resource.hpp +++ b/src/uvw/resource.hpp @@ -23,6 +23,7 @@ template<> struct ResourceType { }; template<> struct ResourceType { }; template<> struct ResourceType { }; template<> struct ResourceType { }; +template<> struct ResourceType { }; template diff --git a/src/uvw/work.hpp b/src/uvw/work.hpp new file mode 100644 index 00000000..1efa6f9a --- /dev/null +++ b/src/uvw/work.hpp @@ -0,0 +1,47 @@ +#pragma once + + +#include +#include +#include +#include "event.hpp" +#include "request.hpp" +#include "util.hpp" + + +namespace uvw { + + +class Work final: public Request { + static void workCallback(uv_work_t *req) { + Work &work = *(static_cast(req->data)); + work.publish(WorkEvent{}); + } + + static void afterWorkCallback(uv_work_t *req, int status) { + Work &work = *(static_cast(req->data)); + auto ptr = work.shared_from_this(); + ptr->reset(); + if(status) { work.publish(ErrorEvent{status}); } + else { work.publish(AfterWorkEvent{}); } + } + + explicit Work(std::shared_ptr ref) + : Request{ResourceType{}, std::move(ref)} + { } + +public: + template + static std::shared_ptr create(Args&&... args) { + return std::shared_ptr{new Work{std::forward(args)...}}; + } + + void queue() noexcept { + if(0 == invoke(&uv_queue_work, parent(), get(), &workCallback, &afterWorkCallback)) { + leak(); + } + } +}; + + +}