xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/io/quic_poll_event_loop.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_CORE_IO_QUIC_POLL_EVENT_LOOP_H_
6 #define QUICHE_QUIC_CORE_IO_QUIC_POLL_EVENT_LOOP_H_
7 
8 #if defined(_WIN32)
9 #include <winsock2.h>
10 #else
11 #include <poll.h>
12 #endif
13 
14 #include <memory>
15 
16 #include "absl/container/btree_map.h"
17 #include "absl/types/span.h"
18 #include "quiche/quic/core/io/quic_event_loop.h"
19 #include "quiche/quic/core/io/socket.h"
20 #include "quiche/quic/core/quic_alarm.h"
21 #include "quiche/quic/core/quic_alarm_factory.h"
22 #include "quiche/quic/core/quic_clock.h"
23 #include "quiche/common/quiche_linked_hash_map.h"
24 
25 namespace quic {
26 
27 // A simple and portable implementation of QuicEventLoop using poll(2).  Works
28 // on all POSIX platforms (and can be potentially made to support Windows using
29 // WSAPoll).
30 //
31 // For most operations, this implementation has a typical runtime of
32 // O(N + log M), where N is the number of file descriptors, and M is the number
33 // of pending alarms.
34 //
35 // This API has to deal with the situations where callbacks are modified from
36 // the callbacks themselves.  To address this, we use the following two
37 // approaches:
38 //   1. The code does not execute any callbacks until the very end of the
39 //      processing, when all of the state for the event loop is consistent.
40 //   2. The callbacks are stored as weak pointers, since other callbacks can
41 //      cause them to be unregistered.
42 class QuicPollEventLoop : public QuicEventLoop {
43  public:
44   QuicPollEventLoop(QuicClock* clock);
45 
46   // QuicEventLoop implementation.
SupportsEdgeTriggered()47   bool SupportsEdgeTriggered() const override { return false; }
48   ABSL_MUST_USE_RESULT bool RegisterSocket(
49       SocketFd fd, QuicSocketEventMask events,
50       QuicSocketEventListener* listener) override;
51   ABSL_MUST_USE_RESULT bool UnregisterSocket(SocketFd fd) override;
52   ABSL_MUST_USE_RESULT bool RearmSocket(SocketFd fd,
53                                         QuicSocketEventMask events) override;
54   ABSL_MUST_USE_RESULT bool ArtificiallyNotifyEvent(
55       SocketFd fd, QuicSocketEventMask events) override;
56   void RunEventLoopOnce(QuicTime::Delta default_timeout) override;
57   std::unique_ptr<QuicAlarmFactory> CreateAlarmFactory() override;
GetClock()58   const QuicClock* GetClock() override { return clock_; }
59 
60  protected:
61   // Allows poll(2) calls to be mocked out in unit tests.
62   virtual int PollSyscall(pollfd* fds, size_t nfds, int timeout);
63 
64  private:
65   friend class QuicPollEventLoopPeer;
66 
67   struct Registration {
68     QuicSocketEventMask events = 0;
69     QuicSocketEventListener* listener;
70 
71     QuicSocketEventMask artificially_notify_at_next_iteration = 0;
72   };
73 
74   class Alarm : public QuicAlarm {
75    public:
76     Alarm(QuicPollEventLoop* loop,
77           QuicArenaScopedPtr<QuicAlarm::Delegate> delegate);
78 
79     void SetImpl() override;
80     void CancelImpl() override;
81 
DoFire()82     void DoFire() {
83       current_schedule_handle_.reset();
84       Fire();
85     }
86 
87    private:
88     QuicPollEventLoop* loop_;
89     // Deleted when the alarm is cancelled, causing the corresponding weak_ptr
90     // in the alarm list to not be executed.
91     std::shared_ptr<Alarm*> current_schedule_handle_;
92   };
93 
94   class AlarmFactory : public QuicAlarmFactory {
95    public:
AlarmFactory(QuicPollEventLoop * loop)96     AlarmFactory(QuicPollEventLoop* loop) : loop_(loop) {}
97 
98     // QuicAlarmFactory implementation.
99     QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
100     QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
101         QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
102         QuicConnectionArena* arena) override;
103 
104    private:
105     QuicPollEventLoop* loop_;
106   };
107 
108   // Used for deferred execution of I/O callbacks.
109   struct ReadyListEntry {
110     SocketFd fd;
111     std::weak_ptr<Registration> registration;
112     QuicSocketEventMask events;
113   };
114 
115   // We're using a linked hash map here to ensure the events are called in the
116   // registration order.  This isn't strictly speaking necessary, but makes
117   // testing things easier.
118   using RegistrationMap =
119       quiche::QuicheLinkedHashMap<SocketFd, std::shared_ptr<Registration>>;
120   // Alarms are stored as weak pointers, since the alarm can be cancelled and
121   // disappear while in the queue.
122   using AlarmList = absl::btree_multimap<QuicTime, std::weak_ptr<Alarm*>>;
123 
124   // Returns the timeout for the next poll(2) call.  It is typically the time at
125   // which the next alarm is supposed to activate.
126   QuicTime::Delta ComputePollTimeout(QuicTime now,
127                                      QuicTime::Delta default_timeout) const;
128   // Calls poll(2) with the provided timeout and dispatches the callbacks
129   // accordingly.
130   void ProcessIoEvents(QuicTime start_time, QuicTime::Delta timeout);
131   // Calls all of the alarm callbacks that are scheduled before or at |time|.
132   void ProcessAlarmsUpTo(QuicTime time);
133 
134   // Adds the I/O callbacks for |fd| to the |ready_lits| as appopriate.
135   void DispatchIoEvent(std::vector<ReadyListEntry>& ready_list, SocketFd fd,
136                        short mask);  // NOLINT(runtime/int)
137   // Runs all of the callbacks on the ready list.
138   void RunReadyCallbacks(std::vector<ReadyListEntry>& ready_list);
139 
140   // Calls poll() while handling EINTR.  Returns the return value of poll(2)
141   // system call.
142   int PollWithRetries(absl::Span<pollfd> fds, QuicTime start_time,
143                       QuicTime::Delta timeout);
144 
145   const QuicClock* clock_;
146   RegistrationMap registrations_;
147   AlarmList alarms_;
148   bool has_artificial_events_pending_ = false;
149 };
150 
151 class QuicPollEventLoopFactory : public QuicEventLoopFactory {
152  public:
Get()153   static QuicPollEventLoopFactory* Get() {
154     static QuicPollEventLoopFactory* factory = new QuicPollEventLoopFactory();
155     return factory;
156   }
157 
Create(QuicClock * clock)158   std::unique_ptr<QuicEventLoop> Create(QuicClock* clock) override {
159     return std::make_unique<QuicPollEventLoop>(clock);
160   }
161 
GetName()162   std::string GetName() const override { return "poll(2)"; }
163 };
164 
165 }  // namespace quic
166 
167 #endif  // QUICHE_QUIC_CORE_IO_QUIC_POLL_EVENT_LOOP_H_
168