userver: userver/engine/io/fd_poller.hpp Source File
Loading...
Searching...
No Matches
fd_poller.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/io/fd_poller.hpp
4/// @brief Low-level file descriptor r/w poller
5
6#include <optional>
7
8#include <userver/compiler/impl/lifetime.hpp>
9#include <userver/engine/awaitable.hpp>
10#include <userver/engine/deadline.hpp>
11#include <userver/utils/fast_pimpl.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace engine::impl {
16class AwaitableBase;
17}
18
19namespace engine::ev {
20class ThreadControl;
21}
22
23namespace engine::io {
24
25namespace impl {
26class Direction;
27}
28
29/// @brief Low-level poller that can wait for read, write, and read/write
30/// operations on a file descriptor. It does not provide read/write operations.
31/// @note FdPoller is not thread safe and its methods must not be called from
32/// multiple threads simultaneously.
33class FdPoller final {
34public:
35 /// @brief Operation kind to wait for
36 enum class Kind {
37 kRead = 1, /// < wait for read availability
38 kWrite = 2, /// < wait for write availability
39 kReadWrite = 3, /// < wait for either read or write availability
40 };
41
42 /// Constructor for FdPoller. `control` parameter could be obtained via
43 /// engine::current_task::GetEventThread().
44 ///
45 /// It is recommended to place read and write FdPoller's of the same FD to
46 /// the same `control` for better ev threads balancing.
47 explicit FdPoller(const ev::ThreadControl& control);
48
49 FdPoller(const FdPoller&) = delete;
50 FdPoller(FdPoller&&) = delete;
51 FdPoller& operator=(const FdPoller&) = delete;
52 FdPoller& operator=(FdPoller&&) = delete;
53 ~FdPoller();
54
55 /// The same as `IsValid()`.
56 explicit operator bool() const noexcept;
57 /// Whether the file descriptor is valid.
58 bool IsValid() const noexcept;
59
60 /// If IsValid(), get file descriptor.
61 int GetFd() const noexcept;
62
63 /// When you're done with fd, call Invalidate(). It unregisters the fd, after
64 /// that you have to call close(2) by yourself. After Invalidate() you may not
65 /// call Wait().
66 void Invalidate();
67
68 /// Setup fd and kind to wait for. After Reset() you may call Wait().
69 /// FdPoller does not take the ownership of `fd`, you still have to close `fd`
70 /// when you're done.
71 void Reset(int fd, Kind kind);
72
73 /// Wait for an event kind that was passed in the latest Reset() call. If the
74 /// operation (read/write) can already be handled, Wait() returns
75 /// immediately. You have to call Reset() at least once before call to
76 /// Wait().
77 [[nodiscard]] std::optional<Kind> Wait(Deadline);
78
79 /// Reset "ready" flag for WaitAny. Once notified, wait operations will return
80 /// immediately on further calls unless readiness is reset.
81 void ResetReady() noexcept;
82
83 /// Get event kind that was triggered on this poller.
84 /// Resets "ready" flag.
85 std::optional<FdPoller::Kind> GetReady() noexcept;
86
87 /// Satisfies @ref engine::Awaitable, for use with @ref engine::WaitAnyContext and friends.
88 AwaitableToken GetAwaitableToken() noexcept USERVER_IMPL_LIFETIME_BOUND;
89
90private:
91 friend class impl::Direction;
92
93 enum class State : int {
94 kInvalid,
95 kReadyToUse,
96 kInUse, /// < used only in debug to detect invalid concurrent usage
97 };
98
99 void SwitchStateToInUse();
100 void SwitchStateToReadyToUse();
101
102 class Impl;
103 utils::FastPimpl<Impl, 144, 16> pimpl_;
104};
105
106} // namespace engine::io
107
108USERVER_NAMESPACE_END