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