diff --git a/src/uvw/async.hpp b/src/uvw/async.hpp index 6e6baa03..41b9fc55 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 an event + * emitted from another thread. + */ class AsyncHandle final: public Handle { static void sendCallback(uv_async_t *handle) { AsyncHandle &async = *(static_cast(handle->data)); @@ -24,15 +35,38 @@ class AsyncHandle final: public Handle { using Handle::Handle; public: + /** + * @brief Creates a new async 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 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 emits the AsyncEvent event. + * + * 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()); } 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 0109c664..bab73c92 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,38 @@ 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. + * + * 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. + */ 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 +218,53 @@ 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. + * + * An ErrorEvent will be emitted in case of errors. + */ 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 +272,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) {