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