1 #pragma once
2 
3 
4 #ifdef _WIN32
5 #include <ciso646>
6 #endif
7 
8 #include <functional>
9 #include <memory>
10 #include <utility>
11 #include <type_traits>
12 #include <chrono>
13 #include <uv.h>
14 #include "emitter.hpp"
15 #include "util.hpp"
16 
17 
18 namespace uvw {
19 
20 
21 namespace details {
22 
23 
24 enum class UVLoopOption: std::underlying_type_t<uv_loop_option> {
25     BLOCK_SIGNAL = UV_LOOP_BLOCK_SIGNAL
26 };
27 
28 
29 enum class UVRunMode: std::underlying_type_t<uv_run_mode> {
30     DEFAULT = UV_RUN_DEFAULT,
31     ONCE = UV_RUN_ONCE,
32     NOWAIT = UV_RUN_NOWAIT
33 };
34 
35 
36 }
37 
38 
39 /**
40  * @brief Untyped handle class
41  *
42  * Handles' types are unknown from the point of view of the loop.<br/>
43  * Anyway, a loop maintains a list of all the associated handles and let the
44  * users walk them as untyped instances.<br/>
45  * This can help to end all the pending requests by closing the handles.
46  */
47 struct BaseHandle {
48     /**
49      * @brief Gets the category of the handle.
50      *
51      * A base handle offers no functionality to promote it to the actual handle
52      * type. By means of this function, an opaque value that identifies the
53      * category of the handle is made available to the users.
54      *
55      * @return The actual category of the handle.
56      */
57     virtual HandleCategory category() const noexcept = 0;
58 
59     /**
60      * @brief Gets the type of the handle.
61      *
62      * A base handle offers no functionality to promote it to the actual handle
63      * type. By means of this function, the type of the underlying handle as
64      * specified by HandleType is made available to the user.
65      *
66      * @return The actual type of the handle.
67      */
68     virtual HandleType type() const noexcept = 0;
69 
70     /**
71      * @brief Checks if the handle is active.
72      *
73      * What _active_ means depends on the type of handle:
74      *
75      * * An AsyncHandle handle is always active and cannot be deactivated,
76      * except by closing it with uv_close().
77      * * A PipeHandle, TcpHandle, UDPHandle, etc. handle - basically any handle
78      * that deals with I/O - is active when it is doing something that involves
79      * I/O, like reading, writing, connecting, accepting new connections, etc.
80      * * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
81      * has been started with a call to `start()`.
82      *
83      * Rule of thumb: if a handle of type `FooHandle` has a `start()` member
84      * method, then it’s active from the moment that method is called. Likewise,
85      * `stop()` deactivates the handle again.
86      *
87      * @return True if the handle is active, false otherwise.
88      */
89     virtual bool active() const noexcept = 0;
90 
91     /**
92      * @brief Checks if a handle is closing or closed.
93      *
94      * This function should only be used between the initialization of the
95      * handle and the arrival of the close callback.
96      *
97      * @return True if the handle is closing or closed, false otherwise.
98      */
99     virtual bool closing() const noexcept = 0;
100 
101     /**
102      * @brief Reference the given handle.
103      *
104      * References are idempotent, that is, if a handle is already referenced
105      * calling this function again will have no effect.
106      */
107     virtual void reference() noexcept = 0;
108 
109     /**
110      * @brief Unreference the given handle.
111      *
112      * References are idempotent, that is, if a handle is not referenced calling
113      * this function again will have no effect.
114      */
115     virtual void unreference() noexcept = 0;
116 
117     /**
118      * @brief Checks if the given handle referenced.
119      * @return True if the handle referenced, false otherwise.
120      */
121     virtual bool referenced() const noexcept = 0;
122 
123     /**
124      * @brief Request handle to be closed.
125      *
126      * This **must** be called on each handle before memory is released.<br/>
127      * In-progress requests are cancelled and this can result in an ErrorEvent
128      * emitted.
129      */
130     virtual void close() noexcept = 0;
131 };
132 
133 
134 /**
135  * @brief The Loop class.
136  *
137  * The event loop is the central part of `uvw`'s functionalities, as well as
138  * `libuv`'s ones.<br/>
139  * It takes care of polling for I/O and scheduling callbacks to be run based on
140  * different sources of events.
141  */
142 class Loop final: public Emitter<Loop>, public std::enable_shared_from_this<Loop> {
143     using Deleter = void(*)(uv_loop_t *);
144 
145     template<typename, typename>
146     friend class Resource;
147 
Loop(std::unique_ptr<uv_loop_t,Deleter> ptr)148     Loop(std::unique_ptr<uv_loop_t, Deleter> ptr) noexcept
149         : loop{std::move(ptr)}
150     {}
151 
152 public:
153     using Time = std::chrono::duration<uint64_t, std::milli>;
154     using Configure = details::UVLoopOption;
155     using Mode = details::UVRunMode;
156 
157     /**
158      * @brief Initializes a new Loop instance.
159      * @return A pointer to the newly created loop.
160      */
create()161     static std::shared_ptr<Loop> create() {
162         auto ptr = std::unique_ptr<uv_loop_t, Deleter>{new uv_loop_t, [](uv_loop_t *l){ delete l; }};
163         auto loop = std::shared_ptr<Loop>{new Loop{std::move(ptr)}};
164 
165         if(uv_loop_init(loop->loop.get())) {
166             loop = nullptr;
167         }
168 
169         return loop;
170     }
171 
172     /**
173      * @brief Gets the initialized default loop.
174      *
175      * It may return an empty pointer in case of failure.<br>
176      * This function is just a convenient way for having a global loop
177      * throughout an application, the default loop is in no way different than
178      * the ones initialized with `create()`.<br>
179      * As such, the default loop can be closed with `close()` so the resources
180      * associated with it are freed (even if it is not strictly necessary).
181      *
182      * @return The initialized default loop.
183      */
getDefault()184     static std::shared_ptr<Loop> getDefault() {
185         static std::weak_ptr<Loop> ref;
186         std::shared_ptr<Loop> loop;
187 
188         if(ref.expired()) {
189             auto def = uv_default_loop();
190 
191             if(def) {
192                 auto ptr = std::unique_ptr<uv_loop_t, Deleter>(def, [](uv_loop_t *){});
193                 loop = std::shared_ptr<Loop>{new Loop{std::move(ptr)}};
194             }
195 
196             ref = loop;
197         } else {
198             loop = ref.lock();
199         }
200 
201         return loop;
202     }
203 
204     Loop(const Loop &) = delete;
205     Loop(Loop &&other) = delete;
206     Loop & operator=(const Loop &) = delete;
207     Loop & operator=(Loop &&other) = delete;
208 
~Loop()209     ~Loop() noexcept {
210         if(loop) {
211             close();
212         }
213     }
214 
215     /**
216      * @brief Sets additional loop options.
217      *
218      * You should normally call this before the first call to uv_run() unless
219      * mentioned otherwise.<br/>
220      * Supported options:
221      *
222      * * `Loop::Configure::BLOCK_SIGNAL`: Block a signal when polling for new
223      * events. A second argument is required and it is the signal number.
224      *
225      * An ErrorEvent will be emitted in case of errors.
226      *
227      * See the official
228      * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_configure)
229      * for further details.
230      */
231     template<typename... Args>
configure(Configure flag,Args &&...args)232     void configure(Configure flag, Args&&... args) {
233         auto option = static_cast<std::underlying_type_t<Configure>>(flag);
234         auto err = uv_loop_configure(loop.get(), static_cast<uv_loop_option>(option), std::forward<Args>(args)...);
235         if(err) { publish(ErrorEvent{err}); }
236     }
237 
238     /**
239      * @brief Creates resources of handles' types.
240      *
241      * This should be used as a default method to create resources.<br/>
242      * The arguments are the ones required for the specific resource.
243      *
244      * Use it as `loop->resource<uvw::TimerHandle>()`.
245      *
246      * @return A pointer to the newly created resource.
247      */
248     template<typename R, typename... Args>
249     std::enable_if_t<std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
resource(Args &&...args)250     resource(Args&&... args) {
251         auto ptr = R::create(shared_from_this(), std::forward<Args>(args)...);
252         ptr = ptr->init() ? ptr : nullptr;
253         return ptr;
254     }
255 
256     /**
257      * @brief Creates resources of types other than handles' ones.
258      *
259      * This should be used as a default method to create resources.<br/>
260      * The arguments are the ones required for the specific resource.
261      *
262      * Use it as `loop->resource<uvw::WorkReq>()`.
263      *
264      * @return A pointer to the newly created resource.
265      */
266     template<typename R, typename... Args>
267     std::enable_if_t<not std::is_base_of<BaseHandle, R>::value, std::shared_ptr<R>>
resource(Args &&...args)268     resource(Args&&... args) {
269         return R::create(shared_from_this(), std::forward<Args>(args)...);
270     }
271 
272     /**
273      * @brief Releases all internal loop resources.
274      *
275      * Call this function only when the loop has finished executing and all open
276      * handles and requests have been closed, or the loop will emit an error.
277      *
278      * An ErrorEvent will be emitted in case of errors.
279      */
close()280     void close() {
281         auto err = uv_loop_close(loop.get());
282         if(err) { publish(ErrorEvent{err}); }
283     }
284 
285     /**
286      * @brief Runs the event loop.
287      *
288      * Available modes are:
289      *
290      * * `Loop::Mode::DEFAULT`: Runs the event loop until there are no more
291      * active and referenced handles or requests.
292      * * `Loop::Mode::ONCE`: Poll for i/o once. Note that this function blocks
293      * if there are no pending callbacks.
294      * * `Loop::Mode::NOWAIT`: Poll for i/o once but don’t block if there are no
295      * pending callbacks.
296      *
297      * See the official
298      * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_run)
299      * for further details.
300      *
301      * @return True when done, false in all other cases.
302      */
303     template<Mode mode = Mode::DEFAULT>
run()304     bool run() noexcept {
305         auto utm = static_cast<std::underlying_type_t<Mode>>(mode);
306         auto uvrm = static_cast<uv_run_mode>(utm);
307         return (uv_run(loop.get(), uvrm) == 0);
308     }
309 
310     /**
311      * @brief Checks if there are active resources.
312      * @return True if there are active resources in the loop.
313      */
alive() const314     bool alive() const noexcept {
315         return !(uv_loop_alive(loop.get()) == 0);
316     }
317 
318     /**
319      * @brief Stops the event loop.
320      *
321      * It causes `run()` to end as soon as possible.<br/>
322      * This will happen not sooner than the next loop iteration.<br/>
323      * If this function was called before blocking for I/O, the loop won’t block
324      * for I/O on this iteration.
325      */
stop()326     void stop() noexcept {
327         uv_stop(loop.get());
328     }
329 
330     /**
331      * @brief Get backend file descriptor.
332      *
333      * Only kqueue, epoll and event ports are supported.<br/>
334      * This can be used in conjunction with `run<Loop::Mode::NOWAIT>()` to poll
335      * in one thread and run the event loop’s callbacks in another.
336      *
337      * @return The backend file descriptor.
338      */
descriptor() const339     int descriptor() const noexcept {
340         return uv_backend_fd(loop.get());
341     }
342 
343     /**
344      * @brief Gets the poll timeout.
345      * @return A `std::pair` composed as it follows:
346      * * A boolean value that is true in case of valid timeout, false otherwise.
347      * * Milliseconds (`std::chrono::duration<uint64_t, std::milli>`).
348      */
timeout() const349     std::pair<bool, Time> timeout() const noexcept {
350         auto to = uv_backend_timeout(loop.get());
351         return std::make_pair(to == -1, Time{to});
352     }
353 
354     /**
355      * @brief Returns the current timestamp in milliseconds.
356      *
357      * The timestamp is cached at the start of the event loop tick.<br/>
358      * The timestamp increases monotonically from some arbitrary point in
359      * time.<br/>
360      * Don’t make assumptions about the starting point, you will only get
361      * disappointed.
362      *
363      * @return The current timestamp in milliseconds (actual type is
364      * `std::chrono::duration<uint64_t, std::milli>`).
365      */
now() const366     Time now() const noexcept {
367         return Time{uv_now(loop.get())};
368     }
369 
370     /**
371      * @brief Updates the event loop’s concept of _now_.
372      *
373      * The current time is cached at the start of the event loop tick in order
374      * to reduce the number of time-related system calls.<br/>
375      * You won’t normally need to call this function unless you have callbacks
376      * that block the event loop for longer periods of time, where _longer_ is
377      * somewhat subjective but probably on the order of a millisecond or more.
378      */
update() const379     void update() const noexcept {
380         return uv_update_time(loop.get());
381     }
382 
383     /**
384      * @brief Walks the list of handles.
385      *
386      * The callback will be executed once for each handle that is still active.
387      *
388      * @param callback A function to be invoked once for each active handle.
389      */
walk(std::function<void (BaseHandle &)> callback)390     void walk(std::function<void(BaseHandle &)> callback) {
391         // remember: non-capturing lambdas decay to pointers to functions
392         uv_walk(loop.get(), [](uv_handle_t *handle, void *func) {
393             BaseHandle &ref = *static_cast<BaseHandle*>(handle->data);
394             std::function<void(BaseHandle &)> &f =
395                     *static_cast<std::function<void(BaseHandle &)>*>(func);
396             f(ref);
397         }, &callback);
398     }
399 
400     /**
401      * @brief Reinitialize any kernel state necessary in the child process after
402      * a fork(2) system call.
403      *
404      * Previously started watchers will continue to be started in the child
405      * process.
406      *
407      * It is necessary to explicitly call this function on every event loop
408      * created in the parent process that you plan to continue to use in the
409      * child, including the default loop (even if you don’t continue to use it
410      * in the parent). This function must be called before calling any API
411      * function using the loop in the child. Failure to do so will result in
412      * undefined behaviour, possibly including duplicate events delivered to
413      * both parent and child or aborting the child process.
414      *
415      * When possible, it is preferred to create a new loop in the child process
416      * instead of reusing a loop created in the parent. New loops created in the
417      * child process after the fork should not use this function.
418      *
419      * Note that this function is not implemented on Windows.<br/>
420      * Note also that this function is experimental in `libuv`. It may contain
421      * bugs, and is subject to change or removal. API and ABI stability is not
422      * guaranteed.
423      *
424      * An ErrorEvent will be emitted in case of errors.
425      *
426      * See the official
427      * [documentation](http://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork)
428      * for further details.
429      */
fork()430     void fork() noexcept {
431         auto err = uv_loop_fork(loop.get());
432         if(err) { publish(ErrorEvent{err}); }
433     }
434 
435     /**
436      * @brief Gets user-defined data. `uvw` won't use this field in any case.
437      * @return User-defined data if any, an invalid pointer otherwise.
438      */
439     template<typename R = void>
data() const440     std::shared_ptr<R> data() const {
441         return std::static_pointer_cast<R>(userData);
442     }
443 
444     /**
445      * @brief Sets arbitrary data. `uvw` won't use this field in any case.
446      * @param uData User-defined arbitrary data.
447      */
data(std::shared_ptr<void> uData)448     void data(std::shared_ptr<void> uData) {
449         userData = std::move(uData);
450     }
451 
452     /**
453      * @brief Gets the underlying raw data structure.
454      *
455      * This function should not be used, unless you know exactly what you are
456      * doing and what are the risks.<br/>
457      * Going raw is dangerous, mainly because the lifetime management of a loop,
458      * a handle or a request is in charge to the library itself and users should
459      * not work around it.
460      *
461      * @warning
462      * Use this function at your own risk, but do not expect any support in case
463      * of bugs.
464      *
465      * @return The underlying raw data structure.
466      */
raw() const467     const uv_loop_t * raw() const noexcept {
468         return loop.get();
469     }
470 
471     /**
472      * @brief Gets the underlying raw data structure.
473      *
474      * This function should not be used, unless you know exactly what you are
475      * doing and what are the risks.<br/>
476      * Going raw is dangerous, mainly because the lifetime management of a loop,
477      * a handle or a request is in charge to the library itself and users should
478      * not work around it.
479      *
480      * @warning
481      * Use this function at your own risk, but do not expect any support in case
482      * of bugs.
483      *
484      * @return The underlying raw data structure.
485      */
raw()486     uv_loop_t * raw() noexcept {
487         return const_cast<uv_loop_t *>(const_cast<const Loop *>(this)->raw());
488     }
489 
490 private:
491     std::unique_ptr<uv_loop_t, Deleter> loop;
492     std::shared_ptr<void> userData{nullptr};
493 };
494 
495 
496 }
497