From ce2f3a5a51c624a5703e508e325c513cac12529e Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 1 Aug 2016 17:10:46 +0200 Subject: [PATCH 1/3] docs: loop.hpp --- src/uvw/loop.hpp | 187 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index 0109c664..102138c9 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -32,17 +32,79 @@ enum class UVRunMode: std::underlying_type_t { } +/** + * @brief Untyped handle class + * + * Handles' types are unknown from the point of view of the loop.
+ * Anyway, a loop maintains a list of all the associated handles and let the + * users walk them as untyped instances.
+ * This can help to end all the pending requests by closing the handles. + */ class BaseHandle { public: + /** + * @brief Checks if a handle is active. + * + * What _active_ means depends on the type of handle.
+ * See the official + * [documentation](http://docs.libuv.org/en/v1.x/handle.html#c.uv_is_active) + * for further details. + * + * @return Non-zero if the handle is active, zero if it’s inactive. + */ virtual bool active() const noexcept = 0; + + /** + * @brief Checks if a handle is closing or closed. + * + * This function should only be used between the initialization of the + * handle and the arrival of the close callback. + * + * @return Non-zero if the handle is closing or closed, zero otherwise. + */ virtual bool closing() const noexcept = 0; + + /** + * @brief Reference the given handle. + * + * References are idempotent, that is, if a handle is already referenced + * calling this function again will have no effect. + */ virtual void reference() noexcept = 0; + + /** + * @brief Unreference the given handle. + * + * References are idempotent, that is, if a handle is not referenced calling + * this function again will have no effect. + */ virtual void unreference() noexcept = 0; + + /** + * @brief Checks if the given handle referenced. + * @return Non-zero if the handle referenced, zero otherwise. + */ virtual bool referenced() const noexcept = 0; + + /** + * @brief Request handle to be closed. + * + * This **must** be called on each handle before memory is released.
+ * In-progress requests are cancelled and this can result in an ErrorEvent + * emitted. + */ virtual void close() noexcept = 0; }; +/** + * @brief The Loop class. + * + * The event loop is the central part of `uvw`'s functionalities, as well as + * libuv's ones.
+ * It takes care of polling for I/O and scheduling callbacks to be run based on + * different sources of events. + */ class Loop final: public Emitter, public std::enable_shared_from_this { using Deleter = void(*)(uv_loop_t *); @@ -58,6 +120,10 @@ public: using Configure = details::UVLoopOption; using Mode = details::UVRunMode; + /** + * @brief Initializes a new Loop instance. + * @return A pointer to the newly created loop. + */ static std::shared_ptr create() { auto ptr = std::unique_ptr{new uv_loop_t, [](uv_loop_t *l){ delete l; }}; auto loop = std::shared_ptr(new Loop{std::move(ptr)}); @@ -69,6 +135,18 @@ public: return loop; } + /** + * @brief Gets the initialized default loop. + * + * It may return an empty pointer in case of failure.
+ * This function is just a convenient way for having a global loop + * throughout an application, the default loop is in no way different than + * the ones initialized with `create()`.
+ * As such, the default loop can be closed with `close()` so the resources + * associated with it are freed (even if it is not strictly necessary). + * + * @return The initialized default loop. + */ static std::shared_ptr getDefault() { static std::weak_ptr ref; std::shared_ptr loop; @@ -100,12 +178,36 @@ public: } } + /** + * @brief Sets additional loop options. + * + * You should normally call this before the first call to uv_run() unless + * mentioned otherwise.
+ * Supported options: + * + * * Loop::Configure::BLOCK_SIGNAL: Block a signal when polling for new + * events. A second argument is required and it is the signal number. + * + * See the official + * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure) + * for further details. + */ template void configure(Configure flag, Args... args) { auto err = uv_loop_configure(loop.get(), static_cast>(flag), std::forward(args)...); if(err) { publish(ErrorEvent{err}); } } + /** + * @brief Creates resources of handles' types. + * + * This should be used as a default method to create resources.
+ * The arguments are the ones required for the specific resource. + * + * Use it as `loop->resource()`. + * + * @return A pointer to the newly created resource. + */ template std::enable_if_t::value, std::shared_ptr> resource(Args&&... args) { @@ -114,17 +216,51 @@ public: return ptr; } + /** + * @brief Creates resources of types other than handles' ones. + * + * This should be used as a default method to create resources.
+ * The arguments are the ones required for the specific resource. + * + * Use it as `loop->resource()`. + * + * @return A pointer to the newly created resource. + */ template std::enable_if_t::value, std::shared_ptr> resource(Args&&... args) { return R::create(shared_from_this(), std::forward(args)...); } + /** + * @brief Releases all internal loop resources. + * + * Call this function only when the loop has finished executing and all open + * handles and requests have been closed, or the loop will emit an error. + */ void close() { auto err = uv_loop_close(loop.get()); if(err) { publish(ErrorEvent{err}); } } + /** + * @brief Runs the event loop. + * + * Available modes are: + * + * * Loop::Mode::DEFAULT: Runs the event loop until there are no more active + * and referenced handles or requests. + * * Loop::Mode::ONCE: Poll for i/o once. Note that this function blocks if + * there are no pending callbacks. + * * Loop::Mode::NOWAIT: Poll for i/o once but don’t block if there are no + * pending callbacks. + * + * See the official + * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run) + * for further details. + * + * @return Zero when done, non-zero in all other cases. + */ template bool run() noexcept { auto utm = static_cast>(mode); @@ -132,30 +268,81 @@ public: return (uv_run(loop.get(), uvrm) == 0); } + /** + * @brief Checks if there are active resources. + * @return Non-zero if there are active resources in the loop. + */ bool alive() const noexcept { return !(uv_loop_alive(loop.get()) == 0); } + /** + * @brief Stops the event loop. + * + * It causes `run()` to end as soon as possible.
+ * This will happen not sooner than the next loop iteration.
+ * If this function was called before blocking for I/O, the loop won’t block + * for I/O on this iteration. + */ void stop() noexcept { uv_stop(loop.get()); } + /** + * @brief Get backend file descriptor. + * + * Only kqueue, epoll and event ports are supported.
+ * This can be used in conjunction with `run()` to poll + * in one thread and run the event loop’s callbacks in another. + * + * @return The backend file descriptor. + */ int descriptor() const noexcept { return uv_backend_fd(loop.get()); } + /** + * @brief Gets the poll timeout. + * @return The return value is in milliseconds, or -1 for no timeout. + */ Time timeout() const noexcept { return Time{uv_backend_timeout(loop.get())}; } + /** + * @brief Returns the current timestamp in milliseconds. + * + * The timestamp is cached at the start of the event loop tick.
+ * The timestamp increases monotonically from some arbitrary point in time. + * Don’t make assumptions about the starting point, you will only get + * disappointed. + * + * @return The current timestamp in milliseconds. + */ Time now() const noexcept { return Time{uv_now(loop.get())}; } + /** + * @brief Updates the event loop’s concept of _now_. + * + * The current time is cached at the start of the event loop tick in order + * to reduce the number of time-related system calls.
+ * You won’t normally need to call this function unless you have callbacks + * that block the event loop for longer periods of time, where _longer_ is + * somewhat subjective but probably on the order of a millisecond or more. + */ void update() const noexcept { return uv_update_time(loop.get()); } + /** + * @brief Walks the list of handles. + * + * The callback will be executed once for each handle that is still active. + * + * @param callback A function to be invoked once for each active handle. + */ void walk(std::function callback) { // remember: non-capturing lambdas decay to pointers to functions uv_walk(loop.get(), [](uv_handle_t *handle, void *func) { From 3673362c5cc92cd01ee3cc230a7e40524e59bb55 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 1 Aug 2016 17:20:45 +0200 Subject: [PATCH 2/3] docs: async.hpp --- src/uvw/async.hpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/uvw/async.hpp b/src/uvw/async.hpp index 6e6baa03..d7274e08 100644 --- a/src/uvw/async.hpp +++ b/src/uvw/async.hpp @@ -12,9 +12,20 @@ namespace uvw { +/** + * @brief Trigger event. + * + * It will be emitted by the AsyncHandle according with its functionalities. + */ struct AsyncEvent: Event { }; +/** + * @brief The AsyncHandle handle. + * + * Async handles allow the user to _wakeup_ the event loop and get a callback + * called from another thread. + */ class AsyncHandle final: public Handle { static void sendCallback(uv_async_t *handle) { AsyncHandle &async = *(static_cast(handle->data)); @@ -24,15 +35,40 @@ class AsyncHandle final: public Handle { using Handle::Handle; public: + /** + * @brief Creates a new async handle. + * + * No arguments required. + * + * @return A pointer to the newly created handle. + */ template static std::shared_ptr create(Args&&... args) { return std::shared_ptr{new AsyncHandle{std::forward(args)...}}; } + /** + * @brief Initializes the handle. + * + * Unlike other handle initialization functions, it immediately starts the + * handle. + * + * @return True in case of success, false otherwise. + */ bool init() { return initialize(&uv_async_init, &sendCallback); } + /** + * @brief Wakeups the event loop and call the async handle’s callback. + * + * It’s safe to call this function from any thread.
+ * An AsyncEvent will be emitted on the loop thread. + * + * See the official + * [documentation](http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send) + * for further details. + */ void send() { invoke(&uv_async_send, get()); } From aff7b27f25dc2b0c4477d041f623ff0b75c86370 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 1 Aug 2016 17:28:46 +0200 Subject: [PATCH 3/3] docs --- src/uvw/async.hpp | 10 ++++------ src/uvw/check.hpp | 29 +++++++++++++++++++++++++++++ src/uvw/loop.hpp | 4 ++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/uvw/async.hpp b/src/uvw/async.hpp index d7274e08..41b9fc55 100644 --- a/src/uvw/async.hpp +++ b/src/uvw/async.hpp @@ -23,8 +23,8 @@ struct AsyncEvent: Event { }; /** * @brief The AsyncHandle handle. * - * Async handles allow the user to _wakeup_ the event loop and get a callback - * called from another thread. + * Async handles allow the user to _wakeup_ the event loop and get an event + * emitted from another thread. */ class AsyncHandle final: public Handle { static void sendCallback(uv_async_t *handle) { @@ -37,9 +37,7 @@ class AsyncHandle final: public Handle { public: /** * @brief Creates a new async handle. - * - * No arguments required. - * + * @param ref A pointer to the loop from which the handle generated. * @return A pointer to the newly created handle. */ template @@ -60,7 +58,7 @@ public: } /** - * @brief Wakeups the event loop and call the async handle’s callback. + * @brief Wakeups the event loop and emits the AsyncEvent event. * * It’s safe to call this function from any thread.
* An AsyncEvent will be emitted on the loop thread. diff --git a/src/uvw/check.hpp b/src/uvw/check.hpp index 379bf17f..3345db5f 100644 --- a/src/uvw/check.hpp +++ b/src/uvw/check.hpp @@ -12,9 +12,20 @@ namespace uvw { +/** + * @brief Trigger event. + * + * It will be emitted by the CheckHandle according with its functionalities. + */ struct CheckEvent: Event { }; +/** + * @brief The CheckHandle handle. + * + * Check handles will emit a CheckEvent once per loop iteration, right after + * polling for I/O. + */ class CheckHandle final: public Handle { static void startCallback(uv_check_t *handle) { CheckHandle &check = *(static_cast(handle->data)); @@ -24,19 +35,37 @@ class CheckHandle final: public Handle { using Handle::Handle; public: + /** + * @brief Creates a new check handle. + * @param ref A pointer to the loop from which the handle generated. + * @return A pointer to the newly created handle. + */ template static std::shared_ptr create(Args&&... args) { return std::shared_ptr{new CheckHandle{std::forward(args)...}}; } + /** + * @brief Initializes the handle. + * @return True in case of success, false otherwise. + */ bool init() { return initialize(&uv_check_init); } + /** + * @brief Starts the handle. + * + * A CheckEvent event will be emitted once per loop iteration, right after + * polling for I/O. + */ void start() { invoke(&uv_check_start, get(), &startCallback); } + /** + * @brief Stops the handle. + */ void stop() { invoke(&uv_check_stop, get()); } diff --git a/src/uvw/loop.hpp b/src/uvw/loop.hpp index 102138c9..bab73c92 100644 --- a/src/uvw/loop.hpp +++ b/src/uvw/loop.hpp @@ -188,6 +188,8 @@ public: * * Loop::Configure::BLOCK_SIGNAL: Block a signal when polling for new * events. A second argument is required and it is the signal number. * + * An ErrorEvent will be emitted in case of errors. + * * See the official * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure) * for further details. @@ -237,6 +239,8 @@ public: * * Call this function only when the loop has finished executing and all open * handles and requests have been closed, or the loop will emit an error. + * + * An ErrorEvent will be emitted in case of errors. */ void close() { auto err = uv_loop_close(loop.get());