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