commit
e783a8ea48
@ -12,9 +12,20 @@
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Trigger event.
|
||||
*
|
||||
* It will be emitted by the AsyncHandle according with its functionalities.
|
||||
*/
|
||||
struct AsyncEvent: Event<AsyncEvent> { };
|
||||
|
||||
|
||||
/**
|
||||
* @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<AsyncHandle, uv_async_t> {
|
||||
static void sendCallback(uv_async_t *handle) {
|
||||
AsyncHandle &async = *(static_cast<AsyncHandle*>(handle->data));
|
||||
@ -24,15 +35,38 @@ class AsyncHandle final: public Handle<AsyncHandle, uv_async_t> {
|
||||
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<typename... Args>
|
||||
static std::shared_ptr<AsyncHandle> create(Args&&... args) {
|
||||
return std::shared_ptr<AsyncHandle>{new AsyncHandle{std::forward<Args>(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_t>(&uv_async_init, &sendCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wakeups the event loop and emits the AsyncEvent event.
|
||||
*
|
||||
* It’s safe to call this function from any thread.<br/>
|
||||
* 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<uv_async_t>());
|
||||
}
|
||||
|
||||
@ -12,9 +12,20 @@
|
||||
namespace uvw {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Trigger event.
|
||||
*
|
||||
* It will be emitted by the CheckHandle according with its functionalities.
|
||||
*/
|
||||
struct CheckEvent: Event<CheckEvent> { };
|
||||
|
||||
|
||||
/**
|
||||
* @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<CheckHandle, uv_check_t> {
|
||||
static void startCallback(uv_check_t *handle) {
|
||||
CheckHandle &check = *(static_cast<CheckHandle*>(handle->data));
|
||||
@ -24,19 +35,37 @@ class CheckHandle final: public Handle<CheckHandle, uv_check_t> {
|
||||
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<typename... Args>
|
||||
static std::shared_ptr<CheckHandle> create(Args&&... args) {
|
||||
return std::shared_ptr<CheckHandle>{new CheckHandle{std::forward<Args>(args)...}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the handle.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool init() {
|
||||
return initialize<uv_check_t>(&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<uv_check_t>(), &startCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the handle.
|
||||
*/
|
||||
void stop() {
|
||||
invoke(&uv_check_stop, get<uv_check_t>());
|
||||
}
|
||||
|
||||
191
src/uvw/loop.hpp
191
src/uvw/loop.hpp
@ -32,17 +32,79 @@ enum class UVRunMode: std::underlying_type_t<uv_run_mode> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Untyped handle class
|
||||
*
|
||||
* Handles' types are unknown from the point of view of the loop.<br/>
|
||||
* Anyway, a loop maintains a list of all the associated handles and let the
|
||||
* users walk them as untyped instances.<br/>
|
||||
* 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.<br/>
|
||||
* 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.<br/>
|
||||
* 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.<br/>
|
||||
* 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<Loop>, public std::enable_shared_from_this<Loop> {
|
||||
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<Loop> create() {
|
||||
auto ptr = std::unique_ptr<uv_loop_t, Deleter>{new uv_loop_t, [](uv_loop_t *l){ delete l; }};
|
||||
auto loop = std::shared_ptr<Loop>(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.<br>
|
||||
* 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()`.<br>
|
||||
* 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<Loop> getDefault() {
|
||||
static std::weak_ptr<Loop> ref;
|
||||
std::shared_ptr<Loop> 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.<br/>
|
||||
* 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<typename... Args>
|
||||
void configure(Configure flag, Args... args) {
|
||||
auto err = uv_loop_configure(loop.get(), static_cast<std::underlying_type_t<Configure>>(flag), std::forward<Args>(args)...);
|
||||
if(err) { publish(ErrorEvent{err}); }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates resources of handles' types.
|
||||
*
|
||||
* This should be used as a default method to create resources.<br/>
|
||||
* The arguments are the ones required for the specific resource.
|
||||
*
|
||||
* Use it as `loop->resource<uvw::TimerHandle>()`.
|
||||
*
|
||||
* @return A pointer to the newly created resource.
|
||||
*/
|
||||
template<typename R, typename... Args>
|
||||
std::enable_if_t<std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
|
||||
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.<br/>
|
||||
* The arguments are the ones required for the specific resource.
|
||||
*
|
||||
* Use it as `loop->resource<uvw::WorkReq>()`.
|
||||
*
|
||||
* @return A pointer to the newly created resource.
|
||||
*/
|
||||
template<typename R, typename... Args>
|
||||
std::enable_if_t<not std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
|
||||
resource(Args&&... args) {
|
||||
return R::create(shared_from_this(), std::forward<Args>(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<Mode mode = Mode::DEFAULT>
|
||||
bool run() noexcept {
|
||||
auto utm = static_cast<std::underlying_type_t<Mode>>(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.<br/>
|
||||
* This will happen not sooner than the next loop iteration.<br/>
|
||||
* 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.<br/>
|
||||
* This can be used in conjunction with `run<Loop::Mode::NOWAIT>()` 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.<br/>
|
||||
* 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.<br/>
|
||||
* 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<void(BaseHandle &)> callback) {
|
||||
// remember: non-capturing lambdas decay to pointers to functions
|
||||
uv_walk(loop.get(), [](uv_handle_t *handle, void *func) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user