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::io {
19
20namespace impl {
21class Direction;
22}
23
24/// @brief Low-level poller that can wait for read, write, and read/write
25/// operations on a file descriptor. It does not provide read/write operations.
26/// @note FdPoller is not thread safe and its methods must not be called from
27/// multiple threads simultaneously.
28class FdPoller final {
29 public:
30 /// @brief Operation kind to wait for
31 enum class Kind {
32 kRead = 1, /// < wait for read availability
33 kWrite = 2, /// < wait for write availability
34 kReadWrite = 3, /// < wait for either read or write availability
35 };
36
37 FdPoller();
38 FdPoller(const FdPoller&) = delete;
39 FdPoller(FdPoller&&) = delete;
40 FdPoller& operator=(const FdPoller&) = delete;
41 FdPoller& operator=(FdPoller&&) = delete;
42 ~FdPoller();
43
44 /// The same as `IsValid()`.
45 explicit operator bool() const noexcept;
46 /// Whether the file descriptor is valid.
47 bool IsValid() const noexcept;
48
49 /// If IsValid(), get file descriptor.
50 int GetFd() const;
51
52 /// When you're done with fd, call Invalidate(). It unregisters the fd, after
53 /// that you have to call close(2) by yourself. After Invalidate() you may not
54 /// call Wait().
55 void Invalidate();
56
57 /// Setup fd and kind to wait for. After Reset() you may call Wait().
58 /// FdPoller does not take the ownership of `fd`, you still have to close `fd`
59 /// when you're done.
60 void Reset(int fd, Kind kind);
61
62 /// Wait for an event kind that was passed in the latest Reset() call. If the
63 /// operation (read/write) can already be handled, Wait() returns
64 /// immediately. You have to call Reset() at least once before call to
65 /// Wait().
66 [[nodiscard]] std::optional<Kind> Wait(Deadline);
67
68 /// Reset "ready" flag for WaitAny().
69 void ResetReady() noexcept;
70
71 /// Get event kind that was triggered on this poller.
72 /// Resets "ready" flag.
73 std::optional<FdPoller::Kind> GetReady() noexcept;
74
75 /// @cond
76 // For internal use only.
77 engine::impl::ContextAccessor* TryGetContextAccessor() noexcept;
78 /// @endcond
79
80 private:
81 friend class impl::Direction;
82
83 enum class State : int {
84 kInvalid,
85 kReadyToUse,
86 kInUse, /// < used only in debug to detect invalid concurrent usage
87 };
88
89 void WakeupWaiters();
90 void SwitchStateToInUse();
91 void SwitchStateToReadyToUse();
92
93 struct Impl;
94 utils::FastPimpl<Impl, 144, 16> pimpl_;
95};
96
97} // namespace engine::io
98
99USERVER_NAMESPACE_END