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 <memory>
7#include <optional>
8
9#include <userver/engine/deadline.hpp>
10#include <userver/utils/fast_pimpl.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace engine::impl {
15class ContextAccessor;
16}
17
18namespace engine::ev {
19class ThreadControl;
20}
21
22namespace engine::io {
23
24namespace impl {
25class Direction;
26}
27
28/// @brief Low-level poller that can wait for read, write, and read/write
29/// operations on a file descriptor. It does not provide read/write operations.
30/// @note FdPoller is not thread safe and its methods must not be called from
31/// multiple threads simultaneously.
32class FdPoller final {
33public:
34 /// @brief Operation kind to wait for
35 enum class Kind {
36 kRead = 1, /// < wait for read availability
37 kWrite = 2, /// < wait for write availability
38 kReadWrite = 3, /// < wait for either read or write availability
39 };
40
41 /// Constructor for FdPoller. `control` parameter could be obtained via
42 /// engine::current_task::GetEventThread().
43 ///
44 /// It is recommended to place read and write FdPoller's of the same FD to
45 /// the same `control` for better ev threads balancing.
46 explicit FdPoller(const ev::ThreadControl& control);
47
48 FdPoller(const FdPoller&) = delete;
49 FdPoller(FdPoller&&) = delete;
50 FdPoller& operator=(const FdPoller&) = delete;
51 FdPoller& operator=(FdPoller&&) = delete;
52 ~FdPoller();
53
54 /// The same as `IsValid()`.
55 explicit operator bool() const noexcept;
56 /// Whether the file descriptor is valid.
57 bool IsValid() const noexcept;
58
59 /// If IsValid(), get file descriptor.
60 int GetFd() const noexcept;
61
62 /// When you're done with fd, call Invalidate(). It unregisters the fd, after
63 /// that you have to call close(2) by yourself. After Invalidate() you may not
64 /// call Wait().
65 void Invalidate();
66
67 /// Setup fd and kind to wait for. After Reset() you may call Wait().
68 /// FdPoller does not take the ownership of `fd`, you still have to close `fd`
69 /// when you're done.
70 void Reset(int fd, Kind kind);
71
72 /// Wait for an event kind that was passed in the latest Reset() call. If the
73 /// operation (read/write) can already be handled, Wait() returns
74 /// immediately. You have to call Reset() at least once before call to
75 /// Wait().
76 [[nodiscard]] std::optional<Kind> Wait(Deadline);
77
78 /// Reset "ready" flag for WaitAny().
79 void ResetReady() noexcept;
80
81 /// Get event kind that was triggered on this poller.
82 /// Resets "ready" flag.
83 std::optional<FdPoller::Kind> GetReady() noexcept;
84
85 /// @cond
86 // For internal use only.
87 engine::impl::ContextAccessor* TryGetContextAccessor() noexcept;
88 /// @endcond
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 WakeupWaiters();
100 void SwitchStateToInUse();
101 void SwitchStateToReadyToUse();
102
103 struct Impl;
104 utils::FastPimpl<Impl, 128, 16> pimpl_;
105};
106
107} // namespace engine::io
108
109USERVER_NAMESPACE_END