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